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
a4abe6e229
commit
20ded22f22
@ -1,10 +1,20 @@
|
|||||||
# Network Admin Web UI
|
# Network Admin Web UI
|
||||||
|
|
||||||
基于 React 和 Chakra UI
|
### 基于 `React` 和 `Chakra UI`
|
||||||
|
|
||||||
- 前端框架:React
|
#### 架构
|
||||||
- UI 组件库:Chakra UI
|
- 前端框架:`React`
|
||||||
- 网络图表:Recharts
|
- UI 组件库:`Chakra UI`
|
||||||
- 状态管理:React hooks
|
- 网络图表:`Recharts`
|
||||||
- 数据通信:Axios
|
- 状态管理:`React hooks`
|
||||||
- 页面路由:React Router
|
- 数据通信:`Axios`
|
||||||
|
- 页面路由:`React Router`
|
||||||
|
|
||||||
|
#### 部署方法
|
||||||
|
- `clone`项目
|
||||||
|
- 导航到`/src/frontend/`目录
|
||||||
|
- 使用`pnpm`管理软件包:`npm install pnpm -g`
|
||||||
|
- 安装依赖:`pnpm install`
|
||||||
|
- 执行`pnpm build`进行`react`服务端构建
|
||||||
|
- 运行`pnpm start`启动服务端
|
||||||
|
- 服务运行在本地`3000`端口
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
import { Box, Image } from '@chakra-ui/react';
|
import { Box, Image } from '@chakra-ui/react';
|
||||||
import image from '@/resources/welcome/image/background.png';
|
import image from '@/resources/welcome/image/background.png';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 带高斯模糊的背景
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
const BackgroundBlur = () => (
|
const BackgroundBlur = () => (
|
||||||
<Box
|
<Box
|
||||||
position={'absolute'}
|
position={'absolute'}
|
||||||
|
@ -1,10 +1,20 @@
|
|||||||
import manageIcon from '@/resources/welcome/image/setting.svg';
|
import manageIcon from '@/resources/welcome/image/setting.svg';
|
||||||
import MotionCard from '@/components/ui/MotionCard';
|
import MotionCard from '@/components/ui/MotionCard';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import FadeInWrapper from '@/components/system/layout/FadeInWrapper';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 进入管理后台按钮组件
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
const DashboardCard = () => {
|
const DashboardCard = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
return <MotionCard icon={manageIcon} text="管理后台" onClick={() => navigate('/dashboard')} />;
|
return (
|
||||||
|
<FadeInWrapper delay={0.4} yOffset={-5}>
|
||||||
|
<MotionCard icon={manageIcon} text="管理后台" onClick={() => navigate('/dashboard')} />
|
||||||
|
</FadeInWrapper>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DashboardCard;
|
export default DashboardCard;
|
||||||
|
@ -1,13 +1,21 @@
|
|||||||
import githubIcon from '@/resources/welcome/image/github.svg';
|
import githubIcon from '@/resources/welcome/image/github.svg';
|
||||||
import MotionCard from '@/components/ui/MotionCard';
|
import MotionCard from '@/components/ui/MotionCard';
|
||||||
|
import FadeInWrapper from '@/components/system/layout/FadeInWrapper';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GitHub按钮组件
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
const GithubCard = () => {
|
const GithubCard = () => {
|
||||||
return (
|
return (
|
||||||
|
<FadeInWrapper delay={0.1} yOffset={-10}>
|
||||||
<MotionCard
|
<MotionCard
|
||||||
icon={githubIcon}
|
icon={githubIcon}
|
||||||
text={'github'}
|
text={'Github'}
|
||||||
onClick={() => window.open('https://github.com/Jerryplusy/AI-powered-switches', '_blank')}
|
onClick={() => window.open('https://github.com/Jerryplusy/AI-powered-switches', '_blank')}
|
||||||
/>
|
/>
|
||||||
|
</FadeInWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,19 +1,31 @@
|
|||||||
import { Box, Heading, Text, VStack } from '@chakra-ui/react';
|
import { Box, Heading, Text, VStack } from '@chakra-ui/react';
|
||||||
import DashboardCard from '@/components/pages/welcome/DashboardCard';
|
import DashboardCard from '@/components/pages/welcome/DashboardCard';
|
||||||
|
import FadeInWrapper from '@/components/system/layout/FadeInWrapper';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 欢迎文字
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
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}>
|
||||||
<Box textAlign="center">
|
<Box textAlign="center">
|
||||||
<Heading size="6xl" fontWeight="black" color="teal.300">
|
<Heading size="6xl" fontWeight="black" color="teal.300">
|
||||||
智能网络交换机
|
智能网络交换机
|
||||||
<br />
|
<br />
|
||||||
管理系统
|
管理系统
|
||||||
</Heading>
|
</Heading>
|
||||||
|
</Box>
|
||||||
|
</FadeInWrapper>
|
||||||
|
<FadeInWrapper delay={0.3} yOffset={-5}>
|
||||||
|
<Box textAlign="center">
|
||||||
<Text mt={6} fontSize="2xl" color="gray.300">
|
<Text mt={6} fontSize="2xl" color="gray.300">
|
||||||
助力大型网络交换机配置及网络流量管理,方便的管控网络,让网络配置不再困难
|
助力大型网络交换机配置及网络流量管理,方便的管控网络,让网络配置不再困难
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
</FadeInWrapper>
|
||||||
<DashboardCard />
|
<DashboardCard />
|
||||||
</VStack>
|
</VStack>
|
||||||
);
|
);
|
||||||
|
@ -3,6 +3,11 @@ 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';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用加壳
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
const AppShell = () => {
|
const AppShell = () => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
|
29
src/frontend/src/components/system/layout/FadeInWrapper.jsx
Normal file
29
src/frontend/src/components/system/layout/FadeInWrapper.jsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组件载入动画
|
||||||
|
* @param children 子组件
|
||||||
|
* @param delay 延迟
|
||||||
|
* @param yOffset y轴偏移量
|
||||||
|
* @param duration 动画时间
|
||||||
|
* @param className 类名
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
const FadeInWrapper = ({ children, delay = 0, yOffset = 10, duration = 0.6, className = '' }) => {
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: yOffset }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{
|
||||||
|
delay,
|
||||||
|
duration,
|
||||||
|
ease: [0.16, 0.77, 0.47, 0.97],
|
||||||
|
}}
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default FadeInWrapper;
|
@ -3,6 +3,11 @@ import { motion, AnimatePresence } from 'framer-motion';
|
|||||||
import { Box, Text, Image } from '@chakra-ui/react';
|
import { Box, Text, Image } from '@chakra-ui/react';
|
||||||
import githubIcon from '@/resources/welcome/image/github.svg';
|
import githubIcon from '@/resources/welcome/image/github.svg';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GitHub图标变换=>导航栏
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
const GithubNavTransition = () => {
|
const GithubNavTransition = () => {
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
const isDashboard = pathname.startsWith('/dashboard');
|
const isDashboard = pathname.startsWith('/dashboard');
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
const PageTransition = ({ children }) => (
|
/**
|
||||||
<motion.div
|
* 页面动效
|
||||||
initial={{ opacity: 0, y: 10 }}
|
* @param children
|
||||||
animate={{ opacity: 1, y: 0 }}
|
* @returns {JSX.Element}
|
||||||
transition={{ duration: 0.2 }}
|
* @constructor
|
||||||
>
|
*/
|
||||||
{children}
|
const PageTransition = ({ children }) => <motion.div>{children}</motion.div>;
|
||||||
</motion.div>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default PageTransition;
|
export default PageTransition;
|
||||||
|
/**
|
||||||
|
* initial={{ opacity: 0, y: 0 }}
|
||||||
|
* animate={{ opacity: 1, y: 0 }}
|
||||||
|
* transition={{ duration: 0.2 }}
|
||||||
|
*/
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
import FadeInWrapper from './FadeInWrapper';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归为组件及子组件添加载入动效
|
||||||
|
* @param children 子组件
|
||||||
|
* @param baseDelay 延迟
|
||||||
|
* @param increment 增值
|
||||||
|
* @param className 类名
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
const StaggeredFadeIn = ({ children, baseDelay = 0.2, increment = 0.1, className = '' }) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{React.Children.map(children, (child, index) => (
|
||||||
|
<FadeInWrapper key={index} delay={baseDelay + index * increment} className={className}>
|
||||||
|
{child}
|
||||||
|
</FadeInWrapper>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StaggeredFadeIn;
|
@ -5,7 +5,10 @@ const MotionBox = motion(Box);
|
|||||||
|
|
||||||
const MotionCard = ({ icon, text, onClick }) => (
|
const MotionCard = ({ icon, text, onClick }) => (
|
||||||
<MotionBox
|
<MotionBox
|
||||||
whileHover={{ y: -5 }}
|
whileHover={{
|
||||||
|
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'}
|
||||||
@ -16,6 +19,7 @@ const MotionCard = ({ icon, text, onClick }) => (
|
|||||||
borderRadius={'md'}
|
borderRadius={'md'}
|
||||||
cursor={'pointer'}
|
cursor={'pointer'}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
|
transition={{ duration: 0.1 }}
|
||||||
>
|
>
|
||||||
{icon && <Image src={icon} boxSize={5} mr={2} />}
|
{icon && <Image src={icon} boxSize={5} mr={2} />}
|
||||||
<Text color={'white'}>{text}</Text>
|
<Text color={'white'}>{text}</Text>
|
||||||
|
@ -2,6 +2,10 @@ import { Route } from 'react-router-dom';
|
|||||||
import Welcome from '@/pages/Welcome';
|
import Welcome from '@/pages/Welcome';
|
||||||
import Dashboard from '@/pages/Dashboard';
|
import Dashboard from '@/pages/Dashboard';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 路由
|
||||||
|
* @type {[{path: string, element: JSX.Element},{path: string, element: JSX.Element}]}
|
||||||
|
*/
|
||||||
const routeList = [
|
const routeList = [
|
||||||
{ path: '/', element: <Welcome /> },
|
{ path: '/', element: <Welcome /> },
|
||||||
{ path: '/dashboard', element: <Dashboard /> },
|
{ path: '/dashboard', element: <Dashboard /> },
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Box, Text } from '@chakra-ui/react';
|
import { Box, Text } from '@chakra-ui/react';
|
||||||
import Header from '../components/system/Header';
|
|
||||||
|
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Header />
|
|
||||||
<Box p={6}>
|
<Box p={6}>
|
||||||
<Text fontSize={'xl'}>控制台奇怪的功能+1</Text>
|
<Text fontSize={'xl'}>控制台奇怪的功能+1</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -3,6 +3,11 @@ 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';
|
import GithubCard from '@/components/pages/welcome/GithubCard';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 欢迎页
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
const Welcome = () => {
|
const Welcome = () => {
|
||||||
return (
|
return (
|
||||||
<Box position={'relative'} height={'100vh'} overflow={'hidden'}>
|
<Box position={'relative'} height={'100vh'} overflow={'hidden'}>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user