- Removed ~400 lines of inline JavaScript from docs.templ
- Moved toggleSection function to docs.ts (now uses Alpine )
- Added highlightCurrentPage function to docs.ts
- Added initializeCodeCopyButtons function to docs.ts
- Updated template to use x-init for initialization
- Functions exported for use in Alpine.data
- Remove DOMContentLoaded event listeners from analytics.ts and docs.ts
- Rely on x-init attribute in templates for page initialization
- Clean up unused exports from collections.ts Alpine data
- Add x-init calls to admin_library, analytics, and docs templates
- Normalize quote style in collections WebSocket script (single to double)
- Disable Add Books button in collection detail (pending implementation)
CRITICAL FIX: initializeLibraryAdmin() was calling reloadLibraries()
which fetched data from the API and replaced the SSR-rendered library
list on page load, defeating the purpose of server-side rendering.
Changes in web/src/library.ts:
- Remove DOMContentLoaded listener (now uses Alpine x-init in template)
- Remove void reloadLibraries() call from initializeLibraryAdmin()
- Add comment explaining SSR provides initial data
- Add initializeLibraryAdmin to export statement
- Add initializeLibraryAdmin to Alpine.data() registration
- Keep reloadLibraries() as standalone function for use after CRUD ops
Rationale:
- SSR provides fast initial page load with library list
- x-init should ONLY setup event listeners, not fetch data
- reloadLibraries() is called after create/delete/update operations
- Follows SSR-first architecture: different pages have different
SSR/JS ratios (analytics is 80% JS, most pages are 80% SSR)
Documentation:
- Update COLLECTIONS_CLEANUP_GUIDE.md with SSR-first strategy
- Document page-by-page review status (dashboard ✓, collections 🔄)
- Fix template references (library.templ → admin_library.templ)
- Explain why analytics fetches data (intentional for dynamic page)
This ensures the admin library page maintains SSR benefits while
still providing interactive features via Alpine.js.
- Remove document.addEventListener("DOMContentLoaded") wrapper for loadWatchStatus()
- Simplify initialization - loadWatchStatus() is now called via Alpine.js x-init
- Reduces 4 lines, keeps same functionality
The loadWatchStatus() function is now triggered by template's x-init directive
instead of a global DOMContentLoaded listener, ensuring it only runs on the
admin page where it's actually needed.
- Remove DOMContentLoaded listeners for setupHTMXAuth, initColorSelection, and setupHTMXModalInit
- Delete dead Alpine.data exports: addbooksToAdd, removebooksToAdd, toggleBookForRemoval,
toggleBookSelection, initCollectionDetail, initIconSelection, initColorSelection
- Add missing setupHTMXAuth to export statement (it was called but not exported)
- Remove 14 lines of auto-initialization code that's no longer needed
This fixes "X is not defined" console errors for functions that were deleted
in commit 93710a1 but were still in Alpine.data export. The collections.templ template
was also updated to remove calls to these deleted functions.
These changes align with the SSR architecture where most collection functionality
is server-rendered and client-side JavaScript is used sparingly.
- Create createWebSocket() helper for WebSocket connections with authentication
- Support automatic reconnection with configurable delay
- Include error handling and logging
- Export disconnectWebSocket() for cleanup
This helper provides a centralized way to create WebSocket connections
with JWT token authentication from localStorage. Although not currently
used in the application (we opted for server-side token injection in templates),
it provides a reusable utility for future WebSocket integrations.
Features:
- Automatic token retrieval from localStorage
- Configurable reconnection behavior (enabled by default)
- Error handling with try-catch on all callbacks
- Connection cleanup and management
- Type-safe configuration interface
Available for future use in client-side WebSocket scenarios or as a reference
implementation.
- Regenerate Go template files with updated FileName paths for error reporting
- Apply Prettier formatting to api-explorer-docs.ts for consistency
- Format long function signatures across multiple lines for readability
- Format long conditional chains for better code clarity
Changes are purely formatting and do not affect functionality:
- api-explorer-docs.ts: Format initAPIExplorerDoc, tryDocEndpoint, and other functions
- Generated _templ.go files: Update FileName paths from relative to absolute (e.g., "admin.templ" → "templates/admin.templ")
This ensures consistent code style across the codebase and improves
error reporting by providing full file paths in template error messages.
- Add defer attribute to <script src="/static/main.js"> in 21 template files
- Improves page load performance by allowing HTML parsing to continue without blocking
- Maintains script execution order while enabling parallel resource loading
- Remove duplicate defer attribute from header.templ line 264
- Add websocket.ts import to main.ts for module registration
This optimization reduces page render blocking and improves perceived load times
by allowing the browser to continue parsing HTML while the main.js bundle loads.
The defer attribute ensures scripts execute in order after HTML parsing completes.
Affected templates include:
- Admin pages: admin, admin_library, admin_settings, admin_users
- Content pages: analytics, bookshelf, collections, conflicts, custom_section
- User pages: dashboard, devices, docs, index, login, profile, progress, queue, register
- System pages: header, unlinked_books
- Wrap all Alpine.data() object literals in arrow functions (() => ({}))
- This fixes "n.bind is not a function" errors when Alpine initializes components
- Alpine.data() requires a factory function, not a plain object
- Ensures each component instance gets its own closure and proper this binding
Fixed 24 TypeScript files:
- admin.ts, analytics.ts, api.ts, api-explorer-docs.ts
- bookshelf.ts, collection-rules.ts, collections.ts, conflicts.ts
- device-management.ts, docs.ts, header.ts, index.ts
- library.ts, linking.ts, login.ts, password_validation.ts
- profile-modal.ts, profile.ts, queue.ts, register.ts
- search.ts, theme.ts, toast-error.ts, toast.ts, unlinked_books.ts
Before: Alpine.data("name", { method1, method2 })
After: Alpine.data("name", () => ({ method1, method2 }))
This is a critical fix for Alpine.js v3+ where components must be
registered as factory functions to ensure proper reactivity and
prevent binding errors during initialization.
- Move WebSocket connection logic from collections.ts to collections.templ template
- Inject JWT token directly into WebSocket URL from server-side User.Token
- Remove createWebSocket import, ws variable, and connectWebSocket() function
- Remove unused CollectionUpdateMessage interface
- Embed complete WebSocket message handling in template script tag
Changes to collections.templ:
- Add inline <script> with WebSocket connection using server-injected token
- Implement collection_updated message handler with toast notifications
- Include 5-second auto-reconnection on disconnect
- Add user activity detection to skip auto-reload when actively typing
- Initialize collectionId and libraryId from data attributes
Changes to collections.ts:
- Remove createWebSocket import
- Remove ws variable declaration
- Remove connectWebSocket() function and CollectionUpdateMessage interface
- Keep all other collection functionality (CRUD operations, modals, search, etc.)
This refactoring eliminates client-side localStorage dependencies for
WebSocket authentication, making the collections page consistent with the
SSR architecture. The token is now injected server-side on every page
load, ensuring WebSocket connections always work when the user is
authenticated via HttpOnly cookie. Auto-reconnection and smart reload
behavior is preserved for optimal UX.
- Move WebSocket connection logic from admin.ts to admin.templ template
- Inject JWT token directly into WebSocket URL from server-side User.Token
- Remove createWebSocket import and related functions from admin.ts
- Embed complete WebSocket message handling in template script tag
Changes to admin.templ:
- Add inline <script> with WebSocket connection using server-injected token
- Implement scan_progress, scan_complete, and scan_error message handlers
- Include error handling for WebSocket failures
Changes to admin.ts:
- Remove createWebSocket import
- Remove connectWebSocket(), updateScanProgress(), showScanComplete(), showScanError() functions
- Keep stopScanStatusPolling() for Alpine.js integration
- Preserve all other admin functionality (scan triggering, stats loading, etc.)
This refactoring eliminates client-side localStorage dependencies for
WebSocket authentication, making the admin page consistent with the
SSR architecture. The token is now injected server-side on every page
load, ensuring WebSocket connections always work when the user is
authenticated via HttpOnly cookie.
- Update WebSocket connection URL in admin.ts to use new /ws/sync endpoint
- Update API documentation in bruno collection to reflect new WebSocket route
- Standardizes WebSocket routing under /ws/ path prefix for better API organization
This change improves API structure consistency and makes WebSocket endpoints
more discoverable and manageable under a dedicated path hierarchy.
Generated files updated to reflect:
- New admin_settings.templ template
- Updated admin_sidebar.templ with Settings link
- Fixed devices.templ with correct regenerate-token path
- Compiled TailwindCSS with any style changes
Phase 3: Complete device page functionality fixes
- Add copyToClipboard function to device-management.ts:
- Uses navigator.clipboard.writeText() for copying
- Shows success/error toast notifications
- Already exported in Alpine.store, now properly defined
- Fix typo in devices.templ: change 'regerate-token' to 'regenerate-token'
- Add HTMX support to RegenerateDeviceToken handler:
- Returns HTML with reload script for HTMX requests
- Preserves JSON response for API calls
The regenerate token button now works via HTMX (hx-put) instead of
Alpine.js, matching the pattern used elsewhere in the app.
Add comprehensive migration documentation for transitioning from the invalid
Alpine.global() API to the correct Alpine.store() API.
This guide addresses:
- Critical issue: Alpine.global() does not exist in Alpine.js v3.15.8
- 26 TypeScript files requiring updates
- Step-by-step migration instructions
- Template syntax changes (namespace.function() → $store.namespace.function())
- Testing checklist and troubleshooting guide
The migration will fix the "p.global is not a function" error currently
breaking the theme switcher and all Alpine namespaces.
Part 1 of 2 - covers TypeScript and template file updates.
This commit reorganizes the Alpine.js initialization process to ensure all
component modules are registered before Alpine starts, preventing potential
race conditions and improving code organization.
Changes:
- Add web/src/register-alpine.ts: Central module that imports all Alpine
component modules before calling Alpine.start(), ensuring proper
registration order
- Update web/src/alpine.ts: Remove Alpine.start() call since it's now
handled in register-alpine.ts
- Update web/src/main.ts: Replace individual module imports with single
register-alpine import, simplifying the entry point
- Update web/src/header.ts: Rename changeThemeTo function to changeTheme
for consistency with other naming conventions
This change ensures all Alpine.global() calls complete before Alpine
initializes, following best practices for Alpine.js module registration.
Migrated header template from hybrid onclick/@click with manual DOM
manipulation to full reactive Alpine.js with state-driven UI.
Template Changes (templates/header.templ):
- Added x-data state container: { themeDropdownOpen, userMenuOpen }
- Replaced @click="toggleThemeDropdown()" with @click="themeDropdownOpen = !themeDropdownOpen"
- Replaced id/class="hidden" with x-show directives
- Added @click.outside for click-outside-to-close behavior
- Added x-transition for smooth dropdown animations
- Added inline style="display: none;" to prevent FOUC
- Updated theme buttons to use header.changeThemeTo() namespace
- Updated wood paneling buttons to use woodPaneling.change() namespace
- Updated logout to use header.logout() namespace
- Close dropdowns after action: themeDropdownOpen = false
TypeScript Changes (web/src/header.ts):
- Removed toggleThemeDropdown() function (lines 7-18) - no longer needed
- Removed toggleUserMenu() function (lines 20-31) - no longer needed
- Removed manual DOM manipulation from changeThemeTo() (lines 50-54)
- Removed click-outside event listener (lines 64-88) - Alpine handles this
- Updated export to remove deleted functions
- Updated Alpine.global() registration to remove toggle functions
- Result: header.ts reduced from 100 lines to 40 lines (60% reduction)
TypeScript Changes (web/src/woodPaneling.ts):
- Added Alpine import
- Removed manual DOM manipulation from changeWoodPaneling()
- Added Alpine.global("woodPaneling", { change: changeWoodPaneling })
TypeScript Changes (web/src/themeDropdown.ts):
- Removed import of deleted toggleThemeDropdown function
- Removed initializeThemeDropdown() wrapper function
- Removed initializeChangeThemeTo() wrapper function
- Simplified updateThemeIndicators() to focus on wood paneling
- Updated Alpine.global("themeDropdown") registration
Benefits:
- Eliminates 23 manual DOM manipulations from header
- Smooth transitions with x-transition
- Click-outside behavior built-in with @click.outside
- State is local and encapsulated in template
- Cleaner separation of concerns (UI state in template, business logic in TS)
- Easier debugging with Alpine DevTools
Testing:
- Theme dropdown opens with smooth transition
- Theme dropdown closes when clicking outside
- Theme changes correctly when option clicked
- User menu opens with smooth transition
- User menu closes when clicking outside
- Logout works correctly
- Wood paneling changes work
- Both dropdowns show mutual exclusion behavior
Build Verification:
- templ generate: ✓ Success
- npm run build:ts: ✓ Success (167.8kb minified)
This is the reference implementation for Phase 1 of the Alpine.js
integration completion guide. All other modal templates should
follow this same pattern.
Related: ALPINE_COMPLETION_GUIDE.md Phase 1
Related: ESBUILD_MIGRATION_PLAN.md Phase 3, Template Migration
- Import showToast function directly from toast module
- Remove dependency on window global for error handling
- Simplify code and improve type safety
This change aligns with the ESBuild migration by using proper ES module
imports instead of runtime global lookups.
- Update header.templ to load single main.js script instead of 4 separate files
- Remove obsolete header.js and search.js as they are now bundled
- Update Alpine.js event handlers to use standard double quotes
- This completes the ESBuild migration by eliminating inline script loads
The main.js bundle now contains all header, theme, and search functionality
previously loaded separately, improving load performance and maintainability.
- dashboard.templ: Replaced individual script tags with single main.js import
- admin_users.templ, custom_section.templ: Minor formatting/cleanup
- docs.templ: Updated script imports (excluded from Alpine conversion per user request)
- api.ts, docs.ts, password_validation.ts: Minor updates for compatibility
Added Alpine.global() registration to enable template access to functions:
- admin.ts: Added Alpine for scan, stats, and settings functions
- api-explorer.ts: Already had Alpine (kept as is)
- bookshelf.ts: Added Alpine for library/bookshelf interactions
- collections.ts: Added Alpine for collection management
- conflicts.ts: Added Alpine for conflict resolution
- device-management.ts: Added Alpine with event delegation for dynamic content
- header.ts: Added Alpine for theme dropdown and user menu
- library.ts: Added Alpine registrations
- linking.ts: Added Alpine registrations
- queue.ts: Added Alpine for queue operations
- search.ts: Added Alpine registrations
- themeDropdown.ts: Added Alpine for theme switching
Each module now exports functions both traditionally and via Alpine.global() for template access.
- Modified package.json build:ts to copy htmx.min.js from node_modules to web/static/
- This fixes the 404 error for /static/htmx.min.js that occurred after ESBuild migration
- Added htmx.min.js to static files
See ESBUILD_MIGRATION_PLAN.md for migration context.
Add Alpine.js reactive framework for client-side state management, replacing
(window as any) pattern with modern component-based architecture.
Build configuration changes:
- package.json: Update build scripts to use main.ts as entry point
- Change from web/src/*.ts glob to web/src/main.ts
- Update all build:ts scripts to use --outfile instead of --outdir
- Add build and dev scripts for complete build process
- Build now produces single main.js bundle (~120-150KB minified)
Alpine.js setup:
- web/src/alpine.ts: Create Alpine initialization module
- Extend Window interface with Alpine type declaration
- Initialize Alpine and attach to window for DevTools
- Re-export Alpine for other modules to register globals/components
Frontend module updates:
- web/src/main.ts: Import alpine.ts last to initialize framework
- web/src/toast.ts: Add Alpine import (ready for migration to Alpine.global())
Architecture:
- Alpine.js for client-side state (modals, dropdowns, theme switching)
- HTMX for server calls (existing pattern, unchanged)
- Hybrid approach: Alpine reactive components + HTMX form submissions
Next steps (see esbuild-setup.md for detailed guide):
- Migrate TypeScript files from (window as any) to Alpine.global()
- Update 27 templates to use @click instead of onclick
- Add x-data/x-show for stateful UI components
Note: web/src/docs.ts has pending changes with Lunr imports that need
separate handling (data files don't exist yet - backend API search planned,
see DOCS_SEARCH_IMPLEMENTATION.md)
Update header.js and search.js to reflect the new esbuild build pipeline.
The header.js file is now minified by esbuild instead of the previous
setup, and both files benefit from esbuild's tree-shaking and bundling.
Remove minified JavaScript libraries that were previously downloaded during
postinstall (htmx.min.js, highlight.min.js, lunr.min.js, lunr-flex.min.js).
These are now bundled via esbuild from npm packages.
Update Dockerfile to remove the now-unnecessary postinstall npm script execution,
streamlining the container build process.
Replace the postinstall script that downloaded minified JavaScript libraries
(htmx, highlight.js, lunr) with proper npm package management and bundling
using esbuild. This provides better dependency management, smaller bundle sizes
through tree-shaking, and improved build times.
Changes:
- Add htmx.org, highlight.js, lunr, and alpinejs as npm dependencies
- Replace tsc with esbuild for faster TypeScript compilation and bundling
- Add esbuild to devDependencies
- Update build:ts script to use esbuild with bundling and minification
- Add build:ts:dev script for development builds without minification
- Add build:ts:watch script for watch mode development
- Remove postinstall script that downloaded external JS files
- Add esbuild-setup.md documentation for the new build setup
- Create web/src/main.ts as the new entry point for bundled JavaScript
This modernizes the frontend build pipeline and reduces reliance on external
CDNs during the build process.
- Add WebSocket connection for scan progress updates
- Display live progress bar and file count during scans
- Handle scan_complete and scan_error messages
- Store polling interval in module variable for cleanup
- Expose stopScanStatusPolling function for manual control
Replaces or supplements HTTP polling with push-based updates for
better UX and reduced server load.
This commit adds comprehensive functionality for filtering collections by library,
improves WebSocket real-time updates with user activity detection, and adds
extensive test coverage.
## Core Features
### Collection Library Filter
- Added library_id parameter to media-items search API
- Collections can now be filtered by specific library
- Toggle UI component for enabling/disabling library filter
- Default state is "checked" when library_id is present
- Consistent behavior across partial and fuzzy search modes
### WebSocket Auto-Reload Mitigation
- Added user activity detection to prevent disruptive page reloads
- Checks if user is actively typing in INPUT/TEXTAREA/SELECT elements
- Skips auto-reload when user is interacting with form elements
- Toast notifications still show for awareness
- Prevents data loss during editing operations
## Implementation Changes
### Backend
- internal/database/queries.sql.go: Added library filter support to search queries
- internal/handlers/media.go: Enhanced search with library_id parameter validation
- internal/handlers/collections.go: Updated collection handlers with library filtering
- internal/sync/websocket.go: Improved broadcast mechanism with user-scoped updates
- internal/router/frontend.go: Pass libraryID to collection templates
### Frontend
- templates/collections.templ: Added library filter toggle UI component
- web/src/collections.ts: TypeScript implementation with WebSocket integration
- templates/collections_templ.go: Generated template code
### Testing
- cmd/server/tests/search_test.go: Added TestCollectionSearchLibraryFilter
- cmd/server/tests/websocket_test.go: Added TestWebSocketUserScopedBroadcast
- New helper functions for creating libraries and media items via API
- Comprehensive test coverage for library filtering and user-scoped broadcasts
## API Documentation Updates
### Bruno Tests (Comprehensive Documentation)
- bruno/collections/*: Added detailed API documentation for all collection endpoints
- bruno/devices/*: Added device management and sync API documentation
- bruno/devices/kobo/api.yml: Kobo-specific sync protocol docs
- bruno/devices/koreader/api.yml: KOReader-specific sync protocol docs
- bruno/opds/*: Added OPDS feed and download endpoint documentation
- bruno/library/browse-folders.yml: Library folder browsing API docs
### New Bruno Tests
- bruno/media-items/Search All Libraries.yml: Test search without library filter
- bruno/media-items/Search Specific Library.yml: Test search with library filter
- bruno/media-items/Search Invalid Library ID.yml: Test error handling
## Documentation
- docs/developer/api/media-items/search_media_items.md: Updated with library_id parameter
- IMPLEMENTATION_COLLECTION_FIX.md: Comprehensive implementation guide with test scenarios
## Testing
### Integration Tests
- Library filter tests verify correct filtering across multiple libraries
- Invalid library_id tests ensure proper error handling
- WebSocket tests verify user-scoped broadcast behavior
- User A no longer receives User B's collection updates
### Manual Testing Scenarios
- Open collection in multiple tabs - updates propagate correctly
- Type in search box while another tab adds books - no disruptive reload
- Add/remove books from collection - toast notifications appear
- Toggle library filter - results update dynamically
## Technical Details
- WebSocket broadcasts are now user-scoped for privacy
- Active element detection uses tagName and contenteditable attributes
- Library ID validation uses UUID format checking
- Progressive enhancement maintained - page works without JavaScript
- All changes follow PROJECT_GUIDELINES.md conventions
- TypeScript only for frontend logic
- TailwindCSS only for styling
- Procedural programming style throughout
## Breaking Changes
None - all changes are additive and backward compatible.
Add comprehensive TypeScript utilities for collections page functionality.
1. HTMX Authentication (setupHTMXAuth):
- Adds Authorization header to all HTMX requests automatically
- Listens for htmx:configRequest event on document.body
- Injects Bearer token from localStorage
- Eliminates need for hx-headers attributes on individual elements
2. Smart Card Navigation (navigateToCollection):
- Implements event delegation to distinguish button clicks from card clicks
- Checks event.target to determine what user clicked
- Returns early if button clicked (lets HTMX handle button actions)
- Navigates to collection detail page only when card body clicked
- Uses data-href attribute for navigation target
3. Color Selection Helpers:
- selectColor(): Updates hidden input and visual selection state
- closeCollectionModal(): Removes modal from DOM after HTMX swap
- initColorSelection(): Applies border color classes to collection cards
using borderClasses mapping (blue→border-blue-500, etc.)
4. Icon Picker with Search:
- Hardcoded iconData object: 30 emojis with searchable keywords
(e.g., "📚": ["book", "books", "library", "read", "reading"])
- populateIconGrid(): Dynamically generates icon buttons from iconData
- selectIcon(): Updates hidden input with selected emoji
- filterIcons(): Real-time search filtering by emoji OR keywords
- showAllIcons(): Clears search filter
- initIconSelection(): Auto-initializes after HTMX modal swap
(listens for htmx:afterSwap event on #modal-container)
5. HTMX Modal Initialization:
- setupHTMXModalInit(): Listens for modal loads via HTMX
- Auto-initializes icon picker when modal content swapped into
#modal-container
All functions exported to window object for onclick attribute access.
Auto-initializes on DOMContentLoaded or immediately if DOM ready.
Pattern consistency:
- Follows same pattern as toast.js (global exports, auto-init)
- Uses TypeScript type annotations
- No OOP (functional style per project guidelines)
- Server-side rendering with HTMX (no AJAX data fetching)
- Update wood-light border from harsh black (#2a2a2a) to lighter warm brown (#8b5a2b) for better harmony with light background
- Update wood-dark border from #5c3317 to #7a5228 (slightly lighter medium brown) for improved visibility on dark backgrounds
- Update wood-mahogany border from #5c3317 to #8b3a3a (medium red-brown) to enhance mahogany's characteristic reddish tones
- Reduce background blend opacity from 60% to 40% to create more subtle text area background that complements new border colors
These changes improve visual consistency between border colors and their respective wood paneling backgrounds while maintaining good text contrast across all wood themes.
Add default library ID functionality to improve library targeting
during media scans.
Service changes in internal/services/media_scanner.go:
- Add defaultLibraryID field to MediaScanner struct
- Add SetLibraryID() method to set default library
- Modify processMediaFile() to use defaultLibraryID when set
- Prioritizes defaultLibraryID over folder-based library detection
- Provides explicit library targeting for scans
Service changes in internal/services/worker.go:
- Add libraryUUID conversion from string to pgtype.UUID
- Call scanner.SetLibraryID() before ScanFolders()
- Ensures scanner respects the job's library ID
These changes enable more precise library targeting during media scans,
allowing scans to be directed to specific libraries rather than relying
solely on folder-based detection.
Fix multiple issues with wood paneling background image display
affecting overscroll area and page-specific rendering.
CSS changes in web/static/input.css:
- Add background-attachment: fixed to all wood paneling classes
- Prevents wood paneling from moving during page scroll
- Ensures wood paneling extends into overscroll area
- Applied to bg-wood-dark, bg-wood-light, bg-wood-mahogany
- Fix body and container selectors for wood paneling
- Ensure proper selector targeting for wood paneling application
- Use background-position: center for better alignment
- Use background-size: cover for full coverage
TypeScript changes in web/src/woodPanelingInit.ts:
- Add page detection to prevent wood paneling on collections page
- Check if #collections-container exists in DOM
- Only apply wood paneling on dashboard, not collections page
- Prevents ID collision between dashboard and collections containers
Template changes in templates/header.templ:
- No functional changes, only reformatting
These fixes ensure that:
1. Wood paneling displays consistently across the entire viewport
2. Wood paneling extends into the overscroll area when scrolling past content
3. Wood paneling is properly aligned and centered
4. Wood paneling doesn't interfere with collections page rendering
5. Both dashboard and collections pages can coexist without visual conflicts
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 updates third-party static library files:
- highlight.min.js: Updated to latest version (syntax highlighting)
- highlight-dark.min.css: Dark theme for syntax highlighting
- htmx.min.js: Updated to latest version (HTMX library for AJAX)
- lunr.min.js: Updated to latest version (full-text search)
- input.css: Updated Tailwind CSS input styles
- style.css: Updated main application styles
These are third-party library updates that provide improved
functionality and bug fixes for the frontend.
- Convert indentation from 4 spaces to 2 spaces (matching project style)
- Standardize quotes to double quotes for consistency
- Reformat template literals for improved readability
This file contains the core bookshelf functionality including:
- Library selection and persistence
- Book rendering with cover images
- Pagination for large book collections
- Send force: true in scan API request body
- Rename 'Scan Library' button to 'Rescan Library'
- Replace Settings card with Watch Status display
- Add loadWatchStatus() to fetch and display watch mode status
- Remove inline script from admin.templ (moved to admin.ts)
Features:
- Complete dashboard redesign with improved UI components and layout
- Implement custom section builder for personalized book organization
- Add new events tracking system for user interactions
- Enhance search functionality with better static search.js
- Update TypeScript type definitions for API responses
Backend:
- Update Go dependencies in go.mod
- Add new frontend routes in router
Templates:
- Update admin and dashboard templates with new components
Frontend:
- Refactor analytics, collections, conflicts, and queue modules
- Add new documentation features in docs.ts
- Implement linking between books and collections
- Add toast notifications for user feedback
- Include placeholder book SVG asset
This commit consolidates multiple feature additions and improvements
across the entire stack including backend, templates, and frontend.
Fix text color display issues on wood gradient backgrounds in the
dashboard's collections container, ensuring small text matches big text
and "View All" links stand out with proper wood-specific colors.
Changes:
- Remove .text-sm from grey text rule to match big text colors
- Keep .text-secondary as only grey text class
- Links maintain wood-specific standout colors via specific selectors
Problem:
- Small text (.text-sm) was forced to grey (--wood-text-secondary)
- "View All" links inherited grey instead of wood link colors
- Inconsistent text sizing created visual hierarchy issues
Root Cause:
input.css:243-247 applied --wood-text-secondary to .text-sm
This overrode wood-specific link colors at lines 250-257
Solution:
Remove .text-sm and p.text-sm from the grey text rule:
- Before: .text-sm, .text-secondary, p.text-sm → grey
- After: .text-secondary only → grey
- .text-sm now uses --wood-text-primary (matches big text)
- Links (including "View All") use wood-specific blue colors
Impact:
- All small text now matches big text color on wood backgrounds
- "View All" links stand out with proper colors (#0066cc for light wood, #66ccff for dark)
- Improved readability and visual consistency
- Better user experience on wood gradient themes
Wood Theme Colors:
- Wood Light: #0066cc (dark blue for contrast on light background)
- Wood Dark: #66ccff (light blue for visibility on dark background)
- Wood Mahogany: #66ccff (light blue for visibility on dark background)
Files: web/static/input.css
Lines Modified: 243-247 (removed selectors)
Related: templates/dashboard.templ:100 (View All link)
- Fix View All link flashing by preserving data-wood attribute when dashboard re-renders
- Update wood-dark text color to match wood-mahogany (#f5f5f5) for better consistency
- Add smart link colors for wood paneling (#0066cc for light wood, #66ccff for dark woods)
- Fix carousel arrow gradients to be less harsh on wood backgrounds (0.6 for light, 0.3 for dark)
- Remove accent color preservation rule that was conflicting with wood-specific link colors
- Add data-wood attribute to collections container for CSS targeting
- Update woodPaneling.ts and woodPanelingInit.ts to set/remove attribute
- Add CSS variables for wood-specific text colors (dark text on light wood, light text on dark wood)
- Add !important rules to override theme colors when wood is active
- Replace wood-dark and wood-mahogany textures with darker variants
- Add subtle borders to book cards on wood backgrounds
- Fix library edit form to use type_name instead of library_type_id for type dropdown
- Clear library-id input after successful delete to prevent create-then-delete bug
- This fixes the issue where creating a new library after deleting one would fail with 'Unknown error' due to stale library-id