stat card + aside

This commit is contained in:
VividTruthKeeper 2022-09-06 17:43:26 +05:00
parent 6e9e18fe98
commit 25b7b797cc
16 changed files with 220 additions and 34 deletions

47
package-lock.json generated
View File

@ -12,6 +12,7 @@
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-filterable-table": "^0.3.439", "react-filterable-table": "^0.3.439",
"react-icons": "^4.4.0",
"react-router-dom": "^6.3.0" "react-router-dom": "^6.3.0"
}, },
"devDependencies": { "devDependencies": {
@ -3640,6 +3641,7 @@
}, },
"node_modules/npm/node_modules/lodash._baseindexof": { "node_modules/npm/node_modules/lodash._baseindexof": {
"version": "3.1.0", "version": "3.1.0",
"extraneous": true,
"inBundle": true, "inBundle": true,
"license": "MIT" "license": "MIT"
}, },
@ -3654,16 +3656,19 @@
}, },
"node_modules/npm/node_modules/lodash._bindcallback": { "node_modules/npm/node_modules/lodash._bindcallback": {
"version": "3.0.1", "version": "3.0.1",
"extraneous": true,
"inBundle": true, "inBundle": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/npm/node_modules/lodash._cacheindexof": { "node_modules/npm/node_modules/lodash._cacheindexof": {
"version": "3.0.2", "version": "3.0.2",
"extraneous": true,
"inBundle": true, "inBundle": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/npm/node_modules/lodash._createcache": { "node_modules/npm/node_modules/lodash._createcache": {
"version": "3.1.2", "version": "3.1.2",
"extraneous": true,
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -3677,6 +3682,7 @@
}, },
"node_modules/npm/node_modules/lodash._getnative": { "node_modules/npm/node_modules/lodash._getnative": {
"version": "3.9.1", "version": "3.9.1",
"extraneous": true,
"inBundle": true, "inBundle": true,
"license": "MIT" "license": "MIT"
}, },
@ -3692,6 +3698,7 @@
}, },
"node_modules/npm/node_modules/lodash.restparam": { "node_modules/npm/node_modules/lodash.restparam": {
"version": "3.6.1", "version": "3.6.1",
"extraneous": true,
"inBundle": true, "inBundle": true,
"license": "MIT" "license": "MIT"
}, },
@ -5764,6 +5771,14 @@
"react-dom": "^15.0.0 || ^16.0.0" "react-dom": "^15.0.0 || ^16.0.0"
} }
}, },
"node_modules/react-icons": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.4.0.tgz",
"integrity": "sha512-fSbvHeVYo/B5/L4VhB7sBA1i2tS8MkT0Hb9t2H1AVPkwGfVHLJCqyr2Py9dKMxsyM63Eng1GkdZfbWj+Fmv8Rg==",
"peerDependencies": {
"react": "*"
}
},
"node_modules/react-is": { "node_modules/react-is": {
"version": "16.13.1", "version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@ -5854,7 +5869,8 @@
"node_modules/safe-buffer": { "node_modules/safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true
}, },
"node_modules/sass": { "node_modules/sass": {
"version": "1.54.8", "version": "1.54.8",
@ -5885,6 +5901,7 @@
"version": "6.3.0", "version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true,
"bin": { "bin": {
"semver": "bin/semver.js" "semver": "bin/semver.js"
} }
@ -8559,7 +8576,8 @@
}, },
"lodash._baseindexof": { "lodash._baseindexof": {
"version": "3.1.0", "version": "3.1.0",
"bundled": true "bundled": true,
"extraneous": true
}, },
"lodash._baseuniq": { "lodash._baseuniq": {
"version": "4.6.0", "version": "4.6.0",
@ -8571,15 +8589,18 @@
}, },
"lodash._bindcallback": { "lodash._bindcallback": {
"version": "3.0.1", "version": "3.0.1",
"bundled": true "bundled": true,
"extraneous": true
}, },
"lodash._cacheindexof": { "lodash._cacheindexof": {
"version": "3.0.2", "version": "3.0.2",
"bundled": true "bundled": true,
"extraneous": true
}, },
"lodash._createcache": { "lodash._createcache": {
"version": "3.1.2", "version": "3.1.2",
"bundled": true, "bundled": true,
"extraneous": true,
"requires": { "requires": {
"lodash._getnative": "^3.0.0" "lodash._getnative": "^3.0.0"
} }
@ -8590,7 +8611,8 @@
}, },
"lodash._getnative": { "lodash._getnative": {
"version": "3.9.1", "version": "3.9.1",
"bundled": true "bundled": true,
"extraneous": true
}, },
"lodash._root": { "lodash._root": {
"version": "3.0.1", "version": "3.0.1",
@ -8602,7 +8624,8 @@
}, },
"lodash.restparam": { "lodash.restparam": {
"version": "3.6.1", "version": "3.6.1",
"bundled": true "bundled": true,
"extraneous": true
}, },
"lodash.union": { "lodash.union": {
"version": "4.6.0", "version": "4.6.0",
@ -10146,6 +10169,12 @@
} }
} }
}, },
"react-icons": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.4.0.tgz",
"integrity": "sha512-fSbvHeVYo/B5/L4VhB7sBA1i2tS8MkT0Hb9t2H1AVPkwGfVHLJCqyr2Py9dKMxsyM63Eng1GkdZfbWj+Fmv8Rg==",
"requires": {}
},
"react-is": { "react-is": {
"version": "16.13.1", "version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@ -10211,7 +10240,8 @@
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true
}, },
"sass": { "sass": {
"version": "1.54.8", "version": "1.54.8",
@ -10235,7 +10265,8 @@
"semver": { "semver": {
"version": "6.3.0", "version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
}, },
"source-map-js": { "source-map-js": {
"version": "1.0.2", "version": "1.0.2",

View File

@ -13,6 +13,7 @@
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-filterable-table": "^0.3.439", "react-filterable-table": "^0.3.439",
"react-icons": "^4.4.0",
"react-router-dom": "^6.3.0" "react-router-dom": "^6.3.0"
}, },
"devDependencies": { "devDependencies": {

View File

@ -9,6 +9,7 @@ import "./assets/styles/style.scss";
// Pages // Pages
import Login from "./pages/Login"; import Login from "./pages/Login";
import Main from "./pages/Main"; import Main from "./pages/Main";
import Dashboard from "./pages/Dashboard";
const App = () => { const App = () => {
const [user, setUser] = useState({ const [user, setUser] = useState({
@ -31,6 +32,7 @@ const App = () => {
<div className="App"> <div className="App">
<Routes> <Routes>
<Route path="/" element={<Main />} /> <Route path="/" element={<Main />} />
<Route path="/dashboard" element={<Main child={<Dashboard />} />} />
<Route path="/login" element={<Login />} /> <Route path="/login" element={<Login />} />
</Routes> </Routes>
</div> </div>

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><path stroke="#869AB8" stroke-width="2.25" stroke-linecap="round" stroke-miterlimit="10" d="M4 7h22M4 15h22M4 23h22"/></svg>

Before

Width:  |  Height:  |  Size: 184 B

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g data-name="Layer 2"><g data-name="grid"><rect width="24" height="24" opacity="0"/><path d="M9 3H5a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zM5 9V5h4v4z"/><path d="M19 3h-4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zm-4 6V5h4v4z"/><path d="M9 13H5a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2zm-4 6v-4h4v4z"/><path d="M19 13h-4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2zm-4 6v-4h4v4z"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 540 B

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="black" d="M256 250.8a73.34 73.34 0 1 1 73.33-73.34A73.41 73.41 0 0 1 256 250.8zm0-125.53a52.2 52.2 0 1 0 52.19 52.19A52.25 52.25 0 0 0 256 125.27zm117.07 282.6H138.93l-10.57-10.57a127.64 127.64 0 1 1 255.28 0zM150 386.73h212a106.51 106.51 0 0 0-212 0z"/></svg>

Before

Width:  |  Height:  |  Size: 334 B

View File

@ -2,12 +2,15 @@
@include transition-std; @include transition-std;
overflow: hidden; overflow: hidden;
max-width: 0; max-width: 0;
min-width: 0rem;
width: 100%; width: 100%;
&__img {
width: 3rem;
height: 3rem;
}
&.active { &.active {
max-width: 100%; max-width: 25rem;
min-width: 20rem;
@include transition-std; @include transition-std;
} }
@ -20,11 +23,15 @@
&__element { &__element {
@include transition-std; @include transition-std;
background: transparent; background: transparent;
display: flex;
gap: 0.6rem;
align-items: center;
font-size: 1.6rem; font-size: 1.6rem;
cursor: pointer; cursor: pointer;
a { a,
div {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-start; justify-content: flex-start;
@ -50,6 +57,10 @@
} }
&--title { &--title {
&:not(:first-child) {
padding-top: 1rem;
margin-top: 1rem;
}
cursor: default !important; cursor: default !important;
background: transparent !important; background: transparent !important;
font-size: 1.4rem; font-size: 1.4rem;

View File

@ -0,0 +1,58 @@
.dashboard {
&__head {
display: flex;
align-items: center;
gap: 1rem;
h1 {
font-size: 3.2rem;
}
}
&__img {
width: 4rem;
height: 4rem;
}
&__content {
&__stats {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
}
&.inner {
display: flex;
flex-direction: column;
gap: 4rem;
}
}
.statcard {
cursor: default;
@include transition-std;
transform: translateY(0);
border-radius: 0.5rem;
color: #fff;
display: flex;
flex-direction: column;
justify-content: center;
padding: 2rem;
&:hover {
@include transition-std;
transform: translateY(-1rem);
}
&.yellow {
background: #c69500;
}
span {
font-size: 2.4rem;
}
p {
font-size: 1.6rem;
}
}

View File

@ -1,7 +1,7 @@
@import url("https://fonts.googleapis.com/css2?family=Montserrat&display=swap"); @import url("https://fonts.googleapis.com/css2?family=Poppins&display=swap");
* { * {
font-family: "Montserrat", sans-serif; font-family: "Poppins", sans-serif;
margin: 0; margin: 0;
padding: 0; padding: 0;
box-sizing: border-box; box-sizing: border-box;

View File

@ -13,7 +13,7 @@
border: 0.1rem solid #c8c8c8; border: 0.1rem solid #c8c8c8;
&.active { &.active {
height: 15rem; height: 16.3rem;
opacity: 1; opacity: 1;
@include transition-std; @include transition-std;
} }

View File

@ -3,3 +3,4 @@
@import "./nav"; @import "./nav";
@import "./main"; @import "./main";
@import "./aside"; @import "./aside";
@import "./dashboard";

View File

@ -1,31 +1,60 @@
// Modules // Modules
import React from "react"; import React from "react";
import { useContext } from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { UserContext } from "../context/UserContext";
// Icons // Icons
import Grid from "../assets/icons/grid-outline.svg"; import { BsFillFileEarmarkPostFill } from "react-icons/bs";
import { AiOutlineBlock } from "react-icons/ai";
import { MdOutlineManageAccounts } from "react-icons/md";
import { CgDetailsLess } from "react-icons/cg";
import { BiLogOut } from "react-icons/bi";
// Types // Types
import { userContextType } from "../types/user";
interface Props { interface Props {
aside: boolean; aside: boolean;
setAside: React.Dispatch<boolean>; setAside: React.Dispatch<boolean>;
} }
const Aside = ({ aside, setAside }: Props) => { const Aside = ({ aside, setAside }: Props) => {
const { setUser }: userContextType = useContext(UserContext);
return ( return (
<aside className={aside ? "aside active" : "aside"}> <aside className={aside ? "aside active" : "aside"}>
<ul className="aside__list"> <ul className="aside__list">
<li className="aside__list__element aside__list__element--title"> <li className="aside__list__element aside__list__element--title">
<AiOutlineBlock className="aside__img" />
<h2>Elements</h2> <h2>Elements</h2>
</li> </li>
<li className="aside__list__element"> <li className="aside__list__element">
<Link to={"/posts"}> <Link to={"/posts"}>
<div className="aside__list__element__img"> <BsFillFileEarmarkPostFill className="aside__list__element__img" />
<img src={Grid} alt="" />
</div>
<span>Posts</span> <span>Posts</span>
</Link> </Link>
</li> </li>
<li className="aside__list__element aside__list__element--title">
<MdOutlineManageAccounts className="aside__img" />
<h2>Account</h2>
</li>
<li className="aside__list__element">
<Link to={"/user_details"}>
<CgDetailsLess className="aside__list__element__img" />
<span>Details</span>
</Link>
</li>
<li
className="aside__list__element"
onClick={() => {
localStorage.removeItem("userData");
setUser({ username: "", accessLevel: "" });
}}
>
<div>
<BiLogOut className="aside__list__element__img" />
<span>Log out</span>
</div>
</li>
</ul> </ul>
</aside> </aside>
); );

View File

@ -1,14 +1,16 @@
// Modules // Modules
import { useContext, useState } from "react"; import { useContext, useState } from "react";
import { UserContext } from "../context/UserContext"; import { UserContext } from "../context/UserContext";
import { Link } from "react-router-dom";
// Icons // Icons
import Orient from "../assets/icons/logo_orient.svg"; import Orient from "../assets/icons/logo_orient.svg";
import Burger from "../assets/icons/burger.svg"; import { GiHamburgerMenu } from "react-icons/gi";
import Profile from "../assets/icons/profile.svg"; import { AiOutlineUser } from "react-icons/ai";
// Types // Types
import { userContextType } from "../types/user"; import { userContextType } from "../types/user";
interface Props { interface Props {
aside: boolean; aside: boolean;
setAside: React.Dispatch<boolean>; setAside: React.Dispatch<boolean>;
@ -22,16 +24,14 @@ const Nav = ({ aside, setAside }: Props) => {
<div className="container"> <div className="container">
<div className="nav inner"> <div className="nav inner">
<div className="nav__left"> <div className="nav__left">
<div className="nav__img"> <Link to={"/dashboard"} className="nav__img">
<img src={Orient} alt="orient" /> <img src={Orient} alt="orient" />
</div> </Link>
<button <GiHamburgerMenu
type="button" type="button"
className="nav__btn" className="nav__btn"
onClick={() => setAside(!aside)} onClick={() => setAside(!aside)}
> />
<img src={Burger} alt="" />
</button>
</div> </div>
<div className="nav__right"> <div className="nav__right">
<div <div
@ -40,9 +40,7 @@ const Nav = ({ aside, setAside }: Props) => {
setDropdown(!dropdown); setDropdown(!dropdown);
}} }}
> >
<div className="nav__right__user__img"> <AiOutlineUser className="nav__right__user__img" />
<img src={Profile} alt="" />
</div>
<span>Profile</span> <span>Profile</span>
<div <div
className={dropdown ? "nav__dropdown active" : "nav__dropdown"} className={dropdown ? "nav__dropdown active" : "nav__dropdown"}

View File

@ -0,0 +1,19 @@
// Modules
// Types
interface Props {
topNumber?: number;
text: string;
color: string;
}
const StatCard = ({ color, topNumber, text }: Props) => {
return (
<div className={`statcard ${color}`}>
<span>{topNumber}</span>
<p>{text}</p>
</div>
);
};
export default StatCard;

31
src/pages/Dashboard.tsx Normal file
View File

@ -0,0 +1,31 @@
// Modules
// Icons
import { AiOutlineDashboard } from "react-icons/ai";
// Components
import StatCard from "../components/StatCard";
const Dashboard = () => {
return (
<main className="dashboard">
<div className="container">
<div className="dashboard inner">
<div className="dashboard__head">
<AiOutlineDashboard className="dashboard__img" />
<h1>Dashboard</h1>
</div>
<div className="dashboard__content__stats">
<StatCard
color="yellow"
text="Lorem, ipsum dolor sit amet consectetur adipisicing elit."
topNumber={123}
/>
</div>
</div>
</div>
</main>
);
};
export default Dashboard;

View File

@ -1,6 +1,9 @@
// Modules // Modules
import { useState, useContext, useEffect } from "react"; import { useState, useContext, useEffect } from "react";
import { useNavigate } from "react-router-dom"; import {
useNavigate,
// useLocation
} from "react-router-dom";
import { UserContext } from "../context/UserContext"; import { UserContext } from "../context/UserContext";
// Components // Components
@ -12,9 +15,14 @@ import { userContextType } from "../types/user";
const Main = ({ child }: any) => { const Main = ({ child }: any) => {
const navigate = useNavigate(); const navigate = useNavigate();
// const location = useLocation();
const { user, setUser }: userContextType = useContext(UserContext); const { user, setUser }: userContextType = useContext(UserContext);
const [aside, setAside] = useState(true); const [aside, setAside] = useState(true);
// useEffect(() => {
// if(location.pathname.includes('dashboard'))
// }, [])
useEffect(() => { useEffect(() => {
if (!user.username) { if (!user.username) {
navigate("/login"); navigate("/login");