Merge pull request 'Add MainFramework and loading mask. Add animation to menu.' (#7) from FatttSnake into dev
Reviewed-on: FatttSnake/fatweb-ui#7
This commit was merged in pull request #7.
This commit is contained in:
@@ -24,11 +24,10 @@ module.exports = {
|
||||
rules: {
|
||||
'no-cond-assign': 'error',
|
||||
'eqeqeq': 'error',
|
||||
'indent': ['error', 4, { 'SwitchCase': 1 }],
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
endOfLine: 'auto'
|
||||
endOfLine: 'auto',
|
||||
}
|
||||
],
|
||||
'react-refresh/only-export-components': [
|
||||
|
||||
8
package-lock.json
generated
8
package-lock.json
generated
@@ -24,7 +24,7 @@
|
||||
"@svgr/core": "^8.1.0",
|
||||
"@svgr/plugin-jsx": "^8.1.0",
|
||||
"@types/jsdom": "^21.1.2",
|
||||
"@types/lodash": "^4.14.197",
|
||||
"@types/lodash": "^4.14.198",
|
||||
"@types/node": "^20.5.9",
|
||||
"@types/react": "^18.2.21",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
@@ -1519,9 +1519,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.14.197",
|
||||
"resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.197.tgz",
|
||||
"integrity": "sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g==",
|
||||
"version": "4.14.198",
|
||||
"resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.198.tgz",
|
||||
"integrity": "sha512-trNJ/vtMZYMLhfN45uLq4ShQSw0/S7xCTLLVM+WM1rmFpba/VS42jVUgaO3w/NOLiWR/09lnYk0yMaA/atdIsg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/minimist": {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"dev-host": "vite --host 0.0.0.0",
|
||||
"build": "vite build && tsc && vite build",
|
||||
"build": "vite build",
|
||||
"clean": "rimraf dist .eslintrc-auto-import.json auto-imports.d.ts",
|
||||
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"format": "prettier --write src/",
|
||||
@@ -29,7 +29,7 @@
|
||||
"@svgr/core": "^8.1.0",
|
||||
"@svgr/plugin-jsx": "^8.1.0",
|
||||
"@types/jsdom": "^21.1.2",
|
||||
"@types/lodash": "^4.14.197",
|
||||
"@types/lodash": "^4.14.198",
|
||||
"@types/node": "^20.5.9",
|
||||
"@types/react": "^18.2.21",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import React from 'react'
|
||||
import router from '@/router'
|
||||
import LoadingMask from '@/components/LoadingMask.tsx'
|
||||
|
||||
const App: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<Suspense fallback={<LoadingMask />}>
|
||||
<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 {
|
||||
color: $font-main-color;
|
||||
user-select: none;
|
||||
min-width: 1800px;
|
||||
min-width: 900px;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
@@ -103,3 +103,19 @@ $font-secondary-color: #9E9E9E;
|
||||
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 {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
@@ -13,6 +15,16 @@
|
||||
color: rgba(204, 204, 204, .33);
|
||||
}
|
||||
}
|
||||
animation: .5s ease both;
|
||||
|
||||
@include mixins.unique-keyframes {
|
||||
0% {
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
padding: 0 40px;
|
||||
@@ -22,4 +34,60 @@
|
||||
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
|
||||
24
src/components/Home.tsx
Normal file
24
src/components/Home.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import React from 'react'
|
||||
import '@/assets/css/home.scss'
|
||||
import { MainFrameworkContext } from '@/pages/MainFramework'
|
||||
|
||||
const Home: React.FC = () => {
|
||||
const {
|
||||
navbarHiddenState: { navbarHidden, setNavbarHidden }
|
||||
} = useContext(MainFrameworkContext)
|
||||
const handleButtonClick = () => {
|
||||
setNavbarHidden(!navbarHidden)
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<h1>Home</h1>
|
||||
<div style={{ marginTop: '100px' }}>
|
||||
<AntdButton onClick={handleButtonClick}>
|
||||
{navbarHidden ? '显示' : '隐藏'}
|
||||
</AntdButton>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
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
|
||||
81
src/pages/MainFramework.tsx
Normal file
81
src/pages/MainFramework.tsx
Normal file
@@ -0,0 +1,81 @@
|
||||
import React, { createContext } from 'react'
|
||||
import '@/assets/css/header.scss'
|
||||
import LoadingMask from '@/components/LoadingMask.tsx'
|
||||
|
||||
export const MainFrameworkContext = createContext<{
|
||||
navbarHiddenState: {
|
||||
navbarHidden: boolean
|
||||
setNavbarHidden: (newValue: boolean) => void
|
||||
}
|
||||
}>({
|
||||
navbarHiddenState: {
|
||||
navbarHidden: false,
|
||||
setNavbarHidden: () => undefined
|
||||
}
|
||||
})
|
||||
|
||||
const MainFramework: React.FC = () => {
|
||||
const [navbarHidden, setNavbarHidden] = useState(false)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={'body'}>
|
||||
<header className={'nav ' + (navbarHidden ? '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={{ navbarHiddenState: { navbarHidden, setNavbarHidden } }}
|
||||
>
|
||||
<Suspense
|
||||
fallback={
|
||||
<>
|
||||
<LoadingMask />
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Outlet />
|
||||
</Suspense>
|
||||
</MainFrameworkContext.Provider>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default MainFramework
|
||||
@@ -10,14 +10,34 @@ const routes: RouteObject[] = [
|
||||
id: '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: '',
|
||||
id: 'home',
|
||||
Component: React.lazy(() => import('@/pages/Home')),
|
||||
Component: React.lazy(() => import('@/components/Home')),
|
||||
handle: {
|
||||
auth: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'project',
|
||||
id: 'project',
|
||||
Component: React.lazy(() => import('@/components/Project')),
|
||||
handle: {
|
||||
auth: false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
element: <Navigate to="/" replace />
|
||||
|
||||
@@ -26,6 +26,7 @@ export default defineConfig({
|
||||
'react-router',
|
||||
'react-router-dom',
|
||||
{
|
||||
react: ['Suspense'],
|
||||
'react-router': ['useMatches', 'RouterProvider'],
|
||||
'react-router-dom': ['createBrowserRouter'],
|
||||
antd: ['message']
|
||||
@@ -34,6 +35,11 @@ export default defineConfig({
|
||||
from: 'react-router',
|
||||
imports: ['RouteObject'],
|
||||
type: true
|
||||
},
|
||||
{
|
||||
from: 'react',
|
||||
imports: ['PropsWithChildren'],
|
||||
type: true
|
||||
}
|
||||
],
|
||||
|
||||
|
||||
Reference in New Issue
Block a user