Merge pull request 'Add dynamic menu. Add slogan to home page' (#8) from FatttSnake into dev
Reviewed-on: FatttSnake/fatweb-ui#8
This commit was merged in pull request #8.
This commit is contained in:
@@ -116,6 +116,15 @@ $font-secondary-color: #9E9E9E;
|
|||||||
}
|
}
|
||||||
|
|
||||||
#fit-fullscreen {
|
#fit-fullscreen {
|
||||||
width: 100vw;
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#fit-center {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
@@ -86,7 +86,6 @@
|
|||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
}
|
}
|
||||||
100% {
|
100% {
|
||||||
display: none;
|
|
||||||
transform: translateY(-100%);
|
transform: translateY(-100%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
@use "mixins" as mixins;
|
||||||
|
|
||||||
|
.center-box {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.big-logo {
|
||||||
|
font: {
|
||||||
|
size: 5em;
|
||||||
|
weight: bold;
|
||||||
|
};
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slogan {
|
||||||
|
font: {
|
||||||
|
size: 1.3em;
|
||||||
|
style: italic;
|
||||||
|
};
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-to-down {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 20px;
|
||||||
|
animation: 1.5s infinite;
|
||||||
|
@include mixins.unique-keyframes {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
-ms-filter: none;
|
||||||
|
filter: none;
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-ms-filter: alpha(opacity=40);
|
||||||
|
filter: alpha(opacity=40);
|
||||||
|
opacity: .4;
|
||||||
|
transform: translateY(-10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/assets/svg/down.svg
Normal file
1
src/assets/svg/down.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="M958.577476 311.180252c0 15.286148-5.878894 29.522384-16.564257 40.166815L551.623951 741.043556c-1.39272 1.425466-2.577708 2.537799-3.846608 3.449565l-2.905166 2.304486c-11.416004 11.362792-24.848944 16.945951-39.068807 16.945951-14.475689 0-28.010961-5.708002-38.110993-16.056698L79.475588 355.310332c-10.467399-10.613732-16.236799-24.786523-16.236799-39.893592 0-14.772448 5.599532-28.726252 15.753799-39.286772 10.18599-10.497075 24.390503-16.539698 38.95215-16.539698 14.382569 0 28.009937 5.723352 38.366819 16.142655l350.169241 353.968777 359.428116-358.485651c10.30981-10.248412 23.781636-15.909341 37.994336-15.909341 14.889105 0 28.859281 6.05081 39.333844 16.999163C953.126324 282.725176 958.577476 296.556183 958.577476 311.180252z" /></svg>
|
||||||
|
After Width: | Height: | Size: 862 B |
11
src/components/FitCenter.tsx
Normal file
11
src/components/FitCenter.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const FitCenter: React.FC<PropsWithChildren> = (props: PropsWithChildren) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div id={'fit-center'}>{props.children}</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FitCenter
|
||||||
@@ -1,9 +1,17 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
const FitFullScreen: React.FC<PropsWithChildren> = (props: PropsWithChildren) => {
|
const FitFullScreen: React.FC<FitFullscreenProps> = (props: FitFullscreenProps) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div id={'fit-fullscreen'}>{props.children}</div>
|
<div
|
||||||
|
id={'fit-fullscreen'}
|
||||||
|
style={{
|
||||||
|
zIndex: props.zIndex,
|
||||||
|
backgroundColor: props.backgroundColor
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,49 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import '@/assets/css/home.scss'
|
import '@/assets/css/home.scss'
|
||||||
import { MainFrameworkContext } from '@/pages/MainFramework'
|
import FitFullScreen from '@/components/FitFullScreen.tsx'
|
||||||
|
import FitCenter from '@/components/FitCenter.tsx'
|
||||||
|
import Icon from '@ant-design/icons'
|
||||||
|
|
||||||
const Home: React.FC = () => {
|
const Home: React.FC = () => {
|
||||||
const {
|
const [slogan, setSlogan] = useState('')
|
||||||
navbarHiddenState: { navbarHidden, setNavbarHidden }
|
const [sloganType, setSloganType] = useState(true)
|
||||||
} = useContext(MainFrameworkContext)
|
const typeText = '/* 因为热爱 所以折腾 */'
|
||||||
const handleButtonClick = () => {
|
if (sloganType) {
|
||||||
setNavbarHidden(!navbarHidden)
|
setTimeout(() => {
|
||||||
|
if (slogan.length < typeText.length) {
|
||||||
|
setSlogan(typeText.substring(0, slogan.length + 1))
|
||||||
|
} else {
|
||||||
|
setSloganType(false)
|
||||||
}
|
}
|
||||||
|
}, 150)
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (slogan.length > 0) {
|
||||||
|
setSlogan(typeText.substring(0, slogan.length - 1))
|
||||||
|
} else {
|
||||||
|
setSloganType(true)
|
||||||
|
}
|
||||||
|
}, 50)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1>Home</h1>
|
<FitFullScreen zIndex={100} backgroundColor={'#FBFBFB'}>
|
||||||
<div style={{ marginTop: '100px' }}>
|
<FitCenter>
|
||||||
<AntdButton onClick={handleButtonClick}>
|
<div className={'center-box'}>
|
||||||
{navbarHidden ? '显示' : '隐藏'}
|
<div className={'big-logo'}>FatWeb</div>
|
||||||
</AntdButton>
|
<span id={'slogan'} className={'slogan'}>
|
||||||
|
{slogan || <> </>}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div className={'scroll-to-down'}>
|
||||||
|
<Icon
|
||||||
|
component={IconFatwebDown}
|
||||||
|
style={{ fontSize: '1.8em', color: '#666' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</FitCenter>
|
||||||
|
</FitFullScreen>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const LoadingMask: React.FC = () => {
|
|||||||
const loadingIcon = (
|
const loadingIcon = (
|
||||||
<>
|
<>
|
||||||
<Icon
|
<Icon
|
||||||
component={IconFatwebLoading as React.ComponentType}
|
component={IconFatwebLoading}
|
||||||
style={{ fontSize: 24, color: COLOR_FONT_MAIN }}
|
style={{ fontSize: 24, color: COLOR_FONT_MAIN }}
|
||||||
spin
|
spin
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { createContext } from 'react'
|
import React, { createContext } from 'react'
|
||||||
import '@/assets/css/header.scss'
|
import '@/assets/css/header.scss'
|
||||||
import LoadingMask from '@/components/LoadingMask.tsx'
|
import LoadingMask from '@/components/LoadingMask.tsx'
|
||||||
|
import router from '@/router'
|
||||||
|
|
||||||
export const MainFrameworkContext = createContext<{
|
export const MainFrameworkContext = createContext<{
|
||||||
navbarHiddenState: {
|
navbarHiddenState: {
|
||||||
@@ -16,6 +17,8 @@ export const MainFrameworkContext = createContext<{
|
|||||||
|
|
||||||
const MainFramework: React.FC = () => {
|
const MainFramework: React.FC = () => {
|
||||||
const [navbarHidden, setNavbarHidden] = useState(false)
|
const [navbarHidden, setNavbarHidden] = useState(false)
|
||||||
|
const routeId = useMatches()[1].id
|
||||||
|
const routeChildren = router.routes[0].children?.find((value) => value.id === routeId)?.children
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -26,36 +29,20 @@ const MainFramework: React.FC = () => {
|
|||||||
</a>
|
</a>
|
||||||
<nav>
|
<nav>
|
||||||
<ul className={'menu'}>
|
<ul className={'menu'}>
|
||||||
|
{routeChildren?.map((route) => {
|
||||||
|
return (
|
||||||
<li className={'item'}>
|
<li className={'item'}>
|
||||||
<NavLink
|
<NavLink
|
||||||
to={''}
|
to={route.path ?? ''}
|
||||||
className={({ isActive, isPending }) =>
|
className={({ isActive, isPending }) =>
|
||||||
isPending ? 'pending' : isActive ? 'active' : ''
|
isPending ? 'pending' : isActive ? 'active' : ''
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
主页
|
{(route.handle as RouteHandle).name}
|
||||||
</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>
|
</NavLink>
|
||||||
</li>
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -25,6 +25,17 @@ const routes: RouteObject[] = [
|
|||||||
id: 'home',
|
id: 'home',
|
||||||
Component: React.lazy(() => import('@/components/Home')),
|
Component: React.lazy(() => import('@/components/Home')),
|
||||||
handle: {
|
handle: {
|
||||||
|
name: '主页',
|
||||||
|
menu: true,
|
||||||
|
auth: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'https://blog.fatweb.top',
|
||||||
|
id: 'blog',
|
||||||
|
handle: {
|
||||||
|
name: '博客',
|
||||||
|
menu: true,
|
||||||
auth: false
|
auth: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -33,6 +44,8 @@ const routes: RouteObject[] = [
|
|||||||
id: 'project',
|
id: 'project',
|
||||||
Component: React.lazy(() => import('@/components/Project')),
|
Component: React.lazy(() => import('@/components/Project')),
|
||||||
handle: {
|
handle: {
|
||||||
|
name: '项目',
|
||||||
|
menu: true,
|
||||||
auth: false
|
auth: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
17
src/vite-env.d.ts
vendored
17
src/vite-env.d.ts
vendored
@@ -1,12 +1,14 @@
|
|||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
type Captcha = {
|
type RouteHandle = {
|
||||||
value: string
|
name?: string
|
||||||
base64Src: string
|
menu?: boolean
|
||||||
|
auth?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type RouteHandle = {
|
interface FitFullscreenProps extends PropsWithChildren {
|
||||||
auth: boolean
|
zIndex?: number
|
||||||
|
backgroundColor?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type _Response<T> = {
|
type _Response<T> = {
|
||||||
@@ -15,6 +17,11 @@ type _Response<T> = {
|
|||||||
data: T | null
|
data: T | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Captcha = {
|
||||||
|
value: string
|
||||||
|
base64Src: string
|
||||||
|
}
|
||||||
|
|
||||||
type Token = {
|
type Token = {
|
||||||
token: string
|
token: string
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user