feat(ui): Phase D.4/D.5 — keyboard nav + density toggle
D.4 useListKeyboardNav: - 신규: frontend/src/lib/composables/useListKeyboardNav.svelte.ts j/k/Arrow/Enter/Esc, isTypingTarget 가드 (input/textarea/select/ contenteditable 포커스 시 비활성) - documents/+page.svelte: kbIndex $state, kbSelectedId $derived, items 변경 시 clamp, URL 변경 시 0 리셋 - DocumentTable/DocumentCard: kbSelectedId prop → data-kb-selected 속성 + ring-accent-ring 시각 표시 - scrollSelectedIntoView: queueMicrotask + querySelector로 현재 커서를 뷰포트 내로 스크롤 (block: nearest) D.5 Table density: - DocumentTable: density prop (compact/comfortable), rowPaddingClass ($derived: py-1 | py-2.5), rowTextClass (text-[10px] | text-xs) - documents/+page.svelte: tableDensity $state, toggleDensity 헬퍼, localStorage.tableDensity persistent, 테이블 뷰에서만 토글 버튼 노출 (Rows2/Rows3 아이콘) - 뷰 모드 버튼도 token 기반으로 리팩토링 검증: - npm run build 통과 - npm run lint:tokens 231 → 229 (뷰 모드 버튼 token swap으로 -2) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,8 +10,15 @@
|
||||
selectable = false,
|
||||
selectedIds = new Set(),
|
||||
onselectionchange = null,
|
||||
// D.4 키보드 네비게이션 커서
|
||||
kbSelectedId = null,
|
||||
// D.5 행 밀도
|
||||
density = 'comfortable', // 'compact' | 'comfortable'
|
||||
} = $props();
|
||||
|
||||
let rowPaddingClass = $derived(density === 'compact' ? 'py-1' : 'py-2.5');
|
||||
let rowTextClass = $derived(density === 'compact' ? 'text-[10px]' : 'text-xs');
|
||||
|
||||
function toggleSelection(id, e) {
|
||||
e?.stopPropagation?.();
|
||||
const next = new Set(selectedIds);
|
||||
@@ -130,10 +137,13 @@
|
||||
<!-- 행 -->
|
||||
{#each sortedItems() as doc}
|
||||
{@const isChecked = selectedIds.has(doc.id)}
|
||||
{@const isKbCursor = doc.id === kbSelectedId}
|
||||
<div
|
||||
class="flex items-center gap-1 px-2 py-1.5 w-full border-b border-default/30 hover:bg-surface transition-colors group
|
||||
data-kb-selected={isKbCursor}
|
||||
class="flex items-center gap-1 px-2 {rowPaddingClass} w-full border-b border-default/30 hover:bg-surface transition-colors group
|
||||
{selectedId === doc.id ? 'bg-accent/5 border-l-2 border-l-accent' : ''}
|
||||
{isChecked ? 'bg-accent/10' : ''}"
|
||||
{isChecked ? 'bg-accent/10' : ''}
|
||||
{isKbCursor ? 'ring-1 ring-accent-ring ring-inset' : ''}"
|
||||
>
|
||||
{#if selectable}
|
||||
<span class="w-6 shrink-0 flex items-center justify-center">
|
||||
@@ -156,7 +166,7 @@
|
||||
<div class="flex-1 flex items-center gap-2 min-w-0">
|
||||
<span class="w-1 h-4 rounded-full shrink-0" style="background: {getDomainColor(doc.ai_domain)}"></span>
|
||||
<FormatIcon format={doc.file_format} size={14} />
|
||||
<span class="text-xs truncate group-hover:text-accent">{doc.title || '제목 없음'}</span>
|
||||
<span class="{rowTextClass} truncate group-hover:text-accent">{doc.title || '제목 없음'}</span>
|
||||
</div>
|
||||
<!-- 분류 -->
|
||||
<div class="w-48 text-[10px] text-dim truncate">
|
||||
|
||||
Reference in New Issue
Block a user