fix: Dashboard modal and slider library-specific behavior

Fix multiple issues with dashboard customization modal and slider
not working correctly per library.

Frontend changes in web/src/dashboard.ts:
- Fix openDashboardSettings() to use current library ID
  - Add library_id parameter to dashboard preferences API call
  - Show toast error message on API failure instead of opening modal
  - Prevent opening modal with stale/inaccurate data

- Fix slider query parameter mismatch
  - Change from 'libraryId' to 'library_id' to match backend API
  - Fix DOM query from collectionList.querySelector to document.querySelector
  - Ensure slider targets correct input element

- Fix saveDashboardSettings() to refresh current library
  - Fetch current library data before saving preferences
  - Use library_id from current library, not from URL
  - Show toast error message on save failure
  - Keep modal open on error for user to retry

- Add localStorage persistence for selected library
  - Store selectedLibrary in localStorage after switching
  - Enables persistence across page refreshes

- Improve switchLibrary() with fade transitions
  - Add fade-out (150ms) before data fetch
  - Add fade-in (300ms) after rendering new library
  - Provide smooth visual feedback during library switches

- Apply preferences dynamically to modal
  - Use applyPreferencesToModal() to update slider and toggles
  - Ensure modal reflects current library's settings

Backend changes in internal/router/dashboard.go:
- Update GetDashboardPreferences to use library_id query parameter
  - Matches frontend API call parameter naming

Template changes in templates/dashboard.templ:
- Remove duplicate renderDashboardCollections() inline script
  - Functionality now handled by dashboard.ts

These fixes ensure that:
1. Dashboard settings work correctly per library
2. Slider reflects and updates the correct library's item limit
3. Toggles show accurate visibility state for each library
4. Library switches provide smooth visual feedback
5. Errors are properly surfaced to users via toast messages
This commit is contained in:
2026-03-01 00:29:00 -05:00
parent 0b666f3fdd
commit 62d3d50140
4 changed files with 271 additions and 112 deletions
+21 -20
View File
@@ -5,7 +5,7 @@ import (
"fmt"
)
templ Dashboard(user User, sections []handlers.SectionData, libData []LibraryData, currentLibraryID string, errorMessage string) {
templ Dashboard(user User, sections []handlers.SectionData, allSections []handlers.SectionData, libData []LibraryData, currentLibraryID string, hiddenCollections []string, itemsPerSection int, errorMessage string) {
<!DOCTYPE html>
<html lang="en">
<head>
@@ -31,7 +31,6 @@ templ Dashboard(user User, sections []handlers.SectionData, libData []LibraryDat
name="library_id"
class="px-4 py-2 rounded-lg border focus:ring-2 focus:ring-blue-500"
style="background-color: var(--bg-secondary); color: var(--text-primary);"
data-action="switch-library"
>
for _, lib := range libData {
if lib.ID == currentLibraryID {
@@ -76,7 +75,7 @@ templ Dashboard(user User, sections []handlers.SectionData, libData []LibraryDat
}
</main>
<!-- Dashboard Settings Modal -->
@DashboardSettingsModal(sections)
@DashboardSettingsModal(allSections, hiddenCollections, itemsPerSection)
@ErrorToast(errorMessage)
<script src="/static/woodPanelingInit.js"></script>
</body>
@@ -158,7 +157,7 @@ templ CollectionCarousel(section handlers.SectionData) {
templ BookCard(item handlers.BookInfo) {
<div
class="book-card flex-shrink-0 w-32 snap-start cursor-pointer
class="book-card flex-shrink-0 w-36 rounded-lg overflow-hidden snap-start cursor-pointer
transition-transform duration-200 hover:scale-105"
data-action="view-book"
data-book-id={ item.MediaItemID }
@@ -167,7 +166,7 @@ templ BookCard(item handlers.BookInfo) {
aria-label={ "View " + item.Title }
>
<div
class="aspect-[2/3] rounded-lg overflow-hidden shadow-lg mb-2
class="aspect-[2/3] overflow-hidden shadow-lg
bg-gradient-to-br from-gray-700 to-gray-900"
>
if item.CoverImagePath != "" {
@@ -186,18 +185,20 @@ templ BookCard(item handlers.BookInfo) {
/>
}
</div>
<h3 class="font-semibold text-sm line-clamp-2" style="color: var(--text-primary)">
{ item.Title }
</h3>
if item.Author != "" {
<p class="text-xs line-clamp-1" style="color: var(--text-secondary)">
{ item.Author }
</p>
}
<div class="book-card-text px-2 py-1 bg-[color-mix(in_srgb,var(--wood-border)_60%,transparent)]">
<h3 class="font-semibold text-base line-clamp-2" style="color: var(--text-primary)">
{ item.Title }
</h3>
if item.Author != "" {
<p class="text-sm line-clamp-1" style="color: var(--text-secondary)">
{ item.Author }
</p>
}
</div>
</div>
}
templ DashboardSettingsModal(sections []handlers.SectionData) {
templ DashboardSettingsModal(sections []handlers.SectionData, hiddenCollections []string, itemsPerSection int) {
<div
id="dashboard-settings-modal"
class="hidden fixed inset-0 z-50 flex items-center justify-center"
@@ -256,9 +257,9 @@ templ DashboardSettingsModal(sections []handlers.SectionData) {
<input
type="checkbox"
class="sr-only peer"
checked
data-action="toggle-collection-visibility"
data-collection-id={ section.ID }
if !ContainsString(hiddenCollections, section.ID) {
checked
}
/>
<div
class="w-11 h-6 bg-gray-600 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-800 rounded-full peer
@@ -275,16 +276,16 @@ templ DashboardSettingsModal(sections []handlers.SectionData) {
<!-- Items Per Section Slider -->
<div class="mb-6">
<label class="block text-sm font-medium mb-2" style="color: var(--text-secondary)">
Items per Collection: <span id="items-count-display" class="font-bold">20</span>
Items per Collection: <span id="items-count-display" class="font-bold">{ itemsPerSection }</span>
</label>
<input
type="range"
min="10"
max="50"
step="5"
value="20"
value={ itemsPerSection }
class="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer"
data-action="update-items-count"
data-input-action="update-items-count"
target="items-count-display"
/>
</div>