New Frontend Preps
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
import { Routes, Route, Navigate } from "react-router-dom";
|
||||
import { Dashboard, Auth } from "@/layouts";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/dashboard/*" element={<Dashboard />} />
|
||||
<Route path="/auth/*" element={<Auth />} />
|
||||
<Route path="*" element={<Navigate to="/dashboard/home" replace />} />
|
||||
</Routes>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,61 @@
|
||||
export const chartsConfig = {
|
||||
chart: {
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
title: {
|
||||
show: "",
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
xaxis: {
|
||||
axisTicks: {
|
||||
show: false,
|
||||
},
|
||||
axisBorder: {
|
||||
show: false,
|
||||
},
|
||||
labels: {
|
||||
style: {
|
||||
colors: "#37474f",
|
||||
fontSize: "13px",
|
||||
fontFamily: "inherit",
|
||||
fontWeight: 300,
|
||||
},
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
labels: {
|
||||
style: {
|
||||
colors: "#37474f",
|
||||
fontSize: "13px",
|
||||
fontFamily: "inherit",
|
||||
fontWeight: 300,
|
||||
},
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
show: true,
|
||||
borderColor: "#dddddd",
|
||||
strokeDashArray: 5,
|
||||
xaxis: {
|
||||
lines: {
|
||||
show: true,
|
||||
},
|
||||
},
|
||||
padding: {
|
||||
top: 5,
|
||||
right: 20,
|
||||
},
|
||||
},
|
||||
fill: {
|
||||
opacity: 0.8,
|
||||
},
|
||||
tooltip: {
|
||||
theme: "dark",
|
||||
},
|
||||
};
|
||||
|
||||
export default chartsConfig;
|
||||
@@ -0,0 +1 @@
|
||||
export * from "@/configs/charts-config";
|
||||
@@ -0,0 +1,85 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
export const MaterialTailwind = React.createContext(null);
|
||||
MaterialTailwind.displayName = "MaterialTailwindContext";
|
||||
|
||||
export function reducer(state, action) {
|
||||
switch (action.type) {
|
||||
case "OPEN_SIDENAV": {
|
||||
return { ...state, openSidenav: action.value };
|
||||
}
|
||||
case "SIDENAV_TYPE": {
|
||||
return { ...state, sidenavType: action.value };
|
||||
}
|
||||
case "SIDENAV_COLOR": {
|
||||
return { ...state, sidenavColor: action.value };
|
||||
}
|
||||
case "TRANSPARENT_NAVBAR": {
|
||||
return { ...state, transparentNavbar: action.value };
|
||||
}
|
||||
case "FIXED_NAVBAR": {
|
||||
return { ...state, fixedNavbar: action.value };
|
||||
}
|
||||
case "OPEN_CONFIGURATOR": {
|
||||
return { ...state, openConfigurator: action.value };
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Unhandled action type: ${action.type}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function MaterialTailwindControllerProvider({ children }) {
|
||||
const initialState = {
|
||||
openSidenav: false,
|
||||
sidenavColor: "dark",
|
||||
sidenavType: "white",
|
||||
transparentNavbar: true,
|
||||
fixedNavbar: false,
|
||||
openConfigurator: false,
|
||||
};
|
||||
|
||||
const [controller, dispatch] = React.useReducer(reducer, initialState);
|
||||
const value = React.useMemo(
|
||||
() => [controller, dispatch],
|
||||
[controller, dispatch]
|
||||
);
|
||||
|
||||
return (
|
||||
<MaterialTailwind.Provider value={value}>
|
||||
{children}
|
||||
</MaterialTailwind.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useMaterialTailwindController() {
|
||||
const context = React.useContext(MaterialTailwind);
|
||||
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
"useMaterialTailwindController should be used inside the MaterialTailwindControllerProvider."
|
||||
);
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
MaterialTailwindControllerProvider.displayName = "/src/context/index.jsx";
|
||||
|
||||
MaterialTailwindControllerProvider.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
export const setOpenSidenav = (dispatch, value) =>
|
||||
dispatch({ type: "OPEN_SIDENAV", value });
|
||||
export const setSidenavType = (dispatch, value) =>
|
||||
dispatch({ type: "SIDENAV_TYPE", value });
|
||||
export const setSidenavColor = (dispatch, value) =>
|
||||
dispatch({ type: "SIDENAV_COLOR", value });
|
||||
export const setTransparentNavbar = (dispatch, value) =>
|
||||
dispatch({ type: "TRANSPARENT_NAVBAR", value });
|
||||
export const setFixedNavbar = (dispatch, value) =>
|
||||
dispatch({ type: "FIXED_NAVBAR", value });
|
||||
export const setOpenConfigurator = (dispatch, value) =>
|
||||
dispatch({ type: "OPEN_CONFIGURATOR", value });
|
||||
@@ -0,0 +1,52 @@
|
||||
export const authorsTableData = [
|
||||
{
|
||||
img: "/img/team-2.jpeg",
|
||||
name: "John Michael",
|
||||
email: "john@creative-tim.com",
|
||||
job: ["Manager", "Organization"],
|
||||
online: true,
|
||||
date: "23/04/18",
|
||||
},
|
||||
{
|
||||
img: "/img/team-1.jpeg",
|
||||
name: "Alexa Liras",
|
||||
email: "alexa@creative-tim.com",
|
||||
job: ["Programator", "Developer"],
|
||||
online: false,
|
||||
date: "11/01/19",
|
||||
},
|
||||
{
|
||||
img: "/img/team-4.jpeg",
|
||||
name: "Laurent Perrier",
|
||||
email: "laurent@creative-tim.com",
|
||||
job: ["Executive", "Projects"],
|
||||
online: true,
|
||||
date: "19/09/17",
|
||||
},
|
||||
{
|
||||
img: "/img/team-3.jpeg",
|
||||
name: "Michael Levi",
|
||||
email: "michael@creative-tim.com",
|
||||
job: ["Programator", "Developer"],
|
||||
online: true,
|
||||
date: "24/12/08",
|
||||
},
|
||||
{
|
||||
img: "/img/bruce-mars.jpeg",
|
||||
name: "Bruce Mars",
|
||||
email: "bruce@creative-tim.com",
|
||||
job: ["Manager", "Executive"],
|
||||
online: false,
|
||||
date: "04/10/21",
|
||||
},
|
||||
{
|
||||
img: "/img/team-2.jpeg",
|
||||
name: "Alexander",
|
||||
email: "alexander@creative-tim.com",
|
||||
job: ["Programator", "Developer"],
|
||||
online: false,
|
||||
date: "14/09/20",
|
||||
},
|
||||
];
|
||||
|
||||
export default authorsTableData;
|
||||
@@ -0,0 +1,29 @@
|
||||
export const conversationsData = [
|
||||
{
|
||||
img: "/img/team-1.jpeg",
|
||||
name: "Sophie B.",
|
||||
message: "Hi! I need more information...",
|
||||
},
|
||||
{
|
||||
img: "/img/team-2.jpeg",
|
||||
name: "Alexander",
|
||||
message: "Awesome work, can you...",
|
||||
},
|
||||
{
|
||||
img: "/img/team-3.jpeg",
|
||||
name: "Ivanna",
|
||||
message: "About files I can...",
|
||||
},
|
||||
{
|
||||
img: "/img/team-4.jpeg",
|
||||
name: "Peterson",
|
||||
message: "Have a great afternoon...",
|
||||
},
|
||||
{
|
||||
img: "/img/bruce-mars.jpeg",
|
||||
name: "Bruce Mars",
|
||||
message: "Hi! I need more information...",
|
||||
},
|
||||
];
|
||||
|
||||
export default conversationsData;
|
||||
@@ -0,0 +1,8 @@
|
||||
export * from "@/data/statistics-cards-data";
|
||||
export * from "@/data/statistics-charts-data";
|
||||
export * from "@/data/projects-table-data";
|
||||
export * from "@/data/orders-overview-data";
|
||||
export * from "@/data/platform-settings-data";
|
||||
export * from "@/data/conversations-data";
|
||||
export * from "@/data/projects-data";
|
||||
export * from "@/data/authors-table-data";
|
||||
@@ -0,0 +1,49 @@
|
||||
import {
|
||||
BellIcon,
|
||||
PlusCircleIcon,
|
||||
ShoppingCartIcon,
|
||||
CreditCardIcon,
|
||||
LockOpenIcon,
|
||||
BanknotesIcon,
|
||||
} from "@heroicons/react/24/solid";
|
||||
|
||||
export const ordersOverviewData = [
|
||||
{
|
||||
icon: BellIcon,
|
||||
color: "text-blue-gray-300",
|
||||
title: "$2400, Design changes",
|
||||
description: "22 DEC 7:20 PM",
|
||||
},
|
||||
{
|
||||
icon: PlusCircleIcon,
|
||||
color: "text-blue-gray-300",
|
||||
title: "New order #1832412",
|
||||
description: "21 DEC 11 PM",
|
||||
},
|
||||
{
|
||||
icon: ShoppingCartIcon,
|
||||
color: "text-blue-gray-300",
|
||||
title: "Server payments for April",
|
||||
description: "21 DEC 9:34 PM",
|
||||
},
|
||||
{
|
||||
icon: CreditCardIcon,
|
||||
color: "text-blue-gray-300",
|
||||
title: "New card added for order #4395133",
|
||||
description: "20 DEC 2:20 AM",
|
||||
},
|
||||
{
|
||||
icon: LockOpenIcon,
|
||||
color: "text-blue-gray-300",
|
||||
title: "Unlock packages for development",
|
||||
description: "18 DEC 4:54 AM",
|
||||
},
|
||||
{
|
||||
icon: BanknotesIcon,
|
||||
color: "text-blue-gray-300",
|
||||
title: "New order #9583120",
|
||||
description: "17 DEC",
|
||||
},
|
||||
];
|
||||
|
||||
export default ordersOverviewData;
|
||||
@@ -0,0 +1,38 @@
|
||||
export const platformSettingsData = [
|
||||
{
|
||||
title: "account",
|
||||
options: [
|
||||
{
|
||||
checked: true,
|
||||
label: "Email me when someone follows me",
|
||||
},
|
||||
{
|
||||
checked: false,
|
||||
label: "Email me when someone answers on my post",
|
||||
},
|
||||
{
|
||||
checked: true,
|
||||
label: "Email me when someone mentions me",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "application",
|
||||
options: [
|
||||
{
|
||||
checked: false,
|
||||
label: "New launches and projects",
|
||||
},
|
||||
{
|
||||
checked: true,
|
||||
label: "Monthly product updates",
|
||||
},
|
||||
{
|
||||
checked: false,
|
||||
label: "Subscribe to newsletter",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default platformSettingsData;
|
||||
@@ -0,0 +1,60 @@
|
||||
export const projectsData = [
|
||||
{
|
||||
img: "/img/home-decor-1.jpeg",
|
||||
title: "Modern",
|
||||
tag: "Project #1",
|
||||
description:
|
||||
"As Uber works through a huge amount of internal management turmoil.",
|
||||
route: "/dashboard/profile",
|
||||
members: [
|
||||
{ img: "/img/team-1.jpeg", name: "Romina Hadid" },
|
||||
{ img: "/img/team-2.jpeg", name: "Ryan Tompson" },
|
||||
{ img: "/img/team-3.jpeg", name: "Jessica Doe" },
|
||||
{ img: "/img/team-4.jpeg", name: "Alexander Smith" },
|
||||
],
|
||||
},
|
||||
{
|
||||
img: "/img/home-decor-2.jpeg",
|
||||
title: "Scandinavian",
|
||||
tag: "Project #2",
|
||||
description:
|
||||
"Music is something that every person has his or her own specific opinion about.",
|
||||
route: "/dashboard/profile",
|
||||
members: [
|
||||
{ img: "/img/team-4.jpeg", name: "Alexander Smith" },
|
||||
{ img: "/img/team-3.jpeg", name: "Jessica Doe" },
|
||||
{ img: "/img/team-2.jpeg", name: "Ryan Tompson" },
|
||||
{ img: "/img/team-1.jpeg", name: "Romina Hadid" },
|
||||
],
|
||||
},
|
||||
{
|
||||
img: "/img/home-decor-3.jpeg",
|
||||
title: "Minimalist",
|
||||
tag: "Project #3",
|
||||
description:
|
||||
"Different people have different taste, and various types of music.",
|
||||
route: "/dashboard/profile",
|
||||
members: [
|
||||
{ img: "/img/team-1.jpeg", name: "Romina Hadid" },
|
||||
{ img: "/img/team-2.jpeg", name: "Ryan Tompson" },
|
||||
{ img: "/img/team-3.jpeg", name: "Jessica Doe" },
|
||||
{ img: "/img/team-4.jpeg", name: "Alexander Smith" },
|
||||
],
|
||||
},
|
||||
{
|
||||
img: "/img/home-decor-4.jpeg",
|
||||
title: "Gothic",
|
||||
tag: "Project #4",
|
||||
description:
|
||||
"Why would anyone pick blue over pink? Pink is obviously a better color.",
|
||||
route: "/dashboard/profile",
|
||||
members: [
|
||||
{ img: "/img/team-4.jpeg", name: "Alexander Smith" },
|
||||
{ img: "/img/team-3.jpeg", name: "Jessica Doe" },
|
||||
{ img: "/img/team-2.jpeg", name: "Ryan Tompson" },
|
||||
{ img: "/img/team-1.jpeg", name: "Romina Hadid" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default projectsData;
|
||||
@@ -0,0 +1,65 @@
|
||||
export const projectsTableData = [
|
||||
{
|
||||
img: "/img/logo-xd.svg",
|
||||
name: "Material XD Version",
|
||||
members: [
|
||||
{ img: "/img/team-1.jpeg", name: "Romina Hadid" },
|
||||
{ img: "/img/team-2.jpeg", name: "Ryan Tompson" },
|
||||
{ img: "/img/team-3.jpeg", name: "Jessica Doe" },
|
||||
{ img: "/img/team-4.jpeg", name: "Alexander Smith" },
|
||||
],
|
||||
budget: "$14,000",
|
||||
completion: 60,
|
||||
},
|
||||
{
|
||||
img: "/img/logo-atlassian.svg",
|
||||
name: "Add Progress Track",
|
||||
members: [
|
||||
{ img: "/img/team-2.jpeg", name: "Ryan Tompson" },
|
||||
{ img: "/img/team-4.jpeg", name: "Alexander Smith" },
|
||||
],
|
||||
budget: "$3,000",
|
||||
completion: 10,
|
||||
},
|
||||
{
|
||||
img: "/img/logo-slack.svg",
|
||||
name: "Fix Platform Errors",
|
||||
members: [
|
||||
{ img: "/img/team-3.jpeg", name: "Jessica Doe" },
|
||||
{ img: "/img/team-1.jpeg", name: "Romina Hadid" },
|
||||
],
|
||||
budget: "Not set",
|
||||
completion: 100,
|
||||
},
|
||||
{
|
||||
img: "/img/logo-spotify.svg",
|
||||
name: "Launch our Mobile App",
|
||||
members: [
|
||||
{ img: "/img/team-4.jpeg", name: "Alexander Smith" },
|
||||
{ img: "/img/team-3.jpeg", name: "Jessica Doe" },
|
||||
{ img: "/img/team-2.jpeg", name: "Ryan Tompson" },
|
||||
{ img: "/img/team-1.jpeg", name: "Romina Hadid" },
|
||||
],
|
||||
budget: "$20,500",
|
||||
completion: 100,
|
||||
},
|
||||
{
|
||||
img: "/img/logo-jira.svg",
|
||||
name: "Add the New Pricing Page",
|
||||
members: [{ img: "/img/team-4.jpeg", name: "Alexander Smith" }],
|
||||
budget: "$500",
|
||||
completion: 25,
|
||||
},
|
||||
{
|
||||
img: "/img/logo-invision.svg",
|
||||
name: "Redesign New Online Shop",
|
||||
members: [
|
||||
{ img: "/img/team-1.jpeg", name: "Romina Hadid" },
|
||||
{ img: "/img/team-4.jpeg", name: "Alexander Smith" },
|
||||
],
|
||||
budget: "$2,000",
|
||||
completion: 40,
|
||||
},
|
||||
];
|
||||
|
||||
export default projectsTableData;
|
||||
@@ -0,0 +1,55 @@
|
||||
import {
|
||||
BanknotesIcon,
|
||||
UserPlusIcon,
|
||||
UsersIcon,
|
||||
ChartBarIcon,
|
||||
} from "@heroicons/react/24/solid";
|
||||
|
||||
export const statisticsCardsData = [
|
||||
{
|
||||
color: "gray",
|
||||
icon: BanknotesIcon,
|
||||
title: "Today's Money",
|
||||
value: "$53k",
|
||||
footer: {
|
||||
color: "text-green-500",
|
||||
value: "+55%",
|
||||
label: "than last week",
|
||||
},
|
||||
},
|
||||
{
|
||||
color: "gray",
|
||||
icon: UsersIcon,
|
||||
title: "Today's Users",
|
||||
value: "2,300",
|
||||
footer: {
|
||||
color: "text-green-500",
|
||||
value: "+3%",
|
||||
label: "than last month",
|
||||
},
|
||||
},
|
||||
{
|
||||
color: "gray",
|
||||
icon: UserPlusIcon,
|
||||
title: "New Clients",
|
||||
value: "3,462",
|
||||
footer: {
|
||||
color: "text-red-500",
|
||||
value: "-2%",
|
||||
label: "than yesterday",
|
||||
},
|
||||
},
|
||||
{
|
||||
color: "gray",
|
||||
icon: ChartBarIcon,
|
||||
title: "Sales",
|
||||
value: "$103,430",
|
||||
footer: {
|
||||
color: "text-green-500",
|
||||
value: "+5%",
|
||||
label: "than yesterday",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default statisticsCardsData;
|
||||
@@ -0,0 +1,131 @@
|
||||
import { chartsConfig } from "@/configs";
|
||||
|
||||
const websiteViewsChart = {
|
||||
type: "bar",
|
||||
height: 220,
|
||||
series: [
|
||||
{
|
||||
name: "Views",
|
||||
data: [50, 20, 10, 22, 50, 10, 40],
|
||||
},
|
||||
],
|
||||
options: {
|
||||
...chartsConfig,
|
||||
colors: "#388e3c",
|
||||
plotOptions: {
|
||||
bar: {
|
||||
columnWidth: "16%",
|
||||
borderRadius: 5,
|
||||
},
|
||||
},
|
||||
xaxis: {
|
||||
...chartsConfig.xaxis,
|
||||
categories: ["M", "T", "W", "T", "F", "S", "S"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const dailySalesChart = {
|
||||
type: "line",
|
||||
height: 220,
|
||||
series: [
|
||||
{
|
||||
name: "Sales",
|
||||
data: [50, 40, 300, 320, 500, 350, 200, 230, 500],
|
||||
},
|
||||
],
|
||||
options: {
|
||||
...chartsConfig,
|
||||
colors: ["#0288d1"],
|
||||
stroke: {
|
||||
lineCap: "round",
|
||||
},
|
||||
markers: {
|
||||
size: 5,
|
||||
},
|
||||
xaxis: {
|
||||
...chartsConfig.xaxis,
|
||||
categories: [
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec",
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const completedTaskChart = {
|
||||
type: "line",
|
||||
height: 220,
|
||||
series: [
|
||||
{
|
||||
name: "Sales",
|
||||
data: [50, 40, 300, 320, 500, 350, 200, 230, 500],
|
||||
},
|
||||
],
|
||||
options: {
|
||||
...chartsConfig,
|
||||
colors: ["#388e3c"],
|
||||
stroke: {
|
||||
lineCap: "round",
|
||||
},
|
||||
markers: {
|
||||
size: 5,
|
||||
},
|
||||
xaxis: {
|
||||
...chartsConfig.xaxis,
|
||||
categories: [
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec",
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
const completedTasksChart = {
|
||||
...completedTaskChart,
|
||||
series: [
|
||||
{
|
||||
name: "Tasks",
|
||||
data: [50, 40, 300, 220, 500, 250, 400, 230, 500],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const statisticsChartsData = [
|
||||
{
|
||||
color: "white",
|
||||
title: "Website View",
|
||||
description: "Last Campaign Performance",
|
||||
footer: "campaign sent 2 days ago",
|
||||
chart: websiteViewsChart,
|
||||
},
|
||||
{
|
||||
color: "white",
|
||||
title: "Daily Sales",
|
||||
description: "15% increase in today sales",
|
||||
footer: "updated 4 min ago",
|
||||
chart: dailySalesChart,
|
||||
},
|
||||
{
|
||||
color: "white",
|
||||
title: "Completed Tasks",
|
||||
description: "Last Campaign Performance",
|
||||
footer: "just updated",
|
||||
chart: completedTasksChart,
|
||||
},
|
||||
];
|
||||
|
||||
export default statisticsChartsData;
|
||||
@@ -0,0 +1,52 @@
|
||||
import { Routes, Route } from "react-router-dom";
|
||||
import {
|
||||
ChartPieIcon,
|
||||
UserIcon,
|
||||
UserPlusIcon,
|
||||
ArrowRightOnRectangleIcon,
|
||||
} from "@heroicons/react/24/solid";
|
||||
import { Navbar, Footer } from "@/widgets/layout";
|
||||
import routes from "@/routes";
|
||||
|
||||
export function Auth() {
|
||||
const navbarRoutes = [
|
||||
{
|
||||
name: "dashboard",
|
||||
path: "/dashboard/home",
|
||||
icon: ChartPieIcon,
|
||||
},
|
||||
{
|
||||
name: "profile",
|
||||
path: "/dashboard/home",
|
||||
icon: UserIcon,
|
||||
},
|
||||
{
|
||||
name: "sign up",
|
||||
path: "/auth/sign-up",
|
||||
icon: UserPlusIcon,
|
||||
},
|
||||
{
|
||||
name: "sign in",
|
||||
path: "/auth/sign-in",
|
||||
icon: ArrowRightOnRectangleIcon,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="relative min-h-screen w-full">
|
||||
<Routes>
|
||||
{routes.map(
|
||||
({ layout, pages }) =>
|
||||
layout === "auth" &&
|
||||
pages.map(({ path, element }) => (
|
||||
<Route exact path={path} element={element} />
|
||||
))
|
||||
)}
|
||||
</Routes>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Auth.displayName = "/src/layout/Auth.jsx";
|
||||
|
||||
export default Auth;
|
||||
@@ -0,0 +1,56 @@
|
||||
import { Routes, Route } from "react-router-dom";
|
||||
import { Cog6ToothIcon } from "@heroicons/react/24/solid";
|
||||
import { IconButton } from "@material-tailwind/react";
|
||||
import {
|
||||
Sidenav,
|
||||
DashboardNavbar,
|
||||
Configurator,
|
||||
Footer,
|
||||
} from "@/widgets/layout";
|
||||
import routes from "@/routes";
|
||||
import { useMaterialTailwindController, setOpenConfigurator } from "@/context";
|
||||
|
||||
export function Dashboard() {
|
||||
const [controller, dispatch] = useMaterialTailwindController();
|
||||
const { sidenavType } = controller;
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-blue-gray-50/50">
|
||||
<Sidenav
|
||||
routes={routes}
|
||||
brandImg={
|
||||
sidenavType === "dark" ? "/img/logo-ct.png" : "/img/logo-ct-dark.png"
|
||||
}
|
||||
/>
|
||||
<div className="p-4 xl:ml-80">
|
||||
<DashboardNavbar />
|
||||
<Configurator />
|
||||
<IconButton
|
||||
size="lg"
|
||||
color="white"
|
||||
className="fixed bottom-8 right-8 z-40 rounded-full shadow-blue-gray-900/10"
|
||||
ripple={false}
|
||||
onClick={() => setOpenConfigurator(dispatch, true)}
|
||||
>
|
||||
<Cog6ToothIcon className="h-5 w-5" />
|
||||
</IconButton>
|
||||
<Routes>
|
||||
{routes.map(
|
||||
({ layout, pages }) =>
|
||||
layout === "dashboard" &&
|
||||
pages.map(({ path, element }) => (
|
||||
<Route exact path={path} element={element} />
|
||||
))
|
||||
)}
|
||||
</Routes>
|
||||
<div className="text-blue-gray-600">
|
||||
<Footer />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Dashboard.displayName = "/src/layout/dashboard.jsx";
|
||||
|
||||
export default Dashboard;
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "@/layouts/dashboard";
|
||||
export * from "@/layouts/auth";
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
=========================================================
|
||||
* Material Tailwind Dashboard React - v2.1.0
|
||||
=========================================================
|
||||
* Product Page: https://www.creative-tim.com/product/material-tailwind-dashboard-react
|
||||
* Copyright 2023 Creative Tim (https://www.creative-tim.com)
|
||||
* Licensed under MIT (https://github.com/creativetimofficial/material-tailwind-dashboard-react/blob/main/LICENSE.md)
|
||||
* Coded by Creative Tim
|
||||
=========================================================
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*/
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import App from "./App";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
import { ThemeProvider } from "@material-tailwind/react";
|
||||
import { MaterialTailwindControllerProvider } from "@/context";
|
||||
import "../public/css/tailwind.css";
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")).render(
|
||||
<React.StrictMode>
|
||||
<BrowserRouter>
|
||||
<ThemeProvider>
|
||||
<MaterialTailwindControllerProvider>
|
||||
<App />
|
||||
</MaterialTailwindControllerProvider>
|
||||
</ThemeProvider>
|
||||
</BrowserRouter>
|
||||
</React.StrictMode>
|
||||
);
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "@/pages/auth/sign-in";
|
||||
export * from "@/pages/auth/sign-up";
|
||||
@@ -0,0 +1,126 @@
|
||||
import {
|
||||
Card,
|
||||
Input,
|
||||
Checkbox,
|
||||
Button,
|
||||
Typography,
|
||||
} from "@material-tailwind/react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
|
||||
export function SignIn() {
|
||||
return (
|
||||
<section className="m-8 flex gap-4">
|
||||
<div className="w-full lg:w-3/5 mt-24">
|
||||
<div className="text-center">
|
||||
<Typography variant="h2" className="font-bold mb-4">Sign In</Typography>
|
||||
<Typography variant="paragraph" color="blue-gray" className="text-lg font-normal">Enter your email and password to Sign In.</Typography>
|
||||
</div>
|
||||
<form className="mt-8 mb-2 mx-auto w-80 max-w-screen-lg lg:w-1/2">
|
||||
<div className="mb-1 flex flex-col gap-6">
|
||||
<Typography variant="small" color="blue-gray" className="-mb-3 font-medium">
|
||||
Your email
|
||||
</Typography>
|
||||
<Input
|
||||
size="lg"
|
||||
placeholder="name@mail.com"
|
||||
className=" !border-t-blue-gray-200 focus:!border-t-gray-900"
|
||||
labelProps={{
|
||||
className: "before:content-none after:content-none",
|
||||
}}
|
||||
/>
|
||||
<Typography variant="small" color="blue-gray" className="-mb-3 font-medium">
|
||||
Password
|
||||
</Typography>
|
||||
<Input
|
||||
type="password"
|
||||
size="lg"
|
||||
placeholder="********"
|
||||
className=" !border-t-blue-gray-200 focus:!border-t-gray-900"
|
||||
labelProps={{
|
||||
className: "before:content-none after:content-none",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Checkbox
|
||||
label={
|
||||
<Typography
|
||||
variant="small"
|
||||
color="gray"
|
||||
className="flex items-center justify-start font-medium"
|
||||
>
|
||||
I agree the
|
||||
<a
|
||||
href="#"
|
||||
className="font-normal text-black transition-colors hover:text-gray-900 underline"
|
||||
>
|
||||
Terms and Conditions
|
||||
</a>
|
||||
</Typography>
|
||||
}
|
||||
containerProps={{ className: "-ml-2.5" }}
|
||||
/>
|
||||
<Button className="mt-6" fullWidth>
|
||||
Sign In
|
||||
</Button>
|
||||
|
||||
<div className="flex items-center justify-between gap-2 mt-6">
|
||||
<Checkbox
|
||||
label={
|
||||
<Typography
|
||||
variant="small"
|
||||
color="gray"
|
||||
className="flex items-center justify-start font-medium"
|
||||
>
|
||||
Subscribe me to newsletter
|
||||
</Typography>
|
||||
}
|
||||
containerProps={{ className: "-ml-2.5" }}
|
||||
/>
|
||||
<Typography variant="small" className="font-medium text-gray-900">
|
||||
<a href="#">
|
||||
Forgot Password
|
||||
</a>
|
||||
</Typography>
|
||||
</div>
|
||||
<div className="space-y-4 mt-8">
|
||||
<Button size="lg" color="white" className="flex items-center gap-2 justify-center shadow-md" fullWidth>
|
||||
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clipPath="url(#clip0_1156_824)">
|
||||
<path d="M16.3442 8.18429C16.3442 7.64047 16.3001 7.09371 16.206 6.55872H8.66016V9.63937H12.9813C12.802 10.6329 12.2258 11.5119 11.3822 12.0704V14.0693H13.9602C15.4741 12.6759 16.3442 10.6182 16.3442 8.18429Z" fill="#4285F4" />
|
||||
<path d="M8.65974 16.0006C10.8174 16.0006 12.637 15.2922 13.9627 14.0693L11.3847 12.0704C10.6675 12.5584 9.7415 12.8347 8.66268 12.8347C6.5756 12.8347 4.80598 11.4266 4.17104 9.53357H1.51074V11.5942C2.86882 14.2956 5.63494 16.0006 8.65974 16.0006Z" fill="#34A853" />
|
||||
<path d="M4.16852 9.53356C3.83341 8.53999 3.83341 7.46411 4.16852 6.47054V4.40991H1.51116C0.376489 6.67043 0.376489 9.33367 1.51116 11.5942L4.16852 9.53356Z" fill="#FBBC04" />
|
||||
<path d="M8.65974 3.16644C9.80029 3.1488 10.9026 3.57798 11.7286 4.36578L14.0127 2.08174C12.5664 0.72367 10.6469 -0.0229773 8.65974 0.000539111C5.63494 0.000539111 2.86882 1.70548 1.51074 4.40987L4.1681 6.4705C4.8001 4.57449 6.57266 3.16644 8.65974 3.16644Z" fill="#EA4335" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1156_824">
|
||||
<rect width="16" height="16" fill="white" transform="translate(0.5)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
<span>Sign in With Google</span>
|
||||
</Button>
|
||||
<Button size="lg" color="white" className="flex items-center gap-2 justify-center shadow-md" fullWidth>
|
||||
<img src="/img/twitter-logo.svg" height={24} width={24} alt="" />
|
||||
<span>Sign in With Twitter</span>
|
||||
</Button>
|
||||
</div>
|
||||
<Typography variant="paragraph" className="text-center text-blue-gray-500 font-medium mt-4">
|
||||
Not registered?
|
||||
<Link to="/auth/sign-up" className="text-gray-900 ml-1">Create account</Link>
|
||||
</Typography>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<div className="w-2/5 h-full hidden lg:block">
|
||||
<img
|
||||
src="/img/pattern.png"
|
||||
className="h-full w-full object-cover rounded-3xl"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default SignIn;
|
||||
@@ -0,0 +1,94 @@
|
||||
import {
|
||||
Card,
|
||||
Input,
|
||||
Checkbox,
|
||||
Button,
|
||||
Typography,
|
||||
} from "@material-tailwind/react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
|
||||
export function SignUp() {
|
||||
return (
|
||||
<section className="m-8 flex">
|
||||
<div className="w-2/5 h-full hidden lg:block">
|
||||
<img
|
||||
src="/img/pattern.png"
|
||||
className="h-full w-full object-cover rounded-3xl"
|
||||
/>
|
||||
</div>
|
||||
<div className="w-full lg:w-3/5 flex flex-col items-center justify-center">
|
||||
<div className="text-center">
|
||||
<Typography variant="h2" className="font-bold mb-4">Join Us Today</Typography>
|
||||
<Typography variant="paragraph" color="blue-gray" className="text-lg font-normal">Enter your email and password to register.</Typography>
|
||||
</div>
|
||||
<form className="mt-8 mb-2 mx-auto w-80 max-w-screen-lg lg:w-1/2">
|
||||
<div className="mb-1 flex flex-col gap-6">
|
||||
<Typography variant="small" color="blue-gray" className="-mb-3 font-medium">
|
||||
Your email
|
||||
</Typography>
|
||||
<Input
|
||||
size="lg"
|
||||
placeholder="name@mail.com"
|
||||
className=" !border-t-blue-gray-200 focus:!border-t-gray-900"
|
||||
labelProps={{
|
||||
className: "before:content-none after:content-none",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Checkbox
|
||||
label={
|
||||
<Typography
|
||||
variant="small"
|
||||
color="gray"
|
||||
className="flex items-center justify-start font-medium"
|
||||
>
|
||||
I agree the
|
||||
<a
|
||||
href="#"
|
||||
className="font-normal text-black transition-colors hover:text-gray-900 underline"
|
||||
>
|
||||
Terms and Conditions
|
||||
</a>
|
||||
</Typography>
|
||||
}
|
||||
containerProps={{ className: "-ml-2.5" }}
|
||||
/>
|
||||
<Button className="mt-6" fullWidth>
|
||||
Register Now
|
||||
</Button>
|
||||
|
||||
<div className="space-y-4 mt-8">
|
||||
<Button size="lg" color="white" className="flex items-center gap-2 justify-center shadow-md" fullWidth>
|
||||
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clipPath="url(#clip0_1156_824)">
|
||||
<path d="M16.3442 8.18429C16.3442 7.64047 16.3001 7.09371 16.206 6.55872H8.66016V9.63937H12.9813C12.802 10.6329 12.2258 11.5119 11.3822 12.0704V14.0693H13.9602C15.4741 12.6759 16.3442 10.6182 16.3442 8.18429Z" fill="#4285F4" />
|
||||
<path d="M8.65974 16.0006C10.8174 16.0006 12.637 15.2922 13.9627 14.0693L11.3847 12.0704C10.6675 12.5584 9.7415 12.8347 8.66268 12.8347C6.5756 12.8347 4.80598 11.4266 4.17104 9.53357H1.51074V11.5942C2.86882 14.2956 5.63494 16.0006 8.65974 16.0006Z" fill="#34A853" />
|
||||
<path d="M4.16852 9.53356C3.83341 8.53999 3.83341 7.46411 4.16852 6.47054V4.40991H1.51116C0.376489 6.67043 0.376489 9.33367 1.51116 11.5942L4.16852 9.53356Z" fill="#FBBC04" />
|
||||
<path d="M8.65974 3.16644C9.80029 3.1488 10.9026 3.57798 11.7286 4.36578L14.0127 2.08174C12.5664 0.72367 10.6469 -0.0229773 8.65974 0.000539111C5.63494 0.000539111 2.86882 1.70548 1.51074 4.40987L4.1681 6.4705C4.8001 4.57449 6.57266 3.16644 8.65974 3.16644Z" fill="#EA4335" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1156_824">
|
||||
<rect width="16" height="16" fill="white" transform="translate(0.5)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
<span>Sign in With Google</span>
|
||||
</Button>
|
||||
<Button size="lg" color="white" className="flex items-center gap-2 justify-center shadow-md" fullWidth>
|
||||
<img src="/img/twitter-logo.svg" height={24} width={24} alt="" />
|
||||
<span>Sign in With Twitter</span>
|
||||
</Button>
|
||||
</div>
|
||||
<Typography variant="paragraph" className="text-center text-blue-gray-500 font-medium mt-4">
|
||||
Already have an account?
|
||||
<Link to="/auth/sign-in" className="text-gray-900 ml-1">Sign in</Link>
|
||||
</Typography>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default SignUp;
|
||||
@@ -0,0 +1,258 @@
|
||||
import React from "react";
|
||||
import {
|
||||
Typography,
|
||||
Card,
|
||||
CardHeader,
|
||||
CardBody,
|
||||
IconButton,
|
||||
Menu,
|
||||
MenuHandler,
|
||||
MenuList,
|
||||
MenuItem,
|
||||
Avatar,
|
||||
Tooltip,
|
||||
Progress,
|
||||
} from "@material-tailwind/react";
|
||||
import {
|
||||
EllipsisVerticalIcon,
|
||||
ArrowUpIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { StatisticsCard } from "@/widgets/cards";
|
||||
import { StatisticsChart } from "@/widgets/charts";
|
||||
import {
|
||||
statisticsCardsData,
|
||||
statisticsChartsData,
|
||||
projectsTableData,
|
||||
ordersOverviewData,
|
||||
} from "@/data";
|
||||
import { CheckCircleIcon, ClockIcon } from "@heroicons/react/24/solid";
|
||||
|
||||
export function Home() {
|
||||
return (
|
||||
<div className="mt-12">
|
||||
<div className="mb-12 grid gap-y-10 gap-x-6 md:grid-cols-2 xl:grid-cols-4">
|
||||
{statisticsCardsData.map(({ icon, title, footer, ...rest }) => (
|
||||
<StatisticsCard
|
||||
key={title}
|
||||
{...rest}
|
||||
title={title}
|
||||
icon={React.createElement(icon, {
|
||||
className: "w-6 h-6 text-white",
|
||||
})}
|
||||
footer={
|
||||
<Typography className="font-normal text-blue-gray-600">
|
||||
<strong className={footer.color}>{footer.value}</strong>
|
||||
{footer.label}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="mb-6 grid grid-cols-1 gap-y-12 gap-x-6 md:grid-cols-2 xl:grid-cols-3">
|
||||
{statisticsChartsData.map((props) => (
|
||||
<StatisticsChart
|
||||
key={props.title}
|
||||
{...props}
|
||||
footer={
|
||||
<Typography
|
||||
variant="small"
|
||||
className="flex items-center font-normal text-blue-gray-600"
|
||||
>
|
||||
<ClockIcon strokeWidth={2} className="h-4 w-4 text-blue-gray-400" />
|
||||
{props.footer}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="mb-4 grid grid-cols-1 gap-6 xl:grid-cols-3">
|
||||
<Card className="overflow-hidden xl:col-span-2 border border-blue-gray-100 shadow-sm">
|
||||
<CardHeader
|
||||
floated={false}
|
||||
shadow={false}
|
||||
color="transparent"
|
||||
className="m-0 flex items-center justify-between p-6"
|
||||
>
|
||||
<div>
|
||||
<Typography variant="h6" color="blue-gray" className="mb-1">
|
||||
Projects
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="small"
|
||||
className="flex items-center gap-1 font-normal text-blue-gray-600"
|
||||
>
|
||||
<CheckCircleIcon strokeWidth={3} className="h-4 w-4 text-blue-gray-200" />
|
||||
<strong>30 done</strong> this month
|
||||
</Typography>
|
||||
</div>
|
||||
<Menu placement="left-start">
|
||||
<MenuHandler>
|
||||
<IconButton size="sm" variant="text" color="blue-gray">
|
||||
<EllipsisVerticalIcon
|
||||
strokeWidth={3}
|
||||
fill="currenColor"
|
||||
className="h-6 w-6"
|
||||
/>
|
||||
</IconButton>
|
||||
</MenuHandler>
|
||||
<MenuList>
|
||||
<MenuItem>Action</MenuItem>
|
||||
<MenuItem>Another Action</MenuItem>
|
||||
<MenuItem>Something else here</MenuItem>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
</CardHeader>
|
||||
<CardBody className="overflow-x-scroll px-0 pt-0 pb-2">
|
||||
<table className="w-full min-w-[640px] table-auto">
|
||||
<thead>
|
||||
<tr>
|
||||
{["companies", "members", "budget", "completion"].map(
|
||||
(el) => (
|
||||
<th
|
||||
key={el}
|
||||
className="border-b border-blue-gray-50 py-3 px-6 text-left"
|
||||
>
|
||||
<Typography
|
||||
variant="small"
|
||||
className="text-[11px] font-medium uppercase text-blue-gray-400"
|
||||
>
|
||||
{el}
|
||||
</Typography>
|
||||
</th>
|
||||
)
|
||||
)}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{projectsTableData.map(
|
||||
({ img, name, members, budget, completion }, key) => {
|
||||
const className = `py-3 px-5 ${
|
||||
key === projectsTableData.length - 1
|
||||
? ""
|
||||
: "border-b border-blue-gray-50"
|
||||
}`;
|
||||
|
||||
return (
|
||||
<tr key={name}>
|
||||
<td className={className}>
|
||||
<div className="flex items-center gap-4">
|
||||
<Avatar src={img} alt={name} size="sm" />
|
||||
<Typography
|
||||
variant="small"
|
||||
color="blue-gray"
|
||||
className="font-bold"
|
||||
>
|
||||
{name}
|
||||
</Typography>
|
||||
</div>
|
||||
</td>
|
||||
<td className={className}>
|
||||
{members.map(({ img, name }, key) => (
|
||||
<Tooltip key={name} content={name}>
|
||||
<Avatar
|
||||
src={img}
|
||||
alt={name}
|
||||
size="xs"
|
||||
variant="circular"
|
||||
className={`cursor-pointer border-2 border-white ${
|
||||
key === 0 ? "" : "-ml-2.5"
|
||||
}`}
|
||||
/>
|
||||
</Tooltip>
|
||||
))}
|
||||
</td>
|
||||
<td className={className}>
|
||||
<Typography
|
||||
variant="small"
|
||||
className="text-xs font-medium text-blue-gray-600"
|
||||
>
|
||||
{budget}
|
||||
</Typography>
|
||||
</td>
|
||||
<td className={className}>
|
||||
<div className="w-10/12">
|
||||
<Typography
|
||||
variant="small"
|
||||
className="mb-1 block text-xs font-medium text-blue-gray-600"
|
||||
>
|
||||
{completion}%
|
||||
</Typography>
|
||||
<Progress
|
||||
value={completion}
|
||||
variant="gradient"
|
||||
color={completion === 100 ? "green" : "blue"}
|
||||
className="h-1"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</CardBody>
|
||||
</Card>
|
||||
<Card className="border border-blue-gray-100 shadow-sm">
|
||||
<CardHeader
|
||||
floated={false}
|
||||
shadow={false}
|
||||
color="transparent"
|
||||
className="m-0 p-6"
|
||||
>
|
||||
<Typography variant="h6" color="blue-gray" className="mb-2">
|
||||
Orders Overview
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="small"
|
||||
className="flex items-center gap-1 font-normal text-blue-gray-600"
|
||||
>
|
||||
<ArrowUpIcon
|
||||
strokeWidth={3}
|
||||
className="h-3.5 w-3.5 text-green-500"
|
||||
/>
|
||||
<strong>24%</strong> this month
|
||||
</Typography>
|
||||
</CardHeader>
|
||||
<CardBody className="pt-0">
|
||||
{ordersOverviewData.map(
|
||||
({ icon, color, title, description }, key) => (
|
||||
<div key={title} className="flex items-start gap-4 py-3">
|
||||
<div
|
||||
className={`relative p-1 after:absolute after:-bottom-6 after:left-2/4 after:w-0.5 after:-translate-x-2/4 after:bg-blue-gray-50 after:content-[''] ${
|
||||
key === ordersOverviewData.length - 1
|
||||
? "after:h-0"
|
||||
: "after:h-4/6"
|
||||
}`}
|
||||
>
|
||||
{React.createElement(icon, {
|
||||
className: `!w-5 !h-5 ${color}`,
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
<Typography
|
||||
variant="small"
|
||||
color="blue-gray"
|
||||
className="block font-medium"
|
||||
>
|
||||
{title}
|
||||
</Typography>
|
||||
<Typography
|
||||
as="span"
|
||||
variant="small"
|
||||
className="text-xs font-medium text-blue-gray-500"
|
||||
>
|
||||
{description}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Home;
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "@/pages/dashboard/home";
|
||||
export * from "@/pages/dashboard/profile";
|
||||
export * from "@/pages/dashboard/tables";
|
||||
export * from "@/pages/dashboard/notifications";
|
||||
@@ -0,0 +1,88 @@
|
||||
import React from "react";
|
||||
import {
|
||||
Typography,
|
||||
Alert,
|
||||
Card,
|
||||
CardHeader,
|
||||
CardBody,
|
||||
} from "@material-tailwind/react";
|
||||
import { InformationCircleIcon } from "@heroicons/react/24/outline";
|
||||
|
||||
export function Notifications() {
|
||||
const [showAlerts, setShowAlerts] = React.useState({
|
||||
blue: true,
|
||||
green: true,
|
||||
orange: true,
|
||||
red: true,
|
||||
});
|
||||
const [showAlertsWithIcon, setShowAlertsWithIcon] = React.useState({
|
||||
blue: true,
|
||||
green: true,
|
||||
orange: true,
|
||||
red: true,
|
||||
});
|
||||
const alerts = ["gray", "green", "orange", "red"];
|
||||
|
||||
return (
|
||||
<div className="mx-auto my-20 flex max-w-screen-lg flex-col gap-8">
|
||||
<Card>
|
||||
<CardHeader
|
||||
color="transparent"
|
||||
floated={false}
|
||||
shadow={false}
|
||||
className="m-0 p-4"
|
||||
>
|
||||
<Typography variant="h5" color="blue-gray">
|
||||
Alerts
|
||||
</Typography>
|
||||
</CardHeader>
|
||||
<CardBody className="flex flex-col gap-4 p-4">
|
||||
{alerts.map((color) => (
|
||||
<Alert
|
||||
key={color}
|
||||
open={showAlerts[color]}
|
||||
color={color}
|
||||
onClose={() => setShowAlerts((current) => ({ ...current, [color]: false }))}
|
||||
>
|
||||
A simple {color} alert with an <a href="#">example link</a>. Give
|
||||
it a click if you like.
|
||||
</Alert>
|
||||
))}
|
||||
</CardBody>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader
|
||||
color="transparent"
|
||||
floated={false}
|
||||
shadow={false}
|
||||
className="m-0 p-4"
|
||||
>
|
||||
<Typography variant="h5" color="blue-gray">
|
||||
Alerts with Icon
|
||||
</Typography>
|
||||
</CardHeader>
|
||||
<CardBody className="flex flex-col gap-4 p-4">
|
||||
{alerts.map((color) => (
|
||||
<Alert
|
||||
key={color}
|
||||
open={showAlertsWithIcon[color]}
|
||||
color={color}
|
||||
icon={
|
||||
<InformationCircleIcon strokeWidth={2} className="h-6 w-6" />
|
||||
}
|
||||
onClose={() => setShowAlertsWithIcon((current) => ({
|
||||
...current,
|
||||
[color]: false,
|
||||
}))}
|
||||
>
|
||||
A simple {color} alert with an <a href="#">example link</a>. Give
|
||||
it a click if you like.
|
||||
</Alert>
|
||||
))}
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Notifications;
|
||||
@@ -0,0 +1,221 @@
|
||||
import {
|
||||
Card,
|
||||
CardBody,
|
||||
CardHeader,
|
||||
CardFooter,
|
||||
Avatar,
|
||||
Typography,
|
||||
Tabs,
|
||||
TabsHeader,
|
||||
Tab,
|
||||
Switch,
|
||||
Tooltip,
|
||||
Button,
|
||||
} from "@material-tailwind/react";
|
||||
import {
|
||||
HomeIcon,
|
||||
ChatBubbleLeftEllipsisIcon,
|
||||
Cog6ToothIcon,
|
||||
PencilIcon,
|
||||
} from "@heroicons/react/24/solid";
|
||||
import { Link } from "react-router-dom";
|
||||
import { ProfileInfoCard, MessageCard } from "@/widgets/cards";
|
||||
import { platformSettingsData, conversationsData, projectsData } from "@/data";
|
||||
|
||||
export function Profile() {
|
||||
return (
|
||||
<>
|
||||
<div className="relative mt-8 h-72 w-full overflow-hidden rounded-xl bg-[url('/img/background-image.png')] bg-cover bg-center">
|
||||
<div className="absolute inset-0 h-full w-full bg-gray-900/75" />
|
||||
</div>
|
||||
<Card className="mx-3 -mt-16 mb-6 lg:mx-4 border border-blue-gray-100">
|
||||
<CardBody className="p-4">
|
||||
<div className="mb-10 flex items-center justify-between flex-wrap gap-6">
|
||||
<div className="flex items-center gap-6">
|
||||
<Avatar
|
||||
src="/img/bruce-mars.jpeg"
|
||||
alt="bruce-mars"
|
||||
size="xl"
|
||||
variant="rounded"
|
||||
className="rounded-lg shadow-lg shadow-blue-gray-500/40"
|
||||
/>
|
||||
<div>
|
||||
<Typography variant="h5" color="blue-gray" className="mb-1">
|
||||
Richard Davis
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="small"
|
||||
className="font-normal text-blue-gray-600"
|
||||
>
|
||||
CEO / Co-Founder
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-96">
|
||||
<Tabs value="app">
|
||||
<TabsHeader>
|
||||
<Tab value="app">
|
||||
<HomeIcon className="-mt-1 mr-2 inline-block h-5 w-5" />
|
||||
App
|
||||
</Tab>
|
||||
<Tab value="message">
|
||||
<ChatBubbleLeftEllipsisIcon className="-mt-0.5 mr-2 inline-block h-5 w-5" />
|
||||
Message
|
||||
</Tab>
|
||||
<Tab value="settings">
|
||||
<Cog6ToothIcon className="-mt-1 mr-2 inline-block h-5 w-5" />
|
||||
Settings
|
||||
</Tab>
|
||||
</TabsHeader>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
<div className="gird-cols-1 mb-12 grid gap-12 px-4 lg:grid-cols-2 xl:grid-cols-3">
|
||||
<div>
|
||||
<Typography variant="h6" color="blue-gray" className="mb-3">
|
||||
Platform Settings
|
||||
</Typography>
|
||||
<div className="flex flex-col gap-12">
|
||||
{platformSettingsData.map(({ title, options }) => (
|
||||
<div key={title}>
|
||||
<Typography className="mb-4 block text-xs font-semibold uppercase text-blue-gray-500">
|
||||
{title}
|
||||
</Typography>
|
||||
<div className="flex flex-col gap-6">
|
||||
{options.map(({ checked, label }) => (
|
||||
<Switch
|
||||
key={label}
|
||||
id={label}
|
||||
label={label}
|
||||
defaultChecked={checked}
|
||||
labelProps={{
|
||||
className: "text-sm font-normal text-blue-gray-500",
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<ProfileInfoCard
|
||||
title="Profile Information"
|
||||
description="Hi, I'm Alec Thompson, Decisions: If you can't decide, the answer is no. If two equally difficult paths, choose the one more painful in the short term (pain avoidance is creating an illusion of equality)."
|
||||
details={{
|
||||
"first name": "Alec M. Thompson",
|
||||
mobile: "(44) 123 1234 123",
|
||||
email: "alecthompson@mail.com",
|
||||
location: "USA",
|
||||
social: (
|
||||
<div className="flex items-center gap-4">
|
||||
<i className="fa-brands fa-facebook text-blue-700" />
|
||||
<i className="fa-brands fa-twitter text-blue-400" />
|
||||
<i className="fa-brands fa-instagram text-purple-500" />
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
action={
|
||||
<Tooltip content="Edit Profile">
|
||||
<PencilIcon className="h-4 w-4 cursor-pointer text-blue-gray-500" />
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
<div>
|
||||
<Typography variant="h6" color="blue-gray" className="mb-3">
|
||||
Platform Settings
|
||||
</Typography>
|
||||
<ul className="flex flex-col gap-6">
|
||||
{conversationsData.map((props) => (
|
||||
<MessageCard
|
||||
key={props.name}
|
||||
{...props}
|
||||
action={
|
||||
<Button variant="text" size="sm">
|
||||
reply
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-4 pb-4">
|
||||
<Typography variant="h6" color="blue-gray" className="mb-2">
|
||||
Projects
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="small"
|
||||
className="font-normal text-blue-gray-500"
|
||||
>
|
||||
Architects design houses
|
||||
</Typography>
|
||||
<div className="mt-6 grid grid-cols-1 gap-12 md:grid-cols-2 xl:grid-cols-4">
|
||||
{projectsData.map(
|
||||
({ img, title, description, tag, route, members }) => (
|
||||
<Card key={title} color="transparent" shadow={false}>
|
||||
<CardHeader
|
||||
floated={false}
|
||||
color="gray"
|
||||
className="mx-0 mt-0 mb-4 h-64 xl:h-40"
|
||||
>
|
||||
<img
|
||||
src={img}
|
||||
alt={title}
|
||||
className="h-full w-full object-cover"
|
||||
/>
|
||||
</CardHeader>
|
||||
<CardBody className="py-0 px-1">
|
||||
<Typography
|
||||
variant="small"
|
||||
className="font-normal text-blue-gray-500"
|
||||
>
|
||||
{tag}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="h5"
|
||||
color="blue-gray"
|
||||
className="mt-1 mb-2"
|
||||
>
|
||||
{title}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="small"
|
||||
className="font-normal text-blue-gray-500"
|
||||
>
|
||||
{description}
|
||||
</Typography>
|
||||
</CardBody>
|
||||
<CardFooter className="mt-6 flex items-center justify-between py-0 px-1">
|
||||
<Link to={route}>
|
||||
<Button variant="outlined" size="sm">
|
||||
view project
|
||||
</Button>
|
||||
</Link>
|
||||
<div>
|
||||
{members.map(({ img, name }, key) => (
|
||||
<Tooltip key={name} content={name}>
|
||||
<Avatar
|
||||
src={img}
|
||||
alt={name}
|
||||
size="xs"
|
||||
variant="circular"
|
||||
className={`cursor-pointer border-2 border-white ${
|
||||
key === 0 ? "" : "-ml-2.5"
|
||||
}`}
|
||||
/>
|
||||
</Tooltip>
|
||||
))}
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Profile;
|
||||
@@ -0,0 +1,221 @@
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardBody,
|
||||
Typography,
|
||||
Avatar,
|
||||
Chip,
|
||||
Tooltip,
|
||||
Progress,
|
||||
} from "@material-tailwind/react";
|
||||
import { EllipsisVerticalIcon } from "@heroicons/react/24/outline";
|
||||
import { authorsTableData, projectsTableData } from "@/data";
|
||||
|
||||
export function Tables() {
|
||||
return (
|
||||
<div className="mt-12 mb-8 flex flex-col gap-12">
|
||||
<Card>
|
||||
<CardHeader variant="gradient" color="gray" className="mb-8 p-6">
|
||||
<Typography variant="h6" color="white">
|
||||
Authors Table
|
||||
</Typography>
|
||||
</CardHeader>
|
||||
<CardBody className="overflow-x-scroll px-0 pt-0 pb-2">
|
||||
<table className="w-full min-w-[640px] table-auto">
|
||||
<thead>
|
||||
<tr>
|
||||
{["author", "function", "status", "employed", ""].map((el) => (
|
||||
<th
|
||||
key={el}
|
||||
className="border-b border-blue-gray-50 py-3 px-5 text-left"
|
||||
>
|
||||
<Typography
|
||||
variant="small"
|
||||
className="text-[11px] font-bold uppercase text-blue-gray-400"
|
||||
>
|
||||
{el}
|
||||
</Typography>
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{authorsTableData.map(
|
||||
({ img, name, email, job, online, date }, key) => {
|
||||
const className = `py-3 px-5 ${
|
||||
key === authorsTableData.length - 1
|
||||
? ""
|
||||
: "border-b border-blue-gray-50"
|
||||
}`;
|
||||
|
||||
return (
|
||||
<tr key={name}>
|
||||
<td className={className}>
|
||||
<div className="flex items-center gap-4">
|
||||
<Avatar src={img} alt={name} size="sm" variant="rounded" />
|
||||
<div>
|
||||
<Typography
|
||||
variant="small"
|
||||
color="blue-gray"
|
||||
className="font-semibold"
|
||||
>
|
||||
{name}
|
||||
</Typography>
|
||||
<Typography className="text-xs font-normal text-blue-gray-500">
|
||||
{email}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className={className}>
|
||||
<Typography className="text-xs font-semibold text-blue-gray-600">
|
||||
{job[0]}
|
||||
</Typography>
|
||||
<Typography className="text-xs font-normal text-blue-gray-500">
|
||||
{job[1]}
|
||||
</Typography>
|
||||
</td>
|
||||
<td className={className}>
|
||||
<Chip
|
||||
variant="gradient"
|
||||
color={online ? "green" : "blue-gray"}
|
||||
value={online ? "online" : "offline"}
|
||||
className="py-0.5 px-2 text-[11px] font-medium w-fit"
|
||||
/>
|
||||
</td>
|
||||
<td className={className}>
|
||||
<Typography className="text-xs font-semibold text-blue-gray-600">
|
||||
{date}
|
||||
</Typography>
|
||||
</td>
|
||||
<td className={className}>
|
||||
<Typography
|
||||
as="a"
|
||||
href="#"
|
||||
className="text-xs font-semibold text-blue-gray-600"
|
||||
>
|
||||
Edit
|
||||
</Typography>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</CardBody>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader variant="gradient" color="gray" className="mb-8 p-6">
|
||||
<Typography variant="h6" color="white">
|
||||
Projects Table
|
||||
</Typography>
|
||||
</CardHeader>
|
||||
<CardBody className="overflow-x-scroll px-0 pt-0 pb-2">
|
||||
<table className="w-full min-w-[640px] table-auto">
|
||||
<thead>
|
||||
<tr>
|
||||
{["companies", "members", "budget", "completion", ""].map(
|
||||
(el) => (
|
||||
<th
|
||||
key={el}
|
||||
className="border-b border-blue-gray-50 py-3 px-5 text-left"
|
||||
>
|
||||
<Typography
|
||||
variant="small"
|
||||
className="text-[11px] font-bold uppercase text-blue-gray-400"
|
||||
>
|
||||
{el}
|
||||
</Typography>
|
||||
</th>
|
||||
)
|
||||
)}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{projectsTableData.map(
|
||||
({ img, name, members, budget, completion }, key) => {
|
||||
const className = `py-3 px-5 ${
|
||||
key === projectsTableData.length - 1
|
||||
? ""
|
||||
: "border-b border-blue-gray-50"
|
||||
}`;
|
||||
|
||||
return (
|
||||
<tr key={name}>
|
||||
<td className={className}>
|
||||
<div className="flex items-center gap-4">
|
||||
<Avatar src={img} alt={name} size="sm" />
|
||||
<Typography
|
||||
variant="small"
|
||||
color="blue-gray"
|
||||
className="font-bold"
|
||||
>
|
||||
{name}
|
||||
</Typography>
|
||||
</div>
|
||||
</td>
|
||||
<td className={className}>
|
||||
{members.map(({ img, name }, key) => (
|
||||
<Tooltip key={name} content={name}>
|
||||
<Avatar
|
||||
src={img}
|
||||
alt={name}
|
||||
size="xs"
|
||||
variant="circular"
|
||||
className={`cursor-pointer border-2 border-white ${
|
||||
key === 0 ? "" : "-ml-2.5"
|
||||
}`}
|
||||
/>
|
||||
</Tooltip>
|
||||
))}
|
||||
</td>
|
||||
<td className={className}>
|
||||
<Typography
|
||||
variant="small"
|
||||
className="text-xs font-medium text-blue-gray-600"
|
||||
>
|
||||
{budget}
|
||||
</Typography>
|
||||
</td>
|
||||
<td className={className}>
|
||||
<div className="w-10/12">
|
||||
<Typography
|
||||
variant="small"
|
||||
className="mb-1 block text-xs font-medium text-blue-gray-600"
|
||||
>
|
||||
{completion}%
|
||||
</Typography>
|
||||
<Progress
|
||||
value={completion}
|
||||
variant="gradient"
|
||||
color={completion === 100 ? "green" : "gray"}
|
||||
className="h-1"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td className={className}>
|
||||
<Typography
|
||||
as="a"
|
||||
href="#"
|
||||
className="text-xs font-semibold text-blue-gray-600"
|
||||
>
|
||||
<EllipsisVerticalIcon
|
||||
strokeWidth={2}
|
||||
className="h-5 w-5 text-inherit"
|
||||
/>
|
||||
</Typography>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Tables;
|
||||
@@ -0,0 +1,66 @@
|
||||
import {
|
||||
HomeIcon,
|
||||
UserCircleIcon,
|
||||
TableCellsIcon,
|
||||
InformationCircleIcon,
|
||||
ServerStackIcon,
|
||||
RectangleStackIcon,
|
||||
} from "@heroicons/react/24/solid";
|
||||
import { Home, Profile, Tables, Notifications } from "@/pages/dashboard";
|
||||
import { SignIn, SignUp } from "@/pages/auth";
|
||||
|
||||
const icon = {
|
||||
className: "w-5 h-5 text-inherit",
|
||||
};
|
||||
|
||||
export const routes = [
|
||||
{
|
||||
layout: "dashboard",
|
||||
pages: [
|
||||
{
|
||||
icon: <HomeIcon {...icon} />,
|
||||
name: "dashboard",
|
||||
path: "/home",
|
||||
element: <Home />,
|
||||
},
|
||||
{
|
||||
icon: <UserCircleIcon {...icon} />,
|
||||
name: "profile",
|
||||
path: "/profile",
|
||||
element: <Profile />,
|
||||
},
|
||||
{
|
||||
icon: <TableCellsIcon {...icon} />,
|
||||
name: "tables",
|
||||
path: "/tables",
|
||||
element: <Tables />,
|
||||
},
|
||||
{
|
||||
icon: <InformationCircleIcon {...icon} />,
|
||||
name: "notifications",
|
||||
path: "/notifications",
|
||||
element: <Notifications />,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "auth pages",
|
||||
layout: "auth",
|
||||
pages: [
|
||||
{
|
||||
icon: <ServerStackIcon {...icon} />,
|
||||
name: "sign in",
|
||||
path: "/sign-in",
|
||||
element: <SignIn />,
|
||||
},
|
||||
{
|
||||
icon: <RectangleStackIcon {...icon} />,
|
||||
name: "sign up",
|
||||
path: "/sign-up",
|
||||
element: <SignUp />,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default routes;
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "@/widgets/cards/statistics-card";
|
||||
export * from "@/widgets/cards/profile-info-card";
|
||||
export * from "@/widgets/cards/message-card";
|
||||
@@ -0,0 +1,45 @@
|
||||
import PropTypes from "prop-types";
|
||||
import { Avatar, Typography } from "@material-tailwind/react";
|
||||
|
||||
export function MessageCard({ img, name, message, action }) {
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<div className="flex items-center gap-4">
|
||||
<Avatar
|
||||
src={img}
|
||||
alt={name}
|
||||
variant="rounded"
|
||||
className="shadow-lg shadow-blue-gray-500/25"
|
||||
/>
|
||||
<div>
|
||||
<Typography
|
||||
variant="small"
|
||||
color="blue-gray"
|
||||
className="mb-1 font-semibold"
|
||||
>
|
||||
{name}
|
||||
</Typography>
|
||||
<Typography className="text-xs font-normal text-blue-gray-400">
|
||||
{message}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
{action}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
MessageCard.defaultProps = {
|
||||
action: null,
|
||||
};
|
||||
|
||||
MessageCard.propTypes = {
|
||||
img: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
message: PropTypes.node.isRequired,
|
||||
action: PropTypes.node,
|
||||
};
|
||||
|
||||
MessageCard.displayName = "/src/widgets/cards/message-card.jsx";
|
||||
|
||||
export default MessageCard;
|
||||
@@ -0,0 +1,79 @@
|
||||
import PropTypes from "prop-types";
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardBody,
|
||||
Typography,
|
||||
} from "@material-tailwind/react";
|
||||
|
||||
export function ProfileInfoCard({ title, description, details, action }) {
|
||||
return (
|
||||
<Card color="transparent" shadow={false}>
|
||||
<CardHeader
|
||||
color="transparent"
|
||||
shadow={false}
|
||||
floated={false}
|
||||
className="mx-0 mt-0 mb-4 flex items-center justify-between gap-4"
|
||||
>
|
||||
<Typography variant="h6" color="blue-gray">
|
||||
{title}
|
||||
</Typography>
|
||||
{action}
|
||||
</CardHeader>
|
||||
<CardBody className="p-0">
|
||||
{description && (
|
||||
<Typography
|
||||
variant="small"
|
||||
className="font-normal text-blue-gray-500"
|
||||
>
|
||||
{description}
|
||||
</Typography>
|
||||
)}
|
||||
{description && details ? (
|
||||
<hr className="my-8 border-blue-gray-50" />
|
||||
) : null}
|
||||
{details && (
|
||||
<ul className="flex flex-col gap-4 p-0">
|
||||
{Object.keys(details).map((el, key) => (
|
||||
<li key={key} className="flex items-center gap-4">
|
||||
<Typography
|
||||
variant="small"
|
||||
color="blue-gray"
|
||||
className="font-semibold capitalize"
|
||||
>
|
||||
{el}:
|
||||
</Typography>
|
||||
{typeof details[el] === "string" ? (
|
||||
<Typography
|
||||
variant="small"
|
||||
className="font-normal text-blue-gray-500"
|
||||
>
|
||||
{details[el]}
|
||||
</Typography>
|
||||
) : (
|
||||
details[el]
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
ProfileInfoCard.defaultProps = {
|
||||
action: null,
|
||||
description: null,
|
||||
details: {},
|
||||
};
|
||||
|
||||
ProfileInfoCard.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
description: PropTypes.node,
|
||||
details: PropTypes.object,
|
||||
};
|
||||
|
||||
ProfileInfoCard.displayName = "/src/widgets/cards/profile-info-card.jsx";
|
||||
|
||||
export default ProfileInfoCard;
|
||||
@@ -0,0 +1,75 @@
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardBody,
|
||||
CardFooter,
|
||||
Typography,
|
||||
} from "@material-tailwind/react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
export function StatisticsCard({ color, icon, title, value, footer }) {
|
||||
return (
|
||||
<Card className="border border-blue-gray-100 shadow-sm">
|
||||
<CardHeader
|
||||
variant="gradient"
|
||||
color={color}
|
||||
floated={false}
|
||||
shadow={false}
|
||||
className="absolute grid h-12 w-12 place-items-center"
|
||||
>
|
||||
{icon}
|
||||
</CardHeader>
|
||||
<CardBody className="p-4 text-right">
|
||||
<Typography variant="small" className="font-normal text-blue-gray-600">
|
||||
{title}
|
||||
</Typography>
|
||||
<Typography variant="h4" color="blue-gray">
|
||||
{value}
|
||||
</Typography>
|
||||
</CardBody>
|
||||
{footer && (
|
||||
<CardFooter className="border-t border-blue-gray-50 p-4">
|
||||
{footer}
|
||||
</CardFooter>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
StatisticsCard.defaultProps = {
|
||||
color: "blue",
|
||||
footer: null,
|
||||
};
|
||||
|
||||
StatisticsCard.propTypes = {
|
||||
color: PropTypes.oneOf([
|
||||
"white",
|
||||
"blue-gray",
|
||||
"gray",
|
||||
"brown",
|
||||
"deep-orange",
|
||||
"orange",
|
||||
"amber",
|
||||
"yellow",
|
||||
"lime",
|
||||
"light-green",
|
||||
"green",
|
||||
"teal",
|
||||
"cyan",
|
||||
"light-blue",
|
||||
"blue",
|
||||
"indigo",
|
||||
"deep-purple",
|
||||
"purple",
|
||||
"pink",
|
||||
"red",
|
||||
]),
|
||||
icon: PropTypes.node.isRequired,
|
||||
title: PropTypes.node.isRequired,
|
||||
value: PropTypes.node.isRequired,
|
||||
footer: PropTypes.node,
|
||||
};
|
||||
|
||||
StatisticsCard.displayName = "/src/widgets/cards/statistics-card.jsx";
|
||||
|
||||
export default StatisticsCard;
|
||||
@@ -0,0 +1 @@
|
||||
export * from "@/widgets/charts/statistics-chart";
|
||||
@@ -0,0 +1,70 @@
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardBody,
|
||||
CardFooter,
|
||||
Typography,
|
||||
} from "@material-tailwind/react";
|
||||
import PropTypes from "prop-types";
|
||||
import Chart from "react-apexcharts";
|
||||
|
||||
export function StatisticsChart({ color, chart, title, description, footer }) {
|
||||
return (
|
||||
<Card className="border border-blue-gray-100 shadow-sm">
|
||||
<CardHeader variant="gradient" color={color} floated={false} shadow={false}>
|
||||
<Chart {...chart} />
|
||||
</CardHeader>
|
||||
<CardBody className="px-6 pt-0">
|
||||
<Typography variant="h6" color="blue-gray">
|
||||
{title}
|
||||
</Typography>
|
||||
<Typography variant="small" className="font-normal text-blue-gray-600">
|
||||
{description}
|
||||
</Typography>
|
||||
</CardBody>
|
||||
{footer && (
|
||||
<CardFooter className="border-t border-blue-gray-50 px-6 py-5">
|
||||
{footer}
|
||||
</CardFooter>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
StatisticsChart.defaultProps = {
|
||||
color: "blue",
|
||||
footer: null,
|
||||
};
|
||||
|
||||
StatisticsChart.propTypes = {
|
||||
color: PropTypes.oneOf([
|
||||
"white",
|
||||
"blue-gray",
|
||||
"gray",
|
||||
"brown",
|
||||
"deep-orange",
|
||||
"orange",
|
||||
"amber",
|
||||
"yellow",
|
||||
"lime",
|
||||
"light-green",
|
||||
"green",
|
||||
"teal",
|
||||
"cyan",
|
||||
"light-blue",
|
||||
"blue",
|
||||
"indigo",
|
||||
"deep-purple",
|
||||
"purple",
|
||||
"pink",
|
||||
"red",
|
||||
]),
|
||||
chart: PropTypes.object.isRequired,
|
||||
title: PropTypes.node.isRequired,
|
||||
description: PropTypes.node.isRequired,
|
||||
footer: PropTypes.node,
|
||||
};
|
||||
|
||||
StatisticsChart.displayName = "/src/widgets/charts/statistics-chart.jsx";
|
||||
|
||||
export default StatisticsChart;
|
||||
@@ -0,0 +1,237 @@
|
||||
import React from "react";
|
||||
import { XMarkIcon } from "@heroicons/react/24/outline";
|
||||
import {
|
||||
Button,
|
||||
IconButton,
|
||||
Switch,
|
||||
Typography,
|
||||
Chip,
|
||||
} from "@material-tailwind/react";
|
||||
import {
|
||||
useMaterialTailwindController,
|
||||
setOpenConfigurator,
|
||||
setSidenavColor,
|
||||
setSidenavType,
|
||||
setFixedNavbar,
|
||||
} from "@/context";
|
||||
|
||||
function formatNumber(number, decPlaces) {
|
||||
decPlaces = Math.pow(10, decPlaces);
|
||||
|
||||
const abbrev = ["K", "M", "B", "T"];
|
||||
|
||||
for (let i = abbrev.length - 1; i >= 0; i--) {
|
||||
var size = Math.pow(10, (i + 1) * 3);
|
||||
|
||||
if (size <= number) {
|
||||
number = Math.round((number * decPlaces) / size) / decPlaces;
|
||||
|
||||
if (number == 1000 && i < abbrev.length - 1) {
|
||||
number = 1;
|
||||
i++;
|
||||
}
|
||||
|
||||
number += abbrev[i];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
export function Configurator() {
|
||||
const [controller, dispatch] = useMaterialTailwindController();
|
||||
const { openConfigurator, sidenavColor, sidenavType, fixedNavbar } =
|
||||
controller;
|
||||
const [stars, setStars] = React.useState(0);
|
||||
|
||||
const sidenavColors = {
|
||||
white: "from-gray-100 to-gray-100 border-gray-200",
|
||||
dark: "from-black to-black border-gray-200",
|
||||
green: "from-green-400 to-green-600",
|
||||
orange: "from-orange-400 to-orange-600",
|
||||
red: "from-red-400 to-red-600",
|
||||
pink: "from-pink-400 to-pink-600",
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
const stars = fetch(
|
||||
"https://api.github.com/repos/creativetimofficial/material-tailwind-dashboard-react"
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then((data) => setStars(formatNumber(data.stargazers_count, 1)));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<aside
|
||||
className={`fixed top-0 right-0 z-50 h-screen w-96 bg-white px-2.5 shadow-lg transition-transform duration-300 ${
|
||||
openConfigurator ? "translate-x-0" : "translate-x-96"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-start justify-between px-6 pt-8 pb-6">
|
||||
<div>
|
||||
<Typography variant="h5" color="blue-gray">
|
||||
Dashboard Configurator
|
||||
</Typography>
|
||||
<Typography className="font-normal text-blue-gray-600">
|
||||
See our dashboard options.
|
||||
</Typography>
|
||||
</div>
|
||||
<IconButton
|
||||
variant="text"
|
||||
color="blue-gray"
|
||||
onClick={() => setOpenConfigurator(dispatch, false)}
|
||||
>
|
||||
<XMarkIcon strokeWidth={2.5} className="h-5 w-5" />
|
||||
</IconButton>
|
||||
</div>
|
||||
<div className="py-4 px-6">
|
||||
<div className="mb-12">
|
||||
<Typography variant="h6" color="blue-gray">
|
||||
Sidenav Colors
|
||||
</Typography>
|
||||
<div className="mt-3 flex items-center gap-2">
|
||||
{Object.keys(sidenavColors).map((color) => (
|
||||
<span
|
||||
key={color}
|
||||
className={`h-6 w-6 cursor-pointer rounded-full border bg-gradient-to-br transition-transform hover:scale-105 ${
|
||||
sidenavColors[color]
|
||||
} ${
|
||||
sidenavColor === color ? "border-black" : "border-transparent"
|
||||
}`}
|
||||
onClick={() => setSidenavColor(dispatch, color)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-12">
|
||||
<Typography variant="h6" color="blue-gray">
|
||||
Sidenav Types
|
||||
</Typography>
|
||||
<Typography variant="small" color="gray">
|
||||
Choose between 3 different sidenav types.
|
||||
</Typography>
|
||||
<div className="mt-3 flex items-center gap-2">
|
||||
<Button
|
||||
variant={sidenavType === "dark" ? "gradient" : "outlined"}
|
||||
onClick={() => setSidenavType(dispatch, "dark")}
|
||||
>
|
||||
Dark
|
||||
</Button>
|
||||
<Button
|
||||
variant={sidenavType === "transparent" ? "gradient" : "outlined"}
|
||||
onClick={() => setSidenavType(dispatch, "transparent")}
|
||||
>
|
||||
Transparent
|
||||
</Button>
|
||||
<Button
|
||||
variant={sidenavType === "white" ? "gradient" : "outlined"}
|
||||
onClick={() => setSidenavType(dispatch, "white")}
|
||||
>
|
||||
White
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-12">
|
||||
<hr />
|
||||
<div className="flex items-center justify-between py-5">
|
||||
<Typography variant="h6" color="blue-gray">
|
||||
Navbar Fixed
|
||||
</Typography>
|
||||
<Switch
|
||||
id="navbar-fixed"
|
||||
value={fixedNavbar}
|
||||
onChange={() => setFixedNavbar(dispatch, !fixedNavbar)}
|
||||
/>
|
||||
</div>
|
||||
<hr />
|
||||
<div className="my-8 flex flex-col gap-4">
|
||||
<a
|
||||
href="https://www.creative-tim.com/product/material-tailwind-dashboard-react?rel=mtdr"
|
||||
target="_black"
|
||||
>
|
||||
<Button variant="gradient" fullWidth>
|
||||
Free Download
|
||||
</Button>
|
||||
</a>
|
||||
<a
|
||||
href="https://www.material-tailwind.com/docs/react/installation?rel=mtdr"
|
||||
target="_black"
|
||||
>
|
||||
<Button variant="outlined" color="blue-gray" fullWidth>
|
||||
View Documentation
|
||||
</Button>
|
||||
</a>
|
||||
<a
|
||||
href="https://www.material-tailwind.com/blocks/react?rel=mtdr"
|
||||
target="_black"
|
||||
>
|
||||
<Button variant="outlined" color="blue-gray" fullWidth>
|
||||
Material Tailwind PRO
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
<a
|
||||
className="mx-auto flex items-center justify-center gap-2"
|
||||
href="https://github.com/creativetimofficial/material-tailwind-dashboard-react"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Chip
|
||||
value={`${stars} - Stars`}
|
||||
icon={
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
className="mt-px ml-1.5 h-4 w-4"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
}
|
||||
className="bg-blue-gray-900 px-4"
|
||||
/>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<Typography variant="h6" color="blue-gray">
|
||||
Thank you for sharing ❤️
|
||||
</Typography>
|
||||
<div className="mt-4 flex justify-center gap-2">
|
||||
<Button
|
||||
variant="gradient"
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<i className="fa-brands fa-twitter text-white" />
|
||||
Tweet
|
||||
</Button>
|
||||
<Button
|
||||
variant="gradient"
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<i className="fa-brands fa-facebook text-white" />
|
||||
Share
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
||||
Configurator.displayName = "/src/widgets/layout/configurator.jsx";
|
||||
|
||||
export default Configurator;
|
||||
@@ -0,0 +1,196 @@
|
||||
import { useLocation, Link } from "react-router-dom";
|
||||
import {
|
||||
Navbar,
|
||||
Typography,
|
||||
Button,
|
||||
IconButton,
|
||||
Breadcrumbs,
|
||||
Input,
|
||||
Menu,
|
||||
MenuHandler,
|
||||
MenuList,
|
||||
MenuItem,
|
||||
Avatar,
|
||||
} from "@material-tailwind/react";
|
||||
import {
|
||||
UserCircleIcon,
|
||||
Cog6ToothIcon,
|
||||
BellIcon,
|
||||
ClockIcon,
|
||||
CreditCardIcon,
|
||||
Bars3Icon,
|
||||
} from "@heroicons/react/24/solid";
|
||||
import {
|
||||
useMaterialTailwindController,
|
||||
setOpenConfigurator,
|
||||
setOpenSidenav,
|
||||
} from "@/context";
|
||||
|
||||
export function DashboardNavbar() {
|
||||
const [controller, dispatch] = useMaterialTailwindController();
|
||||
const { fixedNavbar, openSidenav } = controller;
|
||||
const { pathname } = useLocation();
|
||||
const [layout, page] = pathname.split("/").filter((el) => el !== "");
|
||||
|
||||
return (
|
||||
<Navbar
|
||||
color={fixedNavbar ? "white" : "transparent"}
|
||||
className={`rounded-xl transition-all ${
|
||||
fixedNavbar
|
||||
? "sticky top-4 z-40 py-3 shadow-md shadow-blue-gray-500/5"
|
||||
: "px-0 py-1"
|
||||
}`}
|
||||
fullWidth
|
||||
blurred={fixedNavbar}
|
||||
>
|
||||
<div className="flex flex-col-reverse justify-between gap-6 md:flex-row md:items-center">
|
||||
<div className="capitalize">
|
||||
<Breadcrumbs
|
||||
className={`bg-transparent p-0 transition-all ${
|
||||
fixedNavbar ? "mt-1" : ""
|
||||
}`}
|
||||
>
|
||||
<Link to={`/${layout}`}>
|
||||
<Typography
|
||||
variant="small"
|
||||
color="blue-gray"
|
||||
className="font-normal opacity-50 transition-all hover:text-blue-500 hover:opacity-100"
|
||||
>
|
||||
{layout}
|
||||
</Typography>
|
||||
</Link>
|
||||
<Typography
|
||||
variant="small"
|
||||
color="blue-gray"
|
||||
className="font-normal"
|
||||
>
|
||||
{page}
|
||||
</Typography>
|
||||
</Breadcrumbs>
|
||||
<Typography variant="h6" color="blue-gray">
|
||||
{page}
|
||||
</Typography>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="mr-auto md:mr-4 md:w-56">
|
||||
<Input label="Search" />
|
||||
</div>
|
||||
<IconButton
|
||||
variant="text"
|
||||
color="blue-gray"
|
||||
className="grid xl:hidden"
|
||||
onClick={() => setOpenSidenav(dispatch, !openSidenav)}
|
||||
>
|
||||
<Bars3Icon strokeWidth={3} className="h-6 w-6 text-blue-gray-500" />
|
||||
</IconButton>
|
||||
<Link to="/auth/sign-in">
|
||||
<Button
|
||||
variant="text"
|
||||
color="blue-gray"
|
||||
className="hidden items-center gap-1 px-4 xl:flex normal-case"
|
||||
>
|
||||
<UserCircleIcon className="h-5 w-5 text-blue-gray-500" />
|
||||
Sign In
|
||||
</Button>
|
||||
<IconButton
|
||||
variant="text"
|
||||
color="blue-gray"
|
||||
className="grid xl:hidden"
|
||||
>
|
||||
<UserCircleIcon className="h-5 w-5 text-blue-gray-500" />
|
||||
</IconButton>
|
||||
</Link>
|
||||
<Menu>
|
||||
<MenuHandler>
|
||||
<IconButton variant="text" color="blue-gray">
|
||||
<BellIcon className="h-5 w-5 text-blue-gray-500" />
|
||||
</IconButton>
|
||||
</MenuHandler>
|
||||
<MenuList className="w-max border-0">
|
||||
<MenuItem className="flex items-center gap-3">
|
||||
<Avatar
|
||||
src="https://demos.creative-tim.com/material-dashboard/assets/img/team-2.jpg"
|
||||
alt="item-1"
|
||||
size="sm"
|
||||
variant="circular"
|
||||
/>
|
||||
<div>
|
||||
<Typography
|
||||
variant="small"
|
||||
color="blue-gray"
|
||||
className="mb-1 font-normal"
|
||||
>
|
||||
<strong>New message</strong> from Laur
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="small"
|
||||
color="blue-gray"
|
||||
className="flex items-center gap-1 text-xs font-normal opacity-60"
|
||||
>
|
||||
<ClockIcon className="h-3.5 w-3.5" /> 13 minutes ago
|
||||
</Typography>
|
||||
</div>
|
||||
</MenuItem>
|
||||
<MenuItem className="flex items-center gap-4">
|
||||
<Avatar
|
||||
src="https://demos.creative-tim.com/material-dashboard/assets/img/small-logos/logo-spotify.svg"
|
||||
alt="item-1"
|
||||
size="sm"
|
||||
variant="circular"
|
||||
/>
|
||||
<div>
|
||||
<Typography
|
||||
variant="small"
|
||||
color="blue-gray"
|
||||
className="mb-1 font-normal"
|
||||
>
|
||||
<strong>New album</strong> by Travis Scott
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="small"
|
||||
color="blue-gray"
|
||||
className="flex items-center gap-1 text-xs font-normal opacity-60"
|
||||
>
|
||||
<ClockIcon className="h-3.5 w-3.5" /> 1 day ago
|
||||
</Typography>
|
||||
</div>
|
||||
</MenuItem>
|
||||
<MenuItem className="flex items-center gap-4">
|
||||
<div className="grid h-9 w-9 place-items-center rounded-full bg-gradient-to-tr from-blue-gray-800 to-blue-gray-900">
|
||||
<CreditCardIcon className="h-4 w-4 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<Typography
|
||||
variant="small"
|
||||
color="blue-gray"
|
||||
className="mb-1 font-normal"
|
||||
>
|
||||
Payment successfully completed
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="small"
|
||||
color="blue-gray"
|
||||
className="flex items-center gap-1 text-xs font-normal opacity-60"
|
||||
>
|
||||
<ClockIcon className="h-3.5 w-3.5" /> 2 days ago
|
||||
</Typography>
|
||||
</div>
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
<IconButton
|
||||
variant="text"
|
||||
color="blue-gray"
|
||||
onClick={() => setOpenConfigurator(dispatch, true)}
|
||||
>
|
||||
<Cog6ToothIcon className="h-5 w-5 text-blue-gray-500" />
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
</Navbar>
|
||||
);
|
||||
}
|
||||
|
||||
DashboardNavbar.displayName = "/src/widgets/layout/dashboard-navbar.jsx";
|
||||
|
||||
export default DashboardNavbar;
|
||||
@@ -0,0 +1,62 @@
|
||||
import PropTypes from "prop-types";
|
||||
import { Typography } from "@material-tailwind/react";
|
||||
import { HeartIcon } from "@heroicons/react/24/solid";
|
||||
|
||||
export function Footer({ brandName, brandLink, routes }) {
|
||||
const year = new Date().getFullYear();
|
||||
|
||||
return (
|
||||
<footer className="py-2">
|
||||
<div className="flex w-full flex-wrap items-center justify-center gap-6 px-2 md:justify-between">
|
||||
<Typography variant="small" className="font-normal text-inherit">
|
||||
© {year}, made with{" "}
|
||||
<HeartIcon className="-mt-0.5 inline-block h-3.5 w-3.5 text-red-600" /> by{" "}
|
||||
<a
|
||||
href={brandLink}
|
||||
target="_blank"
|
||||
className="transition-colors hover:text-blue-500 font-bold"
|
||||
>
|
||||
{brandName}
|
||||
</a>{" "}
|
||||
for a better web.
|
||||
</Typography>
|
||||
<ul className="flex items-center gap-4">
|
||||
{routes.map(({ name, path }) => (
|
||||
<li key={name}>
|
||||
<Typography
|
||||
as="a"
|
||||
href={path}
|
||||
target="_blank"
|
||||
variant="small"
|
||||
className="py-0.5 px-1 font-normal text-inherit transition-colors hover:text-blue-500"
|
||||
>
|
||||
{name}
|
||||
</Typography>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
|
||||
Footer.defaultProps = {
|
||||
brandName: "Creative Tim",
|
||||
brandLink: "https://www.creative-tim.com",
|
||||
routes: [
|
||||
{ name: "Creative Tim", path: "https://www.creative-tim.com" },
|
||||
{ name: "About Us", path: "https://www.creative-tim.com/presentation" },
|
||||
{ name: "Blog", path: "https://www.creative-tim.com/blog" },
|
||||
{ name: "License", path: "https://www.creative-tim.com/license" },
|
||||
],
|
||||
};
|
||||
|
||||
Footer.propTypes = {
|
||||
brandName: PropTypes.string,
|
||||
brandLink: PropTypes.string,
|
||||
routes: PropTypes.arrayOf(PropTypes.object),
|
||||
};
|
||||
|
||||
Footer.displayName = "/src/widgets/layout/footer.jsx";
|
||||
|
||||
export default Footer;
|
||||
@@ -0,0 +1,5 @@
|
||||
export * from "@/widgets/layout/sidenav";
|
||||
export * from "@/widgets/layout/dashboard-navbar";
|
||||
export * from "@/widgets/layout/configurator";
|
||||
export * from "@/widgets/layout/footer";
|
||||
export * from "@/widgets/layout/navbar";
|
||||
@@ -0,0 +1,107 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { Link } from "react-router-dom";
|
||||
import {
|
||||
Navbar as MTNavbar,
|
||||
Collapse,
|
||||
Typography,
|
||||
Button,
|
||||
IconButton,
|
||||
} from "@material-tailwind/react";
|
||||
import { Bars3Icon, XMarkIcon } from "@heroicons/react/24/outline";
|
||||
|
||||
export function Navbar({ brandName, routes, action }) {
|
||||
const [openNav, setOpenNav] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
window.addEventListener(
|
||||
"resize",
|
||||
() => window.innerWidth >= 960 && setOpenNav(false)
|
||||
);
|
||||
}, []);
|
||||
|
||||
const navList = (
|
||||
<ul className="mb-4 mt-2 flex flex-col gap-2 lg:mb-0 lg:mt-0 lg:flex-row lg:items-center lg:gap-6">
|
||||
{routes.map(({ name, path, icon }) => (
|
||||
<Typography
|
||||
key={name}
|
||||
as="li"
|
||||
variant="small"
|
||||
color="blue-gray"
|
||||
className="capitalize"
|
||||
>
|
||||
<Link to={path} className="flex items-center gap-1 p-1 font-normal">
|
||||
{icon &&
|
||||
React.createElement(icon, {
|
||||
className: "w-[18px] h-[18px] opacity-50 mr-1",
|
||||
})}
|
||||
{name}
|
||||
</Link>
|
||||
</Typography>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
|
||||
return (
|
||||
<MTNavbar className="p-3">
|
||||
<div className="container mx-auto flex items-center justify-between text-blue-gray-900">
|
||||
<Link to="/">
|
||||
<Typography
|
||||
variant="small"
|
||||
className="mr-4 ml-2 cursor-pointer py-1.5 font-bold"
|
||||
>
|
||||
{brandName}
|
||||
</Typography>
|
||||
</Link>
|
||||
<div className="hidden lg:block">{navList}</div>
|
||||
{React.cloneElement(action, {
|
||||
className: "hidden lg:inline-block",
|
||||
})}
|
||||
<IconButton
|
||||
variant="text"
|
||||
size="sm"
|
||||
className="ml-auto text-inherit hover:bg-transparent focus:bg-transparent active:bg-transparent lg:hidden"
|
||||
onClick={() => setOpenNav(!openNav)}
|
||||
>
|
||||
{openNav ? (
|
||||
<XMarkIcon strokeWidth={2} className="h-6 w-6" />
|
||||
) : (
|
||||
<Bars3Icon strokeWidth={2} className="h-6 w-6" />
|
||||
)}
|
||||
</IconButton>
|
||||
</div>
|
||||
<Collapse open={openNav}>
|
||||
<div className="container mx-auto">
|
||||
{navList}
|
||||
{React.cloneElement(action, {
|
||||
className: "w-full block lg:hidden",
|
||||
})}
|
||||
</div>
|
||||
</Collapse>
|
||||
</MTNavbar>
|
||||
);
|
||||
}
|
||||
|
||||
Navbar.defaultProps = {
|
||||
brandName: "Material Tailwind React",
|
||||
action: (
|
||||
<a
|
||||
href="https://www.creative-tim.com/product/material-tailwind-dashboard-react"
|
||||
target="_blank"
|
||||
>
|
||||
<Button variant="gradient" size="sm" fullWidth>
|
||||
free download
|
||||
</Button>
|
||||
</a>
|
||||
),
|
||||
};
|
||||
|
||||
Navbar.propTypes = {
|
||||
brandName: PropTypes.string,
|
||||
routes: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
action: PropTypes.node,
|
||||
};
|
||||
|
||||
Navbar.displayName = "/src/widgets/layout/navbar.jsx";
|
||||
|
||||
export default Navbar;
|
||||
@@ -0,0 +1,111 @@
|
||||
import PropTypes from "prop-types";
|
||||
import { Link, NavLink } from "react-router-dom";
|
||||
import { XMarkIcon } from "@heroicons/react/24/outline";
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
IconButton,
|
||||
Typography,
|
||||
} from "@material-tailwind/react";
|
||||
import { useMaterialTailwindController, setOpenSidenav } from "@/context";
|
||||
|
||||
export function Sidenav({ brandImg, brandName, routes }) {
|
||||
const [controller, dispatch] = useMaterialTailwindController();
|
||||
const { sidenavColor, sidenavType, openSidenav } = controller;
|
||||
const sidenavTypes = {
|
||||
dark: "bg-gradient-to-br from-gray-800 to-gray-900",
|
||||
white: "bg-white shadow-sm",
|
||||
transparent: "bg-transparent",
|
||||
};
|
||||
|
||||
return (
|
||||
<aside
|
||||
className={`${sidenavTypes[sidenavType]} ${
|
||||
openSidenav ? "translate-x-0" : "-translate-x-80"
|
||||
} fixed inset-0 z-50 my-4 ml-4 h-[calc(100vh-32px)] w-72 rounded-xl transition-transform duration-300 xl:translate-x-0 border border-blue-gray-100`}
|
||||
>
|
||||
<div
|
||||
className={`relative`}
|
||||
>
|
||||
<Link to="/" className="py-6 px-8 text-center">
|
||||
<Typography
|
||||
variant="h6"
|
||||
color={sidenavType === "dark" ? "white" : "blue-gray"}
|
||||
>
|
||||
{brandName}
|
||||
</Typography>
|
||||
</Link>
|
||||
<IconButton
|
||||
variant="text"
|
||||
color="white"
|
||||
size="sm"
|
||||
ripple={false}
|
||||
className="absolute right-0 top-0 grid rounded-br-none rounded-tl-none xl:hidden"
|
||||
onClick={() => setOpenSidenav(dispatch, false)}
|
||||
>
|
||||
<XMarkIcon strokeWidth={2.5} className="h-5 w-5 text-white" />
|
||||
</IconButton>
|
||||
</div>
|
||||
<div className="m-4">
|
||||
{routes.map(({ layout, title, pages }, key) => (
|
||||
<ul key={key} className="mb-4 flex flex-col gap-1">
|
||||
{title && (
|
||||
<li className="mx-3.5 mt-4 mb-2">
|
||||
<Typography
|
||||
variant="small"
|
||||
color={sidenavType === "dark" ? "white" : "blue-gray"}
|
||||
className="font-black uppercase opacity-75"
|
||||
>
|
||||
{title}
|
||||
</Typography>
|
||||
</li>
|
||||
)}
|
||||
{pages.map(({ icon, name, path }) => (
|
||||
<li key={name}>
|
||||
<NavLink to={`/${layout}${path}`}>
|
||||
{({ isActive }) => (
|
||||
<Button
|
||||
variant={isActive ? "gradient" : "text"}
|
||||
color={
|
||||
isActive
|
||||
? sidenavColor
|
||||
: sidenavType === "dark"
|
||||
? "white"
|
||||
: "blue-gray"
|
||||
}
|
||||
className="flex items-center gap-4 px-4 capitalize"
|
||||
fullWidth
|
||||
>
|
||||
{icon}
|
||||
<Typography
|
||||
color="inherit"
|
||||
className="font-medium capitalize"
|
||||
>
|
||||
{name}
|
||||
</Typography>
|
||||
</Button>
|
||||
)}
|
||||
</NavLink>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
))}
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
||||
Sidenav.defaultProps = {
|
||||
brandImg: "/img/logo-ct.png",
|
||||
brandName: "Material Tailwind React",
|
||||
};
|
||||
|
||||
Sidenav.propTypes = {
|
||||
brandImg: PropTypes.string,
|
||||
brandName: PropTypes.string,
|
||||
routes: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
};
|
||||
|
||||
Sidenav.displayName = "/src/widgets/layout/sidnave.jsx";
|
||||
|
||||
export default Sidenav;
|
||||
Reference in New Issue
Block a user