aboutsummaryrefslogtreecommitdiff
path: root/FrontEnd/src
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2023-08-31 19:18:48 +0800
committercrupest <crupest@outlook.com>2023-08-31 19:18:48 +0800
commita1f69d978426c6a4cb7e8f3116e087553dbbffd5 (patch)
tree506eb8fc76336ea2941c373aad570c73ede577e3 /FrontEnd/src
parent1a543da5a018d1a99b51bfe5d7d90edff0502a11 (diff)
downloadtimeline-a1f69d978426c6a4cb7e8f3116e087553dbbffd5.tar.gz
timeline-a1f69d978426c6a4cb7e8f3116e087553dbbffd5.tar.bz2
timeline-a1f69d978426c6a4cb7e8f3116e087553dbbffd5.zip
...
Diffstat (limited to 'FrontEnd/src')
-rw-r--r--FrontEnd/src/components/tab/TabBar.css38
-rw-r--r--FrontEnd/src/components/tab/TabBar.tsx69
-rw-r--r--FrontEnd/src/components/tab/TabPages.css0
-rw-r--r--FrontEnd/src/components/tab/TabPages.tsx56
-rw-r--r--FrontEnd/src/components/tab/Tabs.css33
-rw-r--r--FrontEnd/src/components/tab/Tabs.tsx62
-rw-r--r--FrontEnd/src/components/tab/index.ts2
-rw-r--r--FrontEnd/src/pages/timeline/MarkdownPostEdit.css13
-rw-r--r--FrontEnd/src/pages/timeline/MarkdownPostEdit.tsx10
9 files changed, 148 insertions, 135 deletions
diff --git a/FrontEnd/src/components/tab/TabBar.css b/FrontEnd/src/components/tab/TabBar.css
new file mode 100644
index 00000000..09d48c59
--- /dev/null
+++ b/FrontEnd/src/components/tab/TabBar.css
@@ -0,0 +1,38 @@
+.cru-tab-bar {
+ border-bottom: var(--cru-clickable-normal-color) 1px solid;
+ display: flex;
+}
+
+.cru-tab-bar-tab-area {
+ display: flex;
+ align-items: center;
+ gap: 0.5em;
+ border: var(--cru-clickable-normal-color) 1px solid;
+ border-bottom: none;
+ border-top-left-radius: 5px;
+ border-top-right-radius: 5px;
+ padding: 0.2em 0.5em;
+}
+
+.cru-tab-bar-item {
+ color: var(--cru-clickable-normal-color);
+ transition: all 0.5s;
+ border-radius: 5px;
+ cursor: pointer;
+ padding: 0.3em 1em;
+}
+
+.cru-tab-bar-item:hover {
+ color: var(--cru-push-button-text-color);
+ background-color: var(--cru-clickable-normal-color);
+}
+
+.cru-tab-bar-item.active {
+ color: var(--cru-push-button-text-color);
+ background-color: var(--cru-clickable-normal-color);
+ border-color: var(--cru-primary-color);
+}
+
+.cru-tab-bar-action-area {
+ margin-left: auto;
+}
diff --git a/FrontEnd/src/components/tab/TabBar.tsx b/FrontEnd/src/components/tab/TabBar.tsx
new file mode 100644
index 00000000..601f664d
--- /dev/null
+++ b/FrontEnd/src/components/tab/TabBar.tsx
@@ -0,0 +1,69 @@
+import { ReactNode } from "react";
+import { Link } from "react-router-dom";
+import classNames from "classnames";
+
+import { Text, ThemeColor, useC } from "../common";
+
+import "./TabBar.css";
+
+export interface Tab {
+ name: string;
+ text: Text;
+ link?: string;
+ onClick?: () => void;
+}
+
+export interface TabsProps {
+ activeTabName?: string;
+ tabs: Tab[];
+ color?: ThemeColor;
+ actions?: ReactNode;
+ dense?: boolean;
+ className?: string;
+}
+
+export default function TabBar(props: TabsProps) {
+ const { tabs, color, activeTabName, className, dense, actions } = props;
+
+ const c = useC();
+
+ return (
+ <div
+ className={classNames(
+ "cru-tab-bar",
+ dense && "dense",
+ `cru-clickable-${color ?? "primary"}`,
+ className,
+ )}
+ >
+ <div className="cru-tab-bar-tab-area">
+ {tabs.map((tab) => {
+ const { name, text, link, onClick } = tab;
+
+ const active = activeTabName === name;
+ const className = classNames("cru-tab-bar-item", active && "active");
+
+ if (link != null) {
+ return (
+ <Link
+ key={name}
+ to={link}
+ onClick={onClick}
+ className={className}
+ >
+ {c(text)}
+ </Link>
+ );
+ } else {
+ return (
+ <span key={name} onClick={onClick} className={className}>
+ {c(text)}
+ </span>
+ );
+ }
+ })}
+ </div>
+ <div className="cru-tab-bar-action-area">{actions}</div>
+ </div>
+ );
+}
diff --git a/FrontEnd/src/components/tab/TabPages.css b/FrontEnd/src/components/tab/TabPages.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/FrontEnd/src/components/tab/TabPages.css
diff --git a/FrontEnd/src/components/tab/TabPages.tsx b/FrontEnd/src/components/tab/TabPages.tsx
index 6a5f4469..ab45ffdf 100644
--- a/FrontEnd/src/components/tab/TabPages.tsx
+++ b/FrontEnd/src/components/tab/TabPages.tsx
@@ -1,52 +1,43 @@
-import * as React from "react";
+import { ReactNode, useState } from "react";
+import classNames from "classnames";
-import { I18nText, UiLogicError } from "~src/common";
+import { Text, UiLogicError } from "../common";
-import Tabs from "./Tabs";
+import Tabs from "./TabBar";
-export interface TabPage {
+import "./TabPages.css";
+
+interface TabPage {
name: string;
- text: I18nText;
- page: React.ReactNode;
+ text: Text;
+ page: ReactNode;
}
-export interface TabPagesProps {
+interface TabPagesProps {
pages: TabPage[];
- actions?: React.ReactNode;
+ actions?: ReactNode;
dense?: boolean;
className?: string;
- style?: React.CSSProperties;
- navClassName?: string;
- navStyle?: React.CSSProperties;
+ tabBarClassName?: string;
pageContainerClassName?: string;
- pageContainerStyle?: React.CSSProperties;
}
-const TabPages: React.FC<TabPagesProps> = ({
+export default function TabPages({
pages,
actions,
dense,
className,
- style,
- navClassName,
- navStyle,
+ tabBarClassName,
pageContainerClassName,
- pageContainerStyle,
-}) => {
- if (pages.length === 0) {
- throw new UiLogicError("Page list can't be empty.");
- }
-
- const [tab, setTab] = React.useState<string>(pages[0].name);
+}: TabPagesProps) {
+ const [tab, setTab] = useState<string>(pages[0].name);
const currentPage = pages.find((p) => p.name === tab);
- if (currentPage == null) {
- throw new UiLogicError("Current tab value is bad.");
- }
+ if (currentPage == null) throw new UiLogicError();
return (
- <div className={className} style={style}>
+ <div className={className}>
<Tabs
tabs={pages.map((page) => ({
name: page.name,
@@ -57,15 +48,14 @@ const TabPages: React.FC<TabPagesProps> = ({
}))}
dense={dense}
activeTabName={tab}
- className={navClassName}
- style={navStyle}
+ className={tabBarClassName}
actions={actions}
/>
- <div className={pageContainerClassName} style={pageContainerStyle}>
+ <div
+ className={classNames("cru-tab-page-container", pageContainerClassName)}
+ >
{currentPage.page}
</div>
</div>
);
-};
-
-export default TabPages;
+}
diff --git a/FrontEnd/src/components/tab/Tabs.css b/FrontEnd/src/components/tab/Tabs.css
deleted file mode 100644
index 395d16a7..00000000
--- a/FrontEnd/src/components/tab/Tabs.css
+++ /dev/null
@@ -1,33 +0,0 @@
-.cru-nav {
- border-bottom: var(--cru-primary-color) 1px solid;
- display: flex;
-}
-
-.cru-nav-item {
- color: var(--cru-primary-color);
- border: var(--cru-background-2-color) 0.5px solid;
- border-bottom: none;
- padding: 0.5em 1.5em;
- border-top-left-radius: 5px;
- border-top-right-radius: 5px;
- transition: all 0.5s;
- cursor: pointer;
-}
-
-.cru-nav.dense .cru-nav-item {
- padding: 0.2em 1em;
-}
-
-.cru-nav-item:hover {
- background-color: var(--cru-background-1-color);
-}
-
-.cru-nav-item.active {
- color: var(--cru-primary-t-color);
- background-color: var(--cru-primary-color);
- border-color: var(--cru-primary-color);
-}
-
-.cru-nav-action-area {
- margin-left: auto;
-}
diff --git a/FrontEnd/src/components/tab/Tabs.tsx b/FrontEnd/src/components/tab/Tabs.tsx
deleted file mode 100644
index dc8d9c01..00000000
--- a/FrontEnd/src/components/tab/Tabs.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-import * as React from "react";
-import { Link } from "react-router-dom";
-import { useTranslation } from "react-i18next";
-import classnames from "classnames";
-
-import { convertI18nText, I18nText } from "~src/common";
-
-import "./Tabs.css";
-
-export interface Tab {
- name: string;
- text: I18nText;
- link?: string;
- onClick?: () => void;
-}
-
-export interface TabsProps {
- activeTabName?: string;
- actions?: React.ReactNode;
- dense?: boolean;
- tabs: Tab[];
- className?: string;
- style?: React.CSSProperties;
-}
-
-export default function Tabs(props: TabsProps): React.ReactElement | null {
- const { tabs, activeTabName, className, style, dense, actions } = props;
-
- const { t } = useTranslation();
-
- return (
- <div
- className={classnames("cru-nav", dense && "dense", className)}
- style={style}
- >
- {tabs.map((tab) => {
- const active = activeTabName === tab.name;
- const className = classnames("cru-nav-item", active && "active");
-
- if (tab.link != null) {
- return (
- <Link
- key={tab.name}
- to={tab.link}
- onClick={tab.onClick}
- className={className}
- >
- {convertI18nText(tab.text, t)}
- </Link>
- );
- } else {
- return (
- <span key={tab.name} onClick={tab.onClick} className={className}>
- {convertI18nText(tab.text, t)}
- </span>
- );
- }
- })}
- <div className="cru-nav-action-area">{actions}</div>
- </div>
- );
-}
diff --git a/FrontEnd/src/components/tab/index.ts b/FrontEnd/src/components/tab/index.ts
new file mode 100644
index 00000000..43d545cc
--- /dev/null
+++ b/FrontEnd/src/components/tab/index.ts
@@ -0,0 +1,2 @@
+export { default as TabBar } from "./TabBar";
+export { default as TabPages } from "./TabPages";
diff --git a/FrontEnd/src/pages/timeline/MarkdownPostEdit.css b/FrontEnd/src/pages/timeline/MarkdownPostEdit.css
index e36be992..33a77943 100644
--- a/FrontEnd/src/pages/timeline/MarkdownPostEdit.css
+++ b/FrontEnd/src/pages/timeline/MarkdownPostEdit.css
@@ -3,6 +3,19 @@
max-height: 300px;
}
+.timeline-post-create-markdown-edit-area {
+ border: 1px solid var(--cru-clickable-primary-normal-color);
+ border-top: none;
+ border-bottom-left-radius: 5px;
+ border-bottom-right-radius: 5px;
+ padding: 0.6em;
+}
+
+.timeline-post-create-markdown-edit-area:hover {
+ border: 1px solid var(--cru-clickable-primary-normal-color);
+ border-top: none;
+}
+
.timeline-markdown-post-edit-image-container {
position: relative;
text-align: center;
diff --git a/FrontEnd/src/pages/timeline/MarkdownPostEdit.tsx b/FrontEnd/src/pages/timeline/MarkdownPostEdit.tsx
index fc7b882f..d10d3f2d 100644
--- a/FrontEnd/src/pages/timeline/MarkdownPostEdit.tsx
+++ b/FrontEnd/src/pages/timeline/MarkdownPostEdit.tsx
@@ -10,13 +10,13 @@ import {
import TimelinePostBuilder from "~src/services/TimelinePostBuilder";
import FlatButton from "~src/components/button/FlatButton";
-import TabPages from "~src/components/tab/TabPages";
+import { TabPages } from "~src/components/tab";
import ConfirmDialog from "~src/components/dialog/ConfirmDialog";
import Spinner from "~src/components/Spinner";
import IconButton from "~src/components/button/IconButton";
+import { DialogProvider, useDialog } from "~src/components/dialog";
import "./MarkdownPostEdit.css";
-import { DialogProvider, useDialog } from "~src/components/dialog";
export interface MarkdownPostEditProps {
owner: string;
@@ -25,7 +25,6 @@ export interface MarkdownPostEditProps {
onPostError: () => void;
onClose: () => void;
className?: string;
- style?: React.CSSProperties;
}
const MarkdownPostEdit: React.FC<MarkdownPostEditProps> = ({
@@ -35,7 +34,6 @@ const MarkdownPostEdit: React.FC<MarkdownPostEditProps> = ({
onClose,
onPostError,
className,
- style,
}) => {
const { t } = useTranslation();
@@ -117,8 +115,6 @@ const MarkdownPostEdit: React.FC<MarkdownPostEditProps> = ({
<>
<TabPages
className={className}
- style={style}
- pageContainerClassName="py-2"
dense
actions={
process ? (
@@ -152,7 +148,7 @@ const MarkdownPostEdit: React.FC<MarkdownPostEditProps> = ({
<textarea
value={text}
disabled={process}
- className="cru-fill-parent"
+ className="timeline-post-create-markdown-edit-area cru-fill-parent"
onChange={(event) => {
getBuilder().setMarkdownText(event.currentTarget.value);
}}