From de7df0e4fb38863b830a104a5a38d0e5247679f8 Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 29 Jun 2021 23:50:55 +0800 Subject: ... --- FrontEnd/src/views/common/menu/PopupMenu.tsx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 FrontEnd/src/views/common/menu/PopupMenu.tsx (limited to 'FrontEnd/src/views/common/menu/PopupMenu.tsx') diff --git a/FrontEnd/src/views/common/menu/PopupMenu.tsx b/FrontEnd/src/views/common/menu/PopupMenu.tsx new file mode 100644 index 00000000..0d447f09 --- /dev/null +++ b/FrontEnd/src/views/common/menu/PopupMenu.tsx @@ -0,0 +1,17 @@ +import React from "react"; + +import Menu, { MenuItems } from "./Menu"; + +export interface PopupMenuProps { + items: MenuItems; + children: React.ReactElement; +} + +export const PopupMenu: React.FC = ({ items, children }) => { + const [show, setShow] = React.useState(false); + const toggle = (): void => setShow(!show); + + // TODO: + + return setShow(false)} />; +}; -- cgit v1.2.3 From 6b5d88a6a1a3fe12721f3159a6837d3f41d69022 Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 30 Jun 2021 00:15:20 +0800 Subject: ... --- FrontEnd/package.json | 2 + FrontEnd/src/views/common/menu/Menu.tsx | 22 +++++---- FrontEnd/src/views/common/menu/PopupMenu.css | 3 ++ FrontEnd/src/views/common/menu/PopupMenu.tsx | 56 ++++++++++++++++++++-- .../timeline-common/TimelinePageCardTemplate.tsx | 3 +- .../src/views/timeline-common/TimelinePostEdit.tsx | 2 +- 6 files changed, 73 insertions(+), 15 deletions(-) create mode 100644 FrontEnd/src/views/common/menu/PopupMenu.css (limited to 'FrontEnd/src/views/common/menu/PopupMenu.tsx') diff --git a/FrontEnd/package.json b/FrontEnd/package.json index 55c7c95f..2c92d6b2 100644 --- a/FrontEnd/package.json +++ b/FrontEnd/package.json @@ -7,6 +7,7 @@ "description": "Timeline app.", "dependencies": { "@microsoft/signalr": "^5.0.7", + "@popperjs/core": "^2.9.2", "axios": "^0.21.1", "bootstrap": "^5.0.2", "bootstrap-icons": "^1.5.0", @@ -23,6 +24,7 @@ "react-color": "^2.19.3", "react-dom": "^17.0.2", "react-i18next": "^11.11.0", + "react-popper": "^2.2.5", "react-responsive": "^8.2.0", "react-router": "^5.2.0", "react-router-dom": "^5.2.0", diff --git a/FrontEnd/src/views/common/menu/Menu.tsx b/FrontEnd/src/views/common/menu/Menu.tsx index 7523247d..04243fa3 100644 --- a/FrontEnd/src/views/common/menu/Menu.tsx +++ b/FrontEnd/src/views/common/menu/Menu.tsx @@ -5,6 +5,8 @@ import { useTranslation } from "react-i18next"; import { convertI18nText, I18nText } from "@/common"; import { PaletteColorType } from "@/palette"; +import "./Menu.css"; + export type MenuItem = | { type: "divider"; @@ -19,17 +21,23 @@ export type MenuItem = export type MenuItems = MenuItem[]; -export interface MenuProps { +export type MenuProps = { items: MenuItems; - className?: string; onItemClicked?: () => void; -} + className?: string; + style?: React.CSSProperties; +}; -const Menu: React.FC = ({ items, className, onItemClicked }) => { +export default function _Menu({ + items, + onItemClicked, + className, + style, +}: MenuProps): React.ReactElement | null { const { t } = useTranslation(); return ( -
+
{items.map((item, index) => { if (item.type === "divider") { return
; @@ -61,6 +69,4 @@ const Menu: React.FC = ({ items, className, onItemClicked }) => { })}
); -}; - -export default Menu; +} diff --git a/FrontEnd/src/views/common/menu/PopupMenu.css b/FrontEnd/src/views/common/menu/PopupMenu.css new file mode 100644 index 00000000..8465a1bb --- /dev/null +++ b/FrontEnd/src/views/common/menu/PopupMenu.css @@ -0,0 +1,3 @@ +.cru-popup-menu-menu-container { + +} diff --git a/FrontEnd/src/views/common/menu/PopupMenu.tsx b/FrontEnd/src/views/common/menu/PopupMenu.tsx index 0d447f09..50f80a91 100644 --- a/FrontEnd/src/views/common/menu/PopupMenu.tsx +++ b/FrontEnd/src/views/common/menu/PopupMenu.tsx @@ -1,17 +1,63 @@ +import classNames from "classnames"; import React from "react"; +import { usePopper } from "react-popper"; import Menu, { MenuItems } from "./Menu"; +import "./PopupMenu.css"; + export interface PopupMenuProps { items: MenuItems; - children: React.ReactElement; + children?: React.ReactNode; + containerClassName?: string; + containerStyle?: React.CSSProperties; } -export const PopupMenu: React.FC = ({ items, children }) => { +const PopupMenu: React.FC = ({ + items, + children, + containerClassName, + containerStyle, +}) => { const [show, setShow] = React.useState(false); - const toggle = (): void => setShow(!show); - // TODO: + const [referenceElement, setReferenceElement] = + React.useState(null); + const [popperElement, setPopperElement] = + React.useState(null); + const [arrowElement, setArrowElement] = React.useState( + null + ); + const { styles, attributes } = usePopper(referenceElement, popperElement, { + modifiers: [{ name: "arrow", options: { element: arrowElement } }], + }); - return setShow(false)} />; + return ( + <> +
setShow(true)} + > + {children} +
+ {show ? ( +
+ +
+
+ ) : null} + + ); }; + +export default PopupMenu; diff --git a/FrontEnd/src/views/timeline-common/TimelinePageCardTemplate.tsx b/FrontEnd/src/views/timeline-common/TimelinePageCardTemplate.tsx index 78af1131..75f2d400 100644 --- a/FrontEnd/src/views/timeline-common/TimelinePageCardTemplate.tsx +++ b/FrontEnd/src/views/timeline-common/TimelinePageCardTemplate.tsx @@ -17,7 +17,8 @@ import CollapseButton from "./CollapseButton"; import { TimelineMemberDialog } from "./TimelineMember"; import TimelinePropertyChangeDialog from "./TimelinePropertyChangeDialog"; import ConnectionStatusBadge from "./ConnectionStatusBadge"; -import { MenuItems, PopupMenu } from "../common/menu/Menu"; +import { MenuItems } from "../common/menu/Menu"; +import PopupMenu from "../common/menu/PopupMenu"; import FullPageDialog from "../common/dailog/FullPageDialog"; import Card from "../common/Card"; diff --git a/FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx b/FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx index 1e6591c0..e2045429 100644 --- a/FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx +++ b/FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx @@ -16,7 +16,7 @@ import { base64 } from "@/http/common"; import BlobImage from "../common/BlobImage"; import LoadingButton from "../common/button/LoadingButton"; -import { PopupMenu } from "../common/menu/Menu"; +import PopupMenu from "../common/menu/PopupMenu"; import Card from "../common/Card"; import MarkdownPostEdit from "./MarkdownPostEdit"; import TimelineLine from "./TimelineLine"; -- cgit v1.2.3 From 979ad8556be3576b09e318c9e85ae0138ecf11ec Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 30 Jun 2021 18:18:04 +0800 Subject: ... --- FrontEnd/src/views/common/index.css | 2 ++ FrontEnd/src/views/common/menu/PopupMenu.css | 4 +++- FrontEnd/src/views/common/menu/PopupMenu.tsx | 32 +++++++++++++++++++++------- 3 files changed, 29 insertions(+), 9 deletions(-) (limited to 'FrontEnd/src/views/common/menu/PopupMenu.tsx') diff --git a/FrontEnd/src/views/common/index.css b/FrontEnd/src/views/common/index.css index e2769fe4..cb1cccd4 100644 --- a/FrontEnd/src/views/common/index.css +++ b/FrontEnd/src/views/common/index.css @@ -1,4 +1,6 @@ :root { + --cru-background-color: #f8f9fa; + --cru-primary-color: rgb(255, 105, 0); --cru-primary-l1-color: rgb(255, 120, 26); --cru-primary-l2-color: rgb(255, 135, 51); diff --git a/FrontEnd/src/views/common/menu/PopupMenu.css b/FrontEnd/src/views/common/menu/PopupMenu.css index 8465a1bb..8f8fd20e 100644 --- a/FrontEnd/src/views/common/menu/PopupMenu.css +++ b/FrontEnd/src/views/common/menu/PopupMenu.css @@ -1,3 +1,5 @@ .cru-popup-menu-menu-container { - + border-radius: 5px; + border: var(--cru-primary-color) 1px solid; + background-color: var(--cru-background-color); } diff --git a/FrontEnd/src/views/common/menu/PopupMenu.tsx b/FrontEnd/src/views/common/menu/PopupMenu.tsx index 50f80a91..851f3bee 100644 --- a/FrontEnd/src/views/common/menu/PopupMenu.tsx +++ b/FrontEnd/src/views/common/menu/PopupMenu.tsx @@ -25,12 +25,24 @@ const PopupMenu: React.FC = ({ React.useState(null); const [popperElement, setPopperElement] = React.useState(null); - const [arrowElement, setArrowElement] = React.useState( - null - ); - const { styles, attributes } = usePopper(referenceElement, popperElement, { - modifiers: [{ name: "arrow", options: { element: arrowElement } }], - }); + const { styles, attributes } = usePopper(referenceElement, popperElement); + + React.useEffect(() => { + const handler = (event: MouseEvent): void => { + let element: HTMLElement | null = event.target as HTMLElement; + while (element) { + if (element == referenceElement || element == popperElement) { + return; + } + element = element.parentElement; + } + setShow(false); + }; + document.addEventListener("click", handler); + return () => { + document.removeEventListener("click", handler); + }; + }, [referenceElement, popperElement]); return ( <> @@ -52,8 +64,12 @@ const PopupMenu: React.FC = ({ style={styles.popper} {...attributes.popper} > - -
+ { + setShow(false); + }} + />
) : null} -- cgit v1.2.3 From bb7a017dba4c466eaf167627b3605cf539b1e516 Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 30 Jun 2021 19:00:13 +0800 Subject: ... --- FrontEnd/src/palette.ts | 6 +- FrontEnd/src/views/common/index.css | 78 +++++++++++----------- FrontEnd/src/views/common/menu/Menu.css | 2 +- FrontEnd/src/views/common/menu/PopupMenu.css | 1 + FrontEnd/src/views/common/menu/PopupMenu.tsx | 35 +++++----- .../timeline-common/TimelinePageCardTemplate.tsx | 2 +- FrontEnd/src/views/timeline/TimelineCard.tsx | 12 ++-- FrontEnd/src/views/user/UserCard.tsx | 8 ++- 8 files changed, 77 insertions(+), 67 deletions(-) (limited to 'FrontEnd/src/views/common/menu/PopupMenu.tsx') diff --git a/FrontEnd/src/palette.ts b/FrontEnd/src/palette.ts index fb54f042..ca1f76cf 100644 --- a/FrontEnd/src/palette.ts +++ b/FrontEnd/src/palette.ts @@ -90,7 +90,7 @@ export function generatePalette(options: { primaryEnhance == null ? lightenBy(p, 0.3).saturate(0.3) : Color(primaryEnhance); - const s = secondary == null ? p.rotate(90) : Color(secondary); + const s = secondary == null ? Color("gray") : Color(secondary); return { primary: generatePaletteColor(p.toString()), @@ -130,8 +130,8 @@ export function generatePaletteCSS(palette: Palette): string { const paletteSubject: BehaviorSubject = new BehaviorSubject( - generatePalette({ primary: "rgb(0, 123, 255)" }) - // null + // generatePalette({ primary: "rgb(0, 123, 255)" }) + null ); export const palette$: Observable = diff --git a/FrontEnd/src/views/common/index.css b/FrontEnd/src/views/common/index.css index d7501f98..4a860e95 100644 --- a/FrontEnd/src/views/common/index.css +++ b/FrontEnd/src/views/common/index.css @@ -1,45 +1,45 @@ :root { --cru-background-color: #f8f9fa; - --cru-primary-color: rgb(255, 105, 0); - --cru-primary-l1-color: rgb(255, 120, 26); - --cru-primary-l2-color: rgb(255, 135, 51); - --cru-primary-l3-color: rgb(255, 150, 77); - --cru-primary-d1-color: rgb(230, 95, 0); - --cru-primary-d2-color: rgb(204, 84, 0); - --cru-primary-d3-color: rgb(179, 74, 0); - --cru-primary-f1-color: rgb(230, 95, 0); - --cru-primary-f2-color: rgb(204, 84, 0); - --cru-primary-f3-color: rgb(179, 74, 0); - --cru-primary-r1-color: rgb(255, 120, 26); - --cru-primary-r2-color: rgb(255, 135, 51); - --cru-primary-r3-color: rgb(255, 150, 77); - --cru-primary-enhance-color: rgb(255, 150, 77); - --cru-primary-enhance-l1-color: rgb(255, 161, 94); - --cru-primary-enhance-l2-color: rgb(255, 171, 112); - --cru-primary-enhance-l3-color: rgb(255, 182, 130); - --cru-primary-enhance-d1-color: rgb(255, 131, 43); - --cru-primary-enhance-d2-color: rgb(255, 111, 10); - --cru-primary-enhance-d3-color: rgb(232, 96, 0); - --cru-primary-enhance-f1-color: rgb(255, 161, 94); - --cru-primary-enhance-f2-color: rgb(255, 171, 112); - --cru-primary-enhance-f3-color: rgb(255, 182, 130); - --cru-primary-enhance-r1-color: rgb(255, 131, 43); - --cru-primary-enhance-r2-color: rgb(255, 111, 10); - --cru-primary-enhance-r3-color: rgb(232, 96, 0); - --cru-secondary-color: rgb(23, 255, 0); - --cru-secondary-l1-color: rgb(46, 255, 26); - --cru-secondary-l2-color: rgb(69, 255, 51); - --cru-secondary-l3-color: rgb(92, 255, 77); - --cru-secondary-d1-color: rgb(20, 230, 0); - --cru-secondary-d2-color: rgb(18, 204, 0); - --cru-secondary-d3-color: rgb(16, 179, 0); - --cru-secondary-f1-color: rgb(20, 230, 0); - --cru-secondary-f2-color: rgb(18, 204, 0); - --cru-secondary-f3-color: rgb(16, 179, 0); - --cru-secondary-r1-color: rgb(46, 255, 26); - --cru-secondary-r2-color: rgb(69, 255, 51); - --cru-secondary-r3-color: rgb(92, 255, 77); + --cru-primary-color: rgb(0, 123, 255); + --cru-primary-l1-color: rgb(26, 136, 255); + --cru-primary-l2-color: rgb(51, 149, 255); + --cru-primary-l3-color: rgb(77, 163, 255); + --cru-primary-d1-color: rgb(0, 111, 230); + --cru-primary-d2-color: rgb(0, 98, 204); + --cru-primary-d3-color: rgb(0, 86, 179); + --cru-primary-f1-color: rgb(0, 111, 230); + --cru-primary-f2-color: rgb(0, 98, 204); + --cru-primary-f3-color: rgb(0, 86, 179); + --cru-primary-r1-color: rgb(26, 136, 255); + --cru-primary-r2-color: rgb(51, 149, 255); + --cru-primary-r3-color: rgb(77, 163, 255); + --cru-primary-enhance-color: rgb(77, 163, 255); + --cru-primary-enhance-l1-color: rgb(94, 172, 255); + --cru-primary-enhance-l2-color: rgb(112, 181, 255); + --cru-primary-enhance-l3-color: rgb(130, 190, 255); + --cru-primary-enhance-d1-color: rgb(43, 145, 255); + --cru-primary-enhance-d2-color: rgb(10, 128, 255); + --cru-primary-enhance-d3-color: rgb(0, 112, 232); + --cru-primary-enhance-f1-color: rgb(94, 172, 255); + --cru-primary-enhance-f2-color: rgb(112, 181, 255); + --cru-primary-enhance-f3-color: rgb(130, 190, 255); + --cru-primary-enhance-r1-color: rgb(43, 145, 255); + --cru-primary-enhance-r2-color: rgb(10, 128, 255); + --cru-primary-enhance-r3-color: rgb(0, 112, 232); + --cru-secondary-color: rgb(128, 128, 128); + --cru-secondary-l1-color: rgb(141, 141, 141); + --cru-secondary-l2-color: rgb(153, 153, 153); + --cru-secondary-l3-color: rgb(166, 166, 166); + --cru-secondary-d1-color: rgb(115, 115, 115); + --cru-secondary-d2-color: rgb(102, 102, 102); + --cru-secondary-d3-color: rgb(90, 90, 90); + --cru-secondary-f1-color: rgb(115, 115, 115); + --cru-secondary-f2-color: rgb(102, 102, 102); + --cru-secondary-f3-color: rgb(90, 90, 90); + --cru-secondary-r1-color: rgb(141, 141, 141); + --cru-secondary-r2-color: rgb(153, 153, 153); + --cru-secondary-r3-color: rgb(166, 166, 166); --cru-text-primary-color: rgb(17, 17, 17); --cru-text-primary-l1-color: rgb(41, 41, 41); --cru-text-primary-l2-color: rgb(65, 65, 65); diff --git a/FrontEnd/src/views/common/menu/Menu.css b/FrontEnd/src/views/common/menu/Menu.css index 0b455baa..e0ea2cad 100644 --- a/FrontEnd/src/views/common/menu/Menu.css +++ b/FrontEnd/src/views/common/menu/Menu.css @@ -3,7 +3,7 @@ } .cru-menu-item { - font-size: 1.2em; + font-size: 1em; padding: 0.5em 1.5em; cursor: pointer; } diff --git a/FrontEnd/src/views/common/menu/PopupMenu.css b/FrontEnd/src/views/common/menu/PopupMenu.css index 8f8fd20e..658532d3 100644 --- a/FrontEnd/src/views/common/menu/PopupMenu.css +++ b/FrontEnd/src/views/common/menu/PopupMenu.css @@ -1,4 +1,5 @@ .cru-popup-menu-menu-container { + z-index: 1040; border-radius: 5px; border: var(--cru-primary-color) 1px solid; background-color: var(--cru-background-color); diff --git a/FrontEnd/src/views/common/menu/PopupMenu.tsx b/FrontEnd/src/views/common/menu/PopupMenu.tsx index 851f3bee..d7b81f49 100644 --- a/FrontEnd/src/views/common/menu/PopupMenu.tsx +++ b/FrontEnd/src/views/common/menu/PopupMenu.tsx @@ -1,5 +1,6 @@ import classNames from "classnames"; import React from "react"; +import { createPortal } from "react-dom"; import { usePopper } from "react-popper"; import Menu, { MenuItems } from "./Menu"; @@ -57,21 +58,25 @@ const PopupMenu: React.FC = ({ > {children}
- {show ? ( -
- { - setShow(false); - }} - /> -
- ) : null} + {show + ? createPortal( +
+ { + setShow(false); + }} + /> +
, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + document.getElementById("portal")! + ) + : null} ); }; diff --git a/FrontEnd/src/views/timeline-common/TimelinePageCardTemplate.tsx b/FrontEnd/src/views/timeline-common/TimelinePageCardTemplate.tsx index f57fda2e..4802ca93 100644 --- a/FrontEnd/src/views/timeline-common/TimelinePageCardTemplate.tsx +++ b/FrontEnd/src/views/timeline-common/TimelinePageCardTemplate.tsx @@ -23,7 +23,7 @@ import FullPageDialog from "../common/dailog/FullPageDialog"; import Card from "../common/Card"; export interface TimelineCardTemplateProps extends TimelinePageCardProps { - infoArea: React.ReactElement; + infoArea: React.ReactNode; manageItems?: MenuItems; dialog: string | "property" | "member" | null; setDialog: (dialog: "property" | "member" | null) => void; diff --git a/FrontEnd/src/views/timeline/TimelineCard.tsx b/FrontEnd/src/views/timeline/TimelineCard.tsx index 311aa112..56057560 100644 --- a/FrontEnd/src/views/timeline/TimelineCard.tsx +++ b/FrontEnd/src/views/timeline/TimelineCard.tsx @@ -20,16 +20,18 @@ const TimelineCard: React.FC = (props) => { <>

{timeline.title} - {timeline.name} + + {timeline.name} +

-
+
{timeline.owner.nickname} - - src{timeline.owner.username} + + @{timeline.owner.username}
diff --git a/FrontEnd/src/views/user/UserCard.tsx b/FrontEnd/src/views/user/UserCard.tsx index 8a532512..739d26ee 100644 --- a/FrontEnd/src/views/user/UserCard.tsx +++ b/FrontEnd/src/views/user/UserCard.tsx @@ -16,11 +16,13 @@ const UserCard: React.FC = (props) => { -

+

{timeline.title} - {timeline.name} + + {timeline.name} +

-
+