Optimize submenu in ToolsFramework. Optimize code
This commit is contained in:
@@ -16,9 +16,9 @@ const AuthRoute = () => {
|
||||
if (matches.some(({ handle }) => (handle as RouteHandle)?.auth) && !isLogin) {
|
||||
return (
|
||||
<Navigate
|
||||
to={`/login${
|
||||
'?redirect=' + encodeURIComponent(lastMatch.pathname + location.search)
|
||||
}`}
|
||||
to={`/login?redirect=${encodeURIComponent(
|
||||
`${lastMatch.pathname}${location.search}`
|
||||
)}`}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -27,13 +27,13 @@ const AuthRoute = () => {
|
||||
}
|
||||
return outlet
|
||||
}, [
|
||||
handle?.auth,
|
||||
handle?.title,
|
||||
handle?.titlePostfix,
|
||||
handle?.titlePrefix,
|
||||
isLogin,
|
||||
lastMatch.pathname,
|
||||
location.search,
|
||||
matches,
|
||||
outlet
|
||||
])
|
||||
}
|
||||
|
||||
@@ -8,4 +8,9 @@ $font-secondary-color: #9E9E9E;
|
||||
$focus-color: #DDDDDD;
|
||||
$border-color: rgba(204, 204, 204, 0.33);
|
||||
$url-color: rgba(102, 102, 102, .8);
|
||||
$url-active-color: #ccc
|
||||
$url-active-color: #ccc;
|
||||
$SIZE_ICON_XS: 16px;
|
||||
$SIZE_ICON_SM: 20px;
|
||||
$SIZE_ICON_MD: 24px;
|
||||
$SIZE_ICON_LG: 32px;
|
||||
$SIZE_ICON_XL: 64px;
|
||||
@@ -1,5 +1,9 @@
|
||||
@use "@/assets/css/constants" as constants;
|
||||
|
||||
body {
|
||||
background-color: constants.$background-color;
|
||||
}
|
||||
|
||||
.left-panel {
|
||||
width: 16%;
|
||||
background-color: constants.$origin-color;
|
||||
@@ -17,7 +21,6 @@
|
||||
.content {
|
||||
> ul {
|
||||
> li {
|
||||
//background-color: #4E47BB;
|
||||
margin: 4px 14px;
|
||||
|
||||
&.item {
|
||||
@@ -25,28 +28,79 @@
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
|
||||
a.active {
|
||||
color: constants.$origin-color;
|
||||
background-color: constants.$main-color;
|
||||
.menu-bt {
|
||||
.icon {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
padding: 8px 16px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
.text {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: constants.$origin-color;
|
||||
background-color: constants.$main-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
a.pending {
|
||||
background-color: #123213;
|
||||
|
||||
&:hover {
|
||||
background-color: constants.$background-color;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
padding: 8px 16px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
&.multiple-item {
|
||||
font-size: 1.4em;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
|
||||
.icon {
|
||||
.menu-bt {
|
||||
display: flex;
|
||||
|
||||
.icon-box {
|
||||
cursor: pointer;
|
||||
padding: 8px 16px;
|
||||
|
||||
.icon {
|
||||
transition: all 0.3s ease;
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
padding: {
|
||||
top: 8px;
|
||||
bottom: 8px;
|
||||
right: 16px;
|
||||
};
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
.text {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.submenu {
|
||||
|
||||
}
|
||||
|
||||
.text {
|
||||
flex: 1;
|
||||
margin-left: 10px;
|
||||
&.show {
|
||||
.menu-bt {
|
||||
.icon-box {
|
||||
.icon {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,10 +114,6 @@
|
||||
};
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
&.item:hover {
|
||||
background-color: constants.$background-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ const FitCenter: React.FC<FitCenterProps> = (props) => {
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`fit-center${className ? ' ' + className : ''}${
|
||||
className={`fit-center${className ? ` ${className}` : ''}${
|
||||
vertical ? ' flex-vertical' : ' flex-horizontal'
|
||||
}`}
|
||||
{..._props}
|
||||
|
||||
@@ -12,7 +12,7 @@ const FitFullScreen = forwardRef<HTMLDivElement, FitFullscreenProps>((props, ref
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`fit-fullscreen${className ? ' ' + className : ''}`}
|
||||
className={`fit-fullscreen${className ? ` ${className}` : ''}`}
|
||||
style={{
|
||||
zIndex,
|
||||
backgroundColor,
|
||||
|
||||
@@ -24,7 +24,7 @@ const Indicator: React.FC<IndicatorProps> = (props) => {
|
||||
return (
|
||||
<li
|
||||
key={index}
|
||||
className={'item center-box' + (index === current ? ' active' : '')}
|
||||
className={`item center-box${index === current ? ' active' : ''}`}
|
||||
onClick={handleClick(index)}
|
||||
>
|
||||
<div className={'dot'} />
|
||||
|
||||
3
src/global.d.ts
vendored
3
src/global.d.ts
vendored
@@ -15,6 +15,9 @@ type ToolsJsonObject = {
|
||||
id: string
|
||||
component?: React.ComponentType
|
||||
name?: string
|
||||
titlePrefix?: string
|
||||
title?: string
|
||||
titlePostfix?: string
|
||||
icon?: IconComponent
|
||||
menu?: boolean
|
||||
auth?: boolean
|
||||
|
||||
@@ -84,7 +84,7 @@ const HomeFramework: React.FC = () => {
|
||||
>
|
||||
<div className={'body'}>
|
||||
<div>
|
||||
<header className={'nav' + (navbarHidden ? ' hide' : '')}>
|
||||
<header className={`nav${navbarHidden ? ' hide' : ''}`}>
|
||||
<a className={'logo'} href={'https://fatweb.top'}>
|
||||
<span className={'title'}>FatWeb</span>
|
||||
</a>
|
||||
@@ -115,11 +115,9 @@ const HomeFramework: React.FC = () => {
|
||||
key={subRoute.id}
|
||||
>
|
||||
<NavLink
|
||||
to={
|
||||
(route.path ?? '') +
|
||||
'/' +
|
||||
(subRoute.path ?? '')
|
||||
}
|
||||
to={`${route.path ?? ''}/${
|
||||
subRoute.path ?? ''
|
||||
}`}
|
||||
className={({
|
||||
isActive,
|
||||
isPending
|
||||
@@ -153,9 +151,9 @@ const HomeFramework: React.FC = () => {
|
||||
})}
|
||||
</ul>
|
||||
<div
|
||||
className={
|
||||
'dropdown-menu-button' + (showDropdownMenu ? ' active' : '')
|
||||
}
|
||||
className={`dropdown-menu-button${
|
||||
showDropdownMenu ? ' active' : ''
|
||||
}`}
|
||||
>
|
||||
<Icon
|
||||
component={IconFatwebMenu}
|
||||
@@ -165,9 +163,7 @@ const HomeFramework: React.FC = () => {
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<div
|
||||
className={'dropdown-menu-content' + (showDropdownMenu ? ' show' : '')}
|
||||
>
|
||||
<div className={`dropdown-menu-content${showDropdownMenu ? ' show' : ''}`}>
|
||||
<ul>
|
||||
{routeChildren?.map((route) => {
|
||||
return (
|
||||
|
||||
@@ -1,13 +1,38 @@
|
||||
import React from 'react'
|
||||
import FitFullScreen from '@/components/common/FitFullScreen'
|
||||
import '@/assets/css/pages/tools-framework.scss'
|
||||
import router from '@/router'
|
||||
import Icon from '@ant-design/icons'
|
||||
import { toolsJsonObjects } from '@/router/tools.tsx'
|
||||
import _ from 'lodash'
|
||||
|
||||
const ToolsFramework: React.FC = () => {
|
||||
const frameworkRoute = useMatches()[1]
|
||||
const routeId = frameworkRoute.id
|
||||
const routeChildren = router.routes[0].children?.find((value) => value.id === routeId)?.children
|
||||
const location = useLocation()
|
||||
|
||||
const [multipleMenuShown, setMultipleMenuShown] = useState(
|
||||
toolsJsonObjects.map((value) => ({
|
||||
id: value.id,
|
||||
path: value.path,
|
||||
shown: `${location.pathname}/`.startsWith(`/tools/${value.path}/`)
|
||||
}))
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const temp = _.clone(multipleMenuShown)
|
||||
temp.forEach((value) => {
|
||||
value.shown = `${location.pathname}/`.startsWith(`/tools/${value.path}/`)
|
||||
})
|
||||
setMultipleMenuShown(temp)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [location])
|
||||
|
||||
const switchSubmenu = (menuId: string) => {
|
||||
return () => {
|
||||
const temp = _.clone(multipleMenuShown)
|
||||
const menu = temp.find(({ id }) => id === menuId)
|
||||
menu && (menu.shown = !menu.shown)
|
||||
setMultipleMenuShown(temp)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -20,92 +45,93 @@ const ToolsFramework: React.FC = () => {
|
||||
<div style={{ marginTop: '0' }} className={'separate'} />
|
||||
</li>
|
||||
<li className={'item'}>
|
||||
<NavLink
|
||||
to={''}
|
||||
end
|
||||
className={({ isActive, isPending }) =>
|
||||
isPending ? 'pending' : isActive ? 'active' : ''
|
||||
}
|
||||
>
|
||||
{routeChildren ? (
|
||||
<>
|
||||
<Icon
|
||||
className={'icon'}
|
||||
component={
|
||||
(routeChildren[0].handle as RouteHandle).icon
|
||||
}
|
||||
/>
|
||||
<span className={'text'}>
|
||||
{(routeChildren[0].handle as RouteHandle).name}
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
'主页'
|
||||
)}
|
||||
</NavLink>
|
||||
<div className={'menu-bt'}>
|
||||
<NavLink
|
||||
to={''}
|
||||
end
|
||||
className={({ isActive, isPending }) =>
|
||||
isPending ? 'pending' : isActive ? 'active' : ''
|
||||
}
|
||||
>
|
||||
<Icon
|
||||
className={'icon'}
|
||||
component={toolsJsonObjects[0].icon}
|
||||
/>
|
||||
<span className={'text'}>{toolsJsonObjects[0].name}</span>
|
||||
</NavLink>
|
||||
</div>
|
||||
</li>
|
||||
<li className={'item'}>
|
||||
<NavLink
|
||||
to={'all'}
|
||||
className={({ isActive, isPending }) =>
|
||||
isPending ? ' pending' : isActive ? ' active' : ''
|
||||
}
|
||||
>
|
||||
{routeChildren ? (
|
||||
<>
|
||||
<Icon
|
||||
className={'icon'}
|
||||
component={
|
||||
(routeChildren[1].handle as RouteHandle).icon
|
||||
}
|
||||
/>
|
||||
<span className={'text'}>
|
||||
{(routeChildren[1].handle as RouteHandle).name}
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
'全部工具'
|
||||
)}
|
||||
</NavLink>
|
||||
<div className={'menu-bt'}>
|
||||
<NavLink
|
||||
to={'all'}
|
||||
className={({ isActive, isPending }) =>
|
||||
isPending ? ' pending' : isActive ? ' active' : ''
|
||||
}
|
||||
>
|
||||
<Icon
|
||||
className={'icon'}
|
||||
component={toolsJsonObjects[1].icon}
|
||||
/>
|
||||
<span className={'text'}>{toolsJsonObjects[1].name}</span>
|
||||
</NavLink>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div className={'separate'} />
|
||||
</li>
|
||||
{routeChildren?.map((route) => {
|
||||
return (route.handle as RouteHandle).menu &&
|
||||
route.id !== 'tools' &&
|
||||
route.id !== 'tools-all' ? (
|
||||
{toolsJsonObjects.map((tool) => {
|
||||
return tool.menu &&
|
||||
tool.id !== 'tools' &&
|
||||
tool.id !== 'tools-all' ? (
|
||||
<li
|
||||
className={route.children ? 'multiple-item' : 'item'}
|
||||
key={route.id}
|
||||
className={
|
||||
tool.children
|
||||
? `multiple-item${
|
||||
multipleMenuShown.find(
|
||||
({ id }) => id === tool.id
|
||||
)?.shown ?? false
|
||||
? ' show'
|
||||
: ''
|
||||
}`
|
||||
: 'item'
|
||||
}
|
||||
key={tool.id}
|
||||
>
|
||||
<NavLink
|
||||
to={route.path ?? ''}
|
||||
className={({ isActive, isPending }) =>
|
||||
isPending ? 'pending' : isActive ? 'active' : ''
|
||||
}
|
||||
>
|
||||
{(route.handle as RouteHandle).icon ? (
|
||||
<Icon
|
||||
className={'icon'}
|
||||
component={(route.handle as RouteHandle).icon}
|
||||
/>
|
||||
<div className={'menu-bt'}>
|
||||
{tool.children ? (
|
||||
<div
|
||||
className={'icon-box'}
|
||||
onClick={switchSubmenu(tool.id)}
|
||||
>
|
||||
<Icon
|
||||
className={'icon'}
|
||||
component={IconFatwebDown}
|
||||
/>
|
||||
</div>
|
||||
) : undefined}
|
||||
<span className={'text'}>
|
||||
{(route.handle as RouteHandle).name}
|
||||
</span>
|
||||
</NavLink>
|
||||
{route.children ? (
|
||||
<NavLink
|
||||
to={tool.path}
|
||||
className={({ isActive, isPending }) =>
|
||||
isPending ? 'pending' : isActive ? 'active' : ''
|
||||
}
|
||||
>
|
||||
{tool.children ? undefined : tool.icon ? (
|
||||
<Icon
|
||||
className={'icon'}
|
||||
component={tool.icon}
|
||||
/>
|
||||
) : undefined}
|
||||
<span className={'text'}>{tool.name}</span>
|
||||
</NavLink>
|
||||
</div>
|
||||
{tool.children ? (
|
||||
<ul className={'submenu'}>
|
||||
{route.children.map((subRoute) => {
|
||||
return (subRoute.handle as RouteHandle).menu ? (
|
||||
<li className={'item'} key={subRoute.id}>
|
||||
{tool.children.map((subTool) => {
|
||||
return subTool.menu ? (
|
||||
<li className={'item'} key={subTool.id}>
|
||||
<NavLink
|
||||
to={
|
||||
(route.path ?? '') +
|
||||
'/' +
|
||||
(subRoute.path ?? '')
|
||||
}
|
||||
to={`${tool.path}/${subTool.path}`}
|
||||
className={({
|
||||
isActive,
|
||||
isPending
|
||||
@@ -117,23 +143,14 @@ const ToolsFramework: React.FC = () => {
|
||||
: ''
|
||||
}
|
||||
>
|
||||
{(subRoute.handle as RouteHandle)
|
||||
.icon ? (
|
||||
{subTool.icon ? (
|
||||
<Icon
|
||||
className={'icon'}
|
||||
component={
|
||||
(
|
||||
subRoute.handle as RouteHandle
|
||||
).icon
|
||||
}
|
||||
component={subTool.icon}
|
||||
/>
|
||||
) : undefined}
|
||||
<span className={'text'}>
|
||||
{
|
||||
(
|
||||
subRoute.handle as RouteHandle
|
||||
).name
|
||||
}
|
||||
{subTool.name}
|
||||
</span>
|
||||
</NavLink>
|
||||
</li>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import React from 'react'
|
||||
|
||||
const toolsJsonObjects: ToolsJsonObject[] = [
|
||||
const defaultTitle = '氮工具'
|
||||
|
||||
export const toolsJsonObjects: ToolsJsonObject[] = [
|
||||
{
|
||||
path: '',
|
||||
id: 'tools',
|
||||
@@ -15,6 +17,7 @@ const toolsJsonObjects: ToolsJsonObject[] = [
|
||||
id: 'tools-all',
|
||||
component: React.lazy(() => import('@/pages/tools')),
|
||||
name: '全部工具',
|
||||
titlePostfix: ' - 全部工具',
|
||||
icon: React.lazy(() => import('~icons/fatweb/logo.jsx')),
|
||||
menu: true,
|
||||
auth: false
|
||||
@@ -86,6 +89,9 @@ const tools: RouteObject[] = toolsJsonObjects.map((value) => ({
|
||||
Component: value.component,
|
||||
handle: {
|
||||
name: value.name,
|
||||
titlePrefix: value.titlePrefix,
|
||||
title: value.title ?? defaultTitle,
|
||||
titlePostfix: value.titlePostfix,
|
||||
icon: value.icon,
|
||||
menu: value.menu,
|
||||
auth: value.auth
|
||||
@@ -96,6 +102,9 @@ const tools: RouteObject[] = toolsJsonObjects.map((value) => ({
|
||||
Component: value.component,
|
||||
handle: {
|
||||
name: value.name,
|
||||
titlePrefix: value.titlePrefix,
|
||||
title: value.title ?? defaultTitle,
|
||||
titlePostfix: value.titlePostfix,
|
||||
icon: value.icon,
|
||||
menu: value.menu,
|
||||
auth: value.auth
|
||||
|
||||
@@ -18,14 +18,14 @@ export function setCookie(
|
||||
daysToLive: number | null,
|
||||
path: string | null
|
||||
): void {
|
||||
let cookie = name + '=' + encodeURIComponent(value)
|
||||
let cookie = `${name}=${encodeURIComponent(value)}`
|
||||
|
||||
if (typeof daysToLive === 'number') {
|
||||
cookie = `${cookie}; max-age=${daysToLive * 24 * 60 * 60}`
|
||||
}
|
||||
|
||||
if (typeof path === 'string') {
|
||||
cookie += '; path=' + path
|
||||
cookie = `${cookie}; path=${path}`
|
||||
}
|
||||
|
||||
document.cookie = cookie
|
||||
@@ -61,7 +61,7 @@ export function getToken(): string | null {
|
||||
}
|
||||
|
||||
export function removeCookie(name: string): void {
|
||||
document.cookie = name + '=; max-age=0'
|
||||
document.cookie = `${name}=; max-age=0`
|
||||
}
|
||||
|
||||
export function removeLocalStorage(name: string): void {
|
||||
|
||||
Reference in New Issue
Block a user