refactor(tokens): A-8 Batch 3 — PreviewPanel / DocumentViewer / +layout(toast)

가장 큰 위험 batch. Phase A 디자인 시스템 정착 마지막 mechanical refactor
(8 파일 8/8 누적 — core components 0 hit 달성).

PreviewPanel (53 hits → 0):
- bg-[var(--sidebar-bg)] → bg-sidebar (메인 aside)
- bg-[var(--bg)]         → bg-bg (input 배경)
- bg-[var(--surface)]    → bg-surface (hover)
- bg-[var(--accent)]     → bg-accent + hover:bg-accent-hover (저장 버튼)
- bg-[var(--error)]      → bg-error (삭제 확인)
- text/border 토큰 일괄 swap
- focus:border-accent (input)
- confidence 색상 (green/amber/red palette)은 plan B3 명시 없어 그대로

DocumentViewer (28 hits → 0):
- 뷰어 본체 bg-surface border-default
- 툴바 bg-sidebar
- 마크다운 편집 탭 bg-surface, edit textarea bg-bg
- 상태별 hover 토큰 swap
- 뉴스 article 태그 blue-900/30 그대로 (lint:tokens 미검출)

+layout.svelte (10 hits → 0):
- nav 잔여 var() (햄버거, 로고, 메뉴 링크) 토큰 swap
- 로딩 텍스트 text-dim
- toast 영역 의미 swap (plan B3 명시):
  * green-900/200  → bg-success/10 + text-success + border-success/30
  * red-900/200    → bg-error/10 + text-error + border-error/30
  * yellow-900/200 → bg-warning/10 + text-warning + border-warning/30
  * blue-900/200   → bg-accent/10 + text-accent + border-accent/30
- class:* 디렉티브 8개 → script TOAST_CLASS dict + dynamic class binding
  (svelte 5에서 슬래시 포함 클래스명을 class: 디렉티브로 못 씀)

검증:
- npm run lint:tokens : 360 → 269 (-91, B3 파일 0 hit)
- 누적 진행: 421 → 269 (-152 / 8 파일 완료, plan 정정 목표 정확 달성)
- npm run build       : 
- npx svelte-check    :  0 errors
- ⚠ 3-risk grep       : hover/border-border/var() 잔여 0건

A-8 종료 시점 상태:
- core components 8 파일: lint:tokens 0 hit 
- routes 7 파일 잔존 (~269): news 92, settings 47, documents/[id] 36,
  +page 28, documents 26, inbox 25, login 15
- lint:tokens 강제화 (pre-commit hook)는 Phase D + F 완료 후 별도 commit

플랜: ~/.claude/plans/compressed-churning-dragon.md §A.4 Batch 3
This commit is contained in:
Hyungi Ahn
2026-04-07 12:14:48 +09:00
parent 8ec89517ee
commit c294df5987
3 changed files with 82 additions and 81 deletions

View File

@@ -10,6 +10,15 @@
const PUBLIC_PATHS = ['/login', '/setup', '/__styleguide'];
const NO_CHROME_PATHS = ['/login', '/setup', '/__styleguide'];
// toast 의미 토큰 매핑 (A-8 B3)
const TOAST_CLASS = {
success: 'bg-success/10 text-success border-success/30',
error: 'bg-error/10 text-error border-error/30',
warning: 'bg-warning/10 text-warning border-warning/30',
info: 'bg-accent/10 text-accent border-accent/30',
};
let authChecked = $state(false);
let sidebarOpen = $state(false);
@@ -54,7 +63,7 @@
{#if !authChecked}
<div class="min-h-screen flex items-center justify-center">
<p class="text-[var(--text-dim)]">로딩 중...</p>
<p class="text-dim">로딩 중...</p>
</div>
{:else if $isAuthenticated || PUBLIC_PATHS.some(p => $page.url.pathname.startsWith(p))}
{#if showChrome}
@@ -65,7 +74,7 @@
{#if !$page.url.pathname.startsWith('/news')}
<button
onclick={() => sidebarOpen = !sidebarOpen}
class="p-1.5 rounded-md hover:bg-[var(--border)] text-[var(--text-dim)]"
class="p-1.5 rounded-md hover:bg-default text-dim"
aria-label="사이드바 토글"
>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@@ -73,17 +82,17 @@
</svg>
</button>
{/if}
<a href="/" class="text-sm font-semibold hover:text-[var(--accent)]">PKM</a>
<span class="text-[var(--text-dim)] text-xs">/</span>
<a href="/documents" class="text-xs hover:text-[var(--accent)]">문서</a>
<a href="/" class="text-sm font-semibold hover:text-accent">PKM</a>
<span class="text-dim text-xs">/</span>
<a href="/documents" class="text-xs hover:text-accent">문서</a>
</div>
<div class="flex items-center gap-3">
<a href="/news" class="text-xs text-[var(--text-dim)] hover:text-[var(--text)]">뉴스</a>
<a href="/inbox" class="text-xs text-[var(--text-dim)] hover:text-[var(--text)]">Inbox</a>
<a href="/settings" class="text-xs text-[var(--text-dim)] hover:text-[var(--text)]">설정</a>
<a href="/news" class="text-xs text-dim hover:text-text">뉴스</a>
<a href="/inbox" class="text-xs text-dim hover:text-text">Inbox</a>
<a href="/settings" class="text-xs text-dim hover:text-text">설정</a>
<button
onclick={() => logout()}
class="text-xs text-[var(--text-dim)] hover:text-[var(--text)]"
class="text-xs text-dim hover:text-text"
>로그아웃</button>
</div>
</nav>
@@ -119,15 +128,7 @@
<div class="fixed top-4 right-4 z-50 flex flex-col gap-2 max-w-sm" role="status" aria-live="polite">
{#each $toasts as toast (toast.id)}
<button
class="px-4 py-3 rounded-lg shadow-lg text-sm flex items-center gap-2 cursor-pointer text-left"
class:bg-green-900={toast.type === 'success'}
class:bg-red-900={toast.type === 'error'}
class:bg-yellow-900={toast.type === 'warning'}
class:bg-blue-900={toast.type === 'info'}
class:text-green-200={toast.type === 'success'}
class:text-red-200={toast.type === 'error'}
class:text-yellow-200={toast.type === 'warning'}
class:text-blue-200={toast.type === 'info'}
class="px-4 py-3 rounded-lg shadow-lg text-sm flex items-center gap-2 cursor-pointer text-left border {TOAST_CLASS[toast.type] || TOAST_CLASS.info}"
onclick={() => removeToast(toast.id)}
>
{toast.message}