From cc8bb825fb1bd8713072dfe312eb2c4b2d1cae44 Mon Sep 17 00:00:00 2001 From: Gao Sun Date: Thu, 3 Mar 2022 15:02:30 +0800 Subject: [PATCH] feat(console): active tab by route (#309) * feat(console): active tab by route * refactor(console): export sidebar utils and consts in index --- packages/console/package.json | 5 +- packages/console/src/App.tsx | 24 +++++++- .../Sidebar/components/Item/index.module.scss | 2 + .../Sidebar/components/Item/index.tsx | 5 +- .../console/src/components/Sidebar/index.tsx | 8 ++- .../console/src/components/Sidebar/utils.ts | 3 + packages/console/src/index.tsx | 2 +- pnpm-lock.yaml | 59 ++++++++++++++----- 8 files changed, 85 insertions(+), 23 deletions(-) create mode 100644 packages/console/src/components/Sidebar/utils.ts diff --git a/packages/console/package.json b/packages/console/package.json index 6a6ebb0ec..83b993b1a 100644 --- a/packages/console/package.json +++ b/packages/console/package.json @@ -21,9 +21,11 @@ "classnames": "^2.3.1", "i18next": "^21.6.12", "i18next-browser-languagedetector": "^6.1.3", + "lodash.kebabcase": "^4.1.1", "react": "^17.0.2", "react-dom": "^17.0.2", - "react-i18next": "^11.15.4" + "react-i18next": "^11.15.4", + "react-router-dom": "^6.2.2" }, "devDependencies": { "@parcel/core": "^2.3.1", @@ -32,6 +34,7 @@ "@silverhand/eslint-config-react": "^0.9.3", "@silverhand/ts-config": "^0.9.1", "@silverhand/ts-config-react": "^0.9.3", + "@types/lodash.kebabcase": "^4.1.6", "@types/react": "^17.0.14", "@types/react-dom": "^17.0.9", "eslint": "^8.10.0", diff --git a/packages/console/src/App.tsx b/packages/console/src/App.tsx index c5558adfd..7d5bb189d 100644 --- a/packages/console/src/App.tsx +++ b/packages/console/src/App.tsx @@ -1,15 +1,25 @@ -import React from 'react'; +import React, { useEffect } from 'react'; +import { BrowserRouter, useLocation, useNavigate } from 'react-router-dom'; import './scss/normalized.scss'; import * as styles from './App.module.scss'; import Content from './components/Content'; -import Sidebar from './components/Sidebar'; +import Sidebar, { getPath, sections } from './components/Sidebar'; import Topbar from './components/Topbar'; import initI18n from './i18n/init'; void initI18n(); -export const App = () => { +const Main = () => { + const location = useLocation(); + const navigate = useNavigate(); + + useEffect(() => { + if (location.pathname === '/') { + navigate(getPath(sections[0]?.items[0]?.title ?? '')); + } + }, [location.pathname, navigate]); + return (
@@ -20,3 +30,11 @@ export const App = () => {
); }; + +const App = () => ( + +
+ +); + +export default App; diff --git a/packages/console/src/components/Sidebar/components/Item/index.module.scss b/packages/console/src/components/Sidebar/components/Item/index.module.scss index 8bd8578c2..50c25b8b4 100644 --- a/packages/console/src/components/Sidebar/components/Item/index.module.scss +++ b/packages/console/src/components/Sidebar/components/Item/index.module.scss @@ -7,6 +7,8 @@ padding: _.unit(3) _.unit(4); color: var(--color-on-surface-variant); border-radius: _.unit(2); + text-decoration: none; + user-select: none; .icon { width: _.unit(6); diff --git a/packages/console/src/components/Sidebar/components/Item/index.tsx b/packages/console/src/components/Sidebar/components/Item/index.tsx index c02f1514a..0223b3958 100644 --- a/packages/console/src/components/Sidebar/components/Item/index.tsx +++ b/packages/console/src/components/Sidebar/components/Item/index.tsx @@ -1,6 +1,7 @@ import classNames from 'classnames'; import React, { ReactChild } from 'react'; +import { getPath } from '../../utils'; import * as styles from './index.module.scss'; type Props = { @@ -11,10 +12,10 @@ type Props = { const Item = ({ icon, title, isActive = false }: Props) => { return ( -
+ {icon &&
{icon}
}
{title}
-
+ ); }; diff --git a/packages/console/src/components/Sidebar/index.tsx b/packages/console/src/components/Sidebar/index.tsx index 326445897..8bdaa360f 100644 --- a/packages/console/src/components/Sidebar/index.tsx +++ b/packages/console/src/components/Sidebar/index.tsx @@ -1,11 +1,13 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; +import { useLocation } from 'react-router-dom'; import Item from './components/Item'; import Section from './components/Section'; import { sections } from './consts'; import Gear from './icons/Gear'; import * as styles from './index.module.scss'; +import { getPath } from './utils'; const Sidebar = () => { const { t: tSection } = useTranslation(undefined, { @@ -14,6 +16,7 @@ const Sidebar = () => { const { t: tItem } = useTranslation(undefined, { keyPrefix: 'admin_console.tabs', }); + const location = useLocation(); return (
@@ -24,7 +27,7 @@ const Sidebar = () => { key={title} title={tItem(title)} icon={} - isActive={title === 'api_resources'} + isActive={location.pathname === getPath(title)} /> ))} @@ -36,3 +39,6 @@ const Sidebar = () => { }; export default Sidebar; + +export * from './consts'; +export * from './utils'; diff --git a/packages/console/src/components/Sidebar/utils.ts b/packages/console/src/components/Sidebar/utils.ts new file mode 100644 index 000000000..e86f0b953 --- /dev/null +++ b/packages/console/src/components/Sidebar/utils.ts @@ -0,0 +1,3 @@ +import kebabCase from 'lodash.kebabcase'; + +export const getPath = (title: string): string => `/${kebabCase(title)}`; diff --git a/packages/console/src/index.tsx b/packages/console/src/index.tsx index c4b18d95f..09a8551e3 100644 --- a/packages/console/src/index.tsx +++ b/packages/console/src/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { App } from './App'; +import App from './App'; const app = document.querySelector('#app'); ReactDOM.render(, app); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1b86d1094..9839b537e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28,6 +28,7 @@ importers: '@silverhand/eslint-config-react': ^0.9.3 '@silverhand/ts-config': ^0.9.1 '@silverhand/ts-config-react': ^0.9.3 + '@types/lodash.kebabcase': ^4.1.6 '@types/react': ^17.0.14 '@types/react-dom': ^17.0.9 classnames: ^2.3.1 @@ -35,6 +36,7 @@ importers: i18next: ^21.6.12 i18next-browser-languagedetector: ^6.1.3 lint-staged: ^11.1.1 + lodash.kebabcase: ^4.1.1 parcel: ^2.3.1 postcss: ^8.4.6 postcss-modules: ^4.3.0 @@ -42,6 +44,7 @@ importers: react: ^17.0.2 react-dom: ^17.0.2 react-i18next: ^11.15.4 + react-router-dom: ^6.2.2 stylelint: ^13.13.1 typescript: ^4.5.5 dependencies: @@ -50,9 +53,11 @@ importers: classnames: 2.3.1 i18next: 21.6.12 i18next-browser-languagedetector: 6.1.3 + lodash.kebabcase: 4.1.1 react: 17.0.2 react-dom: 17.0.2_react@17.0.2 react-i18next: 11.15.4_2c37a602a29bb6bd53f3de707a8cfcc5 + react-router-dom: 6.2.2_react-dom@17.0.2+react@17.0.2 devDependencies: '@parcel/core': 2.3.1 '@parcel/transformer-sass': 2.3.1_@parcel+core@2.3.1 @@ -60,6 +65,7 @@ importers: '@silverhand/eslint-config-react': 0.9.3_40768c17363f6507b3c2d36cc72e1a6b '@silverhand/ts-config': 0.9.1_typescript@4.5.5 '@silverhand/ts-config-react': 0.9.3_typescript@4.5.5 + '@types/lodash.kebabcase': 4.1.6 '@types/react': 17.0.37 '@types/react-dom': 17.0.11 eslint: 8.10.0 @@ -3462,6 +3468,12 @@ packages: '@types/node': 16.11.12 dev: true + /@types/lodash.kebabcase/4.1.6: + resolution: {integrity: sha512-+RAD9pCAa8kuVyCYTeDNiwBXwD/0u0p+hos3NSqD+tXTjJextbfF3farfYB+ssAKgEssoewXEtBsfwBpsI7gsA==} + dependencies: + '@types/lodash': 4.14.178 + dev: true + /@types/lodash.pick/4.4.6: resolution: {integrity: sha512-u8bzA16qQ+8dY280z3aK7PoWb3fzX5ATJ0rJB6F+uqchOX2VYF02Aqa+8aYiHiHgPzQiITqCgeimlyKFy4OA6g==} dependencies: @@ -6655,6 +6667,12 @@ packages: value-equal: 1.0.1 dev: false + /history/5.3.0: + resolution: {integrity: sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==} + dependencies: + '@babel/runtime': 7.16.3 + dev: false + /hoist-non-react-statics/3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} dependencies: @@ -8922,7 +8940,6 @@ packages: /lodash.kebabcase/4.1.1: resolution: {integrity: sha1-hImxyw0p/4gZXM7KRI/21swpXDY=} - dev: true /lodash.memoize/4.1.2: resolution: {integrity: sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=} @@ -9272,14 +9289,14 @@ packages: engines: {node: '>=4'} dev: true - /mini-create-react-context/0.4.1_prop-types@15.7.2+react@17.0.2: + /mini-create-react-context/0.4.1_prop-types@15.8.1+react@17.0.2: resolution: {integrity: sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==} peerDependencies: prop-types: ^15.0.0 react: ^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 dependencies: '@babel/runtime': 7.16.3 - prop-types: 15.7.2 + prop-types: 15.8.1 react: 17.0.2 tiny-warning: 1.0.3 dev: false @@ -11037,21 +11054,12 @@ packages: read: 1.0.7 dev: true - /prop-types/15.7.2: - resolution: {integrity: sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==} - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - react-is: 16.13.1 - dev: false - /prop-types/15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 - dev: true /propagate/2.0.1: resolution: {integrity: sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==} @@ -11244,13 +11252,25 @@ packages: '@babel/runtime': 7.16.3 history: 4.10.1 loose-envify: 1.4.0 - prop-types: 15.7.2 + prop-types: 15.8.1 react: 17.0.2 react-router: 5.2.1_react@17.0.2 tiny-invariant: 1.2.0 tiny-warning: 1.0.3 dev: false + /react-router-dom/6.2.2_react-dom@17.0.2+react@17.0.2: + resolution: {integrity: sha512-AtYEsAST7bDD4dLSQHDnk/qxWLJdad5t1HFa1qJyUrCeGgEuCSw0VB/27ARbF9Fi/W5598ujvJOm3ujUCVzuYQ==} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + dependencies: + history: 5.3.0 + react: 17.0.2 + react-dom: 17.0.2_react@17.0.2 + react-router: 6.2.2_react@17.0.2 + dev: false + /react-router/5.2.1_react@17.0.2: resolution: {integrity: sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ==} peerDependencies: @@ -11260,15 +11280,24 @@ packages: history: 4.10.1 hoist-non-react-statics: 3.3.2 loose-envify: 1.4.0 - mini-create-react-context: 0.4.1_prop-types@15.7.2+react@17.0.2 + mini-create-react-context: 0.4.1_prop-types@15.8.1+react@17.0.2 path-to-regexp: 1.8.0 - prop-types: 15.7.2 + prop-types: 15.8.1 react: 17.0.2 react-is: 16.13.1 tiny-invariant: 1.2.0 tiny-warning: 1.0.3 dev: false + /react-router/6.2.2_react@17.0.2: + resolution: {integrity: sha512-/MbxyLzd7Q7amp4gDOGaYvXwhEojkJD5BtExkuKmj39VEE0m3l/zipf6h2WIB2jyAO0lI6NGETh4RDcktRm4AQ==} + peerDependencies: + react: '>=16.8' + dependencies: + history: 5.3.0 + react: 17.0.2 + dev: false + /react/17.0.2: resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==} engines: {node: '>=0.10.0'}