Much neater filters + cleaner code.

This commit is contained in:
Daniel 2022-06-17 14:08:48 +04:30
parent 4d0f4425ea
commit d28df3a061
11 changed files with 208 additions and 263 deletions

View File

@ -4,7 +4,6 @@ import List from "./componets/List";
import AddItem from "./componets/AddItem";
import config from "./config";
import Filters from "./componets/Filters";
import Sort from "./componets/Sort";
import sortList from "./modules/sortList";
import filter from "./modules/filterData";
import concatTags from "./modules/concatTags";
@ -18,13 +17,10 @@ function App() {
const [data, setData] = useState([]),
[newBox, setNewBox] = useState(false),
[filterBox, setFilterBox] = useState(false),
[sortBox, setSortBox] = useState(false),
[searchQuery, setSearchQuery] = useState(""),
[numberOfResults, setNumberOfResults] = useState(0),
[nameChecked, setNameChecked] = useState(true),
[descriptionChecked, setDescriptionChecked] = useState(true),
[tagsChecked, setTagsChecked] = useState(true),
[sortBy, setSortBy] = useState("Default"),
[filterCheckbox, setFilterCheckbox] = useState([true, true, true]),
[sortBy, setSortBy] = useState(1),
[loader, setLoader] = useState(false),
[lightMode, setLightMode] = useState(
localStorage.getItem("light-mode") === "true"
@ -35,16 +31,8 @@ function App() {
setLoader(x);
}
function handleNameCheckbox() {
setNameChecked(!nameChecked);
}
function handleDescriptionCheckbox() {
setDescriptionChecked(!descriptionChecked);
}
function handleTagsCheckbox() {
setTagsChecked(!tagsChecked);
function handleFilterCheckbox(newVal) {
setFilterCheckbox(newVal);
}
function exitAdding() {
@ -55,15 +43,11 @@ function App() {
setFilterBox(false);
}
function exitSorting() {
setSortBox(false);
}
function search(e) {
setSearchQuery(e.target.value);
}
function sortByFunc(e) {
function handleSorting(e) {
setSortBy(e);
}
@ -71,13 +55,7 @@ function App() {
setToggle(!toggle);
}
const filteredData = filter(
data,
searchQuery,
nameChecked,
tagsChecked,
descriptionChecked
);
const filteredData = filter(data, searchQuery, filterCheckbox);
const tags = concatTags(data);
@ -92,9 +70,9 @@ function App() {
useEffect(() => {
const sortedData = sortList(data, sortBy);
setData(sortedData);
exitSorting();
exitFilter();
// eslint-disable-next-line
}, [sortBy]);
}, [sortBy, filterCheckbox]);
useEffect(() => {
fetchData();
@ -138,6 +116,14 @@ function App() {
placeholder=" Search"
onChange={search}
/>
<button
className="btn"
style={{ marginLeft: "10px" }}
onClick={() => setFilterBox(true)}
>
&#xf160;
</button>
<button className="add-btn btn" onClick={() => setNewBox(true)}>
&#xf067;
</button>
@ -151,33 +137,14 @@ function App() {
<p className="results">{numberOfResults} Bookmarks found</p>
) : null}
<button
className="btn"
style={{ marginTop: "10px" }}
onClick={() => setFilterBox(true)}
>
&#xf0b0;
</button>
<button
className="btn"
style={{ marginLeft: "10px" }}
onClick={() => setSortBox(true)}
>
&#xf0dc;
</button>
{numberOfResults === 0 ? <NoResults /> : null}
{sortBox ? <Sort sortBy={sortByFunc} onExit={exitSorting} /> : null}
{filterBox ? (
<Filters
nameChecked={nameChecked}
handleNameCheckbox={handleNameCheckbox}
descriptionChecked={descriptionChecked}
handleDescriptionCheckbox={handleDescriptionCheckbox}
tagsChecked={tagsChecked}
handleTagsCheckbox={handleTagsCheckbox}
filterCheckbox={filterCheckbox}
handleFilterCheckbox={handleFilterCheckbox}
sortBy={handleSorting}
sort={sortBy}
onExit={exitFilter}
/>
) : null}

View File

@ -1,50 +1,137 @@
import "../styles/Filters.css";
import { useState } from "react";
const Filters = ({
nameChecked,
handleNameCheckbox,
descriptionChecked,
handleDescriptionCheckbox,
tagsChecked,
handleTagsCheckbox,
filterCheckbox,
handleFilterCheckbox,
sortBy,
sort,
onExit,
}) => {
const [nameChecked, setNameChecked] = useState(filterCheckbox[0]),
[titleChecked, setTitleChecked] = useState(filterCheckbox[1]),
[tagChecked, setTagChecked] = useState(filterCheckbox[2]),
[radio, setRadio] = useState(sort);
function abort(e) {
if (e.target.className === "filter-overlay") {
onExit();
}
}
function handleRadio(e) {
setRadio(e.target.value);
}
function applyChanges() {
handleFilterCheckbox([nameChecked, titleChecked, tagChecked]);
sortBy(radio);
}
return (
<>
<div className="filter-overlay" onClick={abort}></div>
<div className="filter-box">
<fieldset className="filter">
<legend>Filter by</legend>
<label>
<input
type="checkbox"
checked={nameChecked}
onChange={handleNameCheckbox}
/>
Name
</label>
<label>
<input
type="checkbox"
checked={descriptionChecked}
onChange={handleDescriptionCheckbox}
/>
Website title
</label>
<label>
<input
type="checkbox"
checked={tagsChecked}
onChange={handleTagsCheckbox}
/>
Tags
</label>
<legend>Filter search</legend>
<div className="filter-groups">
<div className="section">
<h4>Sort by</h4>
<label>
<input
name="sort"
checked={radio == 1}
onChange={handleRadio}
type="radio"
value={1}
/>
&#xf271; Date (Newest first)
</label>
<label>
<input
name="sort"
checked={radio == 2}
onChange={handleRadio}
type="radio"
value={2}
/>
&#xf272; Date (Oldest first)
</label>
<label>
<input
name="sort"
checked={radio == 3}
onChange={handleRadio}
type="radio"
value={3}
/>
&#xf15d; Name (A-Z)
</label>
<label>
<input
name="sort"
checked={radio == 4}
onChange={handleRadio}
type="radio"
value={4}
/>
&#xf15e; Name (Z-A)
</label>
<label>
<input
name="sort"
checked={radio == 5}
onChange={handleRadio}
type="radio"
value={5}
/>
&#xf15d; Website title (A-Z)
</label>
<label>
<input
name="sort"
checked={radio == 6}
onChange={handleRadio}
type="radio"
value={6}
/>
&#xf15e; Website title (Z-A)
</label>
</div>
<div className="section">
<h4>Include/Exclude</h4>
<label>
<input
type="checkbox"
checked={nameChecked}
onChange={() => setNameChecked(!nameChecked)}
/>
Name
</label>
<label>
<input
type="checkbox"
checked={titleChecked}
onChange={() => setTitleChecked(!titleChecked)}
/>
Website title
</label>
<label>
<input
type="checkbox"
checked={tagChecked}
onChange={() => setTagChecked(!tagChecked)}
/>
Tags
</label>
</div>
</div>
<button className="apply-btn" onClick={applyChanges}>
Apply
</button>
</fieldset>
</div>
</>

View File

@ -1,44 +0,0 @@
import "../styles/Sort.css";
const Sort = ({ sortBy, onExit }) => {
function abort(e) {
if (e.target.className === "sort-overlay") {
onExit();
}
}
function sort(e) {
sortBy(e.target.value);
}
return (
<>
<div className="sort-overlay" onClick={abort}></div>
<div className="sort-box">
<fieldset className="sort" onClick={sort}>
<legend>Sort by</legend>
<button className="sort-by-btn" value="Default">
&#xf271; Date (Newest first)
</button>
<button className="sort-by-btn" value="Date (Oldest first)">
&#xf272; Date (Oldest first)
</button>
<button className="sort-by-btn" value="Name (A-Z)">
&#xf15d; Name (A-Z)
</button>
<button className="sort-by-btn" value="Name (Z-A)">
&#xf15e; Name (Z-A)
</button>
<button className="sort-by-btn" value="Title (A-Z)">
&#xf15d; Website title (A-Z)
</button>
<button className="sort-by-btn" value="Title (Z-A)">
&#xf15e; Website title (Z-A)
</button>
</fieldset>
</div>
</>
);
};
export default Sort;

View File

@ -1,28 +1,26 @@
const filteredData = (
data,
searchQuery,
nameChecked,
tagsChecked,
descriptionChecked
filterCheckbox
) => {
return data.filter((e) => {
const name = e.name.toLowerCase().includes(searchQuery.toLowerCase());
const title = e.title.toLowerCase().includes(searchQuery.toLowerCase());
const tags = e.tag.some((e) => e.includes(searchQuery.toLowerCase()));
if (nameChecked && tagsChecked && descriptionChecked) {
if (filterCheckbox === [true, true, true]) {
return name || title || tags;
} else if (nameChecked && tagsChecked) {
} else if (filterCheckbox[0] && filterCheckbox[2]) {
return name || tags;
} else if (nameChecked && descriptionChecked) {
} else if (filterCheckbox[0] && filterCheckbox[1]) {
return name || title;
} else if (tagsChecked && descriptionChecked) {
} else if (filterCheckbox[2] && filterCheckbox[1]) {
return tags || title;
} else if (nameChecked) {
} else if (filterCheckbox[0]) {
return name;
} else if (tagsChecked) {
} else if (filterCheckbox[1]) {
return tags;
} else if (descriptionChecked) {
} else if (filterCheckbox[2]) {
return title;
}
});

View File

@ -1,14 +1,14 @@
const sortList = (data, sortBy) => {
let sortedData = data;
if (sortBy === "Default") {
if (sortBy == 1) {
sortedData.sort((a, b) => {
return new Date(b.date) - new Date(a.date);
});
} else if (sortBy === "Date (Oldest first)") {
} else if (sortBy == 2) {
sortedData.sort((a, b) => {
return new Date(a.date) - new Date(b.date);
});
} else if (sortBy === "Name (A-Z)") {
} else if (sortBy == 3) {
sortedData.sort((a, b) => {
const A = a.name.toLowerCase(),
B = b.name.toLowerCase();
@ -16,7 +16,7 @@ const sortList = (data, sortBy) => {
if (A > B) return 1;
return 0;
});
} else if (sortBy === "Name (Z-A)") {
} else if (sortBy == 4) {
sortedData.sort((a, b) => {
const A = a.name.toLowerCase(),
B = b.name.toLowerCase();
@ -24,7 +24,7 @@ const sortList = (data, sortBy) => {
if (A < B) return 1;
return 0;
});
} else if (sortBy === "Title (A-Z)") {
} else if (sortBy == 5) {
sortedData.sort((a, b) => {
const A = a.title.toLowerCase(),
B = b.title.toLowerCase();
@ -32,7 +32,7 @@ const sortList = (data, sortBy) => {
if (A > B) return 1;
return 0;
});
} else if (sortBy === "Title (Z-A)") {
} else if (sortBy == 6) {
sortedData.sort((a, b) => {
const A = a.title.toLowerCase(),
B = b.title.toLowerCase();

View File

@ -1,13 +1,19 @@
@media (min-width: 650px) {
@media (width >= 650px) {
.search {
width: 35%;
min-width: 300px;
}
}
@media (max-width: 650px) {
@media (400px < width < 650px) {
.search {
width: 170px;
width: 40%;
}
}
@media (width <= 400px) {
.search {
width: 120px;
}
}

View File

@ -1,15 +1,20 @@
@media (min-width: 800px) {
@media (min-width: 600px) {
.filter {
left: 35%;
right: 35%;
left: 10%;
right: 10%;
min-width: 200px;
}
.filter-groups {
display: flex;
justify-content: space-evenly;
}
}
@media (max-width: 800px) {
@media (max-width: 600px) {
.filter {
left: 20%;
right: 20%;
left: 10%;
right: 10%;
min-width: 100px;
}
}
@ -36,10 +41,9 @@
border-width: 1px;
font-weight: 300;
border-color: rgb(141, 141, 141);
display: flex;
flex-direction: column;
justify-content: center;
box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px;
padding: 5px;
padding: 10px;
position: absolute;
-moz-user-select: none;
-webkit-user-select: none;
@ -51,10 +55,10 @@
font-weight: 600;
}
.filter > label {
margin: 5px;
.section > label {
display: block;
text-align: left;
margin-bottom: 5px;
margin-bottom: 10px;
font-family: "Font Awesome 5 Free";
padding: 10px;
font-size: 1.1rem;
@ -68,6 +72,25 @@
box-shadow: 0px 0px 10px rgb(83, 143, 255);
}
.apply-btn {
font-family: "Font Awesome 5 Free";
font-size: 1.2rem;
padding: 10px;
cursor: pointer;
box-shadow: rgba(0, 0, 0, 0.4) 0px 2px 4px,
rgba(0, 0, 0, 0.3) 0px 7px 13px -3px, rgba(0, 0, 0, 0.2) 0px -3px 0px inset;
border: none;
margin-top: 20px;
display: block;
margin-left: auto;
margin-right: auto;
transition: background-color 0.1s;
}
.apply-btn:active {
box-shadow: 0px 0px 10px rgb(83, 143, 255);
}
@keyframes fadein {
from {
opacity: 0%;

View File

@ -159,6 +159,7 @@
.tags a {
margin-right: 10px;
color: #2b8add;
text-decoration: none;
}
.tags a::before {

View File

@ -1,9 +1,6 @@
.sidebar {
height: 100vh;
position: fixed;
border-right: solid;
border-width: 1px;
border-color: gray;
}
.sidebar h1 {

View File

@ -1,77 +0,0 @@
@media (min-width: 800px) {
.sort {
left: 30%;
right: 30%;
min-width: 200px;
}
}
@media (max-width: 800px) {
.sort {
left: 20%;
right: 20%;
min-width: 100px;
}
}
.sort-overlay {
animation: fadein 0.2s;
background-color: black;
opacity: 10%;
position: fixed;
top: 0;
left: 0;
bottom: 0;
width: 100vw;
z-index: 1;
}
.sort-box {
position: relative;
}
.sort {
animation: fadein 0.3s;
border: solid;
border-width: 1px;
font-weight: 300;
border-color: rgb(141, 141, 141);
display: flex;
flex-direction: column;
box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px;
padding: 5px;
position: absolute;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
z-index: 2;
}
.sort legend {
font-weight: 600;
}
.sort-by-btn {
margin: 5px;
text-align: left;
font-family: "Font Awesome 5 Free";
padding: 10px;
font-size: 1.1rem;
cursor: pointer;
box-shadow: rgba(0, 0, 0, 0.4) 0px 2px 4px,
rgba(0, 0, 0, 0.3) 0px 7px 13px -3px, rgba(0, 0, 0, 0.2) 0px -3px 0px inset;
border: none;
transition: background-color 0.1s;
}
.sort-by-btn:active {
box-shadow: 0px 0px 10px rgb(83, 143, 255);
}
@keyframes fadein {
from {
opacity: 0%;
}
to {
}
}

View File

@ -32,23 +32,15 @@ body {
background-color: #1f2c38;
}
.send-btn {
background-color: #273949;
color: #ffffffb6;
}
.sort {
background-color: #1f2c38;
}
.sort-by-btn {
.send-btn,
.apply-btn {
background-color: #273949;
color: #ffffffb6;
}
.btn:hover,
.sort-by-btn:hover,
.send-btn:hover {
.send-btn:hover,
.apply-btn:hover {
background-color: rgb(76, 117, 170);
}
@ -89,7 +81,7 @@ body {
background-color: #1f2c38;
}
.filter > label {
.section > label {
background-color: #273949;
color: #ffffffb6;
}
@ -142,29 +134,24 @@ body {
color: rgb(9, 139, 214);
}
.light .filter,
.light .sort {
.light .filter {
background-color: rgb(233, 220, 179);
}
.light .filter > label {
.light .section > label {
background-color: lightyellow;
color: #4b4b4bb6;
}
.light .sort-by-btn {
background-color: lightyellow;
color: #4b4b4bb6;
}
.light .send-btn {
.light .send-btn,
.light .apply-btn {
background-color: lightyellow;
color: #717171b6;
}
.light .sort-by-btn:hover,
.light .btn:hover,
.light .send-btn:hover {
.light .send-btn:hover,
.light .apply-btn:hover {
background-color: rgb(55, 131, 237);
color: #d8d8d8;
}