SentEdit.tsx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. import { Affix } from "antd";
  2. import { useEffect, useRef, useState } from "react";
  3. import type { IStudio } from "../auth/Studio";
  4. import type { IUser } from "../auth/User";
  5. import type { IChannel } from "../channel/Channel";
  6. import type { TContentType } from "../discussion/DiscussionCreate";
  7. import type { ITocPathNode } from "../../../src/components/tipitaka/TocPath";
  8. import SentContent from "./SentEdit/SentContent";
  9. import SentTab from "./SentEdit/SentTab";
  10. import type { IWbw } from "./Wbw/WbwWord";
  11. import type { ArticleMode } from "../article/Article";
  12. import type { TChannelType } from "../../api/Channel";
  13. import { useAppSelector } from "../../hooks";
  14. import { currFocus } from "../../reducers/focus";
  15. import type { ISentenceData } from "../../api/Corpus";
  16. import "./SentEdit/style.css";
  17. import SentCell from "./SentEdit/SentCell";
  18. import { settingInfo } from "../../reducers/setting";
  19. import { GetUserSetting } from "../auth/setting/default";
  20. import { SENTENCE_FIX_WIDTH } from "../../types/article";
  21. import { useSetting } from "../../hooks/useSetting";
  22. export interface IResNumber {
  23. translation?: number;
  24. nissaya?: number;
  25. commentary?: number;
  26. origin?: number;
  27. sim?: number;
  28. }
  29. export interface ISentenceId {
  30. book: number;
  31. para: number;
  32. wordStart: number;
  33. wordEnd: number;
  34. }
  35. export interface IWidgetSentEditInner {
  36. id: string;
  37. book: number;
  38. para: number;
  39. wordStart: number;
  40. wordEnd: number;
  41. channels?: string[];
  42. origin?: ISentence[];
  43. translation?: ISentence[];
  44. commentaries?: ISentence[];
  45. answer?: ISentence;
  46. path?: ITocPathNode[];
  47. layout?: "row" | "column";
  48. tranNum?: number;
  49. nissayaNum?: number;
  50. commNum?: number;
  51. originNum: number;
  52. simNum?: number;
  53. compact?: boolean;
  54. mode?: ArticleMode;
  55. showWbwProgress?: boolean;
  56. readonly?: boolean;
  57. wbwProgress?: number;
  58. wbwScore?: number;
  59. onTranslationChange?: (data: ISentence) => void;
  60. }
  61. export const SentEditInner = ({
  62. id,
  63. book,
  64. para,
  65. wordStart,
  66. wordEnd,
  67. ___channels,
  68. origin,
  69. translation,
  70. answer,
  71. path,
  72. layout = "column",
  73. tranNum,
  74. nissayaNum,
  75. commNum,
  76. originNum,
  77. simNum,
  78. compact = false,
  79. mode,
  80. showWbwProgress = false,
  81. readonly = false,
  82. commentaries,
  83. onTranslationChange,
  84. }: IWidgetSentEditInner) => {
  85. const [wbwData, setWbwData] = useState<IWbw[]>();
  86. const [magicDict, setMagicDict] = useState<string>();
  87. const [magicDictLoading, setMagicDictLoading] = useState(false);
  88. const [isCompact, setIsCompact] = useState(compact);
  89. const [articleMode, setArticleMode] = useState<ArticleMode | undefined>(mode);
  90. const [loadedRes, setLoadedRes] = useState<IResNumber>();
  91. const [isFocus, setIsFocus] = useState(false);
  92. const focus = useAppSelector(currFocus);
  93. const divRef = useRef<HTMLDivElement>(null);
  94. const [affix, setAffix] = useState<boolean>(false);
  95. const settings = useAppSelector(settingInfo);
  96. const [commentaryLayout, setCommentaryLayout] = useState("column");
  97. const rootFixed = useSetting("setting.layout.root.fixed");
  98. useEffect(() => {
  99. const layoutCommentary = GetUserSetting(
  100. "setting.layout.commentary",
  101. settings
  102. );
  103. layoutCommentary &&
  104. typeof layoutCommentary === "string" &&
  105. setCommentaryLayout(layoutCommentary);
  106. }, [settings]);
  107. useEffect(() => {
  108. if (focus) {
  109. if (focus.focus?.type === "sentence") {
  110. if (focus.focus.id === id) {
  111. setIsFocus(true);
  112. divRef.current?.scrollIntoView({
  113. behavior: "smooth",
  114. block: "nearest",
  115. inline: "nearest",
  116. });
  117. } else {
  118. setIsFocus(false);
  119. }
  120. }
  121. } else {
  122. setIsFocus(false);
  123. }
  124. }, [focus, id]);
  125. useEffect(() => {
  126. const validRes = (value: ISentence, type: TChannelType) =>
  127. value.channel.type === type &&
  128. value.content &&
  129. value.content.trim().length > 0;
  130. if (translation) {
  131. const res = {
  132. translation: translation.filter((value) =>
  133. validRes(value, "translation")
  134. ).length,
  135. nissaya: translation.filter((value) => validRes(value, "nissaya"))
  136. .length,
  137. commentary: translation.filter((value) => validRes(value, "commentary"))
  138. .length,
  139. };
  140. setLoadedRes(res);
  141. }
  142. }, [translation]);
  143. useEffect(() => {
  144. const content = origin?.find(
  145. (value) => value.contentType === "json"
  146. )?.content;
  147. if (content) {
  148. setWbwData(JSON.parse(content));
  149. }
  150. }, []);
  151. const channelsId = translation?.map((item) => item.channel.id);
  152. const content = (
  153. <SentContent
  154. sid={id}
  155. book={book}
  156. para={para}
  157. wordStart={wordStart}
  158. wordEnd={wordEnd}
  159. origin={origin}
  160. translation={translation}
  161. answer={answer}
  162. layout={layout}
  163. magicDict={magicDict}
  164. compact={isCompact}
  165. mode={articleMode}
  166. wbwProgress={showWbwProgress}
  167. readonly={readonly}
  168. onWbwChange={(data: IWbw[]) => {
  169. setWbwData(data);
  170. }}
  171. onMagicDictDone={() => {
  172. setMagicDictLoading(false);
  173. setMagicDict(undefined);
  174. }}
  175. onTranslationChange={onTranslationChange}
  176. />
  177. );
  178. return (
  179. <div
  180. ref={divRef}
  181. className={`sent-edit-inner` + (isFocus ? " sent-focus" : "")}
  182. style={{
  183. display: commentaryLayout === "column" ? "block" : "flex",
  184. width: commentaryLayout === "column" ? "100%" : SENTENCE_FIX_WIDTH,
  185. }}
  186. >
  187. <div>
  188. {affix || rootFixed === true ? (
  189. <Affix offsetTop={44}>
  190. <div className="affix">{content}</div>
  191. </Affix>
  192. ) : (
  193. content
  194. )}
  195. <div
  196. style={{
  197. width: commentaryLayout === "column" ? "unset" : SENTENCE_FIX_WIDTH,
  198. }}
  199. >
  200. <SentTab
  201. id={id}
  202. book={book}
  203. para={para}
  204. wordStart={wordStart}
  205. wordEnd={wordEnd}
  206. channelsId={channelsId}
  207. path={path}
  208. tranNum={tranNum}
  209. nissayaNum={nissayaNum}
  210. commNum={commNum}
  211. originNum={originNum}
  212. simNum={simNum}
  213. loadedRes={loadedRes}
  214. wbwData={wbwData}
  215. origin={origin}
  216. magicDictLoading={magicDictLoading}
  217. compact={isCompact}
  218. mode={articleMode}
  219. onMagicDict={(type: string) => {
  220. setMagicDict(type);
  221. setMagicDictLoading(true);
  222. }}
  223. onCompact={(value: boolean) => setIsCompact(value)}
  224. onModeChange={(value: ArticleMode | undefined) =>
  225. setArticleMode(value)
  226. }
  227. onAffix={() => setAffix(!affix)}
  228. />
  229. </div>
  230. </div>
  231. <div className="pcd_sent_commentary">
  232. {commentaries?.map((item, id) => {
  233. return (
  234. <SentCell
  235. value={item}
  236. key={id}
  237. isPr={false}
  238. editMode={item.openInEditMode}
  239. />
  240. );
  241. })}
  242. </div>
  243. </div>
  244. );
  245. };
  246. interface IWidgetSentEdit {
  247. props: string;
  248. }
  249. const Widget = ({ props }: IWidgetSentEdit) => {
  250. const prop = JSON.parse(atob(props)) as IWidgetSentEditInner;
  251. //console.log("sent data", prop);
  252. return <SentEditInner {...prop} />;
  253. };
  254. export default Widget;