+
+
+
+ ...11 more themes...
+
+
+
+
+
+```
+
+### Testing Strategy for Each Template
+
+After migrating each template:
+
+1. **Build**: `npm run build:ts && templ generate`
+2. **Run**: `go run .`
+3. **Test**: Visit the page, test all interactions:
+ - All buttons work
+ - Modals open/close
+ - Dropdowns work
+ - Forms submit (via HTMX)
+ - Toast notifications appear
+ - No console errors
+4. **Verify**: Check Alpine DevTools (if installed) for reactive state
+
+### Rollback Strategy
+
+If a migrated template has issues:
+
+```bash
+# Revert the template file
+git checkout templates/PROBLEM_TEMPLATE.templ
+
+# Rebuild
+templ generate
+go run .
+```
+
+The template is now using old onclick handlers, but the bundle still has the functions registered. Everything works.
+
+---
+
+## Phase 4: Data Injection (Server → Client)
+
+**Goal**: Ensure server-to-client data flow works correctly without window globals.
+
+**Files**: docs.templ, any future templates that need data injection
+
+**Duration**: 1-2 hours
+
+### Current Situation
+
+**docs.templ** currently loads data via fetch (correct approach):
+```javascript
+// In template inline JS (lines 228-285)
+fetch('/docs/search-index.json')
+ .then(r => r.json())
+ .then(data => { searchDocs = data; })
+```
+
+**Go handler provides**:
+```go
+// internal/docs/http_handler.go line 417
+func (h *HTTPHandler) ServeSearchIndex(c *echo.Context) error {
+ index, err := h.docs.GenerateSearchIndex();
+ return c.JSON(http.StatusOK, index)
+}
+```
+
+### Migration Strategy
+
+Keep this pattern! It's already correct:
+
+1. **Server provides JSON endpoints** for data
+2. **Client fetches data** via APIs
+3. **No window globals** needed
+
+### Future Templates (Dashboard Pattern)
+
+For new pages that follow the dashboard pattern:
+
+1. **Server renders HTML** with initial data (SSR)
+2. **Client fetches updates** via API when needed
+3. **No data injection into window**
+
+Example:
+```go
+// Go handler
+func (h *Handler) ShowDashboard(c *echo.Context) error {
+ // Fetch data from database
+ collections := h.queries.GetCollections(c.request().Context())
+
+ // Render template with data
+ return templates.Dashboard(collections).Render(c)
+}
+```
+
+```typescript
+// Client-side (if needed)
+import { apiGet, apiPost, apiPut, apiDelete, apiPatch, handleResponse, handleVoidResponse, handleError } from "./api";
+
+async function refreshCollections() {
+ const response = await apiGet("/collections");
+ const data = await handleResponse(response);
+ // Update DOM
+}
+```
+
+---
+
+## Phase 5: Cleanup
+
+**Goal**: Remove all legacy code and old .js files.
+
+**Duration**: 1-2 hours
+
+### Step 5.1: Remove Individual .js Files
+
+After all 27 templates are migrated and verified working:
+
+```bash
+cd /home/nymusicman/Code/bookhoard/web/static
+
+# Remove old individual JS files
+rm -f api.js toast.js events.js dom.js storage.js
+rm -f theme.js header.js themeDropdown.js woodPaneling.js
+rm -f search.js docs.js collections.js conflicts.js
+rm -f dashboard.js admin.js admin_library.js admin_users.js
+rm -f analytics.js bookshelf.js devices.js
+rm -f index.js login.js profile.js
+rm -f queue.js custom_section.js progress.js
+rm -f register.js settings.js stats.js sync.js
+rm -f testing_templ.js obsidian.js whatsapp.js midnight.js sunset.js
+rm -f password_validation.js api_explorer.js
+
+# Keep only:
+# - main.js (bundled)
+# - main.js.map (sourcemap)
+# - htmx.min.js (separate load)
+# - highlight.min.js (for docs)
+# - style.css (Tailwind)
+```
+
+### Step 5.2: Remove All Window Exports
+
+From all TypeScript files, remove any remaining `(window as any)` exports:
+
+```bash
+# Search for remaining window exports
+cd /home/nymusicman/Code/bookhoard/web/src
+grep -rn "window as any" *.ts
+```
+
+Should only find:
+- Type assertions being removed
+- Comments referencing old pattern
+
+Remove all:
+```typescript
+// DELETE these lines:
+(window as any).functionName = functionName;
+```
+
+### Step 5.3: Update Build Scripts
+
+Verify package.json scripts are correct:
+
+```json
+{
+ "scripts": {
+ "build:css": "tailwindcss -i ./web/static/input.css -o ./web/static/style.css --watch",
+ "build:css:prod": "tailwindcss -i ./web/static/input.css -o ./web/static/style.css --minify",
+ "build:ts": "esbuild web/src/main.ts --bundle --outfile=web/static/main.js --sourcemap --target=es2020 --minify",
+ "build:ts:dev": "esbuild web/src/main.ts --bundle --outfile=web/static/main.js --sourcemap --target=es2020",
+ "build:ts:watch": "esbuild web/src/main.ts --bundle --outfile=web/static/main.js --sourcemap --target=es2020 --watch",
+ "build": "npm run build:ts && npm run build:css:prod",
+ "dev": "npm run build:ts:dev && templ generate && go run ."
+ }
+}
+```
+
+### Step 5.4: Final Verification
+
+```bash
+# Complete build
+npm run build
+templ generate
+go build
+
+# Check bundle size
+ls -lh web/static/main.js
+# Expected: ~120-150KB
+
+# Run tests (if any)
+go test ./...
+
+# Manual testing
+go run .
+# Test all pages, verify functionality
+```
+
+### Step 5.5: Update Documentation
+
+Update or remove any references to old build process in documentation.
+
+---
+
+## Success Criteria
+
+### Phase 0 Completion
+✅ All utility modules have ES exports
+✅ Build succeeds
+✅ No functionality broken
+
+### Phase 1 Completion
+✅ All 193+ internal window reads converted to imports
+✅ All consumer files use ES module imports
+✅ Function wrapping eliminated (themeDropdown.ts restructured)
+✅ Build succeeds
+✅ All pages still work
+
+### Phase 2 Completion
+✅ All template functions registered with Alpine
+✅ Old window exports removed
+✅ Build succeeds
+✅ Alpine loaded and functional
+✅ All pages still work (onclick still works)
+
+### Phase 3 Completion
+✅ All 27 templates migrated to @click
+✅ All individual script tags replaced with single main.js
+✅ Inline JS migrated to TypeScript where appropriate
+✅ All onclick handlers converted to @click
+✅ All UI state uses x-data/x-show
+✅ All templates tested and working
+
+### Phase 4 Completion
+✅ Server data injection uses API endpoints (not window)
+✅ Docs search still works
+✅ Future pages follow SSR-first pattern
+
+### Phase 5 Completion
+✅ All old .js files removed
+✅ No window globals remain
+✅ Only main.js and main.js.map exist
+✅ Bundle size ~120-150KB minified
+✅ Clean codebase ready for launch
+
+---
+
+## Estimated Effort
+
+| Phase | Duration | Risk | Can Ship After |
+|-------|----------|------|----------------|
+| Phase 0 | 1-2 hours | Low | ✅ Yes |
+| Phase 1 | 4-6 hours | Medium | ✅ Yes |
+| Phase 2 | 2-3 hours | Low | ✅ Yes |
+| Phase 3 | 27-54 hours | Medium-High | ✅ Yes (per template) |
+| Phase 4 | 1-2 hours | Low | ✅ Yes |
+| Phase 5 | 1-2 hours | Low | ❌ No (final cleanup) |
+| **Total** | **36-69 hours** | | |
+
+**Recommended Schedule**:
+- Week 1: Phases 0-2 (Foundation) - 7-11 hours
+- Week 2-4: Phase 3 (Templates) - 5-10 templates per week
+- Week 5: Phases 4-5 (Finalize) - 2-4 hours
+
+---
+
+## Rollback Procedures
+
+### If Phase 0 or Phase 1 Fails
+
+```bash
+# Revert TypeScript changes
+git checkout web/src/
+
+# Rebuild
+npm run build:ts
+go run .
+```
+
+### If Phase 2 Fails
+
+```bash
+# Revert to Phase 1 state (window exports still present)
+git checkout web/src/
+
+# Rebuild
+npm run build:ts
+go run .
+```
+
+### If Phase 3 (Template Migration) Fails
+
+```bash
+# Revert specific problematic template
+git checkout templates/PROBLEM_TEMPLATE.templ
+
+# Regenerate templates
+templ generate
+
+# Rebuild
+go run .
+```
+
+All other migrated templates continue working.
+
+---
+
+## Testing Checklist
+
+### After Each Phase
+
+- [ ] Build succeeds (`npm run build:ts`)
+- [ ] Go build succeeds (`go build`)
+- [ ] Application starts (`go run .`)
+- [ ] Homepage loads
+- [ ] Login works
+- [ ] Dashboard loads
+- [ ] No console errors
+- [ ] Network tab shows no 404s for .js files
+
+### After Phase 1 (Internal Dependencies)
+
+- [ ] Dashboard works
+- [ ] Library management works
+- [ ] Collections work
+- [ ] Admin functions work
+- [ ] Queue works
+- [ ] Conflicts work
+- [ ] All toast notifications work
+- [ ] All API calls work
+
+### After Phase 3 (Each Template)
+
+- [ ] Page loads
+- [ ] All buttons work
+- [ ] Modals open/close
+- [ ] Dropdowns work
+- [ ] Forms submit via HTMX
+- [ ] Toast notifications appear
+- [ ] No console errors
+- [ ] Alpine DevTools shows reactive state (if installed)
+
+---
+
+## Files Modified Summary
+
+### New Files Created
+- None (alpine.ts already exists)
+
+### Source Files Modified (21 files)
+- web/src/main.ts (verify imports are correct)
+- web/src/alpine.ts (verify initialization is correct)
+- web/src/api.ts (add ES exports, Alpine already present)
+- web/src/toast.ts (add ES exports, Alpine already present)
+- web/src/storage.ts (already has exports ✅)
+- web/src/events.ts (add ES exports and Alpine)
+- web/src/dom.ts (already has exports ✅)
+- web/src/theme.ts (add ES exports and Alpine)
+- web/src/header.ts (add ES exports and Alpine, restructure)
+- web/src/woodPaneling.ts (add ES exports and Alpine)
+- web/src/themeDropdown.ts (RESTRUCTURE to eliminate wrapping)
+- web/src/library.ts (convert 55 window reads to imports, add Alpine)
+- web/src/collections.ts (convert 54 window reads to imports, add Alpine)
+- web/src/dashboard.ts (convert 10 window reads to imports, add Alpine)
+- web/src/admin.ts (convert 14 window reads to imports, add Alpine)
+- web/src/queue.ts (convert 8 window reads to imports, add Alpine)
+- web/src/conflicts.ts (convert 6 window reads to imports, add Alpine)
+- web/src/linking.ts (convert window reads to imports, add Alpine)
+- web/src/custom-section-builder.ts (convert window reads to imports, add Alpine)
+- web/src/analytics.ts (convert window reads to imports, add Alpine)
+- web/src/bookshelf.ts (convert window reads to imports, add Alpine)
+- web/src/api-explorer.ts (convert window reads to imports, add Alpine)
+- web/src/device-management.ts (convert window reads to imports, add Alpine)
+- web/src/search.ts (add Alpine registration)
+- web/src/docs.ts (remove window globals, move inline JS to module, add Alpine)
+- web/src/password_validation.ts (add Alpine registration)
+
+### Template Files Modified (27 files)
+All templates updated to:
+- Remove individual script tags
+- Use single ``
+- Replace `onclick` with `@click`
+- Add `x-data` for stateful components (modals, dropdowns)
+- Keep htmx.min.js separate
+
+### Generated Files
+- web/static/main.js (bundled output with Alpine)
+- web/static/main.js.map (sourcemap)
+
+### Files Deleted (Phase 5)
+All individual .js files in web/static/ (except main.js, main.js.map, htmx.min.js, highlight.min.js, style.css)
+
+---
+
+## External Dependencies (Not Bundled)
+
+### htmx.org
+- **Status**: Keep as separate script tag
+- **Reason**: Core framework, needs to load before main.js
+- **Location**: ``
+
+### Chart.js
+- **Status**: Keep on CDN
+- **Reason**: 3.4MB minified, only used on analytics page
+- **Location**: `` in analytics.templ only
+
+### highlight.js
+- **Status**: Bundled via ESBuild
+- **Reason**: Used in docs, small enough (~5KB gzipped)
+- **Import**: `import hljs from "highlight.js";`
+
+### lunr
+- **Status**: Bundled via ESBuild
+- **Reason**: Used in docs search, small enough (~10KB gzipped)
+- **Import**: `import * as lunr from "lunr";`
+
+---
+
+## Architecture Decision Records
+
+### ADR-001: ES Modules over Window Globals
+
+**Decision**: Use ES module imports/exports for all TypeScript-to-TypeScript dependencies.
+
+**Rationale**:
+- Standard JavaScript module system
+- Better type safety with TypeScript
+- Clear dependency chains
+- Tree-shaking support
+- No global namespace pollution
+
+**Consequences**:
+- Positive: Cleaner code, better IDE support, easier refactoring
+- Positive: Standard pattern, easier for new developers
+- Neutral: Requires build step (already using ESBuild)
+
+### ADR-002: Alpine.js for Template Interactivity Only
+
+**Decision**: Use Alpine.js ONLY as a bridge between templates and TypeScript, not for internal TypeScript dependencies.
+
+**Rationale**:
+- Alpine is designed for template directives (@click, x-show)
+- Clean separation: ES modules for code, Alpine for templates
+- Avoids over-engineering simple function calls
+- Keeps bundle size smaller
+
+**Consequences**:
+- Positive: Clean template syntax
+- Positive: Progressive enhancement works
+- Positive: Easy to understand data flow
+- Neutral: Need to learn Alpine basics (simple)
+
+### ADR-003: SSR-First with Progressive Enhancement
+
+**Decision**: Server renders complete HTML with data, client-side JavaScript only for interactivity.
+
+**Rationale**:
+- Faster initial page load
+- Better SEO (if needed)
+- Works without JavaScript (degrades gracefully)
+- Simpler state management
+- Aligns with HTMX philosophy
+
+**Consequences**:
+- Positive: Better performance
+- Positive: More resilient
+- Positive: Easier to debug
+- Neutral: Slightly more server work (acceptable)
+
+### ADR-004: Function Wrapping Elimination
+
+**Decision**: Eliminate function wrapping (themeDropdown.ts wraps header.ts functions) in favor of proper module composition.
+
+**Rationale**:
+- Clearer code flow
+- Better testability
+- Easier to understand
+- Standard pattern
+- App not yet deployed, can refactor
+
+**Consequences**:
+- Positive: Cleaner architecture
+- Positive: Easier to maintain
+- Negative: More work upfront (acceptable)
+- Negative: Need to restructure (acceptable)
+
+---
+
+## Troubleshooting
+
+### Build Errors
+
+**Error**: "Cannot find module './xxx'"
+
+**Solution**:
+- Check import path is correct (relative, case-sensitive)
+- Check file has `export {}` statements
+- Run `npm run build:ts` with clean build
+
+**Error**: "Alpine is not defined"
+
+**Solution**:
+- Check alpine.ts is imported in main.ts: `import "./alpine";`
+- Check Alpine.start() is called
+- Check window.Alpine is set
+
+**Error**: "Cannot read property 'xxx' of undefined"
+
+**Solution**:
+- Check Alpine.global() is called after Alpine.start()
+- Check namespace is correct (e.g., `api.post` not `window.api.post`)
+- Check template uses correct namespace: `@click="api.post()"`
+
+### Runtime Errors
+
+**Error**: "@click handler not working"
+
+**Possible Causes**:
+1. Alpine not loaded
+ - Check browser console: `window.Alpine` should be defined
+ - Check main.js is loaded
+ - Check alpine.ts imports Alpine and starts it
+
+2. Function not registered with Alpine
+ - Check source file has `Alpine.global("namespace", { ... })`
+ - Check namespace matches template usage
+
+3. Template syntax error
+ - Check @click syntax: `@click="namespace.function()"`
+ - Check for typos
+
+**Error**: "x-show not working"
+
+**Possible Causes**:
+1. Missing x-data parent
+ - Add `x-data="{ varName: false }"` to parent element
+
+2. Variable name mismatch
+ - Check x-data variable name matches x-show variable
+
+3. Alpine not loaded
+ - See above
+
+### Template Errors
+
+**Error**: "templ generate fails"
+
+**Solution**:
+- Check template syntax (missing closing tags, etc.)
+- Check for invalid templ syntax
+- Check template file encoding (UTF-8)
+
+**Error**: "Page not rendering correctly after migration"
+
+**Solution**:
+- Check all script tags are removed except main.js
+- Check main.js is loaded
+- Check browser console for errors
+- Check Alpine DevTools for state
+- Verify onclick → @click conversion is correct
+
+### Performance Issues
+
+**Issue**: "Bundle size too large (>200KB)"
+
+**Possible Causes**:
+- Check if Chart.js accidentally bundled (should be CDN)
+- Check if duplicate dependencies
+- Run `esbuild --analyze` to see bundle contents
+
+**Issue**: "Page load slow"
+
+**Possible Causes**:
+- Check main.js is minified in production
+- Check sourcemap not loaded in production
+- Check server compression enabled
+- Check browser caching headers
+
+---
+
+## Development Workflow
+
+### During Migration (Phases 0-2)
+
+```bash
+# Terminal 1: Watch TypeScript
+npm run build:ts:watch
+
+# Terminal 2: Watch Templates
+templ generate -watch
+
+# Terminal 3: Run Server
+go run .
+```
+
+### After Migration (All Phases Complete)
+
+```bash
+# Development
+npm run dev
+
+# Production Build
+npm run build
+templ generate
+go build
+```
+
+---
+
+## FAQ
+
+### Q: Why not put everything in main.ts?
+
+**A**: Main.ts imports other modules. This keeps code:
+- Organized (one file per concern)
+- Maintainable (easy to find code)
+- Testable (can test individual modules)
+- Tree-shakeable (unused code eliminated)
+
+### Q: Why Alpine.js instead of vanilla JS event listeners?
+
+**A**: Alpine provides:
+- Cleaner template syntax (@click vs onclick)
+- Built-in state management (x-show, x-data)
+- Better progressive enhancement
+- SSR-friendly
+- Smaller bundle than React/Vue
+
+### Q: Why keep HTMX if we have Alpine?
+
+**A**: They serve different purposes:
+- **HTMX**: Server communication (form submissions, API calls)
+- **Alpine**: Client-side state (modals, dropdowns, UI)
+
+They work great together.
+
+### Q: Can I use React/Vue instead of Alpine?
+
+**A**: You could, but:
+- **Larger bundle size**: React = ~40KB gzipped, Alpine = ~15KB gzipped
+- **More complexity**: Need JSX compilation, more build tools
+- **Overkill**: For this app's needs, Alpine is sufficient
+- **HTMX synergy**: Alpine works better with HTMX
+
+### Q: What if I need to add a new page?
+
+**A**: Follow the dashboard pattern:
+1. Create Go handler that renders template with data
+2. Create .templ file with SSR data
+3. Use Alpine for any client-side interactivity
+4. Import TypeScript modules in main.ts
+5. Register functions with Alpine if templates call them
+
+### Q: How do I debug issues?
+
+**A**:
+1. **Browser DevTools Console**: Check for errors
+2. **Network Tab**: Check main.js loads, no 404s
+3. **Alpine DevTools**: Install browser extension to inspect state
+4. **Sourcemaps**: Use main.js.map to debug original TypeScript
+5. **Go Logs**: Check server logs for errors
+
+---
+
+## Glossary
+
+- **ES Modules**: Standard JavaScript module system (import/export)
+- **ESBuild**: Fast JavaScript bundler
+- **Alpine.js**: Lightweight JavaScript framework for UI interactivity
+- **HTMX**: Library for dynamic web pages using HTML attributes
+- **Templ**: Go templating language that compiles to Go code
+- **SSR**: Server-Side Rendering - server generates complete HTML
+- **Progressive Enhancement**: Page works without JavaScript, enhanced with it
+- **Tree-shaking**: Removing unused code from bundle
+- **Sourcemap**: File that maps bundled code back to source code for debugging
+- **Window globals**: Variables attached to window object (old pattern)
+- **Namespace**: Grouping related functions (e.g., api.post, api.get)
+
+---
+
+## Appendix A: Quick Reference
+
+### Common Patterns
+
+**Import ES Module**:
+```typescript
+import { functionName } from "./module";
+```
+
+**Export from Module**:
+```typescript
+export { functionName1, functionName2 };
+export default function mainFunction() { ... }
+```
+
+**Register with Alpine**:
+```typescript
+import { Alpine } from "./alpine";
+
+Alpine.global("namespace", {
+ functionName1,
+ functionName2,
+});
+```
+
+**Use in Template**:
+```html
+
+