Article.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import { Card, Collapse, Modal, Space } from "antd";
  2. import { Typography } from "antd";
  3. import { useState } from "react";
  4. import Article, { type ArticleMode, ArticleType } from "../article/Article";
  5. import { Link, useSearchParams } from "react-router";
  6. import { fullUrl } from "../../utils";
  7. import { useIntl } from "react-intl";
  8. const { Text } = Typography;
  9. export type TDisplayStyle =
  10. | "modal"
  11. | "card"
  12. | "toggle"
  13. | "link"
  14. | "window"
  15. | "popover";
  16. interface IWidgetChapterCtl {
  17. type?: ArticleType;
  18. id?: string;
  19. mode?: ArticleMode;
  20. anthology?: string;
  21. book?: string;
  22. paragraphs?: string;
  23. channel?: string;
  24. parentChannels?: string[];
  25. title?: React.ReactNode;
  26. focus?: string | null;
  27. style?: TDisplayStyle;
  28. modalExtra?: React.ReactNode;
  29. }
  30. export const ArticleCtl = ({
  31. type,
  32. id,
  33. mode = "auto",
  34. anthology,
  35. channel,
  36. parentChannels,
  37. title,
  38. focus,
  39. book,
  40. paragraphs,
  41. style = "modal",
  42. modalExtra,
  43. }: IWidgetChapterCtl) => {
  44. const intl = useIntl();
  45. const [isModalOpen, setIsModalOpen] = useState(false);
  46. const [searchParams] = useSearchParams();
  47. let currMode: ArticleMode;
  48. if (mode === "auto") {
  49. if (searchParams.get("mode") !== null) {
  50. currMode = searchParams.get("mode") as ArticleMode;
  51. } else {
  52. currMode = "read";
  53. }
  54. } else {
  55. currMode = mode;
  56. }
  57. const channelsToken = channel?.split(",").map((item) => item.split("@"));
  58. channelsToken?.forEach((value) =>
  59. sessionStorage.setItem(value[0], value[1] ?? "")
  60. );
  61. const orgChannels = channel
  62. ? channel.split(",").map((item) => item.split("@")[0])
  63. : [];
  64. const strUrlChannels = searchParams.get("channel");
  65. const urlChannels = strUrlChannels ? strUrlChannels.split("_") : [];
  66. const currChannels = [...orgChannels, ...urlChannels];
  67. const showModal = () => {
  68. setIsModalOpen(true);
  69. };
  70. const handleOk = () => {
  71. setIsModalOpen(false);
  72. };
  73. const handleCancel = () => {
  74. setIsModalOpen(false);
  75. };
  76. const aTitle = title ? title : "chapter" + id;
  77. console.log("anthology", anthology, channel);
  78. const article = (
  79. <Article
  80. active={true}
  81. type={type}
  82. articleId={id}
  83. anthologyId={anthology}
  84. book={book}
  85. para={paragraphs}
  86. channelId={currChannels.join("_")}
  87. parentChannels={parentChannels}
  88. focus={focus}
  89. mode={currMode}
  90. hideInteractive={true}
  91. hideTitle={true}
  92. isSubWindow
  93. />
  94. );
  95. let output = <></>;
  96. let articleLink = `/article/${type}/${id}?mode=${currMode}`;
  97. articleLink += channel ? `&channel=${currChannels.join("_")}` : "";
  98. const OpenLink = (
  99. <Link to={articleLink} target="_blank">
  100. {intl.formatMessage(
  101. {
  102. id: "buttons.open.in.new.tab",
  103. },
  104. { item: "" }
  105. )}
  106. </Link>
  107. );
  108. switch (style) {
  109. case "modal":
  110. output = (
  111. <>
  112. <Typography.Link
  113. onClick={(event: React.MouseEvent<HTMLElement, MouseEvent>) => {
  114. if (event.ctrlKey || event.metaKey) {
  115. window.open(fullUrl(articleLink), "_blank");
  116. } else {
  117. showModal();
  118. }
  119. }}
  120. >
  121. {aTitle}
  122. </Typography.Link>
  123. <Modal
  124. width={"80%"}
  125. style={{ maxWidth: 1000, top: 20 }}
  126. title={
  127. <div
  128. style={{
  129. display: "flex",
  130. justifyContent: "space-between",
  131. marginRight: 30,
  132. }}
  133. >
  134. <Text>{aTitle}</Text>
  135. <Space>
  136. {OpenLink}
  137. {modalExtra}
  138. </Space>
  139. </div>
  140. }
  141. open={isModalOpen}
  142. onOk={handleOk}
  143. onCancel={handleCancel}
  144. footer={[]}
  145. >
  146. {article}
  147. </Modal>
  148. </>
  149. );
  150. break;
  151. case "card":
  152. output = (
  153. <Card title={aTitle} extra={OpenLink}>
  154. {article}
  155. </Card>
  156. );
  157. break;
  158. case "toggle":
  159. output = (
  160. <Collapse bordered={false}>
  161. <Collapse.Panel header={`${aTitle}`} key="parent2">
  162. {article}
  163. </Collapse.Panel>
  164. </Collapse>
  165. );
  166. break;
  167. case "link":
  168. output = OpenLink;
  169. break;
  170. case "window":
  171. output = <div style={{ width: "100%" }}>{article}</div>;
  172. break;
  173. default:
  174. break;
  175. }
  176. return output;
  177. };
  178. interface IWidget {
  179. props: string;
  180. children?: React.ReactNode;
  181. }
  182. const ArticleWidget = ({ props, _____children }: IWidget) => {
  183. const prop = JSON.parse(atob(props)) as IWidgetChapterCtl;
  184. return <ArticleCtl {...prop} />;
  185. };
  186. export default ArticleWidget;