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

View File

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

View File

@ -9,6 +9,7 @@ import "./assets/styles/style.scss";
// Pages
import Login from "./pages/Login";
import Main from "./pages/Main";
import Dashboard from "./pages/Dashboard";
const App = () => {
const [user, setUser] = useState({
@ -31,6 +32,7 @@ const App = () => {
<div className="App">
<Routes>
<Route path="/" element={<Main />} />
<Route path="/dashboard" element={<Main child={<Dashboard />} />} />
<Route path="/login" element={<Login />} />
</Routes>
</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;
overflow: hidden;
max-width: 0;
min-width: 0rem;
width: 100%;
&__img {
width: 3rem;
height: 3rem;
}
&.active {
max-width: 100%;
min-width: 20rem;
max-width: 25rem;
@include transition-std;
}
@ -20,11 +23,15 @@
&__element {
@include transition-std;
background: transparent;
display: flex;
gap: 0.6rem;
align-items: center;
font-size: 1.6rem;
cursor: pointer;
a {
a,
div {
display: flex;
align-items: center;
justify-content: flex-start;
@ -50,6 +57,10 @@
}
&--title {
&:not(:first-child) {
padding-top: 1rem;
margin-top: 1rem;
}
cursor: default !important;
background: transparent !important;
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;
padding: 0;
box-sizing: border-box;

View File

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

View File

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

View File

@ -1,31 +1,60 @@
// Modules
import React from "react";
import { useContext } from "react";
import { Link } from "react-router-dom";
import { UserContext } from "../context/UserContext";
// 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
import { userContextType } from "../types/user";
interface Props {
aside: boolean;
setAside: React.Dispatch<boolean>;
}
const Aside = ({ aside, setAside }: Props) => {
const { setUser }: userContextType = useContext(UserContext);
return (
<aside className={aside ? "aside active" : "aside"}>
<ul className="aside__list">
<li className="aside__list__element aside__list__element--title">
<AiOutlineBlock className="aside__img" />
<h2>Elements</h2>
</li>
<li className="aside__list__element">
<Link to={"/posts"}>
<div className="aside__list__element__img">
<img src={Grid} alt="" />
</div>
<BsFillFileEarmarkPostFill className="aside__list__element__img" />
<span>Posts</span>
</Link>
</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>
</aside>
);

View File

@ -1,14 +1,16 @@
// Modules
import { useContext, useState } from "react";
import { UserContext } from "../context/UserContext";
import { Link } from "react-router-dom";
// Icons
import Orient from "../assets/icons/logo_orient.svg";
import Burger from "../assets/icons/burger.svg";
import Profile from "../assets/icons/profile.svg";
import { GiHamburgerMenu } from "react-icons/gi";
import { AiOutlineUser } from "react-icons/ai";
// Types
import { userContextType } from "../types/user";
interface Props {
aside: boolean;
setAside: React.Dispatch<boolean>;
@ -22,16 +24,14 @@ const Nav = ({ aside, setAside }: Props) => {
<div className="container">
<div className="nav inner">
<div className="nav__left">
<div className="nav__img">
<Link to={"/dashboard"} className="nav__img">
<img src={Orient} alt="orient" />
</div>
<button
</Link>
<GiHamburgerMenu
type="button"
className="nav__btn"
onClick={() => setAside(!aside)}
>
<img src={Burger} alt="" />
</button>
/>
</div>
<div className="nav__right">
<div
@ -40,9 +40,7 @@ const Nav = ({ aside, setAside }: Props) => {
setDropdown(!dropdown);
}}
>
<div className="nav__right__user__img">
<img src={Profile} alt="" />
</div>
<AiOutlineUser className="nav__right__user__img" />
<span>Profile</span>
<div
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
import { useState, useContext, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import {
useNavigate,
// useLocation
} from "react-router-dom";
import { UserContext } from "../context/UserContext";
// Components
@ -12,9 +15,14 @@ import { userContextType } from "../types/user";
const Main = ({ child }: any) => {
const navigate = useNavigate();
// const location = useLocation();
const { user, setUser }: userContextType = useContext(UserContext);
const [aside, setAside] = useState(true);
// useEffect(() => {
// if(location.pathname.includes('dashboard'))
// }, [])
useEffect(() => {
if (!user.username) {
navigate("/login");