mirror of
https://github.com/Jerryplusy/AI-powered-switches.git
synced 2025-07-04 21:29:18 +00:00
添加导航栏,管理后台背景等
This commit is contained in:
parent
7031f7b251
commit
5917e26247
1
.idea/AI-powered-switches.iml
generated
1
.idea/AI-powered-switches.iml
generated
@ -11,6 +11,5 @@
|
|||||||
</content>
|
</content>
|
||||||
<orderEntry type="jdk" jdkName="Python 3.13" jdkType="Python SDK" />
|
<orderEntry type="jdk" jdkName="Python 3.13" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="library" name="Python 3.10 interpreter library" level="application" />
|
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
@ -11,7 +11,6 @@
|
|||||||
- Framer-motion
|
- Framer-motion
|
||||||
- chakra-ui
|
- chakra-ui
|
||||||
- HTML5
|
- HTML5
|
||||||
|
|
||||||
### 项目分工
|
### 项目分工
|
||||||
- **后端api,人工智能算法** : `3`(主要) & `log_out` & `Jerry`(maybe) 使用python
|
- **后端api,人工智能算法** : `3`(主要) & `log_out` & `Jerry`(maybe) 使用python
|
||||||
- **前端管理后台设计**:`Jerry`使用react
|
- **前端管理后台设计**:`Jerry`使用react
|
||||||
@ -19,7 +18,9 @@
|
|||||||
|
|
||||||
### 各部分说明
|
### 各部分说明
|
||||||
|
|
||||||
[网页管理前端](https://github.com/Jerryplusy/AI-powered-switches/blob/main/src/frontend/README.md)
|
[网页管理前端如下](https://github.com/Jerryplusy/AI-powered-switches/blob/main/src/frontend/README.md)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
[逻辑处理后端](https://github.com/Jerryplusy/AI-powered-switches/blob/main/src/backend/README.md)
|
[逻辑处理后端](https://github.com/Jerryplusy/AI-powered-switches/blob/main/src/backend/README.md)
|
||||||
|
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
import { Box, Image } from '@chakra-ui/react';
|
import { Box, Image } from '@chakra-ui/react';
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
import image from '@/resources/welcome/image/background.png';
|
import image from '@/resources/welcome/image/background.png';
|
||||||
|
|
||||||
|
const MotionBox = motion(Box);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 带高斯模糊的背景
|
* 带高斯模糊的背景
|
||||||
* @returns {JSX.Element}
|
* @returns {JSX.Element}
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
const BackgroundBlur = () => (
|
const BackgroundBlur = () => (
|
||||||
<Box
|
<MotionBox
|
||||||
position={'absolute'}
|
position={'absolute'}
|
||||||
top={0}
|
top={0}
|
||||||
left={0}
|
left={0}
|
||||||
@ -15,9 +18,12 @@ const BackgroundBlur = () => (
|
|||||||
height={'100%'}
|
height={'100%'}
|
||||||
filter={'blur(6px)'}
|
filter={'blur(6px)'}
|
||||||
zIndex={0}
|
zIndex={0}
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
transition={{ duration: 0.4, ease: 'easeInOut' }}
|
||||||
>
|
>
|
||||||
<Image src={image} objectFit={'cover'} width={'100%'} height={'100%'} />
|
<Image src={image} objectFit={'cover'} width={'100%'} height={'100%'} />
|
||||||
</Box>
|
</MotionBox>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default BackgroundBlur;
|
export default BackgroundBlur;
|
||||||
|
@ -12,7 +12,7 @@ const DashboardCard = () => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
return (
|
return (
|
||||||
<FadeInWrapper delay={0.4} yOffset={-5}>
|
<FadeInWrapper delay={0.4} yOffset={-5}>
|
||||||
<MotionCard icon={manageIcon} text="管理后台" onClick={() => navigate('/dashboard')} />
|
<MotionCard icon={manageIcon} text={'管理后台'} onClick={() => navigate('/dashboard')} />
|
||||||
</FadeInWrapper>
|
</FadeInWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -13,6 +13,7 @@ const GithubCard = () => {
|
|||||||
<MotionCard
|
<MotionCard
|
||||||
icon={githubIcon}
|
icon={githubIcon}
|
||||||
text={'Github'}
|
text={'Github'}
|
||||||
|
hasBlurBackground={true}
|
||||||
onClick={() => window.open('https://github.com/Jerryplusy/AI-powered-switches', '_blank')}
|
onClick={() => window.open('https://github.com/Jerryplusy/AI-powered-switches', '_blank')}
|
||||||
/>
|
/>
|
||||||
</FadeInWrapper>
|
</FadeInWrapper>
|
||||||
|
@ -9,10 +9,10 @@ import FadeInWrapper from '@/components/system/layout/FadeInWrapper';
|
|||||||
*/
|
*/
|
||||||
const WelcomeContent = () => {
|
const WelcomeContent = () => {
|
||||||
return (
|
return (
|
||||||
<VStack spacing={10} py={200} align="center" px={4}>
|
<VStack spacing={10} py={200} align={'center'} px={4}>
|
||||||
<FadeInWrapper delay={0.2} yOffset={-5}>
|
<FadeInWrapper delay={0.2} yOffset={-5}>
|
||||||
<Box textAlign="center">
|
<Box textAlign={'center'}>
|
||||||
<Heading size="6xl" fontWeight="black" color="teal.300">
|
<Heading size="6xl" fontWeight={'black'} color={'teal.300'}>
|
||||||
智能网络交换机
|
智能网络交换机
|
||||||
<br />
|
<br />
|
||||||
管理系统
|
管理系统
|
||||||
@ -20,8 +20,8 @@ const WelcomeContent = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
</FadeInWrapper>
|
</FadeInWrapper>
|
||||||
<FadeInWrapper delay={0.3} yOffset={-5}>
|
<FadeInWrapper delay={0.3} yOffset={-5}>
|
||||||
<Box textAlign="center">
|
<Box textAlign={'center'}>
|
||||||
<Text mt={6} fontSize="2xl" color="gray.300">
|
<Text mt={6} fontSize={'2xl'} color={'gray.300'}>
|
||||||
助力大型网络交换机配置及网络流量管理,方便的管控网络,让网络配置不再困难
|
助力大型网络交换机配置及网络流量管理,方便的管控网络,让网络配置不再困难
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Box, Flex, Heading, Spacer, Button, Card } from '@chakra-ui/react';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import NavButton from '@/components/ui/NavButton';
|
|
||||||
|
|
||||||
const Header = () => {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
return (
|
|
||||||
<Box bg={'teal.500'} px={4} py={2} color={'white'}>
|
|
||||||
<Flex align={'center'}>
|
|
||||||
<Heading size={'md'}>网络管理后台</Heading>
|
|
||||||
<Spacer />
|
|
||||||
<NavButton varint={'ghost'} color={''} onClick={() => navigate('/')}>
|
|
||||||
返回欢迎页
|
|
||||||
</NavButton>
|
|
||||||
</Flex>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Header;
|
|
17
src/frontend/src/components/system/PageContainer.jsx
Normal file
17
src/frontend/src/components/system/PageContainer.jsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { Box } from '@chakra-ui/react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解决导航栏占位问题
|
||||||
|
* @param children
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
const PageContainer = ({ children }) => {
|
||||||
|
return (
|
||||||
|
<Box pt={'60px'} px={6}>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PageContainer;
|
@ -2,6 +2,7 @@ import { Outlet, useLocation } from 'react-router-dom';
|
|||||||
import PageTransition from './PageTransition';
|
import PageTransition from './PageTransition';
|
||||||
import { Box } from '@chakra-ui/react';
|
import { Box } from '@chakra-ui/react';
|
||||||
import { AnimatePresence } from 'framer-motion';
|
import { AnimatePresence } from 'framer-motion';
|
||||||
|
import GithubTransitionCard from '@/components/system/layout/github/GithubTransitionCard';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 应用加壳
|
* 应用加壳
|
||||||
@ -13,8 +14,9 @@ const AppShell = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box position={'relative'} height={'100vh'} overflow={'hidden'}>
|
<Box position={'relative'} height={'100vh'} overflow={'hidden'}>
|
||||||
|
<GithubTransitionCard />
|
||||||
<Box overflowY={'auto'} height={'100%'}>
|
<Box overflowY={'auto'} height={'100%'}>
|
||||||
<AnimatePresence mode={'wait'}>
|
<AnimatePresence mode={'sync'}>
|
||||||
<PageTransition key={location.pathname}>
|
<PageTransition key={location.pathname}>
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</PageTransition>
|
</PageTransition>
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
import { useLocation } from 'react-router-dom';
|
|
||||||
import { motion, AnimatePresence } from 'framer-motion';
|
|
||||||
import { Box, Text, Image } from '@chakra-ui/react';
|
|
||||||
import githubIcon from '@/resources/welcome/image/github.svg';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GitHub图标变换=>导航栏
|
|
||||||
* @returns {JSX.Element}
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
const GithubNavTransition = () => {
|
|
||||||
const { pathname } = useLocation();
|
|
||||||
const isDashboard = pathname.startsWith('/dashboard');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AnimatePresence>
|
|
||||||
<motion.div
|
|
||||||
key={isDashboard ? 'nav' : 'icon'}
|
|
||||||
initial={{ opacity: 0, scale: 0.9 }}
|
|
||||||
animate={{
|
|
||||||
opacity: 1,
|
|
||||||
scale: 1,
|
|
||||||
right: 16,
|
|
||||||
top: 16,
|
|
||||||
width: isDashboard ? 160 : 50,
|
|
||||||
}}
|
|
||||||
exit={{ opacity: 0, scale: 0.95 }}
|
|
||||||
transition={{ duration: 0.4 }}
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
zIndex: 20,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
display={'flex'}
|
|
||||||
alignItems={'center'}
|
|
||||||
bg={'whiteAlpha.200'}
|
|
||||||
border={'1px solid'}
|
|
||||||
borderColor={'gray.600'}
|
|
||||||
px={isDashboard ? 4 : 2}
|
|
||||||
py={2}
|
|
||||||
borderRadius={'md'}
|
|
||||||
cursor={'pointer'}
|
|
||||||
onClick={() => window.open('https://github.com/Jerryplusy/AI-powered-switches', '_blank')}
|
|
||||||
>
|
|
||||||
<Image src={githubIcon} boxSize={5} mr={2} />
|
|
||||||
{isDashboard && (
|
|
||||||
<Text color={'white'} fontSize={'sm'}>
|
|
||||||
GitHub 项目主页
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</motion.div>
|
|
||||||
</AnimatePresence>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default GithubNavTransition;
|
|
@ -0,0 +1,103 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
|
import { Button, HStack } from '@chakra-ui/react';
|
||||||
|
import web from '@/resources/icon/web.svg';
|
||||||
|
import githubIcon from '@/resources/welcome/image/github.svg';
|
||||||
|
import FadeInWrapper from '@/components/system/layout/FadeInWrapper';
|
||||||
|
import MotionCard from '@/components/ui/MotionCard';
|
||||||
|
|
||||||
|
const navItems = [
|
||||||
|
{ label: '面板', path: '/dashboard' },
|
||||||
|
{ label: '网络', path: '/dashboard/network' },
|
||||||
|
{ label: '交换机', path: '/dashboard/switch' },
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导航栏&github按钮组件
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
const GithubTransitionCard = () => {
|
||||||
|
const { pathname } = useLocation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const isDashboard = pathname.startsWith('/dashboard');
|
||||||
|
const [showNavButtons, setShowNavButtons] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setShowNavButtons(false);
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
if (isDashboard) setShowNavButtons(true);
|
||||||
|
}, 400);
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [isDashboard]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AnimatePresence mode={'wait'}>
|
||||||
|
<motion.div
|
||||||
|
key={isDashboard ? 'dashboard' : 'welcome'}
|
||||||
|
initial={{ opacity: 0, height: 'auto', width: isDashboard ? 200 : 'auto' }}
|
||||||
|
animate={{
|
||||||
|
opacity: 1,
|
||||||
|
height: isDashboard ? 64 : 'auto',
|
||||||
|
width: isDashboard ? '100%' : 'fit-content',
|
||||||
|
}}
|
||||||
|
exit={{ opacity: 0 }}
|
||||||
|
transition={{ duration: 0.4, ease: 'easeInOut' }}
|
||||||
|
style={{
|
||||||
|
position: 'fixed',
|
||||||
|
top: 10,
|
||||||
|
left: isDashboard ? 0 : 'auto',
|
||||||
|
right: isDashboard ? 0 : 16,
|
||||||
|
zIndex: 999,
|
||||||
|
padding: isDashboard ? '0 16px' : 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FadeInWrapper delay={0.1} yOffset={-10}>
|
||||||
|
<MotionCard
|
||||||
|
icon={isDashboard ? web : githubIcon}
|
||||||
|
text={isDashboard ? '控制台导航栏' : 'Github'}
|
||||||
|
hasBlurBackground
|
||||||
|
onClick={() => {
|
||||||
|
if (!isDashboard) {
|
||||||
|
window.open('https://github.com/Jerryplusy/AI-powered-switches', '_blank');
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
justifyContent={isDashboard ? 'flex-start' : 'center'}
|
||||||
|
alignItems={'center'}
|
||||||
|
flexDirection={'row'}
|
||||||
|
w={'100%'}
|
||||||
|
px={isDashboard ? 4 : 3}
|
||||||
|
py={isDashboard ? 3 : 2}
|
||||||
|
noHover={isDashboard}
|
||||||
|
>
|
||||||
|
{isDashboard && showNavButtons && (
|
||||||
|
<HStack spacing={4} ml={'auto'}>
|
||||||
|
{navItems.map((item) => (
|
||||||
|
<Button
|
||||||
|
key={item.path}
|
||||||
|
size={'sm'}
|
||||||
|
variant={'ghost'}
|
||||||
|
color={'white'}
|
||||||
|
_hover={{
|
||||||
|
color: 'teal.300',
|
||||||
|
background: 'transparent',
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
navigate(item.path);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</HStack>
|
||||||
|
)}
|
||||||
|
</MotionCard>
|
||||||
|
</FadeInWrapper>
|
||||||
|
</motion.div>
|
||||||
|
</AnimatePresence>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GithubTransitionCard;
|
@ -0,0 +1,61 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Box } from '@chakra-ui/react';
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
const MotionBox = motion(Box);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 控制台背景
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
const DashboardBackground = () => {
|
||||||
|
const [mousePos, setMousePos] = useState({ x: 0, y: 0 });
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleMouseMove = (e) => {
|
||||||
|
setMousePos({ x: e.clientX, y: e.clientY });
|
||||||
|
};
|
||||||
|
window.addEventListener('mousemove', handleMouseMove);
|
||||||
|
return () => window.removeEventListener('mousemove', handleMouseMove);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const spotlight = {
|
||||||
|
background: `radial-gradient(
|
||||||
|
circle at ${mousePos.x}px ${mousePos.y}px,
|
||||||
|
rgba(255, 255, 255, 0.05) 0%,
|
||||||
|
rgba(255, 255, 255, 0.02) 120px,
|
||||||
|
transparent 240px
|
||||||
|
)`,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MotionBox
|
||||||
|
position={{ base: 'fixed' }}
|
||||||
|
top={0}
|
||||||
|
left={0}
|
||||||
|
w={{ base: '100vw' }}
|
||||||
|
h={{ base: '100vh' }}
|
||||||
|
zIndex={-1}
|
||||||
|
background={{
|
||||||
|
base: 'linear-gradient(135deg, #18274C 0%, #21397F 50%, #1D3062 100%)',
|
||||||
|
}}
|
||||||
|
_after={{
|
||||||
|
content: { base: '""' },
|
||||||
|
position: { base: 'absolute' },
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
w: { base: '100%' },
|
||||||
|
h: { base: '100%' },
|
||||||
|
pointerEvents: { base: 'none' },
|
||||||
|
...spotlight,
|
||||||
|
transition: { base: 'background 0.2s ease' },
|
||||||
|
}}
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
transition={{ duration: 1.2, ease: 'easeInOut' }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DashboardBackground;
|
10
src/frontend/src/components/system/pages/DocumentTitle.jsx
Normal file
10
src/frontend/src/components/system/pages/DocumentTitle.jsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
const DocumentTitle = ({ title, children }) => {
|
||||||
|
useEffect(() => {
|
||||||
|
document.title = title || '网络管理后台';
|
||||||
|
}, [title]);
|
||||||
|
return children;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DocumentTitle;
|
@ -4,19 +4,28 @@ import { motion } from 'framer-motion';
|
|||||||
const MotionBox = motion(Box);
|
const MotionBox = motion(Box);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 带有动作效果的卡片
|
* 卡片组件
|
||||||
* @param icon 可选图标
|
* @param icon 可选图标
|
||||||
* @param text 文字
|
* @param text 文字
|
||||||
* @param onClick 点击执行操作
|
* @param onClick 点击执行函数
|
||||||
|
* @param hasBlurBackground 是否模糊背景
|
||||||
|
* @param noHover 是否禁用 hover 动画
|
||||||
|
* @param children 子组件
|
||||||
|
* @param props
|
||||||
* @returns {JSX.Element}
|
* @returns {JSX.Element}
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
const MotionCard = ({ icon, text, onClick }) => (
|
const MotionCard = ({
|
||||||
|
icon,
|
||||||
|
text,
|
||||||
|
onClick,
|
||||||
|
hasBlurBackground = false,
|
||||||
|
disableHover = false,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}) => (
|
||||||
<MotionBox
|
<MotionBox
|
||||||
whileHover={{
|
position={'relative'}
|
||||||
y: -3,
|
|
||||||
boxShadow: 'inset 0 0 0 1000px rgba(255, 255, 255, 0.3)',
|
|
||||||
}}
|
|
||||||
display={'flex'}
|
display={'flex'}
|
||||||
alignItems={'center'}
|
alignItems={'center'}
|
||||||
bg={'whiteAlpha.200'}
|
bg={'whiteAlpha.200'}
|
||||||
@ -25,12 +34,46 @@ const MotionCard = ({ icon, text, onClick }) => (
|
|||||||
px={4}
|
px={4}
|
||||||
py={2}
|
py={2}
|
||||||
borderRadius={'md'}
|
borderRadius={'md'}
|
||||||
cursor={'pointer'}
|
cursor={onClick ? 'pointer' : 'default'}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
transition={{ duration: 0.1 }}
|
transition={'all 0.2s ease'}
|
||||||
|
overflow={'hidden'}
|
||||||
|
_hover={
|
||||||
|
disableHover
|
||||||
|
? {}
|
||||||
|
: {
|
||||||
|
_before: {
|
||||||
|
content: '""',
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
bg: 'whiteAlpha.100',
|
||||||
|
zIndex: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{...props}
|
||||||
>
|
>
|
||||||
{icon && <Image src={icon} boxSize={5} mr={2} />}
|
{hasBlurBackground && (
|
||||||
<Text color={'white'}>{text}</Text>
|
<Box
|
||||||
|
position={'absolute'}
|
||||||
|
top={0}
|
||||||
|
left={0}
|
||||||
|
right={0}
|
||||||
|
bottom={0}
|
||||||
|
backdropFilter={'blur(4px)'}
|
||||||
|
zIndex={-1}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{icon && <Image src={icon} boxSize={5} mr={2} zIndex={2} />}
|
||||||
|
{text && (
|
||||||
|
<Text color={'white'} zIndex={2}>
|
||||||
|
{text}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
<Box zIndex={2}>{children}</Box>
|
||||||
</MotionBox>
|
</MotionBox>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,90 +1,86 @@
|
|||||||
'use client'
|
'use client';
|
||||||
|
|
||||||
import { ClientOnly, IconButton, Skeleton, Span } from '@chakra-ui/react'
|
import { ClientOnly, IconButton, Skeleton, Span } from '@chakra-ui/react';
|
||||||
import { ThemeProvider, useTheme } from 'next-themes'
|
import { ThemeProvider, useTheme } from 'next-themes';
|
||||||
|
|
||||||
import * as React from 'react'
|
import * as React from 'react';
|
||||||
import { LuMoon, LuSun } from 'react-icons/lu'
|
import { LuMoon, LuSun } from 'react-icons/lu';
|
||||||
|
|
||||||
export function ColorModeProvider(props) {
|
export function ColorModeProvider(props) {
|
||||||
return (
|
return <ThemeProvider attribute="class" disableTransitionOnChange {...props} />;
|
||||||
<ThemeProvider attribute='class' disableTransitionOnChange {...props} />
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useColorMode() {
|
export function useColorMode() {
|
||||||
const { resolvedTheme, setTheme, forcedTheme } = useTheme()
|
const { resolvedTheme, setTheme, forcedTheme } = useTheme();
|
||||||
const colorMode = forcedTheme || resolvedTheme
|
const colorMode = forcedTheme || resolvedTheme;
|
||||||
const toggleColorMode = () => {
|
const toggleColorMode = () => {
|
||||||
setTheme(resolvedTheme === 'dark' ? 'light' : 'dark')
|
setTheme(resolvedTheme === 'dark' ? 'light' : 'dark');
|
||||||
}
|
};
|
||||||
return {
|
return {
|
||||||
colorMode: colorMode,
|
colorMode: colorMode,
|
||||||
setColorMode: setTheme,
|
setColorMode: setTheme,
|
||||||
toggleColorMode,
|
toggleColorMode,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useColorModeValue(light, dark) {
|
export function useColorModeValue(light, dark) {
|
||||||
const { colorMode } = useColorMode()
|
const { colorMode } = useColorMode();
|
||||||
return colorMode === 'dark' ? dark : light
|
return colorMode === 'dark' ? dark : light;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ColorModeIcon() {
|
export function ColorModeIcon() {
|
||||||
const { colorMode } = useColorMode()
|
const { colorMode } = useColorMode();
|
||||||
return colorMode === 'dark' ? <LuMoon /> : <LuSun />
|
return colorMode === 'dark' ? <LuMoon /> : <LuSun />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ColorModeButton = React.forwardRef(
|
export const ColorModeButton = React.forwardRef(function ColorModeButton(props, ref) {
|
||||||
function ColorModeButton(props, ref) {
|
const { toggleColorMode } = useColorMode();
|
||||||
const { toggleColorMode } = useColorMode()
|
return (
|
||||||
return (
|
<ClientOnly fallback={<Skeleton boxSize="8" />}>
|
||||||
<ClientOnly fallback={<Skeleton boxSize='8' />}>
|
<IconButton
|
||||||
<IconButton
|
onClick={toggleColorMode}
|
||||||
onClick={toggleColorMode}
|
variant="ghost"
|
||||||
variant='ghost'
|
aria-label="Toggle color mode"
|
||||||
aria-label='Toggle color mode'
|
size="sm"
|
||||||
size='sm'
|
ref={ref}
|
||||||
ref={ref}
|
{...props}
|
||||||
{...props}
|
css={{
|
||||||
css={{
|
_icon: {
|
||||||
_icon: {
|
width: '5',
|
||||||
width: '5',
|
height: '5',
|
||||||
height: '5',
|
},
|
||||||
},
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<ColorModeIcon />
|
||||||
<ColorModeIcon />
|
</IconButton>
|
||||||
</IconButton>
|
</ClientOnly>
|
||||||
</ClientOnly>
|
);
|
||||||
)
|
});
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
export const LightMode = React.forwardRef(function LightMode(props, ref) {
|
export const LightMode = React.forwardRef(function LightMode(props, ref) {
|
||||||
return (
|
return (
|
||||||
<Span
|
<Span
|
||||||
color='fg'
|
color="fg"
|
||||||
display='contents'
|
display="contents"
|
||||||
className='chakra-theme light'
|
className="chakra-theme light"
|
||||||
colorPalette='gray'
|
colorPalette="gray"
|
||||||
colorScheme='light'
|
colorScheme="light"
|
||||||
ref={ref}
|
ref={ref}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
|
|
||||||
export const DarkMode = React.forwardRef(function DarkMode(props, ref) {
|
export const DarkMode = React.forwardRef(function DarkMode(props, ref) {
|
||||||
return (
|
return (
|
||||||
<Span
|
<Span
|
||||||
color='fg'
|
color="fg"
|
||||||
display='contents'
|
display="contents"
|
||||||
className='chakra-theme dark'
|
className="chakra-theme dark"
|
||||||
colorPalette='gray'
|
colorPalette="gray"
|
||||||
colorScheme='dark'
|
colorScheme="dark"
|
||||||
ref={ref}
|
ref={ref}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Box, Text } from '@chakra-ui/react';
|
import { Box, Text } from '@chakra-ui/react';
|
||||||
|
import DocumentTitle from '@/components/system/pages/DocumentTitle';
|
||||||
|
import PageContainer from '@/components/system/PageContainer';
|
||||||
|
import DashboardBackground from '@/components/system/pages/DashboardBackground';
|
||||||
|
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<DocumentTitle title={'控制台'}>
|
||||||
<Box p={6}>
|
<DashboardBackground />
|
||||||
<Text fontSize={'xl'}>控制台奇怪的功能+1</Text>
|
<PageContainer>
|
||||||
</Box>
|
<Box p={6}>
|
||||||
</>
|
<Text fontSize={'xl'}>控制台奇怪的功能+1</Text>
|
||||||
|
</Box>
|
||||||
|
</PageContainer>
|
||||||
|
</DocumentTitle>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { Box } from '@chakra-ui/react';
|
import { Box } from '@chakra-ui/react';
|
||||||
import BackgroundBlur from '@/components/pages/welcome/BackgroundBlur';
|
import BackgroundBlur from '@/components/pages/welcome/BackgroundBlur';
|
||||||
import WelcomeContent from '@/components/pages/welcome/WelcomeContent';
|
import WelcomeContent from '@/components/pages/welcome/WelcomeContent';
|
||||||
import GithubCard from '@/components/pages/welcome/GithubCard';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 欢迎页
|
* 欢迎页
|
||||||
@ -13,7 +12,7 @@ const Welcome = () => {
|
|||||||
<Box position={'relative'} height={'100vh'} overflow={'hidden'}>
|
<Box position={'relative'} height={'100vh'} overflow={'hidden'}>
|
||||||
<BackgroundBlur />
|
<BackgroundBlur />
|
||||||
<Box position={'absolute'} top={4} right={4} zIndex={10}>
|
<Box position={'absolute'} top={4} right={4} zIndex={10}>
|
||||||
<GithubCard />
|
{/*<GithubCard />*/}
|
||||||
</Box>
|
</Box>
|
||||||
<Box overflowY={'auto'} height={'100%'} zIndex={1} position={'relative'}>
|
<Box overflowY={'auto'} height={'100%'} zIndex={1} position={'relative'}>
|
||||||
<WelcomeContent />
|
<WelcomeContent />
|
||||||
|
1
src/frontend/src/resources/icon/web.svg
Normal file
1
src/frontend/src/resources/icon/web.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 24 24"><g fill="none" stroke="#2ee2e5" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" color="#2ee2e5"><circle cx="12" cy="12" r="10"/><ellipse cx="12" cy="12" rx="4" ry="10"/><path d="M2 12h20"/></g></svg>
|
After Width: | Height: | Size: 300 B |
BIN
src/frontend/src/resources/img.png
Normal file
BIN
src/frontend/src/resources/img.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 869 KiB |
Loading…
x
Reference in New Issue
Block a user