ParaHandle.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. import { Button, Dropdown, MenuProps, message, notification } from "antd";
  2. import { useNavigate, useSearchParams } from "react-router-dom";
  3. import { fullUrl } from "../../utils";
  4. import { useIntl } from "react-intl";
  5. import { addToCart } from "./SentEdit/SentCart";
  6. import { scrollToTop } from "../../pages/library/article/show";
  7. import store from "../../store";
  8. import { modeChange } from "../../reducers/article-mode";
  9. interface IWidgetParaHandleCtl {
  10. book: number;
  11. para: number;
  12. mode?: string;
  13. channels?: string[];
  14. sentences: string[];
  15. }
  16. export const ParaHandleCtl = ({
  17. book,
  18. para,
  19. mode = "read",
  20. channels,
  21. sentences,
  22. }: IWidgetParaHandleCtl) => {
  23. const navigate = useNavigate();
  24. const [searchParams] = useSearchParams();
  25. const intl = useIntl();
  26. const items: MenuProps["items"] = [
  27. {
  28. key: "solo",
  29. label: intl.formatMessage({
  30. id: "labels.curr.paragraph.only",
  31. }),
  32. },
  33. {
  34. key: "solo-in-tab",
  35. label: intl.formatMessage({
  36. id: "labels.curr.paragraph.open",
  37. }),
  38. },
  39. {
  40. type: "divider",
  41. },
  42. {
  43. key: "mode",
  44. label: intl.formatMessage({
  45. id: "buttons.set.display.mode",
  46. }),
  47. children: [
  48. {
  49. key: "mode-translate",
  50. label: intl.formatMessage({
  51. id: "buttons.translate",
  52. }),
  53. },
  54. {
  55. key: "mode-wbw",
  56. label: intl.formatMessage({
  57. id: "buttons.wbw",
  58. }),
  59. },
  60. ],
  61. },
  62. {
  63. type: "divider",
  64. },
  65. {
  66. key: "copy-sent",
  67. label: intl.formatMessage({
  68. id: "labels.curr.paragraph.copy.tpl",
  69. }),
  70. },
  71. {
  72. key: "cart-sent",
  73. label: intl.formatMessage({
  74. id: "labels.curr.paragraph.cart.tpl",
  75. }),
  76. },
  77. {
  78. key: "quote-link-tpl",
  79. label: intl.formatMessage({
  80. id: "labels.curr.paragraph.copy.quote.link.tpl",
  81. }),
  82. children: [
  83. {
  84. key: "quote-link-tpl-c",
  85. label: intl.formatMessage({
  86. id: "labels.page.number.type.c",
  87. }),
  88. },
  89. {
  90. key: "quote-link-tpl-m",
  91. label: intl.formatMessage({
  92. id: "labels.page.number.type.M",
  93. }),
  94. },
  95. {
  96. key: "quote-link-tpl-p",
  97. label: intl.formatMessage({
  98. id: "labels.page.number.type.P",
  99. }),
  100. },
  101. {
  102. key: "quote-link-tpl-t",
  103. label: intl.formatMessage({
  104. id: "labels.page.number.type.T",
  105. }),
  106. },
  107. ],
  108. },
  109. ];
  110. const copyToClipboard = (text: string) => {
  111. navigator.clipboard.writeText(text).then(() => {
  112. message.success("链接地址已经拷贝到剪贴板");
  113. });
  114. };
  115. const onClick: MenuProps["onClick"] = (e) => {
  116. /**
  117. * TODO 临时的解决方案。以后应该从传参获取其他参数,然后reducer 通知更新。
  118. * 因为如果是Article组件被嵌入其他页面。不能直接更新浏览器,而是应该更新Article组件内部
  119. */
  120. let url = `/article/para/${book}-${para}?book=${book}&par=${para}`;
  121. let param: string[] = [];
  122. searchParams.forEach((value, key) => {
  123. if (key !== "book" && key !== "par") {
  124. param.push(`${key}=${value}`);
  125. }
  126. });
  127. if (param.length > 0) {
  128. url += "&" + param.join("&");
  129. }
  130. switch (e.key) {
  131. case "solo":
  132. navigate(url);
  133. scrollToTop();
  134. break;
  135. case "solo-in-tab":
  136. window.open(fullUrl(url), "_blank");
  137. break;
  138. case "mode-translate":
  139. store.dispatch(modeChange({ mode: "edit", id: `${book}-${para}` }));
  140. break;
  141. case "mode-wbw":
  142. store.dispatch(modeChange({ mode: "wbw", id: `${book}-${para}` }));
  143. break;
  144. case "copy-sent":
  145. copyToClipboard(sentences.map((item) => `{{${item}}}`).join(""));
  146. break;
  147. case "cart-sent":
  148. const cartData = sentences.map((item) => {
  149. return { id: `{{${item}}}`, text: `{{${item}}}` };
  150. });
  151. addToCart(cartData);
  152. notification.success({
  153. message: cartData.length + "个句子已经添加到Cart",
  154. });
  155. break;
  156. case "quote-link-tpl-c":
  157. copyToClipboard(`{{ql|type=c|book=${book}|para=${para}}}`);
  158. break;
  159. case "quote-link-tpl-m":
  160. copyToClipboard(`{{ql|type=m|book=${book}|para=${para}}}`);
  161. break;
  162. case "quote-link-tpl-p":
  163. copyToClipboard(`{{ql|type=p|book=${book}|para=${para}}}`);
  164. break;
  165. case "quote-link-tpl-t":
  166. copyToClipboard(`{{ql|type=t|book=${book}|para=${para}}}`);
  167. break;
  168. default:
  169. break;
  170. }
  171. };
  172. return (
  173. <div>
  174. <Dropdown
  175. menu={{ items, onClick }}
  176. placement="bottomLeft"
  177. trigger={["click"]}
  178. >
  179. <Button size="small" type="text">
  180. {para}
  181. </Button>
  182. </Dropdown>
  183. </div>
  184. );
  185. };
  186. interface IWidget {
  187. props: string;
  188. }
  189. const Widget = ({ props }: IWidget) => {
  190. const prop = JSON.parse(atob(props)) as IWidgetParaHandleCtl;
  191. return (
  192. <>
  193. <ParaHandleCtl {...prop} />
  194. </>
  195. );
  196. };
  197. export default Widget;