fix(dashboard): use anchor tags for client-side rendered book cards
When switching libraries via TypeScript, renderBookCard() built book
cards as <div> 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 <a> tags.
Now renderBookCard() wraps cards in <a href="/media/{id}"> 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.
This commit is contained in:
+26
-33
@@ -326,10 +326,9 @@ function renderBookCard(book: BookInfo): string {
|
|||||||
const coverUrl = book.cover_image_path || "/static/placeholder-book.svg";
|
const coverUrl = book.cover_image_path || "/static/placeholder-book.svg";
|
||||||
|
|
||||||
return `
|
return `
|
||||||
|
<a href="/media/${book.media_item_id}">
|
||||||
<div class="book-card flex-shrink-0 w-36 rounded-lg overflow-hidden snap-start cursor-pointer
|
<div class="book-card flex-shrink-0 w-36 rounded-lg overflow-hidden snap-start cursor-pointer
|
||||||
transition-transform duration-200 hover:scale-105"
|
transition-transform duration-200 hover:scale-105"
|
||||||
data-action="view-book"
|
|
||||||
data-book-id="${book.media_item_id}"
|
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="View ${book.title}">
|
aria-label="View ${book.title}">
|
||||||
@@ -348,12 +347,10 @@ function renderBookCard(book: BookInfo): string {
|
|||||||
${book.author ? `<p class="text-sm line-clamp-1" style="color: var(--text-secondary)">${book.author}</p>` : ""}
|
${book.author ? `<p class="text-sm line-clamp-1" style="color: var(--text-secondary)">${book.author}</p>` : ""}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</a>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// function viewBook(bookId: string): void {
|
|
||||||
// console.log("View book:", bookId);
|
|
||||||
// }
|
|
||||||
|
|
||||||
async function reloadPage(): Promise<void> {
|
async function reloadPage(): Promise<void> {
|
||||||
//Get current library from dropdown
|
//Get current library from dropdown
|
||||||
@@ -468,11 +465,6 @@ function initDashboard() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// case "view-book": {
|
|
||||||
// const bookId = target.dataset.bookId || actionElem?.dataset.bookId;
|
|
||||||
// if (bookId) viewBook(bookId);
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
|
|
||||||
case "reload-page":
|
case "reload-page":
|
||||||
reloadPage();
|
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) {
|
document.addEventListener("input", (e: Event) => {
|
||||||
case "update-items-count": {
|
const target = e.target as HTMLElement;
|
||||||
const input = target as HTMLInputElement;
|
const actionElem = target.closest("[data-input-action]") as HTMLElement;
|
||||||
const displayTarget = input.getAttribute("target");
|
const action = actionElem?.getAttribute("data-input-action");
|
||||||
if (displayTarget) updateItemsCount(input, displayTarget);
|
|
||||||
break;
|
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 };
|
export { initDashboard };
|
||||||
|
|||||||
Reference in New Issue
Block a user