E.1 PreviewPanel 7개 editors/* 분할:
- frontend/src/lib/components/editors/ 신설 (7개 컴포넌트):
* NoteEditor — 사용자 메모 편집
* EditUrlEditor — 외부 편집 URL (Synology Drive 등)
* TagsEditor — 태그 추가/삭제
* AIClassificationEditor — AI 분류 read-only 표시
(breadcrumb + document_type + confidence tone Badge + importance)
* FileInfoView — 파일 메타 dl
* ProcessingStatusView — 파이프라인 단계 status dl
* DocumentDangerZone — 삭제 (ConfirmDialog 프리미티브 + id 고유화)
- PreviewPanel.svelte 344줄 → 60줄 얇은 wrapper로 축소
(header + 7개 editors 조합만)
- DocumentMetaRail (D.1)과 detail 페이지(E.2)가 동일 editors 재사용
E.2 detail 페이지 inline 편집:
- documents/[id]/+page.svelte: 기존 read-only 메타 패널 전면 교체
- 오른쪽 aside = 7개 editors 스택 (Card 프리미티브로 감쌈)
- 왼쪽 affordance row: Synology 편집 / 다운로드 / 링크 복사
- 삭제는 DocumentDangerZone이 담당 (ondelete → goto /documents)
- loading/error 상태도 EmptyState 프리미티브로 교체
- marked/DOMPurify renderer 유지, viewer 분기 그대로
E.3 관련 문서 stub:
- detail 페이지 오른쪽 aside에 "관련 문서" Card
- EmptyState "추후 지원" + TODO(backend) GET /documents/{id}/related
E.4 DocumentViewer Tabs 프리미티브:
- Markdown 편집 모드의 편집/미리보기 토글 → Tabs 프리미티브
- 키보드 nav (←→/Home/End), ARIA tablist/tab/tabpanel 자동 적용
검증:
- npm run build 통과 (editors/* 7개 모두 clean, $state 초기값
warning은 빈 문자열로 초기화하고 $effect로 doc 동기화해 해결)
- npm run lint:tokens 204 → 168 (detail 페이지 + PreviewPanel 전면
token 기반 재작성으로 -36)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
59 lines
2.1 KiB
Svelte
59 lines
2.1 KiB
Svelte
<script>
|
|
// Phase E.1 — 얇은 wrapper로 축소.
|
|
// 기존 344줄 → editors/* 7개로 분할. 이 파일은 header + 조합만 담당.
|
|
// DocumentMetaRail (D.1) 과 documents/[id]/+page.svelte (E.2) 둘 다
|
|
// 같은 editors/* 를 재사용한다.
|
|
import { X, ExternalLink } from 'lucide-svelte';
|
|
import FormatIcon from './FormatIcon.svelte';
|
|
import NoteEditor from './editors/NoteEditor.svelte';
|
|
import EditUrlEditor from './editors/EditUrlEditor.svelte';
|
|
import TagsEditor from './editors/TagsEditor.svelte';
|
|
import AIClassificationEditor from './editors/AIClassificationEditor.svelte';
|
|
import FileInfoView from './editors/FileInfoView.svelte';
|
|
import ProcessingStatusView from './editors/ProcessingStatusView.svelte';
|
|
import DocumentDangerZone from './editors/DocumentDangerZone.svelte';
|
|
|
|
let { doc, onclose, ondelete = () => {} } = $props();
|
|
</script>
|
|
|
|
<aside class="h-full w-full flex flex-col bg-sidebar border-l border-default overflow-y-auto">
|
|
<!-- 헤더 -->
|
|
<div class="flex items-center justify-between px-4 py-3 border-b border-default shrink-0">
|
|
<div class="flex items-center gap-2 min-w-0">
|
|
<FormatIcon format={doc.file_format} size={16} />
|
|
<span class="text-sm font-medium text-text truncate">{doc.title || '제목 없음'}</span>
|
|
</div>
|
|
<div class="flex items-center gap-1 shrink-0">
|
|
<a
|
|
href="/documents/{doc.id}"
|
|
class="p-1 rounded hover:bg-surface text-dim hover:text-text"
|
|
title="전체 보기"
|
|
aria-label="전체 보기"
|
|
>
|
|
<ExternalLink size={14} />
|
|
</a>
|
|
<button
|
|
type="button"
|
|
onclick={onclose}
|
|
class="p-1 rounded hover:bg-surface text-dim hover:text-text"
|
|
aria-label="닫기"
|
|
>
|
|
<X size={16} />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 조합 -->
|
|
<div class="flex-1 p-4 space-y-4">
|
|
<NoteEditor {doc} />
|
|
<EditUrlEditor {doc} />
|
|
<TagsEditor {doc} />
|
|
<AIClassificationEditor {doc} />
|
|
<FileInfoView {doc} />
|
|
<ProcessingStatusView {doc} />
|
|
<div class="pt-2 border-t border-default">
|
|
<DocumentDangerZone {doc} {ondelete} />
|
|
</div>
|
|
</div>
|
|
</aside>
|