aboutsummaryrefslogtreecommitdiff
path: root/FrontEnd/src/app/views
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-12-22 00:27:33 +0800
committercrupest <crupest@outlook.com>2020-12-22 00:27:33 +0800
commita337ce43ae91c0c9a1c359dbb91faf75f1375505 (patch)
tree8b71ace9f10c8ce9a13363cdb3de7a29696fc5e0 /FrontEnd/src/app/views
parentd960fdcfb79caf257fed6b68cc169a785003d965 (diff)
downloadtimeline-a337ce43ae91c0c9a1c359dbb91faf75f1375505.tar.gz
timeline-a337ce43ae91c0c9a1c359dbb91faf75f1375505.tar.bz2
timeline-a337ce43ae91c0c9a1c359dbb91faf75f1375505.zip
...
Diffstat (limited to 'FrontEnd/src/app/views')
-rw-r--r--FrontEnd/src/app/views/timeline-common/InfoCardTemplate.tsx26
-rw-r--r--FrontEnd/src/app/views/timeline-common/TimelineCardTemplate.tsx100
-rw-r--r--FrontEnd/src/app/views/timeline/TimelineInfoCard.tsx128
-rw-r--r--FrontEnd/src/app/views/user/UserInfoCard.tsx123
4 files changed, 208 insertions, 169 deletions
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..a47b3d76
--- /dev/null
+++ b/FrontEnd/src/app/views/timeline-common/TimelineCardTemplate.tsx
@@ -0,0 +1,100 @@
+import React from "react";
+import clsx from "clsx";
+import { useTranslation } from "react-i18next";
+import { Dropdown, Button } from "react-bootstrap";
+import Svg from "react-inlinesvg";
+import bookmarkIcon from "bootstrap-icons/icons/bookmark.svg";
+
+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,
+ 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">
+ {onBookmark != null ? (
+ <Svg
+ src={bookmarkIcon}
+ className="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
+ 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/TimelineInfoCard.tsx b/FrontEnd/src/app/views/timeline/TimelineInfoCard.tsx
index 8f967a34..f4dbb67d 100644
--- a/FrontEnd/src/app/views/timeline/TimelineInfoCard.tsx
+++ b/FrontEnd/src/app/views/timeline/TimelineInfoCard.tsx
@@ -1,93 +1,73 @@
import React from "react";
-import { useTranslation } from "react-i18next";
-import { Dropdown, Button } from "react-bootstrap";
-import Svg from "react-inlinesvg";
-import bookmarkIcon from "bootstrap-icons/icons/bookmark.svg";
import { useAvatar } from "@/services/user";
-import { timelineVisibilityTooltipTranslationMap } from "@/services/timeline";
import BlobImage from "../common/BlobImage";
+import TimelineCardTemplate, {
+ TimelineCardTemplateProps,
+} from "../timeline-common/TimelineCardTemplate";
import { TimelineCardComponentProps } from "../timeline-common/TimelinePageTemplateUI";
-import InfoCardTemplate from "../timeline-common/InfoCardTemplate";
export type OrdinaryTimelineManageItem = "delete";
export type TimelineInfoCardProps = TimelineCardComponentProps<OrdinaryTimelineManageItem>;
const TimelineInfoCard: React.FC<TimelineInfoCardProps> = (props) => {
- const {
- timeline,
- collapse,
- onMember,
- onBookmark,
- onManage,
- syncStatus,
- toggleCollapse,
- } = props;
-
- const { t } = useTranslation();
+ const { onMember, onManage, ...otherProps } = props;
+ const { timeline } = props;
const avatar = useAvatar(timeline?.owner?.username);
return (
- <InfoCardTemplate
- className={props.className}
- syncStatus={syncStatus}
- collapse={collapse}
- toggleCollapse={toggleCollapse}
- >
- <h3 className="text-primary d-inline-block align-middle">
- {timeline.title}
- <small className="ml-3 text-secondary">{timeline.name}</small>
- </h3>
- <div className="align-middle">
- <BlobImage blob={avatar} className="avatar small rounded-circle mr-3" />
- {timeline.owner.nickname}
- <small className="ml-3 text-secondary">
- @{timeline.owner.username}
- </small>
- </div>
- <p className="mb-0">{timeline.description}</p>
- <small className="mt-1 d-block">
- {t(timelineVisibilityTooltipTranslationMap[timeline.visibility])}
- </small>
- <div className="text-right mt-2">
- {onBookmark != null ? (
- <Svg
- src={bookmarkIcon}
- className="icon-button text-yellow mr-3"
- onClick={onBookmark}
- />
- ) : null}
- {onManage != null ? (
- <Dropdown className="d-inline-block">
- <Dropdown.Toggle variant="outline-primary">
- {t("timeline.manage")}
- </Dropdown.Toggle>
- <Dropdown.Menu>
- <Dropdown.Item onClick={() => onManage("property")}>
- {t("timeline.manageItem.property")}
- </Dropdown.Item>
- <Dropdown.Item onClick={onMember}>
- {t("timeline.manageItem.member")}
- </Dropdown.Item>
- <Dropdown.Divider />
- <Dropdown.Item
- className="text-danger"
- onClick={() => onManage("delete")}
- >
- {t("timeline.manageItem.delete")}
- </Dropdown.Item>
- </Dropdown.Menu>
- </Dropdown>
- ) : (
- <Button variant="outline-primary" onClick={onMember}>
- {t("timeline.memberButton")}
- </Button>
- )}
- </div>
- </InfoCardTemplate>
+ <TimelineCardTemplate
+ infoArea={
+ <>
+ <h3 className="text-primary d-inline-block align-middle">
+ {timeline.title}
+ <small className="ml-3 text-secondary">{timeline.name}</small>
+ </h3>
+ <div className="align-middle">
+ <BlobImage
+ blob={avatar}
+ className="avatar small rounded-circle mr-3"
+ />
+ {timeline.owner.nickname}
+ <small className="ml-3 text-secondary">
+ @{timeline.owner.username}
+ </small>
+ </div>
+ </>
+ }
+ manageArea={((): TimelineCardTemplateProps["manageArea"] => {
+ if (onManage == null) {
+ return { type: "member", onMember };
+ } else {
+ return {
+ type: "manage",
+ items: [
+ {
+ type: "button",
+ text: "timeline.manageItem.property",
+ onClick: () => onManage("property"),
+ },
+ {
+ type: "button",
+ onClick: onMember,
+ text: "timeline.manageItem.member",
+ },
+ { type: "divider" },
+ {
+ type: "button",
+ onClick: () => onManage("delete"),
+ color: "danger",
+ text: "timeline.manageItem.delete",
+ },
+ ],
+ };
+ }
+ })()}
+ {...otherProps}
+ />
);
};
diff --git a/FrontEnd/src/app/views/user/UserInfoCard.tsx b/FrontEnd/src/app/views/user/UserInfoCard.tsx
index 0e1e093a..f31a939f 100644
--- a/FrontEnd/src/app/views/user/UserInfoCard.tsx
+++ b/FrontEnd/src/app/views/user/UserInfoCard.tsx
@@ -1,88 +1,73 @@
import React from "react";
-import { useTranslation } from "react-i18next";
-import { Dropdown, Button } from "react-bootstrap";
-import Svg from "react-inlinesvg";
-import bookmarkIcon from "bootstrap-icons/icons/bookmark.svg";
-import { timelineVisibilityTooltipTranslationMap } from "@/services/timeline";
import { useAvatar } from "@/services/user";
import BlobImage from "../common/BlobImage";
+import TimelineCardTemplate, {
+ TimelineCardTemplateProps,
+} from "../timeline-common/TimelineCardTemplate";
import { TimelineCardComponentProps } from "../timeline-common/TimelinePageTemplateUI";
-import InfoCardTemplate from "../timeline-common/InfoCardTemplate";
export type PersonalTimelineManageItem = "avatar" | "nickname";
export type UserInfoCardProps = TimelineCardComponentProps<PersonalTimelineManageItem>;
const UserInfoCard: React.FC<UserInfoCardProps> = (props) => {
- const {
- timeline,
- collapse,
- onMember,
- onManage,
- onBookmark,
- syncStatus,
- toggleCollapse,
- } = props;
- const { t } = useTranslation();
+ const { onMember, onManage, ...otherProps } = props;
+ const { timeline } = props;
const avatar = useAvatar(timeline?.owner?.username);
return (
- <InfoCardTemplate
- className={props.className}
- syncStatus={syncStatus}
- collapse={collapse}
- toggleCollapse={toggleCollapse}
- >
- <h3 className="text-primary d-inline-block align-middle">
- {timeline.title}
- <small className="ml-3 text-secondary">{timeline.name}</small>
- </h3>
- <div className="align-middle">
- <BlobImage blob={avatar} className="avatar small rounded-circle mr-3" />
- {timeline.owner.nickname}
- </div>
- <p className="mb-0">{timeline.description}</p>
- <small className="mt-1 d-block">
- {t(timelineVisibilityTooltipTranslationMap[timeline.visibility])}
- </small>
- <div className="text-right mt-2">
- {onBookmark != null ? (
- <Svg
- src={bookmarkIcon}
- className="icon-button text-yellow mr-3"
- onClick={onBookmark}
- />
- ) : null}
- {onManage != null ? (
- <Dropdown className="d-inline-block">
- <Dropdown.Toggle variant="outline-primary">
- {t("timeline.manage")}
- </Dropdown.Toggle>
- <Dropdown.Menu>
- <Dropdown.Item onClick={() => onManage("nickname")}>
- {t("timeline.manageItem.nickname")}
- </Dropdown.Item>
- <Dropdown.Item onClick={() => onManage("avatar")}>
- {t("timeline.manageItem.avatar")}
- </Dropdown.Item>
- <Dropdown.Item onClick={() => onManage("property")}>
- {t("timeline.manageItem.property")}
- </Dropdown.Item>
- <Dropdown.Item onClick={onMember}>
- {t("timeline.manageItem.member")}
- </Dropdown.Item>
- </Dropdown.Menu>
- </Dropdown>
- ) : (
- <Button variant="outline-primary" onClick={onMember}>
- {t("timeline.memberButton")}
- </Button>
- )}
- </div>
- </InfoCardTemplate>
+ <TimelineCardTemplate
+ infoArea={
+ <>
+ <h3 className="text-primary d-inline-block align-middle">
+ {timeline.title}
+ <small className="ml-3 text-secondary">{timeline.name}</small>
+ </h3>
+ <div className="align-middle">
+ <BlobImage
+ blob={avatar}
+ className="avatar small rounded-circle mr-3"
+ />
+ {timeline.owner.nickname}
+ </div>
+ </>
+ }
+ manageArea={((): TimelineCardTemplateProps["manageArea"] => {
+ if (onManage == null) {
+ return { type: "member", onMember };
+ } else {
+ return {
+ type: "manage",
+ items: [
+ {
+ type: "button",
+ text: "timeline.manageItem.nickname",
+ onClick: () => onManage("nickname"),
+ },
+ {
+ type: "button",
+ text: "timeline.manageItem.avatar",
+ onClick: () => onManage("avatar"),
+ },
+ {
+ type: "button",
+ text: "timeline.manageItem.property",
+ onClick: () => onManage("property"),
+ },
+ {
+ type: "button",
+ onClick: onMember,
+ text: "timeline.manageItem.member",
+ },
+ ],
+ };
+ }
+ })()}
+ {...otherProps}
+ />
);
};