├── .yarnrc.yml ├── src ├── vite-env.d.js ├── assets │ └── images │ │ ├── users │ │ ├── avatar-1.jpg │ │ ├── avatar-2.jpg │ │ ├── avatar-3.jpg │ │ └── avatar-4.jpg │ │ ├── social-google.svg │ │ ├── logo-dark.svg │ │ └── logo.svg ├── config.js ├── layouts │ ├── minimalLayout │ │ └── index.jsx │ └── MainLayout │ │ ├── Drawer │ │ ├── DrawerContent │ │ │ ├── Navigation │ │ │ │ ├── index.jsx │ │ │ │ ├── NavGroup.jsx │ │ │ │ ├── NavItem.jsx │ │ │ │ └── NavCollapse.jsx │ │ │ └── index.jsx │ │ └── index.jsx │ │ ├── index.jsx │ │ └── Header │ │ ├── index.jsx │ │ ├── Search.jsx │ │ ├── Profile.jsx │ │ └── Notification.jsx ├── themes │ ├── overrides │ │ ├── CardActions.js │ │ ├── CardContent.js │ │ ├── ListItem.js │ │ ├── Chip.js │ │ ├── ListItemIcon.js │ │ ├── Popper.js │ │ ├── Checkbox.js │ │ ├── CardHeader.js │ │ ├── FormHelperText.js │ │ ├── SvgIcon.js │ │ ├── Paper.js │ │ ├── ListItemButton.js │ │ ├── index.js │ │ └── Avatar.js │ ├── shadow.js │ ├── index.jsx │ ├── typography.js │ └── palette.js ├── views │ ├── dashboard │ │ └── default │ │ │ ├── data │ │ │ ├── small-flat-card-data.jsx │ │ │ ├── traffic-source-card-data.jsx │ │ │ ├── sales-line-chart-card-data.jsx │ │ │ ├── revenue-card-data.jsx │ │ │ └── report-card-data.jsx │ │ │ └── index.jsx │ ├── auth │ │ ├── Register.jsx │ │ ├── Login.jsx │ │ └── CommonAuthLayout.jsx │ ├── pages │ │ └── SamplePage.jsx │ └── components │ │ └── Typography.jsx ├── App.jsx ├── menu-items │ ├── index.js │ ├── other.js │ ├── dashboard.js │ ├── ui-component.js │ └── pages.js ├── routes │ ├── index.jsx │ ├── PagesRoutes.jsx │ └── MainRoutes.jsx ├── components │ ├── loader │ │ └── index.jsx │ ├── Loadable.jsx │ ├── cards │ │ ├── TrafficSourceCard.jsx │ │ ├── ReportCard.jsx │ │ ├── SmallFlatCard.jsx │ │ └── MainCard.jsx │ ├── third-party │ │ ├── SimpleBar.jsx │ │ ├── SalesLineChartCard.jsx │ │ └── RevenuChartCard.jsx │ └── Breadcrumbs.jsx ├── main.jsx ├── sections │ ├── dashboard │ │ └── chart │ │ │ ├── card-data │ │ │ └── revenue-card-data.jsx │ │ │ └── chart-data │ │ │ ├── revenue-chart-data.js │ │ │ └── sales-line-chart.js │ └── auth │ │ ├── AuthLogin.jsx │ │ └── AuthRegister.jsx ├── enum.js ├── index.css ├── utils │ ├── passwordStrength.js │ └── validationSchema.js └── states │ └── menu.js ├── .prettierrc ├── .env ├── jsconfig.node.json ├── .env.qa ├── .gitignore ├── support.html ├── discord.html ├── documentation.html ├── index.html ├── jsconfig.json ├── vite.config.mjs ├── LICENSE ├── .github └── workflows │ ├── prod.yml │ └── stage.yml ├── package.json ├── eslint.config.mjs ├── favicon.svg ├── public └── favicon.svg └── README.md /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | -------------------------------------------------------------------------------- /src/vite-env.d.js: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/assets/images/users/avatar-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codedthemes/materially-free-react-admin-template/HEAD/src/assets/images/users/avatar-1.jpg -------------------------------------------------------------------------------- /src/assets/images/users/avatar-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codedthemes/materially-free-react-admin-template/HEAD/src/assets/images/users/avatar-2.jpg -------------------------------------------------------------------------------- /src/assets/images/users/avatar-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codedthemes/materially-free-react-admin-template/HEAD/src/assets/images/users/avatar-3.jpg -------------------------------------------------------------------------------- /src/assets/images/users/avatar-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codedthemes/materially-free-react-admin-template/HEAD/src/assets/images/users/avatar-4.jpg -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": true, 3 | "printWidth": 140, 4 | "singleQuote": true, 5 | "trailingComma": "none", 6 | "tabWidth": 2, 7 | "useTabs": false 8 | } 9 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | VITE_APP_VERSION = v4.0.0 2 | GENERATE_SOURCEMAP = false 3 | 4 | PUBLIC_URL = https://codedthemes.com/demos/admin-templates/materially/react/free 5 | VITE_APP_BASE_URL=/demos/admin-templates/materially/react/free -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | // ==============================|| THEME CONSTANT ||============================== // 2 | 3 | export const APP_DEFAULT_PATH = 'dashboard/default'; 4 | export const GRID_SPACING = 3; 5 | export const DRAWER_WIDTH = 280; 6 | -------------------------------------------------------------------------------- /jsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.mjs"] 9 | } 10 | -------------------------------------------------------------------------------- /.env.qa: -------------------------------------------------------------------------------- 1 | VITE_APP_VERSION=v4.0.0 2 | GENERATE_SOURCEMAP=false 3 | 4 | PUBLIC_URL = https://codedthemes.com/demos/admin-templates/materially/react/free/stage 5 | VITE_APP_BASE_URL=/demos/admin-templates/materially/react/free/stage 6 | 7 | ## Backend API URL 8 | VITE_APP_API_URL=https://mock-data-api-nextjs.vercel.app/ 9 | -------------------------------------------------------------------------------- /src/layouts/minimalLayout/index.jsx: -------------------------------------------------------------------------------- 1 | import { Outlet } from 'react-router-dom'; 2 | 3 | // ==============================|| MINIMAL LAYOUT ||============================== // 4 | 5 | export default function MinimalLayout() { 6 | return ( 7 | <> 8 | 9 | 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /src/themes/overrides/CardActions.js: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - CARD ACTIONS ||============================== // 2 | 3 | export default function CardActions() { 4 | return { 5 | MuiCardActions: { 6 | styleOverrides: { 7 | root: { 8 | padding: 24 9 | } 10 | } 11 | } 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/themes/overrides/CardContent.js: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - CARD CONTENT ||============================== // 2 | 3 | export default function CardContent() { 4 | return { 5 | MuiCardContent: { 6 | styleOverrides: { 7 | root: { 8 | padding: 24 9 | } 10 | } 11 | } 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/views/dashboard/default/data/small-flat-card-data.jsx: -------------------------------------------------------------------------------- 1 | export const smallFlatCardData = [ 2 | { 3 | value: '-0.99', 4 | label: 'REALTY', 5 | color: 'error.main', 6 | type: 'dashboard' 7 | }, 8 | { 9 | value: '-7.66', 10 | label: 'INFRA', 11 | color: 'success.main', 12 | type: 'dashboard' 13 | } 14 | ]; 15 | -------------------------------------------------------------------------------- /src/themes/overrides/ListItem.js: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - LISTITEM ||============================== // 2 | 3 | export default function ListItem(theme) { 4 | return { 5 | MuiListItem: { 6 | styleOverrides: { 7 | root: { 8 | color: theme.palette.text.primary 9 | } 10 | } 11 | } 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import { RouterProvider } from 'react-router-dom'; 2 | 3 | // project imports 4 | import ThemeCustomization from './themes'; 5 | 6 | import router from 'routes'; 7 | 8 | function App() { 9 | return ( 10 | 11 | 12 | 13 | ); 14 | } 15 | 16 | export default App; 17 | -------------------------------------------------------------------------------- /src/themes/overrides/Chip.js: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - CHIP ||============================== // 2 | 3 | export default function Chip(theme) { 4 | return { 5 | MuiChip: { 6 | styleOverrides: { 7 | avatar: { color: theme.palette.background.paper }, 8 | icon: { color: theme.palette.text.primary } 9 | } 10 | } 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | .yarn 10 | 11 | node_modules 12 | dist 13 | dist-ssr 14 | *.local 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | -------------------------------------------------------------------------------- /src/menu-items/index.js: -------------------------------------------------------------------------------- 1 | // type 2 | import dashboard from './dashboard'; 3 | import pages from './pages'; 4 | import other from './other'; 5 | import uiComponent from './ui-component'; 6 | // ==============================|| MENU ITEMS ||============================== // 7 | 8 | const menuItems = { 9 | items: [dashboard, pages, uiComponent, other] 10 | }; 11 | 12 | export default menuItems; 13 | -------------------------------------------------------------------------------- /src/themes/overrides/ListItemIcon.js: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - LISTITEM ICON ||============================== // 2 | 3 | export default function ListItemIcon(theme) { 4 | return { 5 | MuiListItemIcon: { 6 | styleOverrides: { 7 | root: { 8 | minWidth: '36px', 9 | color: theme.palette.text.primary 10 | } 11 | } 12 | } 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /support.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Support 5 | 6 | 7 | 8 |

9 | If you do not redirect please visit: 10 | https://codedthemes.support-hub.io/tickets 11 |

12 | 13 | 14 | -------------------------------------------------------------------------------- /src/routes/index.jsx: -------------------------------------------------------------------------------- 1 | import { createBrowserRouter } from 'react-router-dom'; 2 | 3 | // routes 4 | import MainRoutes from './MainRoutes'; 5 | import PagesRoutes from './PagesRoutes'; 6 | 7 | // ==============================|| ROUTING RENDER ||============================== // 8 | 9 | const router = createBrowserRouter([MainRoutes, PagesRoutes], { 10 | basename: import.meta.env.VITE_APP_BASE_URL 11 | }); 12 | 13 | export default router; 14 | -------------------------------------------------------------------------------- /src/themes/overrides/Popper.js: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - POPPER ||============================== // 2 | 3 | export default function Popper(theme) { 4 | return { 5 | MuiPopper: { 6 | styleOverrides: { 7 | root: { 8 | zIndex: 1201, 9 | '& .MuiPaper-root': { 10 | border: `1px solid ${theme.palette.divider}` 11 | } 12 | } 13 | } 14 | } 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /discord.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Discord Community | Materially - Admin Dashboard Template 5 | 6 | 7 | 8 |

9 | If you do not redirect please visit : 10 | https://discord.com/invite/p2E2WhCb6s 11 |

12 | 13 | 14 | -------------------------------------------------------------------------------- /src/components/loader/index.jsx: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import LinearProgress from '@mui/material/LinearProgress'; 3 | import Box from '@mui/material/Box'; 4 | 5 | // ==============================|| LOADER ||============================== // 6 | 7 | export default function Loader() { 8 | return ( 9 | 10 | 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /src/themes/overrides/Checkbox.js: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - CHECKBOX ||============================== // 2 | 3 | export default function Checkbox(theme) { 4 | return { 5 | MuiCheckbox: { 6 | styleOverrides: { 7 | root: { 8 | color: theme.palette.text.secondary 9 | }, 10 | indeterminate: { 11 | color: theme.palette.text.primary 12 | } 13 | } 14 | } 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /src/main.jsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | 6 | // google-fonts 7 | import '@fontsource/poppins/400.css'; 8 | import '@fontsource/poppins/500.css'; 9 | import '@fontsource/poppins/600.css'; 10 | import '@fontsource/poppins/700.css'; 11 | 12 | createRoot(document.getElementById('root')).render( 13 | 14 | 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /src/themes/overrides/CardHeader.js: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - CARD HEADER ||============================== // 2 | 3 | export default function CardHeader(theme) { 4 | return { 5 | MuiCardHeader: { 6 | styleOverrides: { 7 | root: { 8 | padding: 24 9 | }, 10 | title: { 11 | ...theme.typography.h6, 12 | color: theme.palette.text.dark 13 | } 14 | } 15 | } 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /src/themes/overrides/FormHelperText.js: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import { alpha } from '@mui/material/styles'; 3 | 4 | // ==============================|| OVERRIDES - FORM HELPER TEXT ||============================== // 5 | 6 | export default function FormHelperText(theme) { 7 | return { 8 | MuiFormHelperText: { 9 | styleOverrides: { 10 | root: { 11 | color: alpha(theme.palette.text.secondary, 0.73) 12 | } 13 | } 14 | } 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /src/sections/dashboard/chart/card-data/revenue-card-data.jsx: -------------------------------------------------------------------------------- 1 | // chart data 2 | import { revenueChartData } from '../chart-data/revenue-chart-data'; 3 | 4 | export const revenueCardData = { 5 | title: 'Total Revenue', 6 | chartData: revenueChartData, 7 | bottomData: [ 8 | { label: 'Youtube', value: '+16.85', color: 'primary.main' }, 9 | { label: 'Facebook', value: '+45.36', color: 'success.main' }, 10 | { label: 'Twitter', value: '-50.69', color: 'warning.main' } 11 | ] 12 | }; 13 | -------------------------------------------------------------------------------- /src/themes/shadow.js: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import { alpha } from '@mui/material/styles'; 3 | 4 | // ==============================|| DEFAULT THEME - SHADOWS ||============================== // 5 | 6 | export default function Shadows(theme) { 7 | const secondaryDarker = theme.palette.secondary.darker; 8 | console.log('secondaryDarker:', secondaryDarker); 9 | return { 10 | posterShadow: `0px 16px 32px ${alpha(secondaryDarker, 0.15)}, 0px 8px 16px ${alpha(secondaryDarker, 0.1)}` 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /src/themes/overrides/SvgIcon.js: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - SVGICON ||============================== // 2 | 3 | export default function CardHeader() { 4 | return { 5 | MuiSvgIcon: { 6 | styleOverrides: { 7 | root: { 8 | fontSize: '1.3rem' 9 | }, 10 | fontSizeInherit: { 11 | fontSize: 'inherit' 12 | }, 13 | fontSizeLarge: { 14 | fontSize: '2.1875rem' 15 | } 16 | } 17 | } 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /documentation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Documentation 5 | 6 | 7 | 8 |

9 | If you do not redirect please visit : 10 | https://codedthemes.gitbook.io/materially-react-material-documentation/ 13 |

14 | 15 | 16 | -------------------------------------------------------------------------------- /src/views/auth/Register.jsx: -------------------------------------------------------------------------------- 1 | // project imports 2 | import CommonAuthLayout from './CommonAuthLayout'; 3 | import AuthRegister from 'sections/auth/AuthRegister'; 4 | 5 | // ==============================|| REGISTER ||============================== // 6 | 7 | export default function Register() { 8 | return ( 9 | 10 | {/* Register form */} 11 | 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /src/views/auth/Login.jsx: -------------------------------------------------------------------------------- 1 | // project imports 2 | import CommonAuthLayout from './CommonAuthLayout'; 3 | import AuthLogin from 'sections/auth/AuthLogin'; 4 | 5 | // ==============================|| LOGIN ||============================== // 6 | 7 | export default function Login() { 8 | return ( 9 | 14 | {/* Login form */} 15 | 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/views/dashboard/default/data/traffic-source-card-data.jsx: -------------------------------------------------------------------------------- 1 | export const trafficSourceData = { 2 | cardTitle: 'Traffic Sources', 3 | items: [ 4 | { label: 'Direct', percentage: 80, progressValue: 80, progressColor: 'primary' }, 5 | { label: 'Social', percentage: 50, progressValue: 50, progressColor: 'secondary' }, 6 | { label: 'Referral', percentage: 20, progressValue: 20, progressColor: 'primary' }, 7 | { label: 'Bounce', percentage: 60, progressValue: 60, progressColor: 'secondary' }, 8 | { label: 'Internet', percentage: 40, progressValue: 40, progressColor: 'primary' } 9 | ] 10 | }; 11 | -------------------------------------------------------------------------------- /src/sections/dashboard/chart/chart-data/revenue-chart-data.js: -------------------------------------------------------------------------------- 1 | export const revenueChartData = { 2 | options: { 3 | dataLabels: { 4 | enabled: false 5 | }, 6 | yaxis: { 7 | min: 0, 8 | max: 100 9 | }, 10 | labels: ['YouTube', 'Facebook', 'Twitter'], 11 | legend: { 12 | show: true, 13 | position: 'bottom', 14 | fontFamily: 'inherit', 15 | labels: { 16 | colors: 'inherit' 17 | }, 18 | itemMargin: { 19 | horizontal: 10, 20 | vertical: 5 21 | } 22 | } 23 | }, 24 | series: [1258, 975, 500] 25 | }; 26 | -------------------------------------------------------------------------------- /src/enum.js: -------------------------------------------------------------------------------- 1 | /** Avatar custom props `size` enum */ 2 | export let AvatarSize; 3 | 4 | (function (AvatarSize) { 5 | AvatarSize['BADGE'] = 'badge'; 6 | AvatarSize['XS'] = 'xs'; 7 | AvatarSize['SM'] = 'sm'; 8 | AvatarSize['MD'] = 'md'; 9 | AvatarSize['LG'] = 'lg'; 10 | AvatarSize['XL'] = 'xl'; 11 | })(AvatarSize || (AvatarSize = {})); 12 | 13 | /** Main Card type enum */ 14 | export let CardVariant; 15 | 16 | (function (CardVariant) { 17 | CardVariant['DEFAULT'] = 'default'; 18 | CardVariant['FILLED'] = 'filled'; 19 | CardVariant['OUTLINED'] = 'outlined'; 20 | })(CardVariant || (CardVariant = {})); 21 | -------------------------------------------------------------------------------- /src/components/Loadable.jsx: -------------------------------------------------------------------------------- 1 | import { Suspense } from 'react'; 2 | 3 | // project imports 4 | import Loader from './loader'; 5 | 6 | // ==============================|| LOADABLE - LAZY LOADING ||============================== // 7 | 8 | /** 9 | * Higher-order component for lazy loading with suspense. 10 | * 11 | * @param Component - The component to be lazily loaded. 12 | * @returns A wrapped component with suspense fallback. 13 | */ 14 | export default function Loadable(Component) { 15 | return (props) => ( 16 | }> 17 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /src/views/dashboard/default/data/sales-line-chart-card-data.jsx: -------------------------------------------------------------------------------- 1 | // assets 2 | import TrendingDownIcon from '@mui/icons-material/TrendingDown'; 3 | 4 | // chart data 5 | import { salesLineChart } from 'sections/dashboard/chart/chart-data/sales-line-chart'; 6 | 7 | export const salesLineCardData = { 8 | chartData: salesLineChart, 9 | footerData: [ 10 | { 11 | value: '$4230', 12 | label: 'Total Revenue' 13 | }, 14 | { 15 | value: '321', 16 | label: 'Today Sales' 17 | } 18 | ], 19 | title: 'Sales Per Day', 20 | percentage: '3%', 21 | icon: TrendingDownIcon, 22 | bgColor: 'primary.main' 23 | }; 24 | -------------------------------------------------------------------------------- /src/menu-items/other.js: -------------------------------------------------------------------------------- 1 | // assets 2 | import ContactSupportOutlinedIcon from '@mui/icons-material/ContactSupportOutlined'; 3 | import BlockOutlinedIcon from '@mui/icons-material/BlockOutlined'; 4 | 5 | // ==============================|| MENU ITEMS - SUPPORT ||============================== // 6 | 7 | const other = { 8 | id: 'support', 9 | title: 'support', 10 | type: 'group', 11 | icon: ContactSupportOutlinedIcon, 12 | children: [ 13 | { 14 | id: 'disabled-menu', 15 | title: 'Disabled Menu', 16 | type: 'item', 17 | icon: BlockOutlinedIcon, 18 | disabled: true 19 | } 20 | ] 21 | }; 22 | 23 | export default other; 24 | -------------------------------------------------------------------------------- /src/themes/overrides/Paper.js: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import { alpha } from '@mui/material/styles'; 3 | 4 | // ==============================|| OVERRIDES - PAPER ||============================== // 5 | 6 | export default function Paper(theme) { 7 | const shadowColor = theme.palette.text.primary; 8 | 9 | return { 10 | MuiPaper: { 11 | styleOverrides: { 12 | root: { backgroundImage: 'none' }, 13 | elevation1: { 14 | boxShadow: `0 4px 6px -2px ${alpha(shadowColor, 0.12)}, 0 2px 2px -1px ${alpha(shadowColor, 0.05)}` 15 | }, 16 | rounded: { 17 | borderRadius: 10 18 | } 19 | } 20 | } 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Materially | Material UI React Dashboard Template 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/menu-items/dashboard.js: -------------------------------------------------------------------------------- 1 | // assets 2 | import NavigationOutlinedIcon from '@mui/icons-material/NavigationOutlined'; 3 | import HomeOutlinedIcon from '@mui/icons-material/HomeOutlined'; 4 | 5 | // ==============================|| MENU ITEMS - DASHBOARD ||============================== // 6 | 7 | const dashboard = { 8 | id: 'dashboard', 9 | title: 'materially', 10 | caption: 'Dashboard', 11 | icon: NavigationOutlinedIcon, 12 | type: 'group', 13 | children: [ 14 | { 15 | id: 'dashboards', 16 | title: 'Dashboard', 17 | type: 'item', 18 | icon: HomeOutlinedIcon, 19 | url: '/dashboard/default', 20 | breadcrumbs: false 21 | } 22 | ] 23 | }; 24 | 25 | export default dashboard; 26 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx", 18 | "baseUrl": "src" 19 | }, 20 | "exclude": ["node_modules", "eslint.config.mjs"], 21 | "include": ["src", "**/*.js", "**/*.jsx", "src/**/*"], 22 | "references": [{ "path": "./jsconfig.node.json" }] 23 | } 24 | -------------------------------------------------------------------------------- /vite.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig, loadEnv } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | import jsconfigPaths from 'vite-jsconfig-paths'; 4 | 5 | export default defineConfig(({ mode }) => { 6 | const env = loadEnv(mode, process.cwd(), ''); 7 | const APP_BASE_URL = `${env.VITE_APP_BASE_URL}`; 8 | const PORT = 3000; 9 | 10 | return { 11 | server: { 12 | // this ensures that the browser opens upon server start 13 | open: true, 14 | // this sets a default port to 3000 15 | port: PORT, 16 | host: true 17 | }, 18 | preview: { 19 | open: true, 20 | host: true 21 | }, 22 | define: { 23 | global: 'window' 24 | }, 25 | base: APP_BASE_URL, 26 | plugins: [react(), jsconfigPaths()] 27 | }; 28 | }); 29 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | /* simpebar styles */ 2 | @import 'simplebar-react/dist/simplebar.min.css'; 3 | 4 | @import 'simplebar-react/dist/simplebar.min.css'; 5 | 6 | /* apex chart styles */ 7 | .apexcharts-legend-marker { 8 | margin-right: 8px !important; 9 | } 10 | 11 | .apexcharts-legend-text { 12 | padding-right: 4px; 13 | } 14 | 15 | .apexcharts-canvas .apexcharts-svg { 16 | background: transparent !important; 17 | } 18 | 19 | /* If .apexcharts-tooltip-title is missing */ 20 | .apexcharts-tooltip:not(:has(.apexcharts-tooltip-title)) > .apexcharts-active { 21 | padding-bottom: 0; 22 | } 23 | 24 | /* If .apexcharts-tooltip-title is present but empty */ 25 | .apexcharts-tooltip:has(.apexcharts-tooltip-title:empty) > .apexcharts-active { 26 | padding-bottom: 0; 27 | } 28 | 29 | .apexcharts-tooltip-text-y-label:empty + .apexcharts-tooltip-text-y-value { 30 | margin-left: 0; 31 | } 32 | -------------------------------------------------------------------------------- /src/routes/PagesRoutes.jsx: -------------------------------------------------------------------------------- 1 | import { lazy } from 'react'; 2 | 3 | // project imports 4 | import Loadable from 'components/Loadable'; 5 | import MinimalLayout from 'layouts/minimalLayout'; 6 | 7 | // pages 8 | const LoginPage = Loadable(lazy(() => import('views/auth/Login'))); 9 | const RegisterPage = Loadable(lazy(() => import('views/auth/Register'))); 10 | 11 | // ==============================|| PAGES ROUTES ||============================== // 12 | 13 | const PagesRoutes = { 14 | path: 'pages', 15 | element: , 16 | children: [ 17 | { 18 | path: 'auth', 19 | children: [ 20 | { 21 | path: 'login', 22 | element: 23 | }, 24 | { 25 | path: 'register', 26 | element: 27 | } 28 | ] 29 | } 30 | ] 31 | }; 32 | 33 | export default PagesRoutes; 34 | -------------------------------------------------------------------------------- /src/layouts/MainLayout/Drawer/DrawerContent/Navigation/index.jsx: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import Typography from '@mui/material/Typography'; 3 | import Box from '@mui/material/Box'; 4 | 5 | // project imports 6 | import menuItems from 'menu-items'; 7 | import NavGroup from './NavGroup'; 8 | 9 | // ==============================|| DRAWER CONTENT - RESPONSIVE DRAWER ||============================== // 10 | 11 | export default function NavigationDrawer() { 12 | const navGroups = menuItems.items.map((item, index) => { 13 | switch (item.type) { 14 | case 'group': 15 | return ; 16 | default: 17 | return ( 18 | 19 | Fix - Navigation Group 20 | 21 | ); 22 | } 23 | }); 24 | 25 | return {navGroups}; 26 | } 27 | -------------------------------------------------------------------------------- /src/views/pages/SamplePage.jsx: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import Typography from '@mui/material/Typography'; 3 | 4 | // project imports 5 | import MainCard from 'components/cards/MainCard'; 6 | 7 | // ==============================|| SAMPLE PAGE ||============================== // 8 | 9 | export default function SamplePage() { 10 | return ( 11 | 12 | 13 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim 14 | ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in 15 | reprehenderit in voluptate velit esse cillum dolore eu fugiatnulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in 16 | culpa qui officia deserunt mollitanim id est laborum. 17 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /src/menu-items/ui-component.js: -------------------------------------------------------------------------------- 1 | // assets 2 | import HardwareOutlinedIcon from '@mui/icons-material/HardwareOutlined'; 3 | import AppsOutlinedIcon from '@mui/icons-material/AppsOutlined'; 4 | import FontDownloadIcon from '@mui/icons-material/FontDownload'; 5 | 6 | // ==============================|| MENU ITEMS - UI COMPONENT ||============================== // 7 | 8 | const uiComponent = { 9 | id: 'utils', 10 | title: 'utils', 11 | type: 'group', 12 | icon: HardwareOutlinedIcon, 13 | children: [ 14 | { 15 | id: 'util-icons', 16 | title: 'Icons', 17 | type: 'item', 18 | url: 'https://mui.com/material-ui/material-icons/', 19 | icon: AppsOutlinedIcon, 20 | external: true, 21 | target: '_blank' 22 | }, 23 | { 24 | id: 'typography', 25 | title: 'Typography', 26 | type: 'item', 27 | url: '/components/typography', 28 | icon: FontDownloadIcon 29 | } 30 | ] 31 | }; 32 | 33 | export default uiComponent; 34 | -------------------------------------------------------------------------------- /src/views/dashboard/default/data/revenue-card-data.jsx: -------------------------------------------------------------------------------- 1 | // assets 2 | import AccountCircleTwoTone from '@mui/icons-material/AccountCircleTwoTone'; 3 | import LocalMallTwoToneIcon from '@mui/icons-material/LocalMallTwoTone'; 4 | import MonetizationOnTwoToneIcon from '@mui/icons-material/MonetizationOnTwoTone'; 5 | 6 | export const revenueCardData = [ 7 | { 8 | title: 'Revenue', 9 | value: '$42,562', 10 | content: '$50,032 Last Month', 11 | iconPrimary: MonetizationOnTwoToneIcon, 12 | color: 'warning.main', 13 | fullWidth: true 14 | }, 15 | { 16 | title: 'Orders Received', 17 | value: '486', 18 | content: '20% Increase', 19 | iconPrimary: AccountCircleTwoTone, 20 | color: 'primary.main', 21 | fullWidth: false 22 | }, 23 | { 24 | title: 'Total Sales', 25 | value: '1641', 26 | content: '$1,055 Revenue Generated', 27 | iconPrimary: LocalMallTwoToneIcon, 28 | color: 'success.main', 29 | fullWidth: false 30 | } 31 | ]; 32 | -------------------------------------------------------------------------------- /src/sections/dashboard/chart/chart-data/sales-line-chart.js: -------------------------------------------------------------------------------- 1 | export const salesLineChart = { 2 | options: { 3 | chart: { 4 | type: 'line', 5 | height: 115, 6 | sparkline: { 7 | enabled: true 8 | } 9 | }, 10 | dataLabels: { 11 | enabled: false 12 | }, 13 | stroke: { 14 | curve: 'smooth', 15 | width: 3 16 | }, 17 | yaxis: { 18 | min: 20, 19 | max: 100, 20 | labels: { 21 | show: false 22 | } 23 | }, 24 | tooltip: { 25 | theme: 'dark', 26 | fixed: { 27 | enabled: false 28 | }, 29 | x: { 30 | show: false 31 | }, 32 | y: { 33 | title: { 34 | formatter: () => 'Sales/Order Per Day' 35 | } 36 | }, 37 | marker: { 38 | show: false 39 | } 40 | } 41 | }, 42 | series: [ 43 | { 44 | name: 'series1', 45 | data: [55, 35, 75, 25, 90, 50] 46 | } 47 | ] 48 | }; 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 CodedThemes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/themes/overrides/ListItemButton.js: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - LISTITEM BUTTON ||============================== // 2 | 3 | export default function ListItemButton(theme) { 4 | return { 5 | MuiListItemButton: { 6 | styleOverrides: { 7 | root: { 8 | color: theme.palette.text.primary, 9 | paddingTop: '12px', 10 | paddingBottom: '12px', 11 | '&.Mui-selected': { 12 | '& .MuiListItemIcon-root': { 13 | color: theme.palette.menu.selected 14 | }, 15 | color: theme.palette.menu.selected, 16 | backgroundColor: theme.palette.menu.hover 17 | }, 18 | '&:hover': { 19 | backgroundColor: theme.palette.menu.hover, 20 | color: theme.palette.menu.selected, 21 | '& .MuiListItemIcon-root': { 22 | color: theme.palette.menu.selected 23 | } 24 | }, 25 | button: { 26 | '&:hover': { 27 | backgroundColor: theme.palette.menu.hover 28 | } 29 | } 30 | } 31 | } 32 | } 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /src/themes/overrides/index.js: -------------------------------------------------------------------------------- 1 | // third party 2 | import { merge } from 'lodash-es'; 3 | 4 | // project imports 5 | import Avatar from './Avatar'; 6 | import CardActions from './CardActions'; 7 | import CardContent from './CardContent'; 8 | import CardHeader from './CardHeader'; 9 | import Checkbox from './Checkbox'; 10 | import Chip from './Chip'; 11 | import FormHelperText from './FormHelperText'; 12 | import ListItem from './ListItem'; 13 | import ListItemButton from './ListItemButton'; 14 | import ListItemIcon from './ListItemIcon'; 15 | import Paper from './Paper'; 16 | import Popper from './Popper'; 17 | import SvgIcon from './SvgIcon'; 18 | 19 | // ==============================|| OVERRIDES - MAIN ||============================== // 20 | 21 | export default function ComponentsOverrides(theme) { 22 | return merge( 23 | Avatar(theme), 24 | CardActions(), 25 | CardContent(), 26 | CardHeader(theme), 27 | Checkbox(theme), 28 | Chip(theme), 29 | FormHelperText(theme), 30 | ListItem(theme), 31 | ListItemButton(theme), 32 | ListItemIcon(theme), 33 | Paper(theme), 34 | Popper(theme), 35 | SvgIcon() 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /src/layouts/MainLayout/Drawer/DrawerContent/index.jsx: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import Stack from '@mui/material/Stack'; 3 | 4 | // project imports 5 | import NavigationDrawer from './Navigation'; 6 | import SimpleBar from 'components/third-party/SimpleBar'; 7 | import { AppBar, CardMedia, Toolbar } from '@mui/material'; 8 | 9 | // assets 10 | import logo from 'assets/images/logo.svg'; 11 | 12 | // ==============================|| DRAWER - CONTENT ||============================== // 13 | 14 | export default function DrawerContent() { 15 | const contentHeight = `calc(100vh - 64px)`; 16 | 17 | return ( 18 | <> 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /src/routes/MainRoutes.jsx: -------------------------------------------------------------------------------- 1 | import { lazy } from 'react'; 2 | 3 | // project imports 4 | import Loadable from 'components/Loadable'; 5 | import MainLayout from 'layouts/MainLayout'; 6 | 7 | // pages 8 | const DashboardDefault = Loadable(lazy(() => import('views/dashboard/default'))); 9 | const SamplePage = Loadable(lazy(() => import('views/pages/SamplePage'))); 10 | 11 | // utils 12 | const UtilsTypography = Loadable(lazy(() => import('views/components/Typography'))); 13 | 14 | // ==============================|| MAIN ROUTES ||============================== // 15 | 16 | const MainRoutes = { 17 | path: '/', 18 | element: , 19 | children: [ 20 | { 21 | path: '/', 22 | element: 23 | }, 24 | { 25 | path: '/dashboard/default', 26 | element: 27 | }, 28 | { 29 | path: '/sample-page', 30 | element: 31 | }, 32 | { 33 | path: 'components', 34 | children: [ 35 | { 36 | path: 'typography', 37 | element: 38 | } 39 | ] 40 | } 41 | ] 42 | }; 43 | 44 | export default MainRoutes; 45 | -------------------------------------------------------------------------------- /src/themes/index.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useMemo } from 'react'; 3 | 4 | // material-ui 5 | import { createTheme, ThemeProvider } from '@mui/material/styles'; 6 | import CssBaseline from '@mui/material/CssBaseline'; 7 | 8 | // project imports 9 | import palette from './palette'; 10 | import componentsOverride from './overrides'; 11 | import typography from './typography'; 12 | 13 | // ==============================|| DEFAULT THEME - MAIN ||============================== // 14 | 15 | export default function ThemeCustomization({ children }) { 16 | const themePalette = useMemo(() => palette('light'), []); 17 | 18 | const themeDefault = createTheme({ 19 | palette: themePalette 20 | }); 21 | 22 | // create duplicate theme due to responsive typography and fontFamily 23 | const theme = createTheme({ 24 | ...themeDefault, 25 | typography: typography() 26 | }); 27 | 28 | theme.components = componentsOverride(theme); 29 | 30 | return ( 31 | 32 | 33 | {children} 34 | 35 | ); 36 | } 37 | 38 | ThemeCustomization.propTypes = { children: PropTypes.any }; 39 | -------------------------------------------------------------------------------- /src/utils/passwordStrength.js: -------------------------------------------------------------------------------- 1 | // has number 2 | const hasNumber = (number) => new RegExp(/[0-9]/).test(number); 3 | 4 | // has mix of small and capitals 5 | const hasMixed = (number) => new RegExp(/[a-z]/).test(number) && new RegExp(/[A-Z]/).test(number); 6 | 7 | // has special chars 8 | const hasSpecial = (number) => new RegExp(/[!#@$%^&*)(+=._-]/).test(number); 9 | 10 | // set color based on password strength 11 | export const strengthColor = (count) => { 12 | if (count < 2) return { label: 'Poor', color: 'error.main' }; 13 | if (count < 3) return { label: 'Weak', color: 'warning.main' }; 14 | if (count < 4) return { label: 'Normal', color: 'warning.dark' }; 15 | if (count < 5) return { label: 'Good', color: 'success.main' }; 16 | if (count < 6) return { label: 'Strong', color: 'success.dark' }; 17 | return { label: 'Poor', color: 'error.main' }; 18 | }; 19 | 20 | // password strength indicator 21 | export const strengthIndicator = (number = '') => { 22 | let strengths = 0; 23 | if (number.length > 5) strengths += 1; 24 | if (number.length > 7) strengths += 1; 25 | if (hasNumber(number)) strengths += 1; 26 | if (hasSpecial(number)) strengths += 1; 27 | if (hasMixed(number)) strengths += 1; 28 | return strengths; 29 | }; 30 | -------------------------------------------------------------------------------- /src/assets/images/social-google.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.github/workflows/prod.yml: -------------------------------------------------------------------------------- 1 | name: Node - SSH deploy 2 | 3 | # Controls when the action will run. 4 | on: 5 | # Triggers the workflow on push or pull request events but only for the master branch 6 | push: 7 | branches: 8 | - main 9 | 10 | jobs: 11 | SFTP-deploy: 12 | name: 🎉 Deploy 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: 🚚 Get latest code 17 | uses: actions/checkout@v4 18 | 19 | - name: Use Node.js 22 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version: '22' 23 | 24 | - name: 🔨 Build Project 25 | run: | 26 | corepack enable 27 | yarn set version 4.9.1 28 | yarn 29 | yarn build 30 | 31 | - name: 📂 Deploy to Server 32 | uses: easingthemes/ssh-deploy@main 33 | env: 34 | SSH_PRIVATE_KEY: ${{ secrets.SERVER_SSH_KEY }} 35 | # ARGS: "-rltgoDzvO --delete" 36 | SOURCE: 'dist/' 37 | REMOTE_HOST: 82.29.156.38 38 | REMOTE_USER: u106957989 39 | REMOTE_PORT: '65002' 40 | TARGET: domains/codedthemes.com/public_html/demos/admin-templates/materially/react/free 41 | EXCLUDE: '/dist/, /node_modules/' 42 | -------------------------------------------------------------------------------- /.github/workflows/stage.yml: -------------------------------------------------------------------------------- 1 | name: Node - SSH deploy 2 | 3 | # Controls when the action will run. 4 | on: 5 | # Triggers the workflow on push or pull request events but only for the master branch 6 | push: 7 | branches: 8 | - stage* 9 | 10 | jobs: 11 | SFTP-deploy: 12 | name: 🎉 Deploy 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: 🚚 Get latest code 17 | uses: actions/checkout@v4 18 | 19 | - name: Use Node.js 22 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version: '22' 23 | 24 | - name: 🔨 Build Project 25 | run: | 26 | corepack enable 27 | yarn set version 4.9.1 28 | yarn 29 | yarn build-stage 30 | 31 | - name: 📂 Deploy to Server 32 | uses: easingthemes/ssh-deploy@main 33 | env: 34 | SSH_PRIVATE_KEY: ${{ secrets.SERVER_SSH_KEY }} 35 | # ARGS: "-rltgoDzvO --delete" 36 | SOURCE: 'dist/' 37 | REMOTE_HOST: 82.29.156.38 38 | REMOTE_USER: u106957989 39 | REMOTE_PORT: '65002' 40 | TARGET: domains/codedthemes.com/public_html/demos/admin-templates/materially/react/free/stage 41 | EXCLUDE: '/dist/, /node_modules/' 42 | -------------------------------------------------------------------------------- /src/components/cards/TrafficSourceCard.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | // material-ui 3 | import LinearProgress from '@mui/material/LinearProgress'; 4 | import Stack from '@mui/material/Stack'; 5 | import Typography from '@mui/material/Typography'; 6 | 7 | // project imports 8 | import { GRID_SPACING } from 'config'; 9 | import MainCard from './MainCard'; 10 | 11 | // ==============================|| TRAFFIC SOURCE CARD ||============================== // 12 | 13 | export default function TrafficSourceCard({ cardTitle, items }) { 14 | return ( 15 | 16 | 17 | {items.map((item, index) => ( 18 | 19 | 20 | {item.label} 21 | 22 | {item.percentage}% 23 | 24 | 25 | 26 | 27 | ))} 28 | 29 | 30 | ); 31 | } 32 | 33 | TrafficSourceCard.propTypes = { cardTitle: PropTypes.string, items: PropTypes.object }; 34 | -------------------------------------------------------------------------------- /src/states/menu.js: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react'; 2 | 3 | // third party 4 | import useSWR, { mutate } from 'swr'; 5 | 6 | const initialState = { 7 | openedItem: '', 8 | isDashboardDrawerOpened: false 9 | }; 10 | 11 | export const endpoints = { 12 | key: 'api/menu', 13 | master: 'master' 14 | }; 15 | 16 | export function useGetMenuMaster() { 17 | // to fetch initial state based on endpoints 18 | 19 | const { data, isLoading } = useSWR(endpoints.key + endpoints.master, () => initialState, { 20 | revalidateIfStale: false, 21 | revalidateOnFocus: false, 22 | revalidateOnReconnect: false 23 | }); 24 | 25 | const memoizedValue = useMemo( 26 | () => ({ 27 | menuMaster: data ?? initialState, 28 | menuMasterLoading: isLoading 29 | }), 30 | [data, isLoading] 31 | ); 32 | 33 | return memoizedValue; 34 | } 35 | 36 | export function handlerDrawerOpen(isDashboardDrawerOpened) { 37 | // to update `isDashboardDrawerOpened` local state based on key 38 | 39 | mutate( 40 | endpoints.key + endpoints.master, 41 | (currentMenuMaster = initialState) => { 42 | return { ...currentMenuMaster, isDashboardDrawerOpened }; 43 | }, 44 | false 45 | ); 46 | } 47 | 48 | export function handlerActiveItem(openedItem) { 49 | // to update `openedItem` local state based on key 50 | 51 | mutate( 52 | endpoints.key + endpoints.master, 53 | (currentMenuMaster = initialState) => { 54 | return { ...currentMenuMaster, openedItem }; 55 | }, 56 | false 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /src/views/dashboard/default/data/report-card-data.jsx: -------------------------------------------------------------------------------- 1 | // assets 2 | import CalendarTodayOutlinedIcon from '@mui/icons-material/CalendarTodayOutlined'; 3 | import DescriptionOutlinedIcon from '@mui/icons-material/DescriptionOutlined'; 4 | import MonetizationOnTwoToneIcon from '@mui/icons-material/MonetizationOnTwoTone'; 5 | import ThumbUpAltTwoToneIcon from '@mui/icons-material/ThumbUpAltTwoTone'; 6 | import TrendingDownIcon from '@mui/icons-material/TrendingDown'; 7 | import TrendingUpIcon from '@mui/icons-material/TrendingUp'; 8 | 9 | export const reportCardData = [ 10 | { 11 | counter: '$30200', 12 | title: 'All Earnings', 13 | color: 'warning.main', 14 | footerData: '10% changes on profit', 15 | iconPrimary: MonetizationOnTwoToneIcon, 16 | iconFooter: TrendingUpIcon, 17 | coloredIcon: true 18 | }, 19 | { 20 | counter: '145', 21 | title: 'Task', 22 | color: 'error.main', 23 | footerData: '28% task performance', 24 | iconPrimary: CalendarTodayOutlinedIcon, 25 | iconFooter: TrendingDownIcon, 26 | coloredIcon: true 27 | }, 28 | { 29 | counter: '290+', 30 | title: 'Page Views', 31 | color: 'success.main', 32 | footerData: '10k daily views', 33 | iconPrimary: DescriptionOutlinedIcon, 34 | iconFooter: TrendingUpIcon, 35 | coloredIcon: true 36 | }, 37 | { 38 | counter: '500', 39 | title: 'Downloads', 40 | color: 'primary.main', 41 | footerData: '1k download in App store', 42 | iconPrimary: ThumbUpAltTwoToneIcon, 43 | iconFooter: TrendingUpIcon, 44 | coloredIcon: true 45 | } 46 | ]; 47 | -------------------------------------------------------------------------------- /src/themes/typography.js: -------------------------------------------------------------------------------- 1 | // ==============================|| DEFAULT - TYPOGRAPHY ||============================== // 2 | 3 | export default function typography() { 4 | return { 5 | fontFamily: `'Poppins', sans-serif`, 6 | h6: { 7 | fontWeight: 600, 8 | fontSize: '0.875rem' 9 | }, 10 | h5: { 11 | fontSize: '1.125rem', 12 | fontWeight: 600 13 | }, 14 | h4: { 15 | fontSize: '1.25rem', 16 | fontWeight: 500 17 | }, 18 | h3: { 19 | fontSize: '1.5rem', 20 | fontWeight: 600 21 | }, 22 | h2: { 23 | fontSize: '2rem', 24 | fontWeight: 600 25 | }, 26 | h1: { 27 | fontSize: '2.2rem', 28 | fontWeight: 600 29 | }, 30 | subtitle1: { 31 | fontSize: '0.875rem', 32 | fontWeight: 500, 33 | lineHeight: '1.643em' 34 | }, 35 | subtitle2: { 36 | fontSize: '0.8125rem', 37 | fontWeight: 400 38 | }, 39 | caption: { 40 | fontSize: '0.68rem', 41 | fontWeight: 500 42 | }, 43 | body1: { 44 | fontSize: '0.875rem', 45 | fontWeight: 400, 46 | lineHeight: '1.643em' 47 | }, 48 | body2: { 49 | letterSpacing: '0em', 50 | fontWeight: 400, 51 | lineHeight: '1.643em' 52 | }, 53 | menuCaption: { 54 | fontSize: '0.6875rem', 55 | fontWeight: 600, 56 | padding: '5px 15px 5px', 57 | textTransform: 'uppercase', 58 | marginTop: '10px' 59 | }, 60 | subMenuCaption: { 61 | fontSize: '0.6875rem', 62 | fontWeight: 400, 63 | textTransform: 'capitalize' 64 | } 65 | }; 66 | } 67 | -------------------------------------------------------------------------------- /src/layouts/MainLayout/index.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useMemo } from 'react'; 2 | import { Outlet } from 'react-router-dom'; 3 | 4 | // material-ui 5 | import useMediaQuery from '@mui/material/useMediaQuery'; 6 | import Stack from '@mui/material/Stack'; 7 | import Toolbar from '@mui/material/Toolbar'; 8 | import Box from '@mui/material/Box'; 9 | 10 | // project imports 11 | import Drawer from './Drawer'; 12 | import Header from './Header'; 13 | import Breadcrumbs from 'components/Breadcrumbs'; 14 | 15 | import { DRAWER_WIDTH } from 'config'; 16 | import { handlerDrawerOpen, useGetMenuMaster } from 'states/menu'; 17 | 18 | // ==============================|| MAIN LAYOUT ||============================== // 19 | 20 | export default function MainLayout() { 21 | const upLG = useMediaQuery((theme) => theme.breakpoints.up('lg')); 22 | 23 | const { menuMaster } = useGetMenuMaster(); 24 | const drawerOpen = menuMaster.isDashboardDrawerOpened; 25 | 26 | useEffect(() => { 27 | handlerDrawerOpen(upLG); 28 | }, [upLG]); 29 | 30 | // drawer toggle handler on resize window 31 | // eslint-disable-next-line react-hooks/exhaustive-deps 32 | const drawer = useMemo(() => , [drawerOpen]); 33 | 34 | return ( 35 | 36 |
37 | {drawer} 38 | 46 | 47 | 48 | 49 | 50 | 51 | ); 52 | } 53 | -------------------------------------------------------------------------------- /src/components/cards/ReportCard.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | // material-ui 4 | import Stack from '@mui/material/Stack'; 5 | import Typography from '@mui/material/Typography'; 6 | 7 | // project imports 8 | import MainCard from './MainCard'; 9 | 10 | // ==============================|| REPORT CARD ||============================== // 11 | 12 | export default function ReportCard({ counter, title, iconPrimary: IconPrimary, footerData, color, iconFooter: IconFooter, coloredIcon }) { 13 | return ( 14 | 17 | {footerData} 18 | {IconFooter && } 19 | 20 | } 21 | actionsDivider={false} 22 | cardActionsSX={{ bgcolor: color, py: 1.5 }} 23 | > 24 | 25 | 26 | 27 | {counter} 28 | 29 | {title} 30 | 31 | {IconPrimary && } 32 | 33 | 34 | ); 35 | } 36 | 37 | ReportCard.propTypes = { 38 | counter: PropTypes.string, 39 | title: PropTypes.string, 40 | iconPrimary: PropTypes.any, 41 | footerData: PropTypes.string, 42 | color: PropTypes.string, 43 | iconFooter: PropTypes.any, 44 | coloredIcon: PropTypes.bool 45 | }; 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "materially-free-react-admin-template", 3 | "version": "4.0.0", 4 | "license": "MIT", 5 | "type": "module", 6 | "scripts": { 7 | "start": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview", 10 | "lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\"", 11 | "lint:fix": "eslint --fix \"src/**/*.{js,jsx,ts,tsx}\"", 12 | "prettier": "prettier --write \"src/**/*.{js,jsx,ts,tsx}\"" 13 | }, 14 | "dependencies": { 15 | "@emotion/cache": "11.14.0", 16 | "@emotion/react": "11.14.0", 17 | "@emotion/styled": "11.14.0", 18 | "@fontsource/poppins": "5.2.6", 19 | "@mui/icons-material": "7.1.0", 20 | "@mui/material": "7.1.0", 21 | "@vitejs/plugin-react": "4.4.1", 22 | "apexcharts": "4.7.0", 23 | "lodash-es": "4.17.21", 24 | "react": "19.1.0", 25 | "react-apexcharts": "1.7.0", 26 | "react-device-detect": "2.2.3", 27 | "react-dom": "19.1.0", 28 | "react-hook-form": "7.56.4", 29 | "react-router-dom": "7.6.0", 30 | "simplebar-react": "3.3.1", 31 | "swr": "2.3.3", 32 | "vite": "6.3.5", 33 | "vite-jsconfig-paths": "2.0.1" 34 | }, 35 | "devDependencies": { 36 | "@eslint/compat": "1.2.9", 37 | "@eslint/eslintrc": "3.3.1", 38 | "@eslint/js": "9.27.0", 39 | "env-cmd": "10.1.0", 40 | "eslint": "9.27.0", 41 | "eslint-config-prettier": "10.1.5", 42 | "eslint-plugin-jsx-a11y": "6.10.2", 43 | "eslint-plugin-prettier": "5.4.0", 44 | "eslint-plugin-react": "7.37.5", 45 | "eslint-plugin-react-hooks": "5.2.0", 46 | "prettier": "3.5.3", 47 | "prettier-eslint-cli": "8.0.1", 48 | "sass-embedded": "1.89.0" 49 | }, 50 | "packageManager": "yarn@4.9.1" 51 | } 52 | -------------------------------------------------------------------------------- /src/layouts/MainLayout/Drawer/DrawerContent/Navigation/NavGroup.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import List from '@mui/material/List'; 3 | import Typography from '@mui/material/Typography'; 4 | 5 | // project imports 6 | import NavCollapse from './NavCollapse'; 7 | import NavItem from './NavItem'; 8 | 9 | // ==============================|| RESPONSIVE DRAWER - GROUP ||============================== // 10 | 11 | export default function NavGroup({ item }) { 12 | const renderNavItem = (menuItem) => { 13 | // Render items based on the type 14 | switch (menuItem.type) { 15 | case 'collapse': 16 | return ; 17 | case 'item': 18 | return ; 19 | default: 20 | return ( 21 | 22 | Fix - Group Collapse or Items 23 | 24 | ); 25 | } 26 | }; 27 | 28 | return ( 29 | ({ ...theme.typography.menuCaption, color: 'primary.main' })} gutterBottom> 33 | {item.title} 34 | {item.caption && ( 35 | ({ ...theme.typography.subMenuCaption, color: 'text.primary' })} gutterBottom> 36 | {item.caption} 37 | 38 | )} 39 | 40 | } 41 | > 42 | {item.children?.map((menuItem) => renderNavItem(menuItem))} 43 | 44 | ); 45 | } 46 | 47 | NavGroup.propTypes = { item: PropTypes.any }; 48 | -------------------------------------------------------------------------------- /src/components/third-party/SimpleBar.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | // material-ui 4 | import { alpha, styled } from '@mui/material/styles'; 5 | import Box from '@mui/material/Box'; 6 | 7 | // third party 8 | import SimpleBar from 'simplebar-react'; 9 | import { BrowserView, MobileView } from 'react-device-detect'; 10 | 11 | // root style 12 | const RootStyle = styled(BrowserView)({ 13 | flexGrow: 1, 14 | height: '100%', 15 | overflow: 'hidden' 16 | }); 17 | 18 | // scroll bar wrapper 19 | const SimpleBarStyle = styled(SimpleBar)(({ theme }) => ({ 20 | maxHeight: '100%', 21 | '& .simplebar-scrollbar': { 22 | '&:before': { 23 | background: alpha(theme.palette.grey[500], 0.48) 24 | }, 25 | '&.simplebar-visible:before': { 26 | opacity: 1 27 | } 28 | }, 29 | '& .simplebar-track': { 30 | zIndex: 1201, 31 | '&.simplebar-vertical': { 32 | width: 10 33 | } 34 | }, 35 | '& .simplebar-track.simplebar-horizontal .simplebar-scrollbar': { 36 | height: 6 37 | }, 38 | '& .simplebar-mask': { 39 | zIndex: 'inherit' 40 | } 41 | })); 42 | 43 | // ==============================|| SIMPLE SCROLL BAR ||============================== // 44 | 45 | export default function SimpleBarScroll({ children, sx, ...other }) { 46 | return ( 47 | <> 48 | 49 | 50 | {children} 51 | 52 | 53 | 54 | 55 | {children} 56 | 57 | 58 | 59 | ); 60 | } 61 | 62 | SimpleBarScroll.propTypes = { children: PropTypes.any, sx: PropTypes.any, other: PropTypes.any }; 63 | -------------------------------------------------------------------------------- /src/layouts/MainLayout/Drawer/index.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | // material-ui 3 | import { alpha } from '@mui/material/styles'; 4 | import useMediaQuery from '@mui/material/useMediaQuery'; 5 | import Drawer from '@mui/material/Drawer'; 6 | import Box from '@mui/material/Box'; 7 | 8 | // project imports 9 | import DrawerContent from './DrawerContent'; 10 | 11 | import { DRAWER_WIDTH } from 'config'; 12 | import { handlerDrawerOpen, useGetMenuMaster } from 'states/menu'; 13 | 14 | // ==============================|| MAIN LAYOUT - DRAWER ||============================== // 15 | 16 | export default function MainDrawer({ window }) { 17 | const downLG = useMediaQuery((theme) => theme.breakpoints.down('lg')); 18 | 19 | const { menuMaster } = useGetMenuMaster(); 20 | const drawerOpen = menuMaster.isDashboardDrawerOpened; 21 | 22 | // Define container for drawer when window is specified 23 | const container = window !== undefined ? () => window().document.body : undefined; 24 | 25 | return ( 26 | 27 | handlerDrawerOpen(false)} 32 | slotProps={{ 33 | paper: { 34 | sx: (theme) => ({ 35 | boxSizing: 'border-box', 36 | width: DRAWER_WIDTH, 37 | backgroundImage: 'none', 38 | boxShadow: `0 0.15rem 1.75rem 0 ${alpha(theme.palette.common.black, 0.15)}`, 39 | borderRight: 'none' 40 | }) 41 | } 42 | }} 43 | > 44 | 45 | 46 | 47 | ); 48 | } 49 | 50 | MainDrawer.propTypes = { window: PropTypes.func }; 51 | -------------------------------------------------------------------------------- /src/themes/palette.js: -------------------------------------------------------------------------------- 1 | // ==============================|| DEFAULT - PALETTE ||============================== // 2 | 3 | export default function palette(mode) { 4 | const lightPalette = { 5 | common: { 6 | black: '#232b38' 7 | }, 8 | primary: { 9 | lighter: '#cbe2ff', 10 | light: '#4f8ef5', 11 | main: '#3366ff', 12 | dark: '#0043a9', 13 | darker: '#002d75', 14 | 100: '#4c6fff' 15 | }, 16 | secondary: { 17 | lighter: '#d3d8db', 18 | light: '#727b80', 19 | main: '#5d646e', 20 | dark: '#272f33', 21 | darker: '#161a1c' 22 | }, 23 | error: { 24 | lighter: '#fde4e2', 25 | light: '#ff625b', 26 | main: '#ec4333', 27 | dark: '#a20e00', 28 | darker: '#750800' 29 | }, 30 | warning: { 31 | lighter: '#fef3d4', 32 | light: '#f8c256', 33 | main: '#f4a100', 34 | dark: '#aa7000', 35 | darker: '#754c00' 36 | }, 37 | info: { 38 | lighter: '#d4f7f8', 39 | light: '#4de3e8', 40 | main: '#00cfd5', 41 | dark: '#009095', 42 | darker: '#005f63' 43 | }, 44 | success: { 45 | lighter: '#d4f2e4', 46 | light: '#4fd29e', 47 | main: '#00ac69', 48 | dark: '#007849', 49 | darker: '#004e2e' 50 | }, 51 | grey: { 52 | 300: '#425466' 53 | }, 54 | bg: { 55 | 100: '#f8f8f9' 56 | }, 57 | text: { 58 | primary: '#242c3a', 59 | secondary: '#a1a1a1', 60 | dark: '#12171e' 61 | }, 62 | divider: '#dcdcdc', 63 | background: { 64 | paper: '#ffffff', 65 | default: '#f0f2f8' 66 | }, 67 | menu: { 68 | hover: '#cbe2ff', 69 | selected: '#3366ff' 70 | } 71 | }; 72 | 73 | return { 74 | mode, 75 | ...lightPalette 76 | }; 77 | } 78 | -------------------------------------------------------------------------------- /src/views/dashboard/default/index.jsx: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import Grid from '@mui/material/Grid'; 3 | import Stack from '@mui/material/Stack'; 4 | 5 | // project imports 6 | import ReportCard from 'components/cards/ReportCard'; 7 | import SmallFlatCard from 'components/cards/SmallFlatCard'; 8 | import TrafficSourceCard from 'components/cards/TrafficSourceCard'; 9 | import RevenuChartCard from 'components/third-party/RevenuChartCard'; 10 | import SalesLineChartCard from 'components/third-party/SalesLineChartCard'; 11 | import { GRID_SPACING } from 'config'; 12 | 13 | // data 14 | import { reportCardData } from './data/report-card-data'; 15 | import { revenueCardData } from 'sections/dashboard/chart/card-data/revenue-card-data'; 16 | import { salesLineCardData } from './data/sales-line-chart-card-data'; 17 | import { smallFlatCardData } from './data/small-flat-card-data'; 18 | import { trafficSourceData } from './data/traffic-source-card-data'; 19 | 20 | // ==============================|| DASHBOARD DEFAULT ||============================== // 21 | 22 | export default function Default() { 23 | return ( 24 | 25 | {reportCardData.map((data, index) => ( 26 | 27 | 28 | 29 | ))} 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | ); 44 | } 45 | -------------------------------------------------------------------------------- /src/layouts/MainLayout/Header/index.jsx: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import AppBar from '@mui/material/AppBar'; 3 | import CardMedia from '@mui/material/CardMedia'; 4 | import IconButton from '@mui/material/IconButton'; 5 | import Stack from '@mui/material/Stack'; 6 | import Toolbar from '@mui/material/Toolbar'; 7 | import Box from '@mui/material/Box'; 8 | 9 | // project imports 10 | import Notification from './Notification'; 11 | import Profile from './Profile'; 12 | import Search from './Search'; 13 | 14 | import { DRAWER_WIDTH } from 'config'; 15 | import { handlerDrawerOpen, useGetMenuMaster } from 'states/menu'; 16 | 17 | // assets 18 | import logo from 'assets/images/logo.svg'; 19 | import MenuTwoToneIcon from '@mui/icons-material/MenuTwoTone'; 20 | 21 | // AppBar props, including styles that vary based on drawer state and screen size 22 | const appBar = { color: 'primary', position: 'fixed', sx: { width: 1, zIndex: { xs: 1100, lg: 1201 } } }; 23 | 24 | // ==============================|| MAIN LAYOUT - HEADER ||============================== // 25 | 26 | export default function Header() { 27 | const { menuMaster } = useGetMenuMaster(); 28 | const drawerOpen = menuMaster.isDashboardDrawerOpened; 29 | 30 | // Common header content 31 | const mainHeader = ( 32 | 33 | 34 | 35 | handlerDrawerOpen(!drawerOpen)} 40 | size="large" 41 | > 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | ); 53 | 54 | return {mainHeader}; 55 | } 56 | -------------------------------------------------------------------------------- /src/themes/overrides/Avatar.js: -------------------------------------------------------------------------------- 1 | // project imports 2 | import { AvatarSize } from 'enum'; 3 | 4 | const colors = ['primary', 'secondary', 'success', 'error', 'warning', 'info']; 5 | 6 | // ==============================|| AVATAR - SIZE ||============================== // 7 | 8 | const avatarSizes = () => ({ 9 | [AvatarSize.BADGE]: { width: 28, height: 28 }, 10 | [AvatarSize.XS]: { width: 34, height: 34 }, 11 | [AvatarSize.SM]: { width: 40, height: 40 }, 12 | [AvatarSize.MD]: { width: 60, height: 60 }, 13 | [AvatarSize.LG]: { width: 72, height: 72 }, 14 | [AvatarSize.XL]: { width: 82, height: 82 } 15 | }); 16 | 17 | // ==============================|| OVERRIDES - AVATAR ||============================== // 18 | 19 | export default function Avatar(theme) { 20 | const sizeVariants = () => { 21 | const styles = avatarSizes(); 22 | 23 | return Object.values(AvatarSize).map((size) => ({ 24 | props: { size }, 25 | style: styles[size] 26 | })); 27 | }; 28 | 29 | const colorVariants = colors.map((color) => { 30 | const paletteColor = theme.palette[color]; 31 | 32 | return { 33 | props: { color }, 34 | style: { 35 | color: theme.palette.background.paper, 36 | backgroundColor: paletteColor.main 37 | } 38 | }; 39 | }); 40 | 41 | return { 42 | MuiAvatar: { 43 | defaultProps: { 44 | color: 'default' // Set the default color here 45 | }, 46 | styleOverrides: { 47 | root: { 48 | variants: [ 49 | { 50 | props: { color: 'default' }, 51 | style: { 52 | color: theme.palette.background.paper, 53 | backgroundColor: theme.palette.grey[500] 54 | } 55 | }, 56 | ...colorVariants, 57 | ...sizeVariants(), 58 | { 59 | props: { type: 'outlined' }, 60 | style: ({ color }) => { 61 | const paletteColor = color ? theme.palette[color] : null; 62 | 63 | return { 64 | border: `2px solid ${paletteColor ? paletteColor.main : theme.palette.grey[500]}`, 65 | backgroundColor: 'transparent', 66 | color: paletteColor ? paletteColor.main : theme.palette.grey[500] 67 | }; 68 | } 69 | } 70 | ] 71 | } 72 | } 73 | } 74 | }; 75 | } 76 | -------------------------------------------------------------------------------- /src/menu-items/pages.js: -------------------------------------------------------------------------------- 1 | // assets 2 | import NavigationOutlinedIcon from '@mui/icons-material/NavigationOutlined'; 3 | import ChromeReaderModeOutlinedIcon from '@mui/icons-material/ChromeReaderModeOutlined'; 4 | import TranslateIcon from '@mui/icons-material/Translate'; 5 | import SecurityOutlinedIcon from '@mui/icons-material/SecurityOutlined'; 6 | import MonetizationOnOutlinedIcon from '@mui/icons-material/MonetizationOnOutlined'; 7 | import ErrorOutlineRoundedIcon from '@mui/icons-material/ErrorOutlineRounded'; 8 | import HourglassEmptyRoundedIcon from '@mui/icons-material/HourglassEmptyRounded'; 9 | import HelpOutlineOutlinedIcon from '@mui/icons-material/HelpOutlineOutlined'; 10 | 11 | const icons = { 12 | NavigationOutlinedIcon, 13 | ChromeReaderModeOutlinedIcon, 14 | TranslateIcon, 15 | SecurityOutlinedIcon, 16 | MonetizationOnOutlinedIcon, 17 | ErrorOutlineRoundedIcon, 18 | HourglassEmptyRoundedIcon, 19 | HelpOutlineOutlinedIcon 20 | }; 21 | 22 | // ==============================|| MENU ITEMS - PAGES ||============================== // 23 | 24 | const pages = { 25 | id: 'pages', 26 | title: 'pages', 27 | caption: 'prebuild-pages', 28 | type: 'group', 29 | icon: icons.NavigationOutlinedIcon, 30 | children: [ 31 | { 32 | id: 'sample-page', 33 | title: 'Sample Page', 34 | type: 'item', 35 | url: '/sample-page', 36 | icon: icons.ChromeReaderModeOutlinedIcon 37 | }, 38 | { 39 | id: 'auth', 40 | title: 'Authentication', 41 | type: 'collapse', 42 | icon: icons.SecurityOutlinedIcon, 43 | children: [ 44 | { 45 | id: 'login-1', 46 | title: 'login', 47 | type: 'item', 48 | url: '/pages/auth/login', 49 | target: '_blank' 50 | }, 51 | { 52 | id: 'register', 53 | title: 'register', 54 | type: 'item', 55 | url: '/pages/auth/register', 56 | target: '_blank' 57 | } 58 | ] 59 | }, 60 | { 61 | id: 'documentation', 62 | title: 'Documentation', 63 | type: 'item', 64 | url: 'https://codedthemes.gitbook.io/materially-react-material-documentation/', 65 | icon: icons.HelpOutlineOutlinedIcon, 66 | chip: { 67 | label: 'Help?', 68 | color: 'primary' 69 | }, 70 | external: true, 71 | target: '_blank' 72 | } 73 | ] 74 | }; 75 | 76 | export default pages; 77 | -------------------------------------------------------------------------------- /src/views/components/Typography.jsx: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import Stack from '@mui/material/Stack'; 3 | import Typography from '@mui/material/Typography'; 4 | 5 | // project imports 6 | import MainCard from 'components/cards/MainCard'; 7 | 8 | // ==============================|| UTILS - TYPOGRAPHY ||============================== // 9 | 10 | export default function UtilsTypography() { 11 | return ( 12 | 13 | 14 | 15 | h1. Heading 16 | 17 | 18 | h2. Heading 19 | 20 | 21 | h3. Heading 22 | 23 | 24 | h4. Heading 25 | 26 | 27 | h5. Heading 28 | 29 | 30 | h6. Heading 31 | 32 | 33 | subtitle1. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos blanditiis tenetur 34 | 35 | 36 | subtitle2. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos blanditiis tenetur 37 | 38 | 39 | body1. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos blanditiis tenetur unde suscipit, quam beatae rerum 40 | inventore consectetur, neque doloribus, cupiditate numquam dignissimos laborum fugiat deleniti? Eum quasi quidem quibusdam. 41 | 42 | 43 | body2. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos blanditiis tenetur unde suscipit, quam beatae rerum 44 | inventore consectetur, neque doloribus, cupiditate numquam dignissimos laborum fugiat deleniti? Eum quasi quidem quibusdam. 45 | 46 | 47 | button text 48 | 49 | 50 | caption text 51 | 52 | 53 | overline text 54 | 55 | 56 | 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /src/components/cards/SmallFlatCard.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | // material-ui 4 | import Grid from '@mui/material/Grid'; 5 | import Stack from '@mui/material/Stack'; 6 | import Typography from '@mui/material/Typography'; 7 | 8 | // project imports 9 | import MainCard from './MainCard'; 10 | 11 | // ==============================|| FLAT CARD ||============================== // 12 | 13 | export default function SmallFlatCard({ items }) { 14 | return ( 15 | 16 | { 20 | const cols = { xs: 1, sm: 3, lg: 6 }; // Number of columns per row at each breakpoint 21 | return { 22 | alignItems: 'center', 23 | '& > *': { borderLeft: 1, borderBottom: 1, borderColor: 'divider' }, 24 | // Remove left border for the first item in each row 25 | [`& > *:nth-of-type(${cols.xs}n + 1)`]: { 26 | [theme.breakpoints.down('sm')]: { borderLeft: 'none' } 27 | }, 28 | [`& > *:nth-of-type(${cols.sm}n + 1)`]: { 29 | [theme.breakpoints.between('sm', 'lg')]: { borderLeft: 'none' } 30 | }, 31 | [`& > *:nth-of-type(${cols.lg}n + 1)`]: { 32 | [theme.breakpoints.up('lg')]: { borderLeft: 'none' } 33 | }, 34 | // Remove bottom border for last row 35 | [`& > *:nth-last-of-type(-n+${cols.xs})`]: { 36 | [theme.breakpoints.down('sm')]: { borderBottom: 'none' } 37 | }, 38 | [`& > *:nth-last-of-type(-n+${cols.sm})`]: { 39 | [theme.breakpoints.between('sm', 'lg')]: { borderBottom: 'none' } 40 | }, 41 | [`& > *:nth-last-of-type(-n+${cols.lg})`]: { 42 | [theme.breakpoints.up('lg')]: { borderBottom: 'none' } 43 | } 44 | }; 45 | }} 46 | > 47 | {items.map((item, index) => ( 48 | 49 | 50 | {item.label} 51 | 52 | {item.value} 53 | 54 | 55 | 56 | ))} 57 | 58 | 59 | ); 60 | } 61 | 62 | SmallFlatCard.propTypes = { items: PropTypes.object }; 63 | -------------------------------------------------------------------------------- /src/views/auth/CommonAuthLayout.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { Link } from 'react-router-dom'; 3 | 4 | // material-ui 5 | import CardMedia from '@mui/material/CardMedia'; 6 | import Grid from '@mui/material/Grid'; 7 | import Stack from '@mui/material/Stack'; 8 | import Typography from '@mui/material/Typography'; 9 | import Box from '@mui/material/Box'; 10 | 11 | // project imports 12 | import MainCard from 'components/cards/MainCard'; 13 | 14 | // assets 15 | import Logo from 'assets/images/logo-dark.svg'; 16 | 17 | // ==============================|| COMMON AUTH LAYOUT ||============================== // 18 | 19 | export default function CommonAuthLayout({ title, subHeading, footerLink, children }) { 20 | return ( 21 | 22 | 23 | 34 | 35 | 39 | 40 | 41 | {title} 42 | 43 | 44 | {subHeading} 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | {children} 53 | 54 | {footerLink && ( 55 | 56 | {footerLink.title} 57 | 58 | )} 59 | 60 | 61 | 62 | ); 63 | } 64 | 65 | CommonAuthLayout.propTypes = { 66 | title: PropTypes.string, 67 | subHeading: PropTypes.string, 68 | footerLink: PropTypes.object, 69 | children: PropTypes.node 70 | }; 71 | -------------------------------------------------------------------------------- /src/components/third-party/SalesLineChartCard.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useEffect, useState } from 'react'; 3 | 4 | // material-ui 5 | import { useTheme } from '@mui/material/styles'; 6 | import Stack from '@mui/material/Stack'; 7 | import Typography from '@mui/material/Typography'; 8 | import Box from '@mui/material/Box'; 9 | 10 | // third party 11 | import ReactApexChart from 'react-apexcharts'; 12 | 13 | // project imports 14 | import MainCard from 'components/cards/MainCard'; 15 | 16 | // ==============================|| SALES LINE CHART CARD ||============================== // 17 | 18 | export default function SalesLineChartCard({ bgColor, chartData, footerData, icon: Icon, title, percentage }) { 19 | const theme = useTheme(); 20 | 21 | const [chartDatas, setChartDatas] = useState(chartData); 22 | const chartColor = theme.palette.common.white; 23 | 24 | useEffect(() => { 25 | setChartDatas((prevState) => ({ 26 | ...prevState, 27 | options: { 28 | ...prevState.options, 29 | tooltip: { 30 | theme: 'light' 31 | }, 32 | colors: [chartColor] 33 | } 34 | })); 35 | }, [chartColor]); 36 | 37 | return ( 38 | 42 | {footerData.map((data, index) => ( 43 | 44 | {data.value} 45 | {data.label} 46 | 47 | ))} 48 | 49 | } 50 | > 51 | 52 | 53 | 54 | 55 | {title} 56 | 57 | 58 | {Icon && } 59 | 60 | {percentage} 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | ); 69 | } 70 | 71 | SalesLineChartCard.propTypes = { 72 | bgColor: PropTypes.string, 73 | chartData: PropTypes.any, 74 | footerData: PropTypes.object, 75 | icon: PropTypes.any, 76 | title: PropTypes.string, 77 | percentage: PropTypes.string 78 | }; 79 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { fixupConfigRules } from '@eslint/compat'; 2 | import prettier from 'eslint-plugin-prettier'; 3 | import react from 'eslint-plugin-react'; 4 | import reactHooks from 'eslint-plugin-react-hooks'; 5 | import jsxA11y from 'eslint-plugin-jsx-a11y'; 6 | import js from '@eslint/js'; 7 | import path from 'node:path'; 8 | import { fileURLToPath } from 'node:url'; 9 | import { FlatCompat } from '@eslint/eslintrc'; 10 | 11 | const __filename = fileURLToPath(import.meta.url); 12 | const __dirname = path.dirname(__filename); 13 | const compat = new FlatCompat({ 14 | baseDirectory: __dirname, 15 | recommendedConfig: js.configs.recommended, 16 | allConfig: js.configs.all 17 | }); 18 | 19 | export default [ 20 | ...fixupConfigRules(compat.extends('prettier')), 21 | 22 | { 23 | plugins: { 24 | prettier, 25 | react, 26 | 'react-hooks': reactHooks, 27 | 'jsx-a11y': jsxA11y 28 | }, 29 | 30 | languageOptions: { 31 | ecmaVersion: 2020, 32 | sourceType: 'module', 33 | parserOptions: { 34 | ecmaFeatures: { 35 | jsx: true 36 | } 37 | } 38 | }, 39 | 40 | settings: { 41 | react: { 42 | version: 'detect' 43 | } 44 | }, 45 | 46 | rules: { 47 | 'react/jsx-filename-extension': 'off', 48 | 'no-param-reassign': 'off', 49 | 'react/prop-types': 'off', 50 | 'react/require-default-props': 'off', 51 | 'react/no-array-index-key': 'off', 52 | 'react/react-in-jsx-scope': 'off', 53 | 'react/jsx-props-no-spreading': 'off', 54 | 'import/order': 'off', 55 | 'no-console': 'off', 56 | 'no-shadow': 'off', 57 | 'import/no-cycle': 'off', 58 | 'import/no-extraneous-dependencies': 'off', 59 | 'jsx-a11y/label-has-associated-control': 'off', 60 | 'jsx-a11y/no-autofocus': 'off', 61 | 'react/jsx-uses-react': 'off', 62 | 'react/jsx-uses-vars': 'error', 63 | 'react-hooks/rules-of-hooks': 'error', 64 | 'react-hooks/exhaustive-deps': 'warn', 65 | 'no-unused-vars': 'off', 66 | 67 | 'no-restricted-imports': [ 68 | 'error', 69 | { 70 | patterns: ['@mui/*/*/*', '!@mui/material/test-utils/*'] 71 | } 72 | ], 73 | 74 | 'no-unused-vars': [ 75 | 'error', 76 | { 77 | vars: 'all', 78 | args: 'none' 79 | } 80 | ], 81 | 82 | 'prettier/prettier': [ 83 | 'warn', 84 | { 85 | bracketSpacing: true, 86 | printWidth: 140, 87 | singleQuote: true, 88 | trailingComma: 'none', 89 | tabWidth: 2, 90 | useTabs: false 91 | } 92 | ] 93 | } 94 | }, 95 | { 96 | ignores: ['node_modules/**'], 97 | files: ['src/**/*.{js,jsx}'] 98 | } 99 | ]; -------------------------------------------------------------------------------- /src/components/third-party/RevenuChartCard.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useEffect, useState } from 'react'; 3 | 4 | // material-ui 5 | import { useTheme } from '@mui/material/styles'; 6 | import useMediaQuery from '@mui/material/useMediaQuery'; 7 | import Divider from '@mui/material/Divider'; 8 | import Grid from '@mui/material/Grid'; 9 | import Stack from '@mui/material/Stack'; 10 | import Typography from '@mui/material/Typography'; 11 | 12 | // third party 13 | import ReactApexChart from 'react-apexcharts'; 14 | 15 | // project imports 16 | import MainCard from 'components/cards/MainCard'; 17 | 18 | // ==============================|| REVENUE CHART CARD ||============================== // 19 | 20 | export default function RevenuChartCard({ title, bottomData, chartData }) { 21 | const theme = useTheme(); 22 | 23 | const onlySM = useMediaQuery(theme.breakpoints.only('sm')); 24 | 25 | const [chartDatas, setChartDatas] = useState(chartData); 26 | 27 | const primaryMain = theme.palette.primary.main; 28 | const infoMain = theme.palette.info.main; 29 | const errorMain = theme.palette.error.main; 30 | const divider = theme.palette.background.paper; 31 | 32 | useEffect(() => { 33 | setChartDatas((prevState) => ({ 34 | ...prevState, 35 | options: { 36 | ...prevState.options, 37 | tooltip: { 38 | theme: 'light' 39 | }, 40 | theme: { 41 | mode: 'light' 42 | }, 43 | colors: [errorMain, primaryMain, infoMain], 44 | stroke: { 45 | colors: divider 46 | } 47 | } 48 | })); 49 | }, [errorMain, primaryMain, infoMain, divider]); 50 | 51 | return ( 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | {bottomData?.map((data, index) => ( 63 | 64 | {data.label} 65 | 66 | {data.value}% 67 | 68 | 69 | ))} 70 | 71 | 72 | 73 | 74 | ); 75 | } 76 | 77 | RevenuChartCard.propTypes = { title: PropTypes.string, bottomData: PropTypes.object, chartData: PropTypes.any }; 78 | -------------------------------------------------------------------------------- /src/layouts/MainLayout/Header/Search.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | // material-ui 4 | import { useTheme, useMediaQuery, alpha } from '@mui/material'; 5 | import IconButton from '@mui/material/IconButton'; 6 | import InputAdornment from '@mui/material/InputAdornment'; 7 | import Popper from '@mui/material/Popper'; 8 | import TextField from '@mui/material/TextField'; 9 | import Box from '@mui/material/Box'; 10 | 11 | // assets 12 | import CloseIcon from '@mui/icons-material/Close'; 13 | import SearchIcon from '@mui/icons-material/Search'; 14 | 15 | const color = 'grey.100'; 16 | 17 | // ==============================|| SEARCH ||============================== // 18 | 19 | export default function Search() { 20 | const theme = useTheme(); 21 | const isMobile = useMediaQuery(theme.breakpoints.down('sm')); 22 | 23 | const [anchorEl, setAnchorEl] = useState(null); 24 | 25 | const handleClick = (event) => { 26 | setAnchorEl(anchorEl ? null : event.currentTarget); 27 | }; 28 | 29 | const open = Boolean(anchorEl); 30 | const id = open ? 'simple-popper' : undefined; 31 | 32 | useEffect(() => { 33 | if (!isMobile && anchorEl) { 34 | setAnchorEl(null); 35 | } 36 | }, [isMobile, anchorEl]); 37 | 38 | return isMobile ? ( 39 | <> 40 | 41 | 42 | 43 | 51 | 52 | 53 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | ) : ( 67 | 75 | 76 | 77 | ) 78 | } 79 | }} 80 | sx={{ 81 | mr: 3, 82 | bgcolor: alpha(theme.palette.common.white, 0.15), 83 | ':hover': { bgcolor: alpha(theme.palette.common.white, 0.25) }, 84 | borderRadius: 1, 85 | '& .MuiInputBase-input': { 86 | transition: theme.transitions.create('width'), 87 | color: 'grey.100', 88 | width: { sm: 100, md: 125 }, 89 | mr: { md: 3 }, 90 | '&:focus': { width: { md: 225 } } 91 | }, 92 | '& .MuiOutlinedInput-notchedOutline': { border: 'none' } 93 | }} 94 | /> 95 | ); 96 | } 97 | -------------------------------------------------------------------------------- /src/layouts/MainLayout/Drawer/DrawerContent/Navigation/NavItem.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useEffect } from 'react'; 3 | import { Link, useLocation } from 'react-router-dom'; 4 | 5 | // material-ui 6 | import { useTheme } from '@mui/material/styles'; 7 | import useMediaQuery from '@mui/material/useMediaQuery'; 8 | import Avatar from '@mui/material/Avatar'; 9 | import Chip from '@mui/material/Chip'; 10 | import ListItemButton from '@mui/material/ListItemButton'; 11 | import ListItemIcon from '@mui/material/ListItemIcon'; 12 | import ListItemText from '@mui/material/ListItemText'; 13 | import Typography from '@mui/material/Typography'; 14 | 15 | // project imports 16 | import { handlerActiveItem, handlerDrawerOpen, useGetMenuMaster } from 'states/menu'; 17 | 18 | // assets 19 | import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; 20 | 21 | // ==============================|| RESPONSIVE DRAWER - ITEM ||============================== // 22 | 23 | export default function NavItem({ item, level = 0 }) { 24 | const theme = useTheme(); 25 | const { menuMaster } = useGetMenuMaster(); 26 | const openItem = menuMaster.openedItem; 27 | 28 | const downLG = useMediaQuery(theme.breakpoints.down('lg')); 29 | 30 | const location = useLocation(); 31 | 32 | useEffect(() => { 33 | if (location.pathname === item.url) handlerActiveItem(item.id); 34 | // eslint-disable-next-line react-hooks/exhaustive-deps 35 | }, [location.pathname]); 36 | 37 | const itemHandler = () => { 38 | if (downLG) handlerDrawerOpen(false); 39 | }; 40 | 41 | const Icon = item.icon; 42 | const itemIcon = item.icon ? : 0 ? 'inherit' : 'medium'} />; 43 | 44 | return ( 45 | 1 && { bgcolor: 'transparent !important', py: 1 }) 59 | }} 60 | > 61 | {itemIcon} 62 | 1 ? 2 : 1.4 }} variant={openItem === item.id ? 'subtitle1' : 'body1'} color="inherit"> 65 | {item.title} 66 | 67 | } 68 | secondary={ 69 | item.caption && ( 70 | 71 | {item.caption} 72 | 73 | ) 74 | } 75 | /> 76 | {item.chip && ( 77 | {item.chip.avatar} : item.chip.avatar} 83 | /> 84 | )} 85 | 86 | ); 87 | } 88 | 89 | NavItem.propTypes = { item: PropTypes.any, level: PropTypes.number }; 90 | -------------------------------------------------------------------------------- /src/components/cards/MainCard.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useMemo } from 'react'; 3 | 4 | // material-ui 5 | import { useTheme } from '@mui/material/styles'; 6 | import Card from '@mui/material/Card'; 7 | import CardActions from '@mui/material/CardActions'; 8 | import CardContent from '@mui/material/CardContent'; 9 | import CardHeader from '@mui/material/CardHeader'; 10 | import Divider from '@mui/material/Divider'; 11 | 12 | // project imports 13 | import { CardVariant } from 'enum'; 14 | 15 | function MainCard({ 16 | title, 17 | content = true, 18 | actions, 19 | headerAction, 20 | headerDivider = true, 21 | headerSX = {}, 22 | actionsDivider = true, 23 | contentSX = {}, 24 | cardActionsSX = {}, 25 | children, 26 | variant = { type: CardVariant.DEFAULT }, 27 | sx = {}, 28 | ref, 29 | ...others 30 | }) { 31 | const theme = useTheme(); 32 | 33 | const cardColors = useMemo( 34 | () => ({ 35 | primary: theme.palette.primary.main, 36 | secondary: theme.palette.secondary.main, 37 | error: theme.palette.error.main, 38 | warning: theme.palette.warning.main, 39 | info: theme.palette.info.main, 40 | success: theme.palette.success.main 41 | }), 42 | [theme] 43 | ); 44 | 45 | function CardDivider() { 46 | return ( 47 | 55 | ); 56 | } 57 | 58 | return ( 59 | 71 | {title && ( 72 | <> 73 | 81 | {headerDivider && } 82 | 83 | )} 84 | 85 | {/* card content */} 86 | {content ? {children} : children} 87 | 88 | {/* card actions */} 89 | {actions && ( 90 | <> 91 | {actionsDivider && } 92 | {actions} 93 | 94 | )} 95 | 96 | ); 97 | } 98 | 99 | export default MainCard; 100 | 101 | MainCard.propTypes = { 102 | title: PropTypes.oneOfType([PropTypes.node, PropTypes.string]), 103 | content: PropTypes.bool, 104 | actions: PropTypes.node, 105 | headerAction: PropTypes.any, 106 | headerDivider: PropTypes.bool, 107 | headerSX: PropTypes.object, 108 | actionsDivider: PropTypes.bool, 109 | contentSX: PropTypes.object, 110 | cardActionsSX: PropTypes.object, 111 | children: PropTypes.any, 112 | variant: PropTypes.object, 113 | sx: PropTypes.object, 114 | ref: PropTypes.object, 115 | others: PropTypes.any 116 | }; 117 | -------------------------------------------------------------------------------- /src/sections/auth/AuthLogin.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useState } from 'react'; 3 | import { Link as RouterLink } from 'react-router-dom'; 4 | 5 | // material-ui 6 | import Button from '@mui/material/Button'; 7 | import FormControl from '@mui/material/FormControl'; 8 | import FormHelperText from '@mui/material/FormHelperText'; 9 | import InputAdornment from '@mui/material/InputAdornment'; 10 | import InputLabel from '@mui/material/InputLabel'; 11 | import Link from '@mui/material/Link'; 12 | import OutlinedInput from '@mui/material/OutlinedInput'; 13 | import Stack from '@mui/material/Stack'; 14 | import TextField from '@mui/material/TextField'; 15 | import Box from '@mui/material/Box'; 16 | 17 | // third party 18 | import { useForm } from 'react-hook-form'; 19 | 20 | // project imports 21 | import { emailSchema, passwordSchema } from 'utils/validationSchema'; 22 | 23 | // assets 24 | import Visibility from '@mui/icons-material/Visibility'; 25 | import VisibilityOff from '@mui/icons-material/VisibilityOff'; 26 | 27 | // ==============================|| AUTH - LOGIN ||============================== // 28 | 29 | export default function AuthLogin({ inputSx }) { 30 | const [isPasswordVisible, setIsPasswordVisible] = useState(false); 31 | 32 | // Initialize react-hook-form 33 | const { 34 | register, 35 | formState: { errors } 36 | } = useForm(); 37 | 38 | return ( 39 |
40 | 41 | 42 | 52 | {errors.email?.message && {errors.email.message}} 53 | 54 | 55 | 56 | 57 | Password 58 | setIsPasswordVisible(!isPasswordVisible)}> 67 | {isPasswordVisible ? : } 68 | 69 | } 70 | sx={inputSx} 71 | /> 72 | 73 | 77 | {errors.password?.message && {errors.password.message}} 78 | 86 | Forgot Password? 87 | 88 | 89 | 90 | 91 | 92 | 95 |
96 | ); 97 | } 98 | 99 | AuthLogin.propTypes = { inputSx: PropTypes.any }; 100 | -------------------------------------------------------------------------------- /src/utils/validationSchema.js: -------------------------------------------------------------------------------- 1 | export const emailSchema = { 2 | required: 'Email is required', 3 | pattern: { 4 | value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i, 5 | message: 'Invalid email address' 6 | } 7 | }; 8 | 9 | export const passwordSchema = { 10 | required: 'Password is required', 11 | minLength: { value: 8, message: 'Password must be at least 8 characters' }, 12 | validate: { 13 | noSpaces: (value) => (value?.includes(' ') ? 'Password cannot contain spaces' : true), 14 | hasUpperCase: (value) => (/[A-Z]/.test(value || '') ? true : 'Password must have at least one uppercase letter'), 15 | hasNumber: (value) => (/[0-9]/.test(value || '') ? true : 'Password must have at least one number'), 16 | hasSpecialChar: (value) => (/[^A-Za-z0-9]/.test(value || '') ? true : 'Password must have at least one special character') 17 | } 18 | }; 19 | 20 | export const firstNameSchema = { 21 | required: 'First name is required', 22 | pattern: { value: /^[a-zA-Z\s]+$/, message: 'Invalid first name' }, 23 | validate: { 24 | trim: (value) => { 25 | const trimmedValue = value.trim(); 26 | return trimmedValue.length > 0 || 'First name cannot be empty or contain only spaces'; 27 | } 28 | }, 29 | onBlur: (e) => { 30 | e.target.value = e.target.value.trim(); 31 | } 32 | }; 33 | 34 | export const lastNameSchema = { 35 | required: 'Last name is required', 36 | pattern: { value: /^[a-zA-Z\s]+$/, message: 'Invalid last name' }, 37 | validate: { 38 | trim: (value) => { 39 | const trimmedValue = value.trim(); 40 | return trimmedValue.length > 0 || 'Last name cannot be empty or contain only spaces'; 41 | } 42 | }, 43 | onBlur: (e) => { 44 | e.target.value = e.target.value.trim(); 45 | } 46 | }; 47 | 48 | export const contactSchema = { 49 | required: 'Contact number is required', 50 | pattern: { value: /^[0-9().-]{7,15}$/, message: 'Invalid contact number' } 51 | }; 52 | 53 | export const otpSchema = { 54 | required: 'OTP is required', 55 | minLength: { value: 6, message: 'OTP must be exactly 6 characters' } 56 | }; 57 | 58 | export const radioBoxSchema = { 59 | required: 'Option selection is required' 60 | }; 61 | 62 | export const colorSchema = { 63 | validate: (value) => (value.length > 0 ? true : 'At least one color is required') 64 | }; 65 | 66 | export const cardSchema = { 67 | cardName: { required: 'Card name is required' }, 68 | cardNumber: { required: 'Card number is required' } 69 | }; 70 | 71 | export const roleSchema = { 72 | role: { 73 | required: 'Role selection is required', 74 | maxLength: { value: 50, message: 'Role must be at most 50 characters' }, 75 | pattern: { value: /^[a-z\d\-/#_\s]+$/i, message: 'Only alphanumerics are allowed' } 76 | }, 77 | skills: { 78 | required: 'Skill selection is required', 79 | validate: (value) => { 80 | if (value.length < 3) return 'Skill tags field must have at least 3 items'; 81 | if (value.length > 15) return 'Please select a maximum of 15 skills.'; 82 | return true; 83 | } 84 | } 85 | }; 86 | 87 | export const addressSchema = { 88 | country: { 89 | required: 'Country is required' 90 | }, 91 | region: { 92 | required: 'Region required' 93 | }, 94 | city: { 95 | required: 'City is required' 96 | }, 97 | address: { 98 | required: 'Address is required' 99 | }, 100 | postCode: { 101 | required: 'Postcode is required' 102 | } 103 | }; 104 | 105 | export const nameSchema = { 106 | required: 'Name is required', 107 | pattern: { value: /^[a-zA-Z\s]+$/, message: 'Invalid name' }, 108 | validate: { 109 | trim: (value) => { 110 | const trimmedValue = value.trim(); 111 | return trimmedValue.length > 0 || 'Name cannot be empty or contain only spaces'; 112 | } 113 | }, 114 | onBlur: (e) => { 115 | e.target.value = e.target.value?.trim(); 116 | } 117 | }; 118 | -------------------------------------------------------------------------------- /src/layouts/MainLayout/Header/Profile.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | // material-ui 4 | import ClickAwayListener from '@mui/material/ClickAwayListener'; 5 | import Fade from '@mui/material/Fade'; 6 | import IconButton from '@mui/material/IconButton'; 7 | import List from '@mui/material/List'; 8 | import ListItemButton from '@mui/material/ListItemButton'; 9 | import ListItemIcon from '@mui/material/ListItemIcon'; 10 | import ListItemText from '@mui/material/ListItemText'; 11 | import Popper from '@mui/material/Popper'; 12 | import Box from '@mui/material/Box'; 13 | 14 | // third party 15 | import { useLocation, useNavigate } from 'react-router-dom'; 16 | 17 | // project imports 18 | import MainCard from 'components/cards/MainCard'; 19 | 20 | // assets 21 | import AccountCircleTwoToneIcon from '@mui/icons-material/AccountCircleTwoTone'; 22 | import DraftsTwoToneIcon from '@mui/icons-material/DraftsTwoTone'; 23 | import LockOpenTwoTone from '@mui/icons-material/LockOpenTwoTone'; 24 | import MeetingRoomTwoToneIcon from '@mui/icons-material/MeetingRoomTwoTone'; 25 | import PersonTwoToneIcon from '@mui/icons-material/PersonTwoTone'; 26 | import SettingsTwoToneIcon from '@mui/icons-material/SettingsTwoTone'; 27 | 28 | const menuItems = [ 29 | { icon: , label: 'Settings' }, 30 | { icon: , label: 'Profile' }, 31 | { icon: , label: 'My Messages' }, 32 | { icon: , label: 'Lock Screen' }, 33 | { icon: , label: 'Logout' } 34 | ]; 35 | 36 | // ==============================|| PROFILE ||============================== // 37 | 38 | export default function Profile() { 39 | const [open, setOpen] = useState(false); 40 | const [anchorEl, setAnchorEl] = useState(null); 41 | const [selectedIndex, setSelectedIndex] = useState(null); 42 | const navigate = useNavigate(); 43 | const location = useLocation(); 44 | 45 | const handleClick = (event) => { 46 | setAnchorEl(event.currentTarget); 47 | setOpen((prev) => !prev); 48 | }; 49 | 50 | const handleClickAway = () => setOpen(false); 51 | 52 | useEffect(() => { 53 | const index = menuItems.findIndex((item) => item.path && location.pathname.startsWith(item.path)); 54 | setSelectedIndex(index !== -1 ? index : null); 55 | }, [location.pathname]); 56 | 57 | const handleMenuItemClick = (index, item) => { 58 | setSelectedIndex(index); 59 | 60 | if (item.path) { 61 | navigate(item.path); 62 | } else if (item.action) { 63 | item.action(); 64 | } 65 | }; 66 | 67 | const canBeOpen = open && Boolean(anchorEl); 68 | const id = canBeOpen ? 'profile-popper' : undefined; 69 | 70 | return ( 71 | 72 | 73 | 74 | 75 | 76 | 77 | 86 | {({ TransitionProps }) => ( 87 | 88 | 89 | 90 | {menuItems.map((item, index) => ( 91 | handleMenuItemClick(index, item)}> 92 | {item.icon} 93 | 94 | 95 | ))} 96 | 97 | 98 | 99 | )} 100 | 101 | 102 | 103 | ); 104 | } 105 | -------------------------------------------------------------------------------- /src/layouts/MainLayout/Drawer/DrawerContent/Navigation/NavCollapse.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useEffect, useState } from 'react'; 3 | import { useLocation } from 'react-router-dom'; 4 | 5 | // material-ui 6 | import Collapse from '@mui/material/Collapse'; 7 | import List from '@mui/material/List'; 8 | import ListItemButton from '@mui/material/ListItemButton'; 9 | import ListItemIcon from '@mui/material/ListItemIcon'; 10 | import ListItemText from '@mui/material/ListItemText'; 11 | import Typography from '@mui/material/Typography'; 12 | 13 | // project imports 14 | import NavItem from './NavItem'; 15 | 16 | // assets 17 | import ExpandLess from '@mui/icons-material/ExpandLess'; 18 | import ExpandMore from '@mui/icons-material/ExpandMore'; 19 | import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; 20 | 21 | // ==============================|| RESPONSIVE DRAWER - COLLAPSE ||============================== // 22 | 23 | function NavCollapseLoop({ item, level }) { 24 | return item.children?.map((item) => { 25 | switch (item.type) { 26 | case 'collapse': 27 | return ; 28 | case 'item': 29 | return ; 30 | default: 31 | return ( 32 | 33 | Fix - Collapse or Item 34 | 35 | ); 36 | } 37 | }); 38 | } 39 | 40 | // ==============================|| RESPONSIVE DRAWER - COLLAPSE ||============================== // 41 | 42 | export default function NavCollapse({ item, level }) { 43 | const [open, setOpen] = useState(false); 44 | const [selected, setSelected] = useState(null); 45 | 46 | // Active item collapse on page load with sub-levels 47 | const { pathname } = useLocation(); 48 | 49 | const checkOpenForParent = (child, id) => { 50 | child.forEach((list) => { 51 | if (list.url === pathname) { 52 | setOpen(true); 53 | setSelected(id); 54 | } 55 | }); 56 | }; 57 | 58 | useEffect(() => { 59 | setOpen(false); 60 | setSelected(null); 61 | if (item.children) { 62 | item.children.forEach((list) => { 63 | if (list.children?.length) { 64 | checkOpenForParent(list.children, item.id); 65 | } 66 | 67 | if (list.url === pathname) { 68 | setSelected(item.id); 69 | setOpen(true); 70 | } 71 | }); 72 | } 73 | 74 | // eslint-disable-next-line react-hooks/exhaustive-deps 75 | }, [pathname, item.children]); 76 | 77 | const handleClick = () => { 78 | setOpen(!open); 79 | }; 80 | 81 | const Icon = item.icon; 82 | const menuIcon = item.icon ? : 0 ? 'inherit' : 'medium'} />; 83 | 84 | return ( 85 | <> 86 | 1 && { bgcolor: 'transparent !important', py: 1 }) 94 | }} 95 | onClick={handleClick} 96 | > 97 | {{menuIcon}} 98 | 101 | {item.title} 102 | 103 | } 104 | secondary={ 105 | item.caption && ( 106 | ({ ...theme.typography.subMenuCaption, pl: 2 })} display="block" gutterBottom> 107 | {item.caption} 108 | 109 | ) 110 | } 111 | /> 112 | {open ? : } 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | ); 121 | } 122 | 123 | NavCollapseLoop.propTypes = { item: PropTypes.any, level: PropTypes.number }; 124 | 125 | NavCollapse.propTypes = { item: PropTypes.any, level: PropTypes.number }; 126 | -------------------------------------------------------------------------------- /src/components/Breadcrumbs.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useEffect, useState } from 'react'; 3 | import { Link, useLocation } from 'react-router-dom'; 4 | 5 | import MuiBreadcrumbs from '@mui/material/Breadcrumbs'; 6 | import Divider from '@mui/material/Divider'; 7 | import Stack from '@mui/material/Stack'; 8 | import Typography from '@mui/material/Typography'; 9 | 10 | // project imports 11 | import { APP_DEFAULT_PATH } from 'config'; 12 | import menuItems from 'menu-items'; 13 | 14 | //assets 15 | import HomeTwoToneIcon from '@mui/icons-material/HomeTwoTone'; 16 | 17 | const homeBreadcrumb = { title: 'Home', url: APP_DEFAULT_PATH, icon: HomeTwoToneIcon }; 18 | const flexStyle = { display: 'flex', alignItems: 'center', gap: 0.5 }; 19 | 20 | // ==============================|| BREADCRUMBS ||============================== // 21 | 22 | export default function Breadcrumbs({ data, divider = true, title, icons = false, sx, ...rest }) { 23 | const location = useLocation(); 24 | 25 | const [breadcrumbItems, setBreadcrumbItems] = useState([]); 26 | const [activeItem, setActiveItem] = useState(); 27 | 28 | useEffect(() => { 29 | if (data?.length) { 30 | dataHandler(data); 31 | } else { 32 | for (const menu of menuItems?.items ?? []) { 33 | if (menu.type && menu.type === 'group') { 34 | const matchedParents = findParentElements(menu.children || [], location.pathname); 35 | dataHandler(matchedParents || []); 36 | if (matchedParents) break; 37 | } 38 | } 39 | } 40 | // eslint-disable-next-line react-hooks/exhaustive-deps 41 | }, [data, location]); 42 | 43 | const dataHandler = (data) => { 44 | const filtered = data; 45 | // display breadcrumbs if breadcrumbs is set to false 46 | // const filtered = data.filter((item) => item.breadcrumbs !== false); 47 | const active = filtered.at(-1); 48 | const linkItems = filtered.slice(0, -1); 49 | if (active && active.url != homeBreadcrumb.url) { 50 | const home = { ...homeBreadcrumb }; 51 | linkItems.unshift(home); 52 | } 53 | setActiveItem(active); 54 | setBreadcrumbItems(linkItems); 55 | }; 56 | 57 | function findParentElements(navItems, targetUrl, parents = []) { 58 | for (const item of navItems) { 59 | // Add the current item to the parents array 60 | const newParents = [...parents, item]; 61 | 62 | // Check if the current item matches the target URL 63 | if (item.url && item.url === targetUrl && targetUrl.includes(item.url)) { 64 | return newParents; // Return the array of parent elements 65 | } 66 | 67 | // If the item has children, recurse into them 68 | if (item.children) { 69 | const result = findParentElements(item.children, targetUrl, newParents); 70 | if (result) { 71 | return result; // Return the result if found in children 72 | } 73 | } 74 | } 75 | 76 | return null; // Return null if no match is found 77 | } 78 | 79 | if (!activeItem || activeItem.breadcrumbs === false) { 80 | return null; 81 | } 82 | 83 | function CoreBreadcrumb() { 84 | return ( 85 | 86 | 87 | {breadcrumbItems.length && 88 | breadcrumbItems.map((item, index) => ( 89 | 101 | {icons && item.icon && } {item.title} 102 | 103 | ))} 104 | {activeItem && ( 105 | 106 | {icons && activeItem.icon && } 107 | {activeItem.title} 108 | 109 | )} 110 | 111 | 112 | 113 | {title || activeItem?.title} 114 | 115 | 116 | ); 117 | } 118 | 119 | return ( 120 | 121 | 122 | {divider && } 123 | 124 | ); 125 | } 126 | 127 | Breadcrumbs.propTypes = { 128 | data: PropTypes.array, 129 | divider: PropTypes.bool, 130 | title: PropTypes.string, 131 | icons: PropTypes.bool, 132 | sx: PropTypes.any, 133 | rest: PropTypes.any 134 | }; 135 | -------------------------------------------------------------------------------- /src/layouts/MainLayout/Header/Notification.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useState } from 'react'; 3 | 4 | // material-ui 5 | import Avatar from '@mui/material/Avatar'; 6 | import Chip from '@mui/material/Chip'; 7 | import ClickAwayListener from '@mui/material/ClickAwayListener'; 8 | import Fade from '@mui/material/Fade'; 9 | import IconButton from '@mui/material/IconButton'; 10 | import List from '@mui/material/List'; 11 | import ListItemAvatar from '@mui/material/ListItemAvatar'; 12 | import ListItemButton from '@mui/material/ListItemButton'; 13 | import ListItemText from '@mui/material/ListItemText'; 14 | import ListSubheader from '@mui/material/ListSubheader'; 15 | import Popper from '@mui/material/Popper'; 16 | import Stack from '@mui/material/Stack'; 17 | import Typography from '@mui/material/Typography'; 18 | import Box from '@mui/material/Box'; 19 | 20 | // project imports 21 | import MainCard from 'components/cards/MainCard'; 22 | import SimpleBar from 'components/third-party/SimpleBar'; 23 | 24 | // assets 25 | import avatar1 from 'assets/images/users/avatar-1.jpg'; 26 | import avatar2 from 'assets/images/users/avatar-2.jpg'; 27 | import avatar3 from 'assets/images/users/avatar-3.jpg'; 28 | import avatar4 from 'assets/images/users/avatar-4.jpg'; 29 | import AccessTimeTwoToneIcon from '@mui/icons-material/AccessTimeTwoTone'; 30 | import NotificationsNoneTwoToneIcon from '@mui/icons-material/NotificationsNoneTwoTone'; 31 | 32 | const notifications = [ 33 | { avatar: avatar1, name: 'John Doe', time: 'now', message: 'New ticket Added' }, 34 | { avatar: avatar2, name: 'Joseph William', time: '10 min', message: 'Purchase a new product' }, 35 | { avatar: avatar3, name: 'Sara Soudein', time: '12 min', message: 'Currently Login' }, 36 | { avatar: avatar4, name: 'Sepha Wilon', time: '30 min', message: 'Purchase a new product' } 37 | ]; 38 | 39 | // ==============================|| NOTIFICATION ITEM ||============================== // 40 | 41 | function NotificationItem({ avatar, name, time, message }) { 42 | return ( 43 | 44 | 45 | 46 | 47 | 50 | {name} 51 | 52 | 53 | {time} 54 | 55 | 56 | } 57 | secondary={{message}} 58 | /> 59 | 60 | ); 61 | } 62 | 63 | // ==============================|| NOTIFICATION ||============================== // 64 | 65 | export default function Notification() { 66 | const [open, setOpen] = useState(false); 67 | const [anchorEl, setAnchorEl] = useState(null); 68 | 69 | const handleClick = (event) => { 70 | setAnchorEl(event.currentTarget); 71 | setOpen((previousOpen) => !previousOpen); 72 | }; 73 | 74 | const handleClickAway = () => { 75 | setOpen(false); 76 | }; 77 | 78 | const canBeOpen = open && Boolean(anchorEl); 79 | const id = canBeOpen ? 'notification-popper' : undefined; 80 | 81 | return ( 82 | 83 | 84 | 85 | 86 | 87 | 88 | 97 | {({ TransitionProps }) => ( 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | {notifications.slice(1).map((item, index) => ( 112 | 113 | ))} 114 | 115 | 116 | 117 | 118 | )} 119 | 120 | 121 | 122 | ); 123 | } 124 | 125 | NotificationItem.propTypes = { avatar: PropTypes.string, name: PropTypes.string, time: PropTypes.string, message: PropTypes.string }; 126 | -------------------------------------------------------------------------------- /favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/sections/auth/AuthRegister.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useEffect, useState } from 'react'; 3 | import { Link } from 'react-router-dom'; 4 | 5 | // material-ui 6 | import Button from '@mui/material/Button'; 7 | import CardMedia from '@mui/material/CardMedia'; 8 | import CircularProgress from '@mui/material/CircularProgress'; 9 | import Checkbox from '@mui/material/Checkbox'; 10 | import Divider from '@mui/material/Divider'; 11 | import FormControl from '@mui/material/FormControl'; 12 | import FormControlLabel from '@mui/material/FormControlLabel'; 13 | import FormHelperText from '@mui/material/FormHelperText'; 14 | import Grid from '@mui/material/Grid'; 15 | import InputAdornment from '@mui/material/InputAdornment'; 16 | import InputLabel from '@mui/material/InputLabel'; 17 | import OutlinedInput from '@mui/material/OutlinedInput'; 18 | import Stack from '@mui/material/Stack'; 19 | import TextField from '@mui/material/TextField'; 20 | import Typography from '@mui/material/Typography'; 21 | import Box from '@mui/material/Box'; 22 | 23 | // third party 24 | import { useForm } from 'react-hook-form'; 25 | 26 | // project imports 27 | import { strengthColor, strengthIndicator } from 'utils/passwordStrength'; 28 | import { emailSchema, firstNameSchema, lastNameSchema, passwordSchema } from 'utils/validationSchema'; 29 | 30 | // assets 31 | import Visibility from '@mui/icons-material/Visibility'; 32 | import VisibilityOff from '@mui/icons-material/VisibilityOff'; 33 | import Google from 'assets/images/social-google.svg'; 34 | 35 | // ==============================|| AUTH - REGISTER ||============================== // 36 | 37 | export default function AuthRegister({ inputSx }) { 38 | const [isPasswordVisible, setIsPasswordVisible] = useState(false); 39 | const [level, setLevel] = useState(); 40 | const [checked, setChecked] = useState(true); 41 | 42 | // Initialize react-hook-form 43 | const { 44 | register, 45 | watch, 46 | formState: { errors } 47 | } = useForm(); 48 | 49 | const passwordValue = watch('password'); 50 | 51 | useEffect(() => { 52 | const temp = strengthIndicator(passwordValue); 53 | setLevel(strengthColor(temp)); 54 | }, [passwordValue]); 55 | 56 | return ( 57 | <> 58 | 67 | 68 | 69 | 70 | 81 | OR 82 | 83 | 84 | 85 | 86 | 87 | Sign up with Email address 88 | 89 | 90 |
91 | 92 | 93 | 101 | {errors.firstname?.message && {errors.firstname.message}} 102 | 103 | 104 | 112 | {errors.lastname?.message && {errors.lastname.message}} 113 | 114 | 115 | 125 | {errors.email?.message && {errors.email.message}} 126 | 127 | 128 | 129 | Password 130 | setIsPasswordVisible(!isPasswordVisible)}> 139 | {isPasswordVisible ? : } 140 | 141 | } 142 | sx={inputSx} 143 | /> 144 | 145 | {errors.password?.message && {errors.password.message}} 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | {level?.label} 154 | 155 | 156 | 157 | 158 | setChecked(event.target.checked)} name="checked" />} 161 | label={ 162 | 163 | Agree with   164 | 165 | Terms & Condition. 166 | 167 | 168 | } 169 | /> 170 | 171 | 180 | 181 | 182 | ); 183 | } 184 | 185 | AuthRegister.propTypes = { inputSx: PropTypes.any }; 186 | -------------------------------------------------------------------------------- /src/assets/images/logo-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/assets/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Materially Free React Material UI Dashboard Template [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Download%20Materially%20React%20-%20The%20professional%20Material%20designed%20React%20Admin%20Dashboard%20Template%20&url=https://codedthemes.com/demos/admin-templates/materially/react/default&via=codedthemes&hashtags=reactjs,webdev,developers,javascript) 2 | 3 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 4 | [![GitHub package version](https://img.shields.io/github/package-json/v/codedthemes/materially-free-react-admin-template)](https://github.com/codedthemes/materially-free-react-admin-template/) 5 | [![Price](https://img.shields.io/badge/price-FREE-0098f7.svg)](https://github.com/codedthemes/materially-free-react-admin-template/blob/main/LICENSE) 6 | [![Download ZIP](https://img.shields.io/badge/Download-ZIP-blue?style=flat-square&logo=github)](https://codedthemes.com/item/materially-free-reactjs-admin-template/) 7 | [![Join Discord](https://img.shields.io/badge/Join-Discord-5865F2?style=flat-square&logo=discord&logoColor=white)](https://discord.com/invite/p2E2WhCb6s) 8 | 9 | Materially is a free and open source React redux dashboard template made using the Material UI React component library with aim of flexibility and better customizability. 10 | 11 | ✨ Support us! If you like this theme, click the ⭐ (Top right) and let it shine 12 | 13 | ![IMG_8566.jpg](https://org-public-assets.s3.us-west-2.amazonaws.com/Free-Version-Banners/GITHUB-FREE-REACT-REPO%20-%20Materially.jpg) 14 | 15 | ## Table of contents 16 | 17 | - [Getting Started](#getting-started) 18 | - [Download](#download) 19 | - [Why Materially?](#why-materially) 20 | - [What's included in Premium Version?](#whats-included-in-premium-version) 21 | - [Documentation](#documentation) 22 | - [Browser support](#browser-support) 23 | - [Technology Stack](#technology-stack) 24 | - 💰[Save more with Big Bundle](#save-more-with-big-bundle)💰 25 | - [More React Dashboard Templates](#more-react-dashboard-templates) 26 | - [Issues?](#issues) 27 | - [License](#license) 28 | - [Contributor](#contributor) 29 | - [Useful Resources](#useful-resources) 30 | - [Community](#community) 31 | - [Follow us](#follow-us) 32 | 33 | ## Getting Started 34 | 35 | 11. Clone from Github 36 | 37 | ``` 38 | git clone https://github.com/codedthemes/materially-free-react-admin-template.git 39 | ``` 40 | 41 | 2. Install packages 42 | 43 | ``` 44 | yarn 45 | ``` 46 | 47 | 3. Run project 48 | 49 | ``` 50 | yarn start 51 | ``` 52 | 53 | ## Download 54 | 55 | - Materially Free 56 | - [Live Preview](https://codedthemes.com/demos/admin-templates/materially/react/free/) 57 | - [Download](https://github.com/codedthemes/materially-free-react-admin-template) 58 | - Materially Pro 59 | - [Live Preview](https://codedthemes.com/demos/admin-templates/materially/react/default) 60 | - [Download](https://codedthemes.com/item/materially-reactjs-admin-dashboard/) 61 | 62 | ## Why Materially? 63 | 64 | Materially offers everything needed to build an advanced dashboard application. In the initial release, we included following high-end features, 65 | 66 | - Support React 19. 67 | - Professional user interface. 68 | - Material UI React components. 69 | - Fully responsive, all modern browser supported. 70 | - Easy to use code structure 71 | - Flexible & high-Performance code 72 | - Simple documentation 73 | 74 | ## What's included in Premium Version? 75 | 76 | The [Pro version](https://codedthemes.com/demos/admin-templates/materially/react/default) of Materially react template includes features such as multiple apps, advance components, form plugins, layouts, widgets, and more. 77 | 78 | | [Materially Free](https://codedthemes.com/demos/admin-templates/materially/react/free/) | [Materially Pro](https://codedthemes.com/demos/admin-templates/materially/react/default) | 79 | | ------------------------------------------------------------------------------------------------------ | :--------------------------------------------------------------------------------------------------------------- | 80 | | **5** Demo pages | **100+** Demo pages | 81 | | - | ✓ 60+ Components | 82 | | - | ✓ Dark/Light Mode 🌓 | 83 | | - | ✓ RTL | 84 | | - | ✓ Localization | 85 | | - | ✓ [More components](https://codedthemes.com/demos/admin-templates/materially/react/default/components/accordion) | 86 | | ✓ [MIT License](https://github.com/codedthemes/materially-free-react-admin-template/blob/main/LICENSE) | ✓ [Pro License](https://codedthemes.com/item/materially-reactjs-admin-dashboard/) | 87 | 88 | ## Documentation 89 | 90 | [Materially React Documentation](https://codedthemes.gitbook.io/materially-react-material-documentation/) helps you out in all aspects from Installation to deployment. 91 | 92 | ## Browser support 93 | 94 | 95 | 96 | ## Technology Stack 97 | 98 | - React (19) 99 | - Material UI (7) 100 | - SASS with JSS Powered 101 | - Vite 102 | - Redux toolkit 103 | - React Router 104 | - Localization 105 | 106 | ## Save more with Big Bundle 107 | 108 | [![bundle-image](https://org-public-assets.s3.us-west-2.amazonaws.com/Banners/Bundle+banner.png)](https://links.codedthemes.com/jhFBJ) 109 | 110 | ## More React Dashboard Templates 111 | 112 | | Dashboard | FREE | PRO | 113 | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- | 114 | | | [**Free**](https://codedthemes.com/item/berry-mui-free-react-admin-template/) | [**Pro**](https://codedthemes.com/item/berry-material-react-admin-template/) | 115 | | | [**Free**](https://codedthemes.com/item/mantis-free-mui-admin-template/) | [**Pro**](https://codedthemes.com/item/mantis-mui-react-dashboard-template/) | 116 | | | [**Free**](https://codedthemes.com/item/datta-able-react-free-admin-template/) | [**Pro**](https://codedthemes.com/item/datta-able-react-admin-template/) | 117 | 118 | ## Issues 119 | 120 | If you found a bug in any version, please generate a [GitHub issue](https://github.com/codedthemes/materially-free-react-admin-template/issues). We are trying our best to resolve the issue. 121 | 122 | ## License 123 | 124 | - Licensed under [MIT](https://github.com/codedthemes/materially-free-react-admin-template/blob/main/LICENSE) 125 | - Copyright © [CodedThemes](https://codedthemes.com/) 126 | 127 | ## Contributor 128 | 129 | **CodedThemes Team** 130 | 131 | - https://x.com/codedthemes 132 | - https://github.com/codedthemes 133 | 134 | **Rakesh Nakrani** 135 | 136 | - https://x.com/rakesh_nakrani 137 | 138 | **Brijesh Dobariya** 139 | 140 | - https://x.com/dobaria_brijesh 141 | 142 | ## Useful Resources 143 | 144 | - [More Admin Templates From CodedThemes](https://codedthemes.com/item/category/admin-templates/) 145 | - [Freebies From CodedThemes](https://codedthemes.com/item/category/free-templates/) 146 | - [Big Bundles](https://codedthemes.com/item/big-bundle/) 147 | - [Figma UI Kits](https://codedthemes.com/item/category/templates/figma/) 148 | - [Affiliate Program](https://codedthemes.com/affiliate/) 149 | - [Blogs](https://blog.codedthemes.com/) 150 | 151 | ## Community 152 | 153 | - 👥Follow [@codedthemes](https://x.com/codedthemes) 154 | - 🔗Join [Discord](https://discord.com/invite/p2E2WhCb6s) 155 | - 🔔Subscribe to [Codedtheme Blogs](https://blog.codedthemes.com/) 156 | 157 | ## Follow Us 158 | 159 | - [Twitter](https://twitter.com/codedthemes) 🐦 160 | - [Dribbble](https://dribbble.com/codedthemes) 🏀 161 | - [Github](https://github.com/codedthemes) 🐙 162 | - [LinkedIn](https://www.linkedin.com/company/codedthemes/) 💼 163 | - [Instagram](https://www.instagram.com/codedthemes/) 📷 164 | - [Facebook](https://www.facebook.com/codedthemes) 🟦 165 | --------------------------------------------------------------------------------