Archive added
This commit is contained in:
parent
01a38ba145
commit
467f405f32
3 changed files with 97 additions and 25 deletions
60
app.js
60
app.js
|
|
@ -24,6 +24,9 @@ const clearAllButton = document.querySelector("#clear-all");
|
||||||
const routeCount = document.querySelector("#route-count");
|
const routeCount = document.querySelector("#route-count");
|
||||||
const emptyState = document.querySelector("#empty-state");
|
const emptyState = document.querySelector("#empty-state");
|
||||||
const routesList = document.querySelector("#routes-list");
|
const routesList = document.querySelector("#routes-list");
|
||||||
|
const archiveSection = document.querySelector("#archive-section");
|
||||||
|
const archiveCount = document.querySelector("#archive-count");
|
||||||
|
const archivedRoutesList = document.querySelector("#archived-routes-list");
|
||||||
const template = document.querySelector("#route-card-template");
|
const template = document.querySelector("#route-card-template");
|
||||||
|
|
||||||
let routes = sortRoutes(loadRoutes());
|
let routes = sortRoutes(loadRoutes());
|
||||||
|
|
@ -35,6 +38,7 @@ form.addEventListener("submit", saveRoute);
|
||||||
cancelEditButton.addEventListener("click", resetForm);
|
cancelEditButton.addEventListener("click", resetForm);
|
||||||
clearAllButton?.addEventListener("click", removeAllRoutes);
|
clearAllButton?.addEventListener("click", removeAllRoutes);
|
||||||
routesList.addEventListener("click", handleRouteAction);
|
routesList.addEventListener("click", handleRouteAction);
|
||||||
|
archivedRoutesList.addEventListener("click", handleRouteAction);
|
||||||
document.addEventListener("click", closeMenusOnOutsideClick);
|
document.addEventListener("click", closeMenusOnOutsideClick);
|
||||||
document.addEventListener("keydown", closeMenusOnEscape);
|
document.addEventListener("keydown", closeMenusOnEscape);
|
||||||
|
|
||||||
|
|
@ -93,8 +97,8 @@ function storeRoutes() {
|
||||||
|
|
||||||
function sortRoutes(routeList) {
|
function sortRoutes(routeList) {
|
||||||
return [...routeList].sort((a, b) => {
|
return [...routeList].sort((a, b) => {
|
||||||
const dateA = a.date || "0000-00-00";
|
const dateA = a.date || "9999-99-99";
|
||||||
const dateB = b.date || "0000-00-00";
|
const dateB = b.date || "9999-99-99";
|
||||||
|
|
||||||
if (dateA !== dateB) {
|
if (dateA !== dateB) {
|
||||||
return dateA.localeCompare(dateB);
|
return dateA.localeCompare(dateB);
|
||||||
|
|
@ -116,6 +120,7 @@ async function saveRoute(event) {
|
||||||
name: nameInput.value.trim(),
|
name: nameInput.value.trim(),
|
||||||
link: linkInput.value.trim(),
|
link: linkInput.value.trim(),
|
||||||
date: dateInput.value,
|
date: dateInput.value,
|
||||||
|
archived: existingRoute?.archived || false,
|
||||||
picture: existingRoute?.picture || "",
|
picture: existingRoute?.picture || "",
|
||||||
description: descriptionInput.value.trim(),
|
description: descriptionInput.value.trim(),
|
||||||
updatedAt: new Date().toISOString(),
|
updatedAt: new Date().toISOString(),
|
||||||
|
|
@ -153,19 +158,40 @@ async function saveRoute(event) {
|
||||||
|
|
||||||
function renderRoutes() {
|
function renderRoutes() {
|
||||||
routesList.innerHTML = "";
|
routesList.innerHTML = "";
|
||||||
|
archivedRoutesList.innerHTML = "";
|
||||||
|
|
||||||
|
const activeRoutes = routes.filter((route) => !route.archived);
|
||||||
|
const archivedRoutes = routes.filter((route) => route.archived);
|
||||||
|
|
||||||
|
routeCount.textContent = activeRoutes.length === 1 ? "1 route saved." : `${activeRoutes.length} routes saved.`;
|
||||||
|
emptyState.classList.toggle("hidden", activeRoutes.length > 0);
|
||||||
|
archiveSection.hidden = archivedRoutes.length === 0;
|
||||||
|
archiveCount.textContent = archivedRoutes.length;
|
||||||
|
|
||||||
|
if (!archivedRoutes.length) {
|
||||||
|
archiveSection.open = false;
|
||||||
|
}
|
||||||
|
|
||||||
routeCount.textContent = routes.length === 1 ? "1 route saved." : `${routes.length} routes saved.`;
|
|
||||||
emptyState.classList.toggle("hidden", routes.length > 0);
|
|
||||||
if (clearAllButton) {
|
if (clearAllButton) {
|
||||||
clearAllButton.hidden = routes.length === 0;
|
clearAllButton.hidden = routes.length === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const route of routes) {
|
for (const route of activeRoutes) {
|
||||||
|
routesList.append(createRouteCard(route));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const route of archivedRoutes) {
|
||||||
|
archivedRoutesList.append(createRouteCard(route));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createRouteCard(route) {
|
||||||
const card = template.content.firstElementChild.cloneNode(true);
|
const card = template.content.firstElementChild.cloneNode(true);
|
||||||
const image = card.querySelector(".route-image");
|
const image = card.querySelector(".route-image");
|
||||||
const meta = card.querySelector(".route-meta");
|
const meta = card.querySelector(".route-meta");
|
||||||
const title = card.querySelector(".route-title");
|
const title = card.querySelector(".route-title");
|
||||||
const description = card.querySelector(".route-description");
|
const description = card.querySelector(".route-description");
|
||||||
|
const archiveButton = card.querySelector(".archive-route");
|
||||||
|
|
||||||
card.dataset.id = route.id;
|
card.dataset.id = route.id;
|
||||||
meta.textContent = route.date ? formatDate(route.date) : "";
|
meta.textContent = route.date ? formatDate(route.date) : "";
|
||||||
|
|
@ -174,14 +200,14 @@ function renderRoutes() {
|
||||||
title.href = route.link;
|
title.href = route.link;
|
||||||
description.textContent = route.description;
|
description.textContent = route.description;
|
||||||
description.hidden = !route.description;
|
description.hidden = !route.description;
|
||||||
|
archiveButton.textContent = route.archived ? "Unarchive" : "Archive";
|
||||||
|
|
||||||
if (route.picture) {
|
if (route.picture) {
|
||||||
image.hidden = false;
|
image.hidden = false;
|
||||||
image.style.backgroundImage = `url("${cssUrlEscape(route.picture)}")`;
|
image.style.backgroundImage = `url("${cssUrlEscape(route.picture)}")`;
|
||||||
}
|
}
|
||||||
|
|
||||||
routesList.append(card);
|
return card;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeMenusOnOutsideClick(event) {
|
function closeMenusOnOutsideClick(event) {
|
||||||
|
|
@ -227,6 +253,26 @@ function handleRouteAction(event) {
|
||||||
if (button.classList.contains("share-route")) {
|
if (button.classList.contains("share-route")) {
|
||||||
shareRoute(route);
|
shareRoute(route);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (button.classList.contains("archive-route")) {
|
||||||
|
toggleArchive(route.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleArchive(id) {
|
||||||
|
const route = routes.find((item) => item.id === id);
|
||||||
|
if (!route) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
route.archived = !route.archived;
|
||||||
|
routes = sortRoutes(routes);
|
||||||
|
storeRoutes();
|
||||||
|
renderRoutes();
|
||||||
|
|
||||||
|
if (idInput.value === id) {
|
||||||
|
resetForm();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function startAddRoute() {
|
function startAddRoute() {
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,11 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="routes-list" class="routes-list" aria-live="polite"></div>
|
<div id="routes-list" class="routes-list" aria-live="polite"></div>
|
||||||
|
|
||||||
|
<details id="archive-section" class="archive-section" hidden>
|
||||||
|
<summary>Archived (<span id="archive-count">0</span>)</summary>
|
||||||
|
<div id="archived-routes-list" class="routes-list archived-routes-list" aria-live="polite"></div>
|
||||||
|
</details>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -99,6 +104,7 @@
|
||||||
<div class="menu-items">
|
<div class="menu-items">
|
||||||
<button type="button" class="share-route">Share</button>
|
<button type="button" class="share-route">Share</button>
|
||||||
<button type="button" class="edit-route">Edit</button>
|
<button type="button" class="edit-route">Edit</button>
|
||||||
|
<button type="button" class="archive-route">Archive</button>
|
||||||
<button type="button" class="danger remove-route">Delete</button>
|
<button type="button" class="danger remove-route">Delete</button>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
|
|
|
||||||
20
styles.css
20
styles.css
|
|
@ -336,6 +336,26 @@ textarea:focus {
|
||||||
background: var(--danger-dark);
|
background: var(--danger-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.archive-section {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archive-section > summary {
|
||||||
|
padding: 0.85rem 0.2rem;
|
||||||
|
color: var(--muted);
|
||||||
|
font-weight: 800;
|
||||||
|
cursor: pointer;
|
||||||
|
list-style-position: inside;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archived-routes-list {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archived-routes-list .route-card {
|
||||||
|
opacity: 0.82;
|
||||||
|
}
|
||||||
|
|
||||||
.empty-state {
|
.empty-state {
|
||||||
padding: 1.5rem 1rem;
|
padding: 1.5rem 1rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue