From a148f11c193d35ba489f887ed393aedf58a1c714 Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 30 Jul 2023 20:52:13 +0800 Subject: ... --- FrontEnd/src/views/common/button/ButtonRow.css | 0 FrontEnd/src/views/common/button/ButtonRow.tsx | 62 ++++++++++++++ FrontEnd/src/views/common/button/index.tsx | 3 +- FrontEnd/src/views/common/dialog/ConfirmDialog.css | 0 FrontEnd/src/views/common/dialog/ConfirmDialog.tsx | 80 ++++++++++-------- FrontEnd/src/views/common/dialog/Dialog.css | 9 --- .../src/views/common/dialog/DialogContainer.css | 20 +++++ .../src/views/common/dialog/DialogContainer.tsx | 68 ++++++++++++++++ .../src/views/common/dialog/OperationDialog.css | 15 ---- .../src/views/common/dialog/OperationDialog.tsx | 94 ++++++++++++---------- 10 files changed, 250 insertions(+), 101 deletions(-) create mode 100644 FrontEnd/src/views/common/button/ButtonRow.css create mode 100644 FrontEnd/src/views/common/button/ButtonRow.tsx create mode 100644 FrontEnd/src/views/common/dialog/ConfirmDialog.css create mode 100644 FrontEnd/src/views/common/dialog/DialogContainer.css create mode 100644 FrontEnd/src/views/common/dialog/DialogContainer.tsx (limited to 'FrontEnd/src/views/common') diff --git a/FrontEnd/src/views/common/button/ButtonRow.css b/FrontEnd/src/views/common/button/ButtonRow.css new file mode 100644 index 00000000..e69de29b diff --git a/FrontEnd/src/views/common/button/ButtonRow.tsx b/FrontEnd/src/views/common/button/ButtonRow.tsx new file mode 100644 index 00000000..eea60cc4 --- /dev/null +++ b/FrontEnd/src/views/common/button/ButtonRow.tsx @@ -0,0 +1,62 @@ +import { ComponentPropsWithoutRef, Ref } from "react"; +import classNames from "classnames"; + +import Button from "./Button"; +import FlatButton from "./FlatButton"; +import IconButton from "./IconButton"; +import LoadingButton from "./LoadingButton"; + +import "./ButtonRow.css"; + +type ButtonRowButton = ( + | { + type: "normal"; + props: ComponentPropsWithoutRef; + } + | { + type: "flat"; + props: ComponentPropsWithoutRef; + } + | { + type: "icon"; + props: ComponentPropsWithoutRef; + } + | { type: "loading"; props: ComponentPropsWithoutRef } +) & { key: string | number }; + +interface ButtonRowProps { + className?: string; + containerRef?: Ref; + buttons: ButtonRowButton[]; + buttonsClassName?: string; +} + +export default function ButtonRow({ + className, + containerRef, + buttons, + buttonsClassName, +}: ButtonRowProps) { + return ( +
+ {buttons.map((button) => { + const { type, key, props } = button; + const newClassName = classNames(props.className, buttonsClassName); + switch (type) { + case "normal": + return
+ ); +} diff --git a/FrontEnd/src/views/common/button/index.tsx b/FrontEnd/src/views/common/button/index.tsx index cff5ba3f..73038849 100644 --- a/FrontEnd/src/views/common/button/index.tsx +++ b/FrontEnd/src/views/common/button/index.tsx @@ -2,5 +2,6 @@ import Button from "./Button"; import FlatButton from "./FlatButton"; import IconButton from "./IconButton"; import LoadingButton from "./LoadingButton"; +import ButtonRow from "./ButtonRow"; -export { Button, FlatButton, IconButton, LoadingButton }; +export { Button, FlatButton, IconButton, LoadingButton, ButtonRow }; diff --git a/FrontEnd/src/views/common/dialog/ConfirmDialog.css b/FrontEnd/src/views/common/dialog/ConfirmDialog.css new file mode 100644 index 00000000..e69de29b diff --git a/FrontEnd/src/views/common/dialog/ConfirmDialog.tsx b/FrontEnd/src/views/common/dialog/ConfirmDialog.tsx index 8c2cea5a..ee4bf2d7 100644 --- a/FrontEnd/src/views/common/dialog/ConfirmDialog.tsx +++ b/FrontEnd/src/views/common/dialog/ConfirmDialog.tsx @@ -1,43 +1,59 @@ -import { convertI18nText, I18nText } from "@/common"; -import * as React from "react"; -import { useTranslation } from "react-i18next"; +import { useC, Text, ThemeColor } from "@/views/common/common"; -import Button from "../button/Button"; import Dialog from "./Dialog"; +import DialogContainer from "./DialogContainer"; -const ConfirmDialog: React.FC<{ +export default function ConfirmDialog({ + open, + onClose, + onConfirm, + title, + body, + color, + bodyColor, +}: { open: boolean; onClose: () => void; onConfirm: () => void; - title: I18nText; - body: I18nText; -}> = ({ open, onClose, onConfirm, title, body }) => { - const { t } = useTranslation(); + title: Text; + body: Text; + color?: ThemeColor; + bodyColor?: ThemeColor; +}) { + const c = useC(); return ( -

{convertI18nText(title, t)}

-
-

{convertI18nText(body, t)}

-
-
-
+ { + onConfirm(); + onClose(); + }, + }, + }, + ]} + > +
{c(body)}
+
); -}; - -export default ConfirmDialog; +} diff --git a/FrontEnd/src/views/common/dialog/Dialog.css b/FrontEnd/src/views/common/dialog/Dialog.css index 0123a29d..e4c61440 100644 --- a/FrontEnd/src/views/common/dialog/Dialog.css +++ b/FrontEnd/src/views/common/dialog/Dialog.css @@ -39,15 +39,6 @@ } } -.cru-dialog-bottom-area { - display: flex; - justify-content: flex-end; -} - -.cru-dialog-bottom-area>* { - margin: 0 0.5em; -} - .cru-dialog-enter .cru-dialog-container { transform: scale(0, 0); opacity: 0; diff --git a/FrontEnd/src/views/common/dialog/DialogContainer.css b/FrontEnd/src/views/common/dialog/DialogContainer.css new file mode 100644 index 00000000..fbb18e0d --- /dev/null +++ b/FrontEnd/src/views/common/dialog/DialogContainer.css @@ -0,0 +1,20 @@ +.cru-dialog-container-title { + font-size: 1.2em; + font-weight: bold; + color: var(--cru-key-color); + margin-bottom: 0.5em; +} + + +.cru-dialog-container-hr { + margin: 1em 0; +} + +.cru-dialog-container-button-row { + display: flex; + justify-content: flex-end; +} + +.cru-dialog-container-button { + margin-left: 1em; +} \ No newline at end of file diff --git a/FrontEnd/src/views/common/dialog/DialogContainer.tsx b/FrontEnd/src/views/common/dialog/DialogContainer.tsx new file mode 100644 index 00000000..b0a87ea5 --- /dev/null +++ b/FrontEnd/src/views/common/dialog/DialogContainer.tsx @@ -0,0 +1,68 @@ +import { ComponentProps, Ref, ReactNode } from "react"; +import classNames from "classnames"; + +import { ThemeColor, Text, useC } from "../common"; +import { ButtonRow } from "../button"; + +import "./DialogContainer.css"; + +interface DialogContainerProps { + className?: string; + title: Text; + titleColor?: ThemeColor; + titleClassName?: string; + titleRef?: Ref; + bodyContainerClassName?: string; + bodyContainerRef?: Ref; + buttons: ComponentProps["buttons"]; + buttonsClassName?: string; + buttonsContainerRef?: ComponentProps["containerRef"]; + children: ReactNode; +} + +export default function DialogContainer({ + className, + title, + titleColor, + titleClassName, + titleRef, + bodyContainerClassName, + bodyContainerRef, + buttons, + buttonsClassName, + buttonsContainerRef, + children, +}: DialogContainerProps) { + const c = useC(); + + return ( +
+
+ {c(title)} +
+
+
+ {children} +
+
+ +
+ ); +} diff --git a/FrontEnd/src/views/common/dialog/OperationDialog.css b/FrontEnd/src/views/common/dialog/OperationDialog.css index 43cdb692..f4b7237e 100644 --- a/FrontEnd/src/views/common/dialog/OperationDialog.css +++ b/FrontEnd/src/views/common/dialog/OperationDialog.css @@ -1,22 +1,7 @@ -.cru-operation-dialog-title { - font-size: 1.2em; - font-weight: bold; - color: var(--cru-key-color); - margin-bottom: 0.5em; -} - .cru-operation-dialog-prompt { color: var(--cru-surface-on-color); } -.cru-dialog-middle-area { - margin: 0.5em 0; -} - -.cru-dialog-bottom-area { - margin-top: 0.5em; -} - .cru-operation-dialog-input-group { display: block; margin: 0.5em 0; diff --git a/FrontEnd/src/views/common/dialog/OperationDialog.tsx b/FrontEnd/src/views/common/dialog/OperationDialog.tsx index 74b4a5fa..da1ff0e0 100644 --- a/FrontEnd/src/views/common/dialog/OperationDialog.tsx +++ b/FrontEnd/src/views/common/dialog/OperationDialog.tsx @@ -1,9 +1,8 @@ -import { useState, ReactNode } from "react"; +import { useState, ReactNode, ComponentProps } from "react"; import classNames from "classnames"; import { useC, Text, ThemeColor } from "../common"; -import Button from "../button/Button"; import { useInputs, InputGroup, @@ -11,8 +10,8 @@ import { InputValueDict, InputErrorDict, } from "../input/InputGroup"; -import LoadingButton from "../button/LoadingButton"; import Dialog from "./Dialog"; +import DialogContainer from "./DialogContainer"; import "./OperationDialog.css"; @@ -124,39 +123,45 @@ function OperationDialog(props: OperationDialogProps) { } let body: ReactNode; + let buttons: ComponentProps["buttons"]; + if (step.type === "input" || step.type === "process") { const isProcessing = step.type === "process"; body = ( -
-
- - -
-
-
-
+
+ +
); + buttons = [ + { + key: "cancel", + type: "normal", + props: { + text: "operationDialog.cancel", + color: "secondary", + outline: true, + onClick: close, + disabled: isProcessing, + }, + }, + { + key: "confirm", + type: "loading", + props: { + text: "operationDialog.confirm", + color, + loading: isProcessing, + disabled: hasErrorAndDirty, + onClick: onConfirm, + }, + }, + ]; } else { const result = step; @@ -171,28 +176,29 @@ function OperationDialog(props: OperationDialogProps) { customMessage: failurePrompt?.(result.data), }; body = ( -
+
-
-
-
); + + buttons = [ + { + key: "ok", + type: "normal", + props: { + text: "operationDialog.ok", + color: "primary", + onClick: close, + }, + }, + ]; } return ( -
-
{c(title)}
-
+ {body} -
+
); } -- cgit v1.2.3