First commit

This commit is contained in:
2025-01-15 12:38:29 +05:30
parent 6e77a9cb3f
commit 3c15bb8859
72 changed files with 15458 additions and 0 deletions

24
.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

1
dev-dist/registerSW.js Normal file
View File

@@ -0,0 +1 @@
if('serviceWorker' in navigator) navigator.serviceWorker.register('/dev-sw.js?dev-sw', { scope: '/', type: 'classic' })

92
dev-dist/sw.js Normal file
View File

@@ -0,0 +1,92 @@
/**
* Copyright 2018 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// If the loader is already loaded, just stop.
if (!self.define) {
let registry = {};
// Used for `eval` and `importScripts` where we can't get script URL by other means.
// In both cases, it's safe to use a global var because those functions are synchronous.
let nextDefineUri;
const singleRequire = (uri, parentUri) => {
uri = new URL(uri + ".js", parentUri).href;
return registry[uri] || (
new Promise(resolve => {
if ("document" in self) {
const script = document.createElement("script");
script.src = uri;
script.onload = resolve;
document.head.appendChild(script);
} else {
nextDefineUri = uri;
importScripts(uri);
resolve();
}
})
.then(() => {
let promise = registry[uri];
if (!promise) {
throw new Error(`Module ${uri} didnt register its module`);
}
return promise;
})
);
};
self.define = (depsNames, factory) => {
const uri = nextDefineUri || ("document" in self ? document.currentScript.src : "") || location.href;
if (registry[uri]) {
// Module is already loading or loaded.
return;
}
let exports = {};
const require = depUri => singleRequire(depUri, uri);
const specialDeps = {
module: { uri },
exports,
require
};
registry[uri] = Promise.all(depsNames.map(
depName => specialDeps[depName] || require(depName)
)).then(deps => {
factory(...deps);
return exports;
});
};
}
define(['./workbox-54d0af47'], (function (workbox) { 'use strict';
self.skipWaiting();
workbox.clientsClaim();
/**
* The precacheAndRoute() method efficiently caches and responds to
* requests for URLs in the manifest.
* See https://goo.gl/S9QRab
*/
workbox.precacheAndRoute([{
"url": "registerSW.js",
"revision": "3ca0b8505b4bec776b69afdba2768812"
}, {
"url": "index.html",
"revision": "0.r4rebmaausg"
}], {});
workbox.cleanupOutdatedCaches();
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
allowlist: [/^\/$/]
}));
}));

3391
dev-dist/workbox-54d0af47.js Normal file

File diff suppressed because it is too large Load Diff

28
eslint.config.js Normal file
View File

@@ -0,0 +1,28 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
)

13
index.html Normal file
View File

@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/assets/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ReGroup Admin</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

10076
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

39
package.json Normal file
View File

@@ -0,0 +1,39 @@
{
"name": "regroup-admin",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@chakra-ui/react": "^3.2.3",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"framer-motion": "^11.18.0",
"next-themes": "^0.4.4",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.54.2",
"react-icons": "^5.4.0",
"react-router-dom": "^7.1.1",
"vite-plugin-pwa": "^0.21.1"
},
"devDependencies": {
"@chakra-ui/cli": "^3.2.3",
"@eslint/js": "^9.17.0",
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
"@vitejs/plugin-react": "^4.3.4",
"eslint": "^9.17.0",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.16",
"globals": "^15.14.0",
"typescript": "~5.6.2",
"typescript-eslint": "^8.18.2",
"vite": "^6.0.5"
}
}

BIN
public/icon-128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
public/icon-144x144.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
public/icon-152x152.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
public/icon-192x192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
public/icon-384x384.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
public/icon-512x512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

BIN
public/icon-72x72.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
public/icon-96x96.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@@ -0,0 +1,32 @@
{
"name": "ReGroup",
"short_name": "RG",
"description": "Join your community now",
"start_url": "/",
"display": "standalone",
"theme_color": "#222935",
"background_color": "#222935",
"icons": [
{
"src": "/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/icon-256x256.png",
"sizes": "256x256",
"type": "image/png"
},
{
"src": "/icon-384x384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}

1
public/vite copy.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
public/vite.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 850 B

1
public/vite.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

24
src/App.tsx Normal file
View File

@@ -0,0 +1,24 @@
import { useContext } from 'react';
import { Route, BrowserRouter as Router, Routes } from "react-router-dom";
import GlobalStateContext from './Contexts/GlobalStateContext';
import DefaultLayout from './Layouts/DefaultLayout';
import Login from './Pages/Login';
import { RouteLink } from './Routes/Routes';
function App() {
const context = useContext(GlobalStateContext);
if (!context) throw new Error('App must be used within a GlobalStateProvider');
const { isAuthenticate } = context;
return (
<Router>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/*" element={isAuthenticate === true ? (<DefaultLayout><Routes>{RouteLink.map(({ path, Component }, index) => (<Route key={index} path={path} element={<Component />} />))}</Routes></DefaultLayout>) : (<Login />)} />
<Route path="*" element={<Login />} />
</Routes>
</Router>
);
}
export default App;

View File

@@ -0,0 +1,13 @@
// GlobalStateContext.ts
import { createContext, Dispatch, SetStateAction } from 'react';
// Define the shape of your context value
type GlobalStateContextType = {
isAuthenticate: boolean;
setIsAuthenticate: Dispatch<SetStateAction<boolean>>;
};
// Create the context with a default value of `undefined`
const GlobalStateContext = createContext<GlobalStateContextType | undefined>(undefined);
export default GlobalStateContext;

View File

@@ -0,0 +1,17 @@
import { ReactNode, useState } from 'react';
import GlobalStateContext from './GlobalStateContext';
const GlobalStateProvider = ({ children }:{children:ReactNode}) => {
const [isAuthenticate, setIsAuthenticate] = useState<boolean>(true);
return (
<GlobalStateContext.Provider value={{ isAuthenticate, setIsAuthenticate }}>
{children}
</GlobalStateContext.Provider>
);
};
export default GlobalStateProvider;

View File

@@ -0,0 +1,62 @@
import { HStack, Image, Text, VStack } from "@chakra-ui/react";
import React, { FC } from "react";
import { GiHamburgerMenu } from "react-icons/gi";
import { RiNotificationLine } from "react-icons/ri";
import { nav } from "../Routes/Nav";
import logo from '../assets/redogo.svg';
import { Avatar } from "../components/ui/avatar";
import { NavLink, useLocation, useNavigate, useParams } from "react-router-dom";
import { AccordionItem, AccordionItemContent, AccordionItemTrigger, AccordionRoot } from "../components/ui/accordion";
const DefaultLayout: FC<{ children: React.ReactNode }> = ({ children }) => {
const navigate = useNavigate()
const location = useLocation()
return (
<HStack position={'relative'} bg="#222935" backgroundPosition="center" backgroundRepeat="repeat" backgroundSize="cover" gap={0} w="100%" h="100vh" p={2}>
{/* ✅ Spheres */}
<span className="red-sphere-1" />
<span className="blue-sphere-1" />
<span className="red-sphere-2" />
<span className="blue-sphere-2" />
<span className="red-sphere-3" />
<span className="blue-sphere-2" />
<VStack shadow={'xs'} zIndex={1} gap={0} rounded={'lg'} h="100%" w="15%" bg="#222935" >
<HStack w={'100%'} p={3} h={'6.5%'} justifyContent={'space-between'}>
<Image w={8} src={logo} />
<GiHamburgerMenu cursor={'pointer'} style={{ fontSize: '20px' }} />
</HStack>
<VStack w={'100%'} p={3}>
<Text ps={'6px'} fontSize={'11px'} w={'100%'} fontWeight={'bold'}>Menu</Text>
{nav?.map(({ title, path, Icon, type, children }, index) => type === 'single' ?
<NavLink className="link" key={index} to={path} style={{ cursor: 'pointer', borderRadius: '8px', padding: '6px', width: '100%', display: 'flex', alignItems: 'center', gap: 6, border: '1px solid #222935' }} ><Icon style={{ fontSize: '20px' }} /> <Text fontSize={'xs'} w={'100%'}>{title}</Text></NavLink> :
<AccordionRoot>
<AccordionItem p={0} key={index} value={title}>
<AccordionItemTrigger className={`link ${location?.pathname === path && 'active'}`} onClick={() => navigate(path)} gap={0} style={{ cursor: 'pointer', borderRadius: '8px', padding: '5px', width: '100%', display: 'flex', alignItems: 'center', border: '1px solid #222935', fontSize: '14px' }}> <Text fontSize={'xs'} gap={1} display={'flex'} alignItems={'center'} ><Icon style={{ fontSize: '20px' }} />{title}</Text></AccordionItemTrigger>
{children?.map(({ title, path, Icon }, index) => <AccordionItemContent ps={4}><NavLink className="link" key={index} to={path} style={{ marginTop: 6, cursor: 'pointer', borderRadius: '8px', padding: '6px', width: '100%', display: 'flex', alignItems: 'center', gap: 6, border: '1px solid #222935' }} ><Icon style={{ fontSize: '20px' }} /> <Text fontSize={'xs'} w={'100%'}>{title}</Text></NavLink></AccordionItemContent>)}
</AccordionItem>
</AccordionRoot>)}
</VStack>
</VStack>
<VStack gap={0} h="100%" w="85%" >
<HStack h={'6%'} w={'100%'} justifyContent={'flex-end'} pe={3} gap={6}>
<RiNotificationLine cursor={'pointer'} style={{ fontSize: '22px' }} />
<HStack cursor={'pointer'} onClick={() => navigate('/profile')} >
<Avatar size={'sm'} src="https://i.pinimg.com/736x/d6/cd/0f/d6cd0ffd4634b0763d3958a7325ce26e.jpg" />
<VStack gap={0} alignItems={'flex-start'}>
<Text fontSize={'sm'} fontWeight={'bold'}>Ritesh Pandey</Text>
<Text fontSize={'xs'} >ritesh.pandey@wdimails.com</Text>
</VStack>
</HStack>
</HStack>
{children}
</VStack>
</HStack>
);
};
export default DefaultLayout;

View File

@@ -0,0 +1,23 @@
import { motion } from "framer-motion";
export const OPACITY_ON_LOAD = {
as: motion.div,
initial: { opacity: 0 },
animate: { opacity: 1 },
}
export const SLIDE_IN_BOTTOM = {
as: motion.div,
initial: { opacity: 0, y: 50 },
animate: { opacity: 1, y: 0 },
transition: { duration: 1, ease: "easeInOut" }
};
export const FADE_IN_SCALE_UP = {
as: motion.div,
initial: { opacity: 0, scale: 0.9 },
animate: { opacity: 1, scale: 1 },
transition: { duration: 0.5, ease: "easeInOut" }
};

6
src/Pages/CMS/CMS.tsx Normal file
View File

@@ -0,0 +1,6 @@
const CMS = () => {
return (
<div>CMS</div>
)
}
export default CMS

View File

@@ -0,0 +1,8 @@
const Dashboard = () => {
return (
<div>Dashboard</div>
)
}
export default Dashboard

93
src/Pages/Login.tsx Normal file
View File

@@ -0,0 +1,93 @@
import { Center, HStack, Image, Input, Text, VStack } from "@chakra-ui/react"
import logo from '../assets/logo.svg'
import bgImage from '../assets/bgImage.png'
import { Field } from "../components/ui/field"
import { useForm } from "react-hook-form"
import { InputGroup } from "../components/ui/input-group"
import { MdEmail } from "react-icons/md"
import { BiLock } from "react-icons/bi"
import { PasswordInput } from "../components/ui/password-input"
import GlobalStateContext from "../Contexts/GlobalStateContext"
import { useContext, useState } from "react"
import { Button } from "../components/ui/button"
import { Toaster, toaster } from "../components/ui/toaster"
interface FormValues {
email: string
password: string
}
const Login = () => {
const [ isLoading, setIsLoading ] = useState<boolean>(false)
const context = useContext(GlobalStateContext);
if (!context) {
throw new Error('App must be used within a GlobalStateProvider');
}
const { setIsAuthenticate } = context;
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormValues>()
const onSubmit = handleSubmit((data) => {
setIsLoading(true)
if (data?.email === 'Admin' && data?.password === 'Admin') {
setTimeout(() => {
setIsAuthenticate(true);
setIsLoading(false)
}, 3000); // 3-second delay
} else {
toaster.create({
title: `Invalid Credentials`,
type: "error",
})
setIsLoading(false)
}
});
return (
<HStack bg={'#222935'}
backgroundImage={`url(${bgImage})`}
backgroundPosition="center"
backgroundRepeat="repeat"
backgroundSize="cover"
w={'100%'} h={'100vh'}>
<Center display={{base:'none', md:'flex'}} bg={'#222935'} w={'55%'} h={'100%'}>
<Image w={150} src={logo} />
</Center>
<Center as={'form'} onSubmit={onSubmit} p={{base:4,md:16}} w={{base:'100%',md:'45%'}} h={'100%'}>
<VStack gap={2} w={'100%'} alignItems={'flex-start'}>
<Text w={'100%'} textAlign={'center'} fontSize={'24px'} fontWeight={'bold'}>Hello Again!</Text>
<Text w={'100%'} textAlign={'center'} fontSize={'sm'}>Welcome Back</Text>
<VStack mt={6} gap={4} w={'100%'}>
<Field invalid={!!errors.email} errorText={errors.email?.message} bgSize={'sm'} >
<InputGroup w={'100%'} flex="1" startElement={<MdEmail color="#fff" />}>
<Input fontSize={'sm'} {...register("email", { required: "Email address is required" })} placeholder="Email Address" focusRingColor={'#D90B2E'} variant="subtle" rounded={'full'} bg={'#434A53'} />
</InputGroup>
</Field>
<Field invalid={!!errors.password} errorText={errors.password?.message} >
<InputGroup w={'100%'} flex="1" startElement={<BiLock color="#fff" />}>
<PasswordInput fontSize={'sm'} {...register("password", { required: "Password address is required" })} placeholder="Password" focusRingColor={'#D90B2E'} variant="subtle" rounded={'full'} bg={'#434A53'} />
</InputGroup>
</Field>
<Button loading={isLoading} mt={4} size={'sm'} bg={'#D90B2E'} rounded={'full'} w={'100%'} color={'#ffffff'} type="submit">Send OTP</Button>
<Text>Forgot password</Text>
</VStack>
</VStack>
</Center>
<Toaster />
</HStack>
)
}
export default Login

View File

@@ -0,0 +1,10 @@
import MainFrame from "../../components/MainFrame"
const ManageCommunity = () => {
return (
<MainFrame title="Manage Community">
</MainFrame>
)
}
export default ManageCommunity

View File

@@ -0,0 +1,11 @@
import MainFrame from "../../components/MainFrame"
const ManagePost = () => {
return (
<MainFrame title="Manage Post">
</MainFrame>
)
}
export default ManagePost

View File

@@ -0,0 +1,11 @@
import MainFrame from "../../components/MainFrame"
const ManageGroups = () => {
return (
<MainFrame title="Manage Group">
</MainFrame>
)
}
export default ManageGroups

View File

@@ -0,0 +1,11 @@
import MainFrame from "../../components/MainFrame"
const ManageUsers = () => {
return (
<MainFrame title="Manage User">
</MainFrame>
)
}
export default ManageUsers

8
src/Pages/NotFound.tsx Normal file
View File

@@ -0,0 +1,8 @@
const NotFound = () => {
return (
<div>NotFound</div>
)
}
export default NotFound

View File

@@ -0,0 +1,6 @@
const Notification = () => {
return (
<div>Notification</div>
)
}
export default Notification

View File

@@ -0,0 +1,11 @@
import MainFrame from "../../components/MainFrame"
const Profile = () => {
return (
<MainFrame title="Pofile">
</MainFrame>
)
}
export default Profile

View File

@@ -0,0 +1,11 @@
import MainFrame from "../../components/MainFrame"
const Reporting = () => {
return (
<MainFrame title="Manage Report">
</MainFrame>
)
}
export default Reporting

View File

@@ -0,0 +1,11 @@
import MainFrame from "../../components/MainFrame"
const SubAdmin = () => {
return (
<MainFrame title="Manage Subadmin">
</MainFrame>
)
}
export default SubAdmin

View File

@@ -0,0 +1,11 @@
import MainFrame from "../../components/MainFrame"
const Support = () => {
return (
<MainFrame title="Manage Support">
</MainFrame>
)
}
export default Support

75
src/Routes/Nav.ts Normal file
View File

@@ -0,0 +1,75 @@
import { LiaUsersSolid } from "react-icons/lia";
import { LuBellDot } from "react-icons/lu";
import { MdOutlineSupportAgent, MdPostAdd } from "react-icons/md";
import { RiUserSettingsLine } from "react-icons/ri";
import { TbFileSettings, TbLayoutDashboard, TbReport, TbUsers, TbUsersGroup } from "react-icons/tb";
export const nav = [
{
title: "Dashboard",
path: "/",
Icon: TbLayoutDashboard,
type:'single'
},
{
title: "Manage Users",
path: "/manage-user",
Icon: TbUsers,
type:'single'
},
{
title: "Manage Groups",
path: "/manage-groups",
Icon: TbUsersGroup,
type:'single'
},
{
title: "Community",
path: "/manage-community",
Icon: LiaUsersSolid,
type:'multiple',
children: [
// {
// title: "Manage Community",
// path: "/manage-community",
// Icon: RiUserCommunityLine,
// },
{
title: "Manage Post",
path: "/manage-post",
Icon: MdPostAdd,
},
],
},
{
title: "Support",
path: "/support",
Icon: MdOutlineSupportAgent,
type:'single'
},
{
title: "Sub-Admin",
path: "/sub-admin",
Icon: RiUserSettingsLine,
type:'single'
},
{
title: "Reporting",
path: "/reporting",
Icon: TbReport,
type:'single'
},
{
title: "CMS",
path: "/cms",
Icon: TbFileSettings,
type:'single'
},
{
title: "Manage Notifications",
path: "/manage-notification",
Icon: LuBellDot,
type:'single'
}
];

24
src/Routes/Routes.ts Normal file
View File

@@ -0,0 +1,24 @@
import CMS from "../Pages/CMS/CMS";
import Dashboard from "../Pages/Dashboard/Dashboard";
import ManageCommunity from "../Pages/ManageCommunity/ManageCommunity";
import ManagePost from "../Pages/ManageCommunity/ManagePost";
import ManageGroups from "../Pages/ManageGroups/ManageGroups";
import ManageUsers from "../Pages/ManageUsers/ManageUsers";
import Profile from "../Pages/Profile/Profile";
import Reporting from "../Pages/Reporting/Reporting";
import SubAdmin from "../Pages/SubAdmin/SubAdmin";
import Support from "../Pages/Support/Support";
export const RouteLink = [
{ path: "/", Component: Dashboard },
{ path: "/manage-user", Component: ManageUsers },
{ path: "/manage-groups", Component: ManageGroups },
{ path: "/manage-community", Component: ManageCommunity},
{ path: "/manage-post", Component: ManagePost},
{ path: "/support", Component: Support},
{ path: "/sub-admin", Component: SubAdmin},
{ path: "/reporting", Component: Reporting},
{ path: "/cms", Component: CMS},
{ path: "/manage-notification", Component: CMS},
{ path: "/profile", Component: Profile},
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
src/assets/bgImage.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

BIN
src/assets/favIcon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 850 B

11
src/assets/logo.svg Normal file
View File

@@ -0,0 +1,11 @@
<svg width="253" height="167" viewBox="0 0 253 167" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M167.181 42.4477H159.188H137.084C137.083 45.3569 136.481 48.0573 135.237 50.4247H158.33C154.826 65.8862 140.985 77.4928 124.479 77.5324C124.45 77.5324 124.421 77.5324 124.393 77.5324C115.154 77.5324 106.468 73.9464 99.9309 67.4294C93.3498 60.8702 89.7216 52.1222 89.712 42.7957C89.7107 41.9292 89.7461 41.0682 89.8089 40.2126H81.7855C81.7418 40.985 81.7132 41.76 81.7118 42.5378C81.6818 54.0094 86.0933 64.785 94.1344 72.878C102.177 80.9723 112.914 85.4425 124.368 85.4657C124.397 85.4657 124.424 85.4657 124.453 85.4657C145.419 85.4657 162.919 70.3222 166.509 50.4234C166.944 48.0109 167.187 45.5329 167.195 42.999C167.195 42.8148 167.184 42.6319 167.181 42.4477Z" fill="#D90B2E"/>
<path d="M124.481 69.5375C125.387 69.5348 126.283 69.4925 127.173 69.4215C123.824 64.8067 120.657 60.4389 117.418 55.9741C126.226 53.0118 129.917 46.2587 129.244 38.1521C128.521 29.4328 123.018 23.695 114.177 23.5107C111.912 23.4644 109.647 23.4412 107.382 23.4261H95.5595C96.8094 21.5622 98.2476 19.8047 99.8673 18.1796C106.422 11.6053 115.145 7.9811 124.426 7.97564C124.434 7.97564 124.44 7.97564 124.448 7.97564C133.728 7.97564 142.453 11.5875 149.013 18.1454C151.667 20.7981 153.829 23.8096 155.476 27.0653H164.162C157.881 11.2996 142.513 0.0846005 124.549 0C124.482 0 124.415 0 124.348 0C113.102 0 102.467 4.41287 94.3805 12.4404C88.8638 17.9176 85.0254 24.5955 83.1123 31.8575H91.4564C91.4577 31.8548 91.4577 31.8521 91.4591 31.8494C94.6343 31.848 97.8082 31.8562 100.983 31.8575H105.024V31.8603C106.809 31.863 108.592 31.8589 110.377 31.8644C111.699 31.8685 113.032 31.9762 114.339 32.1768C117.232 32.623 119.298 34.4624 119.701 37.0646C119.919 38.4809 119.989 39.9614 119.845 41.3833C119.44 45.3991 117.517 47.585 113.504 48.0708C109.988 48.4965 106.41 48.431 102.86 48.573C102.239 48.5975 101.617 48.577 100.661 48.577L114.975 68.2371C118.003 69.0858 121.163 69.5348 124.395 69.5348C124.422 69.5375 124.451 69.5375 124.481 69.5375Z" fill="#D90B2E"/>
<path d="M0 156.088V116.713H17.0443C20.5688 116.713 23.6063 117.285 26.1566 118.428C28.7069 119.573 30.6745 121.213 32.0622 123.35C33.4486 125.487 34.1431 128.018 34.1431 130.944C34.1431 133.906 33.4486 136.447 32.0622 138.566C30.6745 140.685 28.7055 142.298 26.1566 143.403C23.6063 144.51 20.5688 145.062 17.0443 145.062H5.00644L9.1696 141.124V156.086H0V156.088ZM9.16824 142.137L5.00507 137.806H16.5367C19.3107 137.806 21.4107 137.207 22.8367 136.006C24.2612 134.806 24.9749 133.119 24.9749 130.944C24.9749 128.768 24.2626 127.09 22.8367 125.908C21.4107 124.727 19.3107 124.136 16.5367 124.136H5.00507L9.16824 119.805V142.137ZM25.0868 156.088L15.1872 141.8H24.9749L34.8745 156.088H25.0868Z" fill="#D90B2E"/>
<path d="M55.7437 156.538C52.2929 156.538 49.2745 155.862 46.6874 154.513C44.1003 153.163 42.093 151.316 40.6685 148.973C39.2426 146.63 38.5303 143.958 38.5303 140.958C38.5303 137.958 39.2139 135.276 40.5839 132.914C41.9525 130.552 43.8642 128.704 46.3217 127.374C48.7778 126.043 51.5437 125.377 54.618 125.377C57.5804 125.377 60.2521 126.016 62.6332 127.291C65.0143 128.566 66.8987 130.366 68.2864 132.69C69.6728 135.015 70.3673 137.808 70.3673 141.071C70.3673 141.408 70.3482 141.793 70.3114 142.224C70.2732 142.655 70.2364 143.059 70.1995 143.433H45.6176V138.315H65.5874L62.1556 139.833C62.1925 138.259 61.8923 136.89 61.2551 135.727C60.6165 134.565 59.7363 133.656 58.6106 133C57.4862 132.343 56.1722 132.016 54.6726 132.016C53.1716 132.016 51.8508 132.345 50.7073 133C49.5624 133.656 48.6728 134.574 48.0355 135.756C47.397 136.938 47.079 138.335 47.079 139.946V141.296C47.079 142.984 47.4529 144.447 48.2034 145.683C48.9525 146.921 49.9841 147.868 51.2968 148.524C52.6094 149.18 54.1841 149.508 56.0221 149.508C57.5968 149.508 58.994 149.265 60.2126 148.776C61.4311 148.289 62.5473 147.558 63.5597 146.582L68.2291 151.645C66.8414 153.219 65.0976 154.43 62.9976 155.273C60.8989 156.115 58.4796 156.538 55.7437 156.538Z" fill="#D90B2E"/>
<path d="M95.8495 156.762C92.737 156.762 89.8674 156.264 87.2434 155.272C84.6181 154.278 82.3502 152.862 80.4372 151.025C78.5241 149.189 77.034 147.031 75.9656 144.556C74.8972 142.081 74.3623 139.363 74.3623 136.4C74.3623 133.438 74.8972 130.718 75.9656 128.244C77.034 125.769 78.5432 123.613 80.4945 121.775C82.4444 119.939 84.7313 118.522 87.3567 117.529C89.9807 116.535 92.8693 116.039 96.0187 116.039C99.5064 116.039 102.646 116.62 105.441 117.783C108.234 118.945 110.588 120.633 112.501 122.845L106.707 128.246C105.244 126.708 103.67 125.574 101.982 124.843C100.294 124.111 98.438 123.746 96.413 123.746C94.5368 123.746 92.8134 124.055 91.2374 124.674C89.6627 125.292 88.3023 126.164 87.1588 127.289C86.014 128.414 85.1339 129.745 84.5144 131.283C83.8962 132.821 83.5865 134.527 83.5865 136.402C83.5865 138.201 83.8962 139.88 84.5144 141.437C85.1325 142.994 86.014 144.334 87.1588 145.458C88.3023 146.582 89.6518 147.465 91.2087 148.102C92.7643 148.741 94.4795 149.059 96.3557 149.059C98.1555 149.059 99.9089 148.759 101.615 148.158C103.32 147.559 104.979 146.565 106.592 145.177L111.768 151.758C109.593 153.409 107.099 154.655 104.286 155.498C101.474 156.341 98.6618 156.762 95.8495 156.762ZM103.443 150.575V135.781H111.768V151.755L103.443 150.575Z" fill="#D90B2E"/>
<path d="M119.587 156.088V125.825H127.968V134.431L126.786 131.9C127.686 129.762 129.129 128.141 131.117 127.034C133.104 125.929 135.523 125.375 138.373 125.375V133.531C138.036 133.456 137.708 133.4 137.39 133.362C137.07 133.325 136.761 133.306 136.462 133.306C133.986 133.306 132.017 134 130.555 135.387C129.092 136.774 128.361 138.912 128.361 141.8V156.088H119.587Z" fill="#D90B2E"/>
<path d="M158.174 156.538C154.987 156.538 152.146 155.862 149.653 154.513C147.159 153.163 145.199 151.316 143.775 148.973C142.349 146.63 141.636 143.958 141.636 140.958C141.636 137.92 142.349 135.229 143.775 132.885C145.199 130.542 147.159 128.704 149.653 127.373C152.146 126.042 154.987 125.376 158.174 125.376C161.399 125.376 164.268 126.042 166.781 127.373C169.293 128.704 171.262 130.542 172.688 132.885C174.112 135.229 174.826 137.92 174.826 140.958C174.826 143.995 174.113 146.676 172.688 149.002C171.262 151.327 169.293 153.163 166.781 154.514C164.268 155.862 161.399 156.538 158.174 156.538ZM158.174 149.337C159.674 149.337 160.996 149.01 162.14 148.353C163.283 147.698 164.202 146.732 164.896 145.457C165.589 144.182 165.937 142.682 165.937 140.956C165.937 139.193 165.591 137.694 164.896 136.456C164.202 135.219 163.283 134.272 162.14 133.615C160.995 132.96 159.693 132.631 158.23 132.631C156.768 132.631 155.455 132.96 154.292 133.615C153.13 134.272 152.202 135.219 151.507 136.456C150.813 137.694 150.466 139.193 150.466 140.956C150.466 142.681 150.813 144.182 151.507 145.457C152.201 146.732 153.128 147.697 154.292 148.353C155.455 149.01 156.749 149.337 158.174 149.337Z" fill="#D90B2E"/>
<path d="M193.443 156.538C190.893 156.538 188.642 156.051 186.693 155.075C184.743 154.101 183.224 152.6 182.136 150.575C181.049 148.55 180.504 146 180.504 142.926V125.825H189.28V141.576C189.28 144.126 189.815 145.992 190.883 147.173C191.951 148.355 193.461 148.946 195.412 148.946C196.761 148.946 197.962 148.646 199.011 148.045C200.061 147.446 200.896 146.546 201.514 145.345C202.132 144.146 202.442 142.645 202.442 140.845V125.825H211.161V156.088H202.836V147.707L204.355 150.182C203.304 152.282 201.805 153.866 199.855 154.935C197.905 156.003 195.768 156.538 193.443 156.538Z" fill="#D90B2E"/>
<path d="M219.319 167V125.824H227.7V132.012L227.53 141.012L228.092 149.956V167H219.319ZM237.15 156.538C234.637 156.538 232.425 155.976 230.513 154.85C228.6 153.726 227.11 152.009 226.042 149.703C224.973 147.397 224.438 144.481 224.438 140.957C224.438 137.394 224.945 134.47 225.957 132.181C226.969 129.894 228.44 128.187 230.373 127.063C232.303 125.939 234.563 125.375 237.15 125.375C240.038 125.375 242.615 126.022 244.884 127.315C247.152 128.609 248.953 130.418 250.285 132.743C251.616 135.069 252.281 137.806 252.281 140.957C252.281 144.144 251.616 146.891 250.285 149.197C248.953 151.503 247.154 153.303 244.884 154.598C242.615 155.891 240.036 156.538 237.15 156.538ZM235.687 149.337C237.15 149.337 238.452 149 239.597 148.325C240.74 147.649 241.659 146.685 242.353 145.428C243.046 144.171 243.394 142.681 243.394 140.957C243.394 139.194 243.048 137.694 242.353 136.456C241.659 135.219 240.74 134.272 239.597 133.615C238.452 132.96 237.15 132.632 235.687 132.632C234.225 132.632 232.912 132.96 231.749 133.615C230.587 134.272 229.659 135.219 228.964 136.456C228.27 137.694 227.923 139.194 227.923 140.957C227.923 142.681 228.27 144.173 228.964 145.428C229.658 146.685 230.585 147.649 231.749 148.325C232.912 149 234.225 149.337 235.687 149.337Z" fill="#D90B2E"/>
</svg>

After

Width:  |  Height:  |  Size: 8.5 KiB

1
src/assets/react.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

4
src/assets/redogo.svg Normal file
View File

@@ -0,0 +1,4 @@
<svg width="45" height="45" viewBox="0 0 45 45" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M44.5262 22.1134H40.362H28.8468C28.8461 23.6289 28.5326 25.0357 27.8843 26.2691H39.9149C38.0894 34.3238 30.8791 40.3704 22.2799 40.391C22.2649 40.391 22.25 40.391 22.2351 40.391C17.4218 40.391 12.8972 38.5229 9.49148 35.1278C6.063 31.7107 4.17283 27.1534 4.16785 22.2946C4.16714 21.8432 4.18562 21.3947 4.21832 20.949H0.0384642C0.0157166 21.3513 0.000790152 21.7551 7.9292e-05 22.1603C-0.0155596 28.1365 2.28265 33.7501 6.47175 37.9662C10.6616 42.1831 16.2553 44.5118 22.2223 44.5239C22.2372 44.5239 22.2514 44.5239 22.2663 44.5239C33.1887 44.5239 42.3055 36.6348 44.1758 26.2683C44.4025 25.0115 44.529 23.7206 44.5333 22.4006C44.5333 22.3046 44.5276 22.2093 44.5262 22.1134Z" fill="#D90B2E"/>
<path d="M22.2806 36.2261C22.7526 36.2247 23.2197 36.2027 23.6832 36.1657C21.9387 33.7616 20.2888 31.4861 18.6012 29.1602C23.1898 27.6169 25.1127 24.0989 24.7622 19.8756C24.3855 15.3332 21.5186 12.3441 16.9129 12.2481C15.7329 12.2239 14.5529 12.2119 13.3728 12.204H7.21395C7.8651 11.233 8.61435 10.3174 9.45814 9.47079C12.8731 6.04586 17.4169 4.15782 22.2522 4.15497C22.2565 4.15497 22.2593 4.15497 22.2636 4.15497C27.0981 4.15497 31.6434 6.03662 35.0612 9.45302C36.4438 10.8349 37.5698 12.4038 38.4278 14.0999H42.9531C39.6811 5.88663 31.6746 0.0440733 22.3162 0C22.2813 0 22.2465 0 22.2117 0C16.3528 0 10.8123 2.29892 6.59977 6.48091C3.72576 9.3343 1.72612 12.8132 0.729492 16.5964H5.0764C5.07711 16.595 5.07711 16.5936 5.07782 16.5922C6.73199 16.5915 8.38545 16.5957 10.0396 16.5964H12.1445V16.5979C13.0743 16.5993 14.0034 16.5972 14.9332 16.6C15.622 16.6021 16.3165 16.6583 16.9975 16.7628C18.5045 16.9952 19.5808 17.9535 19.7905 19.3091C19.9042 20.047 19.9405 20.8182 19.8658 21.559C19.6547 23.651 18.6531 24.7898 16.5625 25.0429C14.7306 25.2647 12.8667 25.2306 11.0171 25.3045C10.6936 25.3173 10.3695 25.3066 9.87186 25.3066L17.3288 35.5487C18.9062 35.9908 20.5525 36.2247 22.2358 36.2247C22.2501 36.2261 22.265 36.2261 22.2806 36.2261Z" fill="#D90B2E"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,35 @@
import { Box, Text, VStack } from "@chakra-ui/react"
import { motion } from "framer-motion"
import React, { FC } from "react"
import { OPACITY_ON_LOAD } from "../Layouts/animations"
// ✅ Wrap Chakra components with Framer Motion
const MotionVStack = motion(VStack)
interface MainFrameProps {
children: React.ReactNode
title?: string
}
const MainFrame: FC<MainFrameProps> = ({ children, title }) => {
return (
<MotionVStack {...OPACITY_ON_LOAD} w="100%" h="94%" p={4} pt={0} pb={0} >
<Text color={'#fff'} w="100%" fontSize="sm" display="flex" alignItems="center" h="3%">
{title}
</Text>
<Box
w="100%"
h="97%"
border="1px solid #ffffff30"
bg="#434A5330"
rounded="md"
backdropFilter="blur(10px)"
shadow={'xs'}
>
{children}
</Box>
</MotionVStack>
)
}
export default MainFrame

View File

@@ -0,0 +1,47 @@
import { Accordion, HStack } from "@chakra-ui/react"
import * as React from "react"
import { LuChevronDown } from "react-icons/lu"
interface AccordionItemTriggerProps extends Accordion.ItemTriggerProps {
indicatorPlacement?: "start" | "end"
}
export const AccordionItemTrigger = React.forwardRef<
HTMLButtonElement,
AccordionItemTriggerProps
>(function AccordionItemTrigger(props, ref) {
const { children, indicatorPlacement = "end", ...rest } = props
return (
<Accordion.ItemTrigger {...rest} ref={ref}>
{indicatorPlacement === "start" && (
<Accordion.ItemIndicator rotate={{ base: "-90deg", _open: "0deg" }}>
<LuChevronDown />
</Accordion.ItemIndicator>
)}
<HStack gap="4" flex="1" textAlign="start" width="full">
{children}
</HStack>
{indicatorPlacement === "end" && (
<Accordion.ItemIndicator>
<LuChevronDown />
</Accordion.ItemIndicator>
)}
</Accordion.ItemTrigger>
)
})
interface AccordionItemContentProps extends Accordion.ItemContentProps {}
export const AccordionItemContent = React.forwardRef<
HTMLDivElement,
AccordionItemContentProps
>(function AccordionItemContent(props, ref) {
return (
<Accordion.ItemContent>
<Accordion.ItemBody {...props} ref={ref} />
</Accordion.ItemContent>
)
})
export const AccordionRoot = Accordion.Root
export const AccordionItem = Accordion.Item

View File

@@ -0,0 +1,74 @@
"use client"
import type { GroupProps, SlotRecipeProps } from "@chakra-ui/react"
import { Avatar as ChakraAvatar, Group } from "@chakra-ui/react"
import * as React from "react"
type ImageProps = React.ImgHTMLAttributes<HTMLImageElement>
export interface AvatarProps extends ChakraAvatar.RootProps {
name?: string
src?: string
srcSet?: string
loading?: ImageProps["loading"]
icon?: React.ReactElement
fallback?: React.ReactNode
}
export const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(
function Avatar(props, ref) {
const { name, src, srcSet, loading, icon, fallback, children, ...rest } =
props
return (
<ChakraAvatar.Root ref={ref} {...rest}>
<AvatarFallback name={name} icon={icon}>
{fallback}
</AvatarFallback>
<ChakraAvatar.Image src={src} srcSet={srcSet} loading={loading} />
{children}
</ChakraAvatar.Root>
)
},
)
interface AvatarFallbackProps extends ChakraAvatar.FallbackProps {
name?: string
icon?: React.ReactElement
}
const AvatarFallback = React.forwardRef<HTMLDivElement, AvatarFallbackProps>(
function AvatarFallback(props, ref) {
const { name, icon, children, ...rest } = props
return (
<ChakraAvatar.Fallback ref={ref} {...rest}>
{children}
{name != null && children == null && <>{getInitials(name)}</>}
{name == null && children == null && (
<ChakraAvatar.Icon asChild={!!icon}>{icon}</ChakraAvatar.Icon>
)}
</ChakraAvatar.Fallback>
)
},
)
function getInitials(name: string) {
const names = name.trim().split(" ")
const firstName = names[0] != null ? names[0] : ""
const lastName = names.length > 1 ? names[names.length - 1] : ""
return firstName && lastName
? `${firstName.charAt(0)}${lastName.charAt(0)}`
: firstName.charAt(0)
}
interface AvatarGroupProps extends GroupProps, SlotRecipeProps<"avatar"> {}
export const AvatarGroup = React.forwardRef<HTMLDivElement, AvatarGroupProps>(
function AvatarGroup(props, ref) {
const { size, variant, borderless, ...rest } = props
return (
<ChakraAvatar.PropsProvider value={{ size, variant, borderless }}>
<Group gap="0" spaceX="-3" ref={ref} {...rest} />
</ChakraAvatar.PropsProvider>
)
},
)

View File

@@ -0,0 +1,40 @@
import type { ButtonProps as ChakraButtonProps } from "@chakra-ui/react"
import {
AbsoluteCenter,
Button as ChakraButton,
Span,
Spinner,
} from "@chakra-ui/react"
import * as React from "react"
interface ButtonLoadingProps {
loading?: boolean
loadingText?: React.ReactNode
}
export interface ButtonProps extends ChakraButtonProps, ButtonLoadingProps {}
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
function Button(props, ref) {
const { loading, disabled, loadingText, children, ...rest } = props
return (
<ChakraButton disabled={loading || disabled} ref={ref} {...rest}>
{loading && !loadingText ? (
<>
<AbsoluteCenter display="inline-flex">
<Spinner size="inherit" color="inherit" />
</AbsoluteCenter>
<Span opacity={0}>{children}</Span>
</>
) : loading && loadingText ? (
<>
<Spinner size="inherit" color="inherit" />
{loadingText}
</>
) : (
children
)}
</ChakraButton>
)
},
)

View File

@@ -0,0 +1,25 @@
import { Checkbox as ChakraCheckbox } from "@chakra-ui/react"
import * as React from "react"
export interface CheckboxProps extends ChakraCheckbox.RootProps {
icon?: React.ReactNode
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
rootRef?: React.Ref<HTMLLabelElement>
}
export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
function Checkbox(props, ref) {
const { icon, children, inputProps, rootRef, ...rest } = props
return (
<ChakraCheckbox.Root ref={rootRef} {...rest}>
<ChakraCheckbox.HiddenInput ref={ref} {...inputProps} />
<ChakraCheckbox.Control>
{icon || <ChakraCheckbox.Indicator />}
</ChakraCheckbox.Control>
{children != null && (
<ChakraCheckbox.Label>{children}</ChakraCheckbox.Label>
)}
</ChakraCheckbox.Root>
)
},
)

View File

@@ -0,0 +1,17 @@
import type { ButtonProps } from "@chakra-ui/react"
import { IconButton as ChakraIconButton } from "@chakra-ui/react"
import * as React from "react"
import { LuX } from "react-icons/lu"
export type CloseButtonProps = ButtonProps
export const CloseButton = React.forwardRef<
HTMLButtonElement,
CloseButtonProps
>(function CloseButton(props, ref) {
return (
<ChakraIconButton variant="ghost" aria-label="Close" ref={ref} {...props}>
{props.children ?? <LuX />}
</ChakraIconButton>
)
})

View File

@@ -0,0 +1,67 @@
"use client"
import type { IconButtonProps } from "@chakra-ui/react"
import { ClientOnly, IconButton, Skeleton } from "@chakra-ui/react"
import { ThemeProvider, useTheme } from "next-themes"
import type { ThemeProviderProps } from "next-themes"
import * as React from "react"
import { LuMoon, LuSun } from "react-icons/lu"
export interface ColorModeProviderProps extends ThemeProviderProps {}
export function ColorModeProvider(props: ColorModeProviderProps) {
return (
<ThemeProvider attribute="class" disableTransitionOnChange {...props} />
)
}
export function useColorMode() {
const { resolvedTheme, setTheme } = useTheme()
const toggleColorMode = () => {
setTheme(resolvedTheme === "light" ? "dark" : "light")
}
return {
colorMode: resolvedTheme,
setColorMode: setTheme,
toggleColorMode,
}
}
export function useColorModeValue<T>(light: T, dark: T) {
const { colorMode } = useColorMode()
return colorMode === "light" ? light : dark
}
export function ColorModeIcon() {
const { colorMode } = useColorMode()
return colorMode === "light" ? <LuSun /> : <LuMoon />
}
interface ColorModeButtonProps extends Omit<IconButtonProps, "aria-label"> {}
export const ColorModeButton = React.forwardRef<
HTMLButtonElement,
ColorModeButtonProps
>(function ColorModeButton(props, ref) {
const { toggleColorMode } = useColorMode()
return (
<ClientOnly fallback={<Skeleton boxSize="8" />}>
<IconButton
onClick={toggleColorMode}
variant="ghost"
aria-label="Toggle color mode"
size="sm"
ref={ref}
{...props}
css={{
_icon: {
width: "5",
height: "5",
},
}}
>
<ColorModeIcon />
</IconButton>
</ClientOnly>
)
})

View File

@@ -0,0 +1,62 @@
import { Dialog as ChakraDialog, Portal } from "@chakra-ui/react"
import { CloseButton } from "./close-button"
import * as React from "react"
interface DialogContentProps extends ChakraDialog.ContentProps {
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
backdrop?: boolean
}
export const DialogContent = React.forwardRef<
HTMLDivElement,
DialogContentProps
>(function DialogContent(props, ref) {
const {
children,
portalled = true,
portalRef,
backdrop = true,
...rest
} = props
return (
<Portal disabled={!portalled} container={portalRef}>
{backdrop && <ChakraDialog.Backdrop />}
<ChakraDialog.Positioner>
<ChakraDialog.Content ref={ref} {...rest} asChild={false}>
{children}
</ChakraDialog.Content>
</ChakraDialog.Positioner>
</Portal>
)
})
export const DialogCloseTrigger = React.forwardRef<
HTMLButtonElement,
ChakraDialog.CloseTriggerProps
>(function DialogCloseTrigger(props, ref) {
return (
<ChakraDialog.CloseTrigger
position="absolute"
top="2"
insetEnd="2"
{...props}
asChild
>
<CloseButton size="sm" ref={ref}>
{props.children}
</CloseButton>
</ChakraDialog.CloseTrigger>
)
})
export const DialogRoot = ChakraDialog.Root
export const DialogFooter = ChakraDialog.Footer
export const DialogHeader = ChakraDialog.Header
export const DialogBody = ChakraDialog.Body
export const DialogBackdrop = ChakraDialog.Backdrop
export const DialogTitle = ChakraDialog.Title
export const DialogDescription = ChakraDialog.Description
export const DialogTrigger = ChakraDialog.Trigger
export const DialogActionTrigger = ChakraDialog.ActionTrigger

View File

@@ -0,0 +1,52 @@
import { Drawer as ChakraDrawer, Portal } from "@chakra-ui/react"
import { CloseButton } from "./close-button"
import * as React from "react"
interface DrawerContentProps extends ChakraDrawer.ContentProps {
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
offset?: ChakraDrawer.ContentProps["padding"]
}
export const DrawerContent = React.forwardRef<
HTMLDivElement,
DrawerContentProps
>(function DrawerContent(props, ref) {
const { children, portalled = true, portalRef, offset, ...rest } = props
return (
<Portal disabled={!portalled} container={portalRef}>
<ChakraDrawer.Positioner padding={offset}>
<ChakraDrawer.Content ref={ref} {...rest} asChild={false}>
{children}
</ChakraDrawer.Content>
</ChakraDrawer.Positioner>
</Portal>
)
})
export const DrawerCloseTrigger = React.forwardRef<
HTMLButtonElement,
ChakraDrawer.CloseTriggerProps
>(function DrawerCloseTrigger(props, ref) {
return (
<ChakraDrawer.CloseTrigger
position="absolute"
top="2"
insetEnd="2"
{...props}
asChild
>
<CloseButton size="sm" ref={ref} />
</ChakraDrawer.CloseTrigger>
)
})
export const DrawerTrigger = ChakraDrawer.Trigger
export const DrawerRoot = ChakraDrawer.Root
export const DrawerFooter = ChakraDrawer.Footer
export const DrawerHeader = ChakraDrawer.Header
export const DrawerBody = ChakraDrawer.Body
export const DrawerBackdrop = ChakraDrawer.Backdrop
export const DrawerDescription = ChakraDrawer.Description
export const DrawerTitle = ChakraDrawer.Title
export const DrawerActionTrigger = ChakraDrawer.ActionTrigger

View File

@@ -0,0 +1,33 @@
import { Field as ChakraField } from "@chakra-ui/react"
import * as React from "react"
export interface FieldProps extends Omit<ChakraField.RootProps, "label"> {
label?: React.ReactNode
helperText?: React.ReactNode
errorText?: React.ReactNode
optionalText?: React.ReactNode
}
export const Field = React.forwardRef<HTMLDivElement, FieldProps>(
function Field(props, ref) {
const { label, children, helperText, errorText, optionalText, ...rest } =
props
return (
<ChakraField.Root ref={ref} {...rest}>
{label && (
<ChakraField.Label>
{label}
<ChakraField.RequiredIndicator fallback={optionalText} />
</ChakraField.Label>
)}
{children}
{helperText && (
<ChakraField.HelperText>{helperText}</ChakraField.HelperText>
)}
{errorText && (
<ChakraField.ErrorText>{errorText}</ChakraField.ErrorText>
)}
</ChakraField.Root>
)
},
)

View File

@@ -0,0 +1,53 @@
import type { BoxProps, InputElementProps } from "@chakra-ui/react"
import { Group, InputElement } from "@chakra-ui/react"
import * as React from "react"
export interface InputGroupProps extends BoxProps {
startElementProps?: InputElementProps
endElementProps?: InputElementProps
startElement?: React.ReactNode
endElement?: React.ReactNode
children: React.ReactElement<InputElementProps>
startOffset?: InputElementProps["paddingStart"]
endOffset?: InputElementProps["paddingEnd"]
}
export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
function InputGroup(props, ref) {
const {
startElement,
startElementProps,
endElement,
endElementProps,
children,
startOffset = "6px",
endOffset = "6px",
...rest
} = props
const child =
React.Children.only<React.ReactElement<InputElementProps>>(children)
return (
<Group ref={ref} {...rest}>
{startElement && (
<InputElement pointerEvents="none" {...startElementProps}>
{startElement}
</InputElement>
)}
{React.cloneElement(child, {
...(startElement && {
ps: `calc(var(--input-height) - ${startOffset})`,
}),
...(endElement && { pe: `calc(var(--input-height) - ${endOffset})` }),
...children.props,
})}
{endElement && (
<InputElement placement="end" {...endElementProps}>
{endElement}
</InputElement>
)}
</Group>
)
},
)

View File

@@ -0,0 +1,148 @@
"use client"
import type {
ButtonProps,
GroupProps,
InputProps,
StackProps,
} from "@chakra-ui/react"
import {
Box,
HStack,
IconButton,
Input,
Stack,
mergeRefs,
useControllableState,
} from "@chakra-ui/react"
import * as React from "react"
import { LuEye, LuEyeOff } from "react-icons/lu"
import { InputGroup } from "./input-group"
export interface PasswordVisibilityProps {
defaultVisible?: boolean
visible?: boolean
onVisibleChange?: (visible: boolean) => void
visibilityIcon?: { on: React.ReactNode; off: React.ReactNode }
}
export interface PasswordInputProps
extends InputProps,
PasswordVisibilityProps {
rootProps?: GroupProps
}
export const PasswordInput = React.forwardRef<
HTMLInputElement,
PasswordInputProps
>(function PasswordInput(props, ref) {
const {
rootProps,
defaultVisible,
visible: visibleProp,
onVisibleChange,
visibilityIcon = { on: <LuEye />, off: <LuEyeOff /> },
...rest
} = props
const [visible, setVisible] = useControllableState({
value: visibleProp,
defaultValue: defaultVisible || false,
onChange: onVisibleChange,
})
const inputRef = React.useRef<HTMLInputElement>(null)
return (
<InputGroup
width="full"
endElement={
<VisibilityTrigger
disabled={rest.disabled}
onPointerDown={(e) => {
if (rest.disabled) return
if (e.button !== 0) return
e.preventDefault()
setVisible(!visible)
}}
>
{visible ? visibilityIcon.off : visibilityIcon.on}
</VisibilityTrigger>
}
{...rootProps}
>
<Input
{...rest}
ref={mergeRefs(ref, inputRef)}
type={visible ? "text" : "password"}
/>
</InputGroup>
)
})
const VisibilityTrigger = React.forwardRef<HTMLButtonElement, ButtonProps>(
function VisibilityTrigger(props, ref) {
return (
<IconButton
tabIndex={-1}
ref={ref}
me="-2"
aspectRatio="square"
size="sm"
variant="ghost"
height="calc(100% - {spacing.2})"
aria-label="Toggle password visibility"
{...props}
/>
)
},
)
interface PasswordStrengthMeterProps extends StackProps {
max?: number
value: number
}
export const PasswordStrengthMeter = React.forwardRef<
HTMLDivElement,
PasswordStrengthMeterProps
>(function PasswordStrengthMeter(props, ref) {
const { max = 4, value, ...rest } = props
const percent = (value / max) * 100
const { label, colorPalette } = getColorPalette(percent)
return (
<Stack align="flex-end" gap="1" ref={ref} {...rest}>
<HStack width="full" ref={ref} {...rest}>
{Array.from({ length: max }).map((_, index) => (
<Box
key={index}
height="1"
flex="1"
rounded="sm"
data-selected={index < value ? "" : undefined}
layerStyle="fill.subtle"
colorPalette="gray"
_selected={{
colorPalette,
layerStyle: "fill.solid",
}}
/>
))}
</HStack>
{label && <HStack textStyle="xs">{label}</HStack>}
</Stack>
)
})
function getColorPalette(percent: number) {
switch (true) {
case percent < 33:
return { label: "Low", colorPalette: "red" }
case percent < 66:
return { label: "Medium", colorPalette: "orange" }
default:
return { label: "High", colorPalette: "green" }
}
}

View File

@@ -0,0 +1,59 @@
import { Popover as ChakraPopover, Portal } from "@chakra-ui/react"
import { CloseButton } from "./close-button"
import * as React from "react"
interface PopoverContentProps extends ChakraPopover.ContentProps {
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
}
export const PopoverContent = React.forwardRef<
HTMLDivElement,
PopoverContentProps
>(function PopoverContent(props, ref) {
const { portalled = true, portalRef, ...rest } = props
return (
<Portal disabled={!portalled} container={portalRef}>
<ChakraPopover.Positioner>
<ChakraPopover.Content ref={ref} {...rest} />
</ChakraPopover.Positioner>
</Portal>
)
})
export const PopoverArrow = React.forwardRef<
HTMLDivElement,
ChakraPopover.ArrowProps
>(function PopoverArrow(props, ref) {
return (
<ChakraPopover.Arrow {...props} ref={ref}>
<ChakraPopover.ArrowTip />
</ChakraPopover.Arrow>
)
})
export const PopoverCloseTrigger = React.forwardRef<
HTMLButtonElement,
ChakraPopover.CloseTriggerProps
>(function PopoverCloseTrigger(props, ref) {
return (
<ChakraPopover.CloseTrigger
position="absolute"
top="1"
insetEnd="1"
{...props}
asChild
ref={ref}
>
<CloseButton size="sm" />
</ChakraPopover.CloseTrigger>
)
})
export const PopoverTitle = ChakraPopover.Title
export const PopoverDescription = ChakraPopover.Description
export const PopoverFooter = ChakraPopover.Footer
export const PopoverHeader = ChakraPopover.Header
export const PopoverRoot = ChakraPopover.Root
export const PopoverBody = ChakraPopover.Body
export const PopoverTrigger = ChakraPopover.Trigger

View File

@@ -0,0 +1,15 @@
"use client"
import { ChakraProvider, defaultSystem } from "@chakra-ui/react"
import {
ColorModeProvider,
type ColorModeProviderProps,
} from "./color-mode"
export function Provider(props: ColorModeProviderProps) {
return (
<ChakraProvider value={defaultSystem}>
<ColorModeProvider {...props} />
</ChakraProvider>
)
}

View File

@@ -0,0 +1,24 @@
import { RadioGroup as ChakraRadioGroup } from "@chakra-ui/react"
import * as React from "react"
export interface RadioProps extends ChakraRadioGroup.ItemProps {
rootRef?: React.Ref<HTMLDivElement>
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
}
export const Radio = React.forwardRef<HTMLInputElement, RadioProps>(
function Radio(props, ref) {
const { children, inputProps, rootRef, ...rest } = props
return (
<ChakraRadioGroup.Item ref={rootRef} {...rest}>
<ChakraRadioGroup.ItemHiddenInput ref={ref} {...inputProps} />
<ChakraRadioGroup.ItemIndicator />
{children && (
<ChakraRadioGroup.ItemText>{children}</ChakraRadioGroup.ItemText>
)}
</ChakraRadioGroup.Item>
)
},
)
export const RadioGroup = ChakraRadioGroup.Root

View File

@@ -0,0 +1,143 @@
"use client"
import type { CollectionItem } from "@chakra-ui/react"
import { Select as ChakraSelect, Portal } from "@chakra-ui/react"
import { CloseButton } from "./close-button"
import * as React from "react"
interface SelectTriggerProps extends ChakraSelect.ControlProps {
clearable?: boolean
}
export const SelectTrigger = React.forwardRef<
HTMLButtonElement,
SelectTriggerProps
>(function SelectTrigger(props, ref) {
const { children, clearable, ...rest } = props
return (
<ChakraSelect.Control {...rest}>
<ChakraSelect.Trigger ref={ref}>{children}</ChakraSelect.Trigger>
<ChakraSelect.IndicatorGroup>
{clearable && <SelectClearTrigger />}
<ChakraSelect.Indicator />
</ChakraSelect.IndicatorGroup>
</ChakraSelect.Control>
)
})
const SelectClearTrigger = React.forwardRef<
HTMLButtonElement,
ChakraSelect.ClearTriggerProps
>(function SelectClearTrigger(props, ref) {
return (
<ChakraSelect.ClearTrigger asChild {...props} ref={ref}>
<CloseButton
size="xs"
variant="plain"
focusVisibleRing="inside"
focusRingWidth="2px"
pointerEvents="auto"
/>
</ChakraSelect.ClearTrigger>
)
})
interface SelectContentProps extends ChakraSelect.ContentProps {
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
}
export const SelectContent = React.forwardRef<
HTMLDivElement,
SelectContentProps
>(function SelectContent(props, ref) {
const { portalled = true, portalRef, ...rest } = props
return (
<Portal disabled={!portalled} container={portalRef}>
<ChakraSelect.Positioner>
<ChakraSelect.Content {...rest} ref={ref} />
</ChakraSelect.Positioner>
</Portal>
)
})
export const SelectItem = React.forwardRef<
HTMLDivElement,
ChakraSelect.ItemProps
>(function SelectItem(props, ref) {
const { item, children, ...rest } = props
return (
<ChakraSelect.Item key={item.value} item={item} {...rest} ref={ref}>
{children}
<ChakraSelect.ItemIndicator />
</ChakraSelect.Item>
)
})
interface SelectValueTextProps
extends Omit<ChakraSelect.ValueTextProps, "children"> {
children?(items: CollectionItem[]): React.ReactNode
}
export const SelectValueText = React.forwardRef<
HTMLSpanElement,
SelectValueTextProps
>(function SelectValueText(props, ref) {
const { children, ...rest } = props
return (
<ChakraSelect.ValueText {...rest} ref={ref}>
<ChakraSelect.Context>
{(select) => {
const items = select.selectedItems
if (items.length === 0) return props.placeholder
if (children) return children(items)
if (items.length === 1)
return select.collection.stringifyItem(items[0])
return `${items.length} selected`
}}
</ChakraSelect.Context>
</ChakraSelect.ValueText>
)
})
export const SelectRoot = React.forwardRef<
HTMLDivElement,
ChakraSelect.RootProps
>(function SelectRoot(props, ref) {
return (
<ChakraSelect.Root
{...props}
ref={ref}
positioning={{ sameWidth: true, ...props.positioning }}
>
{props.asChild ? (
props.children
) : (
<>
<ChakraSelect.HiddenSelect />
{props.children}
</>
)}
</ChakraSelect.Root>
)
}) as ChakraSelect.RootComponent
interface SelectItemGroupProps extends ChakraSelect.ItemGroupProps {
label: React.ReactNode
}
export const SelectItemGroup = React.forwardRef<
HTMLDivElement,
SelectItemGroupProps
>(function SelectItemGroup(props, ref) {
const { children, label, ...rest } = props
return (
<ChakraSelect.ItemGroup {...rest} ref={ref}>
<ChakraSelect.ItemGroupLabel>{label}</ChakraSelect.ItemGroupLabel>
{children}
</ChakraSelect.ItemGroup>
)
})
export const SelectLabel = ChakraSelect.Label
export const SelectItemText = ChakraSelect.ItemText

View File

@@ -0,0 +1,82 @@
import { Slider as ChakraSlider, For, HStack } from "@chakra-ui/react"
import * as React from "react"
export interface SliderProps extends ChakraSlider.RootProps {
marks?: Array<number | { value: number; label: React.ReactNode }>
label?: React.ReactNode
showValue?: boolean
}
export const Slider = React.forwardRef<HTMLDivElement, SliderProps>(
function Slider(props, ref) {
const { marks: marksProp, label, showValue, ...rest } = props
const value = props.defaultValue ?? props.value
const marks = marksProp?.map((mark) => {
if (typeof mark === "number") return { value: mark, label: undefined }
return mark
})
const hasMarkLabel = !!marks?.some((mark) => mark.label)
return (
<ChakraSlider.Root ref={ref} thumbAlignment="center" {...rest}>
{label && !showValue && (
<ChakraSlider.Label>{label}</ChakraSlider.Label>
)}
{label && showValue && (
<HStack justify="space-between">
<ChakraSlider.Label>{label}</ChakraSlider.Label>
<ChakraSlider.ValueText />
</HStack>
)}
<ChakraSlider.Control data-has-mark-label={hasMarkLabel || undefined}>
<ChakraSlider.Track>
<ChakraSlider.Range />
</ChakraSlider.Track>
<SliderThumbs value={value} />
<SliderMarks marks={marks} />
</ChakraSlider.Control>
</ChakraSlider.Root>
)
},
)
function SliderThumbs(props: { value?: number[] }) {
const { value } = props
return (
<For each={value}>
{(_, index) => (
<ChakraSlider.Thumb key={index} index={index}>
<ChakraSlider.HiddenInput />
</ChakraSlider.Thumb>
)}
</For>
)
}
interface SliderMarksProps {
marks?: Array<number | { value: number; label: React.ReactNode }>
}
const SliderMarks = React.forwardRef<HTMLDivElement, SliderMarksProps>(
function SliderMarks(props, ref) {
const { marks } = props
if (!marks?.length) return null
return (
<ChakraSlider.MarkerGroup ref={ref}>
{marks.map((mark, index) => {
const value = typeof mark === "number" ? mark : mark.value
const label = typeof mark === "number" ? undefined : mark.label
return (
<ChakraSlider.Marker key={index} value={value}>
<ChakraSlider.MarkerIndicator />
{label}
</ChakraSlider.Marker>
)
})}
</ChakraSlider.MarkerGroup>
)
},
)

View File

@@ -0,0 +1,44 @@
"use client"
import {
Toaster as ChakraToaster,
Portal,
Spinner,
Stack,
Toast,
createToaster,
} from "@chakra-ui/react"
export const toaster = createToaster({
placement:'bottom',
pauseOnPageIdle: true,
max:1
})
export const Toaster = () => {
return (
<Portal>
<ChakraToaster toaster={toaster} insetInline={{ mdDown: "4" }}>
{(toast) => (
<Toast.Root width={{ md: "sm" }}>
{toast.type === "loading" ? (
<Spinner size="sm" color="blue.solid" />
) : (
<Toast.Indicator />
)}
<Stack rounded={'full'} gap="1" flex="1" maxWidth="100%">
{toast.title && <Toast.Title>{toast.title}</Toast.Title>}
{toast.description && (
<Toast.Description>{toast.description}</Toast.Description>
)}
</Stack>
{toast.action && (
<Toast.ActionTrigger>{toast.action.label}</Toast.ActionTrigger>
)}
{toast.meta?.closable && <Toast.CloseTrigger />}
</Toast.Root>
)}
</ChakraToaster>
</Portal>
)
}

View File

@@ -0,0 +1,46 @@
import { Tooltip as ChakraTooltip, Portal } from "@chakra-ui/react"
import * as React from "react"
export interface TooltipProps extends ChakraTooltip.RootProps {
showArrow?: boolean
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
content: React.ReactNode
contentProps?: ChakraTooltip.ContentProps
disabled?: boolean
}
export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>(
function Tooltip(props, ref) {
const {
showArrow,
children,
disabled,
portalled,
content,
contentProps,
portalRef,
...rest
} = props
if (disabled) return children
return (
<ChakraTooltip.Root {...rest}>
<ChakraTooltip.Trigger asChild>{children}</ChakraTooltip.Trigger>
<Portal disabled={!portalled} container={portalRef}>
<ChakraTooltip.Positioner>
<ChakraTooltip.Content ref={ref} {...contentProps}>
{showArrow && (
<ChakraTooltip.Arrow>
<ChakraTooltip.ArrowTip />
</ChakraTooltip.Arrow>
)}
{content}
</ChakraTooltip.Content>
</ChakraTooltip.Positioner>
</Portal>
</ChakraTooltip.Root>
)
},
)

105
src/index.css Normal file
View File

@@ -0,0 +1,105 @@
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
.active {
background-color: #434A53;
color: #fff;
border: 1px solid #ffffff20 !important;
transition: all 0.5s;
border-radius: 8px;
/* background-color: #e2e8f01c; */
}
.active:hover {
background-color: #434A53;
color: #fff;
border: 1px solid #ffffff20 !important;
transition: all 0.5s;
border-radius: 8px;
/* background-color: #e2e8f01c !important; */
}
.link{
transition: all 0.5s;
}
.link:hover {
background-color: #434A53;
color: #fff;
border: 1px solid #ffffff20 !important;
/* color: #fff; */
/* background-color: #e2e8f01c !important; */
}
/* Sphere.css */
/* ✅ Red Spheres */
.red-sphere-1,
.red-sphere-2,
.red-sphere-3{
position: absolute;
border-radius: 50%;
background-color: #D90B2E46;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
filter: blur(100px);
}
/* ✅ Blue Spheres */
.blue-sphere-1,
.blue-sphere-2,
.blue-sphere-3{
position: absolute;
border-radius: 50%;
background-color: #009DAB46;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
filter: blur(100px);
}
/* 🔧 Positioning for Spheres */
.red-sphere-1 {
width: 250px;
height: 250px;
top: 10%;
left: 5%;
}
.blue-sphere-1 {
width: 320px;
height: 320px;
top: 30%;
right: 0%;
}
.red-sphere-2 {
width: 180px;
height: 180px;
bottom: 15%;
left: 20%;
}
.blue-sphere-2 {
width: 140px;
height: 140px;
bottom: 5%;
right: 25%;
}
.red-sphere-3 {
width: 480px;
height: 480px;
bottom: 55%;
left: 40%;
}
.blue-sphere-3{
width: 300px;
height: 300px;
bottom: 10%;
right: 40%;
}

17
src/main.tsx Normal file
View File

@@ -0,0 +1,17 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import { Provider } from './components/ui/provider'
import GlobalStateProvider from './Contexts/GlobalStateProvider'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<GlobalStateProvider>
<Provider>
<App />
</Provider>
</GlobalStateProvider>
</React.StrictMode>,
)

1
src/vite-env.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
/// <reference types="vite/client" />

27
tsconfig.app.json Normal file
View File

@@ -0,0 +1,27 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"incremental": true,
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
// "noUncheckedSideEffectImports": true
},
"include": ["src"]
}

7
tsconfig.json Normal file
View File

@@ -0,0 +1,7 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}

24
tsconfig.node.json Normal file
View File

@@ -0,0 +1,24 @@
{
"compilerOptions": {
// "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
// "noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}

51
vite.config.ts Normal file
View File

@@ -0,0 +1,51 @@
// vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { VitePWA } from "vite-plugin-pwa";
export default defineConfig({
server: {
host: "0.0.0.0",
port: 3001, // You can use any port
},
plugins: [
react(),
VitePWA({
registerType: "autoUpdate",
devOptions: {
enabled: true,
},
manifest: {
name: "Re Group",
short_name: "RG",
description: "Join your community now",
start_url: "/",
display: "standalone",
theme_color: "#222935",
background_color: "#222935",
icons: [
{
src: "/icon-192x192.png",
sizes: "192x192",
type: "image/png",
},
{
src: "/icon-256x256.png",
sizes: "256x256",
type: "image/png",
},
{
src: "/icon-384x384.png",
sizes: "384x384",
type: "image/png",
},
{
src: "/icon-512x512.png",
sizes: "512x512",
type: "image/png",
},
],
},
}),
],
});