visuddhinanda 1 месяц назад
Родитель
Сommit
5e4417f736

+ 103 - 121
dashboard-v6/src/components/dict/Community.tsx

@@ -5,7 +5,6 @@ import {
   Dropdown,
   type MenuProps,
   Popover,
-  Skeleton,
   Space,
   Typography,
 } from "antd";
@@ -19,7 +18,7 @@ import MyCreate from "./MyCreate";
 import type { IUser } from "../../api/Auth";
 import MdView from "../general/MdView";
 
-const { Title, Link, Text } = Typography;
+const { Link, Text } = Typography;
 
 interface IItem<R> {
   value: R;
@@ -39,7 +38,6 @@ interface IWidget {
 }
 const CommunityWidget = ({ word }: IWidget) => {
   const intl = useIntl();
-  const [loaded, setLoaded] = useState(false);
   const [loading, setLoading] = useState(false);
   const [wordData, setWordData] = useState<IWord>();
   const [showCreate, setShowCreate] = useState(false);
@@ -142,7 +140,7 @@ const CommunityWidget = ({ word }: IWidget) => {
       });
       _data.editor.sort((a, b) => b.score - a.score);
       setWordData(_data);
-      setLoaded(_data.editor.length > 0);
+      setLoading(_data.editor.length > 0);
     } catch (error) {
       console.error(error);
     } finally {
@@ -181,7 +179,12 @@ const CommunityWidget = ({ word }: IWidget) => {
     return (
       <Space key={id}>
         {name}
-        <Badge color="geekblue" size="small" count={score} />
+        <Badge
+          color="geekblue"
+          size="small"
+          count={score}
+          style={{ display: "none" }}
+        />
       </Space>
     );
   };
@@ -209,127 +212,106 @@ const CommunityWidget = ({ word }: IWidget) => {
   ) : undefined;
 
   return (
-    <Card>
-      <Title level={5} id={`community`}>
-        {"社区字典"}
-      </Title>
-      {loading ? (
-        <Skeleton />
-      ) : loaded ? (
-        <div>
-          <div key="meaning">
-            <Space style={{ flexWrap: "wrap" }}>
-              <Text strong>{"意思:"}</Text>
-              {wordData?.meaning
-                .filter((value, index: number) => isShow(value.score, index))
-                .map((item, id) => {
-                  return (
-                    <Space key={id}>
-                      {item.value}
-                      <Badge color="geekblue" size="small" count={item.score} />
-                    </Space>
-                  );
-                })}
-              {meaningLow && meaningLow.length > 0 ? (
-                <Popover
-                  content={<Space>{meaningExtra}</Space>}
-                  placement="bottom"
-                >
-                  <Link>
-                    <Space>
-                      {intl.formatMessage({
-                        id: `buttons.more`,
-                      })}
-                      <DownOutlined />
-                    </Space>
-                  </Link>
-                </Popover>
-              ) : undefined}
-            </Space>
-          </div>
-          <div key="grammar">
-            <Space style={{ flexWrap: "wrap" }}>
-              <Text strong>{"语法:"}</Text>
-              {wordData?.grammar
-                .filter((value) => value.score >= minScore)
-                .map((item, id) => {
-                  const grammar = item.value.split("$");
-                  const grammarGuide = grammar.map((item, id) => {
-                    const strCase = item.replaceAll(".", "");
+    <Card title="社区字典" loading={loading}>
+      <div>
+        <div key="meaning">
+          <Space style={{ flexWrap: "wrap" }}>
+            <Text strong>{"意思:"}</Text>
+            {wordData?.meaning
+              .filter((value, index: number) => isShow(value.score, index))
+              .map((item) => item.value)}
+            {meaningLow && meaningLow.length > 0 ? (
+              <Popover
+                content={<Space>{meaningExtra}</Space>}
+                placement="bottom"
+              >
+                <Link>
+                  {intl.formatMessage({
+                    id: `buttons.more`,
+                  })}
+                </Link>
+              </Popover>
+            ) : undefined}
+          </Space>
+        </div>
+        <div key="grammar">
+          <Space style={{ flexWrap: "wrap" }}>
+            <Text strong>{"语法:"}</Text>
+            {wordData?.grammar
+              .filter((value) => value.score >= minScore)
+              .map((item, id) => {
+                const grammar = item.value.split("$");
+                const grammarGuide = grammar.map((item, id) => {
+                  const strCase = item.replaceAll(".", "");
 
-                    return strCase.length > 0 ? (
-                      <GrammarPop
-                        key={id}
-                        gid={strCase}
-                        text={intl.formatMessage({
-                          id: `dict.fields.type.${strCase}.label`,
-                          defaultMessage: strCase,
-                        })}
-                      />
-                    ) : undefined;
-                  });
-                  return (
-                    <Space key={id}>
-                      <Space
-                        style={{
-                          backgroundColor: "rgba(0.5,0.5,0.5,0.2)",
-                          borderRadius: 5,
-                          paddingLeft: 5,
-                          paddingRight: 5,
-                        }}
-                      >
-                        {grammarGuide}
-                      </Space>
-                      <Badge color="geekblue" size="small" count={item.score} />
-                    </Space>
-                  );
-                })}
-            </Space>
-          </div>
-          <div key="base">
-            <Space style={{ flexWrap: "wrap" }}>
-              <Text strong>{"词干:"}</Text>
-              {wordData?.parent
-                .filter((value) => value.score >= minScore)
-                .map((item, id) => {
-                  return (
-                    <Space key={id}>
-                      {item.value}
-                      <Badge color="geekblue" size="small" count={item.score} />
+                  return strCase.length > 0 ? (
+                    <GrammarPop
+                      key={id}
+                      gid={strCase}
+                      text={intl.formatMessage({
+                        id: `dict.fields.type.${strCase}.label`,
+                        defaultMessage: strCase,
+                      })}
+                    />
+                  ) : undefined;
+                });
+                return (
+                  <Space key={id}>
+                    <Space
+                      style={{
+                        backgroundColor: "rgba(0.5,0.5,0.5,0.2)",
+                        borderRadius: 5,
+                        paddingLeft: 5,
+                        paddingRight: 5,
+                      }}
+                    >
+                      {grammarGuide}
                     </Space>
-                  );
-                })}
-            </Space>
-          </div>
-          <div key="collaborator">
-            <Space style={{ flexWrap: "wrap" }}>
-              <Text strong>{"贡献者:"}</Text>
-              {wordData?.editor
-                .filter((_value, index) => index < mainCollaboratorNum)
-                .map((item, id) => {
-                  return collaboratorRender(
-                    item.value.nickName,
-                    id,
-                    item.score
-                  );
-                })}
-              {more}
-            </Space>
-          </div>
+                  </Space>
+                );
+              })}
+          </Space>
+        </div>
+        <div key="base">
+          <Space style={{ flexWrap: "wrap" }}>
+            <Text strong>{"词干:"}</Text>
+            {wordData?.parent
+              .filter((value) => value.score >= minScore)
+              .map((item, id) => {
+                return (
+                  <Space key={id}>
+                    {item.value}
+                    <Badge color="geekblue" size="small" count={item.score} />
+                  </Space>
+                );
+              })}
+          </Space>
+        </div>
+        <div key="collaborator">
+          <Space style={{ flexWrap: "wrap" }}>
+            <Text strong>{"贡献者:"}</Text>
+            {wordData?.editor
+              .filter((_value, index) => index < mainCollaboratorNum)
+              .map((item, id) => {
+                return collaboratorRender(item.value.nickName, id, item.score);
+              })}
+            {more}
+          </Space>
+        </div>
 
-          <div key="note">
-            <Text strong>{"注释:"}</Text>
-            <div>
-              {wordData?.note
-                .filter((value) => value.score >= minScore)
-                .slice(0, 1)
-                .map((item, id) => {
-                  return <MdView html={item.value} key={id} />;
-                })}
-            </div>
+        <div key="note">
+          <Text strong>{"注释:"}</Text>
+          <div>
+            {wordData?.note
+              .filter((value) => value.score >= minScore)
+              .slice(0, 1)
+              .map((item, id) => {
+                return <MdView html={item.value} key={id} />;
+              })}
           </div>
         </div>
-      ) : showCreate ? (
+      </div>
+      {showCreate ? (
         <MyCreate
           word={word}
           onSave={() => {

+ 6 - 8
dashboard-v6/src/components/dict/WordCard.tsx

@@ -1,4 +1,4 @@
-import { Space, Typography } from "antd";
+import { Flex, Space, Typography } from "antd";
 
 import GrammarPop from "./GrammarPop";
 import WordCardByDict from "./WordCardByDict";
@@ -25,7 +25,7 @@ const WordCardWidget = ({ data }: IWidgetWordCard) => {
     });
   });
   return (
-    <>
+    <Flex gap="medium" vertical>
       <Title level={4} id={data.anchor}>
         {data.word}
       </Title>
@@ -79,12 +79,10 @@ const WordCardWidget = ({ data }: IWidgetWordCard) => {
       )}
       <Community word={data.word} />
       <TermCommunity word={data.word} />
-      <div>
-        {data.dict.map((it, id) => {
-          return <WordCardByDict key={id} data={it} />;
-        })}
-      </div>
-    </>
+      {data.dict.map((it, id) => {
+        return <WordCardByDict key={id} data={it} />;
+      })}
+    </Flex>
   );
 };
 

+ 5 - 6
dashboard-v6/src/components/dict/WordCardByDict.tsx

@@ -17,11 +17,9 @@ interface IWidgetWordCardByDict {
 }
 const WordCardByDictWidget = ({ data, children }: IWidgetWordCardByDict) => {
   return (
-    <Card>
-      <Space>
-        <Title level={5} id={data.anchor}>
-          {data.dictname}
-        </Title>
+    <Card
+      title={data.dictname}
+      extra={
         <Popover
           overlayStyle={{ maxWidth: 600 }}
           content={
@@ -67,7 +65,8 @@ const WordCardByDictWidget = ({ data, children }: IWidgetWordCardByDict) => {
         >
           <Button type="link" icon={<InfoCircleOutlined />} />
         </Popover>
-      </Space>
+      }
+    >
       <div className="dict_content">
         <MdView html={data.note} />
       </div>

+ 1 - 1
dashboard-v6/src/components/navigation/MainMenu.tsx

@@ -137,7 +137,7 @@ const Widget = ({ onSearch }: Props) => {
       activeId: "workspace.ai",
     },
     {
-      key: "/workspace/tipitaka",
+      key: "/workspace/tipitaka/lib",
       icon: <TipitakaIcon />,
       label: "巴利三藏",
       activeId: "workspace.tipitaka",

+ 1 - 0
dashboard-v6/src/components/sentence-editor/SentEdit.tsx

@@ -53,6 +53,7 @@ export interface IWidgetSentEditInner {
   commNum?: number;
   originNum: number;
   simNum?: number;
+
   compact?: boolean;
   mode?: ArticleMode;
   showWbwProgress?: boolean;

+ 4 - 4
dashboard-v6/src/components/sentence-editor/SentRead.tsx

@@ -31,14 +31,14 @@ const items: MenuProps["items"] = [
 ];
 
 export interface IWidgetSentReadFrame {
-  origin?: ISentence[];
-  translation?: ISentence[];
-  layout?: "row" | "column";
+  sentId?: string;
   book?: number;
   para?: number;
   wordStart?: number;
   wordEnd?: number;
-  sentId?: string;
+  origin?: ISentence[];
+  translation?: ISentence[];
+  layout?: "row" | "column";
   error?: string;
 }
 

+ 4 - 0
dashboard-v6/src/components/template/MdTpl.tsx

@@ -5,6 +5,7 @@ import Nissaya from "./Nissaya";
 import Note from "./Note";
 import ParaHandle from "./ParaHandle";
 import ParaShell from "./ParaShell";
+import Paragraph from "./Paragraph";
 import Quote from "./Quote";
 import Reference from "./Reference";
 import SentEdit from "./SentEdit";
@@ -54,6 +55,9 @@ const Widget = ({ tpl, props, children }: IWidgetMdTpl) => {
       return <Reference props={props ? props : ""} />;
     case "cf":
       return <Confidence props={props ? props : ""} />;
+    case "paragraph":
+      return <Paragraph props={props ? props : ""} />;
+
     default:
       return <>未定义模版({tpl})</>;
   }

+ 94 - 0
dashboard-v6/src/components/template/Paragraph.tsx

@@ -0,0 +1,94 @@
+import { useMemo } from "react";
+import { useAppSelector } from "../../hooks";
+import { currFocus } from "../../reducers/focus";
+import { ParaHandleCtl } from "./ParaHandle";
+
+interface IWidgetParaShellCtl {
+  book: number;
+  para: number;
+  mode?: string;
+  channels?: string[];
+  sentenceIds: string[];
+  children?: React.ReactNode | React.ReactNode[];
+}
+const ParagraphCtl = ({
+  book,
+  para,
+  mode = "read",
+  channels,
+  sentenceIds,
+  children,
+}: IWidgetParaShellCtl) => {
+  const focus = useAppSelector(currFocus);
+
+  const isFocus = useMemo(() => {
+    if (focus) {
+      if (focus.focus?.type === "para") {
+        if (focus.focus.id) {
+          const arrId = focus.focus.id.split("-");
+          if (arrId.length > 1) {
+            const focusBook = parseInt(arrId[0]);
+            const focusPara = arrId[1].split(",").map((item) => parseInt(item));
+            if (focusBook === book && focusPara.includes(para)) {
+              return true;
+            }
+          }
+        } else {
+          return false;
+        }
+      }
+    } else {
+      return false;
+    }
+  }, [book, focus, para]);
+
+  const borderColor = isFocus ? "#e35f00bd " : "rgba(128, 128, 128, 0.3)";
+
+  const border = mode === "read" ? "" : "2px solid " + borderColor;
+
+  return (
+    <div
+      style={{
+        border: border,
+        borderRadius: 6,
+        marginTop: 20,
+        marginBottom: 28,
+        padding: 4,
+      }}
+    >
+      <div
+        style={{
+          position: "absolute",
+          marginTop: -31,
+          marginLeft: -6,
+          border: border,
+          borderRadius: "6px",
+        }}
+      >
+        <ParaHandleCtl
+          book={book}
+          para={para}
+          mode={mode}
+          channels={channels}
+          sentences={sentenceIds}
+        />
+      </div>
+      {children}
+    </div>
+  );
+};
+
+interface IWidget {
+  props: string;
+  children?: React.ReactNode | React.ReactNode[];
+}
+const Widget = ({ props }: IWidget) => {
+  const prop = JSON.parse(atob(props)) as IWidgetParaShellCtl;
+  return (
+    <>
+      <ParagraphCtl {...prop} />
+    </>
+  );
+};
+
+export default Widget;

+ 5 - 9
dashboard-v6/src/components/term/TermCommunity.tsx

@@ -16,7 +16,7 @@ import type { ITermListResponse } from "../../api/Term";
 import { Link } from "react-router";
 import type { IUser } from "../../api/Auth";
 
-const { Title, Text } = Typography;
+const { Text } = Typography;
 
 interface IItem<R> {
   value: R;
@@ -168,14 +168,10 @@ const TermCommunityWidget = ({ word }: IWidget) => {
   ) : undefined;
 
   return show ? (
-    <Card>
-      <Space>
-        <Title level={5} id={`community`}>
-          {"社区术语"}
-        </Title>
-        <Link to={`/term/list/${word}`}>详情</Link>
-      </Space>
-
+    <Card
+      title={"社区术语"}
+      extra={<Link to={`/term/list/${word}`}>详情</Link>}
+    >
       <div key="meaning">
         <Space style={{ flexWrap: "wrap" }}>
           <Text strong>{"意思:"}</Text>