From 1552c0086c396aa89e0ad965a6cbd6c3ea70cac4 Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 15 Jun 2021 21:19:02 +0800 Subject: ... --- FrontEnd/src/index.css | 8 + FrontEnd/src/service-worker.tsx | 2 +- FrontEnd/src/views/timeline-common/Timeline.tsx | 39 +++-- .../views/timeline-common/TimelinePageTemplate.tsx | 38 +---- .../timeline-common/TimelinePagedPostListView.tsx | 2 +- .../src/views/timeline-common/TimelinePostEdit.tsx | 170 ++++++++++----------- .../views/timeline-common/TimelinePostListView.tsx | 1 - .../src/views/timeline-common/TimelinePostView.tsx | 12 +- FrontEnd/src/views/timeline-common/index.css | 3 + 9 files changed, 129 insertions(+), 146 deletions(-) (limited to 'FrontEnd/src') diff --git a/FrontEnd/src/index.css b/FrontEnd/src/index.css index e102fbb4..bcced69a 100644 --- a/FrontEnd/src/index.css +++ b/FrontEnd/src/index.css @@ -1,3 +1,11 @@ +:root { + --tl-background-color: #f8f9fa; +} + +body { + background: var(--tl-background-color); +} + .tl-color-primary { color: var(--tl-primary-color); } diff --git a/FrontEnd/src/service-worker.tsx b/FrontEnd/src/service-worker.tsx index ea8dfc32..e40124fe 100644 --- a/FrontEnd/src/service-worker.tsx +++ b/FrontEnd/src/service-worker.tsx @@ -4,7 +4,7 @@ import { Button } from "react-bootstrap"; import { pushAlert } from "./services/alert"; -if ("serviceWorker" in navigator) { +if (import.meta.env.PROD && "serviceWorker" in navigator) { let isThisTriggerUpgrade = false; const upgradeSuccessLocalStorageKey = "TIMELINE_UPGRADE_SUCCESS"; diff --git a/FrontEnd/src/views/timeline-common/Timeline.tsx b/FrontEnd/src/views/timeline-common/Timeline.tsx index 21daa5e2..90eba18f 100644 --- a/FrontEnd/src/views/timeline-common/Timeline.tsx +++ b/FrontEnd/src/views/timeline-common/Timeline.tsx @@ -6,7 +6,11 @@ import { HttpNetworkError, HttpNotFoundError, } from "@/http/common"; -import { getHttpTimelineClient, HttpTimelinePostInfo } from "@/http/timeline"; +import { + getHttpTimelineClient, + HttpTimelineInfo, + HttpTimelinePostInfo, +} from "@/http/timeline"; import { getTimelinePostUpdate$ } from "@/services/timeline"; @@ -15,6 +19,7 @@ import TimelineTop from "./TimelineTop"; import TimelineLoading from "./TimelineLoading"; import "./index.css"; +import TimelinePostEdit from "./TimelinePostEdit"; export interface TimelineProps { className?: string; @@ -31,10 +36,12 @@ const Timeline: React.FC = (props) => { const [state, setState] = React.useState< "loading" | "loaded" | "offline" | "notexist" | "forbid" | "error" >("loading"); + const [timeline, setTimeline] = React.useState(null); const [posts, setPosts] = React.useState([]); React.useEffect(() => { setState("loading"); + setTimeline(null); setPosts([]); }, [timelineName]); @@ -73,16 +80,20 @@ const Timeline: React.FC = (props) => { if (timelineName != null) { let subscribe = true; - void getHttpTimelineClient() - .listPost(timelineName) - .then( - (data) => { - if (subscribe) { - setState("loaded"); - setPosts(data); - } - }, - (error) => { + const client = getHttpTimelineClient(); + Promise.all([ + client.getTimeline(timelineName), + client.listPost(timelineName), + ]).then( + ([t, p]) => { + if (subscribe) { + setTimeline(t); + setPosts(p); + setState("loaded"); + } + }, + (error) => { + if (subscribe) { if (error instanceof HttpNetworkError) { setState("offline"); } else if (error instanceof HttpForbiddenError) { @@ -94,7 +105,8 @@ const Timeline: React.FC = (props) => { setState("error"); } } - ); + } + ); return () => { subscribe = false; @@ -137,6 +149,9 @@ const Timeline: React.FC = (props) => { posts={posts} onReload={onReload.current} /> + {timeline?.postable && ( + + )} ); } diff --git a/FrontEnd/src/views/timeline-common/TimelinePageTemplate.tsx b/FrontEnd/src/views/timeline-common/TimelinePageTemplate.tsx index 658ce502..9b9ebbc2 100644 --- a/FrontEnd/src/views/timeline-common/TimelinePageTemplate.tsx +++ b/FrontEnd/src/views/timeline-common/TimelinePageTemplate.tsx @@ -87,29 +87,12 @@ const TimelinePageTemplate: React.FC = (props) => { } }, [timeline]); - const [bottomSpaceHeight, setBottomSpaceHeight] = React.useState(0); - const [timelineReloadKey, setTimelineReloadKey] = React.useState(0); const reloadTimeline = (): void => { setTimelineReloadKey((old) => old + 1); }; - const onPostEditHeightChange = React.useCallback((height: number): void => { - setBottomSpaceHeight(height); - if (height === 0) { - const alertHost = getAlertHost(); - if (alertHost != null) { - alertHost.style.removeProperty("margin-bottom"); - } - } else { - const alertHost = getAlertHost(); - if (alertHost != null) { - alertHost.style.marginBottom = `${height}px`; - } - } - }, []); - const cardCollapseLocalStorageKey = `timeline.${timelineName}.cardCollapse`; const [cardCollapse, setCardCollapse] = React.useState(true); @@ -142,12 +125,7 @@ const TimelinePageTemplate: React.FC = (props) => { connectionStatus={connectionStatus} /> ) : null} - + {(() => { if (state === "offline") { // TODO: i18n @@ -169,20 +147,6 @@ const TimelinePageTemplate: React.FC = (props) => { } })()} - {timeline != null && timeline.postable ? ( - <> -
- - - ) : null} ); }; diff --git a/FrontEnd/src/views/timeline-common/TimelinePagedPostListView.tsx b/FrontEnd/src/views/timeline-common/TimelinePagedPostListView.tsx index 37f02a82..2cb32481 100644 --- a/FrontEnd/src/views/timeline-common/TimelinePagedPostListView.tsx +++ b/FrontEnd/src/views/timeline-common/TimelinePagedPostListView.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { HttpTimelinePostInfo } from "@/http/timeline"; +import { HttpTimelineInfo, HttpTimelinePostInfo } from "@/http/timeline"; import useScrollToTop from "@/utilities/useScrollToTop"; diff --git a/FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx b/FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx index 5f3f0345..abb04c1b 100644 --- a/FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx +++ b/FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx @@ -18,7 +18,9 @@ import { base64 } from "@/http/common"; import BlobImage from "../common/BlobImage"; import LoadingButton from "../common/LoadingButton"; import { PopupMenu } from "../common/Menu"; +import Card from "../common/Card"; import MarkdownPostEdit from "./MarkdownPostEdit"; +import TimelineLine from "./TimelineLine"; interface TimelinePostEditTextProps { text: string; @@ -110,13 +112,13 @@ const postKindIconClassNameMap: Record = { export interface TimelinePostEditProps { className?: string; + style?: React.CSSProperties; timeline: HttpTimelineInfo; onPosted: (newPost: HttpTimelinePostInfo) => void; - onHeightChange?: (height: number) => void; } const TimelinePostEdit: React.FC = (props) => { - const { timeline, onHeightChange, className, onPosted } = props; + const { timeline, style, className, onPosted } = props; const { t } = useTranslation(); @@ -138,24 +140,6 @@ const TimelinePostEdit: React.FC = (props) => { (kind === "text" && text.length !== 0) || (kind === "image" && image != null); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const containerRef = React.useRef(null!); - - const notifyHeightChange = (): void => { - if (onHeightChange) { - onHeightChange(containerRef.current.clientHeight); - } - }; - - React.useEffect(() => { - notifyHeightChange(); - return () => { - if (onHeightChange) { - onHeightChange(0); - } - }; - }); - const onPostError = (): void => { pushAlert({ type: "danger", @@ -212,78 +196,86 @@ const TimelinePostEdit: React.FC = (props) => { return (
- {showMarkdown ? ( - setShowMarkdown(false)} - timeline={timeline.name} - onPosted={onPosted} - onPostError={onPostError} - /> - ) : ( - - - {(() => { - if (kind === "text") { - return ( - { - setText(t); - window.localStorage.setItem(draftTextLocalStorageKey, t); - }} - /> - ); - } else if (kind === "image") { - return ( - + + {showMarkdown ? ( + setShowMarkdown(false)} + timeline={timeline.name} + onPosted={onPosted} + onPostError={onPostError} + /> + ) : ( + + + {(() => { + if (kind === "text") { + return ( + { + setText(t); + window.localStorage.setItem( + draftTextLocalStorageKey, + t + ); + }} + /> + ); + } else if (kind === "image") { + return ( + + ); + } + })()} + + +
+ ({ + type: "button", + text: `timeline.post.type.${kind}`, + iconClassName: postKindIconClassNameMap[kind], + onClick: () => { + if (kind === "markdown") { + setShowMarkdown(true); + } else { + setKind(kind); + } + }, + }) + )} + > + - ); - } - })()} - - -
- ({ - type: "button", - text: `timeline.post.type.${kind}`, - iconClassName: postKindIconClassNameMap[kind], - onClick: () => { - if (kind === "markdown") { - setShowMarkdown(true); - } else { - setKind(kind); - } - }, - }))} + +
+ - -
-
- - {t("timeline.send")} - - -
- )} + {t("timeline.send")} + + +
+ )} +
); }; diff --git a/FrontEnd/src/views/timeline-common/TimelinePostListView.tsx b/FrontEnd/src/views/timeline-common/TimelinePostListView.tsx index ba204b72..3213f76d 100644 --- a/FrontEnd/src/views/timeline-common/TimelinePostListView.tsx +++ b/FrontEnd/src/views/timeline-common/TimelinePostListView.tsx @@ -63,7 +63,6 @@ const TimelinePostListView: React.FC = (props) => { diff --git a/FrontEnd/src/views/timeline-common/TimelinePostView.tsx b/FrontEnd/src/views/timeline-common/TimelinePostView.tsx index ea40f80a..5572c5c3 100644 --- a/FrontEnd/src/views/timeline-common/TimelinePostView.tsx +++ b/FrontEnd/src/views/timeline-common/TimelinePostView.tsx @@ -16,7 +16,6 @@ import PostPropertyChangeDialog from "./PostPropertyChangeDialog"; export interface TimelinePostViewProps { post: HttpTimelinePostInfo; - current?: boolean; className?: string; style?: React.CSSProperties; cardStyle?: React.CSSProperties; @@ -26,7 +25,6 @@ export interface TimelinePostViewProps { const TimelinePostView: React.FC = (props) => { const { post, className, style, cardStyle, onChanged, onDeleted } = props; - const current = props.current === true; const [operationMaskVisible, setOperationMaskVisible] = React.useState(false); @@ -55,11 +53,15 @@ const TimelinePostView: React.FC = (props) => { return (
- - + + {post.editable ? (