diff --git a/index.html b/index.html
deleted file mode 100644
index 4f1958b..0000000
--- a/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
- Vite + React + TS
-
-
-
-
-
\ No newline at end of file
diff --git a/package.json b/package.json
index c68f480..c368c81 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
"lint:fix": "eslint . --fix"
},
"dependencies": {
+ "@emotion/cache": "^11.10.5",
"@emotion/react": "^11.10.6",
"@emotion/styled": "^11.10.6",
"@mui/icons-material": "^5.11.11",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 35cba18..3bcea97 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1,6 +1,7 @@
lockfileVersion: 5.4
specifiers:
+ '@emotion/cache': ^11.10.5
'@emotion/react': ^11.10.6
'@emotion/styled': ^11.10.6
'@mui/icons-material': ^5.11.11
@@ -17,6 +18,7 @@ specifiers:
vite-plugin-monkey: 1.1.4
dependencies:
+ '@emotion/cache': 11.10.5
'@emotion/react': 11.10.6_pmekkgnqduwlme35zpnqhenc34
'@emotion/styled': 11.10.6_oouaibmszuch5k64ms7uxp2aia
'@mui/icons-material': 5.11.11_4lyzeezzeeal3x6jtb4ni26w7u
diff --git a/src/App.tsx b/src/App.tsx
index a01ba26..abc7499 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,17 +1,18 @@
-/* eslint-disable no-undef */
import styled from '@emotion/styled';
-import { ContentCopy, ContentPaste, DeleteForever } from '@mui/icons-material';
import AutoFixHighIcon from '@mui/icons-material/AutoFixHigh';
-import {
- Divider,
- IconButton,
- ListItemIcon,
- ListItemText,
- Menu,
- MenuItem,
-} from '@mui/material';
+import ContentCopy from '@mui/icons-material/ContentCopy';
+import ContentPaste from '@mui/icons-material/ContentPaste';
+import DeleteForever from '@mui/icons-material/DeleteForever';
+import Alert from '@mui/material/Alert';
+import Divider from '@mui/material/Divider';
+import IconButton from '@mui/material/IconButton';
+import ListItemIcon from '@mui/material/ListItemIcon';
+import ListItemText from '@mui/material/ListItemText';
+import Menu from '@mui/material/Menu';
+import MenuItem from '@mui/material/MenuItem';
+import Snackbar from '@mui/material/Snackbar';
import { useState } from 'react';
-import notification from './components/notification';
+import useToast from './hooks/useToast';
const Z_INDEX_MAX = 2 ** 31 - 1;
@@ -36,6 +37,15 @@ const CustomMenu = styled(Menu)`
const App = () => {
const [anchorEl, setAnchorEl] = useState(null);
const menuOpen = Boolean(anchorEl);
+
+ const {
+ open: toastOpen,
+ message: toastMessage,
+ severity: toastSeverity,
+ handleOpen: handleToastOpen,
+ handleClose: handleToastClose,
+ } = useToast();
+
const handleMenuOpen = (event: React.MouseEvent) => {
setAnchorEl(event.currentTarget);
};
@@ -89,9 +99,9 @@ const App = () => {
const cookie = await getCookie();
const exportSessionData = JSON.stringify(cookie);
copyToClipboard(exportSessionData);
- notification.success({ message: 'Session 数据已复制到剪贴板' });
+ handleToastOpen('Session 数据已复制到剪贴板', 'success');
} catch (error) {
- notification.error({ message: '获取 Cookie 失败' });
+ handleToastOpen('获取 Cookie 失败', 'error');
}
};
@@ -103,18 +113,18 @@ const App = () => {
cookie.forEach(async (item) => {
await setCookie(item);
});
- notification.success({ message: 'Session 数据已导入' });
+ handleToastOpen('Session 数据已导入', 'success');
} catch (error) {
- notification.error({ message: '导入 Cookie 失败' });
+ handleToastOpen('导入 Cookie 失败', 'error');
}
};
const deleteSession = async () => {
try {
await deleteCookie();
- notification.success({ message: 'Session 数据已删除' });
+ handleToastOpen('Session 数据已删除', 'success');
} catch (error) {
- notification.error({ message: '删除 Cookie 失败' });
+ handleToastOpen('删除 Cookie 失败', 'error');
}
};
@@ -134,7 +144,8 @@ const App = () => {
};
return (
-
+ <>
+ {/* 工具按钮 */}
{
+ {/* 工具菜单 */}
-
+
+ {/* 提示 */}
+
+
+ {toastMessage}
+
+
+ >
);
};
diff --git a/src/components/notification.tsx b/src/components/notification.tsx
deleted file mode 100644
index 4148d07..0000000
--- a/src/components/notification.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-import { Alert, Snackbar } from '@mui/material';
-import { useEffect, useState } from 'react';
-import ReactDOM from 'react-dom';
-
-const defaultDuration = 2000;
-
-interface NotificationProps {
- message: string;
- type: 'success' | 'error' | 'info' | 'warning';
- duration?: number;
-}
-
-interface ConfigProps {
- message: string;
- duration?: number;
-}
-
-const Notification = (props: NotificationProps) => {
- const { message, type, duration } = props;
- const [open, setOpen] = useState(false);
-
- const handleClose = () => {
- setOpen(false);
- };
-
- useEffect(() => {
- setOpen(true);
- }, []);
-
- return (
-
-
- {message}
-
-
- );
-};
-
-const notification = {
- dom: null,
-
- success({ message, duration = defaultDuration }: ConfigProps) {
- const dom = document.createElement('div');
- const JSXdom = (
-
- );
- ReactDOM.render(JSXdom, dom);
- document.body.appendChild(dom);
- },
-
- error({ message, duration = defaultDuration }: ConfigProps) {
- const dom = document.createElement('div');
- const JSXdom = (
-
- );
- ReactDOM.render(JSXdom, dom);
- document.body.appendChild(dom);
- },
-
- warning({ message, duration = defaultDuration }: ConfigProps) {
- const dom = document.createElement('div');
- const JSXdom = (
-
- );
- ReactDOM.render(JSXdom, dom);
- document.body.appendChild(dom);
- },
-
- info({ message, duration = defaultDuration }: ConfigProps) {
- const dom = document.createElement('div');
- const JSXdom = (
-
- );
- ReactDOM.render(JSXdom, dom);
- document.body.appendChild(dom);
- },
-};
-
-export default notification;
diff --git a/src/hooks/useToast.ts b/src/hooks/useToast.ts
new file mode 100644
index 0000000..84f9808
--- /dev/null
+++ b/src/hooks/useToast.ts
@@ -0,0 +1,43 @@
+import { useState } from 'react';
+
+type SeverityType = 'success' | 'error' | 'info' | 'warning';
+
+interface ToastState {
+ open: boolean;
+ message: string;
+ severity: SeverityType;
+}
+
+interface ToastActions {
+ handleOpen: (toastMessage: string, toastSeverity: SeverityType) => void;
+ handleClose: () => void;
+}
+
+type Toast = ToastState & ToastActions;
+
+const useToast = (): Toast => {
+ const [state, setState] = useState({
+ open: false,
+ message: '',
+ severity: 'success',
+ });
+
+ const handleOpen = (toastMessage: string, toastSeverity: SeverityType) => {
+ setState({
+ open: true,
+ message: toastMessage,
+ severity: toastSeverity,
+ });
+ };
+
+ const handleClose = () => {
+ setState({
+ ...state,
+ open: false,
+ });
+ };
+
+ return { ...state, handleOpen, handleClose };
+};
+
+export default useToast;
diff --git a/src/index.css b/src/index.css
deleted file mode 100644
index e69de29..0000000
diff --git a/src/main.tsx b/src/main.tsx
index 447e2ce..edb0853 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -1,16 +1,67 @@
+import createCache from '@emotion/cache';
+import { CacheProvider } from '@emotion/react';
+import createTheme from '@mui/material/styles/createTheme';
+import ThemeProvider from '@mui/material/styles/ThemeProvider';
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
-import './index.css';
-ReactDOM.createRoot(
- (() => {
- const app = document.createElement('div');
- document.body.append(app);
- return app;
- })()
-).render(
+// 注入应用容器
+const container = document.createElement('div');
+container.id = 'monkey';
+container.style.all = 'initial';
+document.body.appendChild(container);
+
+// 创建 shadow DOM
+const shadowContainer = container.attachShadow({ mode: 'closed' });
+
+// 将应用添加到 shadow DOM 中
+const app = document.createElement('div');
+shadowContainer.appendChild(app);
+
+// 将 emotion 样式添加到 shadow DOM 中
+const emotionRoot = document.createElement('style');
+shadowContainer.appendChild(emotionRoot);
+
+const cache = createCache({
+ key: 'css',
+ prepend: true,
+ container: emotionRoot,
+});
+
+// 获取浏览器的字体大小
+const { fontSize } = window.getComputedStyle(document.documentElement);
+const htmlFontSize = parseFloat(fontSize);
+
+const theme = createTheme({
+ components: {
+ MuiPopover: {
+ defaultProps: {
+ container: app,
+ },
+ },
+ MuiPopper: {
+ defaultProps: {
+ container: app,
+ },
+ },
+ MuiModal: {
+ defaultProps: {
+ container: app,
+ },
+ },
+ },
+ typography: {
+ htmlFontSize,
+ },
+});
+
+ReactDOM.createRoot(app).render(
-
+
+
+
+
+
);
diff --git a/vite.config.ts b/vite.config.ts
index 78477da..610ff5a 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -12,7 +12,7 @@ export default defineConfig({
name: 'Session Magician',
namespace: 'https://www.imbytecat.com/',
icon: 'https://vitejs.dev/logo.svg',
- version: '2.2.3',
+ version: '3.1.0',
description: 'Session Magician & Session Tools & Export/Import Sessions',
author: 'imbytecat',
match: ['*://*/*'],