SentTab.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. import { useEffect, useState } from "react";
  2. import { Badge, Space, Tabs, Typography, message } from "antd";
  3. import {
  4. TranslationOutlined,
  5. CloseOutlined,
  6. BlockOutlined,
  7. } from "@ant-design/icons";
  8. import SentTabButton from "./SentTabButton";
  9. import SentCanRead from "./SentCanRead";
  10. import SentSim from "./SentSim";
  11. import { useIntl } from "react-intl";
  12. import TocPath, { ITocPathNode } from "../../corpus/TocPath";
  13. import { IWbw } from "../Wbw/WbwWord";
  14. import RelaGraphic from "../Wbw/RelaGraphic";
  15. import SentMenu from "./SentMenu";
  16. import { ArticleMode } from "../../article/Article";
  17. import { IResNumber } from "../SentEdit";
  18. import SentTabCopy from "./SentTabCopy";
  19. import { fullUrl } from "../../../utils";
  20. import SentWbw from "./SentWbw";
  21. import SentTabButtonWbw from "./SentTabButtonWbw";
  22. const { Text } = Typography;
  23. interface IWidget {
  24. id: string;
  25. book: number;
  26. para: number;
  27. wordStart: number;
  28. wordEnd: number;
  29. channelsId?: string[];
  30. path?: ITocPathNode[];
  31. layout?: "row" | "column";
  32. tranNum?: number;
  33. nissayaNum?: number;
  34. commNum?: number;
  35. originNum: number;
  36. simNum?: number;
  37. wbwData?: IWbw[];
  38. magicDictLoading?: boolean;
  39. compact?: boolean;
  40. mode?: ArticleMode;
  41. loadedRes?: IResNumber;
  42. onMagicDict?: Function;
  43. onCompact?: Function;
  44. onModeChange?: Function;
  45. onAffix?: Function;
  46. }
  47. const SentTabWidget = ({
  48. id,
  49. book,
  50. para,
  51. wordStart,
  52. wordEnd,
  53. channelsId,
  54. path,
  55. tranNum = 0,
  56. nissayaNum = 0,
  57. commNum = 0,
  58. originNum,
  59. simNum = 0,
  60. wbwData,
  61. magicDictLoading = false,
  62. compact = false,
  63. mode,
  64. loadedRes,
  65. onMagicDict,
  66. onCompact,
  67. onModeChange,
  68. onAffix,
  69. }: IWidget) => {
  70. const intl = useIntl();
  71. const [isCompact, setIsCompact] = useState(compact);
  72. const [hover, setHover] = useState(false);
  73. const [currKey, setCurrKey] = useState("close");
  74. const [currTranNum, setCurrTranNum] = useState(tranNum);
  75. const [currNissayaNum, setCurrNissayaNum] = useState(nissayaNum);
  76. const [currCommNum, setCurrCommNum] = useState(commNum);
  77. const [showWbwProgress, setShowWbwProgress] = useState(false);
  78. console.log("SentTabWidget render");
  79. useEffect(() => setIsCompact(compact), [compact]);
  80. const mPath = path
  81. ? [
  82. ...path,
  83. { book: book, paragraph: para, title: para.toString(), level: 100 },
  84. ]
  85. : [];
  86. if (typeof id === "undefined") {
  87. return <></>;
  88. }
  89. const sentId = id.split("_");
  90. const sId = sentId[0].split("-");
  91. const tabButtonStyle: React.CSSProperties | undefined = compact
  92. ? { visibility: hover || currKey !== "close" ? "visible" : "hidden" }
  93. : undefined;
  94. return (
  95. <Tabs
  96. onMouseEnter={() => setHover(true)}
  97. onMouseLeave={() => setHover(false)}
  98. activeKey={currKey}
  99. onChange={(activeKey: string) => {
  100. setCurrKey(activeKey);
  101. }}
  102. style={
  103. isCompact
  104. ? {
  105. position: currKey === "close" ? "absolute" : "unset",
  106. marginTop: -32,
  107. width: "100%",
  108. marginRight: 10,
  109. backgroundColor:
  110. hover || currKey !== "close"
  111. ? "rgba(128, 128, 128, 0.1)"
  112. : "unset",
  113. }
  114. : {
  115. padding: "0 8px",
  116. backgroundColor: "rgba(128, 128, 128, 0.1)",
  117. }
  118. }
  119. tabBarStyle={{ marginBottom: 0 }}
  120. size="small"
  121. tabBarGutter={0}
  122. tabBarExtraContent={
  123. <Space>
  124. <TocPath
  125. link="none"
  126. data={mPath}
  127. channels={channelsId}
  128. trigger={path ? path.length > 0 ? path[0].title : <></> : <></>}
  129. />
  130. <Text>{sentId[0]}</Text>
  131. <SentTabCopy wbwData={wbwData} text={`{{${sentId[0]}}}`} />
  132. <SentMenu
  133. book={book}
  134. para={para}
  135. loading={magicDictLoading}
  136. mode={mode}
  137. onMagicDict={(type: string) => {
  138. if (typeof onMagicDict !== "undefined") {
  139. onMagicDict(type);
  140. }
  141. }}
  142. onMenuClick={(key: string) => {
  143. switch (key) {
  144. case "compact" || "normal":
  145. if (typeof onCompact !== "undefined") {
  146. setIsCompact(true);
  147. onCompact(true);
  148. }
  149. break;
  150. case "normal":
  151. if (typeof onCompact !== "undefined") {
  152. setIsCompact(false);
  153. onCompact(false);
  154. }
  155. break;
  156. case "origin-edit":
  157. if (typeof onModeChange !== "undefined") {
  158. onModeChange("edit");
  159. }
  160. break;
  161. case "origin-wbw":
  162. if (typeof onModeChange !== "undefined") {
  163. onModeChange("wbw");
  164. }
  165. break;
  166. case "copy-id":
  167. const id = `{{${book}-${para}-${wordStart}-${wordEnd}}}`;
  168. navigator.clipboard.writeText(id).then(() => {
  169. message.success("编号已经拷贝到剪贴板");
  170. });
  171. break;
  172. case "copy-link":
  173. let link = `/article/para/${book}-${para}?mode=edit`;
  174. link += `&book=${book}&par=${para}`;
  175. if (channelsId) {
  176. link += `&channel=` + channelsId?.join("_");
  177. }
  178. link += `&focus=${book}-${para}-${wordStart}-${wordEnd}`;
  179. navigator.clipboard.writeText(fullUrl(link)).then(() => {
  180. message.success("链接地址已经拷贝到剪贴板");
  181. });
  182. break;
  183. case "affix":
  184. if (typeof onAffix !== "undefined") {
  185. onAffix();
  186. }
  187. break;
  188. default:
  189. break;
  190. }
  191. }}
  192. />
  193. </Space>
  194. }
  195. items={[
  196. {
  197. label: (
  198. <span style={tabButtonStyle}>
  199. <Badge size="small" count={0}>
  200. <CloseOutlined />
  201. </Badge>
  202. </span>
  203. ),
  204. key: "close",
  205. children: <></>,
  206. },
  207. {
  208. label: (
  209. <SentTabButton
  210. style={tabButtonStyle}
  211. icon={<TranslationOutlined />}
  212. type="translation"
  213. sentId={id}
  214. count={
  215. currTranNum
  216. ? currTranNum -
  217. (loadedRes?.translation ? loadedRes.translation : 0)
  218. : undefined
  219. }
  220. title={intl.formatMessage({
  221. id: "channel.type.translation.label",
  222. })}
  223. />
  224. ),
  225. key: "translation",
  226. children: (
  227. <SentCanRead
  228. book={parseInt(sId[0])}
  229. para={parseInt(sId[1])}
  230. wordStart={parseInt(sId[2])}
  231. wordEnd={parseInt(sId[3])}
  232. type="translation"
  233. channelsId={channelsId}
  234. onCreate={() => setCurrTranNum((origin) => origin + 1)}
  235. />
  236. ),
  237. },
  238. {
  239. label: (
  240. <SentTabButton
  241. style={tabButtonStyle}
  242. icon={<CloseOutlined />}
  243. type="nissaya"
  244. sentId={id}
  245. count={
  246. currNissayaNum
  247. ? currNissayaNum -
  248. (loadedRes?.nissaya ? loadedRes.nissaya : 0)
  249. : undefined
  250. }
  251. title={intl.formatMessage({
  252. id: "channel.type.nissaya.label",
  253. })}
  254. />
  255. ),
  256. key: "nissaya",
  257. children: (
  258. <SentCanRead
  259. book={parseInt(sId[0])}
  260. para={parseInt(sId[1])}
  261. wordStart={parseInt(sId[2])}
  262. wordEnd={parseInt(sId[3])}
  263. type="nissaya"
  264. channelsId={channelsId}
  265. onCreate={() => setCurrNissayaNum((origin) => origin + 1)}
  266. />
  267. ),
  268. },
  269. {
  270. label: (
  271. <SentTabButton
  272. style={tabButtonStyle}
  273. icon={<TranslationOutlined />}
  274. type="commentary"
  275. sentId={id}
  276. count={
  277. currCommNum
  278. ? currCommNum -
  279. (loadedRes?.commentary ? loadedRes.commentary : 0)
  280. : undefined
  281. }
  282. title={intl.formatMessage({
  283. id: "channel.type.commentary.label",
  284. })}
  285. />
  286. ),
  287. key: "commentary",
  288. children: (
  289. <SentCanRead
  290. book={parseInt(sId[0])}
  291. para={parseInt(sId[1])}
  292. wordStart={parseInt(sId[2])}
  293. wordEnd={parseInt(sId[3])}
  294. type="commentary"
  295. channelsId={channelsId}
  296. onCreate={() => setCurrCommNum((origin) => origin + 1)}
  297. />
  298. ),
  299. },
  300. /*{
  301. label: (
  302. <SentTabButton
  303. icon={<BlockOutlined />}
  304. type="original"
  305. sentId={id}
  306. count={originNum}
  307. title={intl.formatMessage({
  308. id: "channel.type.original.label",
  309. })}
  310. />
  311. ),
  312. key: "original",
  313. children: (
  314. <SentCanRead
  315. book={parseInt(sId[0])}
  316. para={parseInt(sId[1])}
  317. wordStart={parseInt(sId[2])}
  318. wordEnd={parseInt(sId[3])}
  319. type="original"
  320. />
  321. ),
  322. },*/
  323. {
  324. label: (
  325. <SentTabButton
  326. style={tabButtonStyle}
  327. icon={<BlockOutlined />}
  328. type="original"
  329. sentId={id}
  330. count={simNum}
  331. title={intl.formatMessage({
  332. id: "buttons.sim",
  333. })}
  334. />
  335. ),
  336. key: "sim",
  337. children: (
  338. <SentSim
  339. book={parseInt(sId[0])}
  340. para={parseInt(sId[1])}
  341. wordStart={parseInt(sId[2])}
  342. wordEnd={parseInt(sId[3])}
  343. channelsId={channelsId}
  344. limit={5}
  345. />
  346. ),
  347. },
  348. {
  349. label: (
  350. <SentTabButtonWbw
  351. style={tabButtonStyle}
  352. sentId={id}
  353. count={0}
  354. onMenuClick={(keyPath: string[]) => {
  355. switch (keyPath.join("-")) {
  356. case "show-progress":
  357. setShowWbwProgress((origin) => !origin);
  358. break;
  359. }
  360. }}
  361. />
  362. ),
  363. key: "wbw",
  364. children: (
  365. <SentWbw
  366. book={parseInt(sId[0])}
  367. para={parseInt(sId[1])}
  368. wordStart={parseInt(sId[2])}
  369. wordEnd={parseInt(sId[3])}
  370. channelsId={channelsId}
  371. wbwProgress={showWbwProgress}
  372. />
  373. ),
  374. },
  375. {
  376. label: <span style={tabButtonStyle}>{"关系图"}</span>,
  377. key: "relation-graphic",
  378. children: <RelaGraphic wbwData={wbwData} />,
  379. },
  380. ]}
  381. />
  382. );
  383. };
  384. export default SentTabWidget;