From d9c1d512fa64ef4f8c08ca34f7a5842642879bcc Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 31 Jul 2023 00:08:48 +0800 Subject: ... --- FrontEnd/src/pages/timeline/Timeline.css | 7 - FrontEnd/src/pages/timeline/Timeline.tsx | 15 +- FrontEnd/src/pages/timeline/TimelineCard.css | 18 ++ FrontEnd/src/pages/timeline/TimelineCard.tsx | 59 ++--- .../src/pages/timeline/TimelineDeleteDialog.tsx | 4 +- .../timeline/TimelinePropertyChangeDialog.tsx | 4 +- FrontEnd/src/views/timeline/CollapseButton.tsx | 21 -- .../src/views/timeline/ConnectionStatusBadge.css | 36 --- .../src/views/timeline/ConnectionStatusBadge.tsx | 41 ---- FrontEnd/src/views/timeline/MarkdownPostEdit.css | 21 -- FrontEnd/src/views/timeline/MarkdownPostEdit.tsx | 215 ----------------- .../views/timeline/PostPropertyChangeDialog.tsx | 42 ---- FrontEnd/src/views/timeline/Timeline.css | 244 ------------------- FrontEnd/src/views/timeline/Timeline.tsx | 207 ---------------- FrontEnd/src/views/timeline/TimelineCard.tsx | 167 ------------- FrontEnd/src/views/timeline/TimelineDateLabel.tsx | 19 -- .../src/views/timeline/TimelineDeleteDialog.tsx | 61 ----- FrontEnd/src/views/timeline/TimelineEmptyItem.tsx | 25 -- FrontEnd/src/views/timeline/TimelineLine.tsx | 51 ---- FrontEnd/src/views/timeline/TimelineLoading.tsx | 16 -- FrontEnd/src/views/timeline/TimelineMember.css | 8 - FrontEnd/src/views/timeline/TimelineMember.tsx | 202 ---------------- .../src/views/timeline/TimelinePostContentView.tsx | 187 --------------- FrontEnd/src/views/timeline/TimelinePostEdit.css | 10 - FrontEnd/src/views/timeline/TimelinePostEdit.tsx | 267 --------------------- .../src/views/timeline/TimelinePostEditCard.tsx | 31 --- .../src/views/timeline/TimelinePostEditNoLogin.tsx | 18 -- .../src/views/timeline/TimelinePostListView.tsx | 76 ------ FrontEnd/src/views/timeline/TimelinePostView.tsx | 159 ------------ .../timeline/TimelinePropertyChangeDialog.tsx | 82 ------- FrontEnd/src/views/timeline/index.tsx | 23 -- 31 files changed, 55 insertions(+), 2281 deletions(-) create mode 100644 FrontEnd/src/pages/timeline/TimelineCard.css delete mode 100644 FrontEnd/src/views/timeline/CollapseButton.tsx delete mode 100644 FrontEnd/src/views/timeline/ConnectionStatusBadge.css delete mode 100644 FrontEnd/src/views/timeline/ConnectionStatusBadge.tsx delete mode 100644 FrontEnd/src/views/timeline/MarkdownPostEdit.css delete mode 100644 FrontEnd/src/views/timeline/MarkdownPostEdit.tsx delete mode 100644 FrontEnd/src/views/timeline/PostPropertyChangeDialog.tsx delete mode 100644 FrontEnd/src/views/timeline/Timeline.css delete mode 100644 FrontEnd/src/views/timeline/Timeline.tsx delete mode 100644 FrontEnd/src/views/timeline/TimelineCard.tsx delete mode 100644 FrontEnd/src/views/timeline/TimelineDateLabel.tsx delete mode 100644 FrontEnd/src/views/timeline/TimelineDeleteDialog.tsx delete mode 100644 FrontEnd/src/views/timeline/TimelineEmptyItem.tsx delete mode 100644 FrontEnd/src/views/timeline/TimelineLine.tsx delete mode 100644 FrontEnd/src/views/timeline/TimelineLoading.tsx delete mode 100644 FrontEnd/src/views/timeline/TimelineMember.css delete mode 100644 FrontEnd/src/views/timeline/TimelineMember.tsx delete mode 100644 FrontEnd/src/views/timeline/TimelinePostContentView.tsx delete mode 100644 FrontEnd/src/views/timeline/TimelinePostEdit.css delete mode 100644 FrontEnd/src/views/timeline/TimelinePostEdit.tsx delete mode 100644 FrontEnd/src/views/timeline/TimelinePostEditCard.tsx delete mode 100644 FrontEnd/src/views/timeline/TimelinePostEditNoLogin.tsx delete mode 100644 FrontEnd/src/views/timeline/TimelinePostListView.tsx delete mode 100644 FrontEnd/src/views/timeline/TimelinePostView.tsx delete mode 100644 FrontEnd/src/views/timeline/TimelinePropertyChangeDialog.tsx delete mode 100644 FrontEnd/src/views/timeline/index.tsx (limited to 'FrontEnd/src') diff --git a/FrontEnd/src/pages/timeline/Timeline.css b/FrontEnd/src/pages/timeline/Timeline.css index 4dd4fdcc..f071f163 100644 --- a/FrontEnd/src/pages/timeline/Timeline.css +++ b/FrontEnd/src/pages/timeline/Timeline.css @@ -230,13 +230,6 @@ margin-right: 0.6em; } -.timeline-card { - position: fixed; - z-index: 1029; - top: 56px; - right: 0; - margin: 0.5em; -} .timeline-top { position: sticky; diff --git a/FrontEnd/src/pages/timeline/Timeline.tsx b/FrontEnd/src/pages/timeline/Timeline.tsx index 3a7fbd00..f93e1623 100644 --- a/FrontEnd/src/pages/timeline/Timeline.tsx +++ b/FrontEnd/src/pages/timeline/Timeline.tsx @@ -41,7 +41,7 @@ const Timeline: React.FC = (props) => { const [timeline, setTimeline] = React.useState(null); const [posts, setPosts] = React.useState(null); const [signalrState, setSignalrState] = React.useState( - HubConnectionState.Connecting + HubConnectionState.Connecting, ); const [error, setError] = React.useState< "offline" | "forbid" | "notfound" | "error" | null @@ -81,7 +81,7 @@ const Timeline: React.FC = (props) => { console.error(error); setError("error"); } - } + }, ); }, [timelineOwner, timelineName, timelineReloadKey]); @@ -91,7 +91,7 @@ const Timeline: React.FC = (props) => { .then( (page) => { setPosts( - page.items.filter((p): p is HttpTimelinePostInfo => !p.deleted) + page.items.filter((p): p is HttpTimelinePostInfo => !p.deleted), ); setTotalPage(page.totalPageCount); }, @@ -106,14 +106,14 @@ const Timeline: React.FC = (props) => { console.error(error); setError("error"); } - } + }, ); }, [timelineOwner, timelineName, postsReloadKey]); React.useEffect(() => { const timelinePostUpdate$ = getTimelinePostUpdate$( timelineOwner, - timelineName + timelineName, ); const subscription = timelinePostUpdate$.subscribe(({ update, state }) => { if (update) { @@ -134,7 +134,7 @@ const Timeline: React.FC = (props) => { .then( (page) => { const ps = page.items.filter( - (p): p is HttpTimelinePostInfo => !p.deleted + (p): p is HttpTimelinePostInfo => !p.deleted, ); setPosts((old) => [...(old ?? []), ...ps]); }, @@ -149,7 +149,7 @@ const Timeline: React.FC = (props) => { console.error(error); setError("error"); } - } + }, ); }, currentPage < totalPage); @@ -183,7 +183,6 @@ const Timeline: React.FC = (props) => { {timeline == null && posts == null && } {timeline && ( void; } -const TimelineCard: React.FC = (props) => { - const { timeline, connectionStatus, onReload, className } = props; +export default function TimelineCard(props: TimelinePageCardProps) { + const { timeline, connectionStatus, onReload } = props; - const { t } = useTranslation(); + const user = useUser(); - const [dialog, setDialog] = React.useState< - "member" | "property" | "delete" | null - >(null); + const c = useC(); - const [collapse, setCollapse] = React.useState(true); + const [collapse, setCollapse] = useState(true); const toggleCollapse = (): void => { setCollapse((o) => !o); }; const isSmallScreen = useIsSmallScreen(); - const user = useUser(); + const { createDialogSwitch, dialog, dialogPropsMap, switchDialog } = + useDialog(["member", "property", "delete"]); const content = ( - <> -

+
+

{timeline.title} - {timeline.nameV2} + {timeline.nameV2}

= (props) => {

{timeline.description}

- {t(timelineVisibilityTooltipTranslationMap[timeline.visibility])} + {c(timelineVisibilityTooltipTranslationMap[timeline.visibility])}
{user != null ? ( @@ -92,7 +93,7 @@ const TimelineCard: React.FC = (props) => { setDialog("member")} + onClick={createDialogSwitch("member")} /> {timeline.manageable ? ( = (props) => { { type: "button", text: "timeline.manageItem.property", - onClick: () => setDialog("property"), + onClick: createDialogSwitch("property"), }, { type: "divider" }, { type: "button", - onClick: () => setDialog("delete"), + onClick: createDialogSwitch("delete"), color: "danger", text: "timeline.manageItem.delete", }, @@ -116,12 +117,12 @@ const TimelineCard: React.FC = (props) => { ) : null}
- +
); return ( <> - +
= (props) => { setDialog(null)} - open={dialog === "member"} onChange={onReload} + {...dialogPropsMap["member"]} /> setDialog(null)} - open={dialog === "property"} onChange={onReload} + {...dialogPropsMap["property"]} /> - setDialog(null)} - /> + ); -}; - -export default TimelineCard; +} diff --git a/FrontEnd/src/pages/timeline/TimelineDeleteDialog.tsx b/FrontEnd/src/pages/timeline/TimelineDeleteDialog.tsx index d5b22aee..0a5a2491 100644 --- a/FrontEnd/src/pages/timeline/TimelineDeleteDialog.tsx +++ b/FrontEnd/src/pages/timeline/TimelineDeleteDialog.tsx @@ -9,7 +9,7 @@ import OperationDialog from "@/views/common/dialog/OperationDialog"; interface TimelineDeleteDialog { timeline: HttpTimelineInfo; open: boolean; - close: () => void; + onClose: () => void; } const TimelineDeleteDialog: React.FC = (props) => { @@ -20,7 +20,7 @@ const TimelineDeleteDialog: React.FC = (props) => { return ( ( diff --git a/FrontEnd/src/pages/timeline/TimelinePropertyChangeDialog.tsx b/FrontEnd/src/pages/timeline/TimelinePropertyChangeDialog.tsx index e26df3eb..b57135bb 100644 --- a/FrontEnd/src/pages/timeline/TimelinePropertyChangeDialog.tsx +++ b/FrontEnd/src/pages/timeline/TimelinePropertyChangeDialog.tsx @@ -12,7 +12,7 @@ import OperationDialog from "@/views/common/dialog/OperationDialog"; export interface TimelinePropertyChangeDialogProps { open: boolean; - close: () => void; + onClose: () => void; timeline: HttpTimelineInfo; onChange: () => void; } @@ -64,7 +64,7 @@ const TimelinePropertyChangeDialog: React.FC< }, }} open={props.open} - onClose={props.close} + onClose={props.onClose} onProcess={({ title, visibility, description }) => { const req: HttpTimelinePatchRequest = {}; if (title !== timeline.title) { diff --git a/FrontEnd/src/views/timeline/CollapseButton.tsx b/FrontEnd/src/views/timeline/CollapseButton.tsx deleted file mode 100644 index 374ccc2e..00000000 --- a/FrontEnd/src/views/timeline/CollapseButton.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import * as React from "react"; - -import IconButton from "../common/button/IconButton"; - -const CollapseButton: React.FC<{ - collapse: boolean; - onClick: () => void; - className?: string; - style?: React.CSSProperties; -}> = ({ collapse, onClick, className, style }) => { - return ( - - ); -}; - -export default CollapseButton; diff --git a/FrontEnd/src/views/timeline/ConnectionStatusBadge.css b/FrontEnd/src/views/timeline/ConnectionStatusBadge.css deleted file mode 100644 index 7fe83b9b..00000000 --- a/FrontEnd/src/views/timeline/ConnectionStatusBadge.css +++ /dev/null @@ -1,36 +0,0 @@ -.connection-status-badge { - font-size: 0.8em; - border-radius: 5px; - padding: 0.1em 1em; - background-color: #eaf2ff; -} -.connection-status-badge::before { - width: 10px; - height: 10px; - border-radius: 50%; - display: inline-block; - content: ""; - margin-right: 0.6em; -} -.connection-status-badge.success { - color: #006100; -} -.connection-status-badge.success::before { - background-color: #006100; -} - -.connection-status-badge.warning { - color: #e4a700; -} - -.connection-status-badge.warning::before { - background-color: #e4a700; -} - -.connection-status-badge.danger { - color: #fd1616; -} - -.connection-status-badge.danger::before { - background-color: #fd1616; -} diff --git a/FrontEnd/src/views/timeline/ConnectionStatusBadge.tsx b/FrontEnd/src/views/timeline/ConnectionStatusBadge.tsx deleted file mode 100644 index 2b820454..00000000 --- a/FrontEnd/src/views/timeline/ConnectionStatusBadge.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import * as React from "react"; -import classnames from "classnames"; -import { HubConnectionState } from "@microsoft/signalr"; -import { useTranslation } from "react-i18next"; - -import "./ConnectionStatusBadge.css"; - -export interface ConnectionStatusBadgeProps { - status: HubConnectionState; - className?: string; - style?: React.CSSProperties; -} - -const classNameMap: Record = { - Connected: "success", - Connecting: "warning", - Disconnected: "danger", - Disconnecting: "warning", - Reconnecting: "warning", -}; - -const ConnectionStatusBadge: React.FC = (props) => { - const { status, className, style } = props; - - const { t } = useTranslation(); - - return ( -
- {t(`connectionState.${status}`)} -
- ); -}; - -export default ConnectionStatusBadge; diff --git a/FrontEnd/src/views/timeline/MarkdownPostEdit.css b/FrontEnd/src/views/timeline/MarkdownPostEdit.css deleted file mode 100644 index e36be992..00000000 --- a/FrontEnd/src/views/timeline/MarkdownPostEdit.css +++ /dev/null @@ -1,21 +0,0 @@ -.timeline-markdown-post-edit-page { - overflow: auto; - max-height: 300px; -} - -.timeline-markdown-post-edit-image-container { - position: relative; - text-align: center; - margin-bottom: 1em; -} - -.timeline-markdown-post-edit-image { - max-width: 100%; - max-height: 200px; -} - -.timeline-markdown-post-edit-image-delete-button { - position: absolute; - right: 10px; - top: 2px; -} diff --git a/FrontEnd/src/views/timeline/MarkdownPostEdit.tsx b/FrontEnd/src/views/timeline/MarkdownPostEdit.tsx deleted file mode 100644 index 6401cfaa..00000000 --- a/FrontEnd/src/views/timeline/MarkdownPostEdit.tsx +++ /dev/null @@ -1,215 +0,0 @@ -import * as React from "react"; -import classnames from "classnames"; -import { useTranslation } from "react-i18next"; - -import { getHttpTimelineClient, HttpTimelinePostInfo } from "@/http/timeline"; - -import TimelinePostBuilder from "@/services/TimelinePostBuilder"; - -import FlatButton from "../common/button/FlatButton"; -import TabPages from "../common/tab/TabPages"; -import ConfirmDialog from "../common/dialog/ConfirmDialog"; -import Spinner from "../common/Spinner"; -import IconButton from "../common/button/IconButton"; - -import "./MarkdownPostEdit.css"; - -export interface MarkdownPostEditProps { - owner: string; - timeline: string; - onPosted: (post: HttpTimelinePostInfo) => void; - onPostError: () => void; - onClose: () => void; - className?: string; - style?: React.CSSProperties; -} - -const MarkdownPostEdit: React.FC = ({ - owner: ownerUsername, - timeline: timelineName, - onPosted, - onClose, - onPostError, - className, - style, -}) => { - const { t } = useTranslation(); - - const [canLeave, setCanLeave] = React.useState(true); - - const [process, setProcess] = React.useState(false); - - const [showLeaveConfirmDialog, setShowLeaveConfirmDialog] = - React.useState(false); - - const [text, _setText] = React.useState(""); - const [images, _setImages] = React.useState<{ file: File; url: string }[]>( - [] - ); - const [previewHtml, _setPreviewHtml] = React.useState(""); - - const _builder = React.useRef(null); - - const getBuilder = (): TimelinePostBuilder => { - if (_builder.current == null) { - const builder = new TimelinePostBuilder(() => { - setCanLeave(builder.isEmpty); - _setText(builder.text); - _setImages(builder.images); - _setPreviewHtml(builder.renderHtml()); - }); - _builder.current = builder; - } - return _builder.current; - }; - - const canSend = text.length > 0; - - React.useEffect(() => { - return () => { - getBuilder().dispose(); - }; - }, []); - - React.useEffect(() => { - window.onbeforeunload = (): unknown => { - if (!canLeave) { - return t("timeline.confirmLeave"); - } - }; - - return () => { - window.onbeforeunload = null; - }; - }, [canLeave, t]); - - const send = async (): Promise => { - setProcess(true); - try { - const dataList = await getBuilder().build(); - const post = await getHttpTimelineClient().postPost( - ownerUsername, - timelineName, - { - dataList, - } - ); - onPosted(post); - onClose(); - } catch (e) { - setProcess(false); - onPostError(); - } - }; - - return ( - <> - - ) : ( -
- { - if (canLeave) { - onClose(); - } else { - setShowLeaveConfirmDialog(true); - } - }} - /> - {canSend && ( - void send()} /> - )} -
- ) - } - pages={[ - { - name: "text", - text: "edit", - page: ( -