diff --git a/frontend/index.html b/frontend/index.html
index e4b78ea..b3a3de4 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -4,7 +4,7 @@
-
Vite + React + TS
+ 皮肤站
diff --git a/frontend/package.json b/frontend/package.json
index a8d48d2..768895e 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -18,6 +18,7 @@
"ahooks": "^3.7.8",
"immer": "^10.0.2",
"jotai": "^2.4.2",
+ "mui-file-input": "^3.0.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.16.0",
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
index 1f51ee0..486ee08 100644
--- a/frontend/pnpm-lock.yaml
+++ b/frontend/pnpm-lock.yaml
@@ -29,6 +29,9 @@ dependencies:
jotai:
specifier: ^2.4.2
version: 2.4.2(@types/react@18.2.21)(react@18.2.0)
+ mui-file-input:
+ specifier: ^3.0.2
+ version: 3.0.2(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@mui/icons-material@5.14.9)(@mui/material@5.14.10)(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0)
react:
specifier: ^18.2.0
version: 18.2.0
@@ -1821,6 +1824,30 @@ packages:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
dev: true
+ /mui-file-input@3.0.2(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@mui/icons-material@5.14.9)(@mui/material@5.14.10)(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-58Jp3+f5MUXjhZjlLfYFOEOBICnLoFC4x0G1+y411JsGBjZQ1lgICv7KQVgP5aF+IRvhJ1vfI6KpbnmqwRKXoA==}
+ peerDependencies:
+ '@emotion/react': ^11.5.0
+ '@emotion/styled': ^11.3.0
+ '@mui/icons-material': ^5.0.0
+ '@mui/material': ^5.0.0
+ '@types/react': ^18.0.0
+ react: ^18.0.0
+ react-dom: ^18.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@emotion/react': 11.11.1(@types/react@18.2.21)(react@18.2.0)
+ '@emotion/styled': 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.21)(react@18.2.0)
+ '@mui/icons-material': 5.14.9(@mui/material@5.14.10)(@types/react@18.2.21)(react@18.2.0)
+ '@mui/material': 5.14.10(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0)
+ '@types/react': 18.2.21
+ pretty-bytes: 6.1.1
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
/nanoid@3.3.6:
resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -1930,6 +1957,11 @@ packages:
engines: {node: '>= 0.8.0'}
dev: true
+ /pretty-bytes@6.1.1:
+ resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==}
+ engines: {node: ^14.13.1 || >=16.0.0}
+ dev: false
+
/prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
dependencies:
diff --git a/frontend/src/hooks/useTitle.ts b/frontend/src/hooks/useTitle.ts
new file mode 100644
index 0000000..6513963
--- /dev/null
+++ b/frontend/src/hooks/useTitle.ts
@@ -0,0 +1,16 @@
+import { serverInfo } from '@/apis/apis'
+import { useTitle as auseTitle, useRequest } from 'ahooks'
+import { useEffect } from 'react'
+
+export default function useTitle(title: string) {
+ const { data, error } = useRequest(serverInfo, {
+ cacheKey: "/api/yggdrasil",
+ staleTime: 60000,
+ })
+ useEffect(() => {
+ error && console.warn(error)
+ }, [error])
+ auseTitle(title + " - " + data?.meta.serverName ?? "", {
+ restoreOnUnmount: true
+ })
+}
\ No newline at end of file
diff --git a/frontend/src/store/store.ts b/frontend/src/store/store.ts
index 52c323d..00bc090 100644
--- a/frontend/src/store/store.ts
+++ b/frontend/src/store/store.ts
@@ -7,4 +7,4 @@ export const user = atomWithStorage("username", {
uuid: ""
})
-export const LayoutAlertErr = atom("")
+export const LayoutAlertErr = atom("")
\ No newline at end of file
diff --git a/frontend/src/views/Layout.tsx b/frontend/src/views/Layout.tsx
index 79a02c6..31a0353 100644
--- a/frontend/src/views/Layout.tsx
+++ b/frontend/src/views/Layout.tsx
@@ -19,7 +19,7 @@ import { AccountCircle } from '@mui/icons-material';
import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem';
import { LayoutAlertErr, token, user } from '@/store/store';
-import { useAtom, useAtomValue, useSetAtom } from 'jotai';
+import { atom, useAtom, useAtomValue, useSetAtom } from 'jotai';
import Button from '@mui/material/Button';
import { useNavigate } from "react-router-dom";
import { useRequest, useMemoizedFn } from 'ahooks';
@@ -37,6 +37,7 @@ import SettingsIcon from '@mui/icons-material/Settings';
import useTilg from 'tilg'
const drawerWidth = 240;
+const DrawerOpen = atom(false)
const DrawerHeader = styled('div')(({ theme }) => ({
display: 'flex',
@@ -53,51 +54,9 @@ interface ListItem {
link: string
}
-
const Layout = memo(function Layout() {
const theme = useTheme();
- const isLg = useMediaQuery(theme.breakpoints.up('lg'))
- const [open, setOpen] = React.useState(false);
- const nowToken = useAtomValue(token)
const [err, setErr] = useAtom(LayoutAlertErr)
- const navigate = useNavigate();
-
- const userinfo = useRequest(() => userInfo(nowToken), {
- refreshDeps: [nowToken],
- cacheKey: "/api/v1/user",
- onError: e => {
- if (e instanceof ApiErr && e.code == 5) {
- navigate("/login")
- }
- console.warn(e)
- setErr(String(e))
- }
- })
-
- const userDrawerList = React.useMemo(() => [
- {
- icon: ,
- title: '个人信息',
- link: '/profile'
- },
- {
- icon: ,
- title: '皮肤设置',
- link: '/textures'
- },
- {
- icon: ,
- title: '安全设置',
- link: '/setting'
- }
- ] as ListItem[], [])
-
- const adminDrawerList = React.useMemo(() => [
- {
- icon: ,
- title: 'test'
- }
- ] as ListItem[], [])
useTilg()
@@ -108,37 +67,9 @@ const Layout = memo(function Layout() {
zIndex: { lg: theme.zIndex.drawer + 1 }
}}
>
-
+
- {userinfo.data && (
- setOpen(false)}
- >
-
- setOpen(false)}>
- {theme.direction === 'ltr' ? : }
-
-
-
-
- {userinfo.data?.is_admin && (
- <>
-
-
- >)}
-
- )}
+
setErr("")} >
setErr("")} severity="error">{err}
@@ -157,15 +88,17 @@ const Layout = memo(function Layout() {
>)
})
-const MyToolbar = memo(function MyToolbar(p: { setOpen: (v: boolean) => void }) {
+const MyToolbar = memo(function MyToolbar() {
const [nowUser, setNowUser] = useAtom(user)
const [anchorEl, setAnchorEl] = React.useState(null);
const navigate = useNavigate();
const [, setToken] = useAtom(token)
const setErr = useSetAtom(LayoutAlertErr)
+ const setOpen = useSetAtom(DrawerOpen)
const server = useRequest(serverInfo, {
cacheKey: "/api/yggdrasil",
+ staleTime: 60000,
onError: e => {
console.warn(e)
setErr(String(e))
@@ -180,6 +113,8 @@ const MyToolbar = memo(function MyToolbar(p: { setOpen: (v: boolean) => void })
navigate("/")
})
+ useTilg()
+
return (
<>
@@ -190,7 +125,7 @@ const MyToolbar = memo(function MyToolbar(p: { setOpen: (v: boolean) => void })
color="inherit"
aria-label="menu"
sx={{ mr: 2, display: { lg: 'none' } }}
- onClick={() => p.setOpen(true)}
+ onClick={() => setOpen(true)}
>
@@ -270,4 +205,85 @@ const MyListItem = function MyListItem(p: ListItem) {
)
}
+const MyDrawer = function MyDrawer() {
+ const nowToken = useAtomValue(token)
+ const setErr = useSetAtom(LayoutAlertErr)
+ const navigate = useNavigate();
+ const theme = useTheme();
+ const isLg = useMediaQuery(theme.breakpoints.up('lg'))
+ const [open, setOpen] = useAtom(DrawerOpen)
+
+ const userinfo = useRequest(() => userInfo(nowToken), {
+ refreshDeps: [nowToken],
+ cacheKey: "/api/v1/user" + nowToken,
+ staleTime: 60000,
+ onError: e => {
+ if (e instanceof ApiErr && e.code == 5) {
+ navigate("/login")
+ }
+ console.warn(e)
+ setErr(String(e))
+ },
+ })
+
+ const userDrawerList = React.useMemo(() => [
+ {
+ icon: ,
+ title: '个人信息',
+ link: '/profile'
+ },
+ {
+ icon: ,
+ title: '皮肤设置',
+ link: '/textures'
+ },
+ {
+ icon: ,
+ title: '安全设置',
+ link: '/setting'
+ }
+ ] as ListItem[], [])
+
+ const adminDrawerList = React.useMemo(() => [
+ {
+ icon: ,
+ title: 'test'
+ }
+ ] as ListItem[], [])
+
+ useTilg()
+
+ return (<>
+ {userinfo.data && (
+ setOpen(false)}
+ >
+
+ setOpen(false)}>
+ {theme.direction === 'ltr' ? : }
+
+
+
+
+ {userinfo.data?.is_admin && (
+ <>
+
+
+ >)}
+
+ )}
+ >)
+}
+
export default Layout
\ No newline at end of file
diff --git a/frontend/src/views/Login.tsx b/frontend/src/views/Login.tsx
index 20b276d..03acf69 100644
--- a/frontend/src/views/Login.tsx
+++ b/frontend/src/views/Login.tsx
@@ -17,6 +17,7 @@ import { login } from '@/apis/apis'
import { Link as RouterLink, useNavigate } from "react-router-dom";
import Loading from '@/components/Loading'
import CheckInput, { refType } from '@/components/CheckInput'
+import useTitle from '@/hooks/useTitle';
@@ -27,6 +28,7 @@ export default function SignIn() {
const setUserInfo = useSetAtom(user)
const checkList = React.useRef