UI improvements.
This commit is contained in:
parent
f5b7f872f0
commit
371eb3c181
|
@ -97,7 +97,7 @@ app.delete("/api", async (req, res) => {
|
||||||
|
|
||||||
await deleteDoc(id);
|
await deleteDoc(id);
|
||||||
|
|
||||||
res.send(`Bookmark with _id:${id} deleted.`);
|
res.send(`Link with _id:${id} deleted.`);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function updateDoc(id, updatedListing) {
|
async function updateDoc(id, updatedListing) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"short_name": "Web Marker",
|
"short_name": "LinkWarden",
|
||||||
"name": "A bookmark manager",
|
"name": "LinkWarden",
|
||||||
"start_url": ".",
|
"start_url": ".",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"theme_color": "#000000",
|
"theme_color": "#000000",
|
||||||
|
|
16
src/App.js
16
src/App.js
|
@ -22,6 +22,7 @@ function App() {
|
||||||
[filterCheckbox, setFilterCheckbox] = useState([true, true, true]),
|
[filterCheckbox, setFilterCheckbox] = useState([true, true, true]),
|
||||||
[sortBy, setSortBy] = useState(1),
|
[sortBy, setSortBy] = useState(1),
|
||||||
[loader, setLoader] = useState(false),
|
[loader, setLoader] = useState(false),
|
||||||
|
[path, setPath] = useState("/"),
|
||||||
[lightMode, setLightMode] = useState(
|
[lightMode, setLightMode] = useState(
|
||||||
localStorage.getItem("light-mode") === "true"
|
localStorage.getItem("light-mode") === "true"
|
||||||
),
|
),
|
||||||
|
@ -55,6 +56,11 @@ function App() {
|
||||||
setToggle(!toggle);
|
setToggle(!toggle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function SetPath(pathname) {
|
||||||
|
setPath(pathname);
|
||||||
|
console.log(path)
|
||||||
|
}
|
||||||
|
|
||||||
const filteredData = filter(data, searchQuery, filterCheckbox);
|
const filteredData = filter(data, searchQuery, filterCheckbox);
|
||||||
|
|
||||||
async function fetchData() {
|
async function fetchData() {
|
||||||
|
@ -71,6 +77,11 @@ function App() {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [sortBy, filterCheckbox]);
|
}, [sortBy, filterCheckbox]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const currentURL = new URL(window.location.href);
|
||||||
|
SetPath(currentURL.pathname);
|
||||||
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchData();
|
fetchData();
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
|
@ -107,7 +118,7 @@ function App() {
|
||||||
<input
|
<input
|
||||||
className="search"
|
className="search"
|
||||||
type="search"
|
type="search"
|
||||||
placeholder=" Search"
|
placeholder={` Search "${path}"`}
|
||||||
onChange={search}
|
onChange={search}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -159,6 +170,7 @@ function App() {
|
||||||
element={
|
element={
|
||||||
<div className="content">
|
<div className="content">
|
||||||
<List
|
<List
|
||||||
|
SetPath={() => SetPath()}
|
||||||
lightMode={lightMode}
|
lightMode={lightMode}
|
||||||
SetLoader={SetLoader}
|
SetLoader={SetLoader}
|
||||||
data={filteredData}
|
data={filteredData}
|
||||||
|
@ -174,6 +186,7 @@ function App() {
|
||||||
path="tags/:tagId"
|
path="tags/:tagId"
|
||||||
element={
|
element={
|
||||||
<Tags
|
<Tags
|
||||||
|
SetPath={() => SetPath()}
|
||||||
lightMode={lightMode}
|
lightMode={lightMode}
|
||||||
SetLoader={SetLoader}
|
SetLoader={SetLoader}
|
||||||
data={filteredData}
|
data={filteredData}
|
||||||
|
@ -188,6 +201,7 @@ function App() {
|
||||||
path="collections/:collectionId"
|
path="collections/:collectionId"
|
||||||
element={
|
element={
|
||||||
<Collections
|
<Collections
|
||||||
|
SetPath={() => SetPath()}
|
||||||
lightMode={lightMode}
|
lightMode={lightMode}
|
||||||
SetLoader={SetLoader}
|
SetLoader={SetLoader}
|
||||||
data={filteredData}
|
data={filteredData}
|
||||||
|
|
|
@ -49,7 +49,7 @@ const AddItem = ({
|
||||||
<div className="add-overlay" onClick={abort}></div>
|
<div className="add-overlay" onClick={abort}></div>
|
||||||
<div className="send-box">
|
<div className="send-box">
|
||||||
<div className="box">
|
<div className="box">
|
||||||
<h2>New bookmark</h2>
|
<h2>New Link</h2>
|
||||||
<div className="AddItem-content">
|
<div className="AddItem-content">
|
||||||
<h3>
|
<h3>
|
||||||
<span style={{ color: "red" }}>* </span>Link:
|
<span style={{ color: "red" }}>* </span>Link:
|
||||||
|
|
|
@ -66,7 +66,7 @@ const EditItem = ({
|
||||||
<div className="send-box">
|
<div className="send-box">
|
||||||
<div className="box">
|
<div className="box">
|
||||||
<div className="title-delete-group">
|
<div className="title-delete-group">
|
||||||
<h2 className="edit-title">Edit bookmark</h2>
|
<h2 className="edit-title">Edit Link</h2>
|
||||||
<button className="delete" onClick={deleteItem}>
|
<button className="delete" onClick={deleteItem}>
|
||||||

|

|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -33,11 +33,11 @@ const Filters = ({
|
||||||
<div className="filter-overlay" onClick={abort}></div>
|
<div className="filter-overlay" onClick={abort}></div>
|
||||||
<div className="filter-box">
|
<div className="filter-box">
|
||||||
<div className="filter">
|
<div className="filter">
|
||||||
<h2>Filter search</h2>
|
<h2>Filter Results</h2>
|
||||||
|
|
||||||
<div className="filter-groups">
|
<div className="filter-groups">
|
||||||
<div className="section">
|
<div className="section">
|
||||||
<h3>Sort by</h3>
|
<h3>Sort By</h3>
|
||||||
<label>
|
<label>
|
||||||
<input
|
<input
|
||||||
name="sort"
|
name="sort"
|
||||||
|
|
|
@ -6,11 +6,16 @@ import { useState, useEffect } from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import NoResults from "./NoResults";
|
import NoResults from "./NoResults";
|
||||||
|
|
||||||
const List = ({ data, tags, collections, reFetch, SetLoader, lightMode }) => {
|
const List = ({ SetPath, data, tags, collections, reFetch, SetLoader, lightMode }) => {
|
||||||
const [editBox, setEditBox] = useState(false),
|
const [editBox, setEditBox] = useState(false),
|
||||||
[editIndex, setEditIndex] = useState(0),
|
[editIndex, setEditIndex] = useState(0),
|
||||||
[numberOfResults, setNumberOfResults] = useState(0);
|
[numberOfResults, setNumberOfResults] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const currentURL = new URL(window.location.href);
|
||||||
|
SetPath(currentURL.pathname);
|
||||||
|
})
|
||||||
|
|
||||||
function edit(index) {
|
function edit(index) {
|
||||||
setEditBox(true);
|
setEditBox(true);
|
||||||
setEditIndex(index);
|
setEditIndex(index);
|
||||||
|
@ -24,10 +29,15 @@ const List = ({ data, tags, collections, reFetch, SetLoader, lightMode }) => {
|
||||||
setNumberOfResults(data.length);
|
setNumberOfResults(data.length);
|
||||||
}, [data]);
|
}, [data]);
|
||||||
|
|
||||||
|
let currentPATH = new URL(window.location.href).pathname
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="list">
|
<div className="list">
|
||||||
{numberOfResults > 0 ? (
|
{numberOfResults > 0 ? (
|
||||||
<p className="results">{numberOfResults} Bookmarks found.</p>
|
<p>
|
||||||
|
{currentPATH === "/" ? null : <Link className="btn return-btn" to="/">Return to main page</Link>} {numberOfResults} {numberOfResults === 1 ? "Link " : "Links "}
|
||||||
|
found.
|
||||||
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{numberOfResults === 0 ? <NoResults /> : null}
|
{numberOfResults === 0 ? <NoResults /> : null}
|
||||||
|
@ -43,7 +53,7 @@ const List = ({ data, tags, collections, reFetch, SetLoader, lightMode }) => {
|
||||||
item={data[editIndex]}
|
item={data[editIndex]}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{/* eslint-disable-next-line */}
|
{/* eslint-disable-next-line */}
|
||||||
{data.map((e, i, array) => {
|
{data.map((e, i, array) => {
|
||||||
try {
|
try {
|
||||||
|
@ -74,6 +84,9 @@ const List = ({ data, tags, collections, reFetch, SetLoader, lightMode }) => {
|
||||||
{e.collection}
|
{e.collection}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="date">
|
||||||
|
{new Date(e.date).toDateString()}
|
||||||
|
</div>
|
||||||
<div className="tags">
|
<div className="tags">
|
||||||
{e.tag.map((e, i) => {
|
{e.tag.map((e, i) => {
|
||||||
const tagPath = `/tags/${e}`;
|
const tagPath = `/tags/${e}`;
|
||||||
|
@ -84,9 +97,6 @@ const List = ({ data, tags, collections, reFetch, SetLoader, lightMode }) => {
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div className="date">
|
|
||||||
{new Date(e.date).toDateString()}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="etc">
|
<div className="etc">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import List from "../componets/List";
|
import List from "../componets/List";
|
||||||
|
|
||||||
const Collections = ({ data, tags, collections, SetLoader, lightMode, reFetch }) => {
|
const Collections = ({ SetPath, data, tags, collections, SetLoader, lightMode, reFetch }) => {
|
||||||
const { collectionId } = useParams();
|
const { collectionId } = useParams();
|
||||||
const dataWithMatchingTag = data.filter((e) => {
|
const dataWithMatchingTag = data.filter((e) => {
|
||||||
return e.collection.includes(collectionId);
|
return e.collection.includes(collectionId);
|
||||||
|
@ -10,6 +10,7 @@ const Collections = ({ data, tags, collections, SetLoader, lightMode, reFetch })
|
||||||
return (
|
return (
|
||||||
<div className="content">
|
<div className="content">
|
||||||
<List
|
<List
|
||||||
|
SetPath={() => SetPath()}
|
||||||
lightMode={lightMode}
|
lightMode={lightMode}
|
||||||
data={dataWithMatchingTag}
|
data={dataWithMatchingTag}
|
||||||
tags={tags}
|
tags={tags}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import List from "../componets/List";
|
import List from "../componets/List";
|
||||||
|
|
||||||
const Tags = ({ data, tags, collections, SetLoader, lightMode, reFetch }) => {
|
const Tags = ({ SetPath, data, tags, collections, SetLoader, lightMode, reFetch }) => {
|
||||||
const { tagId } = useParams();
|
const { tagId } = useParams();
|
||||||
const dataWithMatchingTag = data.filter((e) => {
|
const dataWithMatchingTag = data.filter((e) => {
|
||||||
return e.tag.includes(tagId);
|
return e.tag.includes(tagId);
|
||||||
|
@ -10,6 +10,7 @@ const Tags = ({ data, tags, collections, SetLoader, lightMode, reFetch }) => {
|
||||||
return (
|
return (
|
||||||
<div className="content">
|
<div className="content">
|
||||||
<List
|
<List
|
||||||
|
SetPath={() => SetPath()}
|
||||||
lightMode={lightMode}
|
lightMode={lightMode}
|
||||||
data={dataWithMatchingTag}
|
data={dataWithMatchingTag}
|
||||||
tags={tags}
|
tags={tags}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
.search {
|
.search {
|
||||||
width: 35%;
|
width: 35%;
|
||||||
min-width: 300px;
|
min-width: 300px;
|
||||||
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +15,8 @@
|
||||||
@media (width <= 400px) {
|
@media (width <= 400px) {
|
||||||
.search {
|
.search {
|
||||||
width: 120px;
|
width: 120px;
|
||||||
|
font-size: 0.6rem;
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +46,6 @@
|
||||||
.search {
|
.search {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
font-family: "Font Awesome 5 Free";
|
font-family: "Font Awesome 5 Free";
|
||||||
font-size: 1.2rem;
|
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
@ -93,4 +95,4 @@ input:focus {
|
||||||
|
|
||||||
.select {
|
.select {
|
||||||
font-family: "Font Awesome 5 Free"
|
font-family: "Font Awesome 5 Free"
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,10 +28,6 @@
|
||||||
rgba(0, 0, 0, 0.2) 0px -3px 0px inset;
|
rgba(0, 0, 0, 0.2) 0px -3px 0px inset;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-row:hover img {
|
.list-row:hover img {
|
||||||
opacity: 90%;
|
opacity: 90%;
|
||||||
}
|
}
|
||||||
|
@ -44,6 +40,7 @@
|
||||||
|
|
||||||
.tags {
|
.tags {
|
||||||
margin: 10px auto 10px auto;
|
margin: 10px auto 10px auto;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-row {
|
.list-row {
|
||||||
|
@ -68,10 +65,6 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.date {
|
.date {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
@ -110,6 +103,10 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.list a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
.link {
|
.link {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
font-family: "Font Awesome 5 Free";
|
font-family: "Font Awesome 5 Free";
|
||||||
|
@ -151,19 +148,24 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
font-size: 1rem;
|
font-size: 0.8rem;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tags a {
|
.tags a {
|
||||||
margin-right: 10px;
|
padding: 10px;
|
||||||
color: #2b8add;
|
background-color:rgb(49, 114, 204);
|
||||||
text-decoration: none;
|
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;
|
||||||
|
text-shadow: none;
|
||||||
|
margin: 5px;
|
||||||
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tags a::before {
|
.tags a::before {
|
||||||
color: rgb(42, 125, 172);
|
color: rgb(0, 162, 255);
|
||||||
content: "# ";
|
content: "# ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,6 +204,7 @@
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
opacity: 80%;
|
opacity: 80%;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-results {
|
.no-results {
|
||||||
|
@ -231,5 +234,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-collection-label a {
|
.list-collection-label a {
|
||||||
color: inherit;
|
color: rgb(166, 166, 166);
|
||||||
|
text-shadow: 0px 1px 4px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.return-btn {
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 5px;
|
||||||
|
font-size: small;
|
||||||
|
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
margin-right: 5px;
|
||||||
|
text-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,10 +39,6 @@ body {
|
||||||
background-color: rgb(76, 117, 170);
|
background-color: rgb(76, 117, 170);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tags div {
|
|
||||||
color: rgb(126, 208, 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
@ -120,10 +116,6 @@ body {
|
||||||
color: rgb(102, 102, 102);
|
color: rgb(102, 102, 102);
|
||||||
}
|
}
|
||||||
|
|
||||||
.light .tags div {
|
|
||||||
color: rgb(9, 139, 214);
|
|
||||||
}
|
|
||||||
|
|
||||||
.light .filter {
|
.light .filter {
|
||||||
background-color: rgb(233, 220, 179);
|
background-color: rgb(233, 220, 179);
|
||||||
}
|
}
|
||||||
|
|
Ŝarĝante…
Reference in New Issue