From abef40575f80411d3c722126c290d04ea7c3063f Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Thu, 23 Apr 2026 17:01:20 -0400 Subject: [PATCH] fix(dashboard): use anchor tags for client-side rendered book cards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When switching libraries via TypeScript, renderBookCard() built book cards as
elements with data-action="view-book" for event delegation, but the click handler was commented out — making books unclickable after any library switch. The SSR path used proper tags. Now renderBookCard() wraps cards in to match the SSR BookCard template, so book links work identically regardless of whether content was server-rendered or client-rendered. Also removed the dead view-book handler code and viewBook() stub. Additionally fixed a listener re-registration bug where the input and library-select change listeners were nested inside the click callback, causing them to be registered N times after N clicks. Moved them to initDashboard() scope so they register exactly once. --- web/src/dashboard.ts | 59 +++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/web/src/dashboard.ts b/web/src/dashboard.ts index 99da224..5f7f8b8 100644 --- a/web/src/dashboard.ts +++ b/web/src/dashboard.ts @@ -326,10 +326,9 @@ function renderBookCard(book: BookInfo): string { const coverUrl = book.cover_image_path || "/static/placeholder-book.svg"; return ` +
@@ -348,12 +347,10 @@ function renderBookCard(book: BookInfo): string { ${book.author ? `

${book.author}

` : ""}
+ `; } -// function viewBook(bookId: string): void { -// console.log("View book:", bookId); -// } async function reloadPage(): Promise { //Get current library from dropdown @@ -468,11 +465,6 @@ function initDashboard() { break; } - // case "view-book": { - // const bookId = target.dataset.bookId || actionElem?.dataset.bookId; - // if (bookId) viewBook(bookId); - // break; - // } case "reload-page": reloadPage(); @@ -485,33 +477,34 @@ function initDashboard() { } } - document.addEventListener("input", (e: Event) => { - const target = e.target as HTMLElement; - const actionElem = target.closest("[data-input-action]") as HTMLElement; - const action = actionElem?.getAttribute("data-input-action"); + }); - switch (action) { - case "update-items-count": { - const input = target as HTMLInputElement; - const displayTarget = input.getAttribute("target"); - if (displayTarget) updateItemsCount(input, displayTarget); - break; - } + document.addEventListener("input", (e: Event) => { + const target = e.target as HTMLElement; + const actionElem = target.closest("[data-input-action]") as HTMLElement; + const action = actionElem?.getAttribute("data-input-action"); + + switch (action) { + case "update-items-count": { + const input = target as HTMLInputElement; + const displayTarget = input.getAttribute("target"); + if (displayTarget) updateItemsCount(input, displayTarget); + break; } - }); - // Load saved library on page load - const librarySelect = document.getElementById( - "library-select", - ) as HTMLSelectElement; - if (librarySelect) { - librarySelect.addEventListener("change", (e) => { - const target = e.target as HTMLSelectElement; - if (target.value) { - switchLibrary(target.value); - } - }); } }); + + const librarySelect = document.getElementById( + "library-select", + ) as HTMLSelectElement; + if (librarySelect) { + librarySelect.addEventListener("change", (e) => { + const target = e.target as HTMLSelectElement; + if (target.value) { + switchLibrary(target.value); + } + }); + } } export { initDashboard };