Commit Graph
16 Commits
Author SHA1 Message Date
john-okeefe 006cc0c2c9 chore(frontend): slim admin.ts, remove dead library.ts
- Remove dead functions from admin.ts: loadSystemStats, renderSystemStats,
  triggerLibraryScan, triggerQuickScan, all WebSocket functions
- Remove library.ts (695 lines of innerHTML string-building replaced by
  HTMX server-rendered partials)
- Remove library import from main.ts
2026-08-07 09:35:47 -04:00
john-okeefe f75d68bf66 feat(ui): add first-run setup wizard with 4 guided steps
Add a single-page multi-step setup wizard that guides new users
through initial configuration:

Step 1 - Admin Registration: Creates the first user (auto-admin)
  using the existing POST /api/auth/register endpoint, with
  real-time password validation and confirmation matching.

Step 2 - Library Creation: Create one or more libraries (Ebooks,
  Audiobooks, Comics, Manga) using POST /api/libraries. Libraries
  list updates inline as they're added.

Step 3 - Folder Configuration: Add filesystem folders to each
  library using the existing GET /api/libraries/browse endpoint for
  a visual directory browser. Folders are attached via POST
  /api/libraries/:id/folders.

Step 4 - Initial Scan: Triggers a manual scan of all libraries via
  POST /api/libraries/scan with real-time progress polling using the
  existing scan status endpoint.

On completion, the wizard calls PUT /api/setup/complete and sets the
selectedLibrary cookie to the first library's UUID, ensuring the
dashboard loads with populated content instead of an empty 'All
Libraries' view. Handles the edge case where a stale JWT from a
previous database instance triggers an 'already exists' error by
auto-advancing to step 2.

The wizard reuses all existing API calls, Alpine.js utilities, and
form validation functions — no backend logic was duplicated.
2026-06-06 00:04:09 -04:00
john-okeefe a2fc2613b4 feat(library-switcher): add shared library switcher component and module
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
2026-05-17 21:11:47 -04:00
john-okeefe c5cda015b3 feat(series): add AJAX library switching and stacked-cascade CSS
Create web/src/series.ts with Alpine component implementing the same
switchLibrary pattern as the dashboard:
- Fetch /api/series on library change instead of full page reload
- Fade out/in transition with loading spinner
- Re-render series grid and pagination from JSON response
- Save selected library to localStorage

Import series.ts in main.ts.

Add stacked-cascade CSS to input.css for multi-cover series cards:
- Covers cascade from top-left to bottom-right with increasing z-index
- Front cover sits at bottom-right (highest z-index)
- Separate layout rules for 1-7 covers with rotation offsets
- Hover lift effect on series cards
2026-05-08 20:27:27 -04:00
john-okeefe 99d6c9a5d1 build: configure multi-entry Vite build for reader
- Add reader.ts as second entry point alongside main.ts in vite.config.ts
- Set assetsDir to empty string to output chunks to /static/ root
- Remove reader-shell import from main.ts (loaded separately via reader.js)
- Update .gitignore to exclude web/static/assets/*.js chunks
- Update Bruno environment with new test IDs
2026-04-04 18:17:03 -04:00
john-okeefe 13347a9eed feat(reader): add reader module to main bundle
- Import reader/reader-shell to load reader functionality
- Ensures reader JavaScript is included in main.js bundle
- Reader features and Alpine components are now initialized
2026-04-04 13:38:19 -04:00
john-okeefe eb349cbc95 feat: add book detail page with comprehensive metadata display
Implement SSR-first book detail page at /media/:uuid with complete
book information, progress tracking, and interactivity.

Features:
- Cover image (256x384px) with responsive layout
- Complete metadata: title, author, description, publisher, ISBN,
  language, edition, page count, genre, copyright year, format
- External service links (Goodreads, Open Library, Google Books, Amazon)
  with smart URL fallback: ID → ISBN → Title+Author
- Reading progress display with device sources (web/kobo/koreader)
- Sync progress modal for conflict resolution
- Collections display as clickable badges
- Notes/highlights counter with placeholder modal
- Rating display (1-10 scale with star rendering)
- HTML sanitization for book descriptions using bluemonday

Data Structure:
- handlers.MediaDetail embeds database.MediaItems for zero duplication
- Uses existing database queries (GetMediaItem, GetMediaRating, etc.)
- Follows project pattern: no parallel type systems

Frontend:
- TypeScript modal triggers (book-detail.ts)
- Alpine.js for modal interactions
- TailwindCSS styling with theme variables
- Responsive: cover-left layout, mobile stacks vertically

Backend:
- Route: GET /media/:uuid (protected)
- Handler: inline function in frontend.go following existing pattern
- Template: SSR-first with progressive enhancement
- Returns HTML only (API uses separate /api/media-items/:id endpoint)

Files created:
- internal/handlers/media_detail.go
- templates/book_detail.templ
- templates/book_detail_modals.templ
- web/src/book-detail.ts

Files modified:
- internal/router/frontend.go (add route)
- web/src/main.ts (import module)
2026-03-28 23:54:39 -04:00
john-okeefe e74eeb5c5b feat: implement collections book picker with Alpine.store
Add multi-select book picker modal for collections using Alpine.js patterns:
- Alpine.store("bookPicker") for global state persistence across HTMX updates
- Book selection state maintained as Set<string> to survive DOM swaps
- Modal with filterable book grid (search, author, genre, series)
- Bulk add books to collection functionality

Templates:
- collections.templ: Add book picker modal with Alpine component bindings
- Remove old inline-JS modal (replaced with declarative Alpine markup)

TypeScript:
- web/src/bookPicker.ts: New module with Alpine.store and Alpine.data definitions
- web/src/main.ts: Import bookPicker module
- web/src/collections.ts: Remove old modal functions (replaced by Alpine)

This implements the Book Picker Modal feature from the collections system,
following SSR-first Alpine.js patterns with HTMX for dynamic updates.

Fixes "Add Books" button being disabled - modal now fully functional.
2026-03-20 22:58:09 -04:00
john-okeefe 17fd86aad3 refactor: update main.ts imports for page-specific bookshelf loading
Change from global to page-specific JavaScript loading:

Remove:
- import "./bookshelf" (loaded globally on every page)

Add:
- import "./bookPicker" (needed globally for collections)

This change supports page-specific script loading strategy:
- Bookshelf: Loaded via <script> tag in bookshelf.templ only
- BookPicker: Loaded globally for collections page usage

Reduces JavaScript bundle size for pages that don't need bookshelf.
Matches SSR-first principle of progressive enhancement.
2026-03-20 11:51:11 -04:00
john-okeefe 533f8747e3 perf(templates): add defer attribute to main.js script tags across all pages
- 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
2026-03-12 15:44:15 -04:00
john-okeefe 5faf562250 Fix Path A: Resolve function mismatches and missing functions
Fixed template function call mismatches:
- conflicts.templ: Renamed showConflictModal→showResolveModal, hideConflictModal→hideResolveModal, handleResolveConflict→handleResolveSubmit
- collections.templ: Fixed case mismatch addSelectedBooks→addbooksToAdd
- queue.templ: Removed dead /static/queue.js reference
- progress.templ: Removed vestigial x-data="progress" attribute

Added missing queue functions:
- showQueueItemModal() - Shows queue item detail modal
- hideQueueItemModal() - Hides queue item modal
- filterQueue() - Filters queue by status (stubbed)

Fixed build errors:
- main.ts: Removed imports for deleted themeDropdown.ts and woodPaneling.ts files

All fixes are minimal and conservative. No breaking changes to existing functionality.
TypeScript builds successfully (168KB main.js).
Templates regenerate successfully.
2026-03-11 11:04:53 -04:00
john-okeefe 0a5042e130 docs: add Alpine.js migration guide for global() → store() API
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.
2026-03-09 21:23:07 -04:00
john-okeefe 33cf00f65c refactor: Consolidate Alpine.js initialization and module loading
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.
2026-03-09 20:58:40 -04:00
john-okeefe 533dfd64e2 refactor: Update main.ts imports and add TypeScript types
- main.ts: Added imports for all new Alpine component files:
  * admin, api-explorer-docs, login, profile, profile-modal,
  * register, toast-error, unlinked_books, index, collection-rules
- api.d.ts: Added match_reason field to TestRuleMatch interface
  for collection rules test results display
2026-03-08 21:36:32 -04:00
john-okeefe e45b893eb3 feat: add Alpine.js framework and update build configuration
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)
2026-03-06 22:27:18 -05:00
john-okeefe 8e48de5607 refactor(frontend): migrate from downloaded JS bundles to npm packages with esbuild
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.
2026-03-06 20:18:01 -05:00