- replace any with Prisma types (Post, Project, Album, Media)
- use Component type for Svelte component parameters
- use Snippet type for Svelte 5 render slots
- use Record<string, unknown> for dynamic objects
- add proper type guards for error handling
- fix editor extension types with proper generics
- all frontend components now have zero any type errors
- fix edra placeholder components with proper editor context types
- fix gallery image types with proper type assertions
- fix ProseMirror transaction types in link manager
- fix command types in composer toolbar
- replace any with unknown where type is dynamic
- use Leaflet types (L.Map, L.Marker, L.LeafletEvent) for map components
- use Post and Project types from Prisma for form components
- use JSONContent type for editor instances
- use Snippet type for Svelte 5 render functions
- use EditorView type for TipTap/ProseMirror views
- use proper type guards for error handling
- add editor interface types for save/clear methods
- add GalleryItem type for media/gallery item unions
- add EdraCommand import for editor command types
- add Post, Media imports from Prisma
- add BlockContent, DraftPayload, PostPayload, PhotoPayload types
- replace any with proper types in form handlers and callbacks
- use unknown for truly dynamic data, Record types for object props
Make page headers sticky with subtle shadow on scroll. Fix min-height to 90px to prevent jumping when switching tabs. Modernize layout to use full viewport height.
Convert admin components from Svelte 4 to Svelte 5 syntax using $props, $state, $derived, and $bindable runes. Simplifies AdminNavBar logic and improves type safety.
Extract BrandingToggle and BrandingSection components. Consolidate $effect blocks, add $derived state, and apply BEM naming. Reduces component size by 47% while improving maintainability.
Add live preview to branding form showing featured image, background color, and logo. Add database fields and toggles to control visibility of each element in project headers.
Add return false to drop handler so ProseMirror's Dropcursor extension can handle the actual node movement. Previously the handler would intercept drops but not perform any movement.
Extract reusable form patterns following Svelte 5 best practices:
**New Store Factory** (`project-form.svelte.ts`)
- Centralizes form state management with `$state` and `$derived` runes
- Provides validation, payload building, and field mutation methods
- Type-safe with ProjectFormData interface
- Reusable across different contexts
**New Helpers**
- `useDraftRecovery.svelte.ts`: Generic draft restoration with auto-detection
- `useFormGuards.svelte.ts`: Navigation guards, beforeunload warning, Cmd+S shortcut
- `DraftPrompt.svelte`: Extracted UI component for draft recovery prompts
**Refactored ProjectForm.svelte**
- Reduced from 720 lines to 417 lines (42% reduction)
- Uses new composable helpers instead of inline logic
- Cleaner separation between UI orchestration and business logic
- All form state now managed through formStore
- Draft recovery, navigation guards fully extracted
**Benefits**
- Reusable patterns for PostForm, EssayForm, etc.
- Easier to test helpers in isolation
- Consistent UX across all admin forms
- Better maintainability and code organization
Closes Task 3 of admin modernization plan (Phase 2)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace manual click event listener with clickOutside action for the
pane backdrop click handling. This simplifies the code and ensures
consistent click-outside behavior.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace manual click event listener with clickOutside action for the
publish menu dropdown. This simplifies the code and ensures consistent
click-outside behavior across all admin dropdowns.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Updated components to use the new clickOutside action instead of manual
event listener management:
- ProjectListItem: Add clickOutside action and dropdown coordination
- AdminSegmentedController: Replace $effect with clickOutside action
- BubbleTextStyleMenu: Simplify click-outside handling
- BubbleColorPicker: Simplify click-outside handling
- Posts/Projects pages: Remove redundant page-level click handlers
The clickOutside action provides a cleaner, more maintainable way to
handle click-outside behavior with proper lifecycle management.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Created a reusable clickOutside Svelte action that dispatches a custom
event when users click outside an element. This replaces manual
document.addEventListener patterns.
Features:
- TypeScript support with generic event types
- Configurable enabled/disabled state
- Optional callback parameter
- Proper cleanup on destroy
- setTimeout to avoid immediate triggering
Updated components to use the new action:
- BaseDropdown.svelte: Removed $effect with manual listeners
- PostDropdown.svelte: Replaced manual click handling
Part of Task 5 - Click-Outside Primitives
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed infinite loop caused by calling goto() inside beforeNavigate,
which would trigger the same navigation guard again.
The correct approach is to NOT cancel navigation, but simply await
the autosave flush. SvelteKit's beforeNavigate accepts async callbacks,
so navigation will naturally wait for the flush to complete before
proceeding.
Changes:
- Removed navigation.cancel() calls
- Removed goto() calls that created the loop
- Simply await autoSave.flush() and let navigation proceed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed navigation guards in all forms that were calling the non-existent
navigation.retry() method. After canceling navigation and flushing autosave,
now properly uses goto() to navigate to the intended destination.
Files fixed:
- ProjectForm.svelte
- EssayForm.svelte
- PhotoPostForm.svelte
- SimplePostForm.svelte
- posts/[id]/edit/+page.svelte
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added runes-based autosave functionality to SimplePostForm:
- Added autosave store with updatedAt conflict detection
- Smart navigation guards and beforeunload warnings
- Draft recovery banner instead of inline prompt
- Only saves to localStorage on autosave failure
- Added AutoSaveStatus component
- Fixed $derived syntax to use $derived.by()
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added runes-based autosave functionality to PhotoPostForm following the same pattern as EssayForm:
- Added autosave store with updatedAt conflict detection
- Smart navigation guards and beforeunload warnings
- Draft recovery banner instead of inline prompt
- Only saves to localStorage on autosave failure
- Added AutoSaveStatus component
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add createAutoSaveStore for edit mode
- Add updatedAt tracking for conflict detection
- Add hasLoaded flag to prevent autosave on initial load
- Prime autosave after initial data loads
- Add AutoSaveStatus indicator in header
- Move draft recovery from inline to prominent banner
- Only save draft on autosave failure (not every change)
- Smart navigation guard (only blocks if unsaved)
- Add beforeunload warning (only if unsaved changes)
- Add keyboard shortcut (Cmd/Ctrl+S)
- Add proper cleanup on unmount
- Update clearDraft calls in restore/dismiss functions
- Fix $derived syntax (use $derived.by for draftTimeText)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update beforeNavigate guard to check autosave status before blocking
- Allow instant navigation when status is 'saved' (no interruption)
- Add beforeunload warning for browser close/reload
- Only show warnings when status is NOT 'saved' (saving/error/idle)
- Improves UX by not interrupting users when everything is already saved
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove redundant localStorage saves on every form change
- Only save draft when autosave status is 'error' or 'offline'
- Reduces draft recovery banner noise for successful autosaves
- Navigation guard still prevents data loss when navigating away
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update ProjectForm to use new createAutoSaveStore with Svelte 5 runes
- Fix $derived syntax in AutoSaveStatus (use $derived.by for multi-statement)
- Add hasLoaded flag to prevent infinite loop on autosave completion
- Move draft recovery from inline header to prominent banner below header
- Style draft banner with blue info colors and slide-down animation
- Fix draft persistence by clearing localStorage on restore/dismiss
- Call beforeNavigate at top level for proper Svelte 5 lifecycle
- Add keyboard shortcut (Cmd/Ctrl+S) and navigation guard effects
- Update AutoSaveStatus to support both old stores and new reactive props
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add video player with controls in MediaDetailsModal
- Display video metadata (duration, codecs, bitrate) in metadata panel
- Show video thumbnails with play icon overlay in MediaGrid
- Support video preview in upload components
- Replace emoji icons with SVG play icon
- Maintain natural video aspect ratio in all views
- Add proper styling for video thumbnails and placeholders
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add URL field to Apple Music data type
- Include Apple Music URL in album transformation
- Prioritize Apple Music links over Last.fm in Album component
- Falls back to Last.fm URL when Apple Music data unavailable
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Create DebugPanel component with Now Playing, Albums, and Cache tabs
- Show real-time connection status and update intervals
- Display detailed Apple Music data for each album
- Add inline cache clearing for individual albums
- Implement Apple Music search modal for testing queries
- Add admin endpoints for cache management and API testing
- Only visible in development mode
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>