Since main.js has 'defer' attribute, the DOM is guaranteed to be
ready when modules execute. These wrappers are unnecessary.
dashboard.ts:
- Removed DOMContentLoaded wrapper, code runs directly
- Event delegation setup runs immediately
custom-section-builder.ts:
- Removed DOMContentLoaded wrapper
- initCustomSectionBuilder() called directly
toast.ts:
- Removed DOMContentLoaded wrapper
- initializeToastSystem() called directly at top level
- Removed dead Alpine.data registration (unused)
search.ts:
- Removed DOMContentLoaded wrapper
- initializeSearch exported for use in header
theme.ts:
- Removed DOMContentLoaded wrapper
- Functions now exported for use in header Alpine component
- 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.
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)
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.
- Update fetch interceptor to special-case 401 responses
- Clear invalid tokens from localStorage on 401 (token, refreshToken, user)
- Distinguish between page navigation and API calls:
- Page navigation: throw error to prevent further processing
- API calls: show toast error with session expired message
- Suppress network error toast for redirect errors
- Compile TypeScript to JavaScript
This ensures frontend properly handles expired sessions by clearing
stale credentials and showing appropriate error messages.
- Change from htmx:beforeSwap to htmx:afterSwap event for better error timing
- Simplify event listener setup (removed duplicate handlers)
- Remove 'export {}' statement that was causing syntax errors
- Add proper TypeScript interface for HTMX event details
- Errors now detected after content swap, ensuring accurate error messages
- Toast notifications work correctly for all backend HTTP errors
Resolves JavaScript syntax error on page load and improves error handling.
- Create web/src/ for TypeScript source files
- Create web/static/ for compiled assets and runtime files
- Move input.css and style.css to web/static/
- Add toast.ts - Functional toast notification system
- Add theme.ts - Functional theme management system
- All code uses functional programming (no classes, no OOP)
- TypeScript provides full type safety
Separates frontend code from backend for better organization.