├── .gitattributes
├── .gitignore
├── README.md
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
├── src
├── App.test.tsx
├── App.tsx
├── assets
│ ├── images
│ │ └── typescript-logo-240.png
│ └── index.ts
├── components
│ ├── common
│ │ ├── Sidebar.tsx
│ │ ├── SidebarItem.tsx
│ │ ├── SidebarItemCollapse.tsx
│ │ └── Topbar.tsx
│ └── layout
│ │ ├── MainLayout.tsx
│ │ └── PageWrapper.tsx
├── configs
│ ├── colorConfigs.ts
│ └── sizeConfigs.ts
├── index.tsx
├── pages
│ ├── changelog
│ │ └── ChangelogPage.tsx
│ ├── component
│ │ ├── AlertPage.tsx
│ │ ├── ButtonPage.tsx
│ │ └── ComponentPageLayout.tsx
│ ├── dashboard
│ │ ├── AnalyticsPage.tsx
│ │ ├── DashboardIndex.tsx
│ │ ├── DashboardPageLayout.tsx
│ │ ├── DefaultPage.tsx
│ │ └── SaasPage.tsx
│ ├── documentation
│ │ └── DocumentationPage.tsx
│ ├── home
│ │ └── HomePage.tsx
│ └── installation
│ │ └── InstallationPage.tsx
├── react-app-env.d.ts
├── redux
│ ├── features
│ │ └── appStateSlice.ts
│ └── store.ts
├── reportWebVitals.ts
├── routes
│ ├── appRoutes.tsx
│ ├── config.ts
│ └── index.tsx
└── setupTests.ts
├── tsconfig.json
└── yarn.lock
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Video tutorial
4 |
5 | https://youtu.be/XwnZLgIfIvg
6 |
7 | # Reference
8 |
9 | - Create react app:https://create-react-app.dev/
10 | - Material-UI: https://mui.com/
11 | - React-router: https://reactrouter.com/
12 |
13 | # Preview
14 |
15 | 
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-sidebar-with-dropdown",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@emotion/react": "^11.10.5",
7 | "@emotion/styled": "^11.10.5",
8 | "@mui/icons-material": "^5.10.9",
9 | "@mui/material": "^5.10.12",
10 | "@reduxjs/toolkit": "^1.8.6",
11 | "@testing-library/jest-dom": "^5.14.1",
12 | "@testing-library/react": "^13.0.0",
13 | "@testing-library/user-event": "^13.2.1",
14 | "@types/jest": "^27.0.1",
15 | "@types/node": "^16.7.13",
16 | "@types/react": "^18.0.0",
17 | "@types/react-dom": "^18.0.0",
18 | "react": "^18.2.0",
19 | "react-dom": "^18.2.0",
20 | "react-redux": "^8.0.4",
21 | "react-router-dom": "^6.4.3",
22 | "react-scripts": "5.0.1",
23 | "typescript": "^4.4.2",
24 | "web-vitals": "^2.1.0"
25 | },
26 | "scripts": {
27 | "start": "react-scripts start",
28 | "build": "react-scripts build",
29 | "test": "react-scripts test",
30 | "eject": "react-scripts eject"
31 | },
32 | "eslintConfig": {
33 | "extends": [
34 | "react-app",
35 | "react-app/jest"
36 | ]
37 | },
38 | "browserslist": {
39 | "production": [
40 | ">0.2%",
41 | "not dead",
42 | "not op_mini all"
43 | ],
44 | "development": [
45 | "last 1 chrome version",
46 | "last 1 firefox version",
47 | "last 1 safari version"
48 | ]
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trananhtuat/react-sidebar-with-dropdown/5331d1cd9d33c06c6b5d92bc3ac19a0b288c1157/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
25 |
26 |
27 | React App
28 |
29 |
30 |
31 |
32 |
33 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trananhtuat/react-sidebar-with-dropdown/5331d1cd9d33c06c6b5d92bc3ac19a0b288c1157/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trananhtuat/react-sidebar-with-dropdown/5331d1cd9d33c06c6b5d92bc3ac19a0b288c1157/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/App.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render, screen } from '@testing-library/react';
3 | import App from './App';
4 |
5 | test('renders learn react link', () => {
6 | render();
7 | const linkElement = screen.getByText(/learn react/i);
8 | expect(linkElement).toBeInTheDocument();
9 | });
10 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { BrowserRouter, Route, Routes } from "react-router-dom";
2 | import MainLayout from "./components/layout/MainLayout";
3 | import { routes } from "./routes";
4 |
5 | function App() {
6 | return (
7 |
8 |
9 | }>
10 | {routes}
11 |
12 |
13 |
14 | );
15 | }
16 |
17 | export default App;
18 |
--------------------------------------------------------------------------------
/src/assets/images/typescript-logo-240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trananhtuat/react-sidebar-with-dropdown/5331d1cd9d33c06c6b5d92bc3ac19a0b288c1157/src/assets/images/typescript-logo-240.png
--------------------------------------------------------------------------------
/src/assets/index.ts:
--------------------------------------------------------------------------------
1 | const assets = {
2 | images: {
3 | logo: require("./images/typescript-logo-240.png")
4 | }
5 | };
6 |
7 | export default assets;
--------------------------------------------------------------------------------
/src/components/common/Sidebar.tsx:
--------------------------------------------------------------------------------
1 | import { Avatar, Drawer, List, Stack, Toolbar } from "@mui/material";
2 | import assets from "../../assets";
3 | import colorConfigs from "../../configs/colorConfigs";
4 | import sizeConfigs from "../../configs/sizeConfigs";
5 | import appRoutes from "../../routes/appRoutes";
6 | import SidebarItem from "./SidebarItem";
7 | import SidebarItemCollapse from "./SidebarItemCollapse";
8 |
9 | const Sidebar = () => {
10 | return (
11 |
25 |
26 |
27 |
32 |
33 |
34 |
35 | {appRoutes.map((route, index) => (
36 | route.sidebarProps ? (
37 | route.child ? (
38 |
39 | ) : (
40 |
41 | )
42 | ) : null
43 | ))}
44 |
45 |
46 | );
47 | };
48 |
49 | export default Sidebar;
--------------------------------------------------------------------------------
/src/components/common/SidebarItem.tsx:
--------------------------------------------------------------------------------
1 | import { ListItemButton, ListItemIcon } from "@mui/material";
2 | import { useSelector } from "react-redux";
3 | import { Link } from "react-router-dom";
4 | import colorConfigs from "../../configs/colorConfigs";
5 | import { RootState } from "../../redux/store";
6 | import { RouteType } from "../../routes/config";
7 |
8 | type Props = {
9 | item: RouteType;
10 | };
11 |
12 | const SidebarItem = ({ item }: Props) => {
13 | const { appState } = useSelector((state: RootState) => state.appState);
14 |
15 | return (
16 | item.sidebarProps && item.path ? (
17 |
29 |
32 | {item.sidebarProps.icon && item.sidebarProps.icon}
33 |
34 | {item.sidebarProps.displayText}
35 |
36 | ) : null
37 | );
38 | };
39 |
40 | export default SidebarItem;
--------------------------------------------------------------------------------
/src/components/common/SidebarItemCollapse.tsx:
--------------------------------------------------------------------------------
1 | import { Collapse, List, ListItemButton, ListItemIcon, ListItemText, Typography } from "@mui/material";
2 | import { useEffect, useState } from "react";
3 | import colorConfigs from "../../configs/colorConfigs";
4 | import { RouteType } from "../../routes/config";
5 | import ExpandLessOutlinedIcon from '@mui/icons-material/ExpandLessOutlined';
6 | import ExpandMoreOutlinedIcon from '@mui/icons-material/ExpandMoreOutlined';
7 | import SidebarItem from "./SidebarItem";
8 | import { useSelector } from "react-redux";
9 | import { RootState } from "../../redux/store";
10 |
11 | type Props = {
12 | item: RouteType;
13 | };
14 |
15 | const SidebarItemCollapse = ({ item }: Props) => {
16 | const [open, setOpen] = useState(false);
17 |
18 | const { appState } = useSelector((state: RootState) => state.appState);
19 |
20 | useEffect(() => {
21 | if (appState.includes(item.state)) {
22 | setOpen(true);
23 | }
24 | }, [appState, item]);
25 |
26 | return (
27 | item.sidebarProps ? (
28 | <>
29 | setOpen(!open)}
31 | sx={{
32 | "&: hover": {
33 | backgroundColor: colorConfigs.sidebar.hoverBg
34 | },
35 | paddingY: "12px",
36 | paddingX: "24px"
37 | }}
38 | >
39 |
42 | {item.sidebarProps.icon && item.sidebarProps.icon}
43 |
44 |
48 | {item.sidebarProps.displayText}
49 |
50 | }
51 | />
52 | {open ? : }
53 |
54 |
55 |
56 | {item.child?.map((route, index) => (
57 | route.sidebarProps ? (
58 | route.child ? (
59 |
60 | ) : (
61 |
62 | )
63 | ) : null
64 | ))}
65 |
66 |
67 | >
68 | ) : null
69 | );
70 | };
71 |
72 | export default SidebarItemCollapse;
--------------------------------------------------------------------------------
/src/components/common/Topbar.tsx:
--------------------------------------------------------------------------------
1 | import { AppBar, Toolbar, Typography } from "@mui/material";
2 | import colorConfigs from "../../configs/colorConfigs";
3 | import sizeConfigs from "../../configs/sizeConfigs";
4 |
5 | const Topbar = () => {
6 | return (
7 |
17 |
18 |
19 | React sidebar with dropdown
20 |
21 |
22 |
23 | );
24 | };
25 |
26 | export default Topbar;
--------------------------------------------------------------------------------
/src/components/layout/MainLayout.tsx:
--------------------------------------------------------------------------------
1 | import { Outlet } from "react-router-dom";
2 | import { Box, Toolbar } from "@mui/material";
3 | import colorConfigs from "../../configs/colorConfigs";
4 | import sizeConfigs from "../../configs/sizeConfigs";
5 | import Sidebar from "../common/Sidebar";
6 | import Topbar from "../common/Topbar";
7 |
8 | const MainLayout = () => {
9 | return (
10 |
11 |
12 |
19 |
20 |
21 |
31 |
32 |
33 |
34 |
35 | );
36 | };
37 |
38 | export default MainLayout;
--------------------------------------------------------------------------------
/src/components/layout/PageWrapper.tsx:
--------------------------------------------------------------------------------
1 | import { ReactNode, useEffect } from "react";
2 | import { useDispatch } from "react-redux";
3 | import { setAppState } from "../../redux/features/appStateSlice";
4 |
5 | type Props = {
6 | state?: string,
7 | children: ReactNode;
8 | };
9 |
10 | const PageWrapper = (props: Props) => {
11 | const dispatch = useDispatch();
12 |
13 | useEffect(() => {
14 | if (props.state) {
15 | dispatch(setAppState(props.state));
16 | }
17 | }, [dispatch, props]);
18 |
19 | return (
20 | <>{props.children}>
21 | );
22 | };
23 |
24 | export default PageWrapper;
--------------------------------------------------------------------------------
/src/configs/colorConfigs.ts:
--------------------------------------------------------------------------------
1 | import { colors } from "@mui/material";
2 |
3 | const colorConfigs = {
4 | sidebar: {
5 | bg: "#233044",
6 | color: "#eeeeee",
7 | hoverBg: "#1e293a",
8 | activeBg: "#1e253a"
9 | },
10 | topbar: {
11 | bg: "#fff",
12 | color: "#000"
13 | },
14 | mainBg: colors.grey["100"]
15 | };
16 |
17 | export default colorConfigs;
--------------------------------------------------------------------------------
/src/configs/sizeConfigs.ts:
--------------------------------------------------------------------------------
1 | const sizeConfigs = {
2 | sidebar: {
3 | width: "300px"
4 | }
5 | };
6 |
7 | export default sizeConfigs;
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import { CssBaseline } from '@mui/material';
2 | import React from 'react';
3 | import ReactDOM from 'react-dom/client';
4 | import { Provider } from 'react-redux';
5 | import App from './App';
6 | import { store } from './redux/store';
7 | import reportWebVitals from './reportWebVitals';
8 |
9 | const root = ReactDOM.createRoot(
10 | document.getElementById('root') as HTMLElement
11 | );
12 | root.render(
13 |
14 |
15 |
16 |
17 |
18 |
19 | );
20 |
21 | // If you want to start measuring performance in your app, pass a function
22 | // to log results (for example: reportWebVitals(console.log))
23 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
24 | reportWebVitals();
25 |
--------------------------------------------------------------------------------
/src/pages/changelog/ChangelogPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | type Props = {};
4 |
5 | const ChangelogPage = (props: Props) => {
6 | return (
7 | ChangelogPage
8 | );
9 | };
10 |
11 | export default ChangelogPage;
--------------------------------------------------------------------------------
/src/pages/component/AlertPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | type Props = {};
4 |
5 | const AlertPage = (props: Props) => {
6 | return (
7 | AlertPage
8 | );
9 | };
10 |
11 | export default AlertPage;
--------------------------------------------------------------------------------
/src/pages/component/ButtonPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | type Props = {};
4 |
5 | const ButtonPage = (props: Props) => {
6 | return (
7 | ButtonPage
8 | );
9 | };
10 |
11 | export default ButtonPage;
--------------------------------------------------------------------------------
/src/pages/component/ComponentPageLayout.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Outlet } from 'react-router-dom';
3 |
4 | type Props = {};
5 |
6 | const ComponentPageLayout = (props: Props) => {
7 | return (
8 | <>>
9 | );
10 | };
11 |
12 | export default ComponentPageLayout;
--------------------------------------------------------------------------------
/src/pages/dashboard/AnalyticsPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | type Props = {};
4 |
5 | const AnalyticsPage = (props: Props) => {
6 | return (
7 | AnalyticsPage
8 | );
9 | };
10 |
11 | export default AnalyticsPage;
--------------------------------------------------------------------------------
/src/pages/dashboard/DashboardIndex.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | type Props = {};
4 |
5 | const DashboardIndex = (props: Props) => {
6 | return (
7 | DashboardIndex
8 | );
9 | };
10 |
11 | export default DashboardIndex;
--------------------------------------------------------------------------------
/src/pages/dashboard/DashboardPageLayout.tsx:
--------------------------------------------------------------------------------
1 | import { Outlet } from "react-router-dom";
2 |
3 | const DashboardPageLayout = () => {
4 | return (
5 | <>>
6 | );
7 | };
8 |
9 | export default DashboardPageLayout;
--------------------------------------------------------------------------------
/src/pages/dashboard/DefaultPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | type Props = {};
4 |
5 | const DefaultPage = (props: Props) => {
6 | return (
7 | DefaultPage
8 | );
9 | };
10 |
11 | export default DefaultPage;
--------------------------------------------------------------------------------
/src/pages/dashboard/SaasPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | type Props = {};
4 |
5 | const SaasPage = (props: Props) => {
6 | return (
7 | SaasPage
8 | );
9 | };
10 |
11 | export default SaasPage;
--------------------------------------------------------------------------------
/src/pages/documentation/DocumentationPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | type Props = {};
4 |
5 | const DocumentationPage = (props: Props) => {
6 | return (
7 | DocumentationPage
8 | );
9 | };
10 |
11 | export default DocumentationPage;
--------------------------------------------------------------------------------
/src/pages/home/HomePage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | type Props = {};
4 |
5 | const HomePage = (props: Props) => {
6 | return (
7 | HomePage
8 | );
9 | };
10 |
11 | export default HomePage;
--------------------------------------------------------------------------------
/src/pages/installation/InstallationPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | type Props = {};
4 |
5 | const InstallationPage = (props: Props) => {
6 | return (
7 | InstallationPage
8 | );
9 | };
10 |
11 | export default InstallationPage;
--------------------------------------------------------------------------------
/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/redux/features/appStateSlice.ts:
--------------------------------------------------------------------------------
1 | import { createSlice, PayloadAction } from "@reduxjs/toolkit";
2 |
3 | type appState = {
4 | appState: string;
5 | };
6 |
7 | const initialState: appState = {
8 | appState: ""
9 | };
10 |
11 | export const appStateSlice = createSlice({
12 | name: "appState",
13 | initialState,
14 | reducers: {
15 | setAppState: (state, action: PayloadAction) => {
16 | state.appState = action.payload;
17 | }
18 | }
19 | });
20 |
21 | export const {
22 | setAppState
23 | } = appStateSlice.actions;
24 |
25 | export default appStateSlice.reducer;
--------------------------------------------------------------------------------
/src/redux/store.ts:
--------------------------------------------------------------------------------
1 | import { configureStore } from "@reduxjs/toolkit";
2 | import appStateSlice from "./features/appStateSlice";
3 |
4 | export const store = configureStore({
5 | reducer: {
6 | appState: appStateSlice
7 | }
8 | });
9 |
10 | export type RootState = ReturnType;
--------------------------------------------------------------------------------
/src/reportWebVitals.ts:
--------------------------------------------------------------------------------
1 | import { ReportHandler } from 'web-vitals';
2 |
3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => {
4 | if (onPerfEntry && onPerfEntry instanceof Function) {
5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
6 | getCLS(onPerfEntry);
7 | getFID(onPerfEntry);
8 | getFCP(onPerfEntry);
9 | getLCP(onPerfEntry);
10 | getTTFB(onPerfEntry);
11 | });
12 | }
13 | };
14 |
15 | export default reportWebVitals;
16 |
--------------------------------------------------------------------------------
/src/routes/appRoutes.tsx:
--------------------------------------------------------------------------------
1 | import DashboardPageLayout from "../pages/dashboard/DashboardPageLayout";
2 | import HomePage from "../pages/home/HomePage";
3 | import { RouteType } from "./config";
4 | import DefaultPage from "../pages/dashboard/DefaultPage";
5 | import DashboardIndex from "../pages/dashboard/DashboardIndex";
6 | import ChangelogPage from "../pages/changelog/ChangelogPage";
7 | import AnalyticsPage from "../pages/dashboard/AnalyticsPage";
8 | import SaasPage from "../pages/dashboard/SaasPage";
9 | import ComponentPageLayout from "../pages/component/ComponentPageLayout";
10 | import DashboardOutlinedIcon from '@mui/icons-material/DashboardOutlined';
11 | import AppsOutlinedIcon from '@mui/icons-material/AppsOutlined';
12 | import ArticleOutlinedIcon from '@mui/icons-material/ArticleOutlined';
13 | import FormatListBulletedOutlinedIcon from '@mui/icons-material/FormatListBulletedOutlined';
14 | import FileDownloadOutlinedIcon from '@mui/icons-material/FileDownloadOutlined';
15 | import AlertPage from "../pages/component/AlertPage";
16 | import ButtonPage from "../pages/component/ButtonPage";
17 | import InstallationPage from "../pages/installation/InstallationPage";
18 | import DocumentationPage from "../pages/documentation/DocumentationPage";
19 |
20 | const appRoutes: RouteType[] = [
21 | {
22 | index: true,
23 | element: ,
24 | state: "home"
25 | },
26 | {
27 | path: "/installation",
28 | element: ,
29 | state: "installation",
30 | sidebarProps: {
31 | displayText: "Installation",
32 | icon:
33 | }
34 | },
35 | {
36 | path: "/dashboard",
37 | element: ,
38 | state: "dashboard",
39 | sidebarProps: {
40 | displayText: "Dashboard",
41 | icon:
42 | },
43 | child: [
44 | {
45 | index: true,
46 | element: ,
47 | state: "dashboard.index"
48 | },
49 | {
50 | path: "/dashboard/default",
51 | element: ,
52 | state: "dashboard.default",
53 | sidebarProps: {
54 | displayText: "Default"
55 | },
56 | },
57 | {
58 | path: "/dashboard/analytics",
59 | element: ,
60 | state: "dashboard.analytics",
61 | sidebarProps: {
62 | displayText: "Analytic"
63 | }
64 | },
65 | {
66 | path: "/dashboard/saas",
67 | element: ,
68 | state: "dashboard.saas",
69 | sidebarProps: {
70 | displayText: "Saas"
71 | }
72 | }
73 | ]
74 | },
75 | {
76 | path: "/component",
77 | element: ,
78 | state: "component",
79 | sidebarProps: {
80 | displayText: "Components",
81 | icon:
82 | },
83 | child: [
84 | {
85 | path: "/component/alert",
86 | element: ,
87 | state: "component.alert",
88 | sidebarProps: {
89 | displayText: "Alert"
90 | },
91 | },
92 | {
93 | path: "/component/button",
94 | element: ,
95 | state: "component.button",
96 | sidebarProps: {
97 | displayText: "Button"
98 | }
99 | }
100 | ]
101 | },
102 | {
103 | path: "/documentation",
104 | element: ,
105 | state: "documentation",
106 | sidebarProps: {
107 | displayText: "Documentation",
108 | icon:
109 | }
110 | },
111 | {
112 | path: "/changelog",
113 | element: ,
114 | state: "changelog",
115 | sidebarProps: {
116 | displayText: "Changelog",
117 | icon:
118 | }
119 | }
120 | ];
121 |
122 | export default appRoutes;
--------------------------------------------------------------------------------
/src/routes/config.ts:
--------------------------------------------------------------------------------
1 | import { ReactNode } from "react";
2 |
3 | export type RouteType = {
4 | element: ReactNode,
5 | state: string,
6 | index?: boolean,
7 | path?: string,
8 | child?: RouteType[],
9 | sidebarProps?: {
10 | displayText: string,
11 | icon?: ReactNode;
12 | };
13 | };
--------------------------------------------------------------------------------
/src/routes/index.tsx:
--------------------------------------------------------------------------------
1 | import { ReactNode } from "react";
2 | import { Route } from "react-router-dom";
3 | import PageWrapper from "../components/layout/PageWrapper";
4 | import appRoutes from "./appRoutes";
5 | import { RouteType } from "./config";
6 |
7 | const generateRoute = (routes: RouteType[]): ReactNode => {
8 | return routes.map((route, index) => (
9 | route.index ? (
10 |
14 | {route.element}
15 | }
16 | key={index}
17 | />
18 | ) : (
19 |
23 | {route.element}
24 |
25 | }
26 | key={index}
27 | >
28 | {route.child && (
29 | generateRoute(route.child)
30 | )}
31 |
32 | )
33 | ));
34 | };
35 |
36 | export const routes: ReactNode = generateRoute(appRoutes);
--------------------------------------------------------------------------------
/src/setupTests.ts:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "noFallthroughCasesInSwitch": true,
16 | "module": "esnext",
17 | "moduleResolution": "node",
18 | "resolveJsonModule": true,
19 | "isolatedModules": true,
20 | "noEmit": true,
21 | "jsx": "react-jsx"
22 | },
23 | "include": [
24 | "src"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------