This commit is contained in:
hu xiaotong
2026-03-04 16:55:13 +08:00
parent fc8e8cfcfa
commit 4ea6c97074
3 changed files with 480 additions and 52 deletions

View File

@@ -9,10 +9,29 @@
-moz-osx-font-smoothing: grayscale;
}
html {
overflow-y: scroll;
scrollbar-gutter: stable;
}
body {
margin: 0;
min-width: 320px;
background: #f7f4ee;
background:
linear-gradient(
180deg,
rgba(253, 248, 240, 0.42) 0%,
rgba(252, 245, 234, 0.48) 40%,
rgba(248, 240, 228, 0.58) 100%
),
radial-gradient(circle at 12% 18%, rgba(255, 214, 162, 0.22), transparent 45%),
radial-gradient(circle at 88% 22%, rgba(255, 170, 183, 0.2), transparent 42%),
url("/hero-bg.jpg");
background-size: cover;
background-position: center center;
background-repeat: no-repeat;
background-attachment: fixed;
overflow-x: hidden;
}
a {

View File

@@ -1,34 +1,282 @@
import { AppBar, Box, Button, Container, Stack, Toolbar, Typography } from '@mui/material'
import { Link, Outlet } from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
import MenuIcon from '@mui/icons-material/Menu'
import HomeIcon from '@mui/icons-material/Home'
import PeopleAltIcon from '@mui/icons-material/PeopleAlt'
import AutoAwesomeIcon from '@mui/icons-material/AutoAwesome'
import RefreshIcon from '@mui/icons-material/Refresh'
import TranslateIcon from '@mui/icons-material/Translate'
import ChevronLeftIcon from '@mui/icons-material/ChevronLeft'
import ChevronRightIcon from '@mui/icons-material/ChevronRight'
import MuiDrawer from '@mui/material/Drawer'
import {
AppBar,
Avatar,
Box,
Button,
Container,
Divider,
IconButton,
Stack,
Toolbar,
Typography,
useMediaQuery,
} from '@mui/material'
import {styled, useTheme} from '@mui/material/styles'
import type {CSSObject, Theme} from '@mui/material/styles'
import {Link, Outlet, useRouterState} from '@tanstack/react-router'
import {TanStackRouterDevtools} from '@tanstack/react-router-devtools'
import {useState} from 'react'
const menuItems = [
{label: '首页', to: '/', icon: <HomeIcon fontSize="small"/>},
{label: '角色', to: '/characters', icon: <PeopleAltIcon fontSize="small"/>},
{label: '神器', to: '/artifacts', icon: <AutoAwesomeIcon fontSize="small"/>},
]
const drawerWidth = 260
const collapsedWidth = 76
const openedMixin = (theme: Theme): CSSObject => ({
width: drawerWidth,
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
overflowX: 'hidden',
})
const closedMixin = (theme: Theme): CSSObject => ({
width: collapsedWidth,
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
overflowX: 'hidden',
})
const StyledDrawer = styled(MuiDrawer, {
shouldForwardProp: (prop) => prop !== 'open',
})(({theme, open}) => ({
width: drawerWidth,
flexShrink: 0,
whiteSpace: 'nowrap',
boxSizing: 'border-box',
...(open && {
...openedMixin(theme),
'& .MuiDrawer-paper': {
...openedMixin(theme),
},
}),
...(!open && {
...closedMixin(theme),
'& .MuiDrawer-paper': {
...closedMixin(theme),
},
}),
'& .MuiDrawer-paper': {
height: '100vh',
background:
'linear-gradient(180deg, rgba(31,26,38,0.46) 0%, rgba(25,21,34,0.52) 100%)',
borderRight: 'none',
boxShadow: 'none',
},
}))
export function RootLayout() {
return (
<Box sx={{ minHeight: '100vh', background: 'linear-gradient(180deg, #f7f4ee 0%, #efe8dc 100%)' }}>
<AppBar position="sticky" color="primary" elevation={0}>
<Toolbar sx={{ gap: 2, flexWrap: 'wrap' }}>
<Typography variant="h6" sx={{ fontWeight: 700, letterSpacing: 1 }}>
const pathname = useRouterState({select: (state) => state.location.pathname})
const theme = useTheme()
const isMobile = useMediaQuery(theme.breakpoints.down('md'))
const [drawerOpen, setDrawerOpen] = useState(false)
const [collapsed, setCollapsed] = useState(false)
const sidebarContent = (
<Box
sx={{
height: '100%',
color: '#f3ede6',
display: 'flex',
flexDirection: 'column',
}}
>
<Stack spacing={2} sx={{p: 2.5}}>
<Stack
direction="row"
spacing={1.5}
alignItems="center"
justifyContent={collapsed ? 'center' : 'flex-start'}
>
<Avatar
src="/hero-avatar.png"
sx={{
width: 36,
height: 36,
border: '1px solid rgba(255,255,255,0.2)',
background: 'rgba(255,255,255,0.08)',
}}
/>
{collapsed ? null : (
<Stack spacing={0.2}>
<Typography sx={{fontWeight: 700, letterSpacing: 1}}></Typography>
<Typography variant="body2" sx={{color: 'rgba(243,237,230,0.72)'}}>
Epic Seven Archives
</Typography>
<Stack direction="row" spacing={1} sx={{ ml: 'auto' }}>
<Button component={Link} to="/" color="inherit">
</Stack>
)}
</Stack>
</Stack>
<Divider sx={{borderColor: 'rgba(255,255,255,0.12)'}}/>
<Stack spacing={1} sx={{px: 1.5, py: 2, flex: 1}}>
{menuItems.map((item) => {
const active = pathname === item.to
return (
<Button
key={item.to}
component={Link}
to={item.to}
startIcon={item.icon}
onClick={() => setDrawerOpen(false)}
sx={{
justifyContent: collapsed ? 'center' : 'flex-start',
color: active ? '#1f1a26' : '#f3ede6',
background: active ? '#f7d9b4' : 'rgba(255,255,255,0.06)',
borderRadius: 2,
textTransform: 'none',
fontWeight: 600,
minHeight: 44,
position: 'relative',
overflow: 'hidden',
transition: 'transform 160ms ease, background 160ms ease, box-shadow 160ms ease',
'& .MuiButton-startIcon': {
margin: 0,
},
'&::after': {
content: '""',
position: 'absolute',
inset: 0,
background:
active
? 'radial-gradient(circle at 18% 50%, rgba(255,229,196,0.6), transparent 60%)'
: 'none',
opacity: 0.9,
},
'&:hover': {
transform: collapsed ? 'none' : 'translateX(2px)',
background: active ? '#f4cfa2' : 'rgba(255,255,255,0.12)',
boxShadow: '0 6px 18px rgba(0,0,0,0.2)',
},
}}
>
{collapsed ? null : item.label}
</Button>
<Button component={Link} to="/characters" color="inherit">
)
})}
</Stack>
<Divider sx={{borderColor: 'rgba(255,255,255,0.12)'}}/>
<Stack spacing={1} sx={{px: 1.5, py: 2}}>
<Button
startIcon={<TranslateIcon fontSize="small"/>}
sx={{
justifyContent: collapsed ? 'center' : 'flex-start',
color: '#f3ede6',
background: 'rgba(255,255,255,0.06)',
borderRadius: 2,
textTransform: 'none',
minHeight: 40,
'& .MuiButton-startIcon': {margin: 0},
}}
>
{collapsed ? null : '中文'}
</Button>
<Button component={Link} to="/artifacts" color="inherit">
<Button
startIcon={<RefreshIcon fontSize="small"/>}
sx={{
justifyContent: collapsed ? 'center' : 'flex-start',
color: '#f3ede6',
background: 'rgba(255,255,255,0.06)',
borderRadius: 2,
textTransform: 'none',
minHeight: 40,
'& .MuiButton-startIcon': {margin: 0},
}}
>
{collapsed ? null : '刷新数据'}
</Button>
</Stack>
<Divider sx={{borderColor: 'rgba(255,255,255,0.12)'}}/>
<Box sx={{p: 1.5}}>
<Button
fullWidth
onClick={() => setCollapsed((prev) => !prev)}
startIcon={collapsed ? <ChevronRightIcon fontSize="small"/> : <ChevronLeftIcon fontSize="small"/>}
sx={{
justifyContent: collapsed ? 'center' : 'flex-start',
color: '#f3ede6',
background: 'rgba(255,255,255,0.06)',
borderRadius: 2,
textTransform: 'none',
minHeight: 40,
'& .MuiButton-startIcon': {margin: 0},
}}
>
{collapsed ? null : '收起菜单'}
</Button>
</Box>
</Box>
)
return (
<Box
sx={{
minHeight: '100vh',
}}
>
{isMobile ? (
<AppBar position="sticky" elevation={0} sx={{background: 'rgba(31,26,38,0.75)'}}>
<Toolbar sx={{gap: 1.5}}>
<IconButton color="inherit" onClick={() => setDrawerOpen(true)}>
<MenuIcon/>
</IconButton>
<Typography sx={{fontWeight: 700, letterSpacing: 1}}></Typography>
</Toolbar>
</AppBar>
) : null}
<Container sx={{ py: 4 }}>
<Outlet />
<Box sx={{display: 'flex', minHeight: '100vh'}}>
{isMobile ? null : (
<StyledDrawer variant="permanent" open={!collapsed}>
{sidebarContent}
</StyledDrawer>
)}
<Box sx={{flex: 1, minWidth: 0}}>
<Container sx={{py: {xs: 3, md: 4}}}>
<Outlet/>
</Container>
</Box>
</Box>
{import.meta.env.DEV ? <TanStackRouterDevtools position="bottom-right" /> : null}
<MuiDrawer
anchor="left"
open={drawerOpen}
onClose={() => setDrawerOpen(false)}
PaperProps={{
sx: {
background:
'linear-gradient(180deg, rgba(31,26,38,0.46) 0%, rgba(25,21,34,0.52) 100%)',
borderRight: 'none',
boxShadow: 'none',
},
}}
>
<Box sx={{width: 260}}>{sidebarContent}</Box>
</MuiDrawer>
{import.meta.env.DEV ? <TanStackRouterDevtools position="bottom-right"/> : null}
</Box>
)
}

View File

@@ -1,30 +1,191 @@
import { Box, Divider, Paper, Stack, Typography } from '@mui/material'
import {
Box,
Button,
Chip,
Divider,
Paper,
Stack,
TextField,
Typography,
} from '@mui/material'
export function HomePage() {
return (
<Stack spacing={3}>
<Paper
sx={{
p: { xs: 2.5, md: 4 },
border: '1px solid #e6ded1',
background: 'linear-gradient(120deg, rgba(255,250,242,0.95), rgba(255,245,230,0.9))',
}}
>
<Stack spacing={2}>
<Box>
<Typography variant="h1"></Typography>
<Typography color="text.secondary">
</Typography>
</Box>
<TextField
placeholder="搜索角色、神器、活动或公告"
fullWidth
size="medium"
sx={{
background: '#fffdf8',
borderRadius: 2,
'& .MuiOutlinedInput-notchedOutline': { borderColor: '#eadfce' },
}}
/>
<Stack direction="row" spacing={1} flexWrap="wrap" useFlexGap>
<Chip label="最新公告" color="primary" variant="outlined" />
<Chip label="版本更新" variant="outlined" />
<Chip label="节日活动" variant="outlined" />
<Chip label="新角色" variant="outlined" />
<Chip label="神器推荐" variant="outlined" />
</Stack>
</Stack>
</Paper>
<Box
sx={{
display: 'grid',
gap: 2.5,
gridTemplateColumns: { xs: '1fr', md: '2fr 1fr' },
}}
>
<Stack spacing={2.5}>
<Paper sx={{ p: 3, border: '1px solid #e6ded1', background: '#fffaf2' }}>
<Typography variant="h2"></Typography>
<Typography variant="h2"></Typography>
<Divider sx={{ my: 2 }} />
<Typography color="text.secondary">
<Stack spacing={1.5}>
{[
'3月版本更新预告全新支线与神器强化',
'限时活动:冬日庆典兑换商店开放',
'竞技场平衡调整说明',
].map((item) => (
<Box
key={item}
sx={{
p: 1.5,
borderRadius: 2,
background: '#fffdf8',
border: '1px solid #efe3d2',
}}
>
<Typography sx={{ fontWeight: 600 }}>{item}</Typography>
<Typography color="text.secondary" variant="body2">
2026-03-04 ·
</Typography>
</Box>
))}
</Stack>
</Paper>
<Paper sx={{ p: 3, border: '1px solid #e6ded1', background: '#fffaf2' }}>
<Typography variant="h2"></Typography>
<Typography variant="h2"></Typography>
<Divider sx={{ my: 2 }} />
<Typography color="text.secondary">
<Box
sx={{
display: 'grid',
gap: 2,
gridTemplateColumns: { xs: '1fr', sm: '1fr 1fr' },
}}
>
{[
{ title: '节日活动入口', desc: '兑换、任务、挑战关卡' },
{ title: '版本更新摘要', desc: '职业平衡与UI优化' },
{ title: '新角色专题', desc: '技能、刻印与养成' },
{ title: '装备周报', desc: '热门套装推荐' },
].map((card) => (
<Box
key={card.title}
sx={{
p: 2,
borderRadius: 2,
background: '#fffdf8',
border: '1px solid #efe3d2',
}}
>
<Typography sx={{ fontWeight: 600 }}>{card.title}</Typography>
<Typography color="text.secondary" variant="body2">
{card.desc}
</Typography>
</Box>
))}
</Box>
</Paper>
</Stack>
<Stack spacing={2.5}>
<Paper sx={{ p: 3, border: '1px solid #e6ded1', background: '#fffaf2' }}>
<Typography variant="h2"></Typography>
<Divider sx={{ my: 2 }} />
<Stack spacing={1}>
<Button variant="contained" color="primary">
</Button>
<Button variant="outlined" color="primary">
</Button>
<Button variant="outlined" color="primary">
</Button>
</Stack>
</Paper>
<Paper sx={{ p: 3, border: '1px solid #e6ded1', background: '#fffaf2' }}>
<Typography variant="h2"></Typography>
<Divider sx={{ my: 2 }} />
<Stack spacing={1}>
{['永恒·夏绿蒂', '流浪者·希格尔', '月光·优芬妮'].map((name) => (
<Box
key={name}
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
p: 1.2,
borderRadius: 2,
background: '#fffdf8',
border: '1px solid #efe3d2',
}}
>
<Typography sx={{ fontWeight: 600 }}>{name}</Typography>
<Typography variant="body2" color="text.secondary">
</Typography>
</Box>
))}
</Stack>
</Paper>
<Paper sx={{ p: 3, border: '1px solid #e6ded1', background: '#fffaf2' }}>
<Typography variant="h2"></Typography>
<Divider sx={{ my: 2 }} />
<Stack spacing={1}>
{['黎明之剑', '王座之冠', '圣域之铃'].map((name) => (
<Box
key={name}
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
p: 1.2,
borderRadius: 2,
background: '#fffdf8',
border: '1px solid #efe3d2',
}}
>
<Typography sx={{ fontWeight: 600 }}>{name}</Typography>
<Typography variant="body2" color="text.secondary">
</Typography>
</Box>
))}
</Stack>
</Paper>
</Stack>
</Box>
</Stack>
)
}