refactor(frontend): split large page components into focused sub-components (#75) #76
Reference in New Issue
Block a user
Delete Branch "feat/75-split-page-components"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Closes #75
Purely structural refactor — no behavior changes. Each touched
+page.sveltenow reads as a clear composition of named sub-components, co-located with their route.Page splits
refactor(utils)— Consolidate date utilities into$lib/utils/date.ts(isoToGerman,germanToIso,handleGermanDateInput);$lib/utils.tsbecomes a re-export shimrefactor(layout)— ExtractAppNav(logo + nav links) andUserMenu(avatar dropdown) from+layout.svelte(205 → ~80 lines)refactor(admin)— ExtractUsersTab,TagsTab,GroupsTab,SystemTabfrom admin page (573 → ~40 lines)refactor(profile)— ExtractPersonalInfoFormandPasswordChangeForm(240 → ~25 lines)refactor(admin/users)— Extract sharedUserProfileSection,UserGroupsSection,UserPasswordSection(to$lib/components/user/) and page-localAccountSection; used by bothadmin/users/[id]andadmin/users/newrefactor(documents)— Extract sharedWhoWhenSection,DescriptionSection,TranscriptionSection(to$lib/components/document/) and route-localFileSectionEdit,FileSectionNew,SaveBar; used by botheditandnewpagesrefactor(conversations)— ExtractConversationFilterBarandConversationTimeline(346 → ~70 lines)refactor(home)— ExtractSearchFilterBar,DropZone,DocumentList(580 → ~60 lines)refactor(persons)— ExtractPersonCard,PersonMergePanel,CoCorrespondentsList,PersonDocumentList(610 → ~55 lines)Follow-up cleanup
refactor(comments)— Eliminate duplicated root/reply markup inCommentThreadusing a{#snippet commentEntry(...)}(first use of Svelte 5 snippets in the codebase)refactor(types)— Extract shared types to$lib/types.ts:Comment+CommentReply(were in 3 files),DocumentPanelTab(2 files),Annotation(2 files, PdfViewer'sfileHash?is now canonical)Design decisions
$lib/components/) render field content only — no card wrappers. Pages add card wrappers as needed (avoids conflict between single-card and multi-card layouts)SaveBaruses HTML5form="delete-form"attribute to submit the parent's delete form without needing its own<form>oruse:enhancePersonMergePanelstate resets automatically via{#key person.id}in the parent (no manual$effectneeded)PersonDocumentListis reused for both sent and received document lists (heading + emptyMessage passed as props)Docpartial types intentionally left as-is per component — each component narrows to only the fields it needsTest plan
npm run checkpasses (only pre-existing errors inadmin/users/new/+page.server.ts)npm run lintpasses (0 errors)🤖 Generated with Claude Code
Split the 610-line person detail page into four focused co-located components: - PersonCard: view/edit card with inline form (owns editMode) - PersonMergePanel: merge target typeahead + two-step confirm (state reset via {#key}) - CoCorrespondentsList: frequency-ranked correspondent chips linking to conversations - PersonDocumentList: reusable sorted/paginated document list (used for sent + received) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>The root-comment and reply rendering blocks were near-identical (view mode with author/time/edit-delete, and edit mode with textarea/save/cancel). Extracted a local {#snippet commentEntry(comment, threadId, showReplyButton)} that handles both states, introducing Svelte 5 snippets to the codebase. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>