Novo site

This commit is contained in:
Marco Santos
2025-03-05 01:07:29 +00:00
parent 7d7657f203
commit 471559ccb7
162 changed files with 8335 additions and 1769 deletions

View File

@@ -6,7 +6,6 @@ EXPOSE 8080
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["GeradoresWS/GeradoresWS.csproj", "GeradoresWS/"]

View File

@@ -1,14 +1,22 @@
version: "3.8"
services:
geradoresws:
build: .
build:
context: . # Caminho para a pasta do Dockerfile do backend
dockerfile: Dockerfile
image: docker.io/shini89/geradoresws:latest
ports:
- "5050:8080"
networks:
- app-network
environment:
- ASPNETCORE_ENVIRONMENT=Production # Variavel de ambiente para o backend
geradoresfe:
build: ./geradoresfe
build:
context: ./geradoresfe # Caminho para a pasta do Dockerfile do frontend
dockerfile: Dockerfile
image: docker.io/shini89/geradoresfe:latest
ports:
- "3000:3000"
depends_on:

View File

@@ -1 +1 @@
REACT_APP_API_URL=http://localhost:5015/
REACT_APP_API_URL=https://localhost:44329/

View File

@@ -21,3 +21,8 @@
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.vercel
package-lock.json
yarn-lock.json
pnpm-lock.json

6
geradoresfe/.vscode/iisexpress.json vendored Normal file
View File

@@ -0,0 +1,6 @@
{
"port": 26415,
"path": "./",
"clr": "v4.0",
"protocol": "http"
}

View File

@@ -1,26 +1,45 @@
{
"name": "geradoresfe",
"version": "0.1.0",
"private": true,
"name": "tailadmin-react-free",
"version": "2.0.0",
"dependencies": {
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@headlessui/react": "^2.2.0",
"@heroicons/react": "^2.1.5",
"@mui/icons-material": "^5.15.15",
"@mui/material": "^5.15.15",
"@fullcalendar/core": "^6.1.15",
"@fullcalendar/daygrid": "^6.1.15",
"@fullcalendar/interaction": "^6.1.15",
"@fullcalendar/list": "^6.1.15",
"@fullcalendar/react": "^6.1.15",
"@fullcalendar/timegrid": "^6.1.15",
"@react-jvectormap/core": "^1.0.4",
"@react-jvectormap/world": "^1.1.2",
"@tailwindcss/forms": "^0.5.9",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.18.95",
"@types/react": "^18.2.74",
"@types/react-dom": "^18.2.24",
"axios": "^1.6.8",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@types/node": "^16.18.119",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"apexcharts": "^4.1.0",
"autoprefixer": "^10.4.20",
"classnames": "^2.5.1",
"clsx": "^2.1.1",
"flatpickr": "^4.6.13",
"lucide-react": "^0.477.0",
"motion": "^12.4.10",
"postcss": "^8.4.49",
"react": "^18.3.1",
"react-apexcharts": "^1.6.0",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "^18.3.1",
"react-dropzone": "^14.3.5",
"react-flatpickr": "^3.10.13",
"react-helmet": "^6.1.0",
"react-helmet-async": "^2.0.5",
"react-router": "^7.0.1",
"react-scripts": "5.0.1",
"react-simple-maps": "^3.0.0",
"swiper": "^11.1.15",
"tailwind-merge": "^2.6.0",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4"
},
@@ -49,10 +68,7 @@
]
},
"devDependencies": {
"@types/react-helmet": "^6.1.11",
"eslint": "^8.57.0",
"eslint-config-react-app": "^7.0.1",
"jest-editor-support": "^31.1.2",
"tailwindcss": "^3.4.13"
"@types/react-flatpickr": "^3.8.11",
"tailwindcss": "^3.4.15"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -2,9 +2,8 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="icon" href="%PUBLIC_URL%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
@@ -24,9 +23,8 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<body class="dark:bg-gray-900">
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--

View File

@@ -1,38 +0,0 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

View File

@@ -1,20 +1,37 @@
import React from 'react';
import Navbar from './components/Navbar';
import Hero from './components/Hero';
import FeatureSection from './components/Features';
import Footer from './components/Footer';
import { Route, BrowserRouter as Router, Routes } from "react-router";
import AppLayout from "./layout/AppLayout";
import AuthLayout from "./layout/AuthLayout";
import SignIn from "./pages/AuthPages/SignIn";
import SignUp from "./pages/AuthPages/SignUp";
import Blank from "./pages/Blank";
const App = () => {
import Home from "./pages/Home";
import GenerateNIF from "./pages/GenerateNIF";
import GenerateNISS from "./pages/GenerateNISS";
import GenerateCC from "./pages/GenerateCC";
export default function App() {
return (
<div className="min-h-screen flex flex-col">
<Navbar />
<main className="flex-grow">
<Hero />
<FeatureSection />
</main>
<Footer />
</div>
);
};
<>
<Router>
<Routes>
{/* Dashboard Layout */}
<Route element={<AppLayout />}>
<Route index path="/" element={<Home />} />
<Route path="/NIF" element={<GenerateNIF />} />
<Route path="/NISS" element={<GenerateNISS />} />
<Route path="/CC" element={<GenerateCC />} />
</Route>
export default App;
{/* Auth Layout */}
<Route element={<AuthLayout />}>
<Route path="/signin" element={<SignIn />} />
<Route path="/signup" element={<SignUp />} />
</Route>
{/* Fallback Route */}
</Routes>
</Router>
</>
);
}

View File

@@ -1,633 +0,0 @@
import type { } from '@mui/material/themeCssVarsAugmentation';
import { ThemeOptions, alpha } from '@mui/material/styles';
import { red } from '@mui/material/colors';
import { PaletteMode } from '@mui/material';
declare module '@mui/material/styles/createPalette' {
interface ColorRange {
50: string;
100: string;
200: string;
300: string;
400: string;
500: string;
600: string;
700: string;
800: string;
900: string;
}
interface PaletteColor extends ColorRange { }
}
export const brand = {
50: '#F0F7FF',
100: '#CEE5FD',
200: '#9CCCFC',
300: '#55A6F6',
400: '#0A66C2',
500: '#0959AA',
600: '#064079',
700: '#033363',
800: '#02294F',
900: '#021F3B',
};
export const secondary = {
50: '#F9F0FF',
100: '#E9CEFD',
200: '#D49CFC',
300: '#B355F6',
400: '#750AC2',
500: '#6709AA',
600: '#490679',
700: '#3B0363',
800: '#2F024F',
900: '#23023B',
};
export const gray = {
50: '#FBFCFE',
100: '#EAF0F5',
200: '#D6E2EB',
300: '#BFCCD9',
400: '#94A6B8',
500: '#5B6B7C',
600: '#4C5967',
700: '#364049',
800: '#131B20',
900: '#090E10',
};
export const green = {
50: '#F6FEF6',
100: '#E3FBE3',
200: '#C7F7C7',
300: '#A1E8A1',
400: '#51BC51',
500: '#1F7A1F',
600: '#136C13',
700: '#0A470A',
800: '#042F04',
900: '#021D02',
};
const getDesignTokens = (mode: PaletteMode) => ({
palette: {
mode,
primary: {
light: brand[200],
main: brand[500],
dark: brand[800],
contrastText: brand[50],
...(mode === 'dark' && {
contrastText: brand[100],
light: brand[300],
main: brand[400],
dark: brand[800],
}),
},
secondary: {
light: secondary[300],
main: secondary[500],
dark: secondary[800],
...(mode === 'dark' && {
light: secondary[400],
main: secondary[500],
dark: secondary[900],
}),
},
warning: {
main: '#F7B538',
dark: '#F79F00',
...(mode === 'dark' && { main: '#F7B538', dark: '#F79F00' }),
},
error: {
light: red[50],
main: red[500],
dark: red[700],
...(mode === 'dark' && { light: '#D32F2F', main: '#D32F2F', dark: '#B22A2A' }),
},
success: {
light: green[300],
main: green[400],
dark: green[800],
...(mode === 'dark' && {
light: green[400],
main: green[500],
dark: green[700],
}),
},
grey: {
50: gray[50],
100: gray[100],
200: gray[200],
300: gray[300],
400: gray[400],
500: gray[500],
600: gray[600],
700: gray[700],
800: gray[800],
900: gray[900],
},
divider: mode === 'dark' ? alpha(gray[600], 0.3) : alpha(gray[300], 0.5),
background: {
default: '#fff',
paper: gray[50],
...(mode === 'dark' && { default: gray[900], paper: gray[800] }),
},
text: {
primary: gray[800],
secondary: gray[600],
...(mode === 'dark' && { primary: '#fff', secondary: gray[400] }),
},
action: {
selected: `${alpha(brand[200], 0.2)}`,
...(mode === 'dark' && {
selected: alpha(brand[800], 0.2),
}),
},
},
typography: {
fontFamily: ['"Inter", "sans-serif"'].join(','),
h1: {
fontSize: 60,
fontWeight: 600,
lineHeight: 78 / 70,
letterSpacing: -0.2,
},
h2: {
fontSize: 48,
fontWeight: 600,
lineHeight: 1.2,
},
h3: {
fontSize: 42,
lineHeight: 1.2,
},
h4: {
fontSize: 36,
fontWeight: 500,
lineHeight: 1.5,
},
h5: {
fontSize: 20,
fontWeight: 600,
},
h6: {
fontSize: 18,
},
subtitle1: {
fontSize: 18,
},
subtitle2: {
fontSize: 16,
},
body1: {
fontWeight: 400,
fontSize: 15,
},
body2: {
fontWeight: 400,
fontSize: 14,
},
caption: {
fontWeight: 400,
fontSize: 12,
},
},
});
export default function getLPTheme(mode: PaletteMode): ThemeOptions {
return {
...getDesignTokens(mode),
components: {
MuiAccordion: {
defaultProps: {
elevation: 0,
disableGutters: true,
},
styleOverrides: {
root: ({ theme }) => ({
padding: 8,
overflow: 'clip',
backgroundColor: '#fff',
border: '1px solid',
borderColor: gray[100],
':before': {
backgroundColor: 'transparent',
},
'&:first-of-type': {
borderTopLeftRadius: 10,
borderTopRightRadius: 10,
},
'&:last-of-type': {
borderBottomLeftRadius: 10,
borderBottomRightRadius: 10,
},
...(theme.palette.mode === 'dark' && {
backgroundColor: gray[900],
borderColor: gray[800],
}),
}),
},
},
MuiAccordionSummary: {
styleOverrides: {
root: ({ theme }) => ({
border: 'none',
borderRadius: 8,
'&:hover': { backgroundColor: gray[100] },
...(theme.palette.mode === 'dark' && {
'&:hover': { backgroundColor: gray[800] },
}),
}),
},
},
MuiAccordionDetails: {
styleOverrides: {
root: { mb: 20, border: 'none' },
},
},
MuiToggleButtonGroup: {
styleOverrides: {
root: ({ theme }) => ({
borderRadius: '10px',
boxShadow: `0 4px 16px ${alpha(gray[400], 0.2)}`,
'& .Mui-selected': {
color: brand[500],
},
...(theme.palette.mode === 'dark' && {
'& .Mui-selected': {
color: '#fff',
},
boxShadow: `0 4px 16px ${alpha(brand[700], 0.5)}`,
}),
}),
},
},
MuiToggleButton: {
styleOverrides: {
root: ({ theme }) => ({
padding: '12px 16px',
textTransform: 'none',
borderRadius: '10px',
fontWeight: 500,
...(theme.palette.mode === 'dark' && {
color: gray[400],
boxShadow: '0 4px 16px rgba(0, 0, 0, 0.5)',
'&.Mui-selected': { color: brand[300] },
}),
}),
},
},
MuiButtonBase: {
defaultProps: {
disableTouchRipple: true,
disableRipple: true,
},
styleOverrides: {
root: {
boxSizing: 'border-box',
transition: 'all 100ms ease-in',
'&:focus-visible': {
outline: `3px solid ${alpha(brand[500], 0.5)}`,
outlineOffset: '2px',
},
},
},
},
MuiButton: {
styleOverrides: {
root: ({ theme, ownerState }) => ({
boxSizing: 'border-box',
boxShadow: 'none',
borderRadius: '10px',
textTransform: 'none',
'&:active': {
transform: 'scale(0.98)',
},
...(ownerState.size === 'small' && {
maxHeight: '32px',
}),
...(ownerState.size === 'medium' && {
height: '40px',
}),
...(ownerState.variant === 'contained' &&
ownerState.color === 'primary' && {
color: brand[50],
background: brand[500],
backgroundImage: `linear-gradient(to bottom, ${brand[400]}, ${brand[600]})`,
boxShadow: `inset 0 1px ${alpha(brand[300], 0.4)}`,
outline: `1px solid ${brand[700]}`,
'&:hover': {
background: brand[400],
backgroundImage: 'none',
boxShadow: `0 0 0 1px ${alpha(brand[300], 0.5)}`,
},
}),
...(ownerState.variant === 'outlined' && {
backgroundColor: alpha(brand[300], 0.1),
borderColor: brand[300],
color: brand[500],
'&:hover': {
backgroundColor: alpha(brand[300], 0.3),
borderColor: brand[200],
},
}),
...(ownerState.variant === 'text' && {
color: brand[500],
'&:hover': {
backgroundColor: alpha(brand[300], 0.3),
borderColor: brand[200],
},
}),
...(theme.palette.mode === 'dark' && {
...(ownerState.variant === 'outlined' && {
backgroundColor: alpha(brand[600], 0.1),
borderColor: brand[700],
color: brand[300],
'&:hover': {
backgroundColor: alpha(brand[600], 0.3),
borderColor: brand[700],
},
}),
...(ownerState.variant === 'text' && {
color: brand[300],
'&:hover': {
backgroundColor: alpha(brand[600], 0.3),
borderColor: brand[700],
},
}),
}),
}),
},
},
MuiCard: {
styleOverrides: {
root: ({ theme, ownerState }) => ({
backgroundColor: gray[50],
borderRadius: 10,
border: `1px solid ${alpha(gray[200], 0.8)}`,
boxShadow: 'none',
transition: 'background-color, border, 80ms ease',
...(ownerState.variant === 'outlined' && {
background: `linear-gradient(to bottom, #FFF, ${gray[50]})`,
'&:hover': {
borderColor: brand[300],
boxShadow: `0 0 24px ${brand[100]}`,
},
}),
...(theme.palette.mode === 'dark' && {
backgroundColor: alpha(gray[800], 0.6),
border: `1px solid ${alpha(gray[700], 0.3)}`,
...(ownerState.variant === 'outlined' && {
background: `linear-gradient(to bottom, ${gray[900]}, ${alpha(
gray[800],
0.5,
)})`,
'&:hover': {
borderColor: brand[700],
boxShadow: `0 0 24px ${brand[800]}`,
},
}),
}),
}),
},
},
MuiChip: {
styleOverrides: {
root: ({ theme }) => ({
alignSelf: 'center',
py: 1.5,
px: 0.5,
background: `linear-gradient(to bottom right, ${brand[50]}, ${brand[100]})`,
border: '1px solid',
borderColor: `${alpha(brand[500], 0.3)}`,
fontWeight: '600',
'&:hover': {
backgroundColor: brand[500],
},
'&:focus-visible': {
borderColor: brand[800],
backgroundColor: brand[200],
},
'& .MuiChip-label': {
color: brand[500],
},
'& .MuiChip-icon': {
color: brand[500],
},
...(theme.palette.mode === 'dark' && {
background: `linear-gradient(to bottom right, ${brand[700]}, ${brand[900]})`,
borderColor: `${alpha(brand[500], 0.5)}`,
'&:hover': {
backgroundColor: brand[600],
},
'&:focus-visible': {
borderColor: brand[200],
backgroundColor: brand[600],
},
'& .MuiChip-label': {
color: brand[200],
},
'& .MuiChip-icon': {
color: brand[200],
},
}),
}),
},
},
MuiDivider: {
styleOverrides: {
root: ({ theme }) => ({
borderColor: `${alpha(gray[200], 0.8)}`,
...(theme.palette.mode === 'dark' && {
borderColor: `${alpha(gray[700], 0.4)}`,
}),
}),
},
},
MuiLink: {
defaultProps: {
underline: 'none',
},
styleOverrides: {
root: ({ theme }) => ({
color: brand[600],
fontWeight: 500,
position: 'relative',
textDecoration: 'none',
'&::before': {
content: '""',
position: 'absolute',
width: 0,
height: '1px',
bottom: 0,
left: 0,
backgroundColor: brand[200],
opacity: 0.7,
transition: 'width 0.3s ease, opacity 0.3s ease',
},
'&:hover::before': {
width: '100%',
opacity: 1,
},
...(theme.palette.mode === 'dark' && {
color: brand[200],
}),
}),
},
},
MuiMenuItem: {
styleOverrides: {
root: ({ theme }) => ({
borderRadius: '99px',
color: gray[500],
fontWeight: 500,
...(theme.palette.mode === 'dark' && {
color: gray[300],
}),
}),
},
},
MuiPaper: {
styleOverrides: {
root: ({ theme }) => ({
backgroundImage: 'none',
backgroundColor: gray[100],
...(theme.palette.mode === 'dark' && {
backgroundColor: alpha(gray[900], 0.6),
}),
}),
},
},
MuiSwitch: {
styleOverrides: {
root: ({ theme }) => ({
boxSizing: 'border-box',
width: 36,
height: 24,
padding: 0,
transition: 'background-color 100ms ease-in',
'&:hover': {
'& .MuiSwitch-track': {
backgroundColor: brand[600],
},
},
'& .MuiSwitch-switchBase': {
'&.Mui-checked': {
transform: 'translateX(13px)',
},
},
'& .MuiSwitch-track': {
borderRadius: 50,
},
'& .MuiSwitch-thumb': {
boxShadow: '0 0 2px 2px rgba(0, 0, 0, 0.2)',
backgroundColor: '#FFF',
width: 16,
height: 16,
margin: 2,
},
...(theme.palette.mode === 'dark' && {
width: 36,
height: 24,
padding: 0,
transition: 'background-color 100ms ease-in',
'&:hover': {
'& .MuiSwitch-track': {
backgroundColor: brand[600],
},
},
'& .MuiSwitch-switchBase': {
'&.Mui-checked': {
transform: 'translateX(13px)',
},
},
'& .MuiSwitch-thumb': {
boxShadow: '0 0 2px 2px rgba(0, 0, 0, 0.2)',
backgroundColor: '#FFF',
width: 16,
height: 16,
margin: 2,
},
}),
}),
switchBase: {
height: 24,
width: 24,
padding: 0,
color: '#fff',
'&.Mui-checked + .MuiSwitch-track': {
opacity: 1,
},
},
},
},
MuiTextField: {
styleOverrides: {
root: ({ theme }) => ({
'& label .Mui-focused': {
color: 'white',
},
'& .MuiInputBase-input': {
boxSizing: 'border-box',
'&::placeholder': {
opacity: 0.7,
},
},
'& .MuiOutlinedInput-root': {
boxSizing: 'border-box',
minWidth: 280,
minHeight: 40,
height: '100%',
borderRadius: '10px',
border: '1px solid',
borderColor: gray[200],
transition: 'border-color 120ms ease-in',
'& fieldset': {
border: 'none',
boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)',
background: `${alpha('#FFF', 0.3)}`,
},
'&:hover': {
borderColor: brand[300],
},
'&.Mui-focused': {
borderColor: brand[400],
outline: '4px solid',
outlineColor: brand[200],
},
},
...(theme.palette.mode === 'dark' && {
'& .MuiOutlinedInput-root': {
boxSizing: 'border-box',
minWidth: 280,
minHeight: 40,
height: '100%',
borderRadius: '10px',
border: '1px solid',
borderColor: gray[600],
transition: 'border-color 120ms ease-in',
'& fieldset': {
border: 'none',
boxShadow: ' 0px 2px 4px rgba(0, 0, 0, 0.4)',
background: `${alpha(gray[800], 0.4)}`,
},
'&:hover': {
borderColor: brand[300],
},
'&.Mui-focused': {
borderColor: brand[400],
outline: '4px solid',
outlineColor: alpha(brand[500], 0.5),
},
},
}),
}),
},
},
},
};
}

View File

@@ -1,150 +0,0 @@
import * as React from 'react';
import Accordion from '@mui/material/Accordion';
import AccordionDetails from '@mui/material/AccordionDetails';
import AccordionSummary from '@mui/material/AccordionSummary';
import Box from '@mui/material/Box';
import Container from '@mui/material/Container';
import Link from '@mui/material/Link';
import Typography from '@mui/material/Typography';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
export default function FAQ() {
const [expanded, setExpanded] = React.useState<string | false>(false);
const handleChange =
(panel: string) => (event: React.SyntheticEvent, isExpanded: boolean) => {
setExpanded(isExpanded ? panel : false);
};
return (
<Container
id="faq"
sx={{
pt: { xs: 4, sm: 12 },
pb: { xs: 8, sm: 16 },
position: 'relative',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: { xs: 3, sm: 6 },
}}
>
<Typography
component="h2"
variant="h4"
color="text.primary"
sx={{
width: { sm: '100%', md: '60%' },
textAlign: { sm: 'left', md: 'center' },
}}
>
Frequently asked questions
</Typography>
<Box sx={{ width: '100%' }}>
<Accordion
expanded={expanded === 'panel1'}
onChange={handleChange('panel1')}
>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1d-content"
id="panel1d-header"
>
<Typography component="h3" variant="subtitle2">
How do I contact customer support if I have a question or issue?
</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography
variant="body2"
gutterBottom
sx={{ maxWidth: { sm: '100%', md: '70%' } }}
>
You can reach our customer support team by emailing
<Link> support@email.com </Link>
or calling our toll-free number. We&apos;re here to assist you
promptly.
</Typography>
</AccordionDetails>
</Accordion>
<Accordion
expanded={expanded === 'panel2'}
onChange={handleChange('panel2')}
>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel2d-content"
id="panel2d-header"
>
<Typography component="h3" variant="subtitle2">
Can I return the product if it doesn&apos;t meet my expectations?
</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography
variant="body2"
gutterBottom
sx={{ maxWidth: { sm: '100%', md: '70%' } }}
>
Absolutely! We offer a hassle-free return policy. If you&apos;re not
completely satisfied, you can return the product within [number of
days] days for a full refund or exchange.
</Typography>
</AccordionDetails>
</Accordion>
<Accordion
expanded={expanded === 'panel3'}
onChange={handleChange('panel3')}
>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel3d-content"
id="panel3d-header"
>
<Typography component="h3" variant="subtitle2">
What makes your product stand out from others in the market?
</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography
variant="body2"
gutterBottom
sx={{ maxWidth: { sm: '100%', md: '70%' } }}
>
Our product distinguishes itself through its adaptability, durability,
and innovative features. We prioritize user satisfaction and
continually strive to exceed expectations in every aspect.
</Typography>
</AccordionDetails>
</Accordion>
<Accordion
expanded={expanded === 'panel4'}
onChange={handleChange('panel4')}
>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel4d-content"
id="panel4d-header"
>
<Typography component="h3" variant="subtitle2">
Is there a warranty on the product, and what does it cover?
</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography
variant="body2"
gutterBottom
sx={{ maxWidth: { sm: '100%', md: '70%' } }}
>
Yes, our product comes with a [length of warranty] warranty. It covers
defects in materials and workmanship. If you encounter any issues
covered by the warranty, please contact our customer support for
assistance.
</Typography>
</AccordionDetails>
</Accordion>
</Box>
</Container>
);
}

View File

@@ -1,27 +0,0 @@
import React from 'react';
function FeatureSection() {
return (
<section id="features" className="py-20 bg-white">
<div className="container mx-auto px-4 text-center">
<h2 className="text-3xl font-bold text-gray-800">Why Use Our Generator?</h2>
<div className="mt-8 grid grid-cols-1 md:grid-cols-3 gap-8">
<div className="p-6 bg-gray-50 rounded-lg shadow-md">
<h3 className="text-xl font-bold text-gray-800">NIF (N<EFBFBD>mero Identifica<EFBFBD><EFBFBD>o Fiscal)</h3>
<p className="mt-4 text-gray-600">Quickly generate valid Portuguese Tax Identification Numbers (NIF) for testing.</p>
</div>
<div className="p-6 bg-gray-50 rounded-lg shadow-md">
<h3 className="text-xl font-bold text-gray-800">NISS (N<EFBFBD>mero Identifica<EFBFBD><EFBFBD>o Seguran<EFBFBD>a Social)</h3>
<p className="mt-4 text-gray-600">Create Portuguese Social Security Numbers (NISS) easily with one click.</p>
</div>
<div className="p-6 bg-gray-50 rounded-lg shadow-md">
<h3 className="text-xl font-bold text-gray-800">Cart<EFBFBD>o de Cidad<EFBFBD>o</h3>
<p className="mt-4 text-gray-600">Generate valid Citizen Card numbers for testing purposes in a few seconds.</p>
</div>
</div>
</div>
</section>
);
};
export default FeatureSection;

View File

@@ -1,16 +0,0 @@
import React from 'react';
const Footer = () => {
return (
<footer id="contact" className="bg-gray-800 py-6">
<div className="container mx-auto px-4 text-center text-white">
<p className="text-sm">&copy; {new Date().getFullYear()} GeneratorApp. All rights reserved.</p>
<p className="mt-2">
<a href="mailto:info@generatorapp.com" className="underline">info@generatorapp.com</a>
</p>
</div>
</footer>
);
};
export default Footer;

View File

@@ -1,67 +0,0 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Container from '@mui/material/Container';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import CardActions from '@mui/material/CardActions/CardActions';
import GeradorService from '../Api/GeradorApi';
import { useEffect, useState } from 'react';
export default function GeradorNIF() {
const [nif, setNIF] = useState<any[]>([]);
const fetchNif = async () => {
const nif = await GeradorService.GenerateNIF(null);
setNIF(nif);
}
useEffect(() => {
fetchNif();
}, []);
return (
<Box
id="GeradorNIF"
>
<Container
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
pt: { xs: 14, sm: 20 },
pb: { xs: 8, sm: 12 },
}}
>
<Stack
spacing={2}
alignItems="center"
useFlexGap
sx={{ width: { xs: '100%', sm: '70%' } }}
>
<Card sx={{ minWidth: 275 }}>
<CardContent>
<Typography variant='h4'>
NIF<Button size="small">copiar</Button>
</Typography>
<br />
<Typography sx={{ mb: 1.5 }} color="text.secondary">
{nif}
</Typography>
</CardContent>
<CardActions>
<Button size="small" onClick={fetchNif}>Gerar</Button>
</CardActions>
</Card>
</Stack>
</Container>
</Box>
);
}

View File

@@ -1,23 +0,0 @@
import React from 'react';
function Hero(){
return (
<section id="home" className="bg-blue-50 py-20">
<div className="container mx-auto text-center">
<h1 className="text-5xl font-bold text-gray-800">
Generate Your NIF, NISS, and Cart<EFBFBD>o de Cidad<EFBFBD>o Easily
</h1>
<p className="mt-4 text-gray-600">
Use our simple and efficient platform to generate valid testing numbers quickly.
</p>
<div className="mt-6">
<a href="#generate" className="px-6 py-3 bg-blue-600 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700">
Get Started
</a>
</div>
</div>
</section>
);
};
export default Hero;

View File

@@ -1,124 +0,0 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import Card from '@mui/material/Card';
import Container from '@mui/material/Container';
import Grid from '@mui/material/Grid';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import AutoFixHighRoundedIcon from '@mui/icons-material/AutoFixHighRounded';
import ConstructionRoundedIcon from '@mui/icons-material/ConstructionRounded';
import QueryStatsRoundedIcon from '@mui/icons-material/QueryStatsRounded';
import SettingsSuggestRoundedIcon from '@mui/icons-material/SettingsSuggestRounded';
import SupportAgentRoundedIcon from '@mui/icons-material/SupportAgentRounded';
import ThumbUpAltRoundedIcon from '@mui/icons-material/ThumbUpAltRounded';
const items = [
{
icon: <SettingsSuggestRoundedIcon />,
title: 'Adaptable performance',
description:
'Our product effortlessly adjusts to your needs, boosting efficiency and simplifying your tasks.',
},
{
icon: <ConstructionRoundedIcon />,
title: 'Built to last',
description:
'Experience unmatched durability that goes above and beyond with lasting investment.',
},
{
icon: <ThumbUpAltRoundedIcon />,
title: 'Great user experience',
description:
'Integrate our product into your routine with an intuitive and easy-to-use interface.',
},
{
icon: <AutoFixHighRoundedIcon />,
title: 'Innovative functionality',
description:
'Stay ahead with features that set new standards, addressing your evolving needs better than the rest.',
},
{
icon: <SupportAgentRoundedIcon />,
title: 'Reliable support',
description:
'Count on our responsive customer support, offering assistance that goes beyond the purchase.',
},
{
icon: <QueryStatsRoundedIcon />,
title: 'Precision in every detail',
description:
'Enjoy a meticulously crafted product where small touches make a significant impact on your overall experience.',
},
];
export default function Highlights() {
return (
<Box
id="highlights"
sx={{
pt: { xs: 4, sm: 12 },
pb: { xs: 8, sm: 16 },
color: 'white',
bgcolor: 'hsl(220, 30%, 2%)',
}}
>
<Container
sx={{
position: 'relative',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: { xs: 3, sm: 6 },
}}
>
<Box
sx={{
width: { sm: '100%', md: '60%' },
textAlign: { sm: 'left', md: 'center' },
}}
>
<Typography component="h2" variant="h4">
Highlights
</Typography>
<Typography variant="body1" sx={{ color: 'grey.400' }}>
Explore why our product stands out: adaptability, durability,
user-friendly design, and innovation. Enjoy reliable customer support and
precision in every detail.
</Typography>
</Box>
<Grid container spacing={2.5}>
{items.map((item, index) => (
<Grid item xs={12} sm={6} md={4} key={index}>
<Stack
direction="column"
color="inherit"
component={Card}
spacing={1}
useFlexGap
sx={{
p: 3,
height: '100%',
border: '1px solid',
borderColor: 'hsla(220, 25%, 25%, .3)',
background: 'transparent',
backgroundColor: 'grey.900',
boxShadow: 'none',
}}
>
<Box sx={{ opacity: '50%' }}>{item.icon}</Box>
<div>
<Typography fontWeight="medium" gutterBottom>
{item.title}
</Typography>
<Typography variant="body2" sx={{ color: 'grey.400' }}>
{item.description}
</Typography>
</div>
</Stack>
</Grid>
))}
</Grid>
</Container>
</Box>
);
}

View File

@@ -1,59 +0,0 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import Grid from '@mui/material/Grid';
import { useTheme } from '@mui/system';
const whiteLogos = [
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/6560628e8573c43893fe0ace_Sydney-white.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/655f4d520d0517ae8e8ddf13_Bern-white.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/655f46794c159024c1af6d44_Montreal-white.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/61f12e891fa22f89efd7477a_TerraLight.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/6560a09d1f6337b1dfed14ab_colorado-white.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/655f5caa77bf7d69fb78792e_Ankara-white.svg',
];
const darkLogos = [
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/6560628889c3bdf1129952dc_Sydney-black.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/655f4d4d8b829a89976a419c_Bern-black.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/655f467502f091ccb929529d_Montreal-black.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/61f12e911fa22f2203d7514c_TerraDark.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/6560a0990f3717787fd49245_colorado-black.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/655f5ca4e548b0deb1041c33_Ankara-black.svg',
];
const logoStyle = {
width: '100px',
height: '80px',
margin: '0 32px',
opacity: 0.7,
};
export default function LogoCollection() {
const theme = useTheme();
const logos = theme.palette.mode === 'light' ? darkLogos : whiteLogos;
return (
<Box id="logoCollection" sx={{ py: 4 }}>
<Typography
component="p"
variant="subtitle2"
align="center"
color="text.secondary"
>
Trusted by the best companies
</Typography>
<Grid container justifyContent="center" sx={{ mt: 0.5, opacity: 0.6 }}>
{logos.map((logo, index) => (
<Grid item key={index}>
<img
src={logo}
alt={`Fake company number ${index + 1}`}
style={logoStyle}
/>
</Grid>
))}
</Grid>
</Box>
);
}

View File

@@ -1,108 +0,0 @@
import React, { useState, useEffect } from 'react';
import { Transition } from '@headlessui/react';
import { MoonIcon, SunIcon } from '@heroicons/react/24/outline';
import Logo from '../assets/logotipo.png';
const Navbar = () => {
const [isOpen, setIsOpen] = useState(false);
const [darkMode, setDarkMode] = useState(false);
// Apply dark mode based on the toggle state
useEffect(() => {
if (darkMode) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}, [darkMode]);
return (
<nav className="bg-blue-900 dark:bg-gray-800 shadow-lg sticky top-0 z-50">
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
{/* Logo e Nome da Marca */}
<div className="flex items-center space-x-2">
<img src={Logo} alt="FactoryID Logo" className="h-8 w-auto" />
</div>
{/* Desktop Navigation Links */}
<div className="hidden md:flex space-x-8">
<a href="#home" className="text-gray-800 dark:text-white hover:text-yellow-300 transition duration-300 transform hover:scale-110">
Home
</a>
<a href="#features" className="text-gray-800 dark:text-white hover:text-yellow-300 transition duration-300 transform hover:scale-110">
Features
</a>
<a href="#contact" className="text-gray-800 dark:text-white hover:text-yellow-300 transition duration-300 transform hover:scale-110">
Contact
</a>
<a href="#get-started" className="bg-yellow-300 text-gray-800 px-4 py-2 rounded-lg shadow-md hover:bg-yellow-400 transition duration-300">
Get Started
</a>
</div>
{/* Dark Mode Toggle */}
<div className="flex items-center space-x-4">
<button
onClick={() => setDarkMode(!darkMode)}
className="flex items-center px-2 py-1 rounded-md bg-gray-200 dark:bg-gray-700 dark:text-gray-200 text-gray-800 hover:bg-gray-300 dark:hover:bg-gray-600"
>
{darkMode ? (
<SunIcon className="h-6 w-6 text-yellow-400" />
) : (
<MoonIcon className="h-6 w-6 text-blue-500" />
)}
<span className="ml-2">{darkMode ? 'Light Mode' : 'Dark Mode'}</span>
</button>
{/* Mobile Menu Button */}
<button
onClick={() => setIsOpen(!isOpen)}
type="button"
className="text-gray-800 dark:text-white md:hidden"
aria-controls="mobile-menu"
aria-expanded="false"
>
<span className="sr-only">Open main menu</span>
<svg className="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d={isOpen ? "M6 18L18 6M6 6l12 12" : "M4 6h16M4 12h16M4 18h16"} />
</svg>
</button>
</div>
</div>
</div>
{/* Mobile Menu Dropdown */}
<Transition
show={isOpen}
enter="transition ease-out duration-200 transform"
enterFrom="opacity-0 -translate-y-2"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150 transform"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 -translate-y-2"
>
<div className="md:hidden bg-gray-200 dark:bg-gray-700" id="mobile-menu">
<div className="px-2 pt-2 pb-3 space-y-1 sm:px-3">
<a href="#home" className="block px-3 py-2 rounded-md text-gray-800 dark:text-white hover:bg-purple-600">
Home
</a>
<a href="#features" className="block px-3 py-2 rounded-md text-gray-800 dark:text-white hover:bg-purple-600">
Features
</a>
<a href="#contact" className="block px-3 py-2 rounded-md text-gray-800 dark:text-white hover:bg-purple-600">
Contact
</a>
<a href="#get-started" className="block px-3 py-2 rounded-md bg-yellow-300 text-gray-800 text-center">
Get Started
</a>
</div>
</div>
</Transition>
</nav>
);
};
export default Navbar;

View File

@@ -1,215 +0,0 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Card from '@mui/material/Card';
import Chip from '@mui/material/Chip';
import CardActions from '@mui/material/CardActions';
import CardContent from '@mui/material/CardContent';
import Container from '@mui/material/Container';
import Divider from '@mui/material/Divider';
import Grid from '@mui/material/Grid';
import Typography from '@mui/material/Typography';
import AutoAwesomeIcon from '@mui/icons-material/AutoAwesome';
import CheckCircleRoundedIcon from '@mui/icons-material/CheckCircleRounded';
const tiers = [
{
title: 'Free',
price: '0',
description: [
'10 users included',
'2 GB of storage',
'Help center access',
'Email support',
],
buttonText: 'Sign up for free',
buttonVariant: 'outlined',
},
{
title: 'Professional',
subheader: 'Recommended',
price: '15',
description: [
'20 users included',
'10 GB of storage',
'Help center access',
'Priority email support',
'Dedicated team',
'Best deals',
],
buttonText: 'Start now',
buttonVariant: 'contained',
},
{
title: 'Enterprise',
price: '30',
description: [
'50 users included',
'30 GB of storage',
'Help center access',
'Phone & email support',
],
buttonText: 'Contact us',
buttonVariant: 'outlined',
},
];
export default function Pricing() {
return (
<Container
id="pricing"
sx={{
pt: { xs: 4, sm: 12 },
pb: { xs: 8, sm: 16 },
position: 'relative',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: { xs: 3, sm: 6 },
}}
>
<Box
sx={{
width: { sm: '100%', md: '60%' },
textAlign: { sm: 'left', md: 'center' },
}}
>
<Typography component="h2" variant="h4" color="text.primary">
Pricing
</Typography>
<Typography variant="body1" color="text.secondary">
Quickly build an effective pricing table for your potential customers with
this layout. <br />
It&apos;s built with default Material UI components with little
customization.
</Typography>
</Box>
<Grid container spacing={3} alignItems="center" justifyContent="center">
{tiers.map((tier) => (
<Grid
item
key={tier.title}
xs={12}
sm={tier.title === 'Enterprise' ? 12 : 6}
md={4}
>
<Card
sx={(theme) => ({
p: 2,
display: 'flex',
flexDirection: 'column',
gap: 4,
...(tier.title === 'Professional' && {
border: 'none',
boxShadow:
theme.palette.mode === 'light'
? `0 8px 12px hsla(210, 98%, 42%, 0.2)`
: `0 8px 12px hsla(0, 0%, 0%, 0.8)`,
background:
'radial-gradient(circle at 50% 0%, hsl(210, 98%, 35%), hsl(210, 100%, 16%))',
}),
})}
>
<CardContent>
<Box
sx={{
mb: 1,
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
gap: 2,
color: tier.title === 'Professional' ? 'grey.100' : '',
}}
>
<Typography component="h3" variant="h6">
{tier.title}
</Typography>
{tier.title === 'Professional' && (
<Chip
icon={<AutoAwesomeIcon />}
label={tier.subheader}
size="small"
sx={{
borderColor: 'hsla(220, 60%, 99%, 0.3)',
backgroundColor: 'hsla(220, 60%, 99%, 0.1)',
'& .MuiChip-label': {
color: 'hsl(0, 0%, 100%)',
},
'& .MuiChip-icon': {
color: 'primary.light',
},
}}
/>
)}
</Box>
<Box
sx={{
display: 'flex',
alignItems: 'baseline',
color: tier.title === 'Professional' ? 'grey.50' : undefined,
}}
>
<Typography component="h3" variant="h2">
${tier.price}
</Typography>
<Typography component="h3" variant="h6">
&nbsp; per month
</Typography>
</Box>
<Divider
sx={{
my: 2,
opacity: 0.8,
borderColor: 'divider',
}}
/>
{tier.description.map((line) => (
<Box
key={line}
sx={{
py: 1,
display: 'flex',
gap: 1.5,
alignItems: 'center',
}}
>
<CheckCircleRoundedIcon
sx={{
width: 20,
color:
tier.title === 'Professional'
? 'primary.light'
: 'primary.main',
}}
/>
<Typography
variant="subtitle2"
component={'span'}
sx={{
color: tier.title === 'Professional' ? 'grey.50' : undefined,
}}
>
{line}
</Typography>
</Box>
))}
</CardContent>
<CardActions>
<Button
fullWidth
variant={tier.buttonVariant as 'outlined' | 'contained'}
component="a"
href="/material-ui/getting-started/templates/checkout/"
target="_blank"
>
{tier.buttonText}
</Button>
</CardActions>
</Card>
</Grid>
))}
</Grid>
</Container>
);
}

View File

@@ -1,53 +0,0 @@
import * as React from 'react';
import SvgIcon from '@mui/material/SvgIcon';
export default function SitemarkIcon() {
return (
<SvgIcon sx={{ height: 21, width: 100, mr: 2 }}>
<svg
width={86}
height={19}
viewBox="0 0 86 19"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="#B4C0D3"
d="m.787 12.567 6.055-2.675 3.485 2.006.704 6.583-4.295-.035.634-4.577-.74-.422-3.625 2.817-2.218-3.697Z"
/>
<path
fill="#00D3AB"
d="m10.714 11.616 5.352 3.908 2.112-3.767-4.295-1.725v-.845l4.295-1.76-2.112-3.732-5.352 3.908v4.013Z"
/>
<path
fill="#4876EF"
d="m10.327 7.286.704-6.583-4.295.07.634 4.577-.74.422-3.66-2.816L.786 6.617l6.055 2.676 3.485-2.007Z"
/>
<path
fill="#4876EE"
d="M32.507 8.804v6.167h2.312v-7.86h-3.366v1.693h1.054ZM32.435 6.006c.212.22.535.33.968.33.434 0 .751-.11.953-.33.213-.23.318-.516.318-.86 0-.354-.105-.641-.318-.86-.202-.23-.52-.345-.953-.345-.433 0-.756.115-.968.344-.202.22-.303.507-.303.86 0 .345.101.632.303.861ZM24.46 14.799c.655.296 1.46.444 2.413.444.896 0 1.667-.139 2.312-.416.645-.277 1.141-.664 1.488-1.162.357-.506.535-1.094.535-1.764 0-.65-.169-1.2-.506-1.649-.328-.459-.785-.818-1.373-1.076-.587-.267-1.266-.435-2.037-.502l-.809-.071c-.481-.039-.828-.168-1.04-.388a1.08 1.08 0 0 1-.318-.774c0-.23.058-.44.173-.631.116-.201.29-.359.52-.474.241-.114.535-.172.882-.172.366 0 .67.067.91.201.053.029.104.059.15.09l.012.009.052.037c.146.111.263.243.35.395.125.21.188.444.188.703h2.311c0-.689-.159-1.286-.476-1.793-.318-.516-.776-.913-1.373-1.19-.588-.287-1.296-.43-2.124-.43-.79 0-1.474.133-2.052.4a3.131 3.131 0 0 0-1.358 1.12c-.318.487-.477 1.066-.477 1.735 0 .927.314 1.673.94 2.237.626.564 1.464.89 2.514.976l.794.071c.645.058 1.113.187 1.401.388a.899.899 0 0 1 .434.788 1.181 1.181 0 0 1-.231.717c-.154.201-.38.36-.68.474-.298.115-.669.172-1.112.172-.49 0-.89-.067-1.199-.2-.308-.144-.539-.33-.694-.56a1.375 1.375 0 0 1-.216-.746h-2.297c0 .679.168 1.281.505 1.807.337.517.834.928 1.489 1.234ZM39.977 15.07c-.8 0-1.445-.095-1.936-.286a2.03 2.03 0 0 1-1.084-.99c-.221-.469-.332-1.1-.332-1.893V8.789h-1.2V7.11h1.2V4.988h2.153V7.11h2.312V8.79h-2.312v3.198c0 .373.096.66.289.86.202.192.486.287.852.287h1.17v1.937h-1.112Z"
/>
<path
fill="#4876EE"
fillRule="evenodd"
d="M43.873 14.899c.52.23 1.117.344 1.791.344.665 0 1.252-.115 1.763-.344.51-.23.934-.55 1.271-.96.337-.412.564-.88.679-1.407h-2.124c-.096.24-.279.44-.549.603-.27.162-.616.244-1.04.244-.262 0-.497-.031-.704-.093a1.572 1.572 0 0 1-.423-.194 1.662 1.662 0 0 1-.636-.803 3.159 3.159 0 0 1-.163-.645h5.784v-.775a4.28 4.28 0 0 0-.463-1.98 3.686 3.686 0 0 0-1.343-1.477c-.578-.382-1.291-.574-2.139-.574-.645 0-1.223.115-1.733.345-.501.22-.92.52-1.257.903a4.178 4.178 0 0 0-.78 1.305c-.174.478-.26.98-.26 1.506v.287c0 .507.086 1.004.26 1.492.183.478.443.913.78 1.305.347.382.775.688 1.286.918Zm-.094-4.674.02-.09a2.507 2.507 0 0 1 .117-.356c.145-.354.356-.622.636-.804.104-.067.217-.123.339-.165.204-.071.433-.107.686-.107.395 0 .723.09.983.272.27.173.472.426.607.76a2.487 2.487 0 0 1 .16.603h-3.57c.006-.038.013-.076.022-.113Z"
clipRule="evenodd"
/>
<path
fill="#4876EE"
d="M50.476 14.97V7.112h1.835v1.98a4.54 4.54 0 0 1 .173-.603c.202-.536.506-.937.91-1.205.405-.277.9-.416 1.488-.416h.101c.598 0 1.094.139 1.489.416.404.268.707.67.91 1.205l.016.04.013.037.028-.077c.212-.536.52-.937.925-1.205.405-.277.901-.416 1.489-.416h.1c.598 0 1.098.139 1.503.416.414.268.727.67.94 1.205.211.535.317 1.205.317 2.008v4.475h-2.312v-4.604c0-.43-.115-.78-.346-1.047-.222-.268-.54-.402-.954-.402-.414 0-.742.139-.982.416-.241.268-.362.626-.362 1.076v4.56h-2.326v-4.603c0-.43-.115-.78-.346-1.047-.222-.268-.535-.402-.94-.402-.423 0-.756.139-.996.416-.241.268-.362.626-.362 1.076v4.56h-2.311Z"
/>
<path
fill="#4876EE"
fillRule="evenodd"
d="M68.888 13.456v1.515h1.834v-4.82c0-.726-.144-1.319-.433-1.778-.289-.468-.712-.817-1.271-1.047-.549-.23-1.228-.344-2.037-.344a27.76 27.76 0 0 0-.896.014c-.318.01-.626.024-.924.043l-.229.016a36.79 36.79 0 0 0-.552.042v1.936a81.998 81.998 0 0 1 1.733-.09 37.806 37.806 0 0 1 1.171-.025c.424 0 .732.1.925.301.193.201.289.502.289.904v.029h-1.43c-.704 0-1.325.09-1.864.272-.54.172-.959.445-1.257.818-.299.363-.448.832-.448 1.405 0 .526.12.98.361 1.363.24.373.573.66.997.86.433.201.934.302 1.502.302.55 0 1.012-.1 1.388-.302.385-.2.683-.487.895-.86a2.443 2.443 0 0 0 .228-.498l.018-.056Zm-.39-1.397v-.63h-1.445c-.405 0-.718.1-.939.3-.212.192-.318.455-.318.79 0 .157.026.3.08.429a.99.99 0 0 0 .238.345c.221.191.534.287.939.287a2.125 2.125 0 0 0 .394-.038c.106-.021.206-.052.3-.092.212-.095.385-.253.52-.473.135-.22.212-.526.23-.918Z"
clipRule="evenodd"
/>
<path
fill="#4876EE"
d="M72.106 14.97V7.11h1.835v2.595c.088-.74.31-1.338.665-1.791.481-.603 1.174-.904 2.08-.904h.303v1.98h-.578c-.635 0-1.127.172-1.473.516-.347.334-.52.822-.52 1.463v4.001h-2.312ZM79.92 11.298h.767l2.499 3.672h2.6l-3.169-4.51 2.606-3.35h-2.427l-2.875 3.737V4.5h-2.312v10.47h2.312v-3.672Z"
/>
</svg>
</SvgIcon>
);
}

View File

@@ -1,154 +0,0 @@
import * as React from 'react';
import Card from '@mui/material/Card';
import CardHeader from '@mui/material/CardHeader';
import CardContent from '@mui/material/CardContent';
import Avatar from '@mui/material/Avatar';
import Typography from '@mui/material/Typography';
import Box from '@mui/material/Box';
import Container from '@mui/material/Container';
import Grid from '@mui/material/Grid';
import { useTheme } from '@mui/system';
const userTestimonials = [
{
avatar: <Avatar alt="Remy Sharp" src="/static/images/avatar/1.jpg" />,
name: 'Remy Sharp',
occupation: 'Senior Engineer',
testimonial:
"I absolutely love how versatile this product is! Whether I'm tackling work projects or indulging in my favorite hobbies, it seamlessly adapts to my changing needs. Its intuitive design has truly enhanced my daily routine, making tasks more efficient and enjoyable.",
},
{
avatar: <Avatar alt="Travis Howard" src="/static/images/avatar/2.jpg" />,
name: 'Travis Howard',
occupation: 'Lead Product Designer',
testimonial:
"One of the standout features of this product is the exceptional customer support. In my experience, the team behind this product has been quick to respond and incredibly helpful. It's reassuring to know that they stand firmly behind their product.",
},
{
avatar: <Avatar alt="Cindy Baker" src="/static/images/avatar/3.jpg" />,
name: 'Cindy Baker',
occupation: 'CTO',
testimonial:
'The level of simplicity and user-friendliness in this product has significantly simplified my life. I appreciate the creators for delivering a solution that not only meets but exceeds user expectations.',
},
{
avatar: <Avatar alt="Remy Sharp" src="/static/images/avatar/4.jpg" />,
name: 'Julia Stewart',
occupation: 'Senior Engineer',
testimonial:
"I appreciate the attention to detail in the design of this product. The small touches make a big difference, and it's evident that the creators focused on delivering a premium experience.",
},
{
avatar: <Avatar alt="Travis Howard" src="/static/images/avatar/5.jpg" />,
name: 'John Smith',
occupation: 'Product Designer',
testimonial:
"I've tried other similar products, but this one stands out for its innovative features. It's clear that the makers put a lot of thought into creating a solution that truly addresses user needs.",
},
{
avatar: <Avatar alt="Cindy Baker" src="/static/images/avatar/6.jpg" />,
name: 'Daniel Wolf',
occupation: 'CDO',
testimonial:
"The quality of this product exceeded my expectations. It's durable, well-designed, and built to last. Definitely worth the investment!",
},
];
const whiteLogos = [
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/6560628e8573c43893fe0ace_Sydney-white.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/655f4d520d0517ae8e8ddf13_Bern-white.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/655f46794c159024c1af6d44_Montreal-white.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/61f12e891fa22f89efd7477a_TerraLight.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/6560a09d1f6337b1dfed14ab_colorado-white.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/655f5caa77bf7d69fb78792e_Ankara-white.svg',
];
const darkLogos = [
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/6560628889c3bdf1129952dc_Sydney-black.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/655f4d4d8b829a89976a419c_Bern-black.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/655f467502f091ccb929529d_Montreal-black.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/61f12e911fa22f2203d7514c_TerraDark.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/6560a0990f3717787fd49245_colorado-black.svg',
'https://assets-global.website-files.com/61ed56ae9da9fd7e0ef0a967/655f5ca4e548b0deb1041c33_Ankara-black.svg',
];
const logoStyle = {
width: '64px',
opacity: 0.3,
};
export default function Testimonials() {
const theme = useTheme();
const logos = theme.palette.mode === 'light' ? darkLogos : whiteLogos;
return (
<Container
id="testimonials"
sx={{
pt: { xs: 4, sm: 12 },
pb: { xs: 8, sm: 16 },
position: 'relative',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: { xs: 3, sm: 6 },
}}
>
<Box
sx={{
width: { sm: '100%', md: '60%' },
textAlign: { sm: 'left', md: 'center' },
}}
>
<Typography component="h2" variant="h4" color="text.primary">
Testimonials
</Typography>
<Typography variant="body1" color="text.secondary">
See what our customers love about our products. Discover how we excel in
efficiency, durability, and satisfaction. Join us for quality, innovation,
and reliable support.
</Typography>
</Box>
<Grid container spacing={2}>
{userTestimonials.map((testimonial, index) => (
<Grid item xs={12} sm={6} md={4} key={index} sx={{ display: 'flex' }}>
<Card
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
flexGrow: 1,
p: 1,
}}
>
<CardContent>
<Typography variant="body2" color="text.secondary">
{testimonial.testimonial}
</Typography>
</CardContent>
<Box
sx={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
pr: 2,
}}
>
<CardHeader
avatar={testimonial.avatar}
title={testimonial.name}
subheader={testimonial.occupation}
/>
<img
src={logos[index]}
alt={`Logo ${index + 1}`}
style={logoStyle}
/>
</Box>
</Card>
</Grid>
))}
</Grid>
</Container>
);
}

View File

@@ -1,31 +0,0 @@
import * as React from 'react';
import { PaletteMode } from '@mui/material';
import IconButton from '@mui/material/IconButton';
import WbSunnyRoundedIcon from '@mui/icons-material/WbSunnyRounded';
import ModeNightRoundedIcon from '@mui/icons-material/ModeNightRounded';
interface ToggleColorModeProps {
mode: PaletteMode;
toggleColorMode: () => void;
}
export default function ToggleColorMode({
mode,
toggleColorMode,
}: ToggleColorModeProps) {
return (
<IconButton
onClick={toggleColorMode}
color="primary"
aria-label="Theme toggle button"
size="small"
>
{mode === 'dark' ? (
<WbSunnyRoundedIcon fontSize="small" />
) : (
<ModeNightRoundedIcon fontSize="small" />
)}
</IconButton>
);
}

View File

@@ -0,0 +1,132 @@
import { useModal } from "../../hooks/useModal";
import { Modal } from "../ui/modal";
import Button from "../ui/button/Button";
import Input from "../form/input/InputField";
import Label from "../form/Label";
export default function UserAddressCard() {
const { isOpen, openModal, closeModal } = useModal();
const handleSave = () => {
// Handle save logic here
console.log("Saving changes...");
closeModal();
};
return (
<>
<div className="p-5 border border-gray-200 rounded-2xl dark:border-gray-800 lg:p-6">
<div className="flex flex-col gap-6 lg:flex-row lg:items-start lg:justify-between">
<div>
<h4 className="text-lg font-semibold text-gray-800 dark:text-white/90 lg:mb-6">
Address
</h4>
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2 lg:gap-7 2xl:gap-x-32">
<div>
<p className="mb-2 text-xs leading-normal text-gray-500 dark:text-gray-400">
Country
</p>
<p className="text-sm font-medium text-gray-800 dark:text-white/90">
United States
</p>
</div>
<div>
<p className="mb-2 text-xs leading-normal text-gray-500 dark:text-gray-400">
City/State
</p>
<p className="text-sm font-medium text-gray-800 dark:text-white/90">
Phoenix, Arizona, United States
</p>
</div>
<div>
<p className="mb-2 text-xs leading-normal text-gray-500 dark:text-gray-400">
Postal Code
</p>
<p className="text-sm font-medium text-gray-800 dark:text-white/90">
ERT 2489
</p>
</div>
<div>
<p className="mb-2 text-xs leading-normal text-gray-500 dark:text-gray-400">
TAX ID
</p>
<p className="text-sm font-medium text-gray-800 dark:text-white/90">
AS4568384
</p>
</div>
</div>
</div>
<button
onClick={openModal}
className="flex w-full items-center justify-center gap-2 rounded-full border border-gray-300 bg-white px-4 py-3 text-sm font-medium text-gray-700 shadow-theme-xs hover:bg-gray-50 hover:text-gray-800 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-white/[0.03] dark:hover:text-gray-200 lg:inline-flex lg:w-auto"
>
<svg
className="fill-current"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M15.0911 2.78206C14.2125 1.90338 12.7878 1.90338 11.9092 2.78206L4.57524 10.116C4.26682 10.4244 4.0547 10.8158 3.96468 11.2426L3.31231 14.3352C3.25997 14.5833 3.33653 14.841 3.51583 15.0203C3.69512 15.1996 3.95286 15.2761 4.20096 15.2238L7.29355 14.5714C7.72031 14.4814 8.11172 14.2693 8.42013 13.9609L15.7541 6.62695C16.6327 5.74827 16.6327 4.32365 15.7541 3.44497L15.0911 2.78206ZM12.9698 3.84272C13.2627 3.54982 13.7376 3.54982 14.0305 3.84272L14.6934 4.50563C14.9863 4.79852 14.9863 5.2734 14.6934 5.56629L14.044 6.21573L12.3204 4.49215L12.9698 3.84272ZM11.2597 5.55281L5.6359 11.1766C5.53309 11.2794 5.46238 11.4099 5.43238 11.5522L5.01758 13.5185L6.98394 13.1037C7.1262 13.0737 7.25666 13.003 7.35947 12.9002L12.9833 7.27639L11.2597 5.55281Z"
fill=""
/>
</svg>
Edit
</button>
</div>
</div>
<Modal isOpen={isOpen} onClose={closeModal} className="max-w-[700px] m-4">
<div className="relative w-full p-4 overflow-y-auto bg-white no-scrollbar rounded-3xl dark:bg-gray-900 lg:p-11">
<div className="px-2 pr-14">
<h4 className="mb-2 text-2xl font-semibold text-gray-800 dark:text-white/90">
Edit Address
</h4>
<p className="mb-6 text-sm text-gray-500 dark:text-gray-400 lg:mb-7">
Update your details to keep your profile up-to-date.
</p>
</div>
<form className="flex flex-col">
<div className="px-2 overflow-y-auto custom-scrollbar">
<div className="grid grid-cols-1 gap-x-6 gap-y-5 lg:grid-cols-2">
<div>
<Label>Country</Label>
<Input type="text" value="United Kingdom" />
</div>
<div>
<Label>City/State</Label>
<Input type="text" value="Leeds, East London" />
</div>
<div>
<Label>Postal Code</Label>
<Input type="text" value="ERT 2489" />
</div>
<div>
<Label>TAX ID</Label>
<Input type="text" value="AS4568384" />
</div>
</div>
</div>
<div className="flex items-center gap-3 px-2 mt-6 lg:justify-end">
<Button size="sm" variant="outline" onClick={closeModal}>
Close
</Button>
<Button size="sm" onClick={handleSave}>
Save Changes
</Button>
</div>
</form>
</div>
</Modal>
</>
);
}

View File

@@ -0,0 +1,185 @@
import React from "react";
import { useModal } from "../../hooks/useModal";
import { Modal } from "../ui/modal";
import Button from "../ui/button/Button";
import Input from "../form/input/InputField";
import Label from "../form/Label";
export default function UserInfoCard() {
const { isOpen, openModal, closeModal } = useModal();
const handleSave = () => {
// Handle save logic here
console.log("Saving changes...");
closeModal();
};
return (
<div className="p-5 border border-gray-200 rounded-2xl dark:border-gray-800 lg:p-6">
<div className="flex flex-col gap-6 lg:flex-row lg:items-start lg:justify-between">
<div>
<h4 className="text-lg font-semibold text-gray-800 dark:text-white/90 lg:mb-6">
Personal Information
</h4>
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2 lg:gap-7 2xl:gap-x-32">
<div>
<p className="mb-2 text-xs leading-normal text-gray-500 dark:text-gray-400">
First Name
</p>
<p className="text-sm font-medium text-gray-800 dark:text-white/90">
Musharof
</p>
</div>
<div>
<p className="mb-2 text-xs leading-normal text-gray-500 dark:text-gray-400">
Last Name
</p>
<p className="text-sm font-medium text-gray-800 dark:text-white/90">
Chowdhury
</p>
</div>
<div>
<p className="mb-2 text-xs leading-normal text-gray-500 dark:text-gray-400">
Email address
</p>
<p className="text-sm font-medium text-gray-800 dark:text-white/90">
randomuser@pimjo.com
</p>
</div>
<div>
<p className="mb-2 text-xs leading-normal text-gray-500 dark:text-gray-400">
Phone
</p>
<p className="text-sm font-medium text-gray-800 dark:text-white/90">
+09 363 398 46
</p>
</div>
<div>
<p className="mb-2 text-xs leading-normal text-gray-500 dark:text-gray-400">
Bio
</p>
<p className="text-sm font-medium text-gray-800 dark:text-white/90">
Team Manager
</p>
</div>
</div>
</div>
<button
onClick={openModal}
className="flex w-full items-center justify-center gap-2 rounded-full border border-gray-300 bg-white px-4 py-3 text-sm font-medium text-gray-700 shadow-theme-xs hover:bg-gray-50 hover:text-gray-800 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-white/[0.03] dark:hover:text-gray-200 lg:inline-flex lg:w-auto"
>
<svg
className="fill-current"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M15.0911 2.78206C14.2125 1.90338 12.7878 1.90338 11.9092 2.78206L4.57524 10.116C4.26682 10.4244 4.0547 10.8158 3.96468 11.2426L3.31231 14.3352C3.25997 14.5833 3.33653 14.841 3.51583 15.0203C3.69512 15.1996 3.95286 15.2761 4.20096 15.2238L7.29355 14.5714C7.72031 14.4814 8.11172 14.2693 8.42013 13.9609L15.7541 6.62695C16.6327 5.74827 16.6327 4.32365 15.7541 3.44497L15.0911 2.78206ZM12.9698 3.84272C13.2627 3.54982 13.7376 3.54982 14.0305 3.84272L14.6934 4.50563C14.9863 4.79852 14.9863 5.2734 14.6934 5.56629L14.044 6.21573L12.3204 4.49215L12.9698 3.84272ZM11.2597 5.55281L5.6359 11.1766C5.53309 11.2794 5.46238 11.4099 5.43238 11.5522L5.01758 13.5185L6.98394 13.1037C7.1262 13.0737 7.25666 13.003 7.35947 12.9002L12.9833 7.27639L11.2597 5.55281Z"
fill=""
/>
</svg>
Edit
</button>
</div>
<Modal isOpen={isOpen} onClose={closeModal} className="max-w-[700px] m-4">
<div className="no-scrollbar relative w-full max-w-[700px] overflow-y-auto rounded-3xl bg-white p-4 dark:bg-gray-900 lg:p-11">
<div className="px-2 pr-14">
<h4 className="mb-2 text-2xl font-semibold text-gray-800 dark:text-white/90">
Edit Personal Information
</h4>
<p className="mb-6 text-sm text-gray-500 dark:text-gray-400 lg:mb-7">
Update your details to keep your profile up-to-date.
</p>
</div>
<form className="flex flex-col">
<div className="custom-scrollbar h-[450px] overflow-y-auto px-2 pb-3">
<div>
<h5 className="mb-5 text-lg font-medium text-gray-800 dark:text-white/90 lg:mb-6">
Social Links
</h5>
<div className="grid grid-cols-1 gap-x-6 gap-y-5 lg:grid-cols-2">
<div>
<Label>Facebook</Label>
<Input
type="text"
value="https://www.facebook.com/PimjoHQ"
/>
</div>
<div>
<Label>X.com</Label>
<Input type="text" value="https://x.com/PimjoHQ" />
</div>
<div>
<Label>Linkedin</Label>
<Input
type="text"
value="https://www.linkedin.com/company/pimjo"
/>
</div>
<div>
<Label>Instagram</Label>
<Input type="text" value="https://instagram.com/PimjoHQ" />
</div>
</div>
</div>
<div className="mt-7">
<h5 className="mb-5 text-lg font-medium text-gray-800 dark:text-white/90 lg:mb-6">
Personal Information
</h5>
<div className="grid grid-cols-1 gap-x-6 gap-y-5 lg:grid-cols-2">
<div className="col-span-2 lg:col-span-1">
<Label>First Name</Label>
<Input type="text" value="Emirhan" />
</div>
<div className="col-span-2 lg:col-span-1">
<Label>Last Name</Label>
<Input type="text" value="Boruch" />
</div>
<div className="col-span-2 lg:col-span-1">
<Label>Email Address</Label>
<Input type="text" value="emirhanboruch55@gmail.com" />
</div>
<div className="col-span-2 lg:col-span-1">
<Label>Phone</Label>
<Input type="text" value="+09 363 398 46" />
</div>
<div className="col-span-2">
<Label>Bio</Label>
<Input type="text" value="Team Manager" />
</div>
</div>
</div>
</div>
<div className="flex items-center gap-3 px-2 mt-6 lg:justify-end">
<Button size="sm" variant="outline" onClick={closeModal}>
Close
</Button>
<Button size="sm" onClick={handleSave}>
Save Changes
</Button>
</div>
</form>
</div>
</Modal>
</div>
);
}

View File

@@ -0,0 +1,217 @@
import React from "react";
import { useModal } from "../../hooks/useModal";
import { Modal } from "../ui/modal";
import Button from "../ui/button/Button";
import Input from "../form/input/InputField";
import Label from "../form/Label";
export default function UserMetaCard() {
const { isOpen, openModal, closeModal } = useModal();
const handleSave = () => {
// Handle save logic here
console.log("Saving changes...");
closeModal();
};
return (
<>
<div className="p-5 border border-gray-200 rounded-2xl dark:border-gray-800 lg:p-6">
<div className="flex flex-col gap-5 xl:flex-row xl:items-center xl:justify-between">
<div className="flex flex-col items-center w-full gap-6 xl:flex-row">
<div className="w-20 h-20 overflow-hidden border border-gray-200 rounded-full dark:border-gray-800">
<img src="/images/user/owner.jpg" alt="user" />
</div>
<div className="order-3 xl:order-2">
<h4 className="mb-2 text-lg font-semibold text-center text-gray-800 dark:text-white/90 xl:text-left">
Musharof Chowdhury
</h4>
<div className="flex flex-col items-center gap-1 text-center xl:flex-row xl:gap-3 xl:text-left">
<p className="text-sm text-gray-500 dark:text-gray-400">
Team Manager
</p>
<div className="hidden h-3.5 w-px bg-gray-300 dark:bg-gray-700 xl:block"></div>
<p className="text-sm text-gray-500 dark:text-gray-400">
Arizona, United States
</p>
</div>
</div>
<div className="flex items-center order-2 gap-2 grow xl:order-3 xl:justify-end">
<button className="flex h-11 w-11 items-center justify-center gap-2 rounded-full border border-gray-300 bg-white text-sm font-medium text-gray-700 shadow-theme-xs hover:bg-gray-50 hover:text-gray-800 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-white/[0.03] dark:hover:text-gray-200">
<svg
className="fill-current"
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M11.6666 11.2503H13.7499L14.5833 7.91699H11.6666V6.25033C11.6666 5.39251 11.6666 4.58366 13.3333 4.58366H14.5833V1.78374C14.3118 1.7477 13.2858 1.66699 12.2023 1.66699C9.94025 1.66699 8.33325 3.04771 8.33325 5.58342V7.91699H5.83325V11.2503H8.33325V18.3337H11.6666V11.2503Z"
fill=""
/>
</svg>
</button>
<button className="flex h-11 w-11 items-center justify-center gap-2 rounded-full border border-gray-300 bg-white text-sm font-medium text-gray-700 shadow-theme-xs hover:bg-gray-50 hover:text-gray-800 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-white/[0.03] dark:hover:text-gray-200">
<svg
className="fill-current"
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M15.1708 1.875H17.9274L11.9049 8.75833L18.9899 18.125H13.4424L9.09742 12.4442L4.12578 18.125H1.36745L7.80912 10.7625L1.01245 1.875H6.70078L10.6283 7.0675L15.1708 1.875ZM14.2033 16.475H15.7308L5.87078 3.43833H4.23162L14.2033 16.475Z"
fill=""
/>
</svg>
</button>
<button className="flex h-11 w-11 items-center justify-center gap-2 rounded-full border border-gray-300 bg-white text-sm font-medium text-gray-700 shadow-theme-xs hover:bg-gray-50 hover:text-gray-800 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-white/[0.03] dark:hover:text-gray-200">
<svg
className="fill-current"
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5.78381 4.16645C5.78351 4.84504 5.37181 5.45569 4.74286 5.71045C4.11391 5.96521 3.39331 5.81321 2.92083 5.32613C2.44836 4.83904 2.31837 4.11413 2.59216 3.49323C2.86596 2.87233 3.48886 2.47942 4.16715 2.49978C5.06804 2.52682 5.78422 3.26515 5.78381 4.16645ZM5.83381 7.06645H2.50048V17.4998H5.83381V7.06645ZM11.1005 7.06645H7.78381V17.4998H11.0672V12.0248C11.0672 8.97475 15.0422 8.69142 15.0422 12.0248V17.4998H18.3338V10.8914C18.3338 5.74978 12.4505 5.94145 11.0672 8.46642L11.1005 7.06645Z"
fill=""
/>
</svg>
</button>
<button className="flex h-11 w-11 items-center justify-center gap-2 rounded-full border border-gray-300 bg-white text-sm font-medium text-gray-700 shadow-theme-xs hover:bg-gray-50 hover:text-gray-800 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-white/[0.03] dark:hover:text-gray-200">
<svg
className="fill-current"
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10.8567 1.66699C11.7946 1.66854 12.2698 1.67351 12.6805 1.68573L12.8422 1.69102C13.0291 1.69766 13.2134 1.70599 13.4357 1.71641C14.3224 1.75738 14.9273 1.89766 15.4586 2.10391C16.0078 2.31572 16.4717 2.60183 16.9349 3.06503C17.3974 3.52822 17.6836 3.99349 17.8961 4.54141C18.1016 5.07197 18.2419 5.67753 18.2836 6.56433C18.2935 6.78655 18.3015 6.97088 18.3081 7.15775L18.3133 7.31949C18.3255 7.73011 18.3311 8.20543 18.3328 9.1433L18.3335 9.76463C18.3336 9.84055 18.3336 9.91888 18.3336 9.99972L18.3335 10.2348L18.333 10.8562C18.3314 11.794 18.3265 12.2694 18.3142 12.68L18.3089 12.8417C18.3023 13.0286 18.294 13.213 18.2836 13.4351C18.2426 14.322 18.1016 14.9268 17.8961 15.458C17.6842 16.0074 17.3974 16.4713 16.9349 16.9345C16.4717 17.397 16.0057 17.6831 15.4586 17.8955C14.9273 18.1011 14.3224 18.2414 13.4357 18.2831C13.2134 18.293 13.0291 18.3011 12.8422 18.3076L12.6805 18.3128C12.2698 18.3251 11.7946 18.3306 10.8567 18.3324L10.2353 18.333C10.1594 18.333 10.0811 18.333 10.0002 18.333H9.76516L9.14375 18.3325C8.20591 18.331 7.7306 18.326 7.31997 18.3137L7.15824 18.3085C6.97136 18.3018 6.78703 18.2935 6.56481 18.2831C5.67801 18.2421 5.07384 18.1011 4.5419 17.8955C3.99328 17.6838 3.5287 17.397 3.06551 16.9345C2.60231 16.4713 2.3169 16.0053 2.1044 15.458C1.89815 14.9268 1.75856 14.322 1.7169 13.4351C1.707 13.213 1.69892 13.0286 1.69238 12.8417L1.68714 12.68C1.67495 12.2694 1.66939 11.794 1.66759 10.8562L1.66748 9.1433C1.66903 8.20543 1.67399 7.73011 1.68621 7.31949L1.69151 7.15775C1.69815 6.97088 1.70648 6.78655 1.7169 6.56433C1.75786 5.67683 1.89815 5.07266 2.1044 4.54141C2.3162 3.9928 2.60231 3.52822 3.06551 3.06503C3.5287 2.60183 3.99398 2.31641 4.5419 2.10391C5.07315 1.89766 5.67731 1.75808 6.56481 1.71641C6.78703 1.70652 6.97136 1.69844 7.15824 1.6919L7.31997 1.68666C7.7306 1.67446 8.20591 1.6689 9.14375 1.6671L10.8567 1.66699ZM10.0002 5.83308C7.69781 5.83308 5.83356 7.69935 5.83356 9.99972C5.83356 12.3021 7.69984 14.1664 10.0002 14.1664C12.3027 14.1664 14.1669 12.3001 14.1669 9.99972C14.1669 7.69732 12.3006 5.83308 10.0002 5.83308ZM10.0002 7.49974C11.381 7.49974 12.5002 8.61863 12.5002 9.99972C12.5002 11.3805 11.3813 12.4997 10.0002 12.4997C8.6195 12.4997 7.50023 11.3809 7.50023 9.99972C7.50023 8.61897 8.61908 7.49974 10.0002 7.49974ZM14.3752 4.58308C13.8008 4.58308 13.3336 5.04967 13.3336 5.62403C13.3336 6.19841 13.8002 6.66572 14.3752 6.66572C14.9496 6.66572 15.4169 6.19913 15.4169 5.62403C15.4169 5.04967 14.9488 4.58236 14.3752 4.58308Z"
fill=""
/>
</svg>
</button>
</div>
</div>
<button
onClick={openModal}
className="flex w-full items-center justify-center gap-2 rounded-full border border-gray-300 bg-white px-4 py-3 text-sm font-medium text-gray-700 shadow-theme-xs hover:bg-gray-50 hover:text-gray-800 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-white/[0.03] dark:hover:text-gray-200 lg:inline-flex lg:w-auto"
>
<svg
className="fill-current"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M15.0911 2.78206C14.2125 1.90338 12.7878 1.90338 11.9092 2.78206L4.57524 10.116C4.26682 10.4244 4.0547 10.8158 3.96468 11.2426L3.31231 14.3352C3.25997 14.5833 3.33653 14.841 3.51583 15.0203C3.69512 15.1996 3.95286 15.2761 4.20096 15.2238L7.29355 14.5714C7.72031 14.4814 8.11172 14.2693 8.42013 13.9609L15.7541 6.62695C16.6327 5.74827 16.6327 4.32365 15.7541 3.44497L15.0911 2.78206ZM12.9698 3.84272C13.2627 3.54982 13.7376 3.54982 14.0305 3.84272L14.6934 4.50563C14.9863 4.79852 14.9863 5.2734 14.6934 5.56629L14.044 6.21573L12.3204 4.49215L12.9698 3.84272ZM11.2597 5.55281L5.6359 11.1766C5.53309 11.2794 5.46238 11.4099 5.43238 11.5522L5.01758 13.5185L6.98394 13.1037C7.1262 13.0737 7.25666 13.003 7.35947 12.9002L12.9833 7.27639L11.2597 5.55281Z"
fill=""
/>
</svg>
Edit
</button>
</div>
</div>
<Modal isOpen={isOpen} onClose={closeModal} className="max-w-[700px] m-4">
<div className="no-scrollbar relative w-full max-w-[700px] overflow-y-auto rounded-3xl bg-white p-4 dark:bg-gray-900 lg:p-11">
<div className="px-2 pr-14">
<h4 className="mb-2 text-2xl font-semibold text-gray-800 dark:text-white/90">
Edit Personal Information
</h4>
<p className="mb-6 text-sm text-gray-500 dark:text-gray-400 lg:mb-7">
Update your details to keep your profile up-to-date.
</p>
</div>
<form className="flex flex-col">
<div className="custom-scrollbar h-[450px] pb-3 overflow-y-auto px-2">
<div>
<h5 className="mb-5 text-lg font-medium text-gray-800 dark:text-white/90 lg:mb-6">
Social Links
</h5>
<div className="grid grid-cols-1 gap-x-6 gap-y-5 lg:grid-cols-2">
<div>
<Label>Facebook</Label>
<Input
type="text"
value="https://www.facebook.com/PimjoHQ"
/>
</div>
<div>
<Label>X.com</Label>
<Input type="text" value="https://x.com/PimjoHQ" />
</div>
<div>
<Label>Linkedin</Label>
<Input
type="text"
value="https://www.linkedin.com/company/pimjo"
/>
</div>
<div>
<Label>Instagram</Label>
<Input type="text" value="https://instagram.com/PimjoHQ" />
</div>
</div>
</div>
<div className="mt-7">
<h5 className="mb-5 text-lg font-medium text-gray-800 dark:text-white/90 lg:mb-6">
Personal Information
</h5>
<div className="grid grid-cols-1 gap-x-6 gap-y-5 lg:grid-cols-2">
<div className="col-span-2 lg:col-span-1">
<Label>First Name</Label>
<Input type="text" value="Musharof" />
</div>
<div className="col-span-2 lg:col-span-1">
<Label>Last Name</Label>
<Input type="text" value="Chowdhury" />
</div>
<div className="col-span-2 lg:col-span-1">
<Label>Email Address</Label>
<Input type="text" value="randomuser@pimjo.com" />
</div>
<div className="col-span-2 lg:col-span-1">
<Label>Phone</Label>
<Input type="text" value="+09 363 398 46" />
</div>
<div className="col-span-2">
<Label>Bio</Label>
<Input type="text" value="Team Manager" />
</div>
</div>
</div>
</div>
<div className="flex items-center gap-3 px-2 mt-6 lg:justify-end">
<Button size="sm" variant="outline" onClick={closeModal}>
Close
</Button>
<Button size="sm" onClick={handleSave}>
Save Changes
</Button>
</div>
</form>
</div>
</Modal>
</>
);
}

View File

@@ -0,0 +1,98 @@
import React from "react";
import Chart from "react-apexcharts";
import { ApexOptions } from "apexcharts";
export default function BarChartOne() {
const options: ApexOptions = {
colors: ["#465fff"],
chart: {
fontFamily: "Outfit, sans-serif",
type: "bar",
height: 180,
toolbar: {
show: false,
},
},
plotOptions: {
bar: {
horizontal: false,
columnWidth: "39%",
borderRadius: 5,
borderRadiusApplication: "end",
},
},
dataLabels: {
enabled: false,
},
stroke: {
show: true,
width: 4,
colors: ["transparent"],
},
xaxis: {
categories: [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
],
axisBorder: {
show: false,
},
axisTicks: {
show: false,
},
},
legend: {
show: true,
position: "top",
horizontalAlign: "left",
fontFamily: "Outfit",
},
yaxis: {
title: {
text: undefined,
},
},
grid: {
yaxis: {
lines: {
show: true,
},
},
},
fill: {
opacity: 1,
},
tooltip: {
x: {
show: false,
},
y: {
formatter: (val: number) => `${val}`,
},
},
};
const series = [
{
name: "Sales",
data: [168, 385, 201, 298, 187, 195, 291, 110, 215, 390, 280, 112],
},
];
return (
<div className="max-w-full overflow-x-auto custom-scrollbar">
<div id="chartOne" className="min-w-[1000px]">
<Chart options={options} series={series} type="bar" height={180} />
</div>
</div>
);
}

View File

@@ -0,0 +1,121 @@
import React from "react";
import Chart from "react-apexcharts";
import { ApexOptions } from "apexcharts";
export default function LineChartOne() {
const options: ApexOptions = {
legend: {
show: false, // Hide legend
position: "top",
horizontalAlign: "left",
},
colors: ["#465FFF", "#9CB9FF"], // Define line colors
chart: {
fontFamily: "Outfit, sans-serif",
height: 310,
type: "line", // Set the chart type to 'line'
toolbar: {
show: false, // Hide chart toolbar
},
},
stroke: {
curve: "straight", // Define the line style (straight, smooth, or step)
width: [2, 2], // Line width for each dataset
},
fill: {
type: "gradient",
gradient: {
opacityFrom: 0.55,
opacityTo: 0,
},
},
markers: {
size: 0, // Size of the marker points
strokeColors: "#fff", // Marker border color
strokeWidth: 2,
hover: {
size: 6, // Marker size on hover
},
},
grid: {
xaxis: {
lines: {
show: false, // Hide grid lines on x-axis
},
},
yaxis: {
lines: {
show: true, // Show grid lines on y-axis
},
},
},
dataLabels: {
enabled: false, // Disable data labels
},
tooltip: {
enabled: true, // Enable tooltip
x: {
format: "dd MMM yyyy", // Format for x-axis tooltip
},
},
xaxis: {
type: "category", // Category-based x-axis
categories: [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
],
axisBorder: {
show: false, // Hide x-axis border
},
axisTicks: {
show: false, // Hide x-axis ticks
},
tooltip: {
enabled: false, // Disable tooltip for x-axis points
},
},
yaxis: {
labels: {
style: {
fontSize: "12px", // Adjust font size for y-axis labels
colors: ["#6B7280"], // Color of the labels
},
},
title: {
text: "", // Remove y-axis title
style: {
fontSize: "0px",
},
},
},
};
const series = [
{
name: "Sales",
data: [180, 190, 170, 160, 175, 165, 170, 205, 230, 210, 240, 235],
},
{
name: "Revenue",
data: [40, 30, 50, 40, 55, 40, 70, 100, 110, 120, 150, 140],
},
];
return (
<div className="max-w-full overflow-x-auto custom-scrollbar">
<div id="chartEight" className="min-w-[1000px]">
<Chart options={options} series={series} type="area" height={310} />
</div>
</div>
);
}

View File

@@ -0,0 +1,45 @@
import React, { useState } from "react";
const ChartTab: React.FC = () => {
const [selected, setSelected] = useState<
"optionOne" | "optionTwo" | "optionThree"
>("optionOne");
const getButtonClass = (option: "optionOne" | "optionTwo" | "optionThree") =>
selected === option
? "shadow-theme-xs text-gray-900 dark:text-white bg-white dark:bg-gray-800"
: "text-gray-500 dark:text-gray-400";
return (
<div className="flex items-center gap-0.5 rounded-lg bg-gray-100 p-0.5 dark:bg-gray-900">
<button
onClick={() => setSelected("optionOne")}
className={`px-3 py-2 font-medium w-full rounded-md text-theme-sm hover:text-gray-900 dark:hover:text-white ${getButtonClass(
"optionOne"
)}`}
>
Monthly
</button>
<button
onClick={() => setSelected("optionTwo")}
className={`px-3 py-2 font-medium w-full rounded-md text-theme-sm hover:text-gray-900 dark:hover:text-white ${getButtonClass(
"optionTwo"
)}`}
>
Quarterly
</button>
<button
onClick={() => setSelected("optionThree")}
className={`px-3 py-2 font-medium w-full rounded-md text-theme-sm hover:text-gray-900 dark:hover:text-white ${getButtonClass(
"optionThree"
)}`}
>
Annually
</button>
</div>
);
};
export default ChartTab;

View File

@@ -0,0 +1,42 @@
import React from "react";
interface ComponentCardProps {
title?: string; // O título agora é opcional
children: React.ReactNode;
className?: string; // Additional custom classes for styling
desc?: string; // Description text
}
const ComponentCard: React.FC<ComponentCardProps> = ({
title,
children,
className = "",
desc = "",
}) => {
return (
<div
className={`rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03] ${className}`}
>
{/* Card Header - Só renderiza se o título for passado */}
{title && (
<div className="px-6 py-5">
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
{title}
</h3>
{desc && (
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
{desc}
</p>
)}
</div>
)}
{/* Card Body */}
<div className="p-4 border-t border-gray-100 dark:border-gray-800 sm:p-6">
<div className="space-y-6">{children}</div>
</div>
</div>
);
};
export default ComponentCard;

View File

@@ -0,0 +1,69 @@
import React, { useState, useEffect } from "react";
interface CountdownTimerProps {
targetDate: Date;
}
const CountdownTimer: React.FC<CountdownTimerProps> = ({ targetDate }) => {
const [timeLeft, setTimeLeft] = useState({
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
});
useEffect(() => {
const timer = setInterval(() => {
const now = new Date();
const difference = targetDate.getTime() - now.getTime();
if (difference > 0) {
const days = Math.floor(difference / (1000 * 60 * 60 * 24));
const hours = Math.floor((difference / (1000 * 60 * 60)) % 24);
const minutes = Math.floor((difference / 1000 / 60) % 60);
const seconds = Math.floor((difference / 1000) % 60);
setTimeLeft({ days, hours, minutes, seconds });
} else {
clearInterval(timer);
}
}, 1000);
return () => clearInterval(timer);
}, [targetDate]);
const formatTime = (time: number): string => {
return time.toString().padStart(2, "0");
};
return (
<div className="mb-10">
<div className="flex flex-wrap justify-center gap-2 mb-2 font-bold text-title-md text-brand-500 dark:text-brand-400 xl:text-title-lg">
<div className="timer-box">
<span>{formatTime(timeLeft.days)}</span>
</div>
:
<div className="timer-box">
<span>{formatTime(timeLeft.hours)}</span>
</div>
:
<div className="timer-box">
<span>{formatTime(timeLeft.minutes)}</span>
</div>
:
<div className="timer-box">
<span>{formatTime(timeLeft.seconds)}</span>
</div>
</div>
<div className="text-base text-center text-gray-500 dark:text-gray-400">
<span className="inline-block timer-box">
<span className="inline-block">{timeLeft.days}</span>
</span>
{timeLeft.days === 1 ? " day" : " days"} left
</div>
</div>
);
};
export default CountdownTimer;

View File

@@ -0,0 +1,14 @@
import React from "react";
export default function GridShape() {
return (
<>
<div className="absolute right-0 top-0 -z-1 w-full max-w-[250px] xl:max-w-[450px]">
<img src="/images/shape/grid-01.svg" alt="grid" />
</div>
<div className="absolute bottom-0 left-0 -z-1 w-full max-w-[250px] rotate-180 xl:max-w-[450px]">
<img src="/images/shape/grid-01.svg" alt="grid" />
</div>
</>
);
}

View File

@@ -0,0 +1,52 @@
import React from "react";
import { Link } from "react-router";
interface BreadcrumbProps {
pageTitle: string;
}
const PageBreadcrumb: React.FC<BreadcrumbProps> = ({ pageTitle }) => {
return (
<div className="flex flex-wrap items-center justify-between gap-3 mb-6">
<h2
className="text-xl font-semibold text-gray-800 dark:text-white/90"
x-text="pageName"
>
{pageTitle}
</h2>
<nav>
<ol className="flex items-center gap-1.5">
<li>
<Link
className="inline-flex items-center gap-1.5 text-sm text-gray-500 dark:text-gray-400"
to="/"
>
Home
<svg
className="stroke-current"
width="17"
height="16"
viewBox="0 0 17 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.0765 12.667L10.2432 8.50033L6.0765 4.33366"
stroke=""
strokeWidth="1.2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</Link>
</li>
<li className="text-sm text-gray-800 dark:text-white/90">
{pageTitle}
</li>
</ol>
</nav>
</div>
);
};
export default PageBreadcrumb;

View File

@@ -0,0 +1,21 @@
import React from "react";
import { HelmetProvider, Helmet } from "react-helmet-async";
const PageMeta = ({
title,
description,
}: {
title: string;
description: string;
}) => (
<Helmet>
<title>{title}</title>
<meta name="description" content={description} />
</Helmet>
);
export const AppWrapper = ({ children }: { children: React.ReactNode }) => (
<HelmetProvider>{children}</HelmetProvider>
);
export default PageMeta;

View File

@@ -0,0 +1,42 @@
import React from "react";
import { useTheme } from "../../context/ThemeContext";
export const ThemeToggleButton: React.FC = () => {
const { toggleTheme } = useTheme();
return (
<button
onClick={toggleTheme}
className="relative flex items-center justify-center text-gray-500 transition-colors bg-white border border-gray-200 rounded-full hover:text-dark-900 h-11 w-11 hover:bg-gray-100 hover:text-gray-700 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-white"
>
<svg
className="hidden dark:block"
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.99998 1.5415C10.4142 1.5415 10.75 1.87729 10.75 2.2915V3.5415C10.75 3.95572 10.4142 4.2915 9.99998 4.2915C9.58577 4.2915 9.24998 3.95572 9.24998 3.5415V2.2915C9.24998 1.87729 9.58577 1.5415 9.99998 1.5415ZM10.0009 6.79327C8.22978 6.79327 6.79402 8.22904 6.79402 10.0001C6.79402 11.7712 8.22978 13.207 10.0009 13.207C11.772 13.207 13.2078 11.7712 13.2078 10.0001C13.2078 8.22904 11.772 6.79327 10.0009 6.79327ZM5.29402 10.0001C5.29402 7.40061 7.40135 5.29327 10.0009 5.29327C12.6004 5.29327 14.7078 7.40061 14.7078 10.0001C14.7078 12.5997 12.6004 14.707 10.0009 14.707C7.40135 14.707 5.29402 12.5997 5.29402 10.0001ZM15.9813 5.08035C16.2742 4.78746 16.2742 4.31258 15.9813 4.01969C15.6884 3.7268 15.2135 3.7268 14.9207 4.01969L14.0368 4.90357C13.7439 5.19647 13.7439 5.67134 14.0368 5.96423C14.3297 6.25713 14.8045 6.25713 15.0974 5.96423L15.9813 5.08035ZM18.4577 10.0001C18.4577 10.4143 18.1219 10.7501 17.7077 10.7501H16.4577C16.0435 10.7501 15.7077 10.4143 15.7077 10.0001C15.7077 9.58592 16.0435 9.25013 16.4577 9.25013H17.7077C18.1219 9.25013 18.4577 9.58592 18.4577 10.0001ZM14.9207 15.9806C15.2135 16.2735 15.6884 16.2735 15.9813 15.9806C16.2742 15.6877 16.2742 15.2128 15.9813 14.9199L15.0974 14.036C14.8045 13.7431 14.3297 13.7431 14.0368 14.036C13.7439 14.3289 13.7439 14.8038 14.0368 15.0967L14.9207 15.9806ZM9.99998 15.7088C10.4142 15.7088 10.75 16.0445 10.75 16.4588V17.7088C10.75 18.123 10.4142 18.4588 9.99998 18.4588C9.58577 18.4588 9.24998 18.123 9.24998 17.7088V16.4588C9.24998 16.0445 9.58577 15.7088 9.99998 15.7088ZM5.96356 15.0972C6.25646 14.8043 6.25646 14.3295 5.96356 14.0366C5.67067 13.7437 5.1958 13.7437 4.9029 14.0366L4.01902 14.9204C3.72613 15.2133 3.72613 15.6882 4.01902 15.9811C4.31191 16.274 4.78679 16.274 5.07968 15.9811L5.96356 15.0972ZM4.29224 10.0001C4.29224 10.4143 3.95645 10.7501 3.54224 10.7501H2.29224C1.87802 10.7501 1.54224 10.4143 1.54224 10.0001C1.54224 9.58592 1.87802 9.25013 2.29224 9.25013H3.54224C3.95645 9.25013 4.29224 9.58592 4.29224 10.0001ZM4.9029 5.9637C5.1958 6.25659 5.67067 6.25659 5.96356 5.9637C6.25646 5.6708 6.25646 5.19593 5.96356 4.90303L5.07968 4.01915C4.78679 3.72626 4.31191 3.72626 4.01902 4.01915C3.72613 4.31204 3.72613 4.78692 4.01902 5.07981L4.9029 5.9637Z"
fill="currentColor"
/>
</svg>
<svg
className="dark:hidden"
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M17.4547 11.97L18.1799 12.1611C18.265 11.8383 18.1265 11.4982 17.8401 11.3266C17.5538 11.1551 17.1885 11.1934 16.944 11.4207L17.4547 11.97ZM8.0306 2.5459L8.57989 3.05657C8.80718 2.81209 8.84554 2.44682 8.67398 2.16046C8.50243 1.8741 8.16227 1.73559 7.83948 1.82066L8.0306 2.5459ZM12.9154 13.0035C9.64678 13.0035 6.99707 10.3538 6.99707 7.08524H5.49707C5.49707 11.1823 8.81835 14.5035 12.9154 14.5035V13.0035ZM16.944 11.4207C15.8869 12.4035 14.4721 13.0035 12.9154 13.0035V14.5035C14.8657 14.5035 16.6418 13.7499 17.9654 12.5193L16.944 11.4207ZM16.7295 11.7789C15.9437 14.7607 13.2277 16.9586 10.0003 16.9586V18.4586C13.9257 18.4586 17.2249 15.7853 18.1799 12.1611L16.7295 11.7789ZM10.0003 16.9586C6.15734 16.9586 3.04199 13.8433 3.04199 10.0003H1.54199C1.54199 14.6717 5.32892 18.4586 10.0003 18.4586V16.9586ZM3.04199 10.0003C3.04199 6.77289 5.23988 4.05695 8.22173 3.27114L7.83948 1.82066C4.21532 2.77574 1.54199 6.07486 1.54199 10.0003H3.04199ZM6.99707 7.08524C6.99707 5.52854 7.5971 4.11366 8.57989 3.05657L7.48132 2.03522C6.25073 3.35885 5.49707 5.13487 5.49707 7.08524H6.99707Z"
fill="currentColor"
/>
</svg>
</button>
);
};

View File

@@ -0,0 +1,95 @@
import React from "react";
// react plugin for creating vector maps
import { VectorMap } from "@react-jvectormap/core";
import { worldMill } from "@react-jvectormap/world";
// Define the component props
interface CountryMapProps {
mapColor?: string;
}
const CountryMap: React.FC<CountryMapProps> = ({ mapColor }) => {
return (
<VectorMap
map={worldMill}
backgroundColor="transparent"
markerStyle={{
initial: {
fill: "#465FFF",
r: 4, // Custom radius for markers
} as any, // Type assertion to bypass strict CSS property checks
}}
markersSelectable={true}
markers={[
{
latLng: [37.2580397, -104.657039],
name: "United States",
style: {
fill: "#465FFF",
borderWidth: 1,
borderColor: "white",
stroke: "#383f47",
},
},
{
latLng: [20.7504374, 73.7276105],
name: "India",
style: { fill: "#465FFF", borderWidth: 1, borderColor: "white" },
},
{
latLng: [53.613, -11.6368],
name: "United Kingdom",
style: { fill: "#465FFF", borderWidth: 1, borderColor: "white" },
},
{
latLng: [-25.0304388, 115.2092761],
name: "Sweden",
style: {
fill: "#465FFF",
borderWidth: 1,
borderColor: "white",
strokeOpacity: 0,
},
},
]}
zoomOnScroll={false}
zoomMax={12}
zoomMin={1}
zoomAnimate={true}
zoomStep={1.5}
regionStyle={{
initial: {
fill: mapColor || "#D0D5DD",
fillOpacity: 1,
fontFamily: "Outfit",
stroke: "none",
strokeWidth: 0,
strokeOpacity: 0,
},
hover: {
fillOpacity: 0.7,
cursor: "pointer",
fill: "#465fff",
stroke: "none",
},
selected: {
fill: "#465FFF",
},
selectedHover: {},
}}
regionLabelStyle={{
initial: {
fill: "#35373e",
fontWeight: 500,
fontSize: "13px",
stroke: "none",
},
hover: {},
selected: {},
selectedHover: {},
}}
/>
);
};
export default CountryMap;

View File

@@ -0,0 +1,115 @@
import { useState } from "react";
import { Dropdown } from "../ui/dropdown/Dropdown";
import { DropdownItem } from "../ui/dropdown/DropdownItem";
import CountryMap from "./CountryMap";
import { MoreDotIcon } from "../../icons";
export default function DemographicCard() {
const [isOpen, setIsOpen] = useState(false);
function toggleDropdown() {
setIsOpen(!isOpen);
}
function closeDropdown() {
setIsOpen(false);
}
return (
<div className="rounded-2xl border border-gray-200 bg-white p-5 dark:border-gray-800 dark:bg-white/[0.03] sm:p-6">
<div className="flex justify-between">
<div>
<h3 className="text-lg font-semibold text-gray-800 dark:text-white/90">
Customers Demographic
</h3>
<p className="mt-1 text-gray-500 text-theme-sm dark:text-gray-400">
Number of customer based on country
</p>
</div>
<div className="relative inline-block">
<button onClick={toggleDropdown}>
<MoreDotIcon className="text-gray-400 hover:text-gray-700 dark:hover:text-gray-300" />
</button>
<Dropdown
isOpen={isOpen}
onClose={closeDropdown}
className="w-40 p-2"
>
<DropdownItem
onItemClick={closeDropdown}
className="flex w-full font-normal text-left text-gray-500 rounded-lg hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-300"
>
View More
</DropdownItem>
<DropdownItem
onItemClick={closeDropdown}
className="flex w-full font-normal text-left text-gray-500 rounded-lg hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-300"
>
Delete
</DropdownItem>
</Dropdown>
</div>
</div>
<div className="px-4 py-6 my-6 overflow-hidden border border-gary-200 rounded-2xl dark:border-gray-800 sm:px-6">
<div
id="mapOne"
className="mapOne map-btn -mx-4 -my-6 h-[212px] w-[252px] 2xsm:w-[307px] xsm:w-[358px] sm:-mx-6 md:w-[668px] lg:w-[634px] xl:w-[393px] 2xl:w-[554px]"
>
<CountryMap />
</div>
</div>
<div className="space-y-5">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="items-center w-full rounded-full max-w-8">
<img src="./images/country/country-01.svg" alt="usa" />
</div>
<div>
<p className="font-semibold text-gray-800 text-theme-sm dark:text-white/90">
USA
</p>
<span className="block text-gray-500 text-theme-xs dark:text-gray-400">
2,379 Customers
</span>
</div>
</div>
<div className="flex w-full max-w-[140px] items-center gap-3">
<div className="relative block h-2 w-full max-w-[100px] rounded bg-gray-200 dark:bg-gray-800">
<div className="absolute left-0 top-0 flex h-full w-[79%] items-center justify-center rounded bg-brand-500 text-xs font-medium text-white"></div>
</div>
<p className="font-medium text-gray-800 text-theme-sm dark:text-white/90">
79%
</p>
</div>
</div>
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="items-center w-full rounded-full max-w-8">
<img src="./images/country/country-02.svg" alt="france" />
</div>
<div>
<p className="font-semibold text-gray-800 text-theme-sm dark:text-white/90">
France
</p>
<span className="block text-gray-500 text-theme-xs dark:text-gray-400">
589 Customers
</span>
</div>
</div>
<div className="flex w-full max-w-[140px] items-center gap-3">
<div className="relative block h-2 w-full max-w-[100px] rounded bg-gray-200 dark:bg-gray-800">
<div className="absolute left-0 top-0 flex h-full w-[23%] items-center justify-center rounded bg-brand-500 text-xs font-medium text-white"></div>
</div>
<p className="font-medium text-gray-800 text-theme-sm dark:text-white/90">
23%
</p>
</div>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,60 @@
import React from "react";
import {
ArrowDownIcon,
ArrowUpIcon,
BoxIconLine,
GroupIcon,
} from "../../icons";
import Badge from "../ui/badge/Badge";
export default function EcommerceMetrics() {
return (
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:gap-6">
{/* <!-- Metric Item Start --> */}
<div className="rounded-2xl border border-gray-200 bg-white p-5 dark:border-gray-800 dark:bg-white/[0.03] md:p-6">
<div className="flex items-center justify-center w-12 h-12 bg-gray-100 rounded-xl dark:bg-gray-800">
<GroupIcon className="text-gray-800 size-6 dark:text-white/90" />
</div>
<div className="flex items-end justify-between mt-5">
<div>
<span className="text-sm text-gray-500 dark:text-gray-400">
Customers
</span>
<h4 className="mt-2 font-bold text-gray-800 text-title-sm dark:text-white/90">
3,782
</h4>
</div>
<Badge color="success">
<ArrowUpIcon />
11.01%
</Badge>
</div>
</div>
{/* <!-- Metric Item End --> */}
{/* <!-- Metric Item Start --> */}
<div className="rounded-2xl border border-gray-200 bg-white p-5 dark:border-gray-800 dark:bg-white/[0.03] md:p-6">
<div className="flex items-center justify-center w-12 h-12 bg-gray-100 rounded-xl dark:bg-gray-800">
<BoxIconLine className="text-gray-800 dark:text-white/90" />
</div>
<div className="flex items-end justify-between mt-5">
<div>
<span className="text-sm text-gray-500 dark:text-gray-400">
Orders
</span>
<h4 className="mt-2 font-bold text-gray-800 text-title-sm dark:text-white/90">
5,359
</h4>
</div>
<Badge color="error">
<ArrowDownIcon />
9.05%
</Badge>
</div>
</div>
{/* <!-- Metric Item End --> */}
</div>
);
}

View File

@@ -0,0 +1,142 @@
import Chart from "react-apexcharts";
import { ApexOptions } from "apexcharts";
import { MoreDotIcon } from "../../icons";
import { Dropdown } from "../ui/dropdown/Dropdown";
import { DropdownItem } from "../ui/dropdown/DropdownItem";
import { useState } from "react";
export default function MonthlySalesChart() {
const options: ApexOptions = {
colors: ["#465fff"],
chart: {
fontFamily: "Outfit, sans-serif",
type: "bar",
height: 180,
toolbar: {
show: false,
},
},
plotOptions: {
bar: {
horizontal: false,
columnWidth: "39%",
borderRadius: 5,
borderRadiusApplication: "end",
},
},
dataLabels: {
enabled: false,
},
stroke: {
show: true,
width: 4,
colors: ["transparent"],
},
xaxis: {
categories: [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
],
axisBorder: {
show: false,
},
axisTicks: {
show: false,
},
},
legend: {
show: true,
position: "top",
horizontalAlign: "left",
fontFamily: "Outfit",
},
yaxis: {
title: {
text: undefined,
},
},
grid: {
yaxis: {
lines: {
show: true,
},
},
},
fill: {
opacity: 1,
},
tooltip: {
x: {
show: false,
},
y: {
formatter: (val: number) => `${val}`,
},
},
};
const series = [
{
name: "Sales",
data: [168, 385, 201, 298, 187, 195, 291, 110, 215, 390, 280, 112],
},
];
const [isOpen, setIsOpen] = useState(false);
function toggleDropdown() {
setIsOpen(!isOpen);
}
function closeDropdown() {
setIsOpen(false);
}
return (
<div className="overflow-hidden rounded-2xl border border-gray-200 bg-white px-5 pt-5 dark:border-gray-800 dark:bg-white/[0.03] sm:px-6 sm:pt-6">
<div className="flex items-center justify-between">
<h3 className="text-lg font-semibold text-gray-800 dark:text-white/90">
Monthly Sales
</h3>
<div className="relative inline-block">
<button onClick={toggleDropdown}>
<MoreDotIcon className="text-gray-400 hover:text-gray-700 dark:hover:text-gray-300" />
</button>
<Dropdown
isOpen={isOpen}
onClose={closeDropdown}
className="w-40 p-2"
>
<DropdownItem
onItemClick={closeDropdown}
className="flex w-full font-normal text-left text-gray-500 rounded-lg hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-300"
>
View More
</DropdownItem>
<DropdownItem
onItemClick={closeDropdown}
className="flex w-full font-normal text-left text-gray-500 rounded-lg hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-300"
>
Delete
</DropdownItem>
</Dropdown>
</div>
</div>
<div className="max-w-full overflow-x-auto custom-scrollbar">
<div className="-ml-5 min-w-[650px] xl:min-w-full pl-2">
<Chart options={options} series={series} type="bar" height={180} />
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,198 @@
import Chart from "react-apexcharts";
import { ApexOptions } from "apexcharts";
import { useState } from "react";
import { MoreDotIcon } from "../../icons";
import { Dropdown } from "../ui/dropdown/Dropdown";
import { DropdownItem } from "../ui/dropdown/DropdownItem";
export default function MonthlyTarget() {
const series = [75.55];
const options: ApexOptions = {
colors: ["#465FFF"],
chart: {
fontFamily: "Outfit, sans-serif",
type: "radialBar",
height: 330,
sparkline: {
enabled: true,
},
},
plotOptions: {
radialBar: {
startAngle: -85,
endAngle: 85,
hollow: {
size: "80%",
},
track: {
background: "#E4E7EC",
strokeWidth: "100%",
margin: 5, // margin is in pixels
},
dataLabels: {
name: {
show: false,
},
value: {
fontSize: "36px",
fontWeight: "600",
offsetY: -40,
color: "#1D2939",
formatter: function (val) {
return val + "%";
},
},
},
},
},
fill: {
type: "solid",
colors: ["#465FFF"],
},
stroke: {
lineCap: "round",
},
labels: ["Progress"],
};
const [isOpen, setIsOpen] = useState(false);
function toggleDropdown() {
setIsOpen(!isOpen);
}
function closeDropdown() {
setIsOpen(false);
}
return (
<div className="rounded-2xl border border-gray-200 bg-gray-100 dark:border-gray-800 dark:bg-white/[0.03]">
<div className="px-5 pt-5 bg-white shadow-default rounded-2xl pb-11 dark:bg-gray-900 sm:px-6 sm:pt-6">
<div className="flex justify-between">
<div>
<h3 className="text-lg font-semibold text-gray-800 dark:text-white/90">
Monthly Target
</h3>
<p className="mt-1 text-gray-500 text-theme-sm dark:text-gray-400">
Target youve set for each month
</p>
</div>
<div className="relative inline-block">
<button onClick={toggleDropdown}>
<MoreDotIcon className="text-gray-400 hover:text-gray-700 dark:hover:text-gray-300" />
</button>
<Dropdown
isOpen={isOpen}
onClose={closeDropdown}
className="w-40 p-2"
>
<DropdownItem
onItemClick={closeDropdown}
className="flex w-full font-normal text-left text-gray-500 rounded-lg hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-300"
>
View More
</DropdownItem>
<DropdownItem
onItemClick={closeDropdown}
className="flex w-full font-normal text-left text-gray-500 rounded-lg hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-300"
>
Delete
</DropdownItem>
</Dropdown>
</div>
</div>
<div className="relative ">
<div className="max-h-[330px]">
<Chart
options={options}
series={series}
type="radialBar"
height={330}
/>
</div>
<span className="absolute left-1/2 top-full -translate-x-1/2 -translate-y-[95%] rounded-full bg-success-50 px-3 py-1 text-xs font-medium text-success-600 dark:bg-success-500/15 dark:text-success-500">
+10%
</span>
</div>
<p className="mx-auto mt-10 w-full max-w-[380px] text-center text-sm text-gray-500 sm:text-base">
You earn $3287 today, it's higher than last month. Keep up your good
work!
</p>
</div>
<div className="flex items-center justify-center gap-5 px-6 py-3.5 sm:gap-8 sm:py-5">
<div>
<p className="mb-1 text-center text-gray-500 text-theme-xs dark:text-gray-400 sm:text-sm">
Target
</p>
<p className="flex items-center justify-center gap-1 text-base font-semibold text-gray-800 dark:text-white/90 sm:text-lg">
$20K
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M7.26816 13.6632C7.4056 13.8192 7.60686 13.9176 7.8311 13.9176C7.83148 13.9176 7.83187 13.9176 7.83226 13.9176C8.02445 13.9178 8.21671 13.8447 8.36339 13.6981L12.3635 9.70076C12.6565 9.40797 12.6567 8.9331 12.3639 8.6401C12.0711 8.34711 11.5962 8.34694 11.3032 8.63973L8.5811 11.36L8.5811 2.5C8.5811 2.08579 8.24531 1.75 7.8311 1.75C7.41688 1.75 7.0811 2.08579 7.0811 2.5L7.0811 11.3556L4.36354 8.63975C4.07055 8.34695 3.59568 8.3471 3.30288 8.64009C3.01008 8.93307 3.01023 9.40794 3.30321 9.70075L7.26816 13.6632Z"
fill="#D92D20"
/>
</svg>
</p>
</div>
<div className="w-px bg-gray-200 h-7 dark:bg-gray-800"></div>
<div>
<p className="mb-1 text-center text-gray-500 text-theme-xs dark:text-gray-400 sm:text-sm">
Revenue
</p>
<p className="flex items-center justify-center gap-1 text-base font-semibold text-gray-800 dark:text-white/90 sm:text-lg">
$20K
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M7.60141 2.33683C7.73885 2.18084 7.9401 2.08243 8.16435 2.08243C8.16475 2.08243 8.16516 2.08243 8.16556 2.08243C8.35773 2.08219 8.54998 2.15535 8.69664 2.30191L12.6968 6.29924C12.9898 6.59203 12.9899 7.0669 12.6971 7.3599C12.4044 7.6529 11.9295 7.65306 11.6365 7.36027L8.91435 4.64004L8.91435 13.5C8.91435 13.9142 8.57856 14.25 8.16435 14.25C7.75013 14.25 7.41435 13.9142 7.41435 13.5L7.41435 4.64442L4.69679 7.36025C4.4038 7.65305 3.92893 7.6529 3.63613 7.35992C3.34333 7.06693 3.34348 6.59206 3.63646 6.29926L7.60141 2.33683Z"
fill="#039855"
/>
</svg>
</p>
</div>
<div className="w-px bg-gray-200 h-7 dark:bg-gray-800"></div>
<div>
<p className="mb-1 text-center text-gray-500 text-theme-xs dark:text-gray-400 sm:text-sm">
Today
</p>
<p className="flex items-center justify-center gap-1 text-base font-semibold text-gray-800 dark:text-white/90 sm:text-lg">
$20K
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M7.60141 2.33683C7.73885 2.18084 7.9401 2.08243 8.16435 2.08243C8.16475 2.08243 8.16516 2.08243 8.16556 2.08243C8.35773 2.08219 8.54998 2.15535 8.69664 2.30191L12.6968 6.29924C12.9898 6.59203 12.9899 7.0669 12.6971 7.3599C12.4044 7.6529 11.9295 7.65306 11.6365 7.36027L8.91435 4.64004L8.91435 13.5C8.91435 13.9142 8.57856 14.25 8.16435 14.25C7.75013 14.25 7.41435 13.9142 7.41435 13.5L7.41435 4.64442L4.69679 7.36025C4.4038 7.65305 3.92893 7.6529 3.63613 7.35992C3.34333 7.06693 3.34348 6.59206 3.63646 6.29926L7.60141 2.33683Z"
fill="#039855"
/>
</svg>
</p>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,208 @@
import {
Table,
TableBody,
TableCell,
TableHeader,
TableRow,
} from "../ui/table";
import Badge from "../ui/badge/Badge";
// Define the TypeScript interface for the table rows
interface Product {
id: number; // Unique identifier for each product
name: string; // Product name
variants: string; // Number of variants (e.g., "1 Variant", "2 Variants")
category: string; // Category of the product
price: string; // Price of the product (as a string with currency symbol)
// status: string; // Status of the product
image: string; // URL or path to the product image
status: "Delivered" | "Pending" | "Canceled"; // Status of the product
}
// Define the table data using the interface
const tableData: Product[] = [
{
id: 1,
name: "MacBook Pro 13”",
variants: "2 Variants",
category: "Laptop",
price: "$2399.00",
status: "Delivered",
image: "/images/product/product-01.jpg", // Replace with actual image URL
},
{
id: 2,
name: "Apple Watch Ultra",
variants: "1 Variant",
category: "Watch",
price: "$879.00",
status: "Pending",
image: "/images/product/product-02.jpg", // Replace with actual image URL
},
{
id: 3,
name: "iPhone 15 Pro Max",
variants: "2 Variants",
category: "SmartPhone",
price: "$1869.00",
status: "Delivered",
image: "/images/product/product-03.jpg", // Replace with actual image URL
},
{
id: 4,
name: "iPad Pro 3rd Gen",
variants: "2 Variants",
category: "Electronics",
price: "$1699.00",
status: "Canceled",
image: "/images/product/product-04.jpg", // Replace with actual image URL
},
{
id: 5,
name: "AirPods Pro 2nd Gen",
variants: "1 Variant",
category: "Accessories",
price: "$240.00",
status: "Delivered",
image: "/images/product/product-05.jpg", // Replace with actual image URL
},
];
export default function RecentOrders() {
return (
<div className="overflow-hidden rounded-2xl border border-gray-200 bg-white px-4 pb-3 pt-4 dark:border-gray-800 dark:bg-white/[0.03] sm:px-6">
<div className="flex flex-col gap-2 mb-4 sm:flex-row sm:items-center sm:justify-between">
<div>
<h3 className="text-lg font-semibold text-gray-800 dark:text-white/90">
Recent Orders
</h3>
</div>
<div className="flex items-center gap-3">
<button className="inline-flex items-center gap-2 rounded-lg border border-gray-300 bg-white px-4 py-2.5 text-theme-sm font-medium text-gray-700 shadow-theme-xs hover:bg-gray-50 hover:text-gray-800 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-white/[0.03] dark:hover:text-gray-200">
<svg
className="stroke-current fill-white dark:fill-gray-800"
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M2.29004 5.90393H17.7067"
stroke=""
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M17.7075 14.0961H2.29085"
stroke=""
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M12.0826 3.33331C13.5024 3.33331 14.6534 4.48431 14.6534 5.90414C14.6534 7.32398 13.5024 8.47498 12.0826 8.47498C10.6627 8.47498 9.51172 7.32398 9.51172 5.90415C9.51172 4.48432 10.6627 3.33331 12.0826 3.33331Z"
fill=""
stroke=""
strokeWidth="1.5"
/>
<path
d="M7.91745 11.525C6.49762 11.525 5.34662 12.676 5.34662 14.0959C5.34661 15.5157 6.49762 16.6667 7.91745 16.6667C9.33728 16.6667 10.4883 15.5157 10.4883 14.0959C10.4883 12.676 9.33728 11.525 7.91745 11.525Z"
fill=""
stroke=""
strokeWidth="1.5"
/>
</svg>
Filter
</button>
<button className="inline-flex items-center gap-2 rounded-lg border border-gray-300 bg-white px-4 py-2.5 text-theme-sm font-medium text-gray-700 shadow-theme-xs hover:bg-gray-50 hover:text-gray-800 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-white/[0.03] dark:hover:text-gray-200">
See all
</button>
</div>
</div>
<div className="max-w-full overflow-x-auto">
<Table>
{/* Table Header */}
<TableHeader className="border-gray-100 dark:border-gray-800 border-y">
<TableRow>
<TableCell
isHeader
className="py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400"
>
Products
</TableCell>
<TableCell
isHeader
className="py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400"
>
Category
</TableCell>
<TableCell
isHeader
className="py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400"
>
Price
</TableCell>
<TableCell
isHeader
className="py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400"
>
Status
</TableCell>
</TableRow>
</TableHeader>
{/* Table Body */}
<TableBody className="divide-y divide-gray-100 dark:divide-gray-800">
{tableData.map((product) => (
<TableRow key={product.id} className="">
<TableCell className="py-3">
<div className="flex items-center gap-3">
<div className="h-[50px] w-[50px] overflow-hidden rounded-md">
<img
src={product.image}
className="h-[50px] w-[50px]"
alt={product.name}
/>
</div>
<div>
<p className="font-medium text-gray-800 text-theme-sm dark:text-white/90">
{product.name}
</p>
<span className="text-gray-500 text-theme-xs dark:text-gray-400">
{product.variants}
</span>
</div>
</div>
</TableCell>
<TableCell className="py-3 text-gray-500 text-theme-sm dark:text-gray-400">
{product.price}
</TableCell>
<TableCell className="py-3 text-gray-500 text-theme-sm dark:text-gray-400">
{product.category}
</TableCell>
<TableCell className="py-3 text-gray-500 text-theme-sm dark:text-gray-400">
<Badge
size="sm"
color={
product.status === "Delivered"
? "success"
: product.status === "Pending"
? "warning"
: "error"
}
>
{product.status}
</Badge>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</div>
);
}

View File

@@ -0,0 +1,138 @@
import React from "react";
import Chart from "react-apexcharts";
import { ApexOptions } from "apexcharts";
import ChartTab from "../common/ChartTab";
export default function StatisticsChart() {
const options: ApexOptions = {
legend: {
show: false, // Hide legend
position: "top",
horizontalAlign: "left",
},
colors: ["#465FFF", "#9CB9FF"], // Define line colors
chart: {
fontFamily: "Outfit, sans-serif",
height: 310,
type: "line", // Set the chart type to 'line'
toolbar: {
show: false, // Hide chart toolbar
},
},
stroke: {
curve: "straight", // Define the line style (straight, smooth, or step)
width: [2, 2], // Line width for each dataset
},
fill: {
type: "gradient",
gradient: {
opacityFrom: 0.55,
opacityTo: 0,
},
},
markers: {
size: 0, // Size of the marker points
strokeColors: "#fff", // Marker border color
strokeWidth: 2,
hover: {
size: 6, // Marker size on hover
},
},
grid: {
xaxis: {
lines: {
show: false, // Hide grid lines on x-axis
},
},
yaxis: {
lines: {
show: true, // Show grid lines on y-axis
},
},
},
dataLabels: {
enabled: false, // Disable data labels
},
tooltip: {
enabled: true, // Enable tooltip
x: {
format: "dd MMM yyyy", // Format for x-axis tooltip
},
},
xaxis: {
type: "category", // Category-based x-axis
categories: [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
],
axisBorder: {
show: false, // Hide x-axis border
},
axisTicks: {
show: false, // Hide x-axis ticks
},
tooltip: {
enabled: false, // Disable tooltip for x-axis points
},
},
yaxis: {
labels: {
style: {
fontSize: "12px", // Adjust font size for y-axis labels
colors: ["#6B7280"], // Color of the labels
},
},
title: {
text: "", // Remove y-axis title
style: {
fontSize: "0px",
},
},
},
};
const series = [
{
name: "Sales",
data: [180, 190, 170, 160, 175, 165, 170, 205, 230, 210, 240, 235],
},
{
name: "Revenue",
data: [40, 30, 50, 40, 55, 40, 70, 100, 110, 120, 150, 140],
},
];
return (
<div className="rounded-2xl border border-gray-200 bg-white px-5 pb-5 pt-5 dark:border-gray-800 dark:bg-white/[0.03] sm:px-6 sm:pt-6">
<div className="flex flex-col gap-5 mb-6 sm:flex-row sm:justify-between">
<div className="w-full">
<h3 className="text-lg font-semibold text-gray-800 dark:text-white/90">
Statistics
</h3>
<p className="mt-1 text-gray-500 text-theme-sm dark:text-gray-400">
Target youve set for each month
</p>
</div>
<div className="flex items-start w-full gap-3 sm:justify-end">
<ChartTab />
</div>
</div>
<div className="max-w-full overflow-x-auto custom-scrollbar">
<div className="min-w-[1000px] xl:min-w-full">
<Chart options={options} series={series} type="area" height={310} />
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,23 @@
import React, { FC, ReactNode, FormEvent } from "react";
interface FormProps {
onSubmit: (event: FormEvent<HTMLFormElement>) => void;
children: ReactNode;
className?: string;
}
const Form: FC<FormProps> = ({ onSubmit, children, className }) => {
return (
<form
onSubmit={(event) => {
event.preventDefault(); // Prevent default form submission
onSubmit(event);
}}
className={` ${className}`} // Default spacing between form fields
>
{children}
</form>
);
};
export default Form;

View File

@@ -0,0 +1,27 @@
import React, { FC, ReactNode } from "react";
import { twMerge } from "tailwind-merge";
interface LabelProps {
htmlFor?: string;
children: ReactNode;
className?: string;
}
const Label: FC<LabelProps> = ({ htmlFor, children, className }) => {
return (
<label
htmlFor={htmlFor}
className={twMerge(
// Default classes that apply by default
"mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400",
// User-defined className that can override the default margin
className
)}
>
{children}
</label>
);
};
export default Label;

View File

@@ -0,0 +1,166 @@
import React, { useState } from "react";
interface Option {
value: string;
text: string;
selected: boolean;
}
interface MultiSelectProps {
label: string;
options: Option[];
defaultSelected?: string[];
onChange?: (selected: string[]) => void;
disabled?: boolean;
}
const MultiSelect: React.FC<MultiSelectProps> = ({
label,
options,
defaultSelected = [],
onChange,
disabled = false,
}) => {
const [selectedOptions, setSelectedOptions] =
useState<string[]>(defaultSelected);
const [isOpen, setIsOpen] = useState(false);
const toggleDropdown = () => {
if (disabled) return;
setIsOpen((prev) => !prev);
};
const handleSelect = (optionValue: string) => {
const newSelectedOptions = selectedOptions.includes(optionValue)
? selectedOptions.filter((value) => value !== optionValue)
: [...selectedOptions, optionValue];
setSelectedOptions(newSelectedOptions);
if (onChange) onChange(newSelectedOptions);
};
const removeOption = (index: number, value: string) => {
const newSelectedOptions = selectedOptions.filter((opt) => opt !== value);
setSelectedOptions(newSelectedOptions);
if (onChange) onChange(newSelectedOptions);
};
const selectedValuesText = selectedOptions.map(
(value) => options.find((option) => option.value === value)?.text || ""
);
return (
<div className="w-full">
<label className="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
{label}
</label>
<div className="relative z-20 inline-block w-full">
<div className="relative flex flex-col items-center">
<div onClick={toggleDropdown} className="w-full">
<div className="mb-2 flex h-11 rounded-lg border border-gray-300 py-1.5 pl-3 pr-3 shadow-theme-xs outline-none transition focus:border-brand-300 focus:shadow-focus-ring dark:border-gray-700 dark:bg-gray-900 dark:focus:border-brand-300">
<div className="flex flex-wrap flex-auto gap-2">
{selectedValuesText.length > 0 ? (
selectedValuesText.map((text, index) => (
<div
key={index}
className="group flex items-center justify-center rounded-full border-[0.7px] border-transparent bg-gray-100 py-1 pl-2.5 pr-2 text-sm text-gray-800 hover:border-gray-200 dark:bg-gray-800 dark:text-white/90 dark:hover:border-gray-800"
>
<span className="flex-initial max-w-full">{text}</span>
<div className="flex flex-row-reverse flex-auto">
<div
onClick={() =>
removeOption(index, selectedOptions[index])
}
className="pl-2 text-gray-500 cursor-pointer group-hover:text-gray-400 dark:text-gray-400"
>
<svg
className="fill-current"
role="button"
width="14"
height="14"
viewBox="0 0 14 14"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.40717 4.46881C3.11428 4.17591 3.11428 3.70104 3.40717 3.40815C3.70006 3.11525 4.17494 3.11525 4.46783 3.40815L6.99943 5.93975L9.53095 3.40822C9.82385 3.11533 10.2987 3.11533 10.5916 3.40822C10.8845 3.70112 10.8845 4.17599 10.5916 4.46888L8.06009 7.00041L10.5916 9.53193C10.8845 9.82482 10.8845 10.2997 10.5916 10.5926C10.2987 10.8855 9.82385 10.8855 9.53095 10.5926L6.99943 8.06107L4.46783 10.5927C4.17494 10.8856 3.70006 10.8856 3.40717 10.5927C3.11428 10.2998 3.11428 9.8249 3.40717 9.53201L5.93877 7.00041L3.40717 4.46881Z"
/>
</svg>
</div>
</div>
</div>
))
) : (
<input
placeholder="Select option"
className="w-full h-full p-1 pr-2 text-sm bg-transparent border-0 outline-none appearance-none placeholder:text-gray-800 focus:border-0 focus:outline-none focus:ring-0 dark:placeholder:text-white/90"
readOnly
value="Select option"
/>
)}
</div>
<div className="flex items-center py-1 pl-1 pr-1 w-7">
<button
type="button"
onClick={toggleDropdown}
className="w-5 h-5 text-gray-700 outline-none cursor-pointer focus:outline-none dark:text-gray-400"
>
<svg
className={`stroke-current ${isOpen ? "rotate-180" : ""}`}
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4.79175 7.39551L10.0001 12.6038L15.2084 7.39551"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</button>
</div>
</div>
</div>
{isOpen && (
<div
className="absolute left-0 z-40 w-full overflow-y-auto bg-white rounded-lg shadow top-full max-h-select dark:bg-gray-900"
onClick={(e) => e.stopPropagation()}
>
<div className="flex flex-col">
{options.map((option, index) => (
<div key={index}>
<div
className={`hover:bg-primary/5 w-full cursor-pointer rounded-t border-b border-gray-200 dark:border-gray-800`}
onClick={() => handleSelect(option.value)}
>
<div
className={`relative flex w-full items-center p-2 pl-2 ${
selectedOptions.includes(option.value)
? "bg-primary/10"
: ""
}`}
>
<div className="mx-2 leading-6 text-gray-800 dark:text-white/90">
{option.text}
</div>
</div>
</div>
</div>
))}
</div>
</div>
)}
</div>
</div>
</div>
);
};
export default MultiSelect;

View File

@@ -0,0 +1,64 @@
import React, { useState } from "react";
interface Option {
value: string;
label: string;
}
interface SelectProps {
options: Option[];
placeholder?: string;
onChange: (value: string) => void;
className?: string;
defaultValue?: string;
}
const Select: React.FC<SelectProps> = ({
options,
placeholder = "Select an option",
onChange,
className = "",
defaultValue = "",
}) => {
// Manage the selected value
const [selectedValue, setSelectedValue] = useState<string>(defaultValue);
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
const value = e.target.value;
setSelectedValue(value);
onChange(value); // Trigger parent handler
};
return (
<select
className={`h-11 w-full appearance-none rounded-lg border border-gray-300 bg-transparent px-4 py-2.5 pr-11 text-sm shadow-theme-xs placeholder:text-gray-400 focus:border-brand-300 focus:outline-none focus:ring focus:ring-brand-500/10 dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30 dark:focus:border-brand-800 ${
selectedValue
? "text-gray-800 dark:text-white/90"
: "text-gray-400 dark:text-gray-400"
} ${className}`}
value={selectedValue}
onChange={handleChange}
>
{/* Placeholder option */}
<option
value=""
disabled
className="text-gray-700 dark:bg-gray-900 dark:text-gray-400"
>
{placeholder}
</option>
{/* Map over options */}
{options.map((option) => (
<option
key={option.value}
value={option.value}
className="text-gray-700 dark:bg-gray-900 dark:text-gray-400"
>
{option.label}
</option>
))}
</select>
);
};
export default Select;

View File

@@ -0,0 +1,36 @@
import React, { useState } from "react";
import ComponentCard from "../../common/ComponentCard";
import Checkbox from "../input/Checkbox";
export default function CheckboxComponents() {
const [isChecked, setIsChecked] = useState(false);
const [isCheckedTwo, setIsCheckedTwo] = useState(true);
const [isCheckedDisabled, setIsCheckedDisabled] = useState(true);
return (
<ComponentCard title="Checkbox">
<div className="flex items-center gap-4">
<div className="flex items-center gap-3">
<Checkbox checked={isChecked} onChange={setIsChecked} />
<span className="block text-sm font-medium text-gray-700 dark:text-gray-400">
Default
</span>
</div>
<div className="flex items-center gap-3">
<Checkbox
checked={isCheckedTwo}
onChange={setIsCheckedTwo}
label="Checked"
/>
</div>
<div className="flex items-center gap-3">
<Checkbox
checked={isCheckedDisabled}
onChange={setIsCheckedDisabled}
disabled
label="Disabled"
/>
</div>
</div>
</ComponentCard>
);
}

View File

@@ -0,0 +1,114 @@
import React, { useState } from "react";
import ComponentCard from "../../common/ComponentCard";
import Label from "../Label";
import Input from "../input/InputField";
import Select from "../Select";
import { CalenderIcon, EyeCloseIcon, EyeIcon, TimeIcon } from "../../../icons";
export default function DefaultInputs() {
const [showPassword, setShowPassword] = useState(false);
const options = [
{ value: "marketing", label: "Marketing" },
{ value: "template", label: "Template" },
{ value: "development", label: "Development" },
];
const handleSelectChange = (value: string) => {
console.log("Selected value:", value);
};
return (
<ComponentCard title="Default Inputs">
<div className="space-y-6">
<div>
<Label>Input</Label>
<Input type="text" />
</div>
<div>
<Label>Input with Placeholder</Label>
<Input type="text" placeholder="info@gmail.com" />
</div>
<div>
<Label>Select Input</Label>
<Select
options={options}
placeholder="Select an option"
onChange={handleSelectChange}
className="dark:bg-dark-900"
/>
</div>
<div>
<Label>Password Input</Label>
<div className="relative">
<Input
type={showPassword ? "text" : "password"}
placeholder="Enter your password"
/>
<button
onClick={() => setShowPassword(!showPassword)}
className="absolute z-30 -translate-y-1/2 cursor-pointer right-4 top-1/2"
>
{showPassword ? (
<EyeIcon className="fill-gray-500 dark:fill-gray-400" />
) : (
<EyeCloseIcon className="fill-gray-500 dark:fill-gray-400" />
)}
</button>
</div>
</div>
<div>
<Label htmlFor="datePicker">Date Picker Input</Label>
<div className="relative">
<Input
type="date"
id="datePicker"
name="datePicker"
onChange={(e) => console.log(e.target.value)}
/>
<span className="absolute text-gray-500 -translate-y-1/2 pointer-events-none right-3 top-1/2 dark:text-gray-400">
<CalenderIcon />
</span>
</div>
</div>
<div>
<Label htmlFor="tm">Date Picker Input</Label>
<div className="relative">
<Input
type="time"
id="tm"
name="tm"
onChange={(e) => console.log(e.target.value)}
/>
<span className="absolute text-gray-500 -translate-y-1/2 pointer-events-none right-3 top-1/2 dark:text-gray-400">
<TimeIcon />
</span>
</div>
</div>
<div>
<Label htmlFor="tm">Input with Payment</Label>
<div className="relative">
<Input
type="text"
placeholder="Card number"
className="pl-[62px]"
/>
<span className="absolute left-0 top-1/2 flex h-11 w-[46px] -translate-y-1/2 items-center justify-center border-r border-gray-200 dark:border-gray-800">
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="6.25" cy="10" r="5.625" fill="#E80B26" />
<circle cx="13.75" cy="10" r="5.625" fill="#F59D31" />
<path
d="M10 14.1924C11.1508 13.1625 11.875 11.6657 11.875 9.99979C11.875 8.33383 11.1508 6.8371 10 5.80713C8.84918 6.8371 8.125 8.33383 8.125 9.99979C8.125 11.6657 8.84918 13.1625 10 14.1924Z"
fill="#FC6020"
/>
</svg>
</span>
</div>
</div>
</div>
</ComponentCard>
);
}

View File

@@ -0,0 +1,77 @@
import React from "react";
import ComponentCard from "../../common/ComponentCard";
import { useDropzone } from "react-dropzone";
// import Dropzone from "react-dropzone";
const DropzoneComponent: React.FC = () => {
const onDrop = (acceptedFiles: File[]) => {
console.log("Files dropped:", acceptedFiles);
// Handle file uploads here
};
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
accept: {
"image/png": [],
"image/jpeg": [],
"image/webp": [],
"image/svg+xml": [],
},
});
return (
<ComponentCard title="Dropzone">
<div className="transition border border-gray-300 border-dashed cursor-pointer dark:hover:border-brand-500 dark:border-gray-700 rounded-xl hover:border-brand-500">
<form
{...getRootProps()}
className={`dropzone rounded-xl border-dashed border-gray-300 p-7 lg:p-10
${
isDragActive
? "border-brand-500 bg-gray-100 dark:bg-gray-800"
: "border-gray-300 bg-gray-50 dark:border-gray-700 dark:bg-gray-900"
}
`}
id="demo-upload"
>
{/* Hidden Input */}
<input {...getInputProps()} />
<div className="dz-message flex flex-col items-center !m-0">
{/* Icon Container */}
<div className="mb-[22px] flex justify-center">
<div className="flex h-[68px] w-[68px] items-center justify-center rounded-full bg-gray-200 text-gray-700 dark:bg-gray-800 dark:text-gray-400">
<svg
className="fill-current"
width="29"
height="28"
viewBox="0 0 29 28"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M14.5019 3.91699C14.2852 3.91699 14.0899 4.00891 13.953 4.15589L8.57363 9.53186C8.28065 9.82466 8.2805 10.2995 8.5733 10.5925C8.8661 10.8855 9.34097 10.8857 9.63396 10.5929L13.7519 6.47752V18.667C13.7519 19.0812 14.0877 19.417 14.5019 19.417C14.9161 19.417 15.2519 19.0812 15.2519 18.667V6.48234L19.3653 10.5929C19.6583 10.8857 20.1332 10.8855 20.426 10.5925C20.7188 10.2995 20.7186 9.82463 20.4256 9.53184L15.0838 4.19378C14.9463 4.02488 14.7367 3.91699 14.5019 3.91699ZM5.91626 18.667C5.91626 18.2528 5.58047 17.917 5.16626 17.917C4.75205 17.917 4.41626 18.2528 4.41626 18.667V21.8337C4.41626 23.0763 5.42362 24.0837 6.66626 24.0837H22.3339C23.5766 24.0837 24.5839 23.0763 24.5839 21.8337V18.667C24.5839 18.2528 24.2482 17.917 23.8339 17.917C23.4197 17.917 23.0839 18.2528 23.0839 18.667V21.8337C23.0839 22.2479 22.7482 22.5837 22.3339 22.5837H6.66626C6.25205 22.5837 5.91626 22.2479 5.91626 21.8337V18.667Z"
/>
</svg>
</div>
</div>
{/* Text Content */}
<h4 className="mb-3 font-semibold text-gray-800 text-theme-xl dark:text-white/90">
{isDragActive ? "Drop Files Here" : "Drag & Drop Files Here"}
</h4>
<span className=" text-center mb-5 block w-full max-w-[290px] text-sm text-gray-700 dark:text-gray-400">
Drag and drop your PNG, JPG, WebP, SVG images here or browse
</span>
<span className="font-medium underline text-theme-sm text-brand-500">
Browse File
</span>
</div>
</form>
</div>
</ComponentCard>
);
};
export default DropzoneComponent;

View File

@@ -0,0 +1,22 @@
import React from "react";
import ComponentCard from "../../common/ComponentCard";
import FileInput from "../input/FileInput";
import Label from "../Label";
export default function FileInputExample() {
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (file) {
console.log("Selected file:", file.name);
}
};
return (
<ComponentCard title="File Input">
<div>
<Label>Upload file</Label>
<FileInput onChange={handleFileChange} className="custom-class" />
</div>
</ComponentCard>
);
}

View File

@@ -0,0 +1,55 @@
import React from "react";
import ComponentCard from "../../common/ComponentCard";
import Label from "../Label";
import Input from "../input/InputField";
import { EnvelopeIcon } from "../../../icons";
import PhoneInput from "../group-input/PhoneInput";
export default function InputGroup() {
const countries = [
{ code: "US", label: "+1" },
{ code: "GB", label: "+44" },
{ code: "CA", label: "+1" },
{ code: "AU", label: "+61" },
];
const handlePhoneNumberChange = (phoneNumber: string) => {
console.log("Updated phone number:", phoneNumber);
};
return (
<ComponentCard title="Input Group">
<div className="space-y-6">
<div>
<Label>Email</Label>
<div className="relative">
<Input
placeholder="info@gmail.com"
type="text"
className="pl-[62px]"
/>
<span className="absolute left-0 top-1/2 -translate-y-1/2 border-r border-gray-200 px-3.5 py-3 text-gray-500 dark:border-gray-800 dark:text-gray-400">
<EnvelopeIcon />
</span>
</div>
</div>
<div>
<Label>Phone</Label>
<PhoneInput
selectPosition="start"
countries={countries}
placeholder="+1 (555) 000-0000"
onChange={handlePhoneNumberChange}
/>
</div>{" "}
<div>
<Label>Phone</Label>
<PhoneInput
selectPosition="end"
countries={countries}
placeholder="+1 (555) 000-0000"
onChange={handlePhoneNumberChange}
/>
</div>
</div>
</ComponentCard>
);
}

View File

@@ -0,0 +1,69 @@
import React, { useState } from "react";
import ComponentCard from "../../common/ComponentCard";
import Input from "../input/InputField";
import Label from "../Label";
export default function InputStates() {
const [email, setEmail] = useState("");
const [error, setError] = useState(false);
// Simulate a validation check
const validateEmail = (value: string) => {
const isValidEmail =
/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value);
setError(!isValidEmail);
return isValidEmail;
};
const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
setEmail(value);
validateEmail(value);
};
return (
<ComponentCard
title="Input States"
desc="Validation styles for error, success and disabled states on form controls."
>
<div className="space-y-5 sm:space-y-6">
{/* Error Input */}
<div>
<Label>Email</Label>
<Input
type="email"
value={email}
error={error}
onChange={handleEmailChange}
placeholder="Enter your email"
hint={error ? "This is an invalid email address." : ""}
/>
</div>
{/* Success Input */}
<div>
<Label>Email</Label>
<Input
type="email"
value={email}
success={!error}
onChange={handleEmailChange}
placeholder="Enter your email"
hint={!error ? "Valid email!" : ""}
/>
</div>
{/* Disabled Input */}
<div>
<Label>Email</Label>
<Input
type="text"
value="disabled@example.com"
disabled={true}
placeholder="Disabled email"
hint="This field is disabled."
/>
</div>
</div>
</ComponentCard>
);
}

View File

@@ -0,0 +1,42 @@
import React, { useState } from "react";
import ComponentCard from "../../common/ComponentCard";
import Radio from "../input/Radio";
export default function RadioButtons() {
const [selectedValue, setSelectedValue] = useState<string>("option2");
const handleRadioChange = (value: string) => {
setSelectedValue(value);
};
return (
<ComponentCard title="Radio Buttons">
<div className="flex flex-wrap items-center gap-8">
<Radio
id="radio1"
name="group1"
value="option1"
checked={selectedValue === "option1"}
onChange={handleRadioChange}
label="Default"
/>
<Radio
id="radio2"
name="group1"
value="option2"
checked={selectedValue === "option2"}
onChange={handleRadioChange}
label="Selected"
/>
<Radio
id="radio3"
name="group1"
value="option3"
checked={selectedValue === "option3"}
onChange={handleRadioChange}
label="Disabled"
disabled={true}
/>
</div>
</ComponentCard>
);
}

View File

@@ -0,0 +1,52 @@
import React, { useState } from "react";
import ComponentCard from "../../common/ComponentCard";
import Label from "../Label";
import Select from "../Select";
import MultiSelect from "../MultiSelect";
export default function SelectInputs() {
const options = [
{ value: "marketing", label: "Marketing" },
{ value: "template", label: "Template" },
{ value: "development", label: "Development" },
];
const handleSelectChange = (value: string) => {
console.log("Selected value:", value);
};
const [selectedValues, setSelectedValues] = useState<string[]>([]);
const multiOptions = [
{ value: "1", text: "Option 1", selected: false },
{ value: "2", text: "Option 2", selected: false },
{ value: "3", text: "Option 3", selected: false },
{ value: "4", text: "Option 4", selected: false },
{ value: "5", text: "Option 5", selected: false },
];
return (
<ComponentCard title="Select Inputs">
<div className="space-y-6">
<div>
<Label>Select Input</Label>
<Select
options={options}
placeholder="Select Option"
onChange={handleSelectChange}
className="dark:bg-dark-900"
/>
</div>
<div>
<MultiSelect
label="Multiple Select Options"
options={multiOptions}
defaultSelected={["1", "3"]}
onChange={(values) => setSelectedValues(values)}
/>
</div>
<div>
<Label>Selected Values:</Label>
<p>{selectedValues.join(", ")}</p>
</div>
</div>
</ComponentCard>
);
}

View File

@@ -0,0 +1,42 @@
import React, { useState } from "react";
import ComponentCard from "../../common/ComponentCard";
import TextArea from "../input/TextArea";
import Label from "../Label";
export default function TextAreaInput() {
const [message, setMessage] = useState("");
const [messageTwo, setMessageTwo] = useState("");
return (
<ComponentCard title="Textarea input field">
<div className="space-y-6">
{/* Default TextArea */}
<div>
<Label>Description</Label>
<TextArea
value={message}
onChange={(value) => setMessage(value)}
rows={6}
/>
</div>
{/* Disabled TextArea */}
<div>
<Label>Description</Label>
<TextArea rows={6} disabled />
</div>
{/* Error TextArea */}
<div>
<Label>Description</Label>
<TextArea
rows={6}
value={messageTwo}
error
onChange={(value) => setMessageTwo(value)}
hint="Please enter a valid message."
/>
</div>
</div>
</ComponentCard>
);
}

View File

@@ -0,0 +1,41 @@
import React from "react";
import ComponentCard from "../../common/ComponentCard";
import Switch from "../switch/Switch";
export default function ToggleSwitch() {
const handleSwitchChange = (checked: boolean) => {
console.log("Switch is now:", checked ? "ON" : "OFF");
};
return (
<ComponentCard title="Toggle switch input">
<div className="flex gap-4">
<Switch
label="Default"
defaultChecked={true}
onChange={handleSwitchChange}
/>
<Switch
label="Checked"
defaultChecked={true}
onChange={handleSwitchChange}
/>
<Switch label="Disabled" disabled={true} />
</div>{" "}
<div className="flex gap-4">
<Switch
label="Default"
defaultChecked={true}
onChange={handleSwitchChange}
color="gray"
/>
<Switch
label="Checked"
defaultChecked={true}
onChange={handleSwitchChange}
color="gray"
/>
<Switch label="Disabled" disabled={true} color="gray" />
</div>
</ComponentCard>
);
}

View File

@@ -0,0 +1,140 @@
import React, { useState } from "react";
interface CountryCode {
code: string;
label: string;
}
interface PhoneInputProps {
countries: CountryCode[];
placeholder?: string;
onChange?: (phoneNumber: string) => void;
selectPosition?: "start" | "end"; // New prop for dropdown position
}
const PhoneInput: React.FC<PhoneInputProps> = ({
countries,
placeholder = "+1 (555) 000-0000",
onChange,
selectPosition = "start", // Default position is 'start'
}) => {
const [selectedCountry, setSelectedCountry] = useState<string>("US");
const [phoneNumber, setPhoneNumber] = useState<string>("+1");
const countryCodes: Record<string, string> = countries.reduce(
(acc, { code, label }) => ({ ...acc, [code]: label }),
{}
);
const handleCountryChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
const newCountry = e.target.value;
setSelectedCountry(newCountry);
setPhoneNumber(countryCodes[newCountry]);
if (onChange) {
onChange(countryCodes[newCountry]);
}
};
const handlePhoneNumberChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newPhoneNumber = e.target.value;
setPhoneNumber(newPhoneNumber);
if (onChange) {
onChange(newPhoneNumber);
}
};
return (
<div className="relative flex">
{/* Dropdown position: Start */}
{selectPosition === "start" && (
<div className="absolute">
<select
value={selectedCountry}
onChange={handleCountryChange}
className="appearance-none bg-none rounded-l-lg border-0 border-r border-gray-200 bg-transparent py-3 pl-3.5 pr-8 leading-tight text-gray-700 focus:border-brand-300 focus:outline-none focus:ring focus:ring-brand-500/10 dark:border-gray-800 dark:text-gray-400"
>
{countries.map((country) => (
<option
key={country.code}
value={country.code}
className="text-gray-700 dark:bg-gray-900 dark:text-gray-400"
>
{country.code}
</option>
))}
</select>
<div className="absolute inset-y-0 flex items-center text-gray-700 pointer-events-none bg-none right-3 dark:text-gray-400">
<svg
className="stroke-current"
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4.79175 7.396L10.0001 12.6043L15.2084 7.396"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</div>
</div>
)}
{/* Input field */}
<input
type="tel"
value={phoneNumber}
onChange={handlePhoneNumberChange}
placeholder={placeholder}
className={`dark:bg-dark-900 h-11 w-full ${
selectPosition === "start" ? "pl-[84px]" : "pr-[84px]"
} rounded-lg border border-gray-300 bg-transparent py-3 px-4 text-sm text-gray-800 shadow-theme-xs placeholder:text-gray-400 focus:border-brand-300 focus:outline-none focus:ring focus:ring-brand-500/10 dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30 dark:focus:border-brand-800`}
/>
{/* Dropdown position: End */}
{selectPosition === "end" && (
<div className="absolute right-0">
<select
value={selectedCountry}
onChange={handleCountryChange}
className="appearance-none bg-none rounded-r-lg border-0 border-l border-gray-200 bg-transparent py-3 pl-3.5 pr-8 leading-tight text-gray-700 focus:border-brand-300 focus:outline-none focus:ring focus:ring-brand-500/10 dark:border-gray-800 dark:text-gray-400"
>
{countries.map((country) => (
<option
key={country.code}
value={country.code}
className="text-gray-700 dark:bg-gray-900 dark:text-gray-400"
>
{country.code}
</option>
))}
</select>
<div className="absolute inset-y-0 flex items-center text-gray-700 pointer-events-none right-3 dark:text-gray-400">
<svg
className="stroke-current"
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4.79175 7.396L10.0001 12.6043L15.2084 7.396"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</div>
</div>
)}
</div>
);
};
export default PhoneInput;

View File

@@ -0,0 +1,43 @@
import React from "react";
interface CheckboxProps {
label?: string; // Optional label for the checkbox
checked: boolean; // Checked state
className?: string;
id?: string; // Unique ID for the checkbox
onChange: (checked: boolean) => void; // Change handler
disabled?: boolean; // Disabled state
}
const Checkbox: React.FC<CheckboxProps> = ({
label,
checked,
id,
onChange,
className = "",
disabled = false,
}) => {
return (
<label
className={`flex items-center space-x-3 cursor-pointer ${
disabled ? "cursor-not-allowed opacity-60" : ""
}`}
>
<input
id={id}
type="checkbox"
className={`w-4 h-4 ${className} dark:bg-gray-800 dark:border-gray-700 border-gray-300 dark:focus:outline-none rounded text-brand-500 dark:focus:ring-0 focus:ring-0 dark:focus:ring-transparent focus:ring-transparent focus:outline-none dark:focus:bg-outline-none focus:ring-offset-0`}
checked={checked}
onChange={(e) => onChange(e.target.checked)}
disabled={disabled}
/>
{label && (
<span className="font-medium text-gray-800 text-theme-sm dark:text-white">
{label}
</span>
)}
</label>
);
};
export default Checkbox;

View File

@@ -0,0 +1,18 @@
import React, { FC } from "react";
interface FileInputProps {
className?: string;
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
}
const FileInput: FC<FileInputProps> = ({ className, onChange }) => {
return (
<input
type="file"
className={`focus:border-ring-brand-300 h-11 w-full overflow-hidden rounded-lg border border-gray-300 bg-transparent text-sm text-gray-500 shadow-theme-xs transition-colors file:mr-5 file:border-collapse file:cursor-pointer file:rounded-l-lg file:border-0 file:border-r file:border-solid file:border-gray-200 file:bg-gray-50 file:py-3 file:pl-3.5 file:pr-3 file:text-sm file:text-gray-700 placeholder:text-gray-400 hover:file:bg-gray-100 focus:outline-none focus:file:ring-brand-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-400 dark:text-white/90 dark:file:border-gray-800 dark:file:bg-white/[0.03] dark:file:text-gray-400 dark:placeholder:text-gray-400 ${className}`}
onChange={onChange}
/>
);
};
export default FileInput;

View File

@@ -0,0 +1,84 @@
import React, { FC } from "react";
interface InputProps {
type?: "text" | "number" | "email" | "password" | "date" | "time" | string;
id?: string;
name?: string;
placeholder?: string;
value?: string | number;
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
className?: string;
min?: string;
max?: string;
step?: number;
disabled?: boolean;
success?: boolean;
error?: boolean;
hint?: string; // Optional hint text
}
const Input: FC<InputProps> = ({
type = "text",
id,
name,
placeholder,
value,
onChange,
className = "",
min,
max,
step,
disabled = false,
success = false,
error = false,
hint,
}) => {
// Determine input styles based on state (disabled, success, error)
let inputClasses = `h-11 w-full rounded-lg border appearance-none px-4 py-2.5 text-sm shadow-theme-xs placeholder:text-gray-400 focus:outline-none focus:ring dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30 dark:focus:border-brand-800 ${className}`;
// Add styles for the different states
if (disabled) {
inputClasses += ` text-gray-500 border-gray-300 cursor-not-allowed dark:bg-gray-800 dark:text-gray-400 dark:border-gray-700`;
} else if (error) {
inputClasses += ` text-error-800 border-error-500 focus:ring focus:ring-error-500/10 dark:text-error-400 dark:border-error-500`;
} else if (success) {
inputClasses += ` text-success-500 border-success-400 focus:ring-success-500/10 focus:border-success-300 dark:text-success-400 dark:border-success-500`;
} else {
inputClasses += ` bg-transparent text-gray-800 border-gray-300 focus:border-brand-300 focus:ring focus:ring-brand-500/10 dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:focus:border-brand-800`;
}
return (
<div className="relative">
<input
type={type}
id={id}
name={name}
placeholder={placeholder}
value={value}
onChange={onChange}
min={min}
max={max}
step={step}
disabled={disabled}
className={inputClasses}
/>
{/* Optional Hint Text */}
{hint && (
<p
className={`mt-1.5 text-xs ${
error
? "text-error-500"
: success
? "text-success-500"
: "text-gray-500"
}`}
>
{hint}
</p>
)}
</div>
);
};
export default Input;

View File

@@ -0,0 +1,65 @@
import React from "react";
interface RadioProps {
id: string; // Unique ID for the radio button
name: string; // Radio group name
value: string; // Value of the radio button
checked: boolean; // Whether the radio button is checked
label: string; // Label for the radio button
onChange: (value: string) => void; // Handler for value change
className?: string; // Optional additional classes
disabled?: boolean; // Optional disabled state for the radio button
}
const Radio: React.FC<RadioProps> = ({
id,
name,
value,
checked,
label,
onChange,
className = "",
disabled = false,
}) => {
return (
<label
htmlFor={id}
className={`relative flex cursor-pointer select-none items-center gap-3 text-sm font-medium ${
disabled
? "text-gray-300 dark:text-gray-600 cursor-not-allowed"
: "text-gray-700 dark:text-gray-400"
} ${className}`}
>
<input
id={id}
name={name}
type="radio"
value={value}
checked={checked}
onChange={() => !disabled && onChange(value)} // Prevent onChange when disabled
className="sr-only"
disabled={disabled} // Disable input
/>
<span
className={`flex h-5 w-5 items-center justify-center rounded-full border-[1.25px] ${
checked
? "border-brand-500 bg-brand-500"
: "bg-transparent border-gray-300 dark:border-gray-700"
} ${
disabled
? "bg-gray-100 dark:bg-gray-700 border-gray-200 dark:border-gray-700"
: ""
}`}
>
<span
className={`h-2 w-2 rounded-full bg-white ${
checked ? "block" : "hidden"
}`}
></span>
</span>
{label}
</label>
);
};
export default Radio;

View File

@@ -0,0 +1,59 @@
import React from "react";
interface RadioProps {
id: string; // Unique ID for the radio button
name: string; // Group name for the radio button
value: string; // Value of the radio button
checked: boolean; // Whether the radio button is checked
label: string; // Label text for the radio button
onChange: (value: string) => void; // Handler for when the radio button is toggled
className?: string; // Optional custom classes for styling
}
const RadioSm: React.FC<RadioProps> = ({
id,
name,
value,
checked,
label,
onChange,
className = "",
}) => {
return (
<label
htmlFor={id}
className={`flex cursor-pointer select-none items-center text-sm text-gray-500 dark:text-gray-400 ${className}`}
>
<span className="relative">
{/* Hidden Input */}
<input
type="radio"
id={id}
name={name}
value={value}
checked={checked}
onChange={() => onChange(value)}
className="sr-only"
/>
{/* Styled Radio Circle */}
<span
className={`mr-2 flex h-4 w-4 items-center justify-center rounded-full border ${
checked
? "border-brand-500 bg-brand-500"
: "bg-transparent border-gray-300 dark:border-gray-700"
}`}
>
{/* Inner Dot */}
<span
className={`h-1.5 w-1.5 rounded-full ${
checked ? "bg-white" : "bg-white dark:bg-[#1e2636]"
}`}
></span>
</span>
</span>
{label}
</label>
);
};
export default RadioSm;

View File

@@ -0,0 +1,63 @@
import React from "react";
interface TextareaProps {
placeholder?: string; // Placeholder text
rows?: number; // Number of rows
value?: string; // Current value
onChange?: (value: string) => void; // Change handler
className?: string; // Additional CSS classes
disabled?: boolean; // Disabled state
error?: boolean; // Error state
hint?: string; // Hint text to display
}
const TextArea: React.FC<TextareaProps> = ({
placeholder = "Enter your message", // Default placeholder
rows = 3, // Default number of rows
value = "", // Default value
onChange, // Callback for changes
className = "", // Additional custom styles
disabled = false, // Disabled state
error = false, // Error state
hint = "", // Default hint text
}) => {
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
if (onChange) {
onChange(e.target.value);
}
};
let textareaClasses = `w-full rounded-lg border px-4 py-2.5 text-sm shadow-theme-xs focus:outline-none ${className}`;
if (disabled) {
textareaClasses += ` bg-gray-100 opacity-50 text-gray-500 border-gray-300 cursor-not-allowed dark:bg-gray-800 dark:text-gray-400 dark:border-gray-700`;
} else if (error) {
textareaClasses += ` bg-transparent text-gray-400 border-gray-300 focus:border-error-300 focus:ring focus:ring-error-500/10 dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:focus:border-error-800`;
} else {
textareaClasses += ` bg-transparent text-gray-400 border-gray-300 focus:border-brand-300 focus:ring focus:ring-brand-500/10 dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:focus:border-brand-800`;
}
return (
<div className="relative">
<textarea
placeholder={placeholder}
rows={rows}
value={value}
onChange={handleChange}
disabled={disabled}
className={textareaClasses}
/>
{hint && (
<p
className={`mt-2 text-sm ${
error ? "text-error-500" : "text-gray-500 dark:text-gray-400"
}`}
>
{hint}
</p>
)}
</div>
);
};
export default TextArea;

View File

@@ -0,0 +1,72 @@
import React, { useState } from "react";
interface SwitchProps {
label: string;
defaultChecked?: boolean;
disabled?: boolean;
onChange?: (checked: boolean) => void;
color?: "blue" | "gray"; // Added prop to toggle color theme
}
const Switch: React.FC<SwitchProps> = ({
label,
defaultChecked = false,
disabled = false,
onChange,
color = "blue", // Default to blue color
}) => {
const [isChecked, setIsChecked] = useState(defaultChecked);
const handleToggle = () => {
if (disabled) return;
const newCheckedState = !isChecked;
setIsChecked(newCheckedState);
if (onChange) {
onChange(newCheckedState);
}
};
const switchColors =
color === "blue"
? {
background: isChecked
? "bg-brand-500 "
: "bg-gray-200 dark:bg-white/10", // Blue version
knob: isChecked
? "translate-x-full bg-white"
: "translate-x-0 bg-white",
}
: {
background: isChecked
? "bg-gray-800 dark:bg-white/10"
: "bg-gray-200 dark:bg-white/10", // Gray version
knob: isChecked
? "translate-x-full bg-white"
: "translate-x-0 bg-white",
};
return (
<label
className={`flex cursor-pointer select-none items-center gap-3 text-sm font-medium ${
disabled ? "text-gray-400" : "text-gray-700 dark:text-gray-400"
}`}
onClick={handleToggle} // Toggle when the label itself is clicked
>
<div className="relative">
<div
className={`block transition duration-150 ease-linear h-6 w-11 rounded-full ${
disabled
? "bg-gray-100 pointer-events-none dark:bg-gray-800"
: switchColors.background
}`}
></div>
<div
className={`absolute left-0.5 top-0.5 h-5 w-5 rounded-full shadow-theme-sm duration-150 ease-linear transform ${switchColors.knob}`}
></div>
</div>
{label}
</label>
);
};
export default Switch;

View File

@@ -0,0 +1,189 @@
import React, { useEffect, useRef, useState } from "react";
import { ThemeToggleButton } from "../common/ThemeToggleButton";
import { Link } from "react-router";
import NotificationDropdown from "./NotificationDropdown";
import UserDropdown from "./UserDropdown";
// Define the interface for the props
interface HeaderProps {
onClick?: () => void; // Optional function that takes no arguments and returns void
onToggle: () => void;
}
const Header: React.FC<HeaderProps> = ({ onClick, onToggle }) => {
const [isApplicationMenuOpen, setApplicationMenuOpen] = useState(false);
const toggleApplicationMenu = () => {
setApplicationMenuOpen(!isApplicationMenuOpen);
};
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if ((event.metaKey || event.ctrlKey) && event.key === "k") {
event.preventDefault();
inputRef.current?.focus();
}
};
document.addEventListener("keydown", handleKeyDown);
return () => {
document.removeEventListener("keydown", handleKeyDown);
};
}, []);
return (
<header className="sticky top-0 flex w-full bg-white border-gray-200 z-99999 dark:border-gray-800 dark:bg-gray-900 lg:border-b">
<div className="flex flex-col items-center justify-between flex-grow lg:flex-row lg:px-6">
<div className="flex items-center justify-between w-full gap-2 px-3 py-3 border-b border-gray-200 dark:border-gray-800 sm:gap-4 lg:justify-normal lg:border-b-0 lg:px-0 lg:py-4">
<button
className="block w-10 h-10 text-gray-500 lg:hidden dark:text-gray-400"
onClick={onToggle}
>
{/* Hamburger Icon */}
<svg
className={`block`}
width="16"
height="12"
viewBox="0 0 16 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M0.583252 1C0.583252 0.585788 0.919038 0.25 1.33325 0.25H14.6666C15.0808 0.25 15.4166 0.585786 15.4166 1C15.4166 1.41421 15.0808 1.75 14.6666 1.75L1.33325 1.75C0.919038 1.75 0.583252 1.41422 0.583252 1ZM0.583252 11C0.583252 10.5858 0.919038 10.25 1.33325 10.25L14.6666 10.25C15.0808 10.25 15.4166 10.5858 15.4166 11C15.4166 11.4142 15.0808 11.75 14.6666 11.75L1.33325 11.75C0.919038 11.75 0.583252 11.4142 0.583252 11ZM1.33325 5.25C0.919038 5.25 0.583252 5.58579 0.583252 6C0.583252 6.41421 0.919038 6.75 1.33325 6.75L7.99992 6.75C8.41413 6.75 8.74992 6.41421 8.74992 6C8.74992 5.58579 8.41413 5.25 7.99992 5.25L1.33325 5.25Z"
fill="currentColor"
/>
</svg>
<svg
className="hidden"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M6.21967 7.28131C5.92678 6.98841 5.92678 6.51354 6.21967 6.22065C6.51256 5.92775 6.98744 5.92775 7.28033 6.22065L11.999 10.9393L16.7176 6.22078C17.0105 5.92789 17.4854 5.92788 17.7782 6.22078C18.0711 6.51367 18.0711 6.98855 17.7782 7.28144L13.0597 12L17.7782 16.7186C18.0711 17.0115 18.0711 17.4863 17.7782 17.7792C17.4854 18.0721 17.0105 18.0721 16.7176 17.7792L11.999 13.0607L7.28033 17.7794C6.98744 18.0722 6.51256 18.0722 6.21967 17.7794C5.92678 17.4865 5.92678 17.0116 6.21967 16.7187L10.9384 12L6.21967 7.28131Z"
fill="currentColor"
/>
</svg>
{/* Cross Icon */}
</button>
<button
onClick={onClick}
className="items-center justify-center hidden w-10 h-10 text-gray-500 border-gray-200 rounded-lg z-99999 dark:border-gray-800 lg:flex dark:text-gray-400 lg:h-11 lg:w-11 lg:border"
>
<svg
className="hidden fill-current lg:block"
width="16"
height="12"
viewBox="0 0 16 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M0.583252 1C0.583252 0.585788 0.919038 0.25 1.33325 0.25H14.6666C15.0808 0.25 15.4166 0.585786 15.4166 1C15.4166 1.41421 15.0808 1.75 14.6666 1.75L1.33325 1.75C0.919038 1.75 0.583252 1.41422 0.583252 1ZM0.583252 11C0.583252 10.5858 0.919038 10.25 1.33325 10.25L14.6666 10.25C15.0808 10.25 15.4166 10.5858 15.4166 11C15.4166 11.4142 15.0808 11.75 14.6666 11.75L1.33325 11.75C0.919038 11.75 0.583252 11.4142 0.583252 11ZM1.33325 5.25C0.919038 5.25 0.583252 5.58579 0.583252 6C0.583252 6.41421 0.919038 6.75 1.33325 6.75L7.99992 6.75C8.41413 6.75 8.74992 6.41421 8.74992 6C8.74992 5.58579 8.41413 5.25 7.99992 5.25L1.33325 5.25Z"
fill=""
/>
</svg>
</button>
<Link to="/" className="lg:hidden">
<img
className="dark:hidden"
src="./images/logo/logo.svg"
alt="Logo"
/>
<img
className="hidden dark:block"
src="./images/logo/logo-dark.svg"
alt="Logo"
/>
</Link>
<button
onClick={toggleApplicationMenu}
className="flex items-center justify-center w-10 h-10 text-gray-700 rounded-lg z-99999 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-800 lg:hidden"
>
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M5.99902 10.4951C6.82745 10.4951 7.49902 11.1667 7.49902 11.9951V12.0051C7.49902 12.8335 6.82745 13.5051 5.99902 13.5051C5.1706 13.5051 4.49902 12.8335 4.49902 12.0051V11.9951C4.49902 11.1667 5.1706 10.4951 5.99902 10.4951ZM17.999 10.4951C18.8275 10.4951 19.499 11.1667 19.499 11.9951V12.0051C19.499 12.8335 18.8275 13.5051 17.999 13.5051C17.1706 13.5051 16.499 12.8335 16.499 12.0051V11.9951C16.499 11.1667 17.1706 10.4951 17.999 10.4951ZM13.499 11.9951C13.499 11.1667 12.8275 10.4951 11.999 10.4951C11.1706 10.4951 10.499 11.1667 10.499 11.9951V12.0051C10.499 12.8335 11.1706 13.5051 11.999 13.5051C12.8275 13.5051 13.499 12.8335 13.499 12.0051V11.9951Z"
fill="currentColor"
/>
</svg>
</button>
<div className="hidden lg:block">
<form>
<div className="relative">
<span className="absolute -translate-y-1/2 pointer-events-none left-4 top-1/2">
<svg
className="fill-gray-500 dark:fill-gray-400"
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.04175 9.37363C3.04175 5.87693 5.87711 3.04199 9.37508 3.04199C12.8731 3.04199 15.7084 5.87693 15.7084 9.37363C15.7084 12.8703 12.8731 15.7053 9.37508 15.7053C5.87711 15.7053 3.04175 12.8703 3.04175 9.37363ZM9.37508 1.54199C5.04902 1.54199 1.54175 5.04817 1.54175 9.37363C1.54175 13.6991 5.04902 17.2053 9.37508 17.2053C11.2674 17.2053 13.003 16.5344 14.357 15.4176L17.177 18.238C17.4699 18.5309 17.9448 18.5309 18.2377 18.238C18.5306 17.9451 18.5306 17.4703 18.2377 17.1774L15.418 14.3573C16.5365 13.0033 17.2084 11.2669 17.2084 9.37363C17.2084 5.04817 13.7011 1.54199 9.37508 1.54199Z"
fill=""
/>
</svg>
</span>
<input
ref={inputRef}
type="text"
placeholder="Search or type command..."
aria-label="Search or type command"
className="dark:bg-dark-900 h-11 w-full rounded-lg border border-gray-200 bg-transparent py-2.5 pl-12 pr-14 text-sm text-gray-800 shadow-theme-xs placeholder:text-gray-400 focus:border-brand-300 focus:outline-none focus:ring focus:ring-brand-500/10 dark:border-gray-800 dark:bg-gray-900 dark:bg-white/[0.03] dark:text-white/90 dark:placeholder:text-white/30 dark:focus:border-brand-800 xl:w-[430px]"
/>
<button
type="button"
aria-label="Search shortcut key: Command + K"
className="absolute right-2.5 top-1/2 inline-flex -translate-y-1/2 items-center gap-0.5 rounded-lg border border-gray-200 bg-gray-50 px-[7px] py-[4.5px] text-xs -tracking-[0.2px] text-gray-500 dark:border-gray-800 dark:bg-white/[0.03] dark:text-gray-400 focus:ring-2 focus:ring-brand-500 focus:outline-none"
>
<span> </span>
<span> K </span>
</button>
</div>
</form>
</div>
</div>
<div
className={`${
isApplicationMenuOpen ? "flex" : "hidden"
} items-center justify-between w-full gap-4 px-5 py-4 lg:flex shadow-theme-md lg:justify-end lg:px-0 lg:shadow-none`}
>
<div className="flex items-center gap-2 2xsm:gap-3">
{/* <!-- Dark Mode Toggler --> */}
<ThemeToggleButton />
{/* <!-- Dark Mode Toggler --> */}
<NotificationDropdown />
{/* <!-- Notification Menu Area --> */}
</div>
{/* <!-- User Area --> */}
<UserDropdown />
</div>
</div>
</header>
);
};
export default Header;

View File

@@ -0,0 +1,380 @@
import React, { useState } from "react";
import { Dropdown } from "../ui/dropdown/Dropdown";
import { DropdownItem } from "../ui/dropdown/DropdownItem";
import { Link } from "react-router";
export default function NotificationDropdown() {
const [isOpen, setIsOpen] = useState(false);
const [notifying, setNotifying] = useState(true);
function toggleDropdown() {
setIsOpen(!isOpen);
}
function closeDropdown() {
setIsOpen(false);
}
const handleClick = () => {
toggleDropdown();
setNotifying(false);
};
return (
<div className="relative">
<button
className="relative flex items-center justify-center text-gray-500 transition-colors bg-white border border-gray-200 rounded-full hover:text-gray-700 h-11 w-11 hover:bg-gray-100 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-white"
onClick={handleClick}
>
<span
className={`absolute right-0 top-0.5 z-10 h-2 w-2 rounded-full bg-orange-400 ${
!notifying ? "hidden" : "flex"
}`}
>
<span className="absolute inline-flex w-full h-full bg-orange-400 rounded-full opacity-75 animate-ping"></span>
</span>
<svg
className="fill-current"
width="20"
height="20"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M10.75 2.29248C10.75 1.87827 10.4143 1.54248 10 1.54248C9.58583 1.54248 9.25004 1.87827 9.25004 2.29248V2.83613C6.08266 3.20733 3.62504 5.9004 3.62504 9.16748V14.4591H3.33337C2.91916 14.4591 2.58337 14.7949 2.58337 15.2091C2.58337 15.6234 2.91916 15.9591 3.33337 15.9591H4.37504H15.625H16.6667C17.0809 15.9591 17.4167 15.6234 17.4167 15.2091C17.4167 14.7949 17.0809 14.4591 16.6667 14.4591H16.375V9.16748C16.375 5.9004 13.9174 3.20733 10.75 2.83613V2.29248ZM14.875 14.4591V9.16748C14.875 6.47509 12.6924 4.29248 10 4.29248C7.30765 4.29248 5.12504 6.47509 5.12504 9.16748V14.4591H14.875ZM8.00004 17.7085C8.00004 18.1228 8.33583 18.4585 8.75004 18.4585H11.25C11.6643 18.4585 12 18.1228 12 17.7085C12 17.2943 11.6643 16.9585 11.25 16.9585H8.75004C8.33583 16.9585 8.00004 17.2943 8.00004 17.7085Z"
fill="currentColor"
/>
</svg>
</button>
<Dropdown
isOpen={isOpen}
onClose={closeDropdown}
className="absolute -right-[240px] mt-[17px] flex h-[480px] w-[350px] flex-col rounded-2xl border border-gray-200 bg-white p-3 shadow-theme-lg dark:border-gray-800 dark:bg-gray-dark sm:w-[361px] lg:right-0"
>
<div className="flex items-center justify-between pb-3 mb-3 border-b border-gray-100 dark:border-gray-700">
<h5 className="text-lg font-semibold text-gray-800 dark:text-gray-200">
Notification
</h5>
<button
onClick={toggleDropdown}
className="text-gray-500 transition dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200"
>
<svg
className="fill-current"
width="24"
height="24"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M6.21967 7.28131C5.92678 6.98841 5.92678 6.51354 6.21967 6.22065C6.51256 5.92775 6.98744 5.92775 7.28033 6.22065L11.999 10.9393L16.7176 6.22078C17.0105 5.92789 17.4854 5.92788 17.7782 6.22078C18.0711 6.51367 18.0711 6.98855 17.7782 7.28144L13.0597 12L17.7782 16.7186C18.0711 17.0115 18.0711 17.4863 17.7782 17.7792C17.4854 18.0721 17.0105 18.0721 16.7176 17.7792L11.999 13.0607L7.28033 17.7794C6.98744 18.0722 6.51256 18.0722 6.21967 17.7794C5.92678 17.4865 5.92678 17.0116 6.21967 16.7187L10.9384 12L6.21967 7.28131Z"
fill="currentColor"
/>
</svg>
</button>
</div>
<ul className="flex flex-col h-auto overflow-y-auto custom-scrollbar">
{/* Example notification items */}
<li>
<DropdownItem
onItemClick={closeDropdown}
className="flex gap-3 rounded-lg border-b border-gray-100 p-3 px-4.5 py-3 hover:bg-gray-100 dark:border-gray-800 dark:hover:bg-white/5"
>
<span className="relative block w-full h-10 rounded-full z-1 max-w-10">
<img
width={40}
height={40}
src="/images/user/user-02.jpg"
alt="User"
className="w-full overflow-hidden rounded-full"
/>
<span className="absolute bottom-0 right-0 z-10 h-2.5 w-full max-w-2.5 rounded-full border-[1.5px] border-white bg-success-500 dark:border-gray-900"></span>
</span>
<span className="block">
<span className="mb-1.5 block text-theme-sm text-gray-500 dark:text-gray-400 space-x-1">
<span className="font-medium text-gray-800 dark:text-white/90 ">
Terry Franci
</span>
<span>requests permission to change</span>
<span className="font-medium text-gray-800 dark:text-white/90">
Project - Nganter App
</span>
</span>
<span className="flex items-center gap-2 text-gray-500 text-theme-xs dark:text-gray-400">
<span>Project</span>
<span className="w-1 h-1 bg-gray-400 rounded-full"></span>
<span>5 min ago</span>
</span>
</span>
</DropdownItem>
</li>
<li>
<DropdownItem
onItemClick={closeDropdown}
className="flex gap-3 rounded-lg border-b border-gray-100 p-3 px-4.5 py-3 hover:bg-gray-100 dark:border-gray-800 dark:hover:bg-white/5"
>
<span className="relative block w-full h-10 rounded-full z-1 max-w-10">
<img
width={40}
height={40}
src="/images/user/user-03.jpg"
alt="User"
className="w-full overflow-hidden rounded-full"
/>
<span className="absolute bottom-0 right-0 z-10 h-2.5 w-full max-w-2.5 rounded-full border-[1.5px] border-white bg-success-500 dark:border-gray-900"></span>
</span>
<span className="block">
<span className="mb-1.5 block text-theme-sm text-gray-500 dark:text-gray-400 space-x-1">
<span className="font-medium text-gray-800 dark:text-white/90">
Alena Franci
</span>
<span>requests permission to change</span>
<span className="font-medium text-gray-800 dark:text-white/90">
Project - Nganter App
</span>
</span>
<span className="flex items-center gap-2 text-gray-500 text-theme-xs dark:text-gray-400">
<span>Project</span>
<span className="w-1 h-1 bg-gray-400 rounded-full"></span>
<span>8 min ago</span>
</span>
</span>
</DropdownItem>
</li>
<li>
<DropdownItem
onItemClick={closeDropdown}
className="flex gap-3 rounded-lg border-b border-gray-100 p-3 px-4.5 py-3 hover:bg-gray-100 dark:border-gray-800 dark:hover:bg-white/5"
>
<span className="relative block w-full h-10 rounded-full z-1 max-w-10">
<img
width={40}
height={40}
src="/images/user/user-04.jpg"
alt="User"
className="w-full overflow-hidden rounded-full"
/>
<span className="absolute bottom-0 right-0 z-10 h-2.5 w-full max-w-2.5 rounded-full border-[1.5px] border-white bg-success-500 dark:border-gray-900"></span>
</span>
<span className="block">
<span className="mb-1.5 block space-x-1 text-theme-sm text-gray-500 dark:text-gray-400">
<span className="font-medium text-gray-800 dark:text-white/90">
Jocelyn Kenter
</span>
<span>requests permission to change</span>
<span className="font-medium text-gray-800 dark:text-white/90">
Project - Nganter App
</span>
</span>
<span className="flex items-center gap-2 text-gray-500 text-theme-xs dark:text-gray-400">
<span>Project</span>
<span className="w-1 h-1 bg-gray-400 rounded-full"></span>
<span>15 min ago</span>
</span>
</span>
</DropdownItem>
</li>
<li>
<DropdownItem
onItemClick={closeDropdown}
className="flex gap-3 rounded-lg border-b border-gray-100 p-3 px-4.5 py-3 hover:bg-gray-100 dark:border-gray-800 dark:hover:bg-white/5"
href="/"
>
<span className="relative block w-full h-10 rounded-full z-1 max-w-10">
<img
width={40}
height={40}
src="/images/user/user-05.jpg"
alt="User"
className="w-full overflow-hidden rounded-full"
/>
<span className="absolute bottom-0 right-0 z-10 h-2.5 w-full max-w-2.5 rounded-full border-[1.5px] border-white bg-error-500 dark:border-gray-900"></span>
</span>
<span className="block">
<span className="mb-1.5 block text-theme-sm text-gray-500 dark:text-gray-400 space-x-1">
<span className="font-medium text-gray-800 dark:text-white/90">
Brandon Philips
</span>
<span> requests permission to change</span>
<span className="font-medium text-gray-800 dark:text-white/90">
Project - Nganter App
</span>
</span>
<span className="flex items-center gap-2 text-gray-500 text-theme-xs dark:text-gray-400">
<span>Project</span>
<span className="w-1 h-1 bg-gray-400 rounded-full"></span>
<span>1 hr ago</span>
</span>
</span>
</DropdownItem>
</li>
<li>
<DropdownItem
className="flex gap-3 rounded-lg border-b border-gray-100 p-3 px-4.5 py-3 hover:bg-gray-100 dark:border-gray-800 dark:hover:bg-white/5"
onItemClick={closeDropdown}
>
<span className="relative block w-full h-10 rounded-full z-1 max-w-10">
<img
width={40}
height={40}
src="/images/user/user-02.jpg"
alt="User"
className="w-full overflow-hidden rounded-full"
/>
<span className="absolute bottom-0 right-0 z-10 h-2.5 w-full max-w-2.5 rounded-full border-[1.5px] border-white bg-success-500 dark:border-gray-900"></span>
</span>
<span className="block">
<span className="mb-1.5 block text-theme-sm text-gray-500 dark:text-gray-400 space-x-1">
<span className="font-medium text-gray-800 dark:text-white/90">
Terry Franci
</span>
<span> requests permission to change</span>
<span className="font-medium text-gray-800 dark:text-white/90">
Project - Nganter App
</span>
</span>
<span className="flex items-center gap-2 text-gray-500 text-theme-xs dark:text-gray-400">
<span>Project</span>
<span className="w-1 h-1 bg-gray-400 rounded-full"></span>
<span>5 min ago</span>
</span>
</span>
</DropdownItem>
</li>
<li>
<DropdownItem
onItemClick={closeDropdown}
className="flex gap-3 rounded-lg border-b border-gray-100 p-3 px-4.5 py-3 hover:bg-gray-100 dark:border-gray-800 dark:hover:bg-white/5"
>
<span className="relative block w-full h-10 rounded-full z-1 max-w-10">
<img
width={40}
height={40}
src="/images/user/user-03.jpg"
alt="User"
className="w-full overflow-hidden rounded-full"
/>
<span className="absolute bottom-0 right-0 z-10 h-2.5 w-full max-w-2.5 rounded-full border-[1.5px] border-white bg-success-500 dark:border-gray-900"></span>
</span>
<span className="block">
<span className="mb-1.5 block text-theme-sm text-gray-500 dark:text-gray-400 space-x-1">
<span className="font-medium text-gray-800 dark:text-white/90">
Alena Franci
</span>
<span> requests permission to change</span>
<span className="font-medium text-gray-800 dark:text-white/90">
Project - Nganter App
</span>
</span>
<span className="flex items-center gap-2 text-gray-500 text-theme-xs dark:text-gray-400">
<span>Project</span>
<span className="w-1 h-1 bg-gray-400 rounded-full"></span>
<span>8 min ago</span>
</span>
</span>
</DropdownItem>
</li>
<li>
<DropdownItem
onItemClick={closeDropdown}
className="flex gap-3 rounded-lg border-b border-gray-100 p-3 px-4.5 py-3 hover:bg-gray-100 dark:border-gray-800 dark:hover:bg-white/5"
>
<span className="relative block w-full h-10 rounded-full z-1 max-w-10">
<img
width={40}
height={40}
src="/images/user/user-04.jpg"
alt="User"
className="w-full overflow-hidden rounded-full"
/>
<span className="absolute bottom-0 right-0 z-10 h-2.5 w-full max-w-2.5 rounded-full border-[1.5px] border-white bg-success-500 dark:border-gray-900"></span>
</span>
<span className="block">
<span className="mb-1.5 block text-theme-sm text-gray-500 dark:text-gray-400 space-x-1">
<span className="font-medium text-gray-800 dark:text-white/90">
Jocelyn Kenter
</span>
<span> requests permission to change</span>
<span className="font-medium text-gray-800 dark:text-white/90">
Project - Nganter App
</span>
</span>
<span className="flex items-center gap-2 text-gray-500 text-theme-xs dark:text-gray-400">
<span>Project</span>
<span className="w-1 h-1 bg-gray-400 rounded-full"></span>
<span>15 min ago</span>
</span>
</span>
</DropdownItem>
</li>
<li>
<DropdownItem
onItemClick={closeDropdown}
className="flex gap-3 rounded-lg border-b border-gray-100 p-3 px-4.5 py-3 hover:bg-gray-100 dark:border-gray-800 dark:hover:bg-white/5"
>
<span className="relative block w-full h-10 rounded-full z-1 max-w-10">
<img
width={40}
height={40}
src="/images/user/user-05.jpg"
alt="User"
className="overflow-hidden rounded-full"
/>
<span className="absolute bottom-0 right-0 z-10 h-2.5 w-full max-w-2.5 rounded-full border-[1.5px] border-white bg-error-500 dark:border-gray-900"></span>
</span>
<span className="block">
<span className="mb-1.5 block text-theme-sm text-gray-500 dark:text-gray-400 space-x-1">
<span className="font-medium text-gray-800 dark:text-white/90">
Brandon Philips
</span>
<span> requests permission to change</span>
<span className="font-medium text-gray-800 dark:text-white/90">
Project - Nganter App
</span>
</span>
<span className="flex items-center gap-2 text-gray-500 text-theme-xs dark:text-gray-400">
<span>Project</span>
<span className="w-1 h-1 bg-gray-400 rounded-full"></span>
<span>1 hr ago</span>
</span>
</span>
</DropdownItem>
</li>
{/* Add more items as needed */}
</ul>
<Link
to="/"
className="block px-4 py-2 mt-3 text-sm font-medium text-center text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-100 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700"
>
View All Notifications
</Link>
</Dropdown>
</div>
);
}

View File

@@ -0,0 +1,163 @@
import React, { useState } from "react";
import { DropdownItem } from "../ui/dropdown/DropdownItem";
import { Dropdown } from "../ui/dropdown/Dropdown";
import { Link } from "react-router";
export default function UserDropdown() {
const [isOpen, setIsOpen] = useState(false);
function toggleDropdown() {
setIsOpen(!isOpen);
}
function closeDropdown() {
setIsOpen(false);
}
return (
<div className="relative">
<button
onClick={toggleDropdown}
className="flex items-center text-gray-700 dark:text-gray-400"
>
<span className="mr-3 overflow-hidden rounded-full h-11 w-11">
<img src="/images/user/owner.jpg" alt="User" />
</span>
<span className="block mr-1 font-medium text-theme-sm">Musharof</span>
<svg
className={`stroke-gray-500 dark:stroke-gray-400 transition-transform duration-200 ${
isOpen ? "rotate-180" : ""
}`}
width="18"
height="20"
viewBox="0 0 18 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4.3125 8.65625L9 13.3437L13.6875 8.65625"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</button>
<Dropdown
isOpen={isOpen}
onClose={closeDropdown}
className="absolute right-0 mt-[17px] flex w-[260px] flex-col rounded-2xl border border-gray-200 bg-white p-3 shadow-theme-lg dark:border-gray-800 dark:bg-gray-dark"
>
<div>
<span className="block font-medium text-gray-700 text-theme-sm dark:text-gray-400">
Musharof Chowdhury
</span>
<span className="mt-0.5 block text-theme-xs text-gray-500 dark:text-gray-400">
randomuser@pimjo.com
</span>
</div>
<ul className="flex flex-col gap-1 pt-4 pb-3 border-b border-gray-200 dark:border-gray-800">
<li>
<DropdownItem
onItemClick={closeDropdown}
tag="a"
href="/profile"
className="flex items-center gap-3 px-3 py-2 font-medium text-gray-700 rounded-lg group text-theme-sm hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-300"
>
<svg
className="fill-gray-500 group-hover:fill-gray-700 dark:fill-gray-400 dark:group-hover:fill-gray-300"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M12 3.5C7.30558 3.5 3.5 7.30558 3.5 12C3.5 14.1526 4.3002 16.1184 5.61936 17.616C6.17279 15.3096 8.24852 13.5955 10.7246 13.5955H13.2746C15.7509 13.5955 17.8268 15.31 18.38 17.6167C19.6996 16.119 20.5 14.153 20.5 12C20.5 7.30558 16.6944 3.5 12 3.5ZM17.0246 18.8566V18.8455C17.0246 16.7744 15.3457 15.0955 13.2746 15.0955H10.7246C8.65354 15.0955 6.97461 16.7744 6.97461 18.8455V18.856C8.38223 19.8895 10.1198 20.5 12 20.5C13.8798 20.5 15.6171 19.8898 17.0246 18.8566ZM2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12ZM11.9991 7.25C10.8847 7.25 9.98126 8.15342 9.98126 9.26784C9.98126 10.3823 10.8847 11.2857 11.9991 11.2857C13.1135 11.2857 14.0169 10.3823 14.0169 9.26784C14.0169 8.15342 13.1135 7.25 11.9991 7.25ZM8.48126 9.26784C8.48126 7.32499 10.0563 5.75 11.9991 5.75C13.9419 5.75 15.5169 7.32499 15.5169 9.26784C15.5169 11.2107 13.9419 12.7857 11.9991 12.7857C10.0563 12.7857 8.48126 11.2107 8.48126 9.26784Z"
fill=""
/>
</svg>
Edit profile
</DropdownItem>
</li>
<li>
<DropdownItem
onItemClick={closeDropdown}
tag="a"
href="/profile"
className="flex items-center gap-3 px-3 py-2 font-medium text-gray-700 rounded-lg group text-theme-sm hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-300"
>
<svg
className="fill-gray-500 group-hover:fill-gray-700 dark:fill-gray-400 dark:group-hover:fill-gray-300"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M10.4858 3.5L13.5182 3.5C13.9233 3.5 14.2518 3.82851 14.2518 4.23377C14.2518 5.9529 16.1129 7.02795 17.602 6.1682C17.9528 5.96567 18.4014 6.08586 18.6039 6.43667L20.1203 9.0631C20.3229 9.41407 20.2027 9.86286 19.8517 10.0655C18.3625 10.9253 18.3625 13.0747 19.8517 13.9345C20.2026 14.1372 20.3229 14.5859 20.1203 14.9369L18.6039 17.5634C18.4013 17.9142 17.9528 18.0344 17.602 17.8318C16.1129 16.9721 14.2518 18.0471 14.2518 19.7663C14.2518 20.1715 13.9233 20.5 13.5182 20.5H10.4858C10.0804 20.5 9.75182 20.1714 9.75182 19.766C9.75182 18.0461 7.88983 16.9717 6.40067 17.8314C6.04945 18.0342 5.60037 17.9139 5.39767 17.5628L3.88167 14.937C3.67903 14.586 3.79928 14.1372 4.15026 13.9346C5.63949 13.0748 5.63946 10.9253 4.15025 10.0655C3.79926 9.86282 3.67901 9.41401 3.88165 9.06303L5.39764 6.43725C5.60034 6.08617 6.04943 5.96581 6.40065 6.16858C7.88982 7.02836 9.75182 5.9539 9.75182 4.23399C9.75182 3.82862 10.0804 3.5 10.4858 3.5ZM13.5182 2L10.4858 2C9.25201 2 8.25182 3.00019 8.25182 4.23399C8.25182 4.79884 7.64013 5.15215 7.15065 4.86955C6.08213 4.25263 4.71559 4.61859 4.0986 5.68725L2.58261 8.31303C1.96575 9.38146 2.33183 10.7477 3.40025 11.3645C3.88948 11.647 3.88947 12.3531 3.40026 12.6355C2.33184 13.2524 1.96578 14.6186 2.58263 15.687L4.09863 18.3128C4.71562 19.3814 6.08215 19.7474 7.15067 19.1305C7.64015 18.8479 8.25182 19.2012 8.25182 19.766C8.25182 20.9998 9.25201 22 10.4858 22H13.5182C14.7519 22 15.7518 20.9998 15.7518 19.7663C15.7518 19.2015 16.3632 18.8487 16.852 19.1309C17.9202 19.7476 19.2862 19.3816 19.9029 18.3134L21.4193 15.6869C22.0361 14.6185 21.6701 13.2523 20.6017 12.6355C20.1125 12.3531 20.1125 11.647 20.6017 11.3645C21.6701 10.7477 22.0362 9.38152 21.4193 8.3131L19.903 5.68667C19.2862 4.61842 17.9202 4.25241 16.852 4.86917C16.3632 5.15138 15.7518 4.79856 15.7518 4.23377C15.7518 3.00024 14.7519 2 13.5182 2ZM9.6659 11.9999C9.6659 10.7103 10.7113 9.66493 12.0009 9.66493C13.2905 9.66493 14.3359 10.7103 14.3359 11.9999C14.3359 13.2895 13.2905 14.3349 12.0009 14.3349C10.7113 14.3349 9.6659 13.2895 9.6659 11.9999ZM12.0009 8.16493C9.88289 8.16493 8.1659 9.88191 8.1659 11.9999C8.1659 14.1179 9.88289 15.8349 12.0009 15.8349C14.1189 15.8349 15.8359 14.1179 15.8359 11.9999C15.8359 9.88191 14.1189 8.16493 12.0009 8.16493Z"
fill=""
/>
</svg>
Account settings
</DropdownItem>
</li>
<li>
<DropdownItem
onItemClick={closeDropdown}
tag="a"
href="/profile"
className="flex items-center gap-3 px-3 py-2 font-medium text-gray-700 rounded-lg group text-theme-sm hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-300"
>
<svg
className="fill-gray-500 group-hover:fill-gray-700 dark:fill-gray-400 dark:group-hover:fill-gray-300"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.5 12C3.5 7.30558 7.30558 3.5 12 3.5C16.6944 3.5 20.5 7.30558 20.5 12C20.5 16.6944 16.6944 20.5 12 20.5C7.30558 20.5 3.5 16.6944 3.5 12ZM12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2ZM11.0991 7.52507C11.0991 8.02213 11.5021 8.42507 11.9991 8.42507H12.0001C12.4972 8.42507 12.9001 8.02213 12.9001 7.52507C12.9001 7.02802 12.4972 6.62507 12.0001 6.62507H11.9991C11.5021 6.62507 11.0991 7.02802 11.0991 7.52507ZM12.0001 17.3714C11.5859 17.3714 11.2501 17.0356 11.2501 16.6214V10.9449C11.2501 10.5307 11.5859 10.1949 12.0001 10.1949C12.4143 10.1949 12.7501 10.5307 12.7501 10.9449V16.6214C12.7501 17.0356 12.4143 17.3714 12.0001 17.3714Z"
fill=""
/>
</svg>
Support
</DropdownItem>
</li>
</ul>
<Link
to="/signin"
className="flex items-center gap-3 px-3 py-2 mt-3 font-medium text-gray-700 rounded-lg group text-theme-sm hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-300"
>
<svg
className="fill-gray-500 group-hover:fill-gray-700 dark:group-hover:fill-gray-300"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M15.1007 19.247C14.6865 19.247 14.3507 18.9112 14.3507 18.497L14.3507 14.245H12.8507V18.497C12.8507 19.7396 13.8581 20.747 15.1007 20.747H18.5007C19.7434 20.747 20.7507 19.7396 20.7507 18.497L20.7507 5.49609C20.7507 4.25345 19.7433 3.24609 18.5007 3.24609H15.1007C13.8581 3.24609 12.8507 4.25345 12.8507 5.49609V9.74501L14.3507 9.74501V5.49609C14.3507 5.08188 14.6865 4.74609 15.1007 4.74609L18.5007 4.74609C18.9149 4.74609 19.2507 5.08188 19.2507 5.49609L19.2507 18.497C19.2507 18.9112 18.9149 19.247 18.5007 19.247H15.1007ZM3.25073 11.9984C3.25073 12.2144 3.34204 12.4091 3.48817 12.546L8.09483 17.1556C8.38763 17.4485 8.86251 17.4487 9.15549 17.1559C9.44848 16.8631 9.44863 16.3882 9.15583 16.0952L5.81116 12.7484L16.0007 12.7484C16.4149 12.7484 16.7507 12.4127 16.7507 11.9984C16.7507 11.5842 16.4149 11.2484 16.0007 11.2484L5.81528 11.2484L9.15585 7.90554C9.44864 7.61255 9.44847 7.13767 9.15547 6.84488C8.86248 6.55209 8.3876 6.55226 8.09481 6.84525L3.52309 11.4202C3.35673 11.5577 3.25073 11.7657 3.25073 11.9984Z"
fill=""
/>
</svg>
Sign out
</Link>
</Dropdown>
</div>
);
}

View File

@@ -0,0 +1,215 @@
import React from "react";
import {
Table,
TableBody,
TableCell,
TableHeader,
TableRow,
} from "../ui/table";
import Badge from "../ui/badge/Badge";
interface Order {
id: number;
user: {
image: string;
name: string;
role: string;
};
projectName: string;
team: {
images: string[];
};
status: string;
budget: string;
}
// Define the table data using the interface
const tableData: Order[] = [
{
id: 1,
user: {
image: "/images/user/user-17.jpg",
name: "Lindsey Curtis",
role: "Web Designer",
},
projectName: "Agency Website",
team: {
images: [
"/images/user/user-22.jpg",
"/images/user/user-23.jpg",
"/images/user/user-24.jpg",
],
},
budget: "3.9K",
status: "Active",
},
{
id: 2,
user: {
image: "/images/user/user-18.jpg",
name: "Kaiya George",
role: "Project Manager",
},
projectName: "Technology",
team: {
images: ["/images/user/user-25.jpg", "/images/user/user-26.jpg"],
},
budget: "24.9K",
status: "Pending",
},
{
id: 3,
user: {
image: "/images/user/user-17.jpg",
name: "Zain Geidt",
role: "Content Writing",
},
projectName: "Blog Writing",
team: {
images: ["/images/user/user-27.jpg"],
},
budget: "12.7K",
status: "Active",
},
{
id: 4,
user: {
image: "/images/user/user-20.jpg",
name: "Abram Schleifer",
role: "Digital Marketer",
},
projectName: "Social Media",
team: {
images: [
"/images/user/user-28.jpg",
"/images/user/user-29.jpg",
"/images/user/user-30.jpg",
],
},
budget: "2.8K",
status: "Cancel",
},
{
id: 5,
user: {
image: "/images/user/user-21.jpg",
name: "Carla George",
role: "Front-end Developer",
},
projectName: "Website",
team: {
images: [
"/images/user/user-31.jpg",
"/images/user/user-32.jpg",
"/images/user/user-33.jpg",
],
},
budget: "4.5K",
status: "Active",
},
];
export default function BasicTableOne() {
return (
<div className="overflow-hidden rounded-xl border border-gray-200 bg-white dark:border-white/[0.05] dark:bg-white/[0.03]">
<div className="max-w-full overflow-x-auto">
<div className="min-w-[1102px]">
<Table>
{/* Table Header */}
<TableHeader className="border-b border-gray-100 dark:border-white/[0.05]">
<TableRow>
<TableCell
isHeader
className="px-5 py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400"
>
User
</TableCell>
<TableCell
isHeader
className="px-5 py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400"
>
Project Name
</TableCell>
<TableCell
isHeader
className="px-5 py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400"
>
Team
</TableCell>{" "}
<TableCell
isHeader
className="px-5 py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400"
>
Status
</TableCell>
<TableCell
isHeader
className="px-5 py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400"
>
Budget
</TableCell>
</TableRow>
</TableHeader>
{/* Table Body */}
<TableBody className="divide-y divide-gray-100 dark:divide-white/[0.05]">
{tableData.map((order) => (
<TableRow key={order.id}>
<TableCell className="px-5 py-4 sm:px-6 text-start">
<div className="flex items-center gap-3">
<div className="w-10 h-10 overflow-hidden rounded-full">
<img src={order.user.image} alt={order.user.name} />
</div>
<div>
<span className="block font-medium text-gray-800 text-theme-sm dark:text-white/90">
{order.user.name}
</span>
<span className="block text-gray-500 text-theme-xs dark:text-gray-400">
{order.user.role}
</span>
</div>
</div>
</TableCell>
<TableCell className="px-4 py-3 text-gray-500 text-start text-theme-sm dark:text-gray-400">
{order.projectName}
</TableCell>
<TableCell className="px-4 py-3 text-gray-500 text-start text-theme-sm dark:text-gray-400">
<div className="flex -space-x-2">
{order.team.images.map((teamImage, index) => (
<div className="w-6 h-6 overflow-hidden border-2 border-white rounded-full dark:border-gray-900">
<img
key={index}
src={teamImage}
alt={`Team member ${index + 1}`}
/>
</div>
))}
</div>
</TableCell>
<TableCell className="px-4 py-3 text-gray-500 text-start text-theme-sm dark:text-gray-400">
<Badge
size="sm"
color={
order.status === "Active"
? "success"
: order.status === "Pending"
? "warning"
: "error"
}
>
{order.status}
</Badge>
</TableCell>
<TableCell className="px-4 py-3 text-gray-500 text-theme-sm dark:text-gray-400">
{order.budget}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,145 @@
import React from "react";
import { Link } from "react-router";
interface AlertProps {
variant: "success" | "error" | "warning" | "info"; // Alert type
title: string; // Title of the alert
message: string; // Message of the alert
showLink?: boolean; // Whether to show the "Learn More" link
linkHref?: string; // Link URL
linkText?: string; // Link text
}
const Alert: React.FC<AlertProps> = ({
variant,
title,
message,
showLink = false,
linkHref = "#",
linkText = "Learn more",
}) => {
// Tailwind classes for each variant
const variantClasses = {
success: {
container:
"border-success-500 bg-success-50 dark:border-success-500/30 dark:bg-success-500/15",
icon: "text-success-500",
},
error: {
container:
"border-error-500 bg-error-50 dark:border-error-500/30 dark:bg-error-500/15",
icon: "text-error-500",
},
warning: {
container:
"border-warning-500 bg-warning-50 dark:border-warning-500/30 dark:bg-warning-500/15",
icon: "text-warning-500",
},
info: {
container:
"border-blue-light-500 bg-blue-light-50 dark:border-blue-light-500/30 dark:bg-blue-light-500/15",
icon: "text-blue-light-500",
},
};
// Icon for each variant
const icons = {
success: (
<svg
className="fill-current"
width="24"
height="24"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.70186 12.0001C3.70186 7.41711 7.41711 3.70186 12.0001 3.70186C16.5831 3.70186 20.2984 7.41711 20.2984 12.0001C20.2984 16.5831 16.5831 20.2984 12.0001 20.2984C7.41711 20.2984 3.70186 16.5831 3.70186 12.0001ZM12.0001 1.90186C6.423 1.90186 1.90186 6.423 1.90186 12.0001C1.90186 17.5772 6.423 22.0984 12.0001 22.0984C17.5772 22.0984 22.0984 17.5772 22.0984 12.0001C22.0984 6.423 17.5772 1.90186 12.0001 1.90186ZM15.6197 10.7395C15.9712 10.388 15.9712 9.81819 15.6197 9.46672C15.2683 9.11525 14.6984 9.11525 14.347 9.46672L11.1894 12.6243L9.6533 11.0883C9.30183 10.7368 8.73198 10.7368 8.38051 11.0883C8.02904 11.4397 8.02904 12.0096 8.38051 12.3611L10.553 14.5335C10.7217 14.7023 10.9507 14.7971 11.1894 14.7971C11.428 14.7971 11.657 14.7023 11.8257 14.5335L15.6197 10.7395Z"
/>
</svg>
),
error: (
<svg
className="fill-current"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M20.3499 12.0004C20.3499 16.612 16.6115 20.3504 11.9999 20.3504C7.38832 20.3504 3.6499 16.612 3.6499 12.0004C3.6499 7.38881 7.38833 3.65039 11.9999 3.65039C16.6115 3.65039 20.3499 7.38881 20.3499 12.0004ZM11.9999 22.1504C17.6056 22.1504 22.1499 17.6061 22.1499 12.0004C22.1499 6.3947 17.6056 1.85039 11.9999 1.85039C6.39421 1.85039 1.8499 6.3947 1.8499 12.0004C1.8499 17.6061 6.39421 22.1504 11.9999 22.1504ZM13.0008 16.4753C13.0008 15.923 12.5531 15.4753 12.0008 15.4753L11.9998 15.4753C11.4475 15.4753 10.9998 15.923 10.9998 16.4753C10.9998 17.0276 11.4475 17.4753 11.9998 17.4753L12.0008 17.4753C12.5531 17.4753 13.0008 17.0276 13.0008 16.4753ZM11.9998 6.62898C12.414 6.62898 12.7498 6.96476 12.7498 7.37898L12.7498 13.0555C12.7498 13.4697 12.414 13.8055 11.9998 13.8055C11.5856 13.8055 11.2498 13.4697 11.2498 13.0555L11.2498 7.37898C11.2498 6.96476 11.5856 6.62898 11.9998 6.62898Z"
fill="#F04438"
/>
</svg>
),
warning: (
<svg
className="fill-current"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.6501 12.0001C3.6501 7.38852 7.38852 3.6501 12.0001 3.6501C16.6117 3.6501 20.3501 7.38852 20.3501 12.0001C20.3501 16.6117 16.6117 20.3501 12.0001 20.3501C7.38852 20.3501 3.6501 16.6117 3.6501 12.0001ZM12.0001 1.8501C6.39441 1.8501 1.8501 6.39441 1.8501 12.0001C1.8501 17.6058 6.39441 22.1501 12.0001 22.1501C17.6058 22.1501 22.1501 17.6058 22.1501 12.0001C22.1501 6.39441 17.6058 1.8501 12.0001 1.8501ZM10.9992 7.52517C10.9992 8.07746 11.4469 8.52517 11.9992 8.52517H12.0002C12.5525 8.52517 13.0002 8.07746 13.0002 7.52517C13.0002 6.97289 12.5525 6.52517 12.0002 6.52517H11.9992C11.4469 6.52517 10.9992 6.97289 10.9992 7.52517ZM12.0002 17.3715C11.586 17.3715 11.2502 17.0357 11.2502 16.6215V10.945C11.2502 10.5308 11.586 10.195 12.0002 10.195C12.4144 10.195 12.7502 10.5308 12.7502 10.945V16.6215C12.7502 17.0357 12.4144 17.3715 12.0002 17.3715Z"
fill=""
/>
</svg>
),
info: (
<svg
className="fill-current"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.6501 11.9996C3.6501 7.38803 7.38852 3.64961 12.0001 3.64961C16.6117 3.64961 20.3501 7.38803 20.3501 11.9996C20.3501 16.6112 16.6117 20.3496 12.0001 20.3496C7.38852 20.3496 3.6501 16.6112 3.6501 11.9996ZM12.0001 1.84961C6.39441 1.84961 1.8501 6.39392 1.8501 11.9996C1.8501 17.6053 6.39441 22.1496 12.0001 22.1496C17.6058 22.1496 22.1501 17.6053 22.1501 11.9996C22.1501 6.39392 17.6058 1.84961 12.0001 1.84961ZM10.9992 7.52468C10.9992 8.07697 11.4469 8.52468 11.9992 8.52468H12.0002C12.5525 8.52468 13.0002 8.07697 13.0002 7.52468C13.0002 6.9724 12.5525 6.52468 12.0002 6.52468H11.9992C11.4469 6.52468 10.9992 6.9724 10.9992 7.52468ZM12.0002 17.371C11.586 17.371 11.2502 17.0352 11.2502 16.621V10.9445C11.2502 10.5303 11.586 10.1945 12.0002 10.1945C12.4144 10.1945 12.7502 10.5303 12.7502 10.9445V16.621C12.7502 17.0352 12.4144 17.371 12.0002 17.371Z"
fill=""
/>
</svg>
),
};
return (
<div
className={`rounded-xl border p-4 ${variantClasses[variant].container}`}
>
<div className="flex items-start gap-3">
<div className={`-mt-0.5 ${variantClasses[variant].icon}`}>
{icons[variant]}
</div>
<div>
<h4 className="mb-1 text-sm font-semibold text-gray-800 dark:text-white/90">
{title}
</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">{message}</p>
{showLink && (
<Link
to={linkHref}
className="inline-block mt-3 text-sm font-medium text-gray-500 underline dark:text-gray-400"
>
{linkText}
</Link>
)}
</div>
</div>
</div>
);
};
export default Alert;

View File

@@ -0,0 +1,57 @@
import React from "react";
interface AvatarProps {
src: string; // URL of the avatar image
alt?: string; // Alt text for the avatar
size?: "xsmall" | "small" | "medium" | "large" | "xlarge" | "xxlarge"; // Avatar size
status?: "online" | "offline" | "busy" | "none"; // Status indicator
}
const sizeClasses = {
xsmall: "h-6 w-6 max-w-6",
small: "h-8 w-8 max-w-8",
medium: "h-10 w-10 max-w-10",
large: "h-12 w-12 max-w-12",
xlarge: "h-14 w-14 max-w-14",
xxlarge: "h-16 w-16 max-w-16",
};
const statusSizeClasses = {
xsmall: "h-1.5 w-1.5 max-w-1.5",
small: "h-2 w-2 max-w-2",
medium: "h-2.5 w-2.5 max-w-2.5",
large: "h-3 w-3 max-w-3",
xlarge: "h-3.5 w-3.5 max-w-3.5",
xxlarge: "h-4 w-4 max-w-4",
};
const statusColorClasses = {
online: "bg-success-500",
offline: "bg-error-400",
busy: "bg-warning-500",
};
const Avatar: React.FC<AvatarProps> = ({
src,
alt = "User Avatar",
size = "medium",
status = "none",
}) => {
return (
<div className={`relative rounded-full ${sizeClasses[size]}`}>
{/* Avatar Image */}
<img src={src} alt={alt} className="object-cover rounded-full" />
{/* Status Indicator */}
{status !== "none" && (
<span
className={`absolute bottom-0 right-0 rounded-full border-[1.5px] border-white dark:border-gray-900 ${
statusSizeClasses[size]
} ${statusColorClasses[status] || ""}`}
></span>
)}
</div>
);
};
export default Avatar;

View File

@@ -0,0 +1,47 @@
import React from "react";
interface AvatarTextProps {
name: string;
className?: string;
}
const AvatarText: React.FC<AvatarTextProps> = ({ name, className = "" }) => {
// Generate initials from name
const initials = name
.split(" ")
.map((word) => word[0])
.join("")
.toUpperCase()
.slice(0, 2);
// Generate a consistent pastel color based on the name
const getColorClass = (name: string) => {
const colors = [
"bg-brand-100 text-brand-600",
"bg-pink-100 text-pink-600",
"bg-cyan-100 text-cyan-600",
"bg-orange-100 text-orange-600",
"bg-green-100 text-green-600",
"bg-purple-100 text-purple-600",
"bg-yellow-100 text-yellow-600",
"bg-error-100 text-error-600",
];
const index = name
.split("")
.reduce((acc, char) => acc + char.charCodeAt(0), 0);
return colors[index % colors.length];
};
return (
<div
className={`flex h-10 w-10 ${className} items-center justify-center rounded-full ${getColorClass(
name
)}`}
>
<span className="text-sm font-medium">{initials}</span>
</div>
);
};
export default AvatarText;

View File

@@ -0,0 +1,79 @@
import React from "react";
type BadgeVariant = "light" | "solid";
type BadgeSize = "sm" | "md";
type BadgeColor =
| "primary"
| "success"
| "error"
| "warning"
| "info"
| "light"
| "dark";
interface BadgeProps {
variant?: BadgeVariant; // Light or solid variant
size?: BadgeSize; // Badge size
color?: BadgeColor; // Badge color
startIcon?: React.ReactNode; // Icon at the start
endIcon?: React.ReactNode; // Icon at the end
children: React.ReactNode; // Badge content
}
const Badge: React.FC<BadgeProps> = ({
variant = "light",
color = "primary",
size = "md",
startIcon,
endIcon,
children,
}) => {
const baseStyles =
"inline-flex items-center px-2.5 py-0.5 justify-center gap-1 rounded-full font-medium";
// Define size styles
const sizeStyles = {
sm: "text-theme-xs", // Smaller padding and font size
md: "text-sm", // Default padding and font size
};
// Define color styles for variants
const variants = {
light: {
primary:
"bg-brand-50 text-brand-500 dark:bg-brand-500/15 dark:text-brand-400",
success:
"bg-success-50 text-success-600 dark:bg-success-500/15 dark:text-success-500",
error:
"bg-error-50 text-error-600 dark:bg-error-500/15 dark:text-error-500",
warning:
"bg-warning-50 text-warning-600 dark:bg-warning-500/15 dark:text-orange-400",
info: "bg-blue-light-50 text-blue-light-500 dark:bg-blue-light-500/15 dark:text-blue-light-500",
light: "bg-gray-100 text-gray-700 dark:bg-white/5 dark:text-white/80",
dark: "bg-gray-500 text-white dark:bg-white/5 dark:text-white",
},
solid: {
primary: "bg-brand-500 text-white dark:text-white",
success: "bg-success-500 text-white dark:text-white",
error: "bg-error-500 text-white dark:text-white",
warning: "bg-warning-500 text-white dark:text-white",
info: "bg-blue-light-500 text-white dark:text-white",
light: "bg-gray-400 dark:bg-white/5 text-white dark:text-white/80",
dark: "bg-gray-700 text-white dark:text-white",
},
};
// Get styles based on size and color variant
const sizeClass = sizeStyles[size];
const colorStyles = variants[variant][color];
return (
<span className={`${baseStyles} ${sizeClass} ${colorStyles}`}>
{startIcon && <span className="mr-1">{startIcon}</span>}
{children}
{endIcon && <span className="ml-1">{endIcon}</span>}
</span>
);
};
export default Badge;

View File

@@ -0,0 +1,55 @@
import React, { ReactNode } from "react";
interface ButtonProps {
children: ReactNode; // Button text or content
size?: "sm" | "md"; // Button size
variant?: "primary" | "outline"; // Button variant
startIcon?: ReactNode; // Icon before the text
endIcon?: ReactNode; // Icon after the text
onClick?: () => void; // Click handler
disabled?: boolean; // Disabled state
className?: string; // Disabled state
}
const Button: React.FC<ButtonProps> = ({
children,
size = "md",
variant = "primary",
startIcon,
endIcon,
onClick,
className = "",
disabled = false,
}) => {
// Size Classes
const sizeClasses = {
sm: "px-4 py-3 text-sm",
md: "px-5 py-3.5 text-sm",
};
// Variant Classes
const variantClasses = {
primary:
"bg-brand-500 text-white shadow-theme-xs hover:bg-brand-600 disabled:bg-brand-300",
outline:
"bg-white text-gray-700 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 dark:bg-gray-800 dark:text-gray-400 dark:ring-gray-700 dark:hover:bg-white/[0.03] dark:hover:text-gray-300",
};
return (
<button
className={`inline-flex items-center justify-center gap-2 rounded-lg transition ${className} ${
sizeClasses[size]
} ${variantClasses[variant]} ${
disabled ? "cursor-not-allowed opacity-50" : ""
}`}
onClick={onClick}
disabled={disabled}
>
{startIcon && <span className="flex items-center">{startIcon}</span>}
{children}
{endIcon && <span className="flex items-center">{endIcon}</span>}
</button>
);
};
export default Button;

View File

@@ -0,0 +1,45 @@
import type React from "react";
import { useEffect, useRef } from "react";
interface DropdownProps {
isOpen: boolean;
onClose: () => void;
children: React.ReactNode;
className?: string;
}
export const Dropdown: React.FC<DropdownProps> = ({
isOpen,
onClose,
children,
className = "",
}) => {
const dropdownRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (
dropdownRef.current &&
!dropdownRef.current.contains(event.target as Node)
) {
onClose();
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [onClose]);
if (!isOpen) return null;
return (
<div
ref={dropdownRef}
className={`absolute z-40 right-0 mt-2 rounded-xl border border-gray-200 bg-white shadow-theme-lg dark:border-gray-800 dark:bg-gray-dark ${className}`}
>
{children}
</div>
);
};

View File

@@ -0,0 +1,43 @@
import type React from "react";
import { Link } from "react-router";
interface DropdownItemProps {
tag?: "a" | "button";
href?: string;
onClick?: () => void;
onItemClick?: () => void;
baseClassName?: string;
className?: string;
children: React.ReactNode;
}
export const DropdownItem: React.FC<DropdownItemProps> = ({
tag = "button",
href,
onClick,
onItemClick,
baseClassName = "block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900",
className = "",
children,
}) => {
const combinedClasses = `${baseClassName} ${className}`.trim();
const handleClick = (event: React.MouseEvent) => {
if (onClick) onClick();
if (onItemClick) onItemClick();
};
if (tag === "a" && href) {
return (
<Link to={href} className={combinedClasses} onClick={handleClick}>
{children}
</Link>
);
}
return (
<button onClick={handleClick} className={combinedClasses}>
{children}
</button>
);
};

View File

@@ -0,0 +1,15 @@
import React from "react";
export default function ResponsiveImage() {
return (
<div className="relative">
<div className="overflow-hidden">
<img
src="/images/grid-image/image-01.png"
alt="Cover"
className="w-full border border-gray-200 rounded-xl dark:border-gray-800"
/>
</div>
</div>
);
}

View File

@@ -0,0 +1,31 @@
import React from "react";
export default function ThreeColumnImageGrid() {
return (
<div className="grid grid-cols-1 gap-5 sm:grid-cols-2 xl:grid-cols-3">
<div>
<img
src="/images/grid-image/image-04.png"
alt=" grid"
className="border border-gray-200 rounded-xl dark:border-gray-800"
/>
</div>
<div>
<img
src="/images/grid-image/image-05.png"
alt=" grid"
className="border border-gray-200 rounded-xl dark:border-gray-800"
/>
</div>
<div>
<img
src="/images/grid-image/image-06.png"
alt=" grid"
className="border border-gray-200 rounded-xl dark:border-gray-800"
/>
</div>
</div>
);
}

View File

@@ -0,0 +1,23 @@
import React from "react";
export default function TwoColumnImageGrid() {
return (
<div className="grid grid-cols-1 gap-5 sm:grid-cols-2">
<div>
<img
src="/images/grid-image/image-02.png"
alt=" grid"
className="border border-gray-200 rounded-xl dark:border-gray-800"
/>
</div>
<div>
<img
src="/images/grid-image/image-03.png"
alt=" grid"
className="border border-gray-200 rounded-xl dark:border-gray-800"
/>
</div>
</div>
);
}

View File

@@ -0,0 +1,94 @@
import React, { useRef, useEffect } from "react";
interface ModalProps {
isOpen: boolean;
onClose: () => void;
className?: string;
children: React.ReactNode;
showCloseButton?: boolean; // New prop to control close button visibility
isFullscreen?: boolean; // Default to false for backwards compatibility
}
export const Modal: React.FC<ModalProps> = ({
isOpen,
onClose,
children,
className,
showCloseButton = true, // Default to true for backwards compatibility
isFullscreen = false,
}) => {
const modalRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleEscape = (event: KeyboardEvent) => {
if (event.key === "Escape") {
onClose();
}
};
if (isOpen) {
document.addEventListener("keydown", handleEscape);
}
return () => {
document.removeEventListener("keydown", handleEscape);
};
}, [isOpen, onClose]);
useEffect(() => {
if (isOpen) {
document.body.style.overflow = "hidden";
} else {
document.body.style.overflow = "unset";
}
return () => {
document.body.style.overflow = "unset";
};
}, [isOpen]);
if (!isOpen) return null;
const contentClasses = isFullscreen
? "w-full h-full"
: "relative w-full rounded-3xl bg-white dark:bg-gray-900";
return (
<div className="fixed inset-0 flex items-center justify-center overflow-y-auto modal z-99999">
{!isFullscreen && (
<div
className="fixed inset-0 h-full w-full bg-gray-400/50 backdrop-blur-[32px]"
onClick={onClose}
></div>
)}
<div
ref={modalRef}
className={`${contentClasses} ${className}`}
onClick={(e) => e.stopPropagation()}
>
{showCloseButton && (
<button
onClick={onClose}
className="absolute right-3 top-3 z-999 flex h-9.5 w-9.5 items-center justify-center rounded-full bg-gray-100 text-gray-400 transition-colors hover:bg-gray-200 hover:text-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white sm:right-6 sm:top-6 sm:h-11 sm:w-11"
>
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M6.04289 16.5413C5.65237 16.9318 5.65237 17.565 6.04289 17.9555C6.43342 18.346 7.06658 18.346 7.45711 17.9555L11.9987 13.4139L16.5408 17.956C16.9313 18.3466 17.5645 18.3466 17.955 17.956C18.3455 17.5655 18.3455 16.9323 17.955 16.5418L13.4129 11.9997L17.955 7.4576C18.3455 7.06707 18.3455 6.43391 17.955 6.04338C17.5645 5.65286 16.9313 5.65286 16.5408 6.04338L11.9987 10.5855L7.45711 6.0439C7.06658 5.65338 6.43342 5.65338 6.04289 6.0439C5.65237 6.43442 5.65237 7.06759 6.04289 7.45811L10.5845 11.9997L6.04289 16.5413Z"
fill="currentColor"
/>
</svg>
</button>
)}
<div>{children}</div>
</div>
</div>
);
};

View File

@@ -0,0 +1,64 @@
import React, { ReactNode } from "react";
// Props for Table
interface TableProps {
children: ReactNode; // Table content (thead, tbody, etc.)
className?: string; // Optional className for styling
}
// Props for TableHeader
interface TableHeaderProps {
children: ReactNode; // Header row(s)
className?: string; // Optional className for styling
}
// Props for TableBody
interface TableBodyProps {
children: ReactNode; // Body row(s)
className?: string; // Optional className for styling
}
// Props for TableRow
interface TableRowProps {
children: ReactNode; // Cells (th or td)
className?: string; // Optional className for styling
}
// Props for TableCell
interface TableCellProps {
children: ReactNode; // Cell content
isHeader?: boolean; // If true, renders as <th>, otherwise <td>
className?: string; // Optional className for styling
}
// Table Component
const Table: React.FC<TableProps> = ({ children, className }) => {
return <table className={`min-w-full ${className}`}>{children}</table>;
};
// TableHeader Component
const TableHeader: React.FC<TableHeaderProps> = ({ children, className }) => {
return <thead className={className}>{children}</thead>;
};
// TableBody Component
const TableBody: React.FC<TableBodyProps> = ({ children, className }) => {
return <tbody className={className}>{children}</tbody>;
};
// TableRow Component
const TableRow: React.FC<TableRowProps> = ({ children, className }) => {
return <tr className={className}>{children}</tr>;
};
// TableCell Component
const TableCell: React.FC<TableCellProps> = ({
children,
isHeader = false,
className,
}) => {
const CellTag = isHeader ? "th" : "td";
return <CellTag className={` ${className}`}>{children}</CellTag>;
};
export { Table, TableHeader, TableBody, TableRow, TableCell };

View File

@@ -0,0 +1,28 @@
import React from "react";
type AspectRatioVideoProps = {
videoUrl: string; // URL of the video
aspectRatio?: string; // Aspect ratio in the format "width/height", default is "16/9"
title?: string; // Video title, default is "Embedded Video"
};
const AspectRatioVideo: React.FC<AspectRatioVideoProps> = ({
videoUrl,
aspectRatio = "video", // Default aspect ratio
title = "Embedded Video",
}) => {
return (
<div className={`aspect-${aspectRatio} overflow-hidden rounded-lg`}>
<iframe
src={videoUrl}
title={title}
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
className="w-full h-full"
></iframe>
</div>
);
};
export default AspectRatioVideo;

View File

@@ -0,0 +1,16 @@
import React from "react";
export default function FourIsToThree() {
return (
<div className="aspect-[4/3] overflow-hidden rounded-lg">
<iframe
src="https://www.youtube.com/embed/dQw4w9WgXcQ"
title="YouTube video"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
className="w-full h-full"
></iframe>
</div>
);
}

View File

@@ -0,0 +1,16 @@
import React from "react";
export default function OneIsToOne() {
return (
<div className="overflow-hidden rounded-lg aspect-square">
<iframe
src="https://www.youtube.com/embed/dQw4w9WgXcQ"
title="YouTube video"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
className="w-full h-full"
></iframe>
</div>
);
}

View File

@@ -0,0 +1,16 @@
import React from "react";
export default function SixteenIsToNine() {
return (
<div className="aspect-[4/3] overflow-hidden rounded-lg">
<iframe
src="https://www.youtube.com/embed/dQw4w9WgXcQ"
title="YouTube video"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
className="w-full h-full"
></iframe>
</div>
);
}

View File

@@ -0,0 +1,16 @@
import React from "react";
export default function TwentyOneIsToNine() {
return (
<div className="aspect-[21/9] overflow-hidden rounded-lg">
<iframe
src="https://www.youtube.com/embed/dQw4w9WgXcQ"
title="YouTube video"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
className="w-full h-full"
></iframe>
</div>
);
}

View File

@@ -0,0 +1,83 @@
import React, { createContext, useContext, useState, useEffect } from "react";
type SidebarContextType = {
isExpanded: boolean;
isMobileOpen: boolean;
isHovered: boolean;
activeItem: string | null;
openSubmenu: string | null;
toggleSidebar: () => void;
toggleMobileSidebar: () => void;
setIsHovered: (isHovered: boolean) => void;
setActiveItem: (item: string | null) => void;
toggleSubmenu: (item: string) => void;
};
const SidebarContext = createContext<SidebarContextType | undefined>(undefined);
export const useSidebar = () => {
const context = useContext(SidebarContext);
if (!context) {
throw new Error("useSidebar must be used within a SidebarProvider");
}
return context;
};
export const SidebarProvider: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const [isExpanded, setIsExpanded] = useState(true);
const [isMobileOpen, setIsMobileOpen] = useState(false);
const [isMobile, setIsMobile] = useState(false);
const [isHovered, setIsHovered] = useState(false);
const [activeItem, setActiveItem] = useState<string | null>(null);
const [openSubmenu, setOpenSubmenu] = useState<string | null>(null);
useEffect(() => {
const handleResize = () => {
const mobile = window.innerWidth < 768;
setIsMobile(mobile);
if (!mobile) {
setIsMobileOpen(false);
}
};
handleResize();
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
const toggleSidebar = () => {
setIsExpanded((prev) => !prev);
};
const toggleMobileSidebar = () => {
setIsMobileOpen((prev) => !prev);
};
const toggleSubmenu = (item: string) => {
setOpenSubmenu((prev) => (prev === item ? null : item));
};
return (
<SidebarContext.Provider
value={{
isExpanded: isMobile ? false : isExpanded,
isMobileOpen,
isHovered,
activeItem,
openSubmenu,
toggleSidebar,
toggleMobileSidebar,
setIsHovered,
setActiveItem,
toggleSubmenu,
}}
>
{children}
</SidebarContext.Provider>
);
};

View File

@@ -0,0 +1,58 @@
"use client";
import type React from "react";
import { createContext, useState, useContext, useEffect } from "react";
type Theme = "light" | "dark";
type ThemeContextType = {
theme: Theme;
toggleTheme: () => void;
};
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const [theme, setTheme] = useState<Theme>("light");
const [isInitialized, setIsInitialized] = useState(false);
useEffect(() => {
// This code will only run on the client side
const savedTheme = localStorage.getItem("theme") as Theme | null;
const initialTheme = savedTheme || "light"; // Default to light theme
setTheme(initialTheme);
setIsInitialized(true);
}, []);
useEffect(() => {
if (isInitialized) {
localStorage.setItem("theme", theme);
if (theme === "dark") {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}
}
}, [theme, isInitialized]);
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light"));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
export const useTheme = () => {
const context = useContext(ThemeContext);
if (context === undefined) {
throw new Error("useTheme must be used within a ThemeProvider");
}
return context;
};

View File

@@ -0,0 +1,17 @@
import { useNavigate } from "react-router";
const useGoBack = () => {
const navigate = useNavigate();
const goBack = () => {
if (window.history.state && window.history.state.idx > 0) {
navigate(-1); // Go back to the previous page
} else {
navigate("/"); // Redirect to home if no history exists
}
};
return goBack;
};
export default useGoBack;

View File

@@ -0,0 +1,11 @@
import { useState, useCallback } from "react";
export const useModal = (initialState: boolean = false) => {
const [isOpen, setIsOpen] = useState(initialState);
const openModal = useCallback(() => setIsOpen(true), []);
const closeModal = useCallback(() => setIsOpen(false), []);
const toggleModal = useCallback(() => setIsOpen((prev) => !prev), []);
return { isOpen, openModal, closeModal, toggleModal };
};

View File

@@ -0,0 +1,15 @@
<svg
class="fill-current"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M13.9497 3.875C13.0836 2.375 10.9186 2.375 10.0525 3.875L2.54699 16.875C1.68096 18.375 2.76349 20.25 4.49554 20.25H19.5067C21.2387 20.25 22.3212 18.375 21.4552 16.875L13.9497 3.875ZM11.3516 4.625C11.6403 4.125 12.3619 4.125 12.6506 4.625L20.1562 17.625C20.4448 18.125 20.084 18.75 19.5067 18.75H4.49554C3.91819 18.75 3.55735 18.125 3.84603 17.625L11.3516 4.625ZM12.0018 8.56075C12.416 8.56075 12.7518 8.89653 12.7518 9.31075V13.5303C12.7518 13.9445 12.416 14.2803 12.0018 14.2803C11.5876 14.2803 11.2518 13.9445 11.2518 13.5303V9.31075C11.2518 8.89653 11.5876 8.56075 12.0018 8.56075ZM11.0009 16.0803C11.0009 15.528 11.4486 15.0803 12.0009 15.0803H12.0016C12.5539 15.0803 13.0016 15.528 13.0016 16.0803C13.0016 16.6326 12.5539 17.0803 12.0016 17.0803H12.0009C11.4486 17.0803 11.0009 16.6326 11.0009 16.0803Z"
fill=""
/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,12 @@
<svg
width="8"
height="5"
viewBox="0 0 8 5"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4.40962 4.41483C4.21057 4.69919 3.78943 4.69919 3.59038 4.41483L1.05071 0.786732C0.81874 0.455343 1.05582 0 1.46033 0H6.53967C6.94418 0 7.18126 0.455342 6.94929 0.786731L4.40962 4.41483Z"
fill="currentColor"
/>
</svg>

After

Width:  |  Height:  |  Size: 584 B

View File

View File

View File

@@ -0,0 +1,13 @@
<svg
width="8"
height="5"
viewBox="0 0 8 5"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4.40962 0.585167C4.21057 0.300808 3.78943 0.300807 3.59038 0.585166L1.05071 4.21327C0.81874 4.54466 1.05582 5 1.46033 5H6.53967C6.94418 5 7.18126 4.54466 6.94929 4.21327L4.40962 0.585167Z"
fill="currentColor"
/>
</svg>

After

Width:  |  Height:  |  Size: 609 B

View File

@@ -0,0 +1,15 @@
<svg
class="fill-current"
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M5.31462 10.3761C5.45194 10.5293 5.65136 10.6257 5.87329 10.6257C5.8736 10.6257 5.8739 10.6257 5.87421 10.6257C6.0663 10.6259 6.25845 10.5527 6.40505 10.4062L9.40514 7.4082C9.69814 7.11541 9.69831 6.64054 9.40552 6.34754C9.11273 6.05454 8.63785 6.05438 8.34486 6.34717L6.62329 8.06753L6.62329 1.875C6.62329 1.46079 6.28751 1.125 5.87329 1.125C5.45908 1.125 5.12329 1.46079 5.12329 1.875L5.12329 8.06422L3.40516 6.34719C3.11218 6.05439 2.6373 6.05454 2.3445 6.34752C2.0517 6.64051 2.05185 7.11538 2.34484 7.40818L5.31462 10.3761Z"
fill=""
/>
</svg>

After

Width:  |  Height:  |  Size: 858 B

View File

@@ -0,0 +1,15 @@
<svg
className="fill-current"
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M17.4175 9.9986C17.4178 10.1909 17.3446 10.3832 17.198 10.53L12.2013 15.5301C11.9085 15.8231 11.4337 15.8233 11.1407 15.5305C10.8477 15.2377 10.8475 14.7629 11.1403 14.4699L14.8604 10.7472L3.33301 10.7472C2.91879 10.7472 2.58301 10.4114 2.58301 9.99715C2.58301 9.58294 2.91879 9.24715 3.33301 9.24715L14.8549 9.24715L11.1403 5.53016C10.8475 5.23717 10.8477 4.7623 11.1407 4.4695C11.4336 4.1767 11.9085 4.17685 12.2013 4.46984L17.1588 9.43049C17.3173 9.568 17.4175 9.77087 17.4175 9.99715C17.4175 9.99763 17.4175 9.99812 17.4175 9.9986Z"
fill=""
/>
</svg>

After

Width:  |  Height:  |  Size: 897 B

View File

@@ -0,0 +1,16 @@
<svg
className="fill-current"
width="13"
height="12"
viewBox="0 0 13 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M6.06462 1.62393C6.20193 1.47072 6.40135 1.37432 6.62329 1.37432C6.6236 1.37432 6.62391 1.37432 6.62422 1.37432C6.81631 1.37415 7.00845 1.44731 7.15505 1.5938L10.1551 4.5918C10.4481 4.88459 10.4483 5.35946 10.1555 5.65246C9.86273 5.94546 9.38785 5.94562 9.09486 5.65283L7.37329 3.93247L7.37329 10.125C7.37329 10.5392 7.03751 10.875 6.62329 10.875C6.20908 10.875 5.87329 10.5392 5.87329 10.125L5.87329 3.93578L4.15516 5.65281C3.86218 5.94561 3.3873 5.94546 3.0945 5.65248C2.8017 5.35949 2.80185 4.88462 3.09484 4.59182L6.06462 1.62393Z"
fill=""
/>
</svg>

After

Width:  |  Height:  |  Size: 926 B

View File

@@ -0,0 +1,15 @@
<svg
class="fill-current"
width="25"
height="24"
viewBox="0 0 25 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M21.4166 4.00001C21.4166 3.77689 21.3173 3.56536 21.1456 3.42287C20.9739 3.28039 20.7477 3.22173 20.5284 3.26285L8.52841 5.51285C8.17368 5.57936 7.91663 5.88909 7.91663 6.25001V9.98484C7.91644 9.99437 7.91644 10.0039 7.91663 10.0135V14.4585C7.3716 14.1636 6.72327 14 6.04163 14C5.16738 14 4.34794 14.2691 3.73094 14.7392C3.11333 15.2098 2.66663 15.9138 2.66663 16.75C2.66663 17.5862 3.11333 18.2902 3.73094 18.7608C4.34794 19.2309 5.16738 19.5 6.04163 19.5C6.91587 19.5 7.73532 19.2309 8.35231 18.7608C8.95774 18.2995 9.39893 17.6139 9.41611 16.7993C9.41645 16.79 9.41663 16.7806 9.41663 16.7712V16.75V10.62L19.9166 8.60938V12.2085C19.3716 11.9136 18.7233 11.75 18.0416 11.75C17.1674 11.75 16.3479 12.0191 15.7309 12.4892C15.1133 12.9598 14.6666 13.6638 14.6666 14.5C14.6666 15.3362 15.1133 16.0402 15.7309 16.5108C16.3479 16.9809 17.1674 17.25 18.0416 17.25C18.9159 17.25 19.7353 16.9809 20.3523 16.5108C20.9577 16.0495 21.3989 15.3639 21.4161 14.5493C21.4165 14.54 21.4166 14.5306 21.4166 14.5212V14.5V4.00001ZM19.9166 14.5C19.9166 14.2316 19.7757 13.9357 19.4432 13.6824C19.1102 13.4286 18.6171 13.25 18.0416 13.25C17.4661 13.25 16.9731 13.4286 16.64 13.6824C16.3076 13.9357 16.1666 14.2316 16.1666 14.5C16.1666 14.7684 16.3076 15.0643 16.64 15.3176C16.9731 15.5714 17.4661 15.75 18.0416 15.75C18.6171 15.75 19.1102 15.5714 19.4432 15.3176C19.7757 15.0643 19.9166 14.7684 19.9166 14.5ZM7.44325 15.9324C7.7757 16.1857 7.91663 16.4816 7.91663 16.75C7.91663 17.0184 7.7757 17.3143 7.44325 17.5676C7.11018 17.8214 6.61713 18 6.04163 18C5.46613 18 4.97307 17.8214 4.64 17.5676C4.30755 17.3143 4.16663 17.0184 4.16663 16.75C4.16663 16.4816 4.30755 16.1857 4.64 15.9324C4.97307 15.6786 5.46613 15.5 6.04163 15.5C6.61713 15.5 7.11018 15.6786 7.44325 15.9324ZM19.9166 7.08212V4.9037L9.41663 6.87245V9.09276L19.9166 7.08212Z"
fill="currentColor"
/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,15 @@
<svg
width="24"
height="26"
viewBox="0 0 24 26"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12.814 4.75L4.78516 16.0352H11.1859L11.1859 23.25L19.2148 11.9648L12.814 11.9648V4.75Z"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>

After

Width:  |  Height:  |  Size: 411 B

View File

@@ -0,0 +1,15 @@
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M11.665 3.75618C11.8762 3.65061 12.1247 3.65061 12.3358 3.75618L18.7807 6.97853L12.3358 10.2009C12.1247 10.3064 11.8762 10.3064 11.665 10.2009L5.22014 6.97853L11.665 3.75618ZM4.29297 8.19199V16.0946C4.29297 16.3787 4.45347 16.6384 4.70757 16.7654L11.25 20.0365V11.6512C11.1631 11.6205 11.0777 11.5843 10.9942 11.5425L4.29297 8.19199ZM12.75 20.037L19.2933 16.7654C19.5474 16.6384 19.7079 16.3787 19.7079 16.0946V8.19199L13.0066 11.5425C12.9229 11.5844 12.8372 11.6207 12.75 11.6515V20.037ZM13.0066 2.41453C12.3732 2.09783 11.6277 2.09783 10.9942 2.41453L4.03676 5.89316C3.27449 6.27429 2.79297 7.05339 2.79297 7.90563V16.0946C2.79297 16.9468 3.27448 17.7259 4.03676 18.1071L10.9942 21.5857L11.3296 20.9149L10.9942 21.5857C11.6277 21.9024 12.3732 21.9024 13.0066 21.5857L19.9641 18.1071C20.7264 17.7259 21.2079 16.9468 21.2079 16.0946V7.90563C21.2079 7.05339 20.7264 6.27429 19.9641 5.89316L13.0066 2.41453Z"
fill="currentColor"
/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Some files were not shown because too many files have changed in this diff Show More