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>
- Merge albumStream and nowPlayingStream into unified musicStream store
- Simplify confidence scoring to binary detection (playing/not playing)
- Create single source of truth for music state across components
- Fix synchronization issues between header and album indicators
- Make Album spring animation more subtle (stiffness: 150, damping: 25)
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Always fetch fresh data from Last.fm for now playing detection
- Add confidence-based detection with progress tracking
- Implement dynamic polling intervals (10s when playing, 30s idle)
- Add marquee animation for now playing text in header
- Fix release date formatting to show only year
- Add gradient fade effects to marquee edges
- Enhanced logging for debugging detection issues
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Show currently playing track info when hovering over avatar
- Display album artwork, artist name, and track/album name
- Add music note icons with pulse animation
- Maintain exact same container size as navigation
- Only shows when music is actively playing (avatar has headphones)
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Migrate all Edra components to Svelte 5 with runes syntax
- Implement unified ContentInsertionPane for consistent content insertion
- Standardize placeholder components with improved layouts
- Enhance bubble menu with better color picker and text styling
- Improve drag handle interactions and visual feedback
- Update slash command system for better extensibility
Key improvements:
- ContentInsertionPane: New unified interface for all content types
- Placeholder components: Consistent sizing and spacing
- GeolocationPlaceholder: Simplified map integration
- UrlEmbedPlaceholder: Better preview handling
- ComposerMediaHandler: Converted to Svelte 5 class syntax
- BubbleMenu components: Enhanced UI/UX with modern patterns
All components now use:
- Interface Props pattern for better type safety
- $state and $derived for reactive state
- Modern event handling syntax
- Consistent styling with CSS variables
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add BasePane and Pane components for consistent panel UI
- Create pane-manager store for centralized pane state management
- Support for different pane positions and animations
- Establish foundation for unified pane behavior across the app
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Create ContentInsertionPane component with segmented controls
- Update image placeholder to single-line format with icon + text
- Update gallery placeholder to use unified pane
- Support upload, embed link, and gallery selection for each type
- Add location search placeholder for future geocoding integration
- Add placeholder node styles to editor.css matching other media nodes
- Remove incorrect margins from individual placeholder components
- Placeholders now properly aligned with 2.25rem horizontal spacing
- Consistent with h1, h2, p text elements and YouTube embeds
- Fix slash command keyboard navigation by uncommenting handler
- Update all media placeholders to respect content block margins (2.25rem)
- Refactor placeholder styles to use SCSS variables consistently
- Fix Audio, Gallery, IFrame, Video, Location, and URL embed placeholders
- Fix Image placeholder width to match other placeholders
- Ensure responsive margins on mobile (2rem)
- Replace old slash command list styles with new design
- Use consistent SCSS variables from design system
- Match dropdown styling patterns used elsewhere
- Improve visual hierarchy with better typography
- Add smooth transitions and hover states
- Clean up old CSS styles
- Add left/right margins of 2.25rem to match text block padding
- Ensure YouTube videos, link cards, and other embeds align with text
- Add responsive margins (2rem) for mobile viewports
- Fixes issue where embeds were too wide compared to text content
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add 1rem margin-bottom to all embed types (url, iframe, video, image, gallery, audio, geolocation)
- Ensure YouTube embeds and URL cards have consistent spacing
- Prevent double margins when embeds are adjacent
- Matches the margin-bottom used for text blocks (paragraphs)
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Always initialize editor with content to create paragraph node
- Remove logic that prevented setting empty paragraph content
- Remove unused initialized variable
- This ensures the placeholder is visible when editor first loads
The issue was that the editor needs at least one paragraph node
for the placeholder to display, but the previous logic prevented
this from happening on initial load.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add padding-left and negative margin-left to placeholder pseudo-elements
- Separate styles for paragraphs and headings to target specific elements
- Include responsive styles for mobile viewports
- Fixes issue where placeholder text wasn't aligned with actual content
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update padding for paragraphs, headings, blockquotes, lists, tables, and code blocks
- Change from 48px (3rem) to 36px (2.25rem) for better content density
- Maintains responsive behavior with existing media queries
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace old slot syntax with new snippet syntax to fix compilation error.
BaseDropdown expects snippets as props, not slots.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace inline grid with MediaGrid component
- Replace upload zone with FileUploadZone component
- Replace file list with FilePreviewList component
- Replace metadata sections with dedicated components
- Simplify media selection to idiomatic Svelte patterns
- Remove non-idiomatic composable pattern
This completes the media modal consolidation, reducing duplication
and improving maintainability.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add ComposerBubbleMenu with formatting tools and dropdowns
- Create BubbleTextStyleMenu for paragraph/heading/list selection
- Add BubbleColorPicker with preset palettes and custom color selection
- Use lighter pastel colors for highlight presets
- Implement circle color swatches with even grid spacing
- Add strikethrough support and improved hover states
- Use absolute positioning to prevent scroll issues
- Integrate with existing editor configuration
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add explicit styles for mark elements
- Force normal font-style with \!important
- Add subtle padding and border-radius for highlights
- Ensure text color inheritance for proper contrast
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>