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

View File

@ -1,50 +1,137 @@
import "../styles/Filters.css"; import "../styles/Filters.css";
import { useState } from "react";
const Filters = ({ const Filters = ({
nameChecked, filterCheckbox,
handleNameCheckbox, handleFilterCheckbox,
descriptionChecked, sortBy,
handleDescriptionCheckbox, sort,
tagsChecked,
handleTagsCheckbox,
onExit, onExit,
}) => { }) => {
const [nameChecked, setNameChecked] = useState(filterCheckbox[0]),
[titleChecked, setTitleChecked] = useState(filterCheckbox[1]),
[tagChecked, setTagChecked] = useState(filterCheckbox[2]),
[radio, setRadio] = useState(sort);
function abort(e) { function abort(e) {
if (e.target.className === "filter-overlay") { if (e.target.className === "filter-overlay") {
onExit(); onExit();
} }
} }
function handleRadio(e) {
setRadio(e.target.value);
}
function applyChanges() {
handleFilterCheckbox([nameChecked, titleChecked, tagChecked]);
sortBy(radio);
}
return ( return (
<> <>
<div className="filter-overlay" onClick={abort}></div> <div className="filter-overlay" onClick={abort}></div>
<div className="filter-box"> <div className="filter-box">
<fieldset className="filter"> <fieldset className="filter">
<legend>Filter by</legend> <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> <label>
<input <input
type="checkbox" type="checkbox"
checked={nameChecked} checked={nameChecked}
onChange={handleNameCheckbox} onChange={() => setNameChecked(!nameChecked)}
/> />
Name Name
</label> </label>
<label> <label>
<input <input
type="checkbox" type="checkbox"
checked={descriptionChecked} checked={titleChecked}
onChange={handleDescriptionCheckbox} onChange={() => setTitleChecked(!titleChecked)}
/> />
Website title Website title
</label> </label>
<label> <label>
<input <input
type="checkbox" type="checkbox"
checked={tagsChecked} checked={tagChecked}
onChange={handleTagsCheckbox} onChange={() => setTagChecked(!tagChecked)}
/> />
Tags Tags
</label> </label>
</div>
</div>
<button className="apply-btn" onClick={applyChanges}>
Apply
</button>
</fieldset> </fieldset>
</div> </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 = ( const filteredData = (
data, data,
searchQuery, searchQuery,
nameChecked, filterCheckbox
tagsChecked,
descriptionChecked
) => { ) => {
return data.filter((e) => { return data.filter((e) => {
const name = e.name.toLowerCase().includes(searchQuery.toLowerCase()); const name = e.name.toLowerCase().includes(searchQuery.toLowerCase());
const title = e.title.toLowerCase().includes(searchQuery.toLowerCase()); const title = e.title.toLowerCase().includes(searchQuery.toLowerCase());
const tags = e.tag.some((e) => e.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; return name || title || tags;
} else if (nameChecked && tagsChecked) { } else if (filterCheckbox[0] && filterCheckbox[2]) {
return name || tags; return name || tags;
} else if (nameChecked && descriptionChecked) { } else if (filterCheckbox[0] && filterCheckbox[1]) {
return name || title; return name || title;
} else if (tagsChecked && descriptionChecked) { } else if (filterCheckbox[2] && filterCheckbox[1]) {
return tags || title; return tags || title;
} else if (nameChecked) { } else if (filterCheckbox[0]) {
return name; return name;
} else if (tagsChecked) { } else if (filterCheckbox[1]) {
return tags; return tags;
} else if (descriptionChecked) { } else if (filterCheckbox[2]) {
return title; return title;
} }
}); });

View File

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

View File

@ -1,13 +1,19 @@
@media (min-width: 650px) { @media (width >= 650px) {
.search { .search {
width: 35%; width: 35%;
min-width: 300px; min-width: 300px;
} }
} }
@media (max-width: 650px) { @media (400px < width < 650px) {
.search { .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 { .filter {
left: 35%; left: 10%;
right: 35%; right: 10%;
min-width: 200px; min-width: 200px;
} }
.filter-groups {
display: flex;
justify-content: space-evenly;
}
} }
@media (max-width: 800px) { @media (max-width: 600px) {
.filter { .filter {
left: 20%; left: 10%;
right: 20%; right: 10%;
min-width: 100px; min-width: 100px;
} }
} }
@ -36,10 +41,9 @@
border-width: 1px; border-width: 1px;
font-weight: 300; font-weight: 300;
border-color: rgb(141, 141, 141); border-color: rgb(141, 141, 141);
display: flex; justify-content: center;
flex-direction: column;
box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px; 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; position: absolute;
-moz-user-select: none; -moz-user-select: none;
-webkit-user-select: none; -webkit-user-select: none;
@ -51,10 +55,10 @@
font-weight: 600; font-weight: 600;
} }
.filter > label { .section > label {
margin: 5px; display: block;
text-align: left; text-align: left;
margin-bottom: 5px; margin-bottom: 10px;
font-family: "Font Awesome 5 Free"; font-family: "Font Awesome 5 Free";
padding: 10px; padding: 10px;
font-size: 1.1rem; font-size: 1.1rem;
@ -68,6 +72,25 @@
box-shadow: 0px 0px 10px rgb(83, 143, 255); 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 { @keyframes fadein {
from { from {
opacity: 0%; opacity: 0%;

View File

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

View File

@ -1,9 +1,6 @@
.sidebar { .sidebar {
height: 100vh; height: 100vh;
position: fixed; position: fixed;
border-right: solid;
border-width: 1px;
border-color: gray;
} }
.sidebar h1 { .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; background-color: #1f2c38;
} }
.send-btn { .send-btn,
background-color: #273949; .apply-btn {
color: #ffffffb6;
}
.sort {
background-color: #1f2c38;
}
.sort-by-btn {
background-color: #273949; background-color: #273949;
color: #ffffffb6; color: #ffffffb6;
} }
.btn:hover, .btn:hover,
.sort-by-btn:hover, .send-btn:hover,
.send-btn:hover { .apply-btn:hover {
background-color: rgb(76, 117, 170); background-color: rgb(76, 117, 170);
} }
@ -89,7 +81,7 @@ body {
background-color: #1f2c38; background-color: #1f2c38;
} }
.filter > label { .section > label {
background-color: #273949; background-color: #273949;
color: #ffffffb6; color: #ffffffb6;
} }
@ -142,29 +134,24 @@ body {
color: rgb(9, 139, 214); color: rgb(9, 139, 214);
} }
.light .filter, .light .filter {
.light .sort {
background-color: rgb(233, 220, 179); background-color: rgb(233, 220, 179);
} }
.light .filter > label { .light .section > label {
background-color: lightyellow; background-color: lightyellow;
color: #4b4b4bb6; color: #4b4b4bb6;
} }
.light .sort-by-btn { .light .send-btn,
background-color: lightyellow; .light .apply-btn {
color: #4b4b4bb6;
}
.light .send-btn {
background-color: lightyellow; background-color: lightyellow;
color: #717171b6; color: #717171b6;
} }
.light .sort-by-btn:hover,
.light .btn:hover, .light .btn:hover,
.light .send-btn:hover { .light .send-btn:hover,
.light .apply-btn:hover {
background-color: rgb(55, 131, 237); background-color: rgb(55, 131, 237);
color: #d8d8d8; color: #d8d8d8;
} }