From d65380363e2f1f1701921738ae86a0d7e3a1597b Mon Sep 17 00:00:00 2001 From: victorAnumudu Date: Wed, 12 Feb 2025 23:20:40 +0100 Subject: [PATCH] started dashboard layout --- src/App.js | 25 +++- src/RouteLinks.js | 8 ++ src/SiteRoutes.jsx | 36 ++++++ src/assets/user_avatar.jpg | Bin 0 -> 28862 bytes src/authorization/UserExist.jsx | 47 ++++++++ src/components/DummyLogo.jsx | 8 ++ src/components/MainBtn.jsx | 20 ++++ src/components/auth/LoginCom.jsx | 34 +++--- src/components/breadcrumb/BreadcrumbCom.jsx | 19 +++ src/components/layouts/DashboardHeader.jsx | 83 +++++++++++++ src/components/layouts/DashboardLayout.jsx | 64 ++++++++++ src/components/layouts/HandBurger.jsx | 36 ++++++ src/components/layouts/LogoutModal.jsx | 52 +++++++++ src/components/layouts/aside/AsideLink.jsx | 17 +++ .../layouts/aside/AsideLinkWithSubLinks.jsx | 33 ++++++ .../layouts/aside/DashboardAside.jsx | 96 +++++++++++++++ src/components/links/FooterLinks.jsx | 33 ++++++ src/components/links/NavLinks.jsx | 34 ++++++ src/components/links/NavLinksWithSubLinks.jsx | 109 ++++++++++++++++++ src/components/modals/DummyModalChildren.jsx | 34 ++++++ src/components/modals/ModalWrapper.jsx | 15 +++ src/context/DefaultLayoutContext.jsx | 25 ++++ src/context/GeneralLayoutContext.jsx | 77 +++++++++++++ src/index.css | 36 ++++++ src/index.js | 14 ++- src/pages/HomePage.jsx | 13 +++ src/pages/UsersPage.jsx | 13 +++ src/store/UserDetails.js | 20 ++++ src/store/store.js | 9 ++ tailwind.config.js | 38 +++++- 30 files changed, 1025 insertions(+), 23 deletions(-) create mode 100644 src/RouteLinks.js create mode 100644 src/SiteRoutes.jsx create mode 100644 src/assets/user_avatar.jpg create mode 100644 src/authorization/UserExist.jsx create mode 100644 src/components/DummyLogo.jsx create mode 100644 src/components/MainBtn.jsx create mode 100644 src/components/breadcrumb/BreadcrumbCom.jsx create mode 100644 src/components/layouts/DashboardHeader.jsx create mode 100644 src/components/layouts/DashboardLayout.jsx create mode 100644 src/components/layouts/HandBurger.jsx create mode 100644 src/components/layouts/LogoutModal.jsx create mode 100644 src/components/layouts/aside/AsideLink.jsx create mode 100644 src/components/layouts/aside/AsideLinkWithSubLinks.jsx create mode 100644 src/components/layouts/aside/DashboardAside.jsx create mode 100644 src/components/links/FooterLinks.jsx create mode 100644 src/components/links/NavLinks.jsx create mode 100644 src/components/links/NavLinksWithSubLinks.jsx create mode 100644 src/components/modals/DummyModalChildren.jsx create mode 100644 src/components/modals/ModalWrapper.jsx create mode 100644 src/context/DefaultLayoutContext.jsx create mode 100644 src/context/GeneralLayoutContext.jsx create mode 100644 src/pages/HomePage.jsx create mode 100644 src/pages/UsersPage.jsx create mode 100644 src/store/UserDetails.js create mode 100644 src/store/store.js diff --git a/src/App.js b/src/App.js index 275dc52..d3fcfda 100644 --- a/src/App.js +++ b/src/App.js @@ -1,12 +1,29 @@ +import { useEffect } from 'react' +import { useLocation } from 'react-router-dom' + +import SiteRoutes from './SiteRoutes'; +import LogoutModal from './components/layouts/LogoutModal'; +import { generalLayoutContext } from './context/GeneralLayoutContext'; import './App.css'; -import LoginPage from './pages/LoginPage'; function App() { + + const {pathname} = useLocation() + + const {logoutModal, setLogoutModal} = generalLayoutContext() + + useEffect(()=>{ + window.scrollTo(0,0) + },[pathname]) + return ( -
- -
+ <> + + + {/* LOGOUT MODAL */} + {logoutModal && setLogoutModal(false)} />} + ); } diff --git a/src/RouteLinks.js b/src/RouteLinks.js new file mode 100644 index 0000000..b99e3e9 --- /dev/null +++ b/src/RouteLinks.js @@ -0,0 +1,8 @@ +const RouteLinks = { + loginPage: '/auth/login', + errorPage: '*', + homePage: '/', + usersPage: '/users', +} + +export default RouteLinks \ No newline at end of file diff --git a/src/SiteRoutes.jsx b/src/SiteRoutes.jsx new file mode 100644 index 0000000..a0a20eb --- /dev/null +++ b/src/SiteRoutes.jsx @@ -0,0 +1,36 @@ +import { lazy, Suspense } from 'react' +import { Routes, Route } from 'react-router-dom' +import RouteLinks from './RouteLinks' + +import UserExist from './authorization/UserExist' +import PageLoader from './components/PageLoader' + +import LoginPage from './pages/LoginPage' // LOGIN PAGE +import HomePage from './pages/HomePage' // Home PAGE +import UsersPage from './pages/UsersPage' // Users PAGE + + +// const Home = lazy(() => import('./pages/Home')); + +export default function SiteRoutes() { + return ( + + } /> {`*/LOGIN PAGE*/`} + + }> + } /> {`*/HOME PAGE*/`} + } /> {`*/USERS PAGE*/`} + + + {/* ERROR PAGE */} + }> +

Error Page 1

+ + } + /> +
+ ) +} diff --git a/src/assets/user_avatar.jpg b/src/assets/user_avatar.jpg new file mode 100644 index 0000000000000000000000000000000000000000..699f262cda194616672a388b328be77bb08b1c5b GIT binary patch literal 28862 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 state.userDetails) + + useEffect(()=>{ + const loadUser = (token) =>{ + const userExist = [{name:'dummy'}] + if(userExist && userExist.length > 0){ + dispatch(updateUserDetails(userExist[0])) + setPageIsLoading(false) + }else{ + navigate(RouteLinks.login, {replace:true}) + } + } + if(userDetails.name){ + setPageIsLoading(false) + }else if(!userDetails.name && localStorage.getItem('token')){ + loadUser(localStorage.getItem('token')) + }else{ + navigate(RouteLinks.loginPage, {replace:true}) + } + },[]) + + return ( + <> + {pageIsLoading ? + + : + // + + } + + ) +} diff --git a/src/components/DummyLogo.jsx b/src/components/DummyLogo.jsx new file mode 100644 index 0000000..8d3f36d --- /dev/null +++ b/src/components/DummyLogo.jsx @@ -0,0 +1,8 @@ +export default function DummyLogo() { + return ( +
+

digiFI

+

Admin

+
+ ) +} diff --git a/src/components/MainBtn.jsx b/src/components/MainBtn.jsx new file mode 100644 index 0000000..4c770af --- /dev/null +++ b/src/components/MainBtn.jsx @@ -0,0 +1,20 @@ +export default function MainBtn({ + onClick, + className, + text, + shrinkAside, + icon, + loading, + disabled +}) { + return ( + + ) +} diff --git a/src/components/auth/LoginCom.jsx b/src/components/auth/LoginCom.jsx index 4315838..77c4e2f 100644 --- a/src/components/auth/LoginCom.jsx +++ b/src/components/auth/LoginCom.jsx @@ -1,21 +1,24 @@ import React, { useEffect, useState } from 'react' -// import { useLocation, useNavigate } from 'react-router-dom' +import { useDispatch } from 'react-redux' +import { useLocation, useNavigate } from 'react-router-dom' // import { useMutation } from '@tanstack/react-query' -// import myLinks from '../../myLinks' import Label from '../Label' import InputText from '../InputText' import PageLoader from '../PageLoader' +import { updateUserDetails } from "../../store/UserDetails"; // import { loginUser } from '../../services/siteServices' import GoogleDownload from '../../assets/download/andriod.jpg' import IOSDownload from '../../assets/download/apple.jpg' +import RouteLinks from '../../RouteLinks' export default function LoginCom() { + + const dispatch = useDispatch() + const navigate = useNavigate() - const [loading, setLoading] = useState(true) - // const {state} = useLocation() - // const navigate = useNavigate() + const [loading, setLoading] = useState(false) const [fields, setFields] = useState({ username: '', @@ -49,20 +52,18 @@ export default function LoginCom() { // }) - useEffect(()=>{ - // if(state?.proceed != 'true'){ - // return navigate(myLinks.getStarted, {replace:true}) - // } + const handleLogin = () => { + setLoading(true) + const data = {name: 'dummy'} + localStorage.setItem('token', 'token') + dispatch(updateUserDetails({ ...data })); setTimeout(()=>{ - setLoading(false) - },200) - },[]) + navigate(RouteLinks.homePage, {replace:true}) + },500) + } return ( <> - {loading ? - - :
@@ -88,7 +89,7 @@ export default function LoginCom() {
{/* */} - +
@@ -107,7 +108,6 @@ export default function LoginCom() {
- } ) } diff --git a/src/components/breadcrumb/BreadcrumbCom.jsx b/src/components/breadcrumb/BreadcrumbCom.jsx new file mode 100644 index 0000000..16191c0 --- /dev/null +++ b/src/components/breadcrumb/BreadcrumbCom.jsx @@ -0,0 +1,19 @@ +import { MdKeyboardDoubleArrowRight } from 'react-icons/md' +import { TiHomeOutline } from 'react-icons/ti' + +export default function BreadcrumbCom({title, paths}) { + return ( +
+

{title}

+
+ + {paths.map((item, index) => ( +
+ +

{item}

+
+ ))} +
+
+ ) +} diff --git a/src/components/layouts/DashboardHeader.jsx b/src/components/layouts/DashboardHeader.jsx new file mode 100644 index 0000000..344cc20 --- /dev/null +++ b/src/components/layouts/DashboardHeader.jsx @@ -0,0 +1,83 @@ +import { LuSunDim } from "react-icons/lu"; +import { IoMdSunny } from "react-icons/io"; + +import { generalLayoutContext } from "../../context/GeneralLayoutContext" + +import UserAvatar from '../../assets/user_avatar.jpg' +import HandBurger from "./HandBurger" +import { Link } from "react-router-dom" +import RouteLinks from "../../RouteLinks" + +export default function DashboardHeader({showAsideDrawer, setShowAsideDrawer}) { + const {theme, handleTheme, handleDrawer, setLogoutModal} = generalLayoutContext() + + return ( + <> + {/* HEADER SECTION*/} +
+
+
+ setShowAsideDrawer(prev => !prev)} showAside={showAsideDrawer} barColor="bg-black-gray" /> +
+ + {/* USER AVATAR */} +
+ + {/* GO TO WALLET */} + + + + + {/* MESSAGE */} + {/* */} + + {/* NOTIFICATION */} + {/* */} + + {/* THEME SELECTION */} +
+ {theme == 'dark' ? + + : + + } +
+ + {/* USER AVATRA */} +
+ user image +
+
+ + {/* */} + +
+
+
+
+ + ) +} diff --git a/src/components/layouts/DashboardLayout.jsx b/src/components/layouts/DashboardLayout.jsx new file mode 100644 index 0000000..09481ca --- /dev/null +++ b/src/components/layouts/DashboardLayout.jsx @@ -0,0 +1,64 @@ +import { useEffect, useState } from 'react' +import { Outlet } from 'react-router-dom' +import { FaArrowRight, FaArrowLeft } from "react-icons/fa6"; + +import DashboardAside from './aside/DashboardAside' +import DashboardHeader from './DashboardHeader' +import { generalLayoutContext } from '../../context/GeneralLayoutContext' + +export default function DashboardLayout() { + const [shrinkAside, setShrinkAside] = useState(false) + + const [showAsideDrawer, setShowAsideDrawer] = useState(false) + + useEffect(()=>{ + window.addEventListener('resize', ()=>{ + setShrinkAside(false) + setShowAsideDrawer(false) + }) + },[]) + return ( +
+ + +
setShowAsideDrawer(prev => !prev)} className={`${showAsideDrawer ? 'left-0' : '-left-96'} w-72 lg:hidden fixed inset-0 z-[999] bg-black text-white-light`}> + + +
+ +
+ {/* HEADER SECTION generalLayoutContext*/} + + + {/* BODY SECTION */} + {/* main takes the full width minus that of the header and footer 72 for header, 39 for footer total 111 */} +
+ +
+ + {/* FOOTER SECTION */} +
+

Copyright @ {new Date().getFullYear()} - Developed by digiFi. All Rights Reserved

+
+
+
+ ) +} diff --git a/src/components/layouts/HandBurger.jsx b/src/components/layouts/HandBurger.jsx new file mode 100644 index 0000000..68e6349 --- /dev/null +++ b/src/components/layouts/HandBurger.jsx @@ -0,0 +1,36 @@ + +export default function HandBurger({showAside, asideDisplay, barColor}) { + return ( +
+ {/*
*/} +
+
+
+
+ ) +} diff --git a/src/components/layouts/LogoutModal.jsx b/src/components/layouts/LogoutModal.jsx new file mode 100644 index 0000000..06c5f7b --- /dev/null +++ b/src/components/layouts/LogoutModal.jsx @@ -0,0 +1,52 @@ +import { useNavigate } from "react-router-dom" +import MainBtn from "../MainBtn" +import ModalWrapper from "../modals/ModalWrapper" +import RouteLinks from "../../RouteLinks" +import { updateUserDetails } from "../../store/UserDetails" +import { useDispatch } from "react-redux" + + +export default function LogoutModal({close}) { + const navigate = useNavigate() + + const dispatch = useDispatch() + + const handleLogout = () => { + dispatch(updateUserDetails({})) + localStorage.clear() + navigate(RouteLinks.loginPage, {replace:true}) + close() + // location.reload() + } + return ( + +
+ {/* */} +
+

+ LOGOUT +

+ +
+ {/* */} +
+ +

Are you sure you want to logout?

+
+ + +
+
+ {/* */} +
+
+ ) +} \ No newline at end of file diff --git a/src/components/layouts/aside/AsideLink.jsx b/src/components/layouts/aside/AsideLink.jsx new file mode 100644 index 0000000..eee17d9 --- /dev/null +++ b/src/components/layouts/aside/AsideLink.jsx @@ -0,0 +1,17 @@ +import { Link, useLocation } from "react-router-dom" + +export default function AsideLink({shrinkAside, name, to, icon}) { + + const {pathname} = useLocation() + + return ( + + {/* {icon && } */} + {icon && } + {shrinkAside ? '' : name} + + ) +} diff --git a/src/components/layouts/aside/AsideLinkWithSubLinks.jsx b/src/components/layouts/aside/AsideLinkWithSubLinks.jsx new file mode 100644 index 0000000..aa965c1 --- /dev/null +++ b/src/components/layouts/aside/AsideLinkWithSubLinks.jsx @@ -0,0 +1,33 @@ +import { ReactNode } from "react" +// import { useLocation } from "react-router-dom" + + +export default function AsideLinkWithSubLinks({shrinkAside, name, icon, hideSubMenu, setHideSubMenu, children}) { + + // const btnName = name + +// const {pathname} = useLocation() + +// const [hideSubMenu, setHideSubMenu] = useState(true) + + return ( + // + // {icon && } + // {shrinkAside ? '' : name} + // +
+ +
+ {children} +
+
+ ) +} diff --git a/src/components/layouts/aside/DashboardAside.jsx b/src/components/layouts/aside/DashboardAside.jsx new file mode 100644 index 0000000..c30ecaa --- /dev/null +++ b/src/components/layouts/aside/DashboardAside.jsx @@ -0,0 +1,96 @@ +import { useState } from "react"; +import {Link, useLocation} from 'react-router-dom' +import RouteLinks from "../../../RouteLinks"; +import DummyLogo from "../../DummyLogo"; +import MainBtn from "../../MainBtn"; +import AsideLink from "./AsideLink"; +import AsideLinkWithSubLinks from "./AsideLinkWithSubLinks"; +import { useSelector } from "react-redux"; +import { generalLayoutContext } from "../../../context/GeneralLayoutContext"; + +import { AiOutlineDashboard } from "react-icons/ai"; +import { IoPeople } from "react-icons/io5"; + + +export default function DashboardAside({shrinkAside=false}) { + + const {pathname} = useLocation() + + const {setLogoutModal} = generalLayoutContext() + + const {userDetails} = useSelector((state) => state.userDetails) // GETS LOGGED IN USER ROLE DETAILS + const {role}= userDetails + + const [hideSubMenu, setHideSubMenu] = useState('') + + const handleHideSubMenu = (e) => { + e.stopPropagation() + let name = e.target.name + setHideSubMenu((prev) => { + if(prev == name){ + return '' + }else{ + return name + } + }) + } + + return ( +
+
+ +
+
+ +
+ + + {shrinkAside ? '' : 'Dashboard'} + + +
+

Admin

+ + + {shrinkAside ? '' : 'Users'} + +
+ + {/*
+

Admin

+ + + + + + + + +
*/} + + {/*
+

Admin

+ + +
*/} +
+
+
+ setLogoutModal(true)} + /> +
+
+
+ ) +} diff --git a/src/components/links/FooterLinks.jsx b/src/components/links/FooterLinks.jsx new file mode 100644 index 0000000..4f81d93 --- /dev/null +++ b/src/components/links/FooterLinks.jsx @@ -0,0 +1,33 @@ +import { Link, useLocation } from "react-router-dom" +import { layoutDefaultContext } from "../../context/DefaultLayoutContext" + + +export default function FooterLinks({ + linkName, + href, +}) { + + const {pathname} = useLocation() + + const {subLinkIsActive, setSubLinkIsActive} = layoutDefaultContext() // CONTEXT TO GET WHEN A SUBLINK IS CLICKED + + return ( + { + if(subLinkIsActive){ + setSubLinkIsActive((prev)=>{ + if(prev == linkName){ + return null + }else{ + return linkName + } + }) + } + }} + > + {linkName} + + ) +} diff --git a/src/components/links/NavLinks.jsx b/src/components/links/NavLinks.jsx new file mode 100644 index 0000000..975047a --- /dev/null +++ b/src/components/links/NavLinks.jsx @@ -0,0 +1,34 @@ +import { Link, useLocation } from "react-router-dom" +import { layoutDefaultContext } from "../../context/DefaultLayoutContext" + +export default function NavLinks({ + linkName, + href, +}) { + + const {pathname} = useLocation() + + const {subLinkIsActive, setSubLinkIsActive} = layoutDefaultContext() // CONTEXT TO GET WHEN A SUBLINK IS CLICKED + + return ( + { + if(subLinkIsActive){ + setSubLinkIsActive((prev)=>{ + // e.stopPropagation() + // console.log('bubble') + if(prev == linkName){ + return null + }else{ + return linkName + } + }) + } + }} + > + {linkName} + + ) +} diff --git a/src/components/links/NavLinksWithSubLinks.jsx b/src/components/links/NavLinksWithSubLinks.jsx new file mode 100644 index 0000000..2b8c4c7 --- /dev/null +++ b/src/components/links/NavLinksWithSubLinks.jsx @@ -0,0 +1,109 @@ +// import { useLocation } from "react-router-dom" +import NavLinks from "./NavLinks" +import { layoutDefaultContext } from "../../context/DefaultLayoutContext" + + +export default function NavLinksWithSubLinks({ + linkName, + subLink=[], + asLink=true, +}) { + +// const {pathname} = useLocation() + const {subLinkIsActive, setSubLinkIsActive} = layoutDefaultContext() // CONTEXT TO GET WHEN A SUBLINK IS CLICKED + + return ( + // + // + // {linkName} + // + // + // {/* sub links section */} + //
+ // {subLink.map(item => ( + //
+ // + //
+ // ))} + //
+ // + + <> + {asLink ? + + : + + } + + ) +} diff --git a/src/components/modals/DummyModalChildren.jsx b/src/components/modals/DummyModalChildren.jsx new file mode 100644 index 0000000..9ad15bc --- /dev/null +++ b/src/components/modals/DummyModalChildren.jsx @@ -0,0 +1,34 @@ +export default function DummyModalChildren() { + return ( + <> +
+ {/* */} +
+

+ Terms of Service +

+ +
+ {/* */} +
+

+ With less than a month to go before the European Union enacts new consumer privacy laws for its citizens, companies around the world are updating their terms of service agreements to comply. +

+

+ The European Union’s General Data Protection Regulation (G.D.P.R.) goes into effect on May 25 and is meant to ensure a common set of data rights in the European Union. It requires organizations to notify users as soon as possible of high-risk data breaches that could personally affect them. +

+
+ {/* */} +
+ + +
+
+ + ) +} diff --git a/src/components/modals/ModalWrapper.jsx b/src/components/modals/ModalWrapper.jsx new file mode 100644 index 0000000..81f1791 --- /dev/null +++ b/src/components/modals/ModalWrapper.jsx @@ -0,0 +1,15 @@ + +export default function ModalWrapper({children, maxWidth}) { + return ( +
+
+ {/* */} +
+ {children} +
+
+
+ ) +} + +// id="default-modal" tabIndex={-1} aria-hidden="true" \ No newline at end of file diff --git a/src/context/DefaultLayoutContext.jsx b/src/context/DefaultLayoutContext.jsx new file mode 100644 index 0000000..a5257f8 --- /dev/null +++ b/src/context/DefaultLayoutContext.jsx @@ -0,0 +1,25 @@ +import { createContext, Dispatch, ReactNode, SetStateAction, useContext, useState } from 'react' + +const DefaultLayoutProvider = createContext({}) + +export default function DefaultLayoutContext({children}) { + + const [subLinkIsActive, setSubLinkIsActive] = useState(null) + + + const values = { + subLinkIsActive, + setSubLinkIsActive + } + + return ( + + {children} + + ) +} + + +export const layoutDefaultContext = () => { + return useContext(DefaultLayoutProvider) +} diff --git a/src/context/GeneralLayoutContext.jsx b/src/context/GeneralLayoutContext.jsx new file mode 100644 index 0000000..48dc0d0 --- /dev/null +++ b/src/context/GeneralLayoutContext.jsx @@ -0,0 +1,77 @@ +import { createContext, useContext, useEffect, useState } from 'react' + +const GeneralContextProvider = createContext({}) + +export default function GeneralLayoutContext({children}) { + + const [theme, setTheme] = useState(null) + + const [drawer, setDrawer] = useState('') + + const [booking, setBooking] = useState('') + + const [alertBox, setAlertBox] = useState({status:false, msg:''}) // USE TO SHOW SUcCESS OR FAILED ALERT MESSAGE + + const [logoutModal, setLogoutModal] = useState(false) // USE TO SHOW LOGOUT MODAL BOX + + const handleDrawer = (drawerToOpen) => { // FUNCTION TO DETERMINE WHICH ASIDE DRAWER TO SHOW + setDrawer((prev)=>{ + if(!prev){ + return drawerToOpen + }else if(drawerToOpen == prev){ + return '' + }else{ + return drawerToOpen + } + }) + } + + const handleBooking = (bookingToOpen) => { // FUNCTION TO DETERMINE WHICH ASIDE DRAWER TO SHOW + setBooking((prev)=>{ + if(!prev){ + return bookingToOpen + }else if(bookingToOpen == prev){ + return '' + }else{ + return bookingToOpen + } + }) + } + + const handleAlertBox = (valObj) => { + setAlertBox(valObj) + } + + useEffect(() => { + if (window.matchMedia("(prefers-color-scheme: dark)").matches) { + setTheme("dark"); + } else { + setTheme("light"); + } + }, []); + + useEffect(() => { + if (theme === "dark") { + document.documentElement.classList.add("dark"); + } else { + document.documentElement.classList.remove("dark"); + } + }, [theme]); + + const handleTheme = () => { + setTheme(theme === "dark" ? "light" : "dark"); + } + + let value = {theme, handleTheme, drawer, handleDrawer, booking, handleBooking, alertBox, handleAlertBox, logoutModal, setLogoutModal} + + return ( + + {children} + + ) +} + + +export const generalLayoutContext = () => { + return useContext(GeneralContextProvider) +} diff --git a/src/index.css b/src/index.css index aa352e1..0573138 100644 --- a/src/index.css +++ b/src/index.css @@ -23,3 +23,39 @@ code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } + +@layer components { + .change-text::after{ + content: ''; + animation: text-change 5s linear 0s infinite; + } + .text-slide-in{ + position: relative; + animation: slide-text-in .5s linear 0s forwards; + } + + .pop-modal{ + animation: pop-modal .1s linear 0s forwards; + } + + + /* ANIMATIONS */ + @keyframes text-change { + 0%{content: 'Boundaries';} + 100%{content: 'Limitations';} + } + + @keyframes slide-text-in { + /* 0%{left: -200%;} + 100%{left: 0%;} */ + 0%{transform: scale(0); opacity: 0;} + 100%{transform: scale(1); opacity: 1;} + } + + @keyframes pop-modal { + /* 0%{left: -200%;} + 100%{left: 0%;} */ + 0%{margin-top: 20px; opacity: 0;} + 100%{margin-top: 0; opacity: 1;} + } +} diff --git a/src/index.js b/src/index.js index 2cb1087..df3ff95 100644 --- a/src/index.js +++ b/src/index.js @@ -1,11 +1,23 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; +import { BrowserRouter } from 'react-router-dom' +import { Provider } from "react-redux"; + import './index.css'; import App from './App'; +import store from './store/store.js' +import GeneralLayoutContext from './context/GeneralLayoutContext.jsx'; + const root = ReactDOM.createRoot(document.getElementById('root')); root.render( - + + + + + + + ); diff --git a/src/pages/HomePage.jsx b/src/pages/HomePage.jsx new file mode 100644 index 0000000..2ab360c --- /dev/null +++ b/src/pages/HomePage.jsx @@ -0,0 +1,13 @@ +import React from 'react' +import BreadcrumbCom from '../components/breadcrumb/BreadcrumbCom' + +export default function HomePage() { + return ( +
+ +

+ coming soon ... +

+
+ ) +} diff --git a/src/pages/UsersPage.jsx b/src/pages/UsersPage.jsx new file mode 100644 index 0000000..aaef9fb --- /dev/null +++ b/src/pages/UsersPage.jsx @@ -0,0 +1,13 @@ +import React from 'react' +import BreadcrumbCom from '../components/breadcrumb/BreadcrumbCom' + +export default function UsersPage() { + return ( +
+ +

+ coming soon ... +

+
+ ) +} diff --git a/src/store/UserDetails.js b/src/store/UserDetails.js new file mode 100644 index 0000000..8cb2677 --- /dev/null +++ b/src/store/UserDetails.js @@ -0,0 +1,20 @@ +import { createSlice } from "@reduxjs/toolkit"; + +const initialState = { + userDetails: {}, +}; + +export const userSlice = createSlice({ + name: "userDetails", + initialState, + reducers: { + updateUserDetails: (state, action) => { + state.userDetails = { ...action.payload }; + }, + }, +}); + +// Action creators are generated for each case reducer function +export const { updateUserDetails } = userSlice.actions; + +export default userSlice.reducer; diff --git a/src/store/store.js b/src/store/store.js new file mode 100644 index 0000000..e111aec --- /dev/null +++ b/src/store/store.js @@ -0,0 +1,9 @@ +import { configureStore } from "@reduxjs/toolkit"; + +import userDetailReducer from "./UserDetails"; + +export default configureStore({ + reducer: { + userDetails: userDetailReducer, + }, +}); diff --git a/tailwind.config.js b/tailwind.config.js index 10c37f7..e496ae3 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -3,7 +3,43 @@ module.exports = { content: ["./src/**/*.{js,jsx,ts,tsx}"], darkMode: "class", theme: { - extend: {}, + extend: { + colors:{ + brown:{ + DEFAULT: '#393536', + }, + black:{ + DEFAULT: '#2c2e3e', + gray: '#a6a9b7' + }, + primary: { + DEFAULT: '#0284c7', + }, + orange: { + light: '#ED7747', + dark: '#9a3412' + }, + white: { + DEFAULT: '#fff', + light: '#f1f5f9' + } + }, + screens: { + max_width: '1700px' + }, + fontSize:{ + 10: '10px', + 12: '12px', + 14: '14px' + }, + backgroundImage: { + login_gradient: 'linear-gradient(to right, #8e54e9 0, #4776e6 100%)' + }, + boxShadow: { + round_black: '0 0px 1px 0 rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.19)', + round_white: '0 0px 1px 0 rgba(255, 255, 255, 0.2), 0 1px 5px 0 rgba(255, 255, 255, 0.19)' + } + }, }, plugins: [], }