Added Dark/Light mode feature.

This commit is contained in:
Daniel 2022-06-07 16:30:16 +04:30
parent 91d72e0c0f
commit a2b1d2109f
12 changed files with 237 additions and 110 deletions

View File

@ -22,7 +22,8 @@ function App() {
[descriptionChecked, setDescriptionChecked] = useState(true),
[tagsChecked, setTagsChecked] = useState(true),
[sortBy, setSortBy] = useState('Default'),
[loader, setLoader] = useState(false);
[loader, setLoader] = useState(false),
[lightMode, setLightMode] = useState(false);
function SetLoader(x) {
setLoader(x)
@ -57,7 +58,7 @@ function App() {
}
function sortByFunc(e) {
setSortBy(e)
setSortBy(e);
}
const filteredData = filter(data, searchQuery, nameChecked, tagsChecked, descriptionChecked);
@ -80,6 +81,14 @@ function App() {
useEffect(() => {
setNumberOfResults(filteredData.length);
}, [filteredData]);
useEffect(() => {
if (lightMode) {
document.body.classList.add("light");
} else {
document.body.classList.remove("light");
}
}, [lightMode]);
return (
<div className="App">
@ -87,13 +96,14 @@ function App() {
<div className="head">
<input className="search" type="search" placeholder="&#xf002; Search" onChange={search}/>
<button className="add-btn btn" onClick={() => setNewBox(true)}>&#xf067;</button>
<button className="dark-light-btn btn" onClick={() => setLightMode(!lightMode)}>&#xf042;</button>
</div>
<p className="results">{numberOfResults > 0 ? numberOfResults + ' Bookmarks found' : null}</p>
<button className='btn' onClick={() => setFilterBox(true)}>&#xf0b0;</button>
<button className='btn' style={{marginTop: '10px'}} onClick={() => setFilterBox(true)}>&#xf0b0;</button>
<button className='btn' style={{marginLeft: '10px'}} onClick={() => setSortBox(true)}>&#xf0dc;</button>
<List SetLoader={SetLoader} data={filteredData} tags={tags} reFetch={fetchData} />
<List lightMode={lightMode} SetLoader={SetLoader} data={filteredData} tags={tags} reFetch={fetchData} />
{numberOfResults === 0 ? <NoResults /> : null}
@ -116,10 +126,11 @@ function App() {
SetLoader={SetLoader}
onExit={exitAdding}
reFetch={fetchData}
lightMode={lightMode}
tags={() => tags}
/> : null}
{loader ? <Loader /> : null}
{loader ? <Loader lightMode={lightMode} /> : null}
</div>
</div>
);

View File

@ -3,7 +3,7 @@ import '../styles/SendItem.css';
import TagSelection from './TagSelection';
import addItem from '../modules/send';
const AddItem = ({onExit, reFetch, tags, SetLoader}) => {
const AddItem = ({onExit, reFetch, tags, SetLoader, lightMode}) => {
const [name, setName] = useState('');
const [link, setLink] = useState('');
const [tag, setTag] = useState([]);
@ -43,7 +43,7 @@ const AddItem = ({onExit, reFetch, tags, SetLoader}) => {
<h3>Name: <span className='optional'>(Optional)</span></h3>
<input onChange={SetName} className="AddItem-input" type="search" placeholder="e.g. Example Tutorial"/>
<h3>Tags: <span className='optional'>(Optional)</span></h3>
<TagSelection setTags={SetTags} tags={tags} />
<TagSelection setTags={SetTags} tags={tags} lightMode={lightMode} />
<button onClick={newItem} className="send-btn">Add &#xf067;</button>
</div>
</fieldset>

View File

@ -4,7 +4,7 @@ import '../styles/SendItem.css';
import TagSelection from './TagSelection';
import editItem from '../modules/send';
const EditItem = ({tags, item, onExit, SetLoader, reFetch}) => {
const EditItem = ({tags, item, onExit, SetLoader, reFetch, lightMode }) => {
const [name, setName] = useState(item.name);
const [tag, setTag] = useState(item.tag);
@ -40,7 +40,7 @@ const EditItem = ({tags, item, onExit, SetLoader, reFetch}) => {
<div className='add-overlay' onClick={abort}></div>
<fieldset className='box'>
<legend >Edit bookmark</legend>
<button className="edit-btn delete" onClick={deleteItem}>&#xf2ed;</button>
<button className="delete" onClick={deleteItem}>&#xf2ed;</button>
<div className='AddItem-content'>
<h3>Link: <a target="_blank" rel="noreferrer" href={item.link}>{url.hostname}</a></h3>
<h3 className='title'><b>{item.title}</b></h3>
@ -48,7 +48,7 @@ const EditItem = ({tags, item, onExit, SetLoader, reFetch}) => {
<h3>Name: <span className='optional'>(Optional)</span></h3>
<input onChange={SetName} className="AddItem-input" type="search" value={name} placeholder={"e.g. Example Tutorial"} />
<h3>Tags: <span className='optional'>(Optional)</span></h3>
<TagSelection setTags={SetTags} tags={tags} tag={tag} />
<TagSelection setTags={SetTags} tags={tags} tag={tag} lightMode={lightMode} />
<button onClick={EditItem} className="send-btn">Update &#xf303;</button>
</div>
</fieldset>

View File

@ -4,7 +4,7 @@ import ViewArchived from './ViewArchived';
import EditItem from './EditItem';
import { useState } from 'react'
const List = ({data, tags, reFetch, SetLoader}) => {
const List = ({data, tags, reFetch, SetLoader, lightMode}) => {
const [editBox, setEditBox] = useState(false)
const [editIndex, setEditIndex] = useState(0)
@ -42,7 +42,7 @@ const List = ({data, tags, reFetch, SetLoader}) => {
</div>
<div className='etc'>
<ViewArchived className='view-archived' id={e._id} />
<button className="edit-btn" onClick={() => edit(i)}>&#xf303;</button>
<button className="edit-btn btn" onClick={() => edit(i)}>&#xf303;</button>
</div>
</div>
</LazyLoad>)
@ -50,7 +50,7 @@ const List = ({data, tags, reFetch, SetLoader}) => {
console.log(e);
}
})}
{editBox ? <EditItem tags={() => tags} onExit={exitEditing} SetLoader={SetLoader} reFetch={reFetch} item={data[editIndex]} /> : null}
{editBox ? <EditItem lightMode={lightMode} tags={() => tags} onExit={exitEditing} SetLoader={SetLoader} reFetch={reFetch} item={data[editIndex]} /> : null}
</div>
)
}

View File

@ -2,10 +2,10 @@ import '../styles/Loader.css';
import { InfinitySpin } from 'react-loader-spinner'
const Loader = () => {
const Loader = ({ lightMode }) => {
return (
<div className='loader'>
<InfinitySpin color="white" />
<InfinitySpin color={lightMode ? "Black" : "White"} />
</div>
)
}

View File

@ -1,48 +1,49 @@
import CreatableSelect from "react-select/creatable";
const customStyles = {
placeholder: (provided) => ({
...provided,
color: '#a9a9a9',
// lightMode ? "Black" : "White"
export default function TagSelection({setTags, tags, tag=[], lightMode}) {
const customStyles = {
placeholder: (provided) => ({
...provided,
color: '#a9a9a9',
}),
multiValueRemove: (provided) => ({
...provided,
color: 'gray',
}),
indicatorSeparator: (provided) => ({
...provided,
display: 'none',
}),
menu: (provided) => ({
...provided,
border: 'solid',
borderWidth: '1px',
borderRadius: '0px',
borderColor: 'rgb(141, 141, 141)',
opacity: '90%',
color: 'gray',
background: lightMode ? "lightyellow" : "#273949",
boxShadow: 'rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px',
}),
input: (provided) => ({
...provided,
color: lightMode ? "rgb(64, 64, 64)" : "white",
}),
control: (provided, state) => ({
...provided,
background: lightMode ? "lightyellow" : "#273949",
border: 'none',
borderRadius: '0px',
boxShadow: state.isFocused ? 'rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px' : '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',
}),
}
multiValueRemove: (provided) => ({
...provided,
color: 'gray',
}),
indicatorSeparator: (provided) => ({
...provided,
display: 'none',
}),
menu: (provided) => ({
...provided,
border: 'solid',
borderWidth: '1px',
borderRadius: '0px',
borderColor: 'rgb(141, 141, 141)',
opacity: '90%',
color: 'gray',
background: '#273949',
boxShadow: 'rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px',
}),
input: (provided) => ({
...provided,
color: 'white',
}),
control: (provided, state) => ({
...provided,
background: '#273949',
border: 'none',
borderRadius: '0px',
boxShadow: state.isFocused ? 'rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px' : '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({setTags, tags, tag=[]}) {
const data = tags().map((e) => {
return { value: e, label: e }
})

View File

@ -1,7 +1,5 @@
.App {
min-height: 100vh;
background-color: #1f2c38;
color: white;
display: flex;
}
@ -25,8 +23,6 @@
border: none;
width: 35%;
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;
}
@ -44,24 +40,17 @@
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;
color: #ffffffb6;
background-color:#273949;
border: none;
transition: background-color 0.1s;
}
.btn:active { box-shadow: 0px 0px 10px rgb(83, 143, 255); }
.add-btn {
margin-left: auto;
}
.btn:hover {
background-color: rgb(76, 117, 170);
}
.btn:active {
box-shadow: 0px 0px 10px rgb(83, 143, 255);
}
textarea:focus, input:focus{
outline: none;
}
@ -75,7 +64,11 @@ textarea:focus, input:focus{
text-align: center;
padding-top: 5%;
padding-bottom: 5%;
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;
margin: 20px;
margin-top: 10px;
}
.dark-light-btn {
margin-left: 10px;
font-size: 1.3em;
}

View File

@ -18,7 +18,6 @@
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;
background-color: #1f2c38;
padding: 5px;
top: 15%;
left: 30%;
@ -42,8 +41,6 @@
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;
color: #ffffffb6;
background-color:#273949;
border: none;
}

View File

@ -28,7 +28,6 @@
display: flex;
justify-content: space-between;
align-items: center;
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;
}
@ -50,7 +49,6 @@
font-family: 'Font Awesome 5 Free';
pointer-events: all;
text-decoration: none;
color: rgb(194, 193, 193);
font-size: 1rem;
}
@ -66,20 +64,10 @@
.edit-btn {
position: relative;
border-radius: 100%;
margin: 20px 20px 20px 0px;
font-family: 'Font Awesome 5 Free';
width: 50px;
height: 50px;
padding: 10px;
font-size: 1.3rem;
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: #1f2c38;
border: none;
transition: background-color 0.1s;
font-size: 1.5rem;
}
.edit-btn:hover {
@ -106,7 +94,6 @@
.tags div {
margin-right: 10px;
color: rgb(126, 208, 255);
}
.tags div::before {
@ -125,15 +112,29 @@
}
.delete {
margin: 20px 20px 20px 0px;
background-color:#273949;
float: right;
font-size: 1.1rem;
width: 40px;
height: 40px;
position: relative;
border-radius: 100%;
font-family: 'Font Awesome 5 Free';
width: 40px;
height: 40px;
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;
background-color:#273949;
border: none;
transition: background-color 0.1s;
}
.delete:hover {
background-color: rgba(255, 65, 65, 0.8);
background-color: rgba(255, 75, 75, 0.8);
color: #d8d8d8;
}
.delete:active {

View File

@ -57,8 +57,6 @@
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;
color: #ffffffb6;
background-color:#273949;
border: none;
margin-top: 20px;
display: block;
@ -67,13 +65,7 @@
transition: background-color 0.1s;
}
.send-btn:hover {
background-color: rgb(76, 117, 170);
}
.send-btn:active {
box-shadow: 0px 0px 10px rgb(83, 143, 255);
}
.send-btn:active { box-shadow: 0px 0px 10px rgb(83, 143, 255); }
@keyframes fadein {
from { opacity: 0%; }
@ -87,6 +79,5 @@
}
.title {
color: darkgray;
font-size: 0.9em;
}

View File

@ -18,7 +18,6 @@
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;
background-color: #1f2c38;
padding: 5px;
top: 15%;
left: 25%;
@ -41,16 +40,10 @@
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;
color: #ffffffb6;
background-color:#273949;
border: none;
transition: background-color 0.1s;
}
.sort-by-btn:hover {
background-color: rgb(76, 117, 170);
}
.sort-by-btn:active {
box-shadow: 0px 0px 10px rgb(83, 143, 255);
}

View File

@ -6,9 +6,149 @@ body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: #1f2c38;
text-shadow: 0px 1px 1px #1f2c38;
text-shadow: 0px 1px 2px #000000;
color: white;
transition: background-color 0.1s;
}
*::selection {
background-color: rgba(115, 192, 255, 0.9);
}
background-color: rgba(120, 120, 120, 0.9);
color: white;
text-shadow: none;
}
/* Dark Mode settings (Default) */
.delete {
background-color: #1f2c38;
color: #ffffffb6;
}
.no-results {
background-color: #1f2c38;
}
.send-btn {
background-color:#273949;
color: #ffffffb6;
}
.sort {
background-color: #1f2c38;
}
.sort-by-btn {
background-color:#273949;
color: #ffffffb6;
}
.btn:hover, .sort-by-btn:hover, .send-btn:hover {
background-color: rgb(76, 117, 170);
}
.tags div {
color: rgb(126, 208, 255);
}
.title {
color: darkgray;
}
.list a {
color: rgb(194, 193, 193);
}
.btn {
color: #ffffffb6;
}
.no-results, .list-row {
transition: background-color 0.1s;
background-color:#273949;
}
.search {
transition: background-color 0.1s;
background-color:#273949;
color: white;
}
.filter {
background-color: #1f2c38;
}
.filter > label {
background-color:#273949;
color: #ffffffb6;
}
/* Light Mode settings */
.light {
text-shadow: 0px 1px 2px #ffffff;
background-color:rgb(233, 220, 179);
color: rgb(64, 64, 64);
}
.light .list-row {
background-color: lightyellow;
}
.light .btn {
background-color: lightyellow;
color: gray;
}
.light .delete {
background-color: lightyellow;
color: rgb(176, 176, 176);
}
.light input {
background-color: lightyellow;
color: black;
}
.light .box, .light .edit-btn {
background-color:rgb(233, 220, 179);
}
.light .title {
color: rgb(105, 105, 105);
}
.light .list a {
color: rgb(102, 102, 102);
}
.light .tags div {
color: rgb(9, 139, 214);
}
.light .filter, .light .sort {
background-color: rgb(233, 220, 179);
}
.light .filter > label {
background-color: lightyellow;
color: #4b4b4bb6;
}
.light .sort-by-btn {
background-color:lightyellow;
color: #4b4b4bb6;
}
.light .send-btn {
background-color: lightyellow;
color: #717171b6;
}
.light .sort-by-btn:hover, .light .btn:hover, .light .send-btn:hover {
background-color: rgb(55, 131, 237);
color: #d8d8d8;
}
.light .no-results {
background-color: lightyellow;
}