Tag Selection (using react-select library)

This commit is contained in:
Daniel
2022-05-29 07:57:27 +04:30
parent b81f4e2769
commit 23dbaaf309
7 changed files with 564 additions and 11 deletions
+48 -2
View File
@@ -9,6 +9,29 @@ function App() {
const [isAdding, setIsAdding] = useState(false);
const [searchQuery, setSearchQuery] = useState('');
const [numberOfResults, setNumberOfResults] = useState(0);
const [nameChecked, setNameChecked] = useState(true);
const [descriptionChecked, setDescriptionChecked] = useState(true);
const [tagsChecked, setTagsChecked] = useState(true);
function toggleFilterBtn(e) {
if(e.target.nextSibling.style.display === 'none') {
e.target.nextSibling.style.display = '';
} else if(e.target.nextSibling.style.display === '') {
e.target.nextSibling.style.display = 'none';
}
}
function handleNameCheckbox() {
setNameChecked(!nameChecked);
}
function handleDescriptionCheckbox() {
setDescriptionChecked(!descriptionChecked);
}
function handleTagsCheckbox() {
setTagsChecked(!tagsChecked);
}
function exitAdding() {
setIsAdding(!isAdding);
@@ -19,7 +42,22 @@ function App() {
}
const filteredData = data.filter((e) => {
return (e.name.toLowerCase().includes(searchQuery.toLowerCase()) || e.title.toLowerCase().includes(searchQuery.toLowerCase()) || e.tag.some((e) => e.includes(searchQuery.toLowerCase())))
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) || (!nameChecked && !tagsChecked && !descriptionChecked)) {
return (name || title || tags);
} else if(nameChecked && tagsChecked) {
return (name || tags);
} else if(nameChecked && descriptionChecked) {
return (name || title);
} else if(tagsChecked && descriptionChecked) {
return (tags || title);
}
else if(nameChecked) { return name }
else if(tagsChecked) { return tags }
else if(descriptionChecked) { return title }
});
async function fetchData() {
@@ -41,10 +79,18 @@ function App() {
return (
<div className="App">
<div className="head">
<input className="search" type="search" placeholder="&#xf002; Search for Name / Title / Tag" onChange={search}/>
<input className="search" type="search" placeholder="&#xf002; Search" onChange={search}/>
<button className="add-btn" onClick={() => setIsAdding(true)}>&#xf067;</button>
</div>
<p className="results">{numberOfResults > 0 ? numberOfResults + ' Bookmarks' : 'No bookmarks.'}</p>
<div className='filter'>
<button onClick={(e) => toggleFilterBtn(e)}>&#xf0b0;</button>
<div>
<label><input type="checkbox" checked={nameChecked} onChange={handleNameCheckbox} />Name</label>
<label><input type="checkbox" checked={descriptionChecked} onChange={handleDescriptionCheckbox} />Title/Description</label>
<label><input type="checkbox" checked={tagsChecked} onChange={handleTagsCheckbox} />Tags</label>
</div>
</div>
<List data={filteredData} reFetch={fetchData} />
{isAdding ? <AddModal onExit={exitAdding} reFetch={fetchData} /> : null}
</div>
+5 -3
View File
@@ -2,6 +2,7 @@ import { useState } from 'react';
import { nanoid } from 'nanoid'
import '../styles/Modal.css';
import config from '../config.json';
import TagSelection from './TagSelection';
const AddModal = ({onExit, reFetch}) => {
const [name, setName] = useState('');
@@ -79,13 +80,14 @@ const AddModal = ({onExit, reFetch}) => {
<div className='overlay' onClick={abort}>
<div className='box'>
<div className='modal-content'>
<h2>Add Bookmark</h2>
<h2>New Bookmark</h2>
<h3>Name:</h3>
<input onChange={SetName} className="modal-input" type="search" placeholder="e.g. Example Tutorial"/>
<h3>Link:</h3>
<input onChange={SetLink} className="modal-input" type="search" placeholder="e.g. https://example.com/"/>
<h3>Tag:</h3>
<input onChange={SetTag} className="modal-input" type="search" placeholder="e.g. Tutorials (Seperate with spaces)"/>
<h3>Tags:</h3>
<TagSelection />
{/* <input onChange={SetTag} className="modal-input" type="search" placeholder="e.g. Tutorials (Seperate with spaces)"/> */}
<button onClick={submitBookmark} className="upload-btn">Upload &#xf093;</button>
<button className="cancel-btn">Cancel</button>
</div>
+63
View File
@@ -0,0 +1,63 @@
import { useState } from "react";
import CreatableSelect from "react-select/creatable";
const options = [
{ value: "chocolate", label: "Chocolate" },
{ value: "strawberry", label: "Strawberry" },
{ value: "vanilla", label: "Vanilla" }
];
const customStyles = {
container: (provided) => ({
...provided,
marginLeft: '20%',
marginRight: '20%',
}),
placeholder: (provided) => ({
...provided,
color: '#a9a9a9',
}),
indicatorSeparator: (provided) => ({
...provided,
display: 'none',
}),
menu: (provided) => ({
...provided,
padding: '5px',
borderRadius: '10px',
opacity: '90%',
color: 'gray',
background: '#273949',
boxShadow: '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',
}),
input: (provided) => ({
...provided,
color: 'white',
}),
control: (provided) => ({
...provided,
background: '#273949',
border: 'none',
borderRadius: '10px',
boxShadow: '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',
}),
}
export default function TagSelection() {
const [selectedOption, setSelectedOption] = useState(null);
return (
<CreatableSelect
styles={customStyles}
isMulti
defaultValue={selectedOption}
onChange={setSelectedOption}
options={options}
/>
);
}
+39 -6
View File
@@ -13,11 +13,11 @@
margin: 20px 20px 0px 20px;
padding: 10px;
font-family: 'Font Awesome 5 Free';
font-size: 1.5rem;
font-size: 1.2rem;
padding-left: 10px;
border: none;
width: 30%;
min-width: 450px;
width: 20%;
min-width: 300px;
color: white;
background-color:#273949;
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;
@@ -33,7 +33,7 @@
.add-btn {
border-radius: 10px;
margin: 20px 20px 0px 20px;
margin: 20px 20px 0px auto;
font-family: 'Font Awesome 5 Free';
padding: 10px;
font-size: 1.5rem;
@@ -42,7 +42,6 @@
color: #ffffffb6;
background-color:#273949;
border: none;
margin-left: auto;
transition: background-color 0.1s;
}
@@ -55,5 +54,39 @@ textarea:focus, input:focus{
}
.results {
margin: 20px 20px 20px 30px;
margin: 20px 20px 0px 30px;
display: inline-block;
}
.filter {
display: inline-block;
}
.filter button {
border-radius: 10px;
font-family: 'Font Awesome 5 Free';
padding: 10px;
font-size: 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;
color: #ffffffb6;
background-color:#273949;
border: none;
transition: background-color 0.1s;
}
.filter button:hover {
background-color: rgb(76, 117, 170);
}
.display {
visibility: visible;
}
.filter div {
position: absolute;
margin: -30px 0 0 50px;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
}
+3
View File
@@ -22,9 +22,12 @@
.box h2 {
margin-top: -1px;
margin-bottom: 30px;
text-align: center;
}
.box h3 {text-align: center;}
.modal-content {
padding: 20px;
}