Novo site
@@ -1 +1 @@
|
||||
REACT_APP_API_URL=http://localhost:5015/
|
||||
REACT_APP_API_URL=https://localhost:44329/
|
||||
5
geradoresfe/.gitignore
vendored
@@ -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
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"port": 26415,
|
||||
"path": "./",
|
||||
"clr": "v4.0",
|
||||
"protocol": "http"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 3.8 KiB |
@@ -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>
|
||||
<!--
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 = () => {
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col">
|
||||
<Navbar />
|
||||
<main className="flex-grow">
|
||||
<Hero />
|
||||
<FeatureSection />
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
import Home from "./pages/Home";
|
||||
import GenerateNIF from "./pages/GenerateNIF";
|
||||
import GenerateNISS from "./pages/GenerateNISS";
|
||||
import GenerateCC from "./pages/GenerateCC";
|
||||
|
||||
export default App;
|
||||
export default function App() {
|
||||
return (
|
||||
<>
|
||||
<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>
|
||||
|
||||
{/* Auth Layout */}
|
||||
<Route element={<AuthLayout />}>
|
||||
<Route path="/signin" element={<SignIn />} />
|
||||
<Route path="/signup" element={<SignUp />} />
|
||||
</Route>
|
||||
|
||||
{/* Fallback Route */}
|
||||
</Routes>
|
||||
</Router>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -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'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'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'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>
|
||||
);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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">© {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;
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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'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">
|
||||
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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
132
geradoresfe/src/components/UserProfile/UserAddressCard.tsx
Normal 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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
185
geradoresfe/src/components/UserProfile/UserInfoCard.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
217
geradoresfe/src/components/UserProfile/UserMetaCard.tsx
Normal 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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
98
geradoresfe/src/components/charts/bar/BarChartOne.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
121
geradoresfe/src/components/charts/line/LineChartOne.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
45
geradoresfe/src/components/common/ChartTab.tsx
Normal 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;
|
||||
42
geradoresfe/src/components/common/ComponentCard.tsx
Normal 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;
|
||||
69
geradoresfe/src/components/common/CountdownTimer.tsx
Normal 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;
|
||||
14
geradoresfe/src/components/common/GridShape.tsx
Normal 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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
52
geradoresfe/src/components/common/PageBreadCrumb.tsx
Normal 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;
|
||||
21
geradoresfe/src/components/common/PageMeta.tsx
Normal 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;
|
||||
42
geradoresfe/src/components/common/ThemeToggleButton.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
95
geradoresfe/src/components/ecommerce/CountryMap.tsx
Normal 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;
|
||||
115
geradoresfe/src/components/ecommerce/DemographicCard.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
60
geradoresfe/src/components/ecommerce/EcommerceMetrics.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
142
geradoresfe/src/components/ecommerce/MonthlySalesChart.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
198
geradoresfe/src/components/ecommerce/MonthlyTarget.tsx
Normal 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 you’ve 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>
|
||||
);
|
||||
}
|
||||
208
geradoresfe/src/components/ecommerce/RecentOrders.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
138
geradoresfe/src/components/ecommerce/StatisticsChart.tsx
Normal 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 you’ve 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>
|
||||
);
|
||||
}
|
||||
23
geradoresfe/src/components/form/Form.tsx
Normal 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;
|
||||
27
geradoresfe/src/components/form/Label.tsx
Normal 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;
|
||||
166
geradoresfe/src/components/form/MultiSelect.tsx
Normal 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;
|
||||
64
geradoresfe/src/components/form/Select.tsx
Normal 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;
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
114
geradoresfe/src/components/form/form-elements/DefaultInputs.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
77
geradoresfe/src/components/form/form-elements/DropZone.tsx
Normal 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;
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
55
geradoresfe/src/components/form/form-elements/InputGroup.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
140
geradoresfe/src/components/form/group-input/PhoneInput.tsx
Normal 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;
|
||||
43
geradoresfe/src/components/form/input/Checkbox.tsx
Normal 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;
|
||||
18
geradoresfe/src/components/form/input/FileInput.tsx
Normal 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;
|
||||
84
geradoresfe/src/components/form/input/InputField.tsx
Normal 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;
|
||||
65
geradoresfe/src/components/form/input/Radio.tsx
Normal 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;
|
||||
59
geradoresfe/src/components/form/input/RadioSm.tsx
Normal 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;
|
||||
63
geradoresfe/src/components/form/input/TextArea.tsx
Normal 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;
|
||||
72
geradoresfe/src/components/form/switch/Switch.tsx
Normal 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;
|
||||
189
geradoresfe/src/components/header/Header.tsx
Normal 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;
|
||||
380
geradoresfe/src/components/header/NotificationDropdown.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
163
geradoresfe/src/components/header/UserDropdown.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
215
geradoresfe/src/components/tables/BasicTableOne.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
145
geradoresfe/src/components/ui/alert/Alert.tsx
Normal 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;
|
||||
57
geradoresfe/src/components/ui/avatar/Avatar.tsx
Normal 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;
|
||||
47
geradoresfe/src/components/ui/avatar/AvatarText.tsx
Normal 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;
|
||||
79
geradoresfe/src/components/ui/badge/Badge.tsx
Normal 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;
|
||||
55
geradoresfe/src/components/ui/button/Button.tsx
Normal 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;
|
||||
45
geradoresfe/src/components/ui/dropdown/Dropdown.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
43
geradoresfe/src/components/ui/dropdown/DropdownItem.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
15
geradoresfe/src/components/ui/images/ResponsiveImage.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
23
geradoresfe/src/components/ui/images/TwoColumnImageGrid.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
94
geradoresfe/src/components/ui/modal/index.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
64
geradoresfe/src/components/ui/table/index.tsx
Normal 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 };
|
||||
28
geradoresfe/src/components/ui/videos/AspectRatioVideo.tsx
Normal 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;
|
||||
16
geradoresfe/src/components/ui/videos/FourIsToThree.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
16
geradoresfe/src/components/ui/videos/OneIsToOne.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
16
geradoresfe/src/components/ui/videos/SixteenIsToNine.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
16
geradoresfe/src/components/ui/videos/TwentyOneIsToNine.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
83
geradoresfe/src/context/SidebarContext.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
58
geradoresfe/src/context/ThemeContext.tsx
Normal 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;
|
||||
};
|
||||
17
geradoresfe/src/hooks/useGoBack.ts
Normal 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;
|
||||
11
geradoresfe/src/hooks/useModal.ts
Normal 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 };
|
||||
};
|
||||
15
geradoresfe/src/icons/alert.svg
Normal 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 |
12
geradoresfe/src/icons/angle-down.svg
Normal 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 |
0
geradoresfe/src/icons/angle-left.svg
Normal file
0
geradoresfe/src/icons/angle-right.svg
Normal file
13
geradoresfe/src/icons/angle-up.svg
Normal 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 |
15
geradoresfe/src/icons/arrow-down.svg
Normal 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 |
15
geradoresfe/src/icons/arrow-right.svg
Normal 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 |
16
geradoresfe/src/icons/arrow-up.svg
Normal 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 |
15
geradoresfe/src/icons/audio.svg
Normal 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 |
15
geradoresfe/src/icons/bolt.svg
Normal 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 |
15
geradoresfe/src/icons/box-cube.svg
Normal 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 |
15
geradoresfe/src/icons/box-line.svg
Normal 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.75621C11.8762 3.65064 12.1247 3.65064 12.3358 3.75621L18.7807 6.97856L12.3358 10.2009C12.1247 10.3065 11.8762 10.3065 11.665 10.2009L5.22014 6.97856L11.665 3.75621ZM4.29297 8.19203V16.0946C4.29297 16.3787 4.45347 16.6384 4.70757 16.7654L11.25 20.0366V11.6513C11.1631 11.6205 11.0777 11.5843 10.9942 11.5426L4.29297 8.19203ZM12.75 20.037L19.2933 16.7654C19.5474 16.6384 19.7079 16.3787 19.7079 16.0946V8.19202L13.0066 11.5426C12.9229 11.5844 12.8372 11.6208 12.75 11.6516V20.037ZM13.0066 2.41456C12.3732 2.09786 11.6277 2.09786 10.9942 2.41456L4.03676 5.89319C3.27449 6.27432 2.79297 7.05342 2.79297 7.90566V16.0946C2.79297 16.9469 3.27448 17.726 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.726 21.2079 16.9469 21.2079 16.0946V7.90566C21.2079 7.05342 20.7264 6.27432 19.9641 5.89319L13.0066 2.41456Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
15
geradoresfe/src/icons/box.svg
Normal file
@@ -0,0 +1,15 @@
|
||||
<svg
|
||||
|
||||
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="M9.77692 3.24224C9.91768 3.17186 10.0834 3.17186 10.2241 3.24224L15.3713 5.81573L10.3359 8.33331C10.1248 8.43888 9.87626 8.43888 9.66512 8.33331L4.6298 5.81573L9.77692 3.24224ZM3.70264 7.0292V13.4124C3.70264 13.6018 3.80964 13.775 3.97903 13.8597L9.25016 16.4952L9.25016 9.7837C9.16327 9.75296 9.07782 9.71671 8.99432 9.67496L3.70264 7.0292ZM10.7502 16.4955V9.78396C10.8373 9.75316 10.923 9.71683 11.0067 9.67496L16.2984 7.0292V13.4124C16.2984 13.6018 16.1914 13.775 16.022 13.8597L10.7502 16.4955ZM9.41463 17.4831L9.10612 18.1002C9.66916 18.3817 10.3319 18.3817 10.8949 18.1002L16.6928 15.2013C17.3704 14.8625 17.7984 14.17 17.7984 13.4124V6.58831C17.7984 5.83076 17.3704 5.13823 16.6928 4.79945L10.8949 1.90059C10.3319 1.61908 9.66916 1.61907 9.10612 1.90059L9.44152 2.57141L9.10612 1.90059L3.30823 4.79945C2.63065 5.13823 2.20264 5.83076 2.20264 6.58831V13.4124C2.20264 14.17 2.63065 14.8625 3.30823 15.2013L9.10612 18.1002L9.41463 17.4831Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |