diff --git a/src/components/notice.tsx b/src/components/notice.tsx new file mode 100644 index 0000000..eedc7a5 --- /dev/null +++ b/src/components/notice.tsx @@ -0,0 +1,88 @@ +import ReactDOM from "react-dom"; +import { ReactNode, useState } from "react"; +import { Box, IconButton, Slide, Snackbar, Typography } from "@mui/material"; +import { Close, CheckCircleRounded, ErrorRounded } from "@mui/icons-material"; + +interface InnerProps { + type: string; + duration?: number; + message: ReactNode; + onClose: () => void; +} + +const NoticeInner = (props: InnerProps) => { + const { type, message, duration = 2000, onClose } = props; + const [visible, setVisible] = useState(true); + + const onBtnClose = () => { + setVisible(false); + onClose(); + }; + const onAutoClose = (_e: any, reason: string) => { + if (reason !== "clickaway") onBtnClose(); + }; + + const msgElement = + type === "info" ? ( + message + ) : ( + + {type === "error" && } + {type === "success" && } + + {message} + + ); + + return ( + } + transitionDuration={200} + action={ + + + + } + /> + ); +}; + +interface NoticeInstance { + (props: Omit): void; + + info(message: ReactNode, duration?: number): void; + error(message: ReactNode, duration?: number): void; + success(message: ReactNode, duration?: number): void; +} + +let parent: HTMLDivElement = null!; + +// @ts-ignore +const Notice: NoticeInstance = (props) => { + if (!parent) { + parent = document.createElement("div"); + document.body.appendChild(parent); + } + + const container = document.createElement("div"); + parent.appendChild(container); + + const onUnmount = () => { + const result = ReactDOM.unmountComponentAtNode(container); + if (result && parent) parent.removeChild(container); + }; + + ReactDOM.render(, container); +}; + +(["info", "error", "success"] as const).forEach((type) => { + Notice[type] = (message, duration) => Notice({ type, message, duration }); +}); + +export default Notice; diff --git a/src/pages/profiles.tsx b/src/pages/profiles.tsx index 57ef2d4..cbf8a3f 100644 --- a/src/pages/profiles.tsx +++ b/src/pages/profiles.tsx @@ -9,14 +9,13 @@ import { } from "../services/cmds"; import { getProxies, updateProxy } from "../services/api"; import noop from "../utils/noop"; -import useNotice from "../utils/use-notice"; +import Notice from "../components/notice"; import BasePage from "../components/base-page"; import ProfileItemComp from "../components/profile-item"; const ProfilePage = () => { const [url, setUrl] = useState(""); const [disabled, setDisabled] = useState(false); - const [notice, noticeElement] = useNotice(); const { mutate } = useSWRConfig(); const { data: profiles = {} } = useSWR("getProfiles", getProfiles); @@ -72,9 +71,9 @@ const ProfilePage = () => { await importProfile(url); mutate("getProfiles", getProfiles()); if (!profiles.items?.length) selectProfile(0).catch(noop); - notice.success("Successfully import profile."); + Notice.success("Successfully import profile."); } catch { - notice.error("Failed to import profile."); + Notice.error("Failed to import profile."); } finally { setDisabled(false); } @@ -108,7 +107,7 @@ const ProfilePage = () => { fullWidth value={url} onChange={(e) => setUrl(e.target.value)} - sx={{ mr: 4 }} + sx={{ mr: 2 }} />