New Frontend Preps

This commit is contained in:
root
2025-10-15 14:57:39 +00:00
parent d776b80fe0
commit f8209c3712
102 changed files with 4065 additions and 65 deletions
+14
View File
@@ -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;
+61
View File
@@ -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;
+1
View File
@@ -0,0 +1 @@
export * from "@/configs/charts-config";
+85
View File
@@ -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 });
+52
View File
@@ -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;
+29
View File
@@ -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;
+8
View File
@@ -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";
+49
View File
@@ -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;
+60
View File
@@ -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;
+65
View File
@@ -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;
+131
View File
@@ -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;
+52
View File
@@ -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;
+56
View File
@@ -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;
+2
View File
@@ -0,0 +1,2 @@
export * from "@/layouts/dashboard";
export * from "@/layouts/auth";
+30
View File
@@ -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>
);
+2
View File
@@ -0,0 +1,2 @@
export * from "@/pages/auth/sign-in";
export * from "@/pages/auth/sign-up";
+126
View File
@@ -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&nbsp;
<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;
+94
View File
@@ -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&nbsp;
<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;
+258
View File
@@ -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>
&nbsp;{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" />
&nbsp;{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;
+4
View File
@@ -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;
+221
View File
@@ -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;
+221
View File
@@ -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;
+66
View File
@@ -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;
+3
View File
@@ -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;
+1
View File
@@ -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;
+62
View File
@@ -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">
&copy; {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;
+5
View File
@@ -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";
+107
View File
@@ -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;
+111
View File
@@ -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;