Add category sidebar and category info routing

This commit is contained in:
hippoz 2021-01-05 18:40:03 +02:00
parent 187ae9cfbb
commit ac3df61fec
Signed by: hippoz
GPG key ID: 7C52899193467641
15 changed files with 373 additions and 29 deletions

View file

@ -12201,6 +12201,11 @@
"whatwg-fetch": "^3.4.1"
}
},
"react-content-loader": {
"version": "5.1.4",
"resolved": "https://registry.npmjs.org/react-content-loader/-/react-content-loader-5.1.4.tgz",
"integrity": "sha512-hTq7pZi2GKCK6a9d3u6XStozm0QGCEjw8cSqQReiWnh2up6IwCha5R5TF0o6SY5qUDpByloEZEZtnFxpJyENFw=="
},
"react-dev-utils": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.1.tgz",
@ -12314,6 +12319,11 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"react-media-hook": {
"version": "0.4.9",
"resolved": "https://registry.npmjs.org/react-media-hook/-/react-media-hook-0.4.9.tgz",
"integrity": "sha512-FZr/2xA1+23vDJ1IZ794yLqMRRkBoCNOiJATdtTfB5GyVc5djf8FL2qEB/68pSkiNgHdHsmKknMSDr0sC4zBKQ=="
},
"react-redux": {
"version": "7.2.2",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.2.tgz",

View file

@ -8,7 +8,9 @@
"@testing-library/user-event": "^12.6.0",
"nord": "^0.2.1",
"react": "^17.0.1",
"react-content-loader": "^5.1.4",
"react-dom": "^17.0.1",
"react-media-hook": "^0.4.9",
"react-redux": "^7.2.2",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.1",
@ -22,7 +24,7 @@
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"proxy": "http://localhost:3002",
"proxy": "http://localhost:3005",
"eslintConfig": {
"extends": [
"react-app",

View file

@ -3,6 +3,9 @@ import Root from './Root';
import Authenticator from './../Authenticator';
import Notification from './Notification';
import './../Styles/App.scss';
import { couldNotReach } from '../Errors';
import CategoryView from './Categories/CategoryView';
import Sidebar from './UI/Sidebar';
import { useEffect, useState } from 'react';
import { useDispatch, connect } from 'react-redux'
@ -20,7 +23,7 @@ function App({ user }) {
dispatch({ type: 'authenticator/updatelocaluserobject', user: res })
})
.catch(() => {
setNotificationText('An error has occoured.');
setNotificationText(couldNotReach);
setHasError(true);
});
}, [dispatch]);
@ -28,17 +31,23 @@ function App({ user }) {
if (!hasError) {
return (
<div id="main-container">
<div id="root-container" className="main-display">
<BrowserRouter>
<Switch>
<Route path="/login">
<Login />
</Route>
<Route path="/categories/:id">
<Sidebar />
<CategoryView />
</Route>
<Route path="/">
<Root user={user} />
</Route>
</Switch>
</BrowserRouter>
</div>
</div>
);
} else {
return (
@ -51,7 +60,7 @@ function App({ user }) {
const stateToProps = (state) => {
return {
user: state?.user
user: state?.user,
};
};

View file

@ -0,0 +1,11 @@
import { useHistory } from 'react-router-dom';
export default function CategoryButton({ category }) {
const history = useHistory();
return (
<button className="button category-button" onClick={ () => history.push(`/categories/${category._id}`) }>
{ category.title }
</button>
)
}

View file

@ -0,0 +1,53 @@
import CategoryListLoader from './CategoryListLoader';
import CategoryButton from './CategoryButton';
import APIRequest from '../../APIRequest';
import { couldNotReach } from '../../Errors';
import { useDispatch } from 'react-redux'
import { useState, useEffect } from 'react';
export default function CategoryList() {
const [ categoryList, setCategoryList ] = useState();
const [ error, setError ] = useState();
const dispatch = useDispatch();
useEffect(() => {
APIRequest.authenticated('/api/v1/content/category/list?count=50')
.then(({ isOK, json }) => {
if (!isOK) return setError(true);
setCategoryList(json.categories || []);
dispatch({ type: 'categories/updatecategorylist', categories: json.categories });
})
.catch(() => {
setError(true);
});
}, [dispatch]);
if (!categoryList) {
if (error) {
return (
<div>
<p>
{ couldNotReach }
</p>
</div>
);
} else {
return (
<div>
<CategoryListLoader />
</div>
);
}
} else {
return (
<div className="category-list">
{categoryList.map((category) =>
<CategoryButton key={ category._id } category={ category } />
)}
</div>
);
}
}

View file

@ -0,0 +1,44 @@
import ContentLoader from "react-content-loader"
import { useMediaPredicate } from "react-media-hook";
export default function CategoryListLoader(props) {
const lessThan600 = useMediaPredicate("(max-width: 600px)");
if (lessThan600) {
return (
<ContentLoader
speed={1.5}
width={62}
height={300}
viewBox="0 0 62 300"
backgroundColor="#434c5e"
foregroundColor="#4c566a"
{...props}
>
<rect x="6" y="5" rx="0" ry="0" width="50" height="25" />
<rect x="6" y="35" rx="0" ry="0" width="50" height="25" />
<rect x="6" y="65" rx="0" ry="0" width="50" height="25" />
<rect x="6" y="95" rx="0" ry="0" width="50" height="25" />
<rect x="6" y="125" rx="0" ry="0" width="50" height="25" />
</ContentLoader>
);
} else {
return (
<ContentLoader
speed={1.5}
width={112}
height={300}
viewBox="0 0 112 300"
backgroundColor="#434c5e"
foregroundColor="#4c566a"
{...props}
>
<rect x="6" y="5" rx="0" ry="0" width="100" height="25" />
<rect x="6" y="35" rx="0" ry="0" width="100" height="25" />
<rect x="6" y="65" rx="0" ry="0" width="100" height="25" />
<rect x="6" y="95" rx="0" ry="0" width="100" height="25" />
<rect x="6" y="125" rx="0" ry="0" width="100" height="25" />
</ContentLoader>
);
}
}

View file

@ -0,0 +1,55 @@
import CategoryViewLoader from './CategoryViewLoader';
import { useParams } from 'react-router-dom';
import { connect } from 'react-redux'
function CategoryView({ categories }) {
const { id } = useParams();
let category;
if (categories) {
category = categories.find(x => x._id === id);
}
if (category) {
return (
<div className="card main-card main-content-card">
<div className="card bar-card">
{ category.title }
</div>
<div className="card message-list-card">
In terms of development, the first year of a cats life is equal to the first 15 years of a human life. After its second year, a cat is 25 in human years. And after that, each year of a cats life is equal to about 7 human years.
Cats can rotate their ears 180 degrees.
</div>
<div className="card bar-card-bottom">
The hearing of the average cat is at least five times keener than that of a human adult.
In the largest cat breed, the average male weighs approximately 20 pounds.
</div>
</div>
)
} else {
return (
<div className="card main-card main-content-card">
<div className="card bar-card">
<CategoryViewLoader />
</div>
<div className="card message-list-card">
</div>
<div className="card bar-card-bottom">
</div>
</div>
)
}
}
const stateToProps = (state) => {
return {
categories: state?.categories
};
};
export default connect(stateToProps)(CategoryView);

View file

@ -0,0 +1,17 @@
import ContentLoader from "react-content-loader"
export default function CategoryViewLoader(props) {
return (
<ContentLoader
speed={1.5}
width={100}
height={40}
viewBox="0 0 100 40"
backgroundColor="#434c5e"
foregroundColor="#4c566a"
{...props}
>
<rect x="6" y="6" rx="0" ry="0" width="100" height="24" />
</ContentLoader>
)
}

View file

@ -1,22 +1,16 @@
import { useHistory } from 'react-router-dom';
import Sidebar from './UI/Sidebar';
export default function Root(props) {
const history = useHistory();
if (props.user) {
return (
<div id="root-container" className="main-display">
<div className="main-card">
hhhhhhhhhhhhhhhhhhhhhh
</div>
<div className="main-card main-content-card">
sdfsdfsdf
</div>
</div>
<Sidebar />
);
} else {
return (
<div id="root-container">
<div id="login-message-container">
<h1>Welcome, - nevermind, you aren't logged in</h1>
<button onClick={ () => { history.push('/login') } }>Log in</button>
</div>

View file

@ -0,0 +1,9 @@
import CategoryList from '../Categories/CategoryList';
export default function Sidebar() {
return (
<div className="card main-card category-list-container">
<CategoryList />
</div>
)
}

View file

@ -110,4 +110,6 @@ const getCreateCategoryError = (json) => {
}
};
module.exports = { getLoginMessageFromError, getSignupMessageFromError, getCreatePostError, getCreateCategoryError }
const couldNotReach = "Whoops! We couldn't reach Brainlet."
module.exports = { couldNotReach, getLoginMessageFromError, getSignupMessageFromError, getCreatePostError, getCreateCategoryError }

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 B

View file

@ -1,28 +1,159 @@
@import "../../node_modules/nord/src/sass/nord.scss";
:root {
--background-color: #{$nord0};
--default-main-card-color: #{$nord1};
--card-box-shadow-color:rgba(0, 0, 0, 0.25);
--default-text-color: #{$nord5};
--accent-color-dark: #{$nord2};
--accent-color-light: #{$nord3};
--default-transition-duration: 200ms;
--default-border-radius: 0px;
--default-button-border-radius: 0px;
}
::-webkit-scrollbar {
width: 0px;
}
::-webkit-scrollbar-track {
background: var(--accent-color-light);
}
::-webkit-scrollbar-thumb {
background: var(--default-main-card-color);
}
@mixin card {
padding: 0px;
margin: 0px;
background-color: var(--default-main-card-color);
border-radius: var(--default-border-radius);
box-shadow: 0px 3px 5px var(--card-box-shadow-color);
}
@mixin fancy-scrollbar-firefox {
scrollbar-width: none;
scrollbar-color: var(--default-main-card-color) var(--accent-color-light);
}
body {
margin: 0px;
padding: 0px;
color: var(--default-text-color);
font-family: Noto Sans,-apple-system,BlinkMacSystemFont,sans-serif;
}
.main-display {
padding: 0px;
margin: 0px;
display: flex;
background-color: $nord0;
background-color: var(--background-color);
min-height: 100vh;
max-height: 100vh;
flex-direction: row;
}
.card {
@include card;
&.bar-card {
background-color: var(--accent-color-dark);
min-height: 40px;
border-radius: var(--default-button-border-radius) var(--default-button-border-radius) 0px 0px;
display: flex;
align-items: center;
justify-content: left;
font-size: large;
}
&.bar-card-bottom {
background-color: var(--accent-color-dark);
min-height: 30px;
border-radius: 0px 0px var(--default-button-border-radius) var(--default-button-border-radius);
}
&.message-list-card {
border-radius: 0px;
flex-grow: 1;
box-shadow: none;
}
}
.main-card {
padding: 0px;
margin: 0px;
background-color: $nord1;
border-radius: 10px;
box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.25);
@include card;
margin: 12px;
&.main-content-card {
flex-grow: 1;
display: flex;
flex-direction: column;
}
}
.button {
@include card;
padding: 5px;
margin: 5px;
border: 0px;
background-color: var(--accent-color-dark);
color: var(--default-text-color);
cursor: pointer;
transition: background-color, var(--default-transition-duration);
border-radius: var(--default-button-border-radius);
min-height: 25px;
&.category-button {
min-width: 100px;
max-width: 100px;
}
&.pressed {
background-color: var(--accent-color-light);
}
}
.button:hover {
background-color: var(--accent-color-light);
}
.category-list {
display: flex;
flex-direction: column;
word-wrap: break-word;
}
.category-list-container {
@include fancy-scrollbar-firefox;
overflow: auto;
overflow-x: hidden;
min-width: 110px;
max-width: 110px;
}
@media only screen and (max-width: 600px) {
.button.category-button {
min-width: 50px;
max-width: 50px;
}
.category-list-container {
min-width: 60px;
max-width: 60px;
}
.main-card {
margin: 6px;
}
}

View file

@ -9,6 +9,13 @@ const reducer = (state, payload) => {
}
}
case 'categories/updatecategorylist': {
return {
...state,
categories: payload.categories
}
}
default: {
return state;
}