From f5dfd52f6efece2f4cad227044ecf4dd66301bbc Mon Sep 17 00:00:00 2001 From: crupest Date: Sat, 26 Aug 2023 21:36:58 +0800 Subject: ... --- FrontEnd/src/components/alert/AlertHost.tsx | 113 ++++++++++++++++++++++++++++ FrontEnd/src/components/alert/alert.css | 33 ++++++++ 2 files changed, 146 insertions(+) create mode 100644 FrontEnd/src/components/alert/AlertHost.tsx create mode 100644 FrontEnd/src/components/alert/alert.css (limited to 'FrontEnd/src/components/alert') diff --git a/FrontEnd/src/components/alert/AlertHost.tsx b/FrontEnd/src/components/alert/AlertHost.tsx new file mode 100644 index 00000000..b234ac03 --- /dev/null +++ b/FrontEnd/src/components/alert/AlertHost.tsx @@ -0,0 +1,113 @@ +import * as React from "react"; +import without from "lodash/without"; +import { useTranslation } from "react-i18next"; +import classNames from "classnames"; + +import { alertService, AlertInfoEx, AlertInfo } from "~src/services/alert"; +import { convertI18nText } from "~src/common"; + +import IconButton from "../button/IconButton"; + +import "./alert.css"; + +interface AutoCloseAlertProps { + alert: AlertInfo; + close: () => void; +} + +export const AutoCloseAlert: React.FC = (props) => { + const { alert, close } = props; + const { dismissTime } = alert; + + const { t } = useTranslation(); + + const timerTag = React.useRef(null); + const closeHandler = React.useRef<(() => void) | null>(null); + + React.useEffect(() => { + closeHandler.current = close; + }, [close]); + + React.useEffect(() => { + const tag = + dismissTime === "never" + ? null + : typeof dismissTime === "number" + ? window.setTimeout(() => closeHandler.current?.(), dismissTime) + : window.setTimeout(() => closeHandler.current?.(), 5000); + timerTag.current = tag; + return () => { + if (tag != null) { + window.clearTimeout(tag); + } + }; + }, [dismissTime]); + + const cancelTimer = (): void => { + const { current: tag } = timerTag; + if (tag != null) { + window.clearTimeout(tag); + } + }; + + return ( +
+
+ {(() => { + const { message, customMessage } = alert; + if (customMessage != null) { + return customMessage; + } else { + return convertI18nText(message, t); + } + })()} +
+
+ +
+
+ ); +}; + +const AlertHost: React.FC = () => { + const [alerts, setAlerts] = React.useState([]); + + React.useEffect(() => { + const consume = (alert: AlertInfoEx): void => { + setAlerts((old) => [...old, alert]); + }; + + alertService.registerConsumer(consume); + return () => { + alertService.unregisterConsumer(consume); + }; + }, []); + + return ( +
+ {alerts.map((alert) => { + return ( + { + setAlerts((old) => without(old, alert)); + }} + /> + ); + })} +
+ ); +}; + +export default AlertHost; diff --git a/FrontEnd/src/components/alert/alert.css b/FrontEnd/src/components/alert/alert.css new file mode 100644 index 00000000..54c2b87f --- /dev/null +++ b/FrontEnd/src/components/alert/alert.css @@ -0,0 +1,33 @@ +.alert-container { + position: fixed; + z-index: 1040; +} + +.cru-alert { + border-radius: 5px; + border: var(--cru-key-color) 1px solid; + color: var(--cru-key-t-color); + background-color: var(--cru-key-b1-color); + + display: flex; + overflow: hidden; +} + +.cru-alert-content { + padding: 0.5em 2em; +} + +.cru-alert-close-button-container { + flex-shrink: 0; + margin-left: auto; + width: 2em; + text-align: center; + display: flex; + align-items: center; + justify-content: center; + background-color: var(--cru-key-t-color); +} + +.cru-alert-close-button { + color: var(--cru-key-color); +} -- cgit v1.2.3