visuddhinanda 3 лет назад
Родитель
Сommit
967a0a4ce4

+ 16 - 0
dashboard/src/components/auth/setting/SettingArticle.tsx

@@ -0,0 +1,16 @@
+import { Divider } from "antd";
+import { SettingFind } from "./default";
+import SettingItem from "./SettingItem";
+
+const Widget = () => {
+  return (
+    <div>
+      <Divider>翻译</Divider>
+      <SettingItem data={SettingFind("setting.display.original")} />
+      <SettingItem data={SettingFind("setting.layout.direction")} />
+      <SettingItem data={SettingFind("setting.layout.paragraph")} />
+    </div>
+  );
+};
+
+export default Widget;

+ 106 - 0
dashboard/src/components/auth/setting/SettingItem.tsx

@@ -0,0 +1,106 @@
+import { Switch, Typography, Radio, RadioChangeEvent } from "antd";
+import {
+  onChange as onSettingChanged,
+  settingInfo,
+  ISettingItem,
+} from "../../../reducers/setting";
+import { useAppSelector } from "../../../hooks";
+import store from "../../../store";
+import { ISetting } from "./default";
+import { useEffect, useState } from "react";
+
+const { Title, Text } = Typography;
+
+interface IWidgetSettingItem {
+  data?: ISetting;
+  onChange?: Function;
+}
+const Widget = ({ data, onChange }: IWidgetSettingItem) => {
+  const settings: ISettingItem[] | undefined = useAppSelector(settingInfo);
+  const [value, setValue] = useState(data?.defaultValue);
+  const title = <Title level={5}>{data?.label}</Title>;
+  console.log(data);
+  useEffect(() => {
+    const currSetting = settings?.find((element) => element.key === data?.key);
+    if (typeof currSetting !== "undefined") {
+      setValue(currSetting.value);
+    }
+  }, [data?.key, settings]);
+  let content: JSX.Element = <></>;
+  if (typeof data === "undefined") {
+    return content;
+  } else {
+    switch (typeof data.defaultValue) {
+      case "number":
+        break;
+      case "string":
+        switch (data.widget) {
+          case "radio-button":
+            if (typeof data.options !== "undefined") {
+              return (
+                <>
+                  {title}
+                  <div>
+                    <Text>{data.description}</Text>
+                  </div>
+                  <Radio.Group
+                    value={value}
+                    buttonStyle="solid"
+                    onChange={(e: RadioChangeEvent) => {
+                      setValue(e.target.value);
+                      store.dispatch(
+                        onSettingChanged({
+                          key: data.key,
+                          value: e.target.value,
+                        })
+                      );
+                    }}
+                  >
+                    {data.options.map((item, id) => {
+                      return (
+                        <Radio.Button key={item.key} value={item.key}>
+                          {item.label}
+                        </Radio.Button>
+                      );
+                    })}
+                  </Radio.Group>
+                </>
+              );
+            }
+
+            break;
+        }
+        break;
+      case "boolean":
+        content = (
+          <div>
+            <Switch
+              defaultChecked={value as boolean}
+              onChange={(checked) => {
+                if (typeof onChange !== "undefined") {
+                  onChange(checked);
+                }
+                console.log("setting changed", data.key, checked);
+                store.dispatch(
+                  onSettingChanged({ key: data.key, value: checked })
+                );
+              }}
+            />
+            <Text>{data.description}</Text>
+          </div>
+        );
+        break;
+      default:
+        break;
+    }
+
+    return (
+      <div>
+        <Title level={5}>{data.label}</Title>
+        {content}
+      </div>
+    );
+  }
+};
+
+export default Widget;

+ 160 - 0
dashboard/src/components/auth/setting/default.ts

@@ -0,0 +1,160 @@
+import { useIntl } from "react-intl";
+
+export interface ISettingItemOption {
+  label: string;
+  key: string;
+}
+export interface ISetting {
+  key: string;
+  label: string;
+  description: string;
+  defaultValue: string | number | boolean;
+  value?: string | number | boolean;
+  widget?: "input" | "select" | "radio" | "radio-button";
+  options?: ISettingItemOption[];
+  max?: number;
+  min?: number;
+}
+
+export const SettingFind = (key: string): ISetting | undefined => {
+  return Settings().find((element) => element.key === key);
+};
+export const Settings = (): ISetting[] => {
+  const intl = useIntl();
+
+  const defaultSetting: ISetting[] = [
+    {
+      /**
+       * 是否显示巴利原文
+       */
+      key: "setting.display.original",
+      label: intl.formatMessage({ id: "setting.display.original.label" }),
+      description: intl.formatMessage({
+        id: "setting.display.original.description",
+      }),
+      defaultValue: true,
+    },
+    {
+      /**
+       * 排版方向
+       */
+      key: "setting.layout.direction",
+      label: intl.formatMessage({ id: "setting.layout.direction.label" }),
+      description: intl.formatMessage({
+        id: "setting.layout.direction.description",
+      }),
+      defaultValue: "column",
+      options: [
+        {
+          key: "column",
+          label: intl.formatMessage({
+            id: "setting.layout.direction.col.label",
+          }),
+        },
+        {
+          key: "row",
+          label: intl.formatMessage({
+            id: "setting.layout.direction.row.label",
+          }),
+        },
+      ],
+      widget: "radio-button",
+    },
+    {
+      /**
+       * 段落或者逐句对读
+       */
+      key: "setting.layout.paragraph",
+      label: intl.formatMessage({ id: "setting.layout.paragraph.label" }),
+      description: intl.formatMessage({
+        id: "setting.layout.paragraph.description",
+      }),
+      defaultValue: "sentence",
+      options: [
+        {
+          key: "sentence",
+          label: intl.formatMessage({
+            id: "setting.layout.paragraph.sentence.label",
+          }),
+        },
+        {
+          key: "paragraph",
+          label: intl.formatMessage({
+            id: "setting.layout.paragraph.paragraph.label",
+          }),
+        },
+      ],
+      widget: "radio-button",
+    },
+    {
+      /**
+       * 第一巴利脚本
+       */
+      key: "setting.pali.script1",
+      label: intl.formatMessage({ id: "setting.pali.script1.label" }),
+      description: intl.formatMessage({
+        id: "setting.pali.script1.description",
+      }),
+      defaultValue: "rome",
+      options: [
+        {
+          key: "rome",
+          label: intl.formatMessage({
+            id: "setting.pali.script.rome.label",
+          }),
+        },
+        {
+          key: "my",
+          label: intl.formatMessage({
+            id: "setting.pali.script.my.label",
+          }),
+        },
+        {
+          key: "si",
+          label: intl.formatMessage({
+            id: "setting.pali.script.si.label",
+          }),
+        },
+      ],
+    },
+    {
+      /**
+       * 第一巴利脚本
+       */
+      key: "setting.pali.script2",
+      label: intl.formatMessage({ id: "setting.pali.script2.label" }),
+      description: intl.formatMessage({
+        id: "setting.pali.script2.description",
+      }),
+      defaultValue: "none",
+      options: [
+        {
+          key: "none",
+          label: intl.formatMessage({
+            id: "setting.pali.script.none.label",
+          }),
+        },
+        {
+          key: "rome",
+          label: intl.formatMessage({
+            id: "setting.pali.script.rome.label",
+          }),
+        },
+        {
+          key: "my",
+          label: intl.formatMessage({
+            id: "setting.pali.script.my.label",
+          }),
+        },
+        {
+          key: "si",
+          label: intl.formatMessage({
+            id: "setting.pali.script.si.label",
+          }),
+        },
+      ],
+    },
+  ];
+
+  return defaultSetting;
+};

+ 6 - 0
dashboard/src/components/auth/setting/index.tsx

@@ -0,0 +1,6 @@
+const Widget = () => {
+	return <div>change password</div>;
+  };
+  
+  export default Widget;
+  

+ 80 - 0
dashboard/src/components/template/SentEdit/SentTabButton.tsx

@@ -0,0 +1,80 @@
+import { useIntl } from "react-intl";
+import { Badge, Dropdown } from "antd";
+import {
+  OneToOneOutlined,
+  LinkOutlined,
+  CalendarOutlined,
+} from "@ant-design/icons";
+
+import store from "../../../store";
+import {
+  ISite,
+  refresh as refreshLayout,
+} from "../../../reducers/open-article";
+import type { MenuProps } from "antd";
+
+const handleButtonClick = (e: React.MouseEvent<HTMLButtonElement>) => {
+  console.log("click left button", e);
+};
+
+interface IWidgetSentTabButton {
+  icon?: JSX.Element;
+  type: string;
+  sentId: string;
+  count?: number;
+}
+const Widget = ({ icon, type, sentId, count = 0 }: IWidgetSentTabButton) => {
+  const intl = useIntl();
+  const items: MenuProps["items"] = [
+    {
+      label: "在分栏中打开",
+      key: "openInCol",
+      icon: <OneToOneOutlined />,
+    },
+    {
+      label: "在新标签页中打开",
+      key: "openInWin",
+      icon: <CalendarOutlined />,
+    },
+    {
+      label: "复制链接",
+      key: "copyLink",
+      icon: <LinkOutlined />,
+    },
+  ];
+  const handleMenuClick: MenuProps["onClick"] = (e) => {
+    e.domEvent.stopPropagation();
+    switch (e.key) {
+      case "openInCol":
+        const it: ISite = {
+          title: intl.formatMessage({
+            id: `channel.type.${type}.label`,
+          }),
+          url: "corpus_sent/" + type,
+          id: sentId,
+        };
+        store.dispatch(refreshLayout(it));
+        break;
+    }
+  };
+  const menuProps = {
+    items,
+    onClick: handleMenuClick,
+  };
+
+  return (
+    <Dropdown.Button
+      size="small"
+      type="text"
+      menu={menuProps}
+      onClick={handleButtonClick}
+    >
+      {intl.formatMessage({
+        id: `channel.type.${type}.label`,
+      })}
+      <Badge size="small" color="geekblue" count={count}></Badge>
+    </Dropdown.Button>
+  );
+};
+
+export default Widget;

+ 22 - 0
dashboard/src/locales/zh-Hans/setting/index.ts

@@ -0,0 +1,22 @@
+const items = {
+  "setting.display.original.label": "显示原文",
+  "setting.display.original.description": "是否显示原文(仅阅读模式)",
+  "setting.layout.direction.label": "排版方向",
+  "setting.layout.direction.description": "横向或者纵向排版",
+  "setting.layout.direction.col.label": "纵向排版",
+  "setting.layout.direction.row.label": "横向排版",
+  "setting.layout.paragraph.label": "对照方式",
+  "setting.layout.paragraph.description": "逐段或逐句对照(仅阅读模式)",
+  "setting.layout.paragraph.paragraph.label": "逐段",
+  "setting.layout.paragraph.sentence.label": "逐句",
+  "setting.pali.script1.label": "第一巴利脚本",
+  "setting.pali.script1.description": "首要的巴利语脚本",
+  "setting.pali.script2.label": "第二巴利脚本",
+  "setting.pali.script2.description": "第二个巴利语脚本",
+  "setting.pali.script.rome.label": "罗马巴利",
+  "setting.pali.script.my.label": "缅文字母",
+  "setting.pali.script.si.label": "新哈拉字母",
+  "setting.pali.script.none.label": "不显示",
+};
+
+export default items;

+ 65 - 0
dashboard/src/reducers/setting.ts

@@ -0,0 +1,65 @@
+import { createSlice, PayloadAction } from "@reduxjs/toolkit";
+
+import type { RootState } from "../store";
+
+export interface ISettingItem {
+  key: string;
+  value: string | number | boolean | undefined;
+}
+
+interface IState {
+  settings?: ISettingItem[];
+  key?: string;
+  value?: string | number | boolean;
+}
+
+const initialState: IState = {};
+
+const KEY = "user-settings";
+
+const set = (settings: ISettingItem[]) => {
+  localStorage.setItem(KEY, JSON.stringify(settings));
+};
+
+export const slice = createSlice({
+  name: "setting",
+  initialState,
+  reducers: {
+    refresh: (state, action: PayloadAction<ISettingItem[]>) => {
+      state.settings = action.payload;
+    },
+    onChange: (state, action: PayloadAction<ISettingItem>) => {
+      state.key = action.payload.key;
+      state.value = action.payload.value;
+      //将新的改变放入 settings
+      if (typeof state.settings !== "undefined") {
+        const index = state.settings.findIndex(
+          (element) => element.key === action.payload.key
+        );
+        if (index >= 0) {
+          state.settings[index].value = action.payload.value;
+        } else {
+          state.settings.push(action.payload);
+        }
+      } else {
+        state.settings = [action.payload];
+      }
+      set(state.settings);
+    },
+  },
+});
+
+export const { refresh, onChange } = slice.actions;
+
+export const setting = (state: RootState): IState => state.setting;
+
+export const settingInfo = (state: RootState): ISettingItem[] | undefined =>
+  state.setting.settings;
+
+export const onChangeKey = (state: RootState): string | undefined =>
+  state.setting.key;
+export const onChangeValue = (
+  state: RootState
+): string | number | boolean | undefined => state.setting.value;
+
+export default slice.reducer;