增加组件
This commit is contained in:
parent
2cd8e574d8
commit
b969560ee6
177
package-lock.json
generated
177
package-lock.json
generated
@ -8,9 +8,16 @@
|
||||
"name": "ai-copyright",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@fortawesome/free-regular-svg-icons": "^6.5.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.1",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"antd": "^5.15.2",
|
||||
"localforage": "^1.10.0",
|
||||
"match-sorter": "^6.3.4",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"sort-by": "^1.2.0",
|
||||
"stylus": "^0.63.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -953,6 +960,64 @@
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/fontawesome-common-types": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz",
|
||||
"integrity": "sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A==",
|
||||
"hasInstallScript": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/fontawesome-svg-core": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz",
|
||||
"integrity": "sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ==",
|
||||
"hasInstallScript": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/free-regular-svg-icons": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.5.1.tgz",
|
||||
"integrity": "sha512-m6ShXn+wvqEU69wSP84coxLbNl7sGVZb+Ca+XZq6k30SzuP3X4TfPqtycgUh9ASwlNh5OfQCd8pDIWxl+O+LlQ==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/free-solid-svg-icons": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.1.tgz",
|
||||
"integrity": "sha512-S1PPfU3mIJa59biTtXJz1oI0+KAXW6bkAb31XKhxdxtuXDiUIFsih4JR1v5BbxY7hVHsD1RKq+jRkVRaf773NQ==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/react-fontawesome": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz",
|
||||
"integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==",
|
||||
"dependencies": {
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "~1 || ~6",
|
||||
"react": ">=16.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.11.14",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
||||
@ -1203,6 +1268,14 @@
|
||||
"react-dom": ">=16.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.15.3",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.3.tgz",
|
||||
"integrity": "sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.1.tgz",
|
||||
@ -2630,6 +2703,11 @@
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/immediate": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
@ -2803,6 +2881,22 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lie": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
|
||||
"integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==",
|
||||
"dependencies": {
|
||||
"immediate": "~3.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/localforage": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
|
||||
"integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==",
|
||||
"dependencies": {
|
||||
"lie": "3.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/locate-path": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
@ -2844,6 +2938,15 @@
|
||||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/match-sorter": {
|
||||
"version": "6.3.4",
|
||||
"resolved": "https://registry.npmjs.org/match-sorter/-/match-sorter-6.3.4.tgz",
|
||||
"integrity": "sha512-jfZW7cWS5y/1xswZo8VBOdudUiSd9nifYRWphc9M5D/ee4w4AoXLgBEdRbgVaxbMuagBPeUC5y2Hi8DO6o9aDg==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.23.8",
|
||||
"remove-accents": "0.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
@ -2916,6 +3019,22 @@
|
||||
"integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-path": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/object-path/-/object-path-0.6.0.tgz",
|
||||
"integrity": "sha512-fxrwsCFi3/p+LeLOAwo/wyRMODZxdGBtUlWRzsEpsUVrisZbEfZ21arxLGfaWfcnqb8oHPNihIb4XPE8CQPN5A==",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
@ -3073,6 +3192,21 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types": {
|
||||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types/node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
@ -3719,11 +3853,46 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "6.22.3",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz",
|
||||
"integrity": "sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.15.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "6.22.3",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.3.tgz",
|
||||
"integrity": "sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.15.3",
|
||||
"react-router": "6.22.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8",
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
|
||||
},
|
||||
"node_modules/remove-accents": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz",
|
||||
"integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A=="
|
||||
},
|
||||
"node_modules/resize-observer-polyfill": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
|
||||
@ -3902,6 +4071,14 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/sort-by": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/sort-by/-/sort-by-1.2.0.tgz",
|
||||
"integrity": "sha512-aRyW65r3xMnf4nxJRluCg0H/woJpksU1dQxRtXYzau30sNBOmf5HACpDd9MZDhKh7ALQ5FgSOfMPwZEtUmMqcg==",
|
||||
"dependencies": {
|
||||
"object-path": "0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
|
||||
|
@ -10,9 +10,16 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/free-regular-svg-icons": "^6.5.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.1",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"antd": "^5.15.2",
|
||||
"localforage": "^1.10.0",
|
||||
"match-sorter": "^6.3.4",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"sort-by": "^1.2.0",
|
||||
"stylus": "^0.63.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1,12 +1,17 @@
|
||||
import React from 'react';
|
||||
import Head from './layout/head/Head.tsx';
|
||||
import Nav from "./layout/nav/Nav.tsx";
|
||||
import Body from './layout/body/Body.tsx';
|
||||
import Foot from './layout/foot/Foot.tsx';
|
||||
|
||||
|
||||
const App: React.FC = () => {
|
||||
return (
|
||||
<div>
|
||||
<Head />
|
||||
<Foot />
|
||||
<Head/>
|
||||
<Nav/>
|
||||
<Body/>
|
||||
<Foot/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
78
src/components/menu/MenuTree.tsx
Normal file
78
src/components/menu/MenuTree.tsx
Normal file
@ -0,0 +1,78 @@
|
||||
import './menu-tree.css';
|
||||
import {useState} from "react";
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'
|
||||
import {faCaretRight, faCaretDown, faEdit, faPlus, faRemove} from '@fortawesome/free-solid-svg-icons';
|
||||
import {IMenuTree, IMenuTreeItem} from "../../interfaces/menu/IMenuTree.ts";
|
||||
|
||||
|
||||
export default function MenuTree(props: IMenuTree) {
|
||||
|
||||
const [menusArray, setMenuArray] = useState([
|
||||
{
|
||||
id: '1',
|
||||
name: '一级目录',
|
||||
active: true,
|
||||
level: 1,
|
||||
children: [
|
||||
{
|
||||
id: '1-1',
|
||||
name: '二级目录',
|
||||
active: false,
|
||||
level: 1,
|
||||
children: [
|
||||
{
|
||||
id: '1-1-1',
|
||||
name: '三级目录',
|
||||
active: false,
|
||||
level: 1,
|
||||
children: []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
const triggerChildren = (item: IMenuTreeItem) => {
|
||||
item.active = !item.active;
|
||||
setMenuArray([
|
||||
...menusArray
|
||||
]);
|
||||
}
|
||||
|
||||
const renderMenu = (children: Array<IMenuTreeItem>, parent?: IMenuTreeItem) => {
|
||||
if (!children || children.length == 0) {
|
||||
return <></>
|
||||
}
|
||||
const lis = children.map((item, index) => {
|
||||
const isParent = item.children && item.children.length > 0;
|
||||
const icon = item.active ? faCaretDown : faCaretRight;
|
||||
const renderChildrenMenu = renderMenu(item.children, item);
|
||||
return (
|
||||
<li key={item.id}>
|
||||
<div className="menu-title">
|
||||
<div className="label">
|
||||
{isParent ? <FontAwesomeIcon className="icon" icon={icon} onClick={() => {
|
||||
triggerChildren(item)
|
||||
}}/> : <></>}
|
||||
<span onDoubleClick={() => {
|
||||
triggerChildren(item)
|
||||
}}>{item.name}</span>
|
||||
</div>
|
||||
<div className="icon-group">
|
||||
<FontAwesomeIcon className="icon" icon={faEdit}/>
|
||||
<FontAwesomeIcon className="icon" icon={faPlus}/>
|
||||
<FontAwesomeIcon className="icon" icon={faRemove}/>
|
||||
</div>
|
||||
</div>
|
||||
{renderChildrenMenu}
|
||||
</li>
|
||||
)
|
||||
})
|
||||
const active = parent ? parent.active : true;
|
||||
return <ul style={{display: active ? 'block' : 'none'}}>{lis}</ul>
|
||||
}
|
||||
|
||||
const menuUl = renderMenu(menusArray);
|
||||
return <div className="menu-tree">{menuUl}</div>
|
||||
}
|
26
src/components/menu/MenuWithTopButton.tsx
Normal file
26
src/components/menu/MenuWithTopButton.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import './menu-with-top-button.css'
|
||||
import {IMenuWithTopButton} from "../../interfaces/menu/IMenuWithTopButton.ts";
|
||||
|
||||
export default function MenuWithTopButton(props: IMenuWithTopButton) {
|
||||
const list = props.list.map((item, index) => (
|
||||
<li key={item.id} onClick={(e) => {
|
||||
props.handleListItem(e, index, item);
|
||||
}}>
|
||||
<img src={item.icon} className="menu-icon" alt="加载失败"/>
|
||||
<span className="menu-name">{item.name}</span>
|
||||
</li>
|
||||
));
|
||||
|
||||
return (
|
||||
<div className="menu-with-top-button">
|
||||
<button className="btn btn-blue top-button"
|
||||
onClick={(e) => {
|
||||
props.button.handle(e);
|
||||
}}
|
||||
>
|
||||
{props.button.name}
|
||||
</button>
|
||||
<ul>{list}</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
27
src/components/menu/menu-tree.css
Normal file
27
src/components/menu/menu-tree.css
Normal file
@ -0,0 +1,27 @@
|
||||
.menu-tree {
|
||||
padding: 0 15px;
|
||||
}
|
||||
.menu-tree ul {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.menu-tree ul li {}
|
||||
.menu-tree ul li .menu-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.menu-tree ul li .menu-title .label {
|
||||
cursor: pointer;
|
||||
}
|
||||
.menu-tree ul li .menu-title .label span {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.menu-tree ul li .menu-title .icon-group {
|
||||
width: 50px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.menu-tree ul li .menu-title .icon-group .icon {
|
||||
cursor: pointer;
|
||||
}
|
36
src/components/menu/menu-with-top-button.css
Normal file
36
src/components/menu/menu-with-top-button.css
Normal file
@ -0,0 +1,36 @@
|
||||
.menu-with-top-button {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.menu-with-top-button .top-button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.menu-with-top-button ul {
|
||||
padding: 10px;
|
||||
background-color: yellow;
|
||||
}
|
||||
|
||||
.menu-with-top-button ul li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.menu-with-top-button ul li:hover {
|
||||
background-color: var(--color-hover);
|
||||
}
|
||||
|
||||
.menu-with-top-button ul li:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.menu-with-top-button ul li .menu-icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.menu-with-top-button ul li .menu-name {
|
||||
padding-left: 5px;
|
||||
}
|
@ -8,7 +8,11 @@
|
||||
--color-purple: #a233c6;
|
||||
--color-dark: #2f363c;
|
||||
--color-light: #fafafa;
|
||||
--color-hover: #eeeeee;
|
||||
--font-size-head: 16px;
|
||||
--width-workspace: 1280px;
|
||||
--height-head: 60px;
|
||||
--height-foot: 30px;
|
||||
}
|
||||
|
||||
html, body {
|
||||
@ -16,3 +20,55 @@ html, body {
|
||||
padding: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.btn {
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.btn-red {
|
||||
background-color: var(--color-red);
|
||||
color: var(--color-light);
|
||||
}
|
||||
|
||||
.btn-orange {
|
||||
background-color: var(--color-orange);
|
||||
color: var(--color-light);
|
||||
}
|
||||
|
||||
.btn-green {
|
||||
background-color: var(--color-green);
|
||||
color: var(--color-light);
|
||||
}
|
||||
|
||||
.btn-blue {
|
||||
background-color: var(--color-blue);
|
||||
color: var(--color-light);
|
||||
}
|
||||
|
||||
.btn-purple {
|
||||
background-color: var(--color-purple);
|
||||
color: var(--color-light);
|
||||
}
|
||||
|
||||
.btn-dark {
|
||||
background-color: var(--color-dark);
|
||||
color: var(--color-light);
|
||||
}
|
||||
|
||||
.btn-light {
|
||||
background-color: var(--color-light);
|
||||
color: var(--color-dark);
|
||||
}
|
15
src/interfaces/menu/IMenuTree.ts
Normal file
15
src/interfaces/menu/IMenuTree.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import {MouseEvent} from 'react';
|
||||
|
||||
export interface IMenuTreeItem {
|
||||
id: string;
|
||||
name: string;
|
||||
active: boolean;
|
||||
level: number;
|
||||
children: Array<IMenuTreeItem>;
|
||||
}
|
||||
|
||||
export interface IMenuTree {
|
||||
menus: Array<IMenuTreeItem>;
|
||||
|
||||
handleClick(e: MouseEvent<HTMLSpanElement>, item: IMenuTreeItem): void;
|
||||
}
|
22
src/interfaces/menu/IMenuWithTopButton.ts
Normal file
22
src/interfaces/menu/IMenuWithTopButton.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import {MouseEvent} from "react";
|
||||
|
||||
export interface IMenuListItem {
|
||||
id: string;
|
||||
icon: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface IMenuButton {
|
||||
name: string;
|
||||
|
||||
handle(e: MouseEvent<HTMLButtonElement>): void;
|
||||
}
|
||||
|
||||
export interface IMenuWithTopButton {
|
||||
|
||||
button: IMenuButton;
|
||||
list: Array<IMenuListItem>;
|
||||
|
||||
handleListItem(e: MouseEvent<HTMLLIElement>, index: number, item: IMenuListItem): void;
|
||||
|
||||
}
|
19
src/layout/body/Body.tsx
Normal file
19
src/layout/body/Body.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import './body.css'
|
||||
import {createBrowserRouter, RouterProvider} from 'react-router-dom';
|
||||
import Index from '../../route/index';
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: '/',
|
||||
element: <Index />
|
||||
}
|
||||
])
|
||||
|
||||
export default function Body() {
|
||||
const winHeight: number = window.innerHeight
|
||||
return (
|
||||
<div className="body" style={{height: `${winHeight - 145}px`}}>
|
||||
<RouterProvider router={router}/>
|
||||
</div>
|
||||
)
|
||||
}
|
5
src/layout/body/body.css
Normal file
5
src/layout/body/body.css
Normal file
@ -0,0 +1,5 @@
|
||||
.body {
|
||||
margin: 0 auto 10px auto;
|
||||
background-color: red;
|
||||
width: var(--width-workspace);
|
||||
}
|
@ -2,6 +2,6 @@ import './foot.css';
|
||||
|
||||
export default function Foot() {
|
||||
return (
|
||||
<div className="foot">footer</div>
|
||||
<div className="foot"></div>
|
||||
)
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
height: var(--height-foot);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
@ -1,6 +1,6 @@
|
||||
.head {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
height: var(--height-head);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
.head .center {
|
||||
margin: 0 auto;
|
||||
max-width: 1280px;
|
||||
width: var(--width-workspace);
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
19
src/layout/nav/Nav.tsx
Normal file
19
src/layout/nav/Nav.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import './nav.css';
|
||||
|
||||
export default function Nav() {
|
||||
return (
|
||||
<div className="nav">
|
||||
<ul>
|
||||
<li>
|
||||
<span>首页</span>
|
||||
</li>
|
||||
<li>
|
||||
<span>首页</span>
|
||||
</li>
|
||||
<li>
|
||||
<span>首页</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
22
src/layout/nav/nav.css
Normal file
22
src/layout/nav/nav.css
Normal file
@ -0,0 +1,22 @@
|
||||
.nav {
|
||||
width: var(--width-workspace);
|
||||
margin: calc(var(--height-head) + 15px) auto 10px auto;
|
||||
}
|
||||
|
||||
.nav ul {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav ul li {
|
||||
|
||||
}
|
||||
|
||||
.nav li::after {
|
||||
content: ' > ';
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.nav li:last-child::after {
|
||||
content: ''
|
||||
}
|
18
src/route/index/index.css
Normal file
18
src/route/index/index.css
Normal file
@ -0,0 +1,18 @@
|
||||
.index {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.index .left {
|
||||
position: absolute;
|
||||
width: 220px;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.index .right {
|
||||
margin-left: 235px;
|
||||
height: 100%;
|
||||
background-color: green;
|
||||
}
|
64
src/route/index/index.tsx
Normal file
64
src/route/index/index.tsx
Normal file
@ -0,0 +1,64 @@
|
||||
import './index.css';
|
||||
import {MouseEvent} from "react";
|
||||
import {IMenuListItem, IMenuWithTopButton} from "../../interfaces/menu/IMenuWithTopButton.ts";
|
||||
import MenuWithTopButton from "../../components/menu/MenuWithTopButton.tsx";
|
||||
import MenuTree from "../../components/menu/MenuTree.tsx";
|
||||
|
||||
const projMenu: IMenuWithTopButton = {
|
||||
button: {
|
||||
name: '创建项目',
|
||||
handle(e: MouseEvent<HTMLButtonElement>) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
list: [
|
||||
{id: 'proj1', icon: './vite.svg', name: '全部项目'},
|
||||
{id: 'proj2', icon: './vite.svg', name: '进行中的'},
|
||||
{id: 'proj3', icon: './vite.svg', name: '已完成的'}
|
||||
],
|
||||
handleListItem(e: MouseEvent<HTMLLIElement>, index: number, item: IMenuListItem) {
|
||||
console.log(e);
|
||||
console.log(index);
|
||||
console.log(item)
|
||||
}
|
||||
}
|
||||
|
||||
const agentMenu: IMenuWithTopButton = {
|
||||
button: {
|
||||
name: '代理服务',
|
||||
handle(e: MouseEvent<HTMLButtonElement>) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
list: [
|
||||
{id: 'agent1', icon: './vite.svg', name: '全部项目'},
|
||||
{id: 'agent2', icon: './vite.svg', name: '进行中的'},
|
||||
{id: 'agent3', icon: './vite.svg', name: '已完成的'},
|
||||
],
|
||||
handleListItem(e: MouseEvent<HTMLLIElement>, index: number, item: IMenuListItem) {
|
||||
console.log(e);
|
||||
console.log(index);
|
||||
console.log(item)
|
||||
}
|
||||
}
|
||||
|
||||
export default function Index() {
|
||||
return (
|
||||
<div className="index">
|
||||
<div className="left">
|
||||
<MenuWithTopButton
|
||||
button={projMenu.button}
|
||||
list={projMenu.list}
|
||||
handleListItem={projMenu.handleListItem}
|
||||
/>
|
||||
<MenuTree/>
|
||||
<MenuWithTopButton
|
||||
button={agentMenu.button}
|
||||
list={agentMenu.list}
|
||||
handleListItem={agentMenu.handleListItem}
|
||||
/>
|
||||
</div>
|
||||
<div className="right"></div>
|
||||
</div>
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue
Block a user