diff options
author | crupest <crupest@outlook.com> | 2021-03-07 16:48:51 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2021-03-07 16:48:51 +0800 |
commit | 28d3fe8bb0a60402ed09ab3c208b577d0607324c (patch) | |
tree | 623ef95fbd5fa703d66812dad8fe6998defb7264 | |
parent | 486663e6b4b2aa4addc4c84d24e1ce5252941858 (diff) | |
download | timeline-28d3fe8bb0a60402ed09ab3c208b577d0607324c.tar.gz timeline-28d3fe8bb0a60402ed09ab3c208b577d0607324c.tar.bz2 timeline-28d3fe8bb0a60402ed09ab3c208b577d0607324c.zip |
...
-rw-r--r-- | FrontEnd/src/app/views/timeline-common/TimelinePostEdit.tsx | 135 |
1 files changed, 98 insertions, 37 deletions
diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePostEdit.tsx b/FrontEnd/src/app/views/timeline-common/TimelinePostEdit.tsx index 5bc5b166..efe5a6ff 100644 --- a/FrontEnd/src/app/views/timeline-common/TimelinePostEdit.tsx +++ b/FrontEnd/src/app/views/timeline-common/TimelinePostEdit.tsx @@ -18,12 +18,38 @@ import { base64 } from "@/http/common"; import BlobImage from "../common/BlobImage"; import LoadingButton from "../common/LoadingButton"; +interface TimelinePostEditTextProps { + text: string; + disabled: boolean; + onChange: (text: string) => void; + className?: string; + style?: React.CSSProperties; +} + +const TimelinePostEditText: React.FC<TimelinePostEditTextProps> = (props) => { + const { text, disabled, onChange, className, style } = props; + + return ( + <Form.Control + as="textarea" + value={text} + disabled={disabled} + onChange={(event) => { + onChange(event.target.value); + }} + className={className} + style={style} + /> + ); +}; + interface TimelinePostEditImageProps { onSelect: (file: File | null) => void; + disabled: boolean; } const TimelinePostEditImage: React.FC<TimelinePostEditImageProps> = (props) => { - const { onSelect } = props; + const { onSelect, disabled } = props; const { t } = useTranslation(); @@ -47,6 +73,7 @@ const TimelinePostEditImage: React.FC<TimelinePostEditImageProps> = (props) => { label={t("chooseImage")} onChange={onInputChange} accept="image/*" + disabled={disabled} className="mx-3 my-1 d-inline-block" /> {file != null && !error && ( @@ -78,15 +105,24 @@ const TimelinePostEdit: React.FC<TimelinePostEditProps> = (props) => { const { t } = useTranslation(); const [process, setProcess] = React.useState<boolean>(false); - const [kind, setKind] = React.useState<"text" | "image">("text"); + + type PostKind = "text" | "markdown" | "image"; + + const [kind, setKind] = React.useState<PostKind>("text"); + const [text, setText] = React.useState<string>(""); + const [markdown, setMarkdown] = React.useState<string>(""); const [image, setImage] = React.useState<File | null>(null); - const draftLocalStorageKey = `timeline.${timeline.name}.postDraft`; + const draftTextLocalStorageKey = `timeline.${timeline.name}.postDraft.text`; + const draftMarkdownLocalStorageKey = `timeline.${timeline.name}.postDraft.markdown`; React.useEffect(() => { - setText(window.localStorage.getItem(draftLocalStorageKey) ?? ""); - }, [draftLocalStorageKey]); + setText(window.localStorage.getItem(draftTextLocalStorageKey) ?? ""); + setMarkdown( + window.localStorage.getItem(draftMarkdownLocalStorageKey) ?? "" + ); + }, [draftTextLocalStorageKey, draftMarkdownLocalStorageKey]); const canSend = (kind === "text" && text.length !== 0) || @@ -102,9 +138,7 @@ const TimelinePostEdit: React.FC<TimelinePostEditProps> = (props) => { }; React.useEffect(() => { - if (onHeightChange) { - onHeightChange(containerRef.current.clientHeight); - } + notifyHeightChange(); return () => { if (onHeightChange) { onHeightChange(0); @@ -112,11 +146,6 @@ const TimelinePostEdit: React.FC<TimelinePostEditProps> = (props) => { }; }); - const toggleKind = React.useCallback(() => { - setKind((oldKind) => (oldKind === "text" ? "image" : "text")); - setImage(null); - }, []); - const onSend = async (): Promise<void> => { setProcess(true); @@ -128,6 +157,12 @@ const TimelinePostEdit: React.FC<TimelinePostEditProps> = (props) => { data: await base64(new Blob([text])), }; break; + case "markdown": + requestData = { + contentType: "text/markdown", + data: await base64(new Blob([markdown])), + }; + break; case "image": if (image == null) { throw new UiLogicError( @@ -151,7 +186,10 @@ const TimelinePostEdit: React.FC<TimelinePostEditProps> = (props) => { (data) => { if (kind === "text") { setText(""); - window.localStorage.removeItem(draftLocalStorageKey); + window.localStorage.removeItem(draftTextLocalStorageKey); + } else if (kind === "markdown") { + setMarkdown(""); + window.localStorage.removeItem(draftMarkdownLocalStorageKey); } setProcess(false); setKind("text"); @@ -174,32 +212,55 @@ const TimelinePostEdit: React.FC<TimelinePostEditProps> = (props) => { > <Row> <Col className="px-1 py-1"> - {kind === "text" ? ( - <Form.Control - as="textarea" - className="w-100 h-100 timeline-post-edit" - value={text} - disabled={process} - onChange={(event: React.ChangeEvent<HTMLTextAreaElement>) => { - const value = event.currentTarget.value; - setText(value); - window.localStorage.setItem(draftLocalStorageKey, value); - }} - /> - ) : ( - <TimelinePostEditImage onSelect={setImage} /> - )} + {(() => { + if (kind === "text") { + return ( + <TimelinePostEditText + className="w-100 h-100 timeline-post-edit" + text={text} + disabled={process} + onChange={(t) => { + setText(t); + window.localStorage.setItem(draftTextLocalStorageKey, t); + }} + /> + ); + } else if (kind === "image") { + return ( + <TimelinePostEditImage onSelect={setImage} disabled={process} /> + ); + } else if (kind === "markdown") { + return ( + <TimelinePostEditText + className="w-100 h-100 timeline-post-edit" + text={markdown} + disabled={process} + onChange={(t) => { + setMarkdown(t); + window.localStorage.setItem( + draftMarkdownLocalStorageKey, + t + ); + }} + /> + ); + } + })()} </Col> <Col xs="auto" className="align-self-end m-1"> <div className="d-block text-center mt-1 mb-2"> - <i - onLoad={notifyHeightChange} - className={clsx( - kind === "text" ? "bi-image" : "bi-card-text", - "icon-button" - )} - onClick={process ? undefined : toggleKind} - /> + <Form.Control + as="select" + value={kind} + onChange={(event) => { + const { value } = event.currentTarget; + setKind(value as PostKind); + }} + > + <option value="text">text</option> + <option value="image">image</option> + <option value="markdown">markdown</option> + </Form.Control> </div> <LoadingButton variant="primary" |