From 72f07aeaf0be1ac9fcef627f1ab9f43cd5a4bc8d Mon Sep 17 00:00:00 2001 From: crupest Date: Sat, 19 Dec 2020 21:42:58 +0800 Subject: ... --- FrontEnd/src/app/views/home/BoardWithUser.tsx | 70 +++++++-------------------- 1 file changed, 17 insertions(+), 53 deletions(-) (limited to 'FrontEnd/src/app/views/home') diff --git a/FrontEnd/src/app/views/home/BoardWithUser.tsx b/FrontEnd/src/app/views/home/BoardWithUser.tsx index bbef835a..16648820 100644 --- a/FrontEnd/src/app/views/home/BoardWithUser.tsx +++ b/FrontEnd/src/app/views/home/BoardWithUser.tsx @@ -12,87 +12,51 @@ import OfflineBoard from "./OfflineBoard"; const BoardWithUser: React.FC<{ user: AuthUser }> = ({ user }) => { const { t } = useTranslation(); - const [ownTimelines, setOwnTimelines] = React.useState< + const [relatedTimelines, setRelatedTimelines] = React.useState< TimelineInfo[] | "offline" | "loading" >("loading"); - const [joinTimelines, setJoinTimelines] = React.useState< - TimelineInfo[] | "offline" | "loading" - >("loading"); - - React.useEffect(() => { - let subscribe = true; - if (ownTimelines === "loading") { - void getHttpTimelineClient() - .listTimeline({ relate: user.username, relateType: "own" }) - .then( - (timelines) => { - if (subscribe) { - setOwnTimelines(timelines); - } - }, - () => { - setOwnTimelines("offline"); - } - ); - } - return () => { - subscribe = false; - }; - }, [user, ownTimelines]); React.useEffect(() => { let subscribe = true; - if (joinTimelines === "loading") { + if (relatedTimelines === "loading") { void getHttpTimelineClient() - .listTimeline({ relate: user.username, relateType: "join" }) + .listTimeline({ relate: user.username }) .then( (timelines) => { if (subscribe) { - setJoinTimelines(timelines); + setRelatedTimelines(timelines); } }, () => { - setJoinTimelines("offline"); + setRelatedTimelines("offline"); } ); } return () => { subscribe = false; }; - }, [user, joinTimelines]); + }, [user, relatedTimelines]); return ( - {ownTimelines === "offline" && joinTimelines === "offline" ? ( + {relatedTimelines === "offline" ? ( { - setOwnTimelines("loading"); - setJoinTimelines("loading"); + setRelatedTimelines("loading"); }} /> ) : ( - <> - - { - setOwnTimelines("loading"); - }} - /> - - - { - setJoinTimelines("loading"); - }} - /> - - + + { + setRelatedTimelines("loading"); + }} + /> + )} ); -- cgit v1.2.3 From 36c25327415441d32c4a3535b919704be3ddd36e Mon Sep 17 00:00:00 2001 From: crupest Date: Sat, 19 Dec 2020 22:04:25 +0800 Subject: ... --- FrontEnd/src/app/locales/en/translation.json | 5 +- FrontEnd/src/app/locales/zh/translation.json | 5 +- FrontEnd/src/app/views/home/BoardWithUser.tsx | 61 ++++++------------------ FrontEnd/src/app/views/home/BoardWithoutUser.tsx | 61 +++++++----------------- FrontEnd/src/app/views/home/TimelineBoard.tsx | 50 ++++++++++++++++++- 5 files changed, 84 insertions(+), 98 deletions(-) (limited to 'FrontEnd/src/app/views/home') diff --git a/FrontEnd/src/app/locales/en/translation.json b/FrontEnd/src/app/locales/en/translation.json index f07efafe..be80d21e 100644 --- a/FrontEnd/src/app/locales/en/translation.json +++ b/FrontEnd/src/app/locales/en/translation.json @@ -20,10 +20,9 @@ "loadImageError": "Failed to load image.", "home": { "go": "Go!", - "allTimeline": "All Timelines", + "highlightTimeline": "Highlight Timelines", "relatedTimeline": "Timelines Related To You", - "joinTimeline": "Joined Timelines", - "ownTimeline": "Owned Timelines", + "publicTimeline": "Public Timelines", "offlinePrompt": "Oh oh, it seems you are offline. Here list some timelines cached locally. You can view them or click <1>here to refresh.", "createButton": "Create Timeline", "createDialog": { diff --git a/FrontEnd/src/app/locales/zh/translation.json b/FrontEnd/src/app/locales/zh/translation.json index 5991f3cd..8c925eb9 100644 --- a/FrontEnd/src/app/locales/zh/translation.json +++ b/FrontEnd/src/app/locales/zh/translation.json @@ -20,10 +20,9 @@ "loadImageError": "加载图片失败", "home": { "go": "冲!", - "allTimeline": "所有的时间线", + "highlightTimeline": "高光时间线", "relatedTimeline": "关于你的时间线", - "joinTimeline": "加入的时间线", - "ownTimeline": "拥有的时间线", + "publicTimeline": "公开时间线", "offlinePrompt": "你好像处于离线状态。以下是一些缓存在本地的时间线。你可以查看它们或者<1>点击重新获取在线信息。", "createButton": "创建时间线", "createDialog": { diff --git a/FrontEnd/src/app/views/home/BoardWithUser.tsx b/FrontEnd/src/app/views/home/BoardWithUser.tsx index 16648820..9b2f395d 100644 --- a/FrontEnd/src/app/views/home/BoardWithUser.tsx +++ b/FrontEnd/src/app/views/home/BoardWithUser.tsx @@ -3,61 +3,30 @@ import { Row, Col } from "react-bootstrap"; import { useTranslation } from "react-i18next"; import { AuthUser } from "@/services/user"; -import { TimelineInfo } from "@/services/timeline"; +import { getHttpHighlightClient } from "@/http/highlight"; import { getHttpTimelineClient } from "@/http/timeline"; import TimelineBoard from "./TimelineBoard"; -import OfflineBoard from "./OfflineBoard"; const BoardWithUser: React.FC<{ user: AuthUser }> = ({ user }) => { const { t } = useTranslation(); - const [relatedTimelines, setRelatedTimelines] = React.useState< - TimelineInfo[] | "offline" | "loading" - >("loading"); - - React.useEffect(() => { - let subscribe = true; - if (relatedTimelines === "loading") { - void getHttpTimelineClient() - .listTimeline({ relate: user.username }) - .then( - (timelines) => { - if (subscribe) { - setRelatedTimelines(timelines); - } - }, - () => { - setRelatedTimelines("offline"); - } - ); - } - return () => { - subscribe = false; - }; - }, [user, relatedTimelines]); - return ( - {relatedTimelines === "offline" ? ( - - { - setRelatedTimelines("loading"); - }} - /> - - ) : ( - - { - setRelatedTimelines("loading"); - }} - /> - - )} + + getHttpHighlightClient().list()} + /> + + + + getHttpTimelineClient().listTimeline({ relate: user.username }) + } + /> + ); }; diff --git a/FrontEnd/src/app/views/home/BoardWithoutUser.tsx b/FrontEnd/src/app/views/home/BoardWithoutUser.tsx index 7e30f799..ad88af7a 100644 --- a/FrontEnd/src/app/views/home/BoardWithoutUser.tsx +++ b/FrontEnd/src/app/views/home/BoardWithoutUser.tsx @@ -1,58 +1,31 @@ import React from "react"; import { Row, Col } from "react-bootstrap"; +import { useTranslation } from "react-i18next"; -import { TimelineInfo } from "@/services/timeline"; +import { getHttpHighlightClient } from "@/http/highlight"; import { getHttpTimelineClient } from "@/http/timeline"; import TimelineBoard from "./TimelineBoard"; -import OfflineBoard from "./OfflineBoard"; const BoardWithoutUser: React.FC = () => { - const [publicTimelines, setPublicTimelines] = React.useState< - TimelineInfo[] | "offline" | "loading" - >("loading"); - - React.useEffect(() => { - let subscribe = true; - if (publicTimelines === "loading") { - void getHttpTimelineClient() - .listTimeline({ visibility: "Public" }) - .then( - (timelines) => { - if (subscribe) { - setPublicTimelines(timelines); - } - }, - () => { - setPublicTimelines("offline"); - } - ); - } - return () => { - subscribe = false; - }; - }, [publicTimelines]); + const { t } = useTranslation(); return ( - {publicTimelines === "offline" ? ( - - { - setPublicTimelines("loading"); - }} - /> - - ) : ( - - { - setPublicTimelines("loading"); - }} - /> - - )} + + getHttpHighlightClient().list()} + /> + + + + getHttpTimelineClient().listTimeline({ visibility: "Public" }) + } + /> + ); }; diff --git a/FrontEnd/src/app/views/home/TimelineBoard.tsx b/FrontEnd/src/app/views/home/TimelineBoard.tsx index c2a7e5fe..ae7783e6 100644 --- a/FrontEnd/src/app/views/home/TimelineBoard.tsx +++ b/FrontEnd/src/app/views/home/TimelineBoard.tsx @@ -8,14 +8,14 @@ import { TimelineInfo } from "@/services/timeline"; import TimelineLogo from "../common/TimelineLogo"; import UserTimelineLogo from "../common/UserTimelineLogo"; -export interface TimelineBoardProps { +interface TimelineBoardUIProps { title?: string; timelines: TimelineInfo[] | "offline" | "loading"; onReload: () => void; className?: string; } -const TimelineBoard: React.FC = (props) => { +const TimelineBoardUI: React.FC = (props) => { const { title, timelines, className } = props; return ( @@ -71,4 +71,50 @@ const TimelineBoard: React.FC = (props) => { ); }; +export interface TimelineBoardProps { + title?: string; + className?: string; + load: () => Promise; +} + +const TimelineBoard: React.FC = ({ + className, + title, + load, +}) => { + const [timelines, setTimelines] = React.useState< + TimelineInfo[] | "offline" | "loading" + >("loading"); + + React.useEffect(() => { + let subscribe = true; + if (timelines === "loading") { + void load().then( + (timelines) => { + if (subscribe) { + setTimelines(timelines); + } + }, + () => { + setTimelines("offline"); + } + ); + } + return () => { + subscribe = false; + }; + }, [load, timelines]); + + return ( + { + setTimelines("loading"); + }} + /> + ); +}; + export default TimelineBoard; -- cgit v1.2.3 From 898f7bf50243cc6f25b9368b873c8bdcd230400e Mon Sep 17 00:00:00 2001 From: crupest Date: Sat, 19 Dec 2020 22:15:05 +0800 Subject: ... --- FrontEnd/src/app/index.sass | 7 +++++-- FrontEnd/src/app/views/home/BoardWithUser.tsx | 4 ++-- FrontEnd/src/app/views/home/BoardWithoutUser.tsx | 4 ++-- FrontEnd/src/app/views/home/index.tsx | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) (limited to 'FrontEnd/src/app/views/home') diff --git a/FrontEnd/src/app/index.sass b/FrontEnd/src/app/index.sass index d5e1ea22..6325895a 100644 --- a/FrontEnd/src/app/index.sass +++ b/FrontEnd/src/app/index.sass @@ -50,10 +50,13 @@ textarea .cru-card @extend .shadow - @extend .border @extend .rounded + border: 1px solid border-color: $gray-200 - background: $light + background: $gray-100 + transition: all 0.3s + &:hover + border-color: $primary .full-viewport-center-child position: fixed diff --git a/FrontEnd/src/app/views/home/BoardWithUser.tsx b/FrontEnd/src/app/views/home/BoardWithUser.tsx index 9b2f395d..469eb388 100644 --- a/FrontEnd/src/app/views/home/BoardWithUser.tsx +++ b/FrontEnd/src/app/views/home/BoardWithUser.tsx @@ -13,13 +13,13 @@ const BoardWithUser: React.FC<{ user: AuthUser }> = ({ user }) => { return ( - + getHttpHighlightClient().list()} /> - + diff --git a/FrontEnd/src/app/views/home/BoardWithoutUser.tsx b/FrontEnd/src/app/views/home/BoardWithoutUser.tsx index ad88af7a..d9c7fcf4 100644 --- a/FrontEnd/src/app/views/home/BoardWithoutUser.tsx +++ b/FrontEnd/src/app/views/home/BoardWithoutUser.tsx @@ -12,13 +12,13 @@ const BoardWithoutUser: React.FC = () => { return ( - + getHttpHighlightClient().list()} /> - + diff --git a/FrontEnd/src/app/views/home/index.tsx b/FrontEnd/src/app/views/home/index.tsx index 0d439f36..3c53736d 100644 --- a/FrontEnd/src/app/views/home/index.tsx +++ b/FrontEnd/src/app/views/home/index.tsx @@ -33,7 +33,7 @@ const HomePage: React.FC = () => { return ( <> - + Date: Thu, 24 Dec 2020 17:14:06 +0800 Subject: ... --- FrontEnd/src/app/views/home/TimelineBoard.tsx | 89 ++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 16 deletions(-) (limited to 'FrontEnd/src/app/views/home') diff --git a/FrontEnd/src/app/views/home/TimelineBoard.tsx b/FrontEnd/src/app/views/home/TimelineBoard.tsx index ae7783e6..87ed98e1 100644 --- a/FrontEnd/src/app/views/home/TimelineBoard.tsx +++ b/FrontEnd/src/app/views/home/TimelineBoard.tsx @@ -7,20 +7,90 @@ import { Spinner } from "react-bootstrap"; import { TimelineInfo } from "@/services/timeline"; import TimelineLogo from "../common/TimelineLogo"; import UserTimelineLogo from "../common/UserTimelineLogo"; +import { HttpTimelineInfo } from "@/http/timeline"; + +interface TimelineBoardItemProps { + timeline: HttpTimelineInfo; + // If not null, will disable navigation on click. + actions?: { + onDelete: () => void; + onMove: (e: React.MouseEvent) => void; + }; +} + +const TimelineBoardItem: React.FC = ({ + timeline, + actions, +}) => { + const { name, title } = timeline; + const isPersonal = name.startsWith("@"); + const url = isPersonal + ? `/users/${timeline.owner.username}` + : `/timelines/${name}`; + + const content = ( + <> + {isPersonal ? ( + + ) : ( + + )} + {title} + {name} + + ); + + return actions == null ? ( + + {content} + + ) : ( +
{content}
+ ); +}; interface TimelineBoardUIProps { title?: string; timelines: TimelineInfo[] | "offline" | "loading"; onReload: () => void; className?: string; + editHandler?: { + onDelete: (timeline: string) => Promise; + }; } const TimelineBoardUI: React.FC = (props) => { - const { title, timelines, className } = props; + const { title, timelines, className, editHandler } = props; + + const editable = editHandler != null; + + const [editing, setEditing] = React.useState(false); return (
- {title != null &&

{title}

} +
+ {title != null &&

{title}

} + { + editable && + (editing ? ( +
{ + setEditing(false); + }} + > + Done +
+ ) : ( +
{ + setEditing(true); + }} + > + Edit +
+ )) // TODO: i18n + } +
{(() => { if (timelines === "loading") { return ( @@ -48,21 +118,8 @@ const TimelineBoardUI: React.FC = (props) => { ); } else { return timelines.map((timeline) => { - const { name, title } = timeline; - const isPersonal = name.startsWith("@"); - const url = isPersonal - ? `/users/${timeline.owner.username}` - : `/timelines/${name}`; return ( - - {isPersonal ? ( - - ) : ( - - )} - {title} - {name} - + ); }); } -- cgit v1.2.3 From 681ed22edbe6ead81f7177c956322c8645f77398 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 31 Dec 2020 21:38:22 +0800 Subject: ... --- FrontEnd/src/app/views/home/BoardWithUser.tsx | 10 +++++++ FrontEnd/src/app/views/home/TimelineBoard.tsx | 33 +++++++++++++++------- FrontEnd/src/app/views/home/home.sass | 8 +++++- .../timeline-common/TimelinePageTemplateUI.tsx | 2 ++ 4 files changed, 42 insertions(+), 11 deletions(-) (limited to 'FrontEnd/src/app/views/home') diff --git a/FrontEnd/src/app/views/home/BoardWithUser.tsx b/FrontEnd/src/app/views/home/BoardWithUser.tsx index 469eb388..ab87a58f 100644 --- a/FrontEnd/src/app/views/home/BoardWithUser.tsx +++ b/FrontEnd/src/app/views/home/BoardWithUser.tsx @@ -17,6 +17,16 @@ const BoardWithUser: React.FC<{ user: AuthUser }> = ({ user }) => { getHttpHighlightClient().list()} + editHandler={ + user.hasHighlightTimelineAdministrationPermission + ? { + onDelete: () => { + // TODO: Implement this. + return Promise.resolve(); + }, + } + : undefined + } /> diff --git a/FrontEnd/src/app/views/home/TimelineBoard.tsx b/FrontEnd/src/app/views/home/TimelineBoard.tsx index 87ed98e1..0195f1b5 100644 --- a/FrontEnd/src/app/views/home/TimelineBoard.tsx +++ b/FrontEnd/src/app/views/home/TimelineBoard.tsx @@ -30,13 +30,21 @@ const TimelineBoardItem: React.FC = ({ const content = ( <> - {isPersonal ? ( - - ) : ( - - )} - {title} - {name} +
+ {isPersonal ? ( + + ) : ( + + )} + {title} + {name} +
+ {actions != null ? ( +
+ + +
+ ) : null} ); @@ -49,7 +57,7 @@ const TimelineBoardItem: React.FC = ({ ); }; -interface TimelineBoardUIProps { +export interface TimelineBoardUIProps { title?: string; timelines: TimelineInfo[] | "offline" | "loading"; onReload: () => void; @@ -68,8 +76,8 @@ const TimelineBoardUI: React.FC = (props) => { return (
-
- {title != null &&

{title}

} +
+ {title != null &&

{title}

} { editable && (editing ? ( @@ -132,12 +140,16 @@ export interface TimelineBoardProps { title?: string; className?: string; load: () => Promise; + editHandler?: { + onDelete: (timeline: string) => Promise; + }; } const TimelineBoard: React.FC = ({ className, title, load, + editHandler, }) => { const [timelines, setTimelines] = React.useState< TimelineInfo[] | "offline" | "loading" @@ -170,6 +182,7 @@ const TimelineBoard: React.FC = ({ onReload={() => { setTimelines("loading"); }} + editHandler={editHandler} /> ); }; diff --git a/FrontEnd/src/app/views/home/home.sass b/FrontEnd/src/app/views/home/home.sass index 0c01019b..e15441bc 100644 --- a/FrontEnd/src/app/views/home/home.sass +++ b/FrontEnd/src/app/views/home/home.sass @@ -3,13 +3,19 @@ @extend .d-flex @extend .flex-column @extend .py-3 + @extend .px-3 min-height: 200px +.timeline-board-header + display: flex + justify-content: space-between + .timeline-board-item font-size: 1.1em - @extend .px-3 @extend .py-2 transition: background 0.3s + display: flex + justify-content: space-between .icon height: 1.3em color: black diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplateUI.tsx b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplateUI.tsx index b7cd4a45..20ec6e43 100644 --- a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplateUI.tsx +++ b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplateUI.tsx @@ -31,6 +31,7 @@ export interface TimelinePageTemplateUIProps { onManage?: (item: TManageItems | "property") => void; onMember: () => void; onBookmark?: () => void; + onHighlight?: () => void; onPost?: TimelinePostSendCallback; } | I18nText; @@ -157,6 +158,7 @@ export default function TimelinePageTemplateUI( onManage={data.onManage} onMember={data.onMember} onBookmark={data.onBookmark} + onHighlight={data.onHighlight} syncStatus={syncStatus} collapse={cardCollapse} toggleCollapse={toggleCardCollapse} -- cgit v1.2.3 From f75e57ba17fa101c7a573445023c9e0c55adb7ec Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 31 Dec 2020 22:21:29 +0800 Subject: ... --- FrontEnd/src/app/index.sass | 11 +++++++++-- FrontEnd/src/app/views/home/TimelineBoard.tsx | 25 +++++++++++++++++++++---- FrontEnd/src/app/views/home/home.sass | 5 ++++- 3 files changed, 34 insertions(+), 7 deletions(-) (limited to 'FrontEnd/src/app/views/home') diff --git a/FrontEnd/src/app/index.sass b/FrontEnd/src/app/index.sass index 1a833174..f1ccf50b 100644 --- a/FrontEnd/src/app/index.sass +++ b/FrontEnd/src/app/index.sass @@ -35,10 +35,17 @@ small width: 40px .icon-button - font-size: 1.4em + font-size: 1.4rem cursor: pointer &.large - font-size: 1.6em + font-size: 1.6rem + +.flat-button + cursor: pointer + padding: 0.2em 0.5em + border-radius: 0.2em + &:hover + background-color: $gray-200 .cursor-pointer cursor: pointer diff --git a/FrontEnd/src/app/views/home/TimelineBoard.tsx b/FrontEnd/src/app/views/home/TimelineBoard.tsx index 0195f1b5..a83095d4 100644 --- a/FrontEnd/src/app/views/home/TimelineBoard.tsx +++ b/FrontEnd/src/app/views/home/TimelineBoard.tsx @@ -14,7 +14,7 @@ interface TimelineBoardItemProps { // If not null, will disable navigation on click. actions?: { onDelete: () => void; - onMove: (e: React.MouseEvent) => void; + onMove: (e: React.PointerEvent) => void; }; } @@ -41,8 +41,8 @@ const TimelineBoardItem: React.FC = ({
{actions != null ? (
- - + +
) : null} @@ -82,6 +82,7 @@ const TimelineBoardUI: React.FC = (props) => { editable && (editing ? (
{ setEditing(false); }} @@ -90,6 +91,7 @@ const TimelineBoardUI: React.FC = (props) => {
) : (
{ setEditing(true); }} @@ -127,7 +129,22 @@ const TimelineBoardUI: React.FC = (props) => { } else { return timelines.map((timeline) => { return ( - + { + //TODO: Implement this. + }, + onMove: () => { + //TODO: Implement this. + }, + } + : undefined + } + /> ); }); } diff --git a/FrontEnd/src/app/views/home/home.sass b/FrontEnd/src/app/views/home/home.sass index e15441bc..7694b50c 100644 --- a/FrontEnd/src/app/views/home/home.sass +++ b/FrontEnd/src/app/views/home/home.sass @@ -3,18 +3,21 @@ @extend .d-flex @extend .flex-column @extend .py-3 - @extend .px-3 min-height: 200px .timeline-board-header + @extend .px-3 display: flex + align-items: center justify-content: space-between .timeline-board-item font-size: 1.1em + @extend .px-3 @extend .py-2 transition: background 0.3s display: flex + align-items: center justify-content: space-between .icon height: 1.3em -- cgit v1.2.3 From a4787040a97fcc188891fad2553076c8b1357494 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 1 Jan 2021 00:34:10 +0800 Subject: ... --- FrontEnd/src/app/views/home/TimelineBoard.tsx | 45 ++++++++++++++++++++++++--- FrontEnd/src/app/views/home/home.sass | 2 +- 2 files changed, 42 insertions(+), 5 deletions(-) (limited to 'FrontEnd/src/app/views/home') diff --git a/FrontEnd/src/app/views/home/TimelineBoard.tsx b/FrontEnd/src/app/views/home/TimelineBoard.tsx index a83095d4..b389309a 100644 --- a/FrontEnd/src/app/views/home/TimelineBoard.tsx +++ b/FrontEnd/src/app/views/home/TimelineBoard.tsx @@ -11,15 +11,23 @@ import { HttpTimelineInfo } from "@/http/timeline"; interface TimelineBoardItemProps { timeline: HttpTimelineInfo; + // In height. + offset?: number; + // In px. + arbitraryOffset?: number; // If not null, will disable navigation on click. actions?: { onDelete: () => void; - onMove: (e: React.PointerEvent) => void; + onMoveStart: (e: React.PointerEvent) => void; + onMoving: (e: React.PointerEvent) => void; + onMoveEnd: (e: React.PointerEvent) => void; }; } const TimelineBoardItem: React.FC = ({ timeline, + arbitraryOffset, + offset, actions, }) => { const { name, title } = timeline; @@ -42,18 +50,36 @@ const TimelineBoardItem: React.FC = ({ {actions != null ? (
- +
) : null} ); + const offsetStyle: React.CSSProperties = { + translate: + arbitraryOffset != null + ? `0 ${arbitraryOffset}px` + : offset != null + ? `0 ${offset * 100}%` + : undefined, + transition: + arbitraryOffset == null && offset != null ? "translate 0.5s" : undefined, + }; + return actions == null ? ( {content} ) : ( -
{content}
+
+ {content} +
); }; @@ -74,6 +100,11 @@ const TimelineBoardUI: React.FC = (props) => { const [editing, setEditing] = React.useState(false); + const [moveState, setMoveState] = React.useState(null); + return (
@@ -138,7 +169,13 @@ const TimelineBoardUI: React.FC = (props) => { onDelete: () => { //TODO: Implement this. }, - onMove: () => { + onMoveStart: () => { + //TODO: Implement this. + }, + onMoving: () => { + //TODO: Implement this. + }, + onMoveEnd: () => { //TODO: Implement this. }, } diff --git a/FrontEnd/src/app/views/home/home.sass b/FrontEnd/src/app/views/home/home.sass index 7694b50c..644eb550 100644 --- a/FrontEnd/src/app/views/home/home.sass +++ b/FrontEnd/src/app/views/home/home.sass @@ -14,7 +14,7 @@ .timeline-board-item font-size: 1.1em @extend .px-3 - @extend .py-2 + height: 48px transition: background 0.3s display: flex align-items: center -- cgit v1.2.3 From 6dd67488191469d14623b5b097927ceae32106f2 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 1 Jan 2021 23:16:37 +0800 Subject: ... --- FrontEnd/src/app/views/home/BoardWithUser.tsx | 4 ++ FrontEnd/src/app/views/home/TimelineBoard.tsx | 100 +++++++++++++++++++++++--- FrontEnd/src/app/views/home/home.sass | 1 + 3 files changed, 94 insertions(+), 11 deletions(-) (limited to 'FrontEnd/src/app/views/home') diff --git a/FrontEnd/src/app/views/home/BoardWithUser.tsx b/FrontEnd/src/app/views/home/BoardWithUser.tsx index ab87a58f..7c736695 100644 --- a/FrontEnd/src/app/views/home/BoardWithUser.tsx +++ b/FrontEnd/src/app/views/home/BoardWithUser.tsx @@ -24,6 +24,10 @@ const BoardWithUser: React.FC<{ user: AuthUser }> = ({ user }) => { // TODO: Implement this. return Promise.resolve(); }, + onMove: () => { + // TODO: Implement this. + return Promise.resolve(); + }, } : undefined } diff --git a/FrontEnd/src/app/views/home/TimelineBoard.tsx b/FrontEnd/src/app/views/home/TimelineBoard.tsx index b389309a..ae4a1180 100644 --- a/FrontEnd/src/app/views/home/TimelineBoard.tsx +++ b/FrontEnd/src/app/views/home/TimelineBoard.tsx @@ -68,8 +68,8 @@ const TimelineBoardItem: React.FC = ({ : offset != null ? `0 ${offset * 100}%` : undefined, - transition: - arbitraryOffset == null && offset != null ? "translate 0.5s" : undefined, + transition: offset != null ? "translate 0.5s" : undefined, + zIndex: arbitraryOffset != null ? 1 : undefined, }; return actions == null ? ( @@ -89,7 +89,8 @@ export interface TimelineBoardUIProps { onReload: () => void; className?: string; editHandler?: { - onDelete: (timeline: string) => Promise; + onMove: (timeline: string, index: number, offset: number) => void; + onDelete: (timeline: string) => void; }; } @@ -103,6 +104,7 @@ const TimelineBoardUI: React.FC = (props) => { const [moveState, setMoveState] = React.useState(null); return ( @@ -158,25 +160,75 @@ const TimelineBoardUI: React.FC = (props) => {
); } else { - return timelines.map((timeline) => { + return timelines.map((timeline, index) => { + const height = 48; + + let offset: number | undefined = undefined; + let arbitraryOffset: number | undefined = undefined; + if (moveState != null) { + if (index === moveState.index) { + arbitraryOffset = moveState.offset; + } else { + if (moveState.offset >= 0) { + const offsetCount = Math.round(moveState.offset / height); + if ( + index > moveState.index && + index <= moveState.index + offsetCount + ) { + offset = -1; + } + } else { + const offsetCount = Math.round(-moveState.offset / height); + if ( + index < moveState.index && + index >= moveState.index - offsetCount + ) { + offset = 1; + } + } + } + } + return ( { - //TODO: Implement this. + editHandler.onDelete(timeline.name); }, - onMoveStart: () => { - //TODO: Implement this. + onMoveStart: (e) => { + if (moveState != null) return; + setMoveState({ + index, + offset: 0, + startPointY: e.clientY, + }); }, - onMoving: () => { - //TODO: Implement this. + onMoving: (e) => { + if (moveState == null) return; + setMoveState({ + index, + offset: e.clientY - moveState.startPointY, + startPointY: moveState.startPointY, + }); }, onMoveEnd: () => { - //TODO: Implement this. + if (moveState != null) { + const offsetCount = Math.round( + moveState.offset / height + ); + editHandler.onMove( + timeline.name, + moveState.index, + offsetCount + ); + } + setMoveState(null); }, } : undefined @@ -195,6 +247,7 @@ export interface TimelineBoardProps { className?: string; load: () => Promise; editHandler?: { + onMove: (timeline: string, index: number, offset: number) => Promise; onDelete: (timeline: string) => Promise; }; } @@ -236,7 +289,32 @@ const TimelineBoard: React.FC = ({ onReload={() => { setTimelines("loading"); }} - editHandler={editHandler} + editHandler={ + typeof timelines === "object" && editHandler != null + ? { + onMove: (timeline, index, offset) => { + const newTimelines = timelines.slice(); + const [t] = newTimelines.splice(index, 1); + newTimelines.splice(index + offset, 0, t); + setTimelines(newTimelines); + editHandler.onMove(timeline, index, offset).then(null, () => { + setTimelines(timelines); + }); + }, + onDelete: (timeline) => { + const newTimelines = timelines.slice(); + newTimelines.splice( + timelines.findIndex((t) => t.name === timeline), + 1 + ); + setTimelines(newTimelines); + editHandler.onDelete(timeline).then(null, () => { + setTimelines(timelines); + }); + }, + } + : undefined + } /> ); }; diff --git a/FrontEnd/src/app/views/home/home.sass b/FrontEnd/src/app/views/home/home.sass index 644eb550..e2dc4b66 100644 --- a/FrontEnd/src/app/views/home/home.sass +++ b/FrontEnd/src/app/views/home/home.sass @@ -4,6 +4,7 @@ @extend .flex-column @extend .py-3 min-height: 200px + position: relative .timeline-board-header @extend .px-3 -- cgit v1.2.3 From a48affeb30d537495a82447c47ddcb636b2ec7cd Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 1 Jan 2021 23:20:21 +0800 Subject: ... --- FrontEnd/src/app/views/home/TimelineCreateDialog.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'FrontEnd/src/app/views/home') diff --git a/FrontEnd/src/app/views/home/TimelineCreateDialog.tsx b/FrontEnd/src/app/views/home/TimelineCreateDialog.tsx index 12bbfb54..5dcba612 100644 --- a/FrontEnd/src/app/views/home/TimelineCreateDialog.tsx +++ b/FrontEnd/src/app/views/home/TimelineCreateDialog.tsx @@ -1,7 +1,11 @@ import React from "react"; import { useHistory } from "react-router"; -import { validateTimelineName, timelineService } from "@/services/timeline"; +import { + validateTimelineName, + timelineService, + TimelineInfo, +} from "@/services/timeline"; import OperationDialog from "../common/OperationDialog"; interface TimelineCreateDialogProps { @@ -12,8 +16,6 @@ interface TimelineCreateDialogProps { const TimelineCreateDialog: React.FC = (props) => { const history = useHistory(); - let nameSaved: string; - return ( = (props) => { return null; } }} - onProcess={([name]) => { + onProcess={([name]): Promise => { return timelineService.createTimeline(name).toPromise(); }} - onSuccessAndClose={() => { - history.push(`timelines/${nameSaved}`); + onSuccessAndClose={(timeline: TimelineInfo) => { + history.push(`timelines/${timeline.name}`); }} failurePrompt={(e) => `${e as string}`} /> -- cgit v1.2.3 From 4a90b0738e562de64dd71b482f09063d36be84a8 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 1 Jan 2021 23:23:18 +0800 Subject: ... --- FrontEnd/src/app/views/home/TimelineBoard.tsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'FrontEnd/src/app/views/home') diff --git a/FrontEnd/src/app/views/home/TimelineBoard.tsx b/FrontEnd/src/app/views/home/TimelineBoard.tsx index ae4a1180..77801a57 100644 --- a/FrontEnd/src/app/views/home/TimelineBoard.tsx +++ b/FrontEnd/src/app/views/home/TimelineBoard.tsx @@ -52,8 +52,14 @@ const TimelineBoardItem: React.FC = ({ { + e.currentTarget.setPointerCapture(e.pointerId); + actions.onMoveStart(e); + }} + onPointerUp={(e) => { + actions.onMoveEnd(e); + e.currentTarget.releasePointerCapture(e.pointerId); + }} onPointerMove={actions.onMoving} />
@@ -176,6 +182,8 @@ const TimelineBoardUI: React.FC = (props) => { index <= moveState.index + offsetCount ) { offset = -1; + } else { + offset = 0; } } else { const offsetCount = Math.round(-moveState.offset / height); @@ -184,6 +192,8 @@ const TimelineBoardUI: React.FC = (props) => { index >= moveState.index - offsetCount ) { offset = 1; + } else { + offset = 0; } } } -- cgit v1.2.3 From c101f128df316fa23f461ba8c0545bc0a53d61d4 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 1 Jan 2021 23:37:59 +0800 Subject: ... --- FrontEnd/src/app/views/home/TimelineBoard.tsx | 25 ++++++++++++++----------- FrontEnd/src/app/views/home/home.sass | 9 ++++++++- 2 files changed, 22 insertions(+), 12 deletions(-) (limited to 'FrontEnd/src/app/views/home') diff --git a/FrontEnd/src/app/views/home/TimelineBoard.tsx b/FrontEnd/src/app/views/home/TimelineBoard.tsx index 77801a57..93da14cb 100644 --- a/FrontEnd/src/app/views/home/TimelineBoard.tsx +++ b/FrontEnd/src/app/views/home/TimelineBoard.tsx @@ -38,17 +38,16 @@ const TimelineBoardItem: React.FC = ({ const content = ( <> -
- {isPersonal ? ( - - ) : ( - - )} - {title} - {name} -
+ {isPersonal ? ( + + ) : ( + + )} + {title} + {name} + {actions != null ? ( -
+
= ({ }} onPointerUp={(e) => { actions.onMoveEnd(e); - e.currentTarget.releasePointerCapture(e.pointerId); + try { + e.currentTarget.releasePointerCapture(e.pointerId); + } catch (_) { + void null; + } }} onPointerMove={actions.onMoving} /> diff --git a/FrontEnd/src/app/views/home/home.sass b/FrontEnd/src/app/views/home/home.sass index e2dc4b66..6af1b6d8 100644 --- a/FrontEnd/src/app/views/home/home.sass +++ b/FrontEnd/src/app/views/home/home.sass @@ -19,10 +19,17 @@ transition: background 0.3s display: flex align-items: center - justify-content: space-between .icon height: 1.3em color: black @extend .mr-2 &:hover background: $gray-300 + .right + display: flex + align-items: center + flex-shrink: 0 + .title + white-space: nowrap + overflow: hidden + text-overflow: ellipsis -- cgit v1.2.3 From 7c6d41c8ac02958c0ba98e6879513c958af6249d Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 3 Jan 2021 18:27:20 +0800 Subject: ... --- FrontEnd/src/app/views/home/TimelineBoard.tsx | 219 +++++++++++++++----------- 1 file changed, 125 insertions(+), 94 deletions(-) (limited to 'FrontEnd/src/app/views/home') diff --git a/FrontEnd/src/app/views/home/TimelineBoard.tsx b/FrontEnd/src/app/views/home/TimelineBoard.tsx index 93da14cb..120083e3 100644 --- a/FrontEnd/src/app/views/home/TimelineBoard.tsx +++ b/FrontEnd/src/app/views/home/TimelineBoard.tsx @@ -18,9 +18,11 @@ interface TimelineBoardItemProps { // If not null, will disable navigation on click. actions?: { onDelete: () => void; - onMoveStart: (e: React.PointerEvent) => void; - onMoving: (e: React.PointerEvent) => void; - onMoveEnd: (e: React.PointerEvent) => void; + onMove: { + start: (e: React.PointerEvent) => void; + moving: (e: React.PointerEvent) => void; + end: (e: React.PointerEvent) => void; + }; }; } @@ -48,22 +50,25 @@ const TimelineBoardItem: React.FC = ({ {actions != null ? (
- + { e.currentTarget.setPointerCapture(e.pointerId); - actions.onMoveStart(e); + actions.onMove.start(e); }} onPointerUp={(e) => { - actions.onMoveEnd(e); + actions.onMove.end(e); try { e.currentTarget.releasePointerCapture(e.pointerId); } catch (_) { void null; } }} - onPointerMove={actions.onMoving} + onPointerMove={actions.onMove.moving} />
) : null} @@ -92,7 +97,113 @@ const TimelineBoardItem: React.FC = ({ ); }; -export interface TimelineBoardUIProps { +interface TimelineBoardItemContainerProps { + timelines: TimelineInfo[]; + editHandler?: { + onMove: (timeline: string, index: number, offset: number) => void; + onDelete: (timeline: string) => void; + }; +} + +const TimelineBoardItemContainer: React.FC = ({ + timelines, + editHandler, +}) => { + const [moveState, setMoveState] = React.useState(null); + + return ( + <> + {timelines.map((timeline, index) => { + const height = 48; + + let offset: number | undefined = undefined; + let arbitraryOffset: number | undefined = undefined; + if (moveState != null) { + if (index === moveState.index) { + arbitraryOffset = moveState.offset; + } else { + if (moveState.offset >= 0) { + const offsetCount = Math.round(moveState.offset / height); + if ( + index > moveState.index && + index <= moveState.index + offsetCount + ) { + offset = -1; + } else { + offset = 0; + } + } else { + const offsetCount = Math.round(-moveState.offset / height); + if ( + index < moveState.index && + index >= moveState.index - offsetCount + ) { + offset = 1; + } else { + offset = 0; + } + } + } + } + + return ( + { + editHandler.onDelete(timeline.name); + }, + onMove: { + start: (e) => { + if (moveState != null) return; + setMoveState({ + index, + offset: 0, + startPointY: e.clientY, + }); + }, + moving: (e) => { + if (moveState == null) return; + setMoveState({ + index, + offset: e.clientY - moveState.startPointY, + startPointY: moveState.startPointY, + }); + }, + end: () => { + if (moveState != null) { + const offsetCount = Math.round( + moveState.offset / height + ); + editHandler.onMove( + timeline.name, + moveState.index, + offsetCount + ); + } + setMoveState(null); + }, + }, + } + : undefined + } + /> + ); + })} + + ); +}; + +interface TimelineBoardUIProps { title?: string; timelines: TimelineInfo[] | "offline" | "loading"; onReload: () => void; @@ -110,12 +221,6 @@ const TimelineBoardUI: React.FC = (props) => { const [editing, setEditing] = React.useState(false); - const [moveState, setMoveState] = React.useState(null); - return (
@@ -169,86 +274,12 @@ const TimelineBoardUI: React.FC = (props) => {
); } else { - return timelines.map((timeline, index) => { - const height = 48; - - let offset: number | undefined = undefined; - let arbitraryOffset: number | undefined = undefined; - if (moveState != null) { - if (index === moveState.index) { - arbitraryOffset = moveState.offset; - } else { - if (moveState.offset >= 0) { - const offsetCount = Math.round(moveState.offset / height); - if ( - index > moveState.index && - index <= moveState.index + offsetCount - ) { - offset = -1; - } else { - offset = 0; - } - } else { - const offsetCount = Math.round(-moveState.offset / height); - if ( - index < moveState.index && - index >= moveState.index - offsetCount - ) { - offset = 1; - } else { - offset = 0; - } - } - } - } - - return ( - { - editHandler.onDelete(timeline.name); - }, - onMoveStart: (e) => { - if (moveState != null) return; - setMoveState({ - index, - offset: 0, - startPointY: e.clientY, - }); - }, - onMoving: (e) => { - if (moveState == null) return; - setMoveState({ - index, - offset: e.clientY - moveState.startPointY, - startPointY: moveState.startPointY, - }); - }, - onMoveEnd: () => { - if (moveState != null) { - const offsetCount = Math.round( - moveState.offset / height - ); - editHandler.onMove( - timeline.name, - moveState.index, - offsetCount - ); - } - setMoveState(null); - }, - } - : undefined - } - /> - ); - }); + return ( + + ); } })()}
-- cgit v1.2.3 From 79dbad6f92d105fc541f2035d317de7a547c3441 Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 3 Jan 2021 18:49:32 +0800 Subject: ... --- FrontEnd/src/app/views/home/TimelineBoard.tsx | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'FrontEnd/src/app/views/home') diff --git a/FrontEnd/src/app/views/home/TimelineBoard.tsx b/FrontEnd/src/app/views/home/TimelineBoard.tsx index 120083e3..bb3f5947 100644 --- a/FrontEnd/src/app/views/home/TimelineBoard.tsx +++ b/FrontEnd/src/app/views/home/TimelineBoard.tsx @@ -100,6 +100,7 @@ const TimelineBoardItem: React.FC = ({ interface TimelineBoardItemContainerProps { timelines: TimelineInfo[]; editHandler?: { + // offset may exceed index range plusing index. onMove: (timeline: string, index: number, offset: number) => void; onDelete: (timeline: string) => void; }; @@ -277,7 +278,21 @@ const TimelineBoardUI: React.FC = (props) => { return ( { + if (index + offset >= timelines.length) { + offset = timelines.length - index - 1; + } else if (index + offset < 0) { + offset = -index; + } + editHandler.onMove(timeline, index, offset); + }, + } + : undefined + } /> ); } -- cgit v1.2.3 From 4f301a32778fb006bcf2cc183c7118ca5961f7ba Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 3 Jan 2021 19:01:32 +0800 Subject: ... --- FrontEnd/src/app/locales/en/translation.json | 3 + FrontEnd/src/app/locales/zh/translation.json | 3 + FrontEnd/src/app/views/home/BoardWithUser.tsx | 89 ++++++++++++++++++--------- FrontEnd/src/app/views/home/TimelineBoard.tsx | 46 +++++++------- FrontEnd/src/app/views/home/home.sass | 1 + 5 files changed, 89 insertions(+), 53 deletions(-) (limited to 'FrontEnd/src/app/views/home') diff --git a/FrontEnd/src/app/locales/en/translation.json b/FrontEnd/src/app/locales/en/translation.json index be80d21e..28e7c978 100644 --- a/FrontEnd/src/app/locales/en/translation.json +++ b/FrontEnd/src/app/locales/en/translation.json @@ -1,6 +1,8 @@ { "welcome": "Welcome!", "search": "Search", + "edit": "Edit", + "done": "Done", "loadFailReload": "Load failed, click <1>here to reload.", "serviceWorker": { "availableOffline": "Timeline is now cached in your computer and you can use it offline. 🎉🎉🎉", @@ -23,6 +25,7 @@ "highlightTimeline": "Highlight Timelines", "relatedTimeline": "Timelines Related To You", "publicTimeline": "Public Timelines", + "bookmarkTimeline": "Bookmark Timelines", "offlinePrompt": "Oh oh, it seems you are offline. Here list some timelines cached locally. You can view them or click <1>here to refresh.", "createButton": "Create Timeline", "createDialog": { diff --git a/FrontEnd/src/app/locales/zh/translation.json b/FrontEnd/src/app/locales/zh/translation.json index 8c925eb9..708d0b3b 100644 --- a/FrontEnd/src/app/locales/zh/translation.json +++ b/FrontEnd/src/app/locales/zh/translation.json @@ -1,6 +1,8 @@ { "welcome": "欢迎!", "search": "搜索", + "edit": "编辑", + "done": "完成", "loadFailReload": "加载失败,<1>点击重试。", "serviceWorker": { "availableOffline": "Timeline 已经缓存在本地,你可以离线使用它。🎉🎉🎉", @@ -23,6 +25,7 @@ "highlightTimeline": "高光时间线", "relatedTimeline": "关于你的时间线", "publicTimeline": "公开时间线", + "bookmarkTimeline": "书签时间线", "offlinePrompt": "你好像处于离线状态。以下是一些缓存在本地的时间线。你可以查看它们或者<1>点击重新获取在线信息。", "createButton": "创建时间线", "createDialog": { diff --git a/FrontEnd/src/app/views/home/BoardWithUser.tsx b/FrontEnd/src/app/views/home/BoardWithUser.tsx index 7c736695..1c6f713a 100644 --- a/FrontEnd/src/app/views/home/BoardWithUser.tsx +++ b/FrontEnd/src/app/views/home/BoardWithUser.tsx @@ -5,6 +5,7 @@ import { useTranslation } from "react-i18next"; import { AuthUser } from "@/services/user"; import { getHttpHighlightClient } from "@/http/highlight"; import { getHttpTimelineClient } from "@/http/timeline"; +import { getHttpBookmarkClient } from "@/http/bookmark"; import TimelineBoard from "./TimelineBoard"; @@ -12,36 +13,64 @@ const BoardWithUser: React.FC<{ user: AuthUser }> = ({ user }) => { const { t } = useTranslation(); return ( - - - getHttpHighlightClient().list()} - editHandler={ - user.hasHighlightTimelineAdministrationPermission - ? { - onDelete: () => { - // TODO: Implement this. - return Promise.resolve(); - }, - onMove: () => { - // TODO: Implement this. - return Promise.resolve(); - }, - } - : undefined - } - /> - - - - getHttpTimelineClient().listTimeline({ relate: user.username }) - } - /> - - + <> + + + getHttpBookmarkClient().list(user.token)} + editHandler={{ + onDelete: () => { + // TODO: Implement this. + return Promise.resolve(); + }, + onMove: () => { + // TODO: Implement this. + return Promise.resolve(); + }, + }} + /> + + + + getHttpTimelineClient().listTimeline({ relate: user.username }) + } + /> + + + + + getHttpHighlightClient().list()} + editHandler={ + user.hasHighlightTimelineAdministrationPermission + ? { + onDelete: () => { + // TODO: Implement this. + return Promise.resolve(); + }, + onMove: () => { + // TODO: Implement this. + return Promise.resolve(); + }, + } + : undefined + } + /> + + + + getHttpTimelineClient().listTimeline({ visibility: "Public" }) + } + /> + + + ); }; diff --git a/FrontEnd/src/app/views/home/TimelineBoard.tsx b/FrontEnd/src/app/views/home/TimelineBoard.tsx index bb3f5947..083f4034 100644 --- a/FrontEnd/src/app/views/home/TimelineBoard.tsx +++ b/FrontEnd/src/app/views/home/TimelineBoard.tsx @@ -1,7 +1,7 @@ import React from "react"; import clsx from "clsx"; import { Link } from "react-router-dom"; -import { Trans } from "react-i18next"; +import { Trans, useTranslation } from "react-i18next"; import { Spinner } from "react-bootstrap"; import { TimelineInfo } from "@/services/timeline"; @@ -218,6 +218,8 @@ interface TimelineBoardUIProps { const TimelineBoardUI: React.FC = (props) => { const { title, timelines, className, editHandler } = props; + const { t } = useTranslation(); + const editable = editHandler != null; const [editing, setEditing] = React.useState(false); @@ -226,28 +228,26 @@ const TimelineBoardUI: React.FC = (props) => {
{title != null &&

{title}

} - { - editable && - (editing ? ( -
{ - setEditing(false); - }} - > - Done -
- ) : ( -
{ - setEditing(true); - }} - > - Edit -
- )) // TODO: i18n - } + {editable && + (editing ? ( +
{ + setEditing(false); + }} + > + {t("done")} +
+ ) : ( +
{ + setEditing(true); + }} + > + {t("edit")} +
+ ))}
{(() => { if (timelines === "loading") { diff --git a/FrontEnd/src/app/views/home/home.sass b/FrontEnd/src/app/views/home/home.sass index 6af1b6d8..4b86f241 100644 --- a/FrontEnd/src/app/views/home/home.sass +++ b/FrontEnd/src/app/views/home/home.sass @@ -4,6 +4,7 @@ @extend .flex-column @extend .py-3 min-height: 200px + height: 100% position: relative .timeline-board-header -- cgit v1.2.3 From b7be2446ab3136b35ff8b752b13873ac690066f2 Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 3 Jan 2021 19:13:47 +0800 Subject: ... --- FrontEnd/src/app/index.sass | 3 +++ FrontEnd/src/app/views/home/TimelineBoard.tsx | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'FrontEnd/src/app/views/home') diff --git a/FrontEnd/src/app/index.sass b/FrontEnd/src/app/index.sass index 4c57030d..87616998 100644 --- a/FrontEnd/src/app/index.sass +++ b/FrontEnd/src/app/index.sass @@ -85,3 +85,6 @@ textarea color: $value &:hover color: adjust-color($value, $lightness: +15%) + +.touch-action-none + touch-action: none diff --git a/FrontEnd/src/app/views/home/TimelineBoard.tsx b/FrontEnd/src/app/views/home/TimelineBoard.tsx index 083f4034..c3f01aed 100644 --- a/FrontEnd/src/app/views/home/TimelineBoard.tsx +++ b/FrontEnd/src/app/views/home/TimelineBoard.tsx @@ -55,7 +55,7 @@ const TimelineBoardItem: React.FC = ({ onClick={actions.onDelete} /> { e.currentTarget.setPointerCapture(e.pointerId); actions.onMove.start(e); -- cgit v1.2.3 From 76e818a722a9c8cdb82c66dafaf0bd2768e29bc1 Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 3 Jan 2021 19:31:11 +0800 Subject: ... --- FrontEnd/src/app/locales/en/translation.json | 6 +++ FrontEnd/src/app/locales/zh/translation.json | 6 +++ FrontEnd/src/app/views/home/BoardWithUser.tsx | 72 ++++++++++++++++++++++----- 3 files changed, 72 insertions(+), 12 deletions(-) (limited to 'FrontEnd/src/app/views/home') diff --git a/FrontEnd/src/app/locales/en/translation.json b/FrontEnd/src/app/locales/en/translation.json index 28e7c978..414cc747 100644 --- a/FrontEnd/src/app/locales/en/translation.json +++ b/FrontEnd/src/app/locales/en/translation.json @@ -27,6 +27,12 @@ "publicTimeline": "Public Timelines", "bookmarkTimeline": "Bookmark Timelines", "offlinePrompt": "Oh oh, it seems you are offline. Here list some timelines cached locally. You can view them or click <1>here to refresh.", + "message": { + "moveHighlightFail": "Failed to move highlight timeline.", + "deleteHighlightFail": "Failed to delete highlight timeline.", + "moveBookmarkFail": "Failed to move bookmark timeline.", + "deleteBookmarkFail": "Failed to delete bookmark timeline." + }, "createButton": "Create Timeline", "createDialog": { "title": "Create Timeline!", diff --git a/FrontEnd/src/app/locales/zh/translation.json b/FrontEnd/src/app/locales/zh/translation.json index 708d0b3b..bbee28af 100644 --- a/FrontEnd/src/app/locales/zh/translation.json +++ b/FrontEnd/src/app/locales/zh/translation.json @@ -27,6 +27,12 @@ "publicTimeline": "公开时间线", "bookmarkTimeline": "书签时间线", "offlinePrompt": "你好像处于离线状态。以下是一些缓存在本地的时间线。你可以查看它们或者<1>点击重新获取在线信息。", + "message": { + "moveHighlightFail": "移动高光时间线失败。", + "deleteHighlightFail": "删除高光时间线失败。", + "moveBookmarkFail": "移动书签时间线失败。", + "deleteBookmarkFail": "删除书签时间线失败。" + }, "createButton": "创建时间线", "createDialog": { "title": "创建时间线!", diff --git a/FrontEnd/src/app/views/home/BoardWithUser.tsx b/FrontEnd/src/app/views/home/BoardWithUser.tsx index 1c6f713a..8afe440b 100644 --- a/FrontEnd/src/app/views/home/BoardWithUser.tsx +++ b/FrontEnd/src/app/views/home/BoardWithUser.tsx @@ -3,6 +3,8 @@ import { Row, Col } from "react-bootstrap"; import { useTranslation } from "react-i18next"; import { AuthUser } from "@/services/user"; +import { pushAlert } from "@/services/alert"; + import { getHttpHighlightClient } from "@/http/highlight"; import { getHttpTimelineClient } from "@/http/timeline"; import { getHttpBookmarkClient } from "@/http/bookmark"; @@ -20,13 +22,36 @@ const BoardWithUser: React.FC<{ user: AuthUser }> = ({ user }) => { title={t("home.bookmarkTimeline")} load={() => getHttpBookmarkClient().list(user.token)} editHandler={{ - onDelete: () => { - // TODO: Implement this. - return Promise.resolve(); + onDelete: (timeline) => { + return getHttpBookmarkClient() + .delete(timeline, user.token) + .catch((e) => { + pushAlert({ + message: { + type: "i18n", + key: "home.message.deleteBookmarkFail", + }, + type: "danger", + }); + throw e; + }); }, - onMove: () => { - // TODO: Implement this. - return Promise.resolve(); + onMove: (timeline, index, offset) => { + return getHttpBookmarkClient() + .move( + { timeline, newPosition: index + offset + 1 }, // +1 because backend contract: index starts at 1 + user.token + ) + .catch((e) => { + pushAlert({ + message: { + type: "i18n", + key: "home.message.moveBookmarkFail", + }, + type: "danger", + }); + throw e; + }); }, }} /> @@ -48,13 +73,36 @@ const BoardWithUser: React.FC<{ user: AuthUser }> = ({ user }) => { editHandler={ user.hasHighlightTimelineAdministrationPermission ? { - onDelete: () => { - // TODO: Implement this. - return Promise.resolve(); + onDelete: (timeline) => { + return getHttpHighlightClient() + .delete(timeline, user.token) + .catch((e) => { + pushAlert({ + message: { + type: "i18n", + key: "home.message.deleteHighlightFail", + }, + type: "danger", + }); + throw e; + }); }, - onMove: () => { - // TODO: Implement this. - return Promise.resolve(); + onMove: (timeline, index, offset) => { + return getHttpHighlightClient() + .move( + { timeline, newPosition: index + offset + 1 }, // +1 because backend contract: index starts at 1 + user.token + ) + .catch((e) => { + pushAlert({ + message: { + type: "i18n", + key: "home.message.moveHighlightFail", + }, + type: "danger", + }); + throw e; + }); }, } : undefined -- cgit v1.2.3