Add reusable library switcher infrastructure that can be used across
dashboard, collections list, and collection detail pages.
New files:
- templates/library_switcher.templ: Shared LibrarySwitcher component
with variadic actions slot for page-specific buttons (e.g. dashboard
settings/refresh). Includes DashboardActions sub-component.
- web/src/library-switcher.ts: Shared module providing:
- initLibrarySwitcher(): syncs dropdown with localStorage, attaches
change listener with configurable onSwitch callback
- switchWithTransition(): generic fade-out -> spinner -> fetch ->
fade-in transition used by all pages
- getCurrentLibraryId(): reads "selectedLibrary" from localStorage
Modified:
- web/src/main.ts: import new library-switcher module
- web/src/types/api.d.ts: add book_count field to CollectionData
60 lines
1.8 KiB
Templ
60 lines
1.8 KiB
Templ
package templates
|
|
|
|
templ LibrarySwitcher(libData []LibraryData, currentLibraryID string, actions ...templ.Component) {
|
|
<div class="sticky top-0 z-40 bg-opacity-95 backdrop-blur border-b" style="background-color: var(--bg-primary);">
|
|
<div class="w-full px-4 py-3 flex items-center justify-between">
|
|
<div class="flex items-center gap-4">
|
|
<label class="text-sm font-medium" style="color: var(--text-secondary)">Library:</label>
|
|
<select
|
|
id="library-select"
|
|
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);"
|
|
>
|
|
<option value="">All Libraries</option>
|
|
for _, lib := range libData {
|
|
if lib.ID == currentLibraryID {
|
|
<option value={ lib.ID } selected>{ lib.Name }</option>
|
|
} else {
|
|
<option value={ lib.ID }>{ lib.Name }</option>
|
|
}
|
|
}
|
|
</select>
|
|
</div>
|
|
if len(actions) > 0 {
|
|
<div class="flex items-center gap-2">
|
|
for _, action := range actions {
|
|
@action
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
<div
|
|
id="loading-spinner"
|
|
class="hidden fixed inset-0 bg-opacity-50 flex items-center justify-center z-50"
|
|
style="background-color: var(--bg-primary);"
|
|
>
|
|
<div class="animate-spin rounded-full h-12 w-12 border-b-2" style="border-color: var(--accent);"></div>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
templ DashboardActions() {
|
|
<button
|
|
data-action="open-dashboard-settings"
|
|
class="p-2 rounded-lg hover:bg-gray-700 transition-colors"
|
|
style="background-color: var(--bg-secondary);"
|
|
title="Customize Dashboard"
|
|
>
|
|
⚙️
|
|
</button>
|
|
<button
|
|
data-action="reload-page"
|
|
class="p-2 rounded-lg hover:bg-gray-700 transition-colors"
|
|
style="background-color: var(--bg-secondary);"
|
|
title="Refresh"
|
|
>
|
|
🔄
|
|
</button>
|
|
}
|