aboutsummaryrefslogtreecommitdiff
path: root/FrontEnd/src/app/views/timeline-common
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2021-01-03 19:38:05 +0800
committerGitHub <noreply@github.com>2021-01-03 19:38:05 +0800
commit418d631528fdb581a384068719e9af5dbaa66740 (patch)
tree42e2c0396a16cb5fbaaae665a238a8a031bef7f0 /FrontEnd/src/app/views/timeline-common
parent4b3ae3edd9e8aceac5ff26ef137d2a8d686fe305 (diff)
parent8af803cb0da57af1355ad28cd056cb5dcf6d6915 (diff)
downloadtimeline-418d631528fdb581a384068719e9af5dbaa66740.tar.gz
timeline-418d631528fdb581a384068719e9af5dbaa66740.tar.bz2
timeline-418d631528fdb581a384068719e9af5dbaa66740.zip
Merge pull request #197 from crupest/front-dev
Front: Highlight and bookmark timeline and new home page.
Diffstat (limited to 'FrontEnd/src/app/views/timeline-common')
-rw-r--r--FrontEnd/src/app/views/timeline-common/CollapseButton.tsx12
-rw-r--r--FrontEnd/src/app/views/timeline-common/InfoCardTemplate.tsx26
-rw-r--r--FrontEnd/src/app/views/timeline-common/TimelineCardTemplate.tsx105
-rw-r--r--FrontEnd/src/app/views/timeline-common/TimelineItem.tsx13
-rw-r--r--FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx34
-rw-r--r--FrontEnd/src/app/views/timeline-common/TimelinePageTemplateUI.tsx6
-rw-r--r--FrontEnd/src/app/views/timeline-common/TimelinePostEdit.tsx11
7 files changed, 160 insertions, 47 deletions
diff --git a/FrontEnd/src/app/views/timeline-common/CollapseButton.tsx b/FrontEnd/src/app/views/timeline-common/CollapseButton.tsx
index 3c52150f..da54f3fd 100644
--- a/FrontEnd/src/app/views/timeline-common/CollapseButton.tsx
+++ b/FrontEnd/src/app/views/timeline-common/CollapseButton.tsx
@@ -1,8 +1,5 @@
import React from "react";
import clsx from "clsx";
-import Svg from "react-inlinesvg";
-import arrowsAngleContractIcon from "bootstrap-icons/icons/arrows-angle-contract.svg";
-import arrowsAngleExpandIcon from "bootstrap-icons/icons/arrows-angle-expand.svg";
const CollapseButton: React.FC<{
collapse: boolean;
@@ -11,10 +8,13 @@ const CollapseButton: React.FC<{
style?: React.CSSProperties;
}> = ({ collapse, onClick, className, style }) => {
return (
- <Svg
- src={collapse ? arrowsAngleExpandIcon : arrowsAngleContractIcon}
+ <i
onClick={onClick}
- className={clsx("text-primary icon-button", className)}
+ className={clsx(
+ collapse ? "bi-arrows-angle-expand" : "bi-arrows-angle-contract",
+ "text-primary icon-button",
+ className
+ )}
style={style}
/>
);
diff --git a/FrontEnd/src/app/views/timeline-common/InfoCardTemplate.tsx b/FrontEnd/src/app/views/timeline-common/InfoCardTemplate.tsx
deleted file mode 100644
index a8de20aa..00000000
--- a/FrontEnd/src/app/views/timeline-common/InfoCardTemplate.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import React from "react";
-import clsx from "clsx";
-
-import { TimelineCardComponentProps } from "../timeline-common/TimelinePageTemplateUI";
-import SyncStatusBadge from "../timeline-common/SyncStatusBadge";
-import CollapseButton from "../timeline-common/CollapseButton";
-
-const InfoCardTemplate: React.FC<
- Pick<
- TimelineCardComponentProps<"">,
- "collapse" | "toggleCollapse" | "syncStatus" | "className"
- > & { children: React.ReactElement[] }
-> = ({ collapse, toggleCollapse, syncStatus, className, children }) => {
- return (
- <div className={clsx("cru-card p-2 clearfix", className)}>
- <div className="float-right d-flex align-items-center">
- <SyncStatusBadge status={syncStatus} className="mr-2" />
- <CollapseButton collapse={collapse} onClick={toggleCollapse} />
- </div>
-
- <div style={{ display: collapse ? "none" : "block" }}>{children}</div>
- </div>
- );
-};
-
-export default InfoCardTemplate;
diff --git a/FrontEnd/src/app/views/timeline-common/TimelineCardTemplate.tsx b/FrontEnd/src/app/views/timeline-common/TimelineCardTemplate.tsx
new file mode 100644
index 00000000..ece1942f
--- /dev/null
+++ b/FrontEnd/src/app/views/timeline-common/TimelineCardTemplate.tsx
@@ -0,0 +1,105 @@
+import React from "react";
+import clsx from "clsx";
+import { useTranslation } from "react-i18next";
+import { Dropdown, Button } from "react-bootstrap";
+
+import { timelineVisibilityTooltipTranslationMap } from "@/services/timeline";
+
+import { TimelineCardComponentProps } from "../timeline-common/TimelinePageTemplateUI";
+import SyncStatusBadge from "../timeline-common/SyncStatusBadge";
+import CollapseButton from "../timeline-common/CollapseButton";
+
+export interface TimelineCardTemplateProps
+ extends Omit<TimelineCardComponentProps<"">, "onManage" | "onMember"> {
+ infoArea: React.ReactElement;
+ manageArea:
+ | { type: "member"; onMember: () => void }
+ | {
+ type: "manage";
+ items: (
+ | {
+ type: "button";
+ text: string;
+ color?: string;
+ onClick: () => void;
+ }
+ | { type: "divider" }
+ )[];
+ };
+}
+
+function TimelineCardTemplate({
+ timeline,
+ collapse,
+ infoArea,
+ manageArea,
+ onBookmark,
+ onHighlight,
+ toggleCollapse,
+ syncStatus,
+ className,
+}: TimelineCardTemplateProps): React.ReactElement | null {
+ const { t } = useTranslation();
+
+ return (
+ <div className={clsx("cru-card p-2 clearfix", className)}>
+ <div className="float-right d-flex align-items-center">
+ <SyncStatusBadge status={syncStatus} className="mr-2" />
+ <CollapseButton collapse={collapse} onClick={toggleCollapse} />
+ </div>
+ <div style={{ display: collapse ? "none" : "block" }}>
+ {infoArea}
+ <p className="mb-0">{timeline.description}</p>
+ <small className="mt-1 d-block">
+ {t(timelineVisibilityTooltipTranslationMap[timeline.visibility])}
+ </small>
+ <div className="text-right mt-2">
+ {onHighlight != null ? (
+ <i
+ className="bi-star icon-button text-yellow mr-3"
+ onClick={onHighlight}
+ />
+ ) : null}
+ {onBookmark != null ? (
+ <i
+ className="bi-bookmark icon-button text-yellow mr-3"
+ onClick={onBookmark}
+ />
+ ) : null}
+ {manageArea.type === "manage" ? (
+ <Dropdown className="d-inline-block">
+ <Dropdown.Toggle variant="outline-primary">
+ {t("timeline.manage")}
+ </Dropdown.Toggle>
+ <Dropdown.Menu>
+ {manageArea.items.map((item, index) => {
+ if (item.type === "divider") {
+ return <Dropdown.Divider key={index} />;
+ } else {
+ return (
+ <Dropdown.Item
+ key={index}
+ onClick={item.onClick}
+ className={
+ item.color != null ? "text-" + item.color : undefined
+ }
+ >
+ {t(item.text)}
+ </Dropdown.Item>
+ );
+ }
+ })}
+ </Dropdown.Menu>
+ </Dropdown>
+ ) : (
+ <Button variant="outline-primary" onClick={manageArea.onMember}>
+ {t("timeline.memberButton")}
+ </Button>
+ )}
+ </div>
+ </div>
+ </div>
+ );
+}
+
+export default TimelineCardTemplate;
diff --git a/FrontEnd/src/app/views/timeline-common/TimelineItem.tsx b/FrontEnd/src/app/views/timeline-common/TimelineItem.tsx
index 408c49a1..233c81bd 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelineItem.tsx
+++ b/FrontEnd/src/app/views/timeline-common/TimelineItem.tsx
@@ -2,9 +2,6 @@ import React from "react";
import clsx from "clsx";
import { Link } from "react-router-dom";
import { useTranslation } from "react-i18next";
-import Svg from "react-inlinesvg";
-import chevronDownIcon from "bootstrap-icons/icons/chevron-down.svg";
-import trashIcon from "bootstrap-icons/icons/trash.svg";
import { Modal, Button } from "react-bootstrap";
import { useAvatar } from "@/services/user";
@@ -98,9 +95,8 @@ const TimelineItem: React.FC<TimelineItemProps> = (props) => {
<small className="text-dark">{props.post.author.nickname}</small>
</span>
{more != null ? (
- <Svg
- src={chevronDownIcon}
- className="text-info icon-button"
+ <i
+ className="bi-chevron-down text-info icon-button"
onClick={(e) => {
more.toggle();
e.stopPropagation();
@@ -139,9 +135,8 @@ const TimelineItem: React.FC<TimelineItemProps> = (props) => {
className="position-absolute position-lt w-100 h-100 mask d-flex justify-content-center align-items-center"
onClick={more.toggle}
>
- <Svg
- src={trashIcon}
- className="text-danger icon-button large"
+ <i
+ className="bi-trash text-danger icon-button large"
onClick={(e) => {
setDeleteDialog(true);
e.stopPropagation();
diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx
index 6c57e91d..7f5c8206 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx
+++ b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx
@@ -11,6 +11,8 @@ import {
usePostList,
useTimelineInfo,
} from "@/services/timeline";
+import { getHttpBookmarkClient } from "@/http/bookmark";
+import { getHttpHighlightClient } from "@/http/highlight";
import { TimelineMemberDialog } from "./TimelineMember";
import TimelinePropertyChangeDialog from "./TimelinePropertyChangeDialog";
@@ -116,6 +118,38 @@ export default function TimelinePageTemplate<TManageItem>(
? onManage
: undefined,
onMember: () => setDialog("member"),
+ onBookmark:
+ user != null
+ ? () => {
+ void getHttpBookmarkClient()
+ .put(name, user.token)
+ .then(() => {
+ pushAlert({
+ message: {
+ type: "i18n",
+ key: "timeline.addBookmarkSuccess",
+ },
+ type: "success",
+ });
+ });
+ }
+ : undefined,
+ onHighlight:
+ user != null && user.hasHighlightTimelineAdministrationPermission
+ ? () => {
+ void getHttpHighlightClient()
+ .put(name, user.token)
+ .then(() => {
+ pushAlert({
+ message: {
+ type: "i18n",
+ key: "timeline.addHighlightSuccess",
+ },
+ type: "success",
+ });
+ });
+ }
+ : undefined,
};
if (type === "cache") {
diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplateUI.tsx b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplateUI.tsx
index f60383dd..20ec6e43 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplateUI.tsx
+++ b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplateUI.tsx
@@ -15,6 +15,8 @@ export interface TimelineCardComponentProps<TManageItems> {
timeline: TimelineInfo;
onManage?: (item: TManageItems | "property") => void;
onMember: () => void;
+ onBookmark?: () => void;
+ onHighlight?: () => void;
className?: string;
collapse: boolean;
syncStatus: TimelineSyncStatus;
@@ -28,6 +30,8 @@ export interface TimelinePageTemplateUIProps<TManageItems> {
posts?: TimelinePostInfoEx[];
onManage?: (item: TManageItems | "property") => void;
onMember: () => void;
+ onBookmark?: () => void;
+ onHighlight?: () => void;
onPost?: TimelinePostSendCallback;
}
| I18nText;
@@ -153,6 +157,8 @@ export default function TimelinePageTemplateUI<TManageItems>(
timeline={data.timeline}
onManage={data.onManage}
onMember={data.onMember}
+ onBookmark={data.onBookmark}
+ onHighlight={data.onHighlight}
syncStatus={syncStatus}
collapse={cardCollapse}
toggleCollapse={toggleCardCollapse}
diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePostEdit.tsx b/FrontEnd/src/app/views/timeline-common/TimelinePostEdit.tsx
index dfa2f879..207bf6af 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelinePostEdit.tsx
+++ b/FrontEnd/src/app/views/timeline-common/TimelinePostEdit.tsx
@@ -1,10 +1,7 @@
import React from "react";
import clsx from "clsx";
import { useTranslation } from "react-i18next";
-import Svg from "react-inlinesvg";
import { Button, Spinner, Row, Col, Form } from "react-bootstrap";
-import textIcon from "bootstrap-icons/icons/card-text.svg";
-import imageIcon from "bootstrap-icons/icons/image.svg";
import { UiLogicError } from "@/common";
@@ -212,10 +209,12 @@ const TimelinePostEdit: React.FC<TimelinePostEditProps> = (props) => {
return (
<>
<div className="d-block text-center mt-1 mb-2">
- <Svg
+ <i
onLoad={notifyHeightChange}
- src={kind === "text" ? imageIcon : textIcon}
- className="icon-button"
+ className={clsx(
+ kind === "text" ? "bi-image" : "bi-card-text",
+ "icon-button"
+ )}
onClick={toggleKind}
/>
</div>