aboutsummaryrefslogtreecommitdiff
path: root/FrontEnd/src
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2021-03-07 16:15:47 +0800
committercrupest <crupest@outlook.com>2021-03-07 16:15:47 +0800
commit486663e6b4b2aa4addc4c84d24e1ce5252941858 (patch)
treeab4e6995049a660047614f642ac7d1ba5fb62c99 /FrontEnd/src
parent7d74e849d96fa29019ef001b528df6612d93f085 (diff)
downloadtimeline-486663e6b4b2aa4addc4c84d24e1ce5252941858.tar.gz
timeline-486663e6b4b2aa4addc4c84d24e1ce5252941858.tar.bz2
timeline-486663e6b4b2aa4addc4c84d24e1ce5252941858.zip
feat: Add markdown content view.
Diffstat (limited to 'FrontEnd/src')
-rw-r--r--FrontEnd/src/app/views/timeline-common/TimelinePostContentView.tsx82
1 files changed, 79 insertions, 3 deletions
diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePostContentView.tsx b/FrontEnd/src/app/views/timeline-common/TimelinePostContentView.tsx
index 2f5d3989..d836d1db 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelinePostContentView.tsx
+++ b/FrontEnd/src/app/views/timeline-common/TimelinePostContentView.tsx
@@ -1,5 +1,8 @@
import React from "react";
import clsx from "clsx";
+import { Remarkable } from "remarkable";
+
+import { UiLogicError } from "@/common";
import { HttpNetworkError } from "@/http/common";
import { getHttpTimelineClient, HttpTimelinePostInfo } from "@/http/timeline";
@@ -81,9 +84,82 @@ const ImageView: React.FC<TimelinePostContentViewProps> = (props) => {
);
};
-const MarkdownView: React.FC<TimelinePostContentViewProps> = (_props) => {
- // TODO: Implement this.
- return <div>Unsupported now!</div>;
+const MarkdownView: React.FC<TimelinePostContentViewProps> = (props) => {
+ const { post, className, style } = props;
+
+ const _remarkable = React.useRef<Remarkable>();
+
+ const getRemarkable = (): Remarkable => {
+ if (_remarkable.current) {
+ return _remarkable.current;
+ } else {
+ _remarkable.current = new Remarkable();
+ return _remarkable.current;
+ }
+ };
+
+ const [markdown, setMarkdown] = React.useState<string | null>(null);
+ const [error, setError] = React.useState<"offline" | "error" | null>(null);
+
+ const [reloadKey, setReloadKey] = React.useState<number>(0);
+
+ React.useEffect(() => {
+ let subscribe = true;
+
+ setMarkdown(null);
+ setError(null);
+
+ void getHttpTimelineClient()
+ .getPostDataAsString(post.timelineName, post.id)
+ .then(
+ (data) => {
+ if (subscribe) setMarkdown(data);
+ },
+ (error) => {
+ if (subscribe) {
+ if (error instanceof HttpNetworkError) {
+ setError("offline");
+ } else {
+ setError("error");
+ }
+ }
+ }
+ );
+
+ return () => {
+ subscribe = false;
+ };
+ }, [post.timelineName, post.id, reloadKey]);
+
+ const markdownHtml = React.useMemo<string | null>(() => {
+ if (markdown == null) return null;
+ return getRemarkable().render(markdown);
+ }, [markdown]);
+
+ if (error != null) {
+ return (
+ <LoadFailReload
+ className={className}
+ style={style}
+ onReload={() => setReloadKey(reloadKey + 1)}
+ />
+ );
+ } else if (markdown == null) {
+ return <Skeleton />;
+ } else {
+ if (markdownHtml == null) {
+ throw new UiLogicError("Markdown is not null but markdown html is.");
+ }
+ return (
+ <div
+ className={className}
+ style={style}
+ dangerouslySetInnerHTML={{
+ __html: markdownHtml,
+ }}
+ />
+ );
+ }
};
export interface TimelinePostContentViewProps {