Phase 1 Batch 3: Route Pages type safety improvements
Fixed 10 any-type errors across 7 route page files:
1. src/routes/+page.ts (1 error)
- Added PaginationInfo interface for fetchProjects return type
2. src/routes/admin/+layout.svelte (1 error)
- Changed children prop from any to Snippet type
3. src/routes/admin/albums/+page.svelte (1 error)
- Changed Album.content from any to EditorData type
4. src/routes/admin/universe/+page.svelte (1 error)
- Changed form prop from any to Record<string, unknown> | null | undefined
5. src/routes/albums/[slug]/+page.svelte (4 errors)
- Added AlbumPhoto and AlbumData interfaces
- Fixed photo map parameters to use AlbumPhoto
- Fixed extractContentPreview to accept EditorData | null
- Fixed generateAlbumJsonLd to accept AlbumData
6. src/routes/albums/+page.svelte (1 error)
- Changed coverPhoto.colors from any to ColorPalette[]
7. src/routes/photos/[id]/+page.svelte (1 error)
- Changed navigateToPhoto parameter from any to PhotoItem | null
Progress: 67 any-type errors remaining (down from 77)
Phase 1 Batch 2: Logger & Simple Utilities
Replaced any types with proper TypeScript types across 3 files:
- logger.ts: Created LogContext type, added RequestEvent import from SvelteKit
- Defined LogContext = Record<string, string | number | boolean | null | undefined>
- Changed all context parameters from Record<string, any> to LogContext
- Changed event parameter in createRequestLogger from any to RequestEvent
- extractEmbeds.ts: Used TiptapNode type from editor.ts
- Changed content and node parameters from any to TiptapNode
- global.d.ts: Improved SVG module declarations
- Changed *.svg from any to string (raw SVG content)
- Changed *.svg?component from any to Component<any> (Svelte component)
Progress: 199 → 185 errors (91 → 77 any-type errors)
Phase 1 Batch 1: Type Definitions
Replaced any types with proper TypeScript types across 5 type definition files:
- apple-music.ts: Added AppleMusicArtistAttributes, changed type guards to use unknown
- editor.ts: Changed any to unknown for flexible block/node attributes
- lastfm.ts: Defined editorialNotes structure, changed rawResponse to unknown
- project.ts: Changed caseStudyContent to EditorData type
- photos.ts: Defined ColorPalette interface for color data
Progress: 207 → 199 errors (103 → 91 any-type errors)
- Restore AlbumForm handleSave() and validateForm() functions
- Add back missing imports (goto, zod, Button, toast)
- Restore isSaving and validationErrors state
- Add back albumSchema validation
This fixes the critical issue where AlbumForm had no way to save albums
due to over-aggressive dead code removal in previous cleanup.
Also update docs/eslint-cleanup-plan.md to reflect:
- Current branch status (207 errors remaining)
- Quality review of previous LLM work (84% good, 1 critical issue fixed)
- Detailed breakdown of remaining errors
- Actionable roadmap for completing the cleanup
- add ContentNode interface for content rendering
- replace any with proper types in content.ts (15 -> 6 errors)
- use Record<string, unknown> for dynamic content objects
- add type assertions for content arrays
- 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
- use Prisma.JsonValue and Prisma input types throughout
- add proper type guards for array and object checks
- replace any with Record<string, unknown> where appropriate
- all API/RSS routes now have zero any type errors
- add ProjectUpdateBody interface for partial updates
- use Prisma.ProjectUpdateInput for update operations
- replace all remaining any types in projects endpoints
- consistent use of proper types across all API routes
- add AlbumPhoto, BlockContent, AppleMusicData types
- add ProjectCreateBody interface for request validation
- use Prisma.ProjectWhereInput for query filters
- use Prisma.JsonValue for JSON fields
- add proper type guards for content validation
- add ContentNode, GalleryItem, TextNode, ParagraphNode, DocContent types
- use Prisma.JsonValue for JSON column content
- use Prisma.ProjectUpdateInput and Prisma.PostUpdateInput for update payloads
- improve type guards for content filtering
- replace any[] with never[] for empty placeholder arrays
- 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
Replace broken text extraction logic with renderEdraContent() which correctly handles TipTap marks including links, bold, italic, etc.
Before: Links were stripped from RSS content (only plain text extracted)
After: Full HTML with proper links, formatting preserved in CDATA sections
Files updated:
- src/routes/rss/+server.ts: Main RSS feed
- src/routes/rss/universe/+server.ts: Universe RSS feed
Fixes issue where content.blocks was expected but TipTap uses content.type='doc' format.
Migrate remaining Svelte 4 reactive statements to Svelte 5 $derived:
- media/audit/+page.svelte: Convert allSelected, hasSelection, selectedSize to $derived
- universe/compose/+page.svelte: Convert postType, initialContent to $derived
- Also migrated all let declarations to $state() in audit page for consistency
All reactive statements now use Svelte 5 runes mode.
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.