feat(components): add control and visual components
This commit is contained in:
parent
5f0d8e2737
commit
7156c22a56
5 changed files with 204 additions and 23 deletions
80
src/client/web/src/components/control/tabs.tsx
Normal file
80
src/client/web/src/components/control/tabs.tsx
Normal file
|
@ -0,0 +1,80 @@
|
|||
import * as React from "react";
|
||||
import { List, Map, update } from "immutable";
|
||||
|
||||
import { updater } from "../state_updater";
|
||||
import { getIcon } from "../visual/icons";
|
||||
import { Flexbox } from "../layout/flexbox";
|
||||
import { ICoreState, MsgProps, UIProps } from "../core_state";
|
||||
import { AdminProps } from "../pane_admin";
|
||||
import { LoginProps } from "../pane_login";
|
||||
import { alertMsg } from "../../common/env";
|
||||
import { IconProps } from "../visual/icons";
|
||||
import { colorClass } from "../visual/colors";
|
||||
|
||||
const defaultIconProps: IconProps = {
|
||||
name: "RiFolder2Fill",
|
||||
size: "1.6rem",
|
||||
color: `${colorClass("cyan0")}-font`,
|
||||
};
|
||||
|
||||
export interface Props {
|
||||
targetSwitch: string;
|
||||
tabIcons: Map<string, IconProps>; // option name -> icon name
|
||||
login: LoginProps;
|
||||
admin: AdminProps;
|
||||
ui: UIProps;
|
||||
msg: MsgProps;
|
||||
update?: (updater: (prevState: ICoreState) => ICoreState) => void;
|
||||
}
|
||||
|
||||
export interface State {}
|
||||
export class Tabs extends React.Component<Props, State, {}> {
|
||||
constructor(p: Props) {
|
||||
super(p);
|
||||
}
|
||||
|
||||
setTab = (targetSwitch: string, targetOption: string) => {
|
||||
if (!updater().setControlOption(targetSwitch, targetOption)) {
|
||||
alertMsg(this.props.msg.pkg.get("op.fail"));
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const displaying = this.props.ui.control.controls.get(
|
||||
this.props.targetSwitch
|
||||
);
|
||||
const options = this.props.ui.control.options.get(this.props.targetSwitch);
|
||||
const tabs = options.map((option: string, targetSwitch: string) => {
|
||||
const iconProps = this.props.tabIcons.has(option)
|
||||
? this.props.tabIcons.get(option)
|
||||
: defaultIconProps;
|
||||
|
||||
// <RiFolder2Fill size="1.6rem" className="margin-r-s cyan0-font" />,
|
||||
const icon = getIcon(iconProps.name, iconProps.size, iconProps.color);
|
||||
|
||||
return (
|
||||
<button
|
||||
key={`${targetSwitch}-${option}`}
|
||||
onClick={() => {
|
||||
this.setTab(targetSwitch, option);
|
||||
}}
|
||||
className="float"
|
||||
>
|
||||
<Flexbox
|
||||
children={List([
|
||||
<span className="margin-r-s">{icon}</span>,
|
||||
<span>
|
||||
{this.props.msg.pkg.get(`switch.${targetSwitch}.${option}`)}
|
||||
</span>,
|
||||
])}
|
||||
childrenStyles={List([{ flex: "30%" }, { flex: "70%" }])}
|
||||
/>
|
||||
</button>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={`tabs control-${this.props.targetSwitch}`}>{tabs}</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -11,10 +11,6 @@ import { AdminProps } from "./pane_admin";
|
|||
import { MsgPackage } from "../i18n/msger";
|
||||
import { User, MetadataResp } from "../client";
|
||||
|
||||
export interface PanelsProps {
|
||||
displaying: string;
|
||||
}
|
||||
|
||||
export interface MsgProps {
|
||||
lan: string;
|
||||
pkg: Map<string, string>;
|
||||
|
@ -30,15 +26,18 @@ export interface UIProps {
|
|||
position: string;
|
||||
align: string;
|
||||
};
|
||||
control: {
|
||||
controls: Map<string, string>;
|
||||
options: Map<string, Set<string>>;
|
||||
};
|
||||
}
|
||||
export interface ICoreState {
|
||||
panels: PanelsProps;
|
||||
filesInfo: FilesProps;
|
||||
uploadingsInfo: UploadingsProps;
|
||||
sharingsInfo: SharingsProps;
|
||||
panes: PanesProps;
|
||||
login: LoginProps;
|
||||
admin: AdminProps;
|
||||
login: LoginProps;
|
||||
panes: PanesProps;
|
||||
ui: UIProps;
|
||||
msg: MsgProps;
|
||||
}
|
||||
|
@ -49,9 +48,6 @@ export function newState(): ICoreState {
|
|||
|
||||
export function initState(): ICoreState {
|
||||
return {
|
||||
panels: {
|
||||
displaying: "item",
|
||||
},
|
||||
filesInfo: {
|
||||
dirPath: List<string>([]),
|
||||
items: List<MetadataResp>([]),
|
||||
|
@ -112,6 +108,10 @@ export function initState(): ICoreState {
|
|||
position: "",
|
||||
align: "",
|
||||
},
|
||||
control: {
|
||||
controls: Map<string, string>(),
|
||||
options: Map<string, Set<string>>(),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -554,20 +554,34 @@ export class Updater {
|
|||
};
|
||||
|
||||
setTab = (tabName: string) => {
|
||||
switch (tabName) {
|
||||
case "item":
|
||||
this.props.panels.displaying = tabName;
|
||||
break;
|
||||
case "uploading":
|
||||
this.props.panels.displaying = tabName;
|
||||
break;
|
||||
case "sharing":
|
||||
this.props.panels.displaying = tabName;
|
||||
break;
|
||||
default:
|
||||
this.props.panels.displaying = "item";
|
||||
break;
|
||||
// switch (tabName) {
|
||||
// case "item":
|
||||
// this.props.panels.displaying = tabName;
|
||||
// break;
|
||||
// case "uploading":
|
||||
// this.props.panels.displaying = tabName;
|
||||
// break;
|
||||
// case "sharing":
|
||||
// this.props.panels.displaying = tabName;
|
||||
// break;
|
||||
// default:
|
||||
// this.props.panels.displaying = "item";
|
||||
// break;
|
||||
// }
|
||||
};
|
||||
|
||||
setControlOption = (controlName: string, option: string): boolean => {
|
||||
const controlExists = this.props.ui.control.controls.has(controlName);
|
||||
const options = this.props.ui.control.options.get(controlName);
|
||||
if (!controlExists || !options.has(option)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.props.ui.control.controls = this.props.ui.control.controls.set(
|
||||
controlName,
|
||||
option
|
||||
);
|
||||
return true;
|
||||
};
|
||||
|
||||
generateHash = async (filePath: string): Promise<boolean> => {
|
||||
|
|
37
src/client/web/src/components/visual/colors.tsx
Normal file
37
src/client/web/src/components/visual/colors.tsx
Normal file
|
@ -0,0 +1,37 @@
|
|||
import { Set, Map } from "immutable";
|
||||
|
||||
export const colors = Set<string>([
|
||||
"blue0",
|
||||
"blue1",
|
||||
"cyan0",
|
||||
"cyan1",
|
||||
"purple0",
|
||||
"purple1",
|
||||
"red0",
|
||||
"red1",
|
||||
"yellow0",
|
||||
"yellow1",
|
||||
"yellow2",
|
||||
"yellow3",
|
||||
"green0",
|
||||
"green1",
|
||||
"green2",
|
||||
"white",
|
||||
"white0",
|
||||
"white1",
|
||||
"grey0",
|
||||
"grey1",
|
||||
"grey2",
|
||||
"grey3",
|
||||
"black",
|
||||
"black0",
|
||||
"black1",
|
||||
]);
|
||||
|
||||
export function colorClass(name: string): string {
|
||||
if (!colors.has(name)) {
|
||||
console.error(`color ${name} not found`);
|
||||
return colors.get("black");
|
||||
}
|
||||
return colors.get(name);
|
||||
}
|
50
src/client/web/src/components/visual/icons.tsx
Normal file
50
src/client/web/src/components/visual/icons.tsx
Normal file
|
@ -0,0 +1,50 @@
|
|||
import * as React from "react";
|
||||
import { Map } from "immutable";
|
||||
|
||||
import { IconType, IconBaseProps } from "@react-icons/all-files";
|
||||
import { RiFolder2Fill } from "@react-icons/all-files/ri/RiFolder2Fill";
|
||||
import { RiShareBoxLine } from "@react-icons/all-files/ri/RiShareBoxLine";
|
||||
import { RiUploadCloudFill } from "@react-icons/all-files/ri/RiUploadCloudFill";
|
||||
|
||||
import { colorClass } from "./colors";
|
||||
|
||||
export interface IconProps {
|
||||
name: string;
|
||||
size: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
const icons = Map<string, IconType>({
|
||||
RiFolder2Fill: RiFolder2Fill,
|
||||
RiShareBoxLine: RiShareBoxLine,
|
||||
RiUploadCloudFill: RiUploadCloudFill,
|
||||
});
|
||||
|
||||
export function getIconWithProps(
|
||||
name: string,
|
||||
props: IconBaseProps
|
||||
): JSX.Element | null {
|
||||
const icon = icons.get(name);
|
||||
if (icon == null) {
|
||||
throw Error(`icon "${name}" is not found`);
|
||||
}
|
||||
|
||||
return React.createElement(icon, { ...props }, null);
|
||||
}
|
||||
|
||||
export function getIcon(
|
||||
name: string,
|
||||
size: string,
|
||||
color: string
|
||||
): JSX.Element | null {
|
||||
const icon = icons.get(name);
|
||||
if (icon == null) {
|
||||
throw Error(`icon "${name}" is not found`);
|
||||
}
|
||||
|
||||
return React.createElement(
|
||||
icon,
|
||||
{ size, className: `${colorClass(color)}-font` },
|
||||
null
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue