v1.0-230926 #27
@@ -1,10 +1,13 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
|
import LoadingMask from '@/components/LoadingMask.tsx'
|
||||||
|
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<Suspense fallback={<LoadingMask />}>
|
||||||
<RouterProvider router={router} />
|
<RouterProvider router={router} />
|
||||||
|
</Suspense>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
22
src/assets/css/_mixins.scss
Normal file
22
src/assets/css/_mixins.scss
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
@mixin keyframes($animationName) {
|
||||||
|
@-webkit-keyframes #{$animationName} {
|
||||||
|
@content
|
||||||
|
}
|
||||||
|
@-moz-keyframes #{$animationName} {
|
||||||
|
@content
|
||||||
|
}
|
||||||
|
@-o-keyframes #{$animationName} {
|
||||||
|
@content
|
||||||
|
}
|
||||||
|
@keyframes #{$animationName} {
|
||||||
|
@content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin unique-keyframes {
|
||||||
|
$animationName: unique-id();
|
||||||
|
animation-name: $animationName;
|
||||||
|
@include keyframes($animationName) {
|
||||||
|
@content
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ $font-secondary-color: #9E9E9E;
|
|||||||
.body {
|
.body {
|
||||||
color: $font-main-color;
|
color: $font-main-color;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
min-width: 1800px;
|
min-width: 900px;
|
||||||
min-height: 400px;
|
min-height: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,3 +103,19 @@ $font-secondary-color: #9E9E9E;
|
|||||||
height: 23px;
|
height: 23px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#loading-mask {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 100;
|
||||||
|
background-color: rgba(200, 200, 200, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#fit-fullscreen {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
@use "mixins" as mixins;
|
||||||
|
|
||||||
.nav {
|
.nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -13,6 +15,16 @@
|
|||||||
color: rgba(204, 204, 204, .33);
|
color: rgba(204, 204, 204, .33);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
animation: .5s ease both;
|
||||||
|
|
||||||
|
@include mixins.unique-keyframes {
|
||||||
|
0% {
|
||||||
|
transform: translateY(-100%);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
padding: 0 40px;
|
padding: 0 40px;
|
||||||
@@ -22,4 +34,60 @@
|
|||||||
font-family: century gothic, texgyreadventor, stheiti, sans-serif;
|
font-family: century gothic, texgyreadventor, stheiti, sans-serif;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
display: flex;
|
||||||
|
justify-content: end;
|
||||||
|
flex: 1;
|
||||||
|
transition: {
|
||||||
|
property: all;
|
||||||
|
duration: .5s;
|
||||||
|
};
|
||||||
|
|
||||||
|
.menu {
|
||||||
|
padding: 0 30px;
|
||||||
|
|
||||||
|
.item {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 1.5em;
|
||||||
|
transition: {
|
||||||
|
property: all;
|
||||||
|
duration: .3s;
|
||||||
|
};
|
||||||
|
|
||||||
|
a {
|
||||||
|
padding: 5px 20px;
|
||||||
|
color: rgba(102, 102, 102, .8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.active {
|
||||||
|
border: {
|
||||||
|
bottom: {
|
||||||
|
width: 2px;
|
||||||
|
style: solid;
|
||||||
|
color: #CCC;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav.hide {
|
||||||
|
animation: .5s ease both;
|
||||||
|
|
||||||
|
@include mixins.unique-keyframes {
|
||||||
|
0% {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
display: none;
|
||||||
|
transform: translateY(-100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
@import url(header.scss);
|
|
||||||
1
src/assets/svg/loading.svg
Normal file
1
src/assets/svg/loading.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="64" height="64"><path d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 0 0-94.3-139.9 437.71 437.71 0 0 0-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3 0.1 19.9-16 36-35.9 36z" /></svg>
|
||||||
|
After Width: | Height: | Size: 439 B |
11
src/components/FitFullScreen.tsx
Normal file
11
src/components/FitFullScreen.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const FitFullScreen: React.FC<PropsWithChildren> = (props: PropsWithChildren) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div id={'fit-fullscreen'}>{props.children}</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FitFullScreen
|
||||||
12
src/components/Home.tsx
Normal file
12
src/components/Home.tsx
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import '@/assets/css/home.scss'
|
||||||
|
|
||||||
|
const Home: React.FC = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>Home</h1>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Home
|
||||||
27
src/components/LoadingMask.tsx
Normal file
27
src/components/LoadingMask.tsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Icon from '@ant-design/icons'
|
||||||
|
import FitFullScreen from '@/components/FitFullScreen.tsx'
|
||||||
|
import { COLOR_FONT_MAIN } from '@/constants/Common.constants.ts'
|
||||||
|
|
||||||
|
const LoadingMask: React.FC = () => {
|
||||||
|
const loadingIcon = (
|
||||||
|
<>
|
||||||
|
<Icon
|
||||||
|
component={IconFatwebLoading as React.ComponentType}
|
||||||
|
style={{ fontSize: 24, color: COLOR_FONT_MAIN }}
|
||||||
|
spin
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FitFullScreen>
|
||||||
|
<div id={'loading-mask'}>
|
||||||
|
<AntdSpin indicator={loadingIcon} />
|
||||||
|
</div>
|
||||||
|
</FitFullScreen>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LoadingMask
|
||||||
11
src/components/Project.tsx
Normal file
11
src/components/Project.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const Project: React.FC = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>App</h1>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Project
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import '@/assets/css/home.scss'
|
|
||||||
|
|
||||||
const Home: React.FC = () => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<header className={'nav'}>
|
|
||||||
<a className={'logo'} href={'https://fatweb.top'}>
|
|
||||||
<span className={'title'}>FatWeb</span>
|
|
||||||
</a>
|
|
||||||
</header>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Home
|
|
||||||
75
src/pages/MainFramework.tsx
Normal file
75
src/pages/MainFramework.tsx
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import React, { createContext } from 'react'
|
||||||
|
import '@/assets/css/header.scss'
|
||||||
|
import LoadingMask from '@/components/LoadingMask.tsx'
|
||||||
|
|
||||||
|
export const MainFrameworkContext = createContext<{
|
||||||
|
hideNavbar: boolean
|
||||||
|
setHideNavbar: (newValue: boolean) => void
|
||||||
|
}>({
|
||||||
|
hideNavbar: false,
|
||||||
|
setHideNavbar: () => undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
const MainFramework: React.FC = () => {
|
||||||
|
const [hideNavbar, setHideNavbar] = useState(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={'body'}>
|
||||||
|
<header className={'nav ' + (hideNavbar ? 'hide' : '')}>
|
||||||
|
<a className={'logo'} href={'https://fatweb.top'}>
|
||||||
|
<span className={'title'}>FatWeb</span>
|
||||||
|
</a>
|
||||||
|
<nav>
|
||||||
|
<ul className={'menu'}>
|
||||||
|
<li className={'item'}>
|
||||||
|
<NavLink
|
||||||
|
to={''}
|
||||||
|
className={({ isActive, isPending }) =>
|
||||||
|
isPending ? 'pending' : isActive ? 'active' : ''
|
||||||
|
}
|
||||||
|
>
|
||||||
|
主页
|
||||||
|
</NavLink>
|
||||||
|
</li>
|
||||||
|
<li className={'item'}>
|
||||||
|
<NavLink
|
||||||
|
to={'https://blog.fatweb.top'}
|
||||||
|
className={({ isActive, isPending }) =>
|
||||||
|
isPending ? 'pending' : isActive ? 'active' : ''
|
||||||
|
}
|
||||||
|
>
|
||||||
|
博客
|
||||||
|
</NavLink>
|
||||||
|
</li>
|
||||||
|
<li className={'item'}>
|
||||||
|
<NavLink
|
||||||
|
to={'project'}
|
||||||
|
className={({ isActive, isPending }) =>
|
||||||
|
isPending ? 'pending' : isActive ? 'active' : ''
|
||||||
|
}
|
||||||
|
>
|
||||||
|
App
|
||||||
|
</NavLink>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<MainFrameworkContext.Provider value={{ hideNavbar, setHideNavbar }}>
|
||||||
|
<Suspense
|
||||||
|
fallback={
|
||||||
|
<>
|
||||||
|
<LoadingMask />
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Outlet />
|
||||||
|
</Suspense>
|
||||||
|
</MainFrameworkContext.Provider>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MainFramework
|
||||||
@@ -10,14 +10,34 @@ const routes: RouteObject[] = [
|
|||||||
id: 'login',
|
id: 'login',
|
||||||
Component: React.lazy(() => import('@/pages/Login'))
|
Component: React.lazy(() => import('@/pages/Login'))
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/loading',
|
||||||
|
id: 'loading',
|
||||||
|
Component: React.lazy(() => import('@/components/LoadingMask'))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
id: 'mainFramework',
|
||||||
|
Component: React.lazy(() => import('@/pages/MainFramework')),
|
||||||
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
id: 'home',
|
id: 'home',
|
||||||
Component: React.lazy(() => import('@/pages/Home')),
|
Component: React.lazy(() => import('@/components/Home')),
|
||||||
handle: {
|
handle: {
|
||||||
auth: false
|
auth: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'project',
|
||||||
|
id: 'project',
|
||||||
|
Component: React.lazy(() => import('@/components/Project')),
|
||||||
|
handle: {
|
||||||
|
auth: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '*',
|
path: '*',
|
||||||
element: <Navigate to="/" replace />
|
element: <Navigate to="/" replace />
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export default defineConfig({
|
|||||||
'react-router',
|
'react-router',
|
||||||
'react-router-dom',
|
'react-router-dom',
|
||||||
{
|
{
|
||||||
|
react: ['Suspense'],
|
||||||
'react-router': ['useMatches', 'RouterProvider'],
|
'react-router': ['useMatches', 'RouterProvider'],
|
||||||
'react-router-dom': ['createBrowserRouter'],
|
'react-router-dom': ['createBrowserRouter'],
|
||||||
antd: ['message']
|
antd: ['message']
|
||||||
@@ -34,6 +35,11 @@ export default defineConfig({
|
|||||||
from: 'react-router',
|
from: 'react-router',
|
||||||
imports: ['RouteObject'],
|
imports: ['RouteObject'],
|
||||||
type: true
|
type: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 'react',
|
||||||
|
imports: ['PropsWithChildren'],
|
||||||
|
type: true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user