Commit graph

245 commits

Author SHA1 Message Date
1190bfc62e fix: enable drag and drop reordering in Edra editor
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.
2025-11-03 23:03:07 -08:00
1c98aff722 feat(admin): complete Task 7 Phase 2 - styling rollout
Extended the theming system to additional pages and components, continuing
to eliminate hardcoded colors and duplicated styles.

**Pages Refactored:**
- /admin/media - Integrated EmptyState with action button (~20 lines removed)
- /admin/albums - Integrated EmptyState & ErrorMessage (~25 lines removed)
  - Fixed hardcoded spacing in loading spinner (32px → calc($unit * 4))
  - Replaced hardcoded error color (#d33 → $error-text)

**Components Updated with Semantic Colors:**
- Button.svelte - Replaced 3 instances of #dc2626 → $error-text
- AlbumSelector.svelte - Error message uses $error-bg, $error-text
- AlbumSelectorModal.svelte - Error message uses $error-bg, $error-text, $error-border
  - Fixed border width (1px → $unit-1px)

**Phase 2 Results:**
- Total lines removed: ~105 across 4 pages (Phase 1: 60, Phase 2: 45)
- EmptyState component now used in 4 pages
- ErrorMessage component now used in 3 pages
- Standardized error colors across 3 modal components

**Theming Benefits:**
- Error styling centralized (change $error-bg once, updates everywhere)
- Empty states guaranteed visual consistency
- Dark mode ready (just remap CSS variables in themes.scss)

**Remaining work (future):**
- ~30 files with remaining hardcoded colors
- ~15 files with spacing that could use $unit system
- Opportunity for additional semantic variables as needed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-08 22:02:33 -07:00
45e3556663 feat(admin): complete Task 7 Phase 1 - styling & theming foundation
Implemented a three-layer theming architecture to standardize admin component
styling and prepare for future dark mode support.

**Architecture:**
- Layer 1: Base colors ($gray-80, $red-60) in variables.scss
- Layer 2: Semantic SCSS variables ($input-bg, $error-bg) in variables.scss
- Layer 3: CSS custom properties (--input-bg, --error-bg) in themes.scss

**New semantic variables (~30 added):**
- Inputs & forms (bg, hover, focus, text, border states)
- State messages (error, success, warning with bg/text/border)
- Empty states (text, heading colors)
- Cards, dropdowns, popovers, modals (bg, border, shadow)

**New reusable components:**
- EmptyState.svelte - Supports icon and action snippets
- ErrorMessage.svelte - Supports dismissible errors

**Pages refactored:**
- /admin/projects - Uses EmptyState and ErrorMessage (~30 lines removed)
- /admin/posts - Uses EmptyState and ErrorMessage with icon (~30 lines removed)

**Benefits:**
- 60+ lines of duplicate styles removed (just 2 pages)
- Future dark mode = remap CSS variables in themes.scss only
- Guaranteed visual consistency for errors and empty states
- $unit-based spacing system enforced

**Remaining work (Phase 2):**
- Replace hardcoded colors in ~40 files
- Fix hardcoded spacing in ~20 files
- Expand EmptyState/ErrorMessage to remaining pages

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-08 21:28:28 -07:00
48e53aea3a feat(admin): complete Task 5 dropdown primitives (Option A)
Task 5 was ~85% complete when reviewed. This commit finalizes the
implementation with minimal cleanup and comprehensive documentation.

Changes:
- Refactored GenericMetadataPopover to use clickOutside action
  - Removed manual document.addEventListener for click outside
  - Now uses standardized action with trigger exclusion logic
  - Cleaner code, consistent with other components

Documentation:
- Created task-5-dropdown-primitives-completion.md
- Documented existing infrastructure (clickOutside, BaseDropdown)
- Justified 15 remaining manual event listeners
- API documentation for clickOutside action and BaseDropdown

What Already Existed:
- clickOutside action (full TypeScript, proper cleanup)
- BaseDropdown component (Svelte 5 snippets)
- Dropdown primitives (DropdownMenuContainer, DropdownItem, DropdownMenu)
- ~10 components already using clickOutside
- Specialized dropdowns (StatusDropdown, PostDropdown, etc.)

Justified Exceptions (manual listeners kept):
- DropdownMenu.svelte: Complex submenu logic with Floating UI
- ProjectListItem/PostListItem: Global dropdown coordination pattern
- BaseModal + forms: Keyboard shortcuts (Escape, Cmd+S)
- Various: Scroll/resize positioning (layout concerns)

Decision: Did NOT use Runed library
- Custom clickOutside implementation is production-ready
- No advantage from external dependency
- Current solution is type-safe and well-tested

Phase 3 (List Utilities & Primitives) now complete!
- Task 4: List filtering utilities 
- Task 5: Dropdown primitives 

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-08 19:47:09 -07:00
34a3e370ec refactor(admin): modularize ProjectForm with composable stores
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>
2025-10-07 23:24:50 -07:00
3fded37d64 fix(svelte5): update event handler syntax from on:clickoutside to onclickoutside
Update all clickOutside action usages to use Svelte 5's new event handler
syntax. Replace deprecated `on:clickoutside` with `onclickoutside` across
all components to fix Svelte 5 compilation errors.

Fixed in:
- ProjectListItem
- AdminSegmentedController
- BaseDropdown
- PostDropdown
- BubbleTextStyleMenu
- BubbleColorPicker
- EssayForm
- BasePane

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-07 22:16:13 -07:00
dcca9eb6e5 refactor(ui): update BasePane to use clickOutside action
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>
2025-10-07 22:00:54 -07:00
7300bd672b refactor(admin): update EssayForm to use clickOutside action
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>
2025-10-07 22:00:06 -07:00
9cc7baddc6 refactor(admin): migrate dropdowns to clickOutside action
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>
2025-10-07 21:58:34 -07:00
97a80d9c3e feat(admin): add clickOutside action and update dropdowns
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>
2025-10-07 21:33:33 -07:00
128a24ccde fix(admin): remove infinite loop in navigation guards
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>
2025-10-07 18:43:28 -07:00
8fa26fb39e fix(admin): replace navigation.retry() with goto() after flush
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>
2025-10-07 18:34:56 -07:00
fe923c3dbf refactor(admin): add autosave to SimplePostForm
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>
2025-10-07 14:19:38 -07:00
6ed1b0f1a8 refactor(admin): add autosave to PhotoPostForm
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>
2025-10-07 14:04:20 -07:00
c49ce5cbb5 feat(admin): add runes-based autosave to EssayForm
- 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>
2025-10-07 14:00:28 -07:00
672eb47143 fix(admin): only block navigation/close when changes are unsaved
- 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>
2025-10-07 13:21:57 -07:00
f35fa60207 refactor(admin): only save local draft on autosave failure
- 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>
2025-10-07 13:09:39 -07:00
dfbf45f8a4 refactor(admin): migrate ProjectForm to runes-based autosave
- 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>
2025-10-07 11:55:51 -07:00
c67dbeaf38 fix(admin): make filters reactive in Svelte 5
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-07 07:30:01 -07:00
3554d0af2c fix(admin): keep universe route authenticated 2025-10-07 06:09:26 -07:00
e2949bff20 refactor(admin): update form flows for session auth 2025-10-07 05:57:45 -07:00
94fb5f6daf refactor(admin): use session fetch in media components 2025-10-07 05:54:18 -07:00
376df12c20 refactor(admin): remove legacy client auth helper 2025-10-07 05:53:55 -07:00
3a588fdf89 refactor(admin): load posts list on server 2025-10-07 05:30:50 -07:00
dbcd7a9e1b refactor(admin): load projects list on server 2025-10-07 05:30:34 -07:00
280bdfc06d feat(drafts): add local draft backup with restore prompt to EssayForm, SimplePostForm, and PhotoPostForm 2025-08-31 11:03:27 -07:00
c98ba3dcf0 feat(admin): integrate autosave and local draft prompt into ProjectForm and Post Edit; add Cmd/Ctrl+S and beforeNavigate flush 2025-08-31 11:03:27 -07:00
1a5ecf9ecf feat(autosave): add autosave controller and status component 2025-08-31 11:03:27 -07:00
9bc942211a refactor(admin): use shared api client across projects list, posts list, new post, project edit load, and media modal 2025-08-31 11:03:27 -07:00
aa3622d606 feat: add video playback UI and thumbnail display
- 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>
2025-08-23 03:14:06 -04:00
1b0269e81e Tentative fix for mobile zoom 2025-07-24 03:45:00 -07:00
4fd35ec1f0 feat: link albums to Apple Music when available
- 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>
2025-07-11 20:12:13 -07:00
a74e9d8c4d Fix hover effect in two column grid 2025-07-11 20:11:18 -07:00
f1d0453b63 feat: add comprehensive debug panel for development
- 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>
2025-07-10 21:32:59 -07:00
3d7eb6e985 refactor: consolidate now playing detection into single music stream store
- 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>
2025-07-10 21:32:14 -07:00
4d24be2457 Fix some bad photos changes 2025-07-10 09:33:43 -07:00
27075088ee Fix the mobile nav dropdown 2025-07-10 09:14:21 -07:00
5e4b0949c2 Fix styling of embeds 2025-07-10 02:53:38 -07:00
103c69664b fix: improve now playing detection reliability
- 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>
2025-07-10 01:25:31 -07:00
e21d5eab9d feat: add now playing display to header on avatar hover
- 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>
2025-07-10 00:08:46 -07:00
9ee98a2ff8 refactor: modernize Edra editor components and enhance functionality
- 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>
2025-07-09 23:21:27 -07:00
a4f5c36f71 refactor: migrate media components to Svelte 5 runes
- Convert all media-related admin components to use $state and $derived
- Update event handlers to use new syntax (onclick instead of on:click)
- Refactor prop destructuring to use interface Props pattern
- Improve type safety and remove legacy reactive statements
- Simplify component logic with Svelte 5 patterns

Components updated:
- AlbumForm: Enhanced validation and state management
- FilePreviewList: Simplified preview rendering
- FileUploadZone: Improved drag-and-drop handling
- MediaDetailsModal: Better metadata display
- MediaGrid: Optimized selection state
- MediaMetadataPanel: Cleaner EXIF data presentation
- MediaUploadModal: Streamlined upload flow
- MediaUsageList: Enhanced usage tracking
- UnifiedMediaModal: Consolidated media management

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-09 23:20:56 -07:00
d767d9578f feat: implement reusable pane system components
- 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>
2025-07-09 23:20:32 -07:00
12c30c1501 feat: implement unified content insertion pane for Edra editor
- 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
2025-06-26 16:15:17 -04:00
737a34b950 fix: correct placeholder spacing in Edra editor
- 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
2025-06-26 15:56:49 -04:00
48cc27770f fix: standardize Edra editor placeholder widths and slash command navigation
- 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)
2025-06-26 15:37:47 -04:00
22c27a0e64 refactor: update slash command menu to match visual style
- 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
2025-06-26 15:15:57 -04:00
ebdd958374 fix: remove unnecessary margin-top from editor with toolbar 2025-06-26 14:29:29 -04:00
68d931df82 style: align embeds with text content horizontal margins
- 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>
2025-06-26 14:26:36 -04:00
fd27d68fc6 style: add consistent margin-bottom to content embeds
- 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>
2025-06-26 14:19:51 -04:00