2
0

SentEditMenu.tsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. import { Button, Dropdown, Tooltip, message } from "antd";
  2. import { useState } from "react";
  3. import {
  4. EditOutlined,
  5. CopyOutlined,
  6. MoreOutlined,
  7. FieldTimeOutlined,
  8. LinkOutlined,
  9. FileMarkdownOutlined,
  10. DeleteOutlined,
  11. ReloadOutlined,
  12. } from "@ant-design/icons";
  13. import type { MenuProps } from "antd";
  14. import type { ISentence } from "../SentEdit"
  15. import SentHistoryModal from "../../corpus/SentHistoryModal";
  16. import {
  17. CommentOutlinedIcon,
  18. HandOutlinedIcon,
  19. JsonOutlinedIcon,
  20. MergeIcon2,
  21. PasteOutLinedIcon,
  22. } from "../../../assets/icon";
  23. import { useIntl } from "react-intl";
  24. import { fullUrl } from "../../../utils";
  25. interface IWidget {
  26. data?: ISentence;
  27. children?: React.ReactNode;
  28. isPr?: boolean;
  29. onModeChange?: Function;
  30. onConvert?: Function;
  31. onMenuClick?: Function;
  32. }
  33. const SentEditMenuWidget = ({
  34. data,
  35. children,
  36. isPr = false,
  37. onModeChange,
  38. onConvert,
  39. onMenuClick,
  40. }: IWidget) => {
  41. const [isHover, setIsHover] = useState(false);
  42. const [timelineOpen, setTimelineOpen] = useState(false);
  43. const intl = useIntl();
  44. const onClick: MenuProps["onClick"] = (e) => {
  45. if (typeof onMenuClick !== "undefined") {
  46. onMenuClick(e.key);
  47. }
  48. switch (e.key) {
  49. case "json":
  50. if (typeof onConvert !== "undefined") {
  51. onConvert("json");
  52. }
  53. break;
  54. case "markdown":
  55. if (typeof onConvert !== "undefined") {
  56. onConvert("markdown");
  57. }
  58. break;
  59. case "timeline":
  60. setTimelineOpen(true);
  61. break;
  62. case "refresh":
  63. break;
  64. case "copy-link":
  65. if (data) {
  66. let link = `/article/para/${data.book}-${data.para}?mode=edit`;
  67. link += `&book=${data.book}&par=${data.para}`;
  68. link += `&channel=${data.channel.id}`;
  69. link += `&focus=${data.book}-${data.para}-${data.wordStart}-${data.wordEnd}`;
  70. navigator.clipboard.writeText(fullUrl(link)).then(() => {
  71. message.success("链接地址已经拷贝到剪贴板");
  72. });
  73. }
  74. break;
  75. default:
  76. break;
  77. }
  78. };
  79. const items: MenuProps["items"] = [
  80. {
  81. key: "refresh",
  82. label: intl.formatMessage({
  83. id: "buttons.refresh",
  84. }),
  85. icon: <ReloadOutlined />,
  86. },
  87. {
  88. key: "timeline",
  89. label: intl.formatMessage({
  90. id: "buttons.timeline",
  91. }),
  92. icon: <FieldTimeOutlined />,
  93. disabled: isPr,
  94. },
  95. {
  96. key: "copy-to",
  97. label: intl.formatMessage({
  98. id: "buttons.copy.to",
  99. }),
  100. icon: <MergeIcon2 />,
  101. disabled: isPr,
  102. },
  103. {
  104. type: "divider",
  105. },
  106. {
  107. key: "suggestion",
  108. label: "suggestion",
  109. icon: <HandOutlinedIcon />,
  110. disabled: isPr,
  111. },
  112. {
  113. key: "discussion",
  114. label: "discussion",
  115. icon: <CommentOutlinedIcon />,
  116. disabled: isPr,
  117. },
  118. {
  119. type: "divider",
  120. },
  121. {
  122. key: "markdown",
  123. label: "To Markdown",
  124. icon: <FileMarkdownOutlined />,
  125. disabled: !data || data.contentType === "markdown" || isPr,
  126. },
  127. {
  128. key: "json",
  129. label: "To Json",
  130. icon: <JsonOutlinedIcon />,
  131. disabled:
  132. !data ||
  133. data.channel.type !== "nissaya" ||
  134. data.contentType === "json" ||
  135. isPr,
  136. },
  137. {
  138. type: "divider",
  139. },
  140. {
  141. key: "copy-link",
  142. label: intl.formatMessage({
  143. id: "buttons.copy.link",
  144. }),
  145. icon: <LinkOutlined />,
  146. },
  147. {
  148. key: "delete",
  149. label: intl.formatMessage({
  150. id: "buttons.delete",
  151. }),
  152. icon: <DeleteOutlined />,
  153. danger: true,
  154. disabled: !isPr,
  155. },
  156. ];
  157. const buttonStyle = { backgroundColor: "rgba(1,1,1,0)", marginRight: 2 };
  158. return (
  159. <div
  160. style={{ position: "relative" }}
  161. onMouseEnter={() => {
  162. setIsHover(true);
  163. }}
  164. onMouseLeave={() => {
  165. setIsHover(false);
  166. }}
  167. >
  168. <SentHistoryModal
  169. open={timelineOpen}
  170. onClose={() => setTimelineOpen(false)}
  171. sentId={data?.id}
  172. />
  173. <div
  174. style={{
  175. marginTop: -22,
  176. right: 30,
  177. padding: 4,
  178. border: "1px solid black",
  179. borderRadius: 4,
  180. backgroundColor: "rgb(239 239 206)",
  181. position: "absolute",
  182. display: isHover ? "block" : "none",
  183. }}
  184. >
  185. <Tooltip
  186. title={intl.formatMessage({
  187. id: "buttons.edit",
  188. })}
  189. >
  190. <Button
  191. icon={<EditOutlined />}
  192. size="small"
  193. style={buttonStyle}
  194. onClick={() => {
  195. if (typeof onModeChange !== "undefined") {
  196. onModeChange("edit");
  197. }
  198. }}
  199. />
  200. </Tooltip>
  201. <Tooltip
  202. title={intl.formatMessage({
  203. id: "buttons.copy",
  204. })}
  205. >
  206. <Button
  207. icon={<CopyOutlined />}
  208. style={buttonStyle}
  209. size="small"
  210. onClick={() => {
  211. if (data?.content) {
  212. navigator.clipboard.writeText(data.content).then(() => {
  213. message.success("已经拷贝到剪贴板");
  214. });
  215. } else {
  216. message.success("内容为空");
  217. }
  218. }}
  219. />
  220. </Tooltip>
  221. <Tooltip
  222. title={intl.formatMessage({
  223. id: "buttons.paste",
  224. })}
  225. >
  226. <Button
  227. icon={<PasteOutLinedIcon />}
  228. size="small"
  229. style={buttonStyle}
  230. onClick={() => {
  231. if (typeof onMenuClick !== "undefined") {
  232. onMenuClick("paste");
  233. }
  234. }}
  235. />
  236. </Tooltip>
  237. <Dropdown
  238. disabled={data ? false : true}
  239. menu={{ items, onClick }}
  240. placement="bottomRight"
  241. >
  242. <Button icon={<MoreOutlined />} size="small" style={buttonStyle} />
  243. </Dropdown>
  244. </div>
  245. <div
  246. style={{
  247. border: isHover ? "1px solid black" : "1px solid rgba(1,1,1,0)",
  248. borderRadius: 4,
  249. }}
  250. >
  251. {children}
  252. </div>
  253. </div>
  254. );
  255. };
  256. export default SentEditMenuWidget;