aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2021-03-12 17:46:27 +0800
committercrupest <crupest@outlook.com>2021-03-12 17:46:27 +0800
commit4475f2a89c2f2adf3fcc68bad4054f9710199875 (patch)
treef7cc4f6f01d403f2472849651b1dd7b9b1831b02
parent6d35c11754b3840a1debf36ce1ab8df3ec4fc491 (diff)
downloadtimeline-4475f2a89c2f2adf3fcc68bad4054f9710199875.tar.gz
timeline-4475f2a89c2f2adf3fcc68bad4054f9710199875.tar.bz2
timeline-4475f2a89c2f2adf3fcc68bad4054f9710199875.zip
...
-rw-r--r--FrontEnd/src/app/locales/en/translation.json2
-rw-r--r--FrontEnd/src/app/locales/zh/translation.json2
-rw-r--r--FrontEnd/src/app/services/TimelinePostBuilder.ts6
-rw-r--r--FrontEnd/src/app/views/timeline-common/MarkdownPostEdit.tsx116
4 files changed, 125 insertions, 1 deletions
diff --git a/FrontEnd/src/app/locales/en/translation.json b/FrontEnd/src/app/locales/en/translation.json
index 4002ee4f..5613668e 100644
--- a/FrontEnd/src/app/locales/en/translation.json
+++ b/FrontEnd/src/app/locales/en/translation.json
@@ -2,7 +2,9 @@
"welcome": "Welcome!",
"search": "Search",
"edit": "Edit",
+ "image": "Image",
"done": "Done",
+ "preview": "Preview",
"loadFailReload": "Load failed, <1>click here to reload</1>.",
"error": {
"network": "Network error.",
diff --git a/FrontEnd/src/app/locales/zh/translation.json b/FrontEnd/src/app/locales/zh/translation.json
index 3f966d7c..c73f2876 100644
--- a/FrontEnd/src/app/locales/zh/translation.json
+++ b/FrontEnd/src/app/locales/zh/translation.json
@@ -2,7 +2,9 @@
"welcome": "欢迎!",
"search": "搜索",
"edit": "编辑",
+ "image": "图片",
"done": "完成",
+ "preview": "预览",
"loadFailReload": "加载失败,<1>点击重试</1>。",
"error": {
"network": "网络错误。",
diff --git a/FrontEnd/src/app/services/TimelinePostBuilder.ts b/FrontEnd/src/app/services/TimelinePostBuilder.ts
index 8594fa49..f6c8f881 100644
--- a/FrontEnd/src/app/services/TimelinePostBuilder.ts
+++ b/FrontEnd/src/app/services/TimelinePostBuilder.ts
@@ -10,7 +10,7 @@ import { UiLogicError } from "@/common";
import { base64 } from "@/http/common";
import { HttpTimelinePostPostRequest } from "@/http/timeline";
-export class TimelinePostBuilder {
+export default class TimelinePostBuilder {
private _onChange: () => void;
private _text = "";
private _images: { file: File; url: string }[] = [];
@@ -86,6 +86,10 @@ export class TimelinePostBuilder {
this._onChange();
}
+ get text(): string {
+ return this._text;
+ }
+
get images(): { file: File; url: string }[] {
return this._images;
}
diff --git a/FrontEnd/src/app/views/timeline-common/MarkdownPostEdit.tsx b/FrontEnd/src/app/views/timeline-common/MarkdownPostEdit.tsx
new file mode 100644
index 00000000..079344e1
--- /dev/null
+++ b/FrontEnd/src/app/views/timeline-common/MarkdownPostEdit.tsx
@@ -0,0 +1,116 @@
+import React from "react";
+import { Nav, Form } from "react-bootstrap";
+import { useTranslation } from "react-i18next";
+
+import { getHttpTimelineClient, HttpTimelinePostInfo } from "@/http/timeline";
+
+import TimelinePostBuilder from "@/services/TimelinePostBuilder";
+
+export interface MarkdownPostEditProps {
+ timeline: string;
+ onPosted: (post: HttpTimelinePostInfo) => void;
+}
+
+const MarkdownPostEdit: React.FC<MarkdownPostEditProps> = ({
+ timeline: timelineName,
+ onPosted,
+}) => {
+ const { t } = useTranslation();
+
+ const [tab, setTab] = React.useState<"text" | "images" | "preview">("text");
+
+ const [process, setProcess] = React.useState<boolean>(false);
+
+ const [text, _setText] = React.useState<string>("");
+ const [images, _setImages] = React.useState<{ file: File; url: string }[]>(
+ []
+ );
+ const [previewHtml, _setPreviewHtml] = React.useState<string>("");
+
+ const _builder = React.useRef<TimelinePostBuilder | null>(null);
+
+ const getBuilder = (): TimelinePostBuilder => {
+ if (_builder.current == null) {
+ const builder = new TimelinePostBuilder(() => {
+ _setText(builder.text);
+ _setImages(builder.images);
+ _setPreviewHtml(builder.renderHtml());
+ });
+ _builder.current = builder;
+ }
+ return _builder.current;
+ };
+
+ React.useEffect(() => {
+ return () => {
+ getBuilder().dispose();
+ };
+ }, []);
+
+ const send = async (): Promise<void> => {
+ const dataList = await getBuilder().build();
+ const post = await getHttpTimelineClient().postPost(timelineName, {
+ dataList,
+ });
+ onPosted(post);
+ };
+
+ return (
+ <div>
+ <Nav variant="tabs" className="my-2">
+ <Nav.Item>
+ <Nav.Link
+ active={tab === "text"}
+ onClick={() => {
+ setTab("text");
+ }}
+ >
+ {t("edit")}
+ </Nav.Link>
+ </Nav.Item>
+ <Nav.Item>
+ <Nav.Link
+ active={tab === "images"}
+ onClick={() => {
+ setTab("images");
+ }}
+ >
+ {t("image")}
+ </Nav.Link>
+ </Nav.Item>
+ <Nav.Item>
+ <Nav.Link
+ active={tab === "preview"}
+ onClick={() => {
+ setTab("preview");
+ }}
+ >
+ {t("preview")}
+ </Nav.Link>
+ </Nav.Item>
+ </Nav>
+ <div>
+ {(() => {
+ if (tab === "text") {
+ return (
+ <Form.Control
+ as="textarea"
+ value={text}
+ disabled={process}
+ onChange={(event) => {
+ getBuilder().setMarkdownText(event.currentTarget.value);
+ }}
+ />
+ );
+ } else if (tab === "images") {
+ return <div></div>;
+ } else {
+ return <div dangerouslySetInnerHTML={{ __html: previewHtml }} />;
+ }
+ })()}
+ </div>
+ </div>
+ );
+};
+
+export default MarkdownPostEdit;