From f5dfd52f6efece2f4cad227044ecf4dd66301bbc Mon Sep 17 00:00:00 2001
From: crupest <crupest@outlook.com>
Date: Sat, 26 Aug 2023 21:36:58 +0800
Subject: ...

---
 FrontEnd/src/components/Page.tsx | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
 create mode 100644 FrontEnd/src/components/Page.tsx

(limited to 'FrontEnd/src/components/Page.tsx')

diff --git a/FrontEnd/src/components/Page.tsx b/FrontEnd/src/components/Page.tsx
new file mode 100644
index 00000000..86fdb2f5
--- /dev/null
+++ b/FrontEnd/src/components/Page.tsx
@@ -0,0 +1,15 @@
+import { ComponentPropsWithoutRef, Ref } from "react";
+import classNames from "classnames";
+
+interface PageProps extends ComponentPropsWithoutRef<"div"> {
+  noTopPadding?: boolean;
+  pageRef?: Ref<HTMLDivElement>;
+}
+
+export default function Page({ noTopPadding, pageRef, className, children }: PageProps) {
+  return (
+    <div ref={pageRef} className={classNames(className, "cru-page", noTopPadding && "cru-page-no-top-padding")}>
+      {children}
+    </div>
+  );
+}
-- 
cgit v1.2.3


From aef14be13c3bd9e93eeea598dbfbf707ba98d448 Mon Sep 17 00:00:00 2001
From: crupest <crupest@outlook.com>
Date: Thu, 14 Sep 2023 23:47:16 +0800
Subject: ...

---
 FrontEnd/src/components/Page.css                   |  8 +++
 FrontEnd/src/components/Page.tsx                   |  2 +
 FrontEnd/src/components/index.css                  | 66 +++-------------------
 FrontEnd/src/components/menu/Menu.tsx              | 14 ++---
 FrontEnd/src/components/menu/PopupMenu.tsx         |  3 +-
 FrontEnd/src/components/tab/TabBar.css             | 18 ++----
 FrontEnd/src/components/tab/TabPages.css           |  3 +
 FrontEnd/src/components/theme.css                  |  4 +-
 FrontEnd/src/pages/timeline/edit/ImagePostEdit.css |  3 +-
 FrontEnd/src/pages/timeline/edit/ImagePostEdit.tsx | 10 ++--
 .../src/pages/timeline/edit/MarkdownPostEdit.css   | 34 ++++-------
 .../src/pages/timeline/edit/MarkdownPostEdit.tsx   |  3 +-
 .../src/pages/timeline/edit/PlainTextPostEdit.css  | 19 ++-----
 .../pages/timeline/edit/TimelinePostCreateView.css |  8 ++-
 .../pages/timeline/edit/TimelinePostCreateView.tsx |  2 +
 15 files changed, 71 insertions(+), 126 deletions(-)
 create mode 100644 FrontEnd/src/components/Page.css

(limited to 'FrontEnd/src/components/Page.tsx')

diff --git a/FrontEnd/src/components/Page.css b/FrontEnd/src/components/Page.css
new file mode 100644
index 00000000..b22d83af
--- /dev/null
+++ b/FrontEnd/src/components/Page.css
@@ -0,0 +1,8 @@
+.cru-page {
+  padding: var(--cru-page-padding);
+}
+
+.cru-page-no-top-padding {
+  padding-top: 0;
+}
+
diff --git a/FrontEnd/src/components/Page.tsx b/FrontEnd/src/components/Page.tsx
index 86fdb2f5..8c9febcc 100644
--- a/FrontEnd/src/components/Page.tsx
+++ b/FrontEnd/src/components/Page.tsx
@@ -1,6 +1,8 @@
 import { ComponentPropsWithoutRef, Ref } from "react";
 import classNames from "classnames";
 
+import "./Page.css";
+
 interface PageProps extends ComponentPropsWithoutRef<"div"> {
   noTopPadding?: boolean;
   pageRef?: Ref<HTMLDivElement>;
diff --git a/FrontEnd/src/components/index.css b/FrontEnd/src/components/index.css
index 32e762cb..de156e0e 100644
--- a/FrontEnd/src/components/index.css
+++ b/FrontEnd/src/components/index.css
@@ -13,69 +13,17 @@ body {
   line-height: 1.2;
 }
 
-.cru-page {
-  padding: var(--cru-page-padding);
+textarea {
+  transition: border-color 0.3s;
+  border-color: var(--cru-text-minor-color);
 }
 
-.cru-page-no-top-padding {
-  padding-top: 0;
+textarea:hover {
+  border-color: var(--cru-clickable-primary-hover-color);
 }
 
-.cru-text-center {
-  text-align: center;
-}
-
-.cru-text-end {
-  text-align: end;
-}
-
-.cru-float-left {
-  float: left;
-}
-
-.cru-float-right {
-  float: right;
-}
-
-.cru-align-text-bottom {
-  vertical-align: text-bottom;
-}
-
-.cru-align-middle {
-  vertical-align: middle;
-}
-
-.cru-clearfix::after {
-  clear: both;
-}
-
-.cru-fill-parent {
-  width: 100%;
-  height: 100%;
-}
-
-.cru-avatar {
-  width: 60px;
-  height: 60px;
-}
-
-.cru-avatar.large {
-  width: 100px;
-  height: 100px;
-}
-
-.cru-avatar.small {
-  width: 40px;
-  height: 40px;
-}
-
-.cru-round {
-  border-radius: 50%;
-}
-
-.cru-tab-pages-action-area {
-  display: flex;
-  align-items: center;
+textarea:focus {
+  border-color: var(--cru-clickable-primary-normal-color);
 }
 
 .alert-container {
diff --git a/FrontEnd/src/components/menu/Menu.tsx b/FrontEnd/src/components/menu/Menu.tsx
index c01c6cfb..1a196a69 100644
--- a/FrontEnd/src/components/menu/Menu.tsx
+++ b/FrontEnd/src/components/menu/Menu.tsx
@@ -1,4 +1,4 @@
-import { CSSProperties } from "react";
+import { MouseEvent, CSSProperties } from "react";
 import classNames from "classnames";
 
 import { useC, Text, ThemeColor } from "../common";
@@ -15,21 +15,21 @@ export type MenuItem =
       text: Text;
       icon?: string;
       color?: ThemeColor;
-      onClick: () => void;
+      onClick?: (e: MouseEvent<HTMLButtonElement>) => void;
     };
 
 export type MenuItems = MenuItem[];
 
 export type MenuProps = {
   items: MenuItems;
-  onItemClicked?: () => void;
+  onItemClick?: (e: MouseEvent<HTMLButtonElement>) => void;
   className?: string;
   style?: CSSProperties;
 };
 
 export default function Menu({
   items,
-  onItemClicked,
+  onItemClick,
   className,
   style,
 }: MenuProps) {
@@ -46,9 +46,9 @@ export default function Menu({
             <button
               key={index}
               className={`cru-menu-item cru-clickable-${color ?? "primary"}`}
-              onClick={() => {
-                onClick();
-                onItemClicked?.();
+              onClick={(e) => {
+                onClick?.(e);
+                onItemClick?.(e);
               }}
             >
               {icon != null && <Icon color={color} icon={icon} />}
diff --git a/FrontEnd/src/components/menu/PopupMenu.tsx b/FrontEnd/src/components/menu/PopupMenu.tsx
index 9d90799d..7ac2abfe 100644
--- a/FrontEnd/src/components/menu/PopupMenu.tsx
+++ b/FrontEnd/src/components/menu/PopupMenu.tsx
@@ -58,8 +58,9 @@ export default function PopupMenu({
           >
             <Menu
               items={items}
-              onItemClicked={() => {
+              onItemClick={(e) => {
                 setShow(false);
+                e.stopPropagation();
               }}
             />
           </div>,
diff --git a/FrontEnd/src/components/tab/TabBar.css b/FrontEnd/src/components/tab/TabBar.css
index 09d48c59..dc6970c7 100644
--- a/FrontEnd/src/components/tab/TabBar.css
+++ b/FrontEnd/src/components/tab/TabBar.css
@@ -1,30 +1,24 @@
 .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;
+  border: var(--cru-clickable-normal-color) 1.6px solid;
+  border-radius: 3px;
+  overflow: hidden;
 }
 
 .cru-tab-bar-item {
-  color: var(--cru-clickable-normal-color);
-  transition: all 0.5s;
-  border-radius: 5px;
+  color: var(--cru-text-minor-color);
+  transition: all 0.2s;
   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);
+  color: var(--cru-clickable-normal-color);
 }
 
 .cru-tab-bar-item.active {
diff --git a/FrontEnd/src/components/tab/TabPages.css b/FrontEnd/src/components/tab/TabPages.css
index e69de29b..c07d042e 100644
--- a/FrontEnd/src/components/tab/TabPages.css
+++ b/FrontEnd/src/components/tab/TabPages.css
@@ -0,0 +1,3 @@
+.cru-tab-page-container {
+  padding-top: 0.5em;
+}
diff --git a/FrontEnd/src/components/theme.css b/FrontEnd/src/components/theme.css
index 487ab959..4727d6dd 100644
--- a/FrontEnd/src/components/theme.css
+++ b/FrontEnd/src/components/theme.css
@@ -1,5 +1,5 @@
 :root {
-  --cru-default-font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
+  --cru-default-font-family: 'Segoe UI', 'DengXian', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
   --cru-page-padding: 1em 2em;
 
   --cru-border-radius: 4px;
@@ -197,4 +197,4 @@
 .cru-card-danger {
   --cru-card-background-color: var(--cru-card-background-danger-color);
   --cru-card-border-color: var(--cru-card-border-danger-color)
-}
\ No newline at end of file
+}
diff --git a/FrontEnd/src/pages/timeline/edit/ImagePostEdit.css b/FrontEnd/src/pages/timeline/edit/ImagePostEdit.css
index df7a6af6..232681c8 100644
--- a/FrontEnd/src/pages/timeline/edit/ImagePostEdit.css
+++ b/FrontEnd/src/pages/timeline/edit/ImagePostEdit.css
@@ -1,4 +1,5 @@
-.timeline-edit-image {
+.timeline-edit-image-image {
   max-width: 100px;
   max-height: 100px;
 }
+
diff --git a/FrontEnd/src/pages/timeline/edit/ImagePostEdit.tsx b/FrontEnd/src/pages/timeline/edit/ImagePostEdit.tsx
index 4676e45a..c62c8ee5 100644
--- a/FrontEnd/src/pages/timeline/edit/ImagePostEdit.tsx
+++ b/FrontEnd/src/pages/timeline/edit/ImagePostEdit.tsx
@@ -2,6 +2,8 @@ import classNames from "classnames";
 
 import BlobImage from "~/src/components/BlobImage";
 
+import "./ImagePostEdit.css";
+
 interface TimelinePostEditImageProps {
   file: File | null;
   onChange: (file: File | null) => void;
@@ -13,9 +15,7 @@ export default function ImagePostEdit(props: TimelinePostEditImageProps) {
   const { file, onChange, disabled, className } = props;
 
   return (
-    <div
-      className={classNames("timeline-edit-image-container", className)}
-    >
+    <div className={classNames("timeline-edit-image-container", className)}>
       <input
         type="file"
         accept="image/*"
@@ -28,9 +28,9 @@ export default function ImagePostEdit(props: TimelinePostEditImageProps) {
             onChange(files[0]);
           }
         }}
-        className="mx-3 my-1"
+        className="timeline-edit-image-input"
       />
-      {file && <BlobImage src={file} className="timeline-edit-image" />}
+      {file && <BlobImage src={file} className="timeline-edit-image-image" />}
     </div>
   );
 }
diff --git a/FrontEnd/src/pages/timeline/edit/MarkdownPostEdit.css b/FrontEnd/src/pages/timeline/edit/MarkdownPostEdit.css
index 33a77943..c5b41b40 100644
--- a/FrontEnd/src/pages/timeline/edit/MarkdownPostEdit.css
+++ b/FrontEnd/src/pages/timeline/edit/MarkdownPostEdit.css
@@ -1,34 +1,24 @@
-.timeline-markdown-post-edit-page {
-  overflow: auto;
-  max-height: 300px;
+.timeline-edit-markdown-tab-page {
+  min-height: 8em;
+  display: flex;
 }
 
-.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-edit-markdown-text {
+  width: 100%;
 }
 
-.timeline-post-create-markdown-edit-area:hover {
-  border: 1px solid var(--cru-clickable-primary-normal-color);
-  border-top: none;
+.timeline-edit-markdown-images {
+  display: flex;
+  flex-wrap: wrap;
 }
 
-.timeline-markdown-post-edit-image-container {
-  position: relative;
-  text-align: center;
-  margin-bottom: 1em;
+.timeline-edit-markdown-images img {
+  max-width: 100%;
+  max-height: 200px;
 }
 
-.timeline-markdown-post-edit-image {
+.timeline-edit-markdown-preview img {
   max-width: 100%;
   max-height: 200px;
 }
 
-.timeline-markdown-post-edit-image-delete-button {
-  position: absolute;
-  right: 10px;
-  top: 2px;
-}
diff --git a/FrontEnd/src/pages/timeline/edit/MarkdownPostEdit.tsx b/FrontEnd/src/pages/timeline/edit/MarkdownPostEdit.tsx
index 0dfaf33e..692221fd 100644
--- a/FrontEnd/src/pages/timeline/edit/MarkdownPostEdit.tsx
+++ b/FrontEnd/src/pages/timeline/edit/MarkdownPostEdit.tsx
@@ -27,7 +27,7 @@ class MarkedRenderer extends marked.Renderer {
       }
     }
 
-    return this.image(href, title, text);
+    return super.image(href, title, text);
   }
 }
 
@@ -136,6 +136,7 @@ export function MarkdownPostEdit({
   return (
     <TabPages
       className={className}
+      pageContainerClassName="timeline-edit-markdown-tab-page"
       dense
       pages={[
         {
diff --git a/FrontEnd/src/pages/timeline/edit/PlainTextPostEdit.css b/FrontEnd/src/pages/timeline/edit/PlainTextPostEdit.css
index 4a608304..d1a61793 100644
--- a/FrontEnd/src/pages/timeline/edit/PlainTextPostEdit.css
+++ b/FrontEnd/src/pages/timeline/edit/PlainTextPostEdit.css
@@ -1,19 +1,12 @@
-.timeline-edit-plain-text-input {
+.timeline-edit-plain-text-container {
   width: 100%;
   height: 100%;
-  background-color: var(--cru-background-color);
-  color: var(--cru-text-major-color);
-  border: 1px solid var(--cru-text-major-color);
-  padding: 0.5em;
-  border-radius: 5px;
-  transition: border-color 0.5s;
-}
-
-.timeline-edit-plain-text-input:hover {
-  border-color: var(--cru-clickable-secondary-normal-color);
 }
 
-.timeline-edit-plain-text-input:focus {
-  border-color: var(--cru-clickable-secondary-normal-color);
+.timeline-edit-plain-text-input {
+  width: 100%;
+  height: 100%;
+  padding: 0.5em;
+  border-radius: 4px;
 }
 
diff --git a/FrontEnd/src/pages/timeline/edit/TimelinePostCreateView.css b/FrontEnd/src/pages/timeline/edit/TimelinePostCreateView.css
index 5e93d9f2..6efe93e9 100644
--- a/FrontEnd/src/pages/timeline/edit/TimelinePostCreateView.css
+++ b/FrontEnd/src/pages/timeline/edit/TimelinePostCreateView.css
@@ -10,7 +10,7 @@
     padding-top: 60px;
   }
 
-  .timeline-post-create-card{
+  .timeline-post-create-card {
     margin-right: 0;
   }
 }
@@ -23,11 +23,13 @@
   flex-grow: 1;
 }
 
-
-
 .timeline-post-create-right-area {
   display: flex;
   flex-direction: column;
   align-items: center;
   margin-left: 1em;
 }
+
+.timeline-post-create-send {
+  margin-top: auto;
+}
diff --git a/FrontEnd/src/pages/timeline/edit/TimelinePostCreateView.tsx b/FrontEnd/src/pages/timeline/edit/TimelinePostCreateView.tsx
index 0de75ccd..c0a80ad0 100644
--- a/FrontEnd/src/pages/timeline/edit/TimelinePostCreateView.tsx
+++ b/FrontEnd/src/pages/timeline/edit/TimelinePostCreateView.tsx
@@ -104,6 +104,7 @@ function TimelinePostEdit(props: TimelinePostEditProps) {
           throw new UiLogicError();
         }
         requestDataList = await mdBuild();
+        break;
       default:
         throw new UiLogicError("Unknown content type.");
     }
@@ -174,6 +175,7 @@ function TimelinePostEdit(props: TimelinePostEditProps) {
               <IconButton color="primary" icon={postKindIconMap[kind]} />
             </PopupMenu>
             <LoadingButton
+              className="timeline-post-create-send"
               onClick={() => void onSend()}
               color="primary"
               disabled={!canSend}
-- 
cgit v1.2.3

