feat(frontend): 절 바로가기 페이지(/clause) + 사이드바 링크 — U-1 진입점

ASME 절 식별자(UG-79 등) 입력 → /api/documents/clause-lookup → 문서·위치 결과 →
읽기뷰 이동. 절은 in_corpus=false(의미검색 비활성)라 이 정확지목 진입점이 유일 경로.
사이드바(자료실 옆 'Hash 절 바로가기')로 노출. 신규 라우트라 기존 표면 미접촉.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
hyungi
2026-06-20 08:25:41 +09:00
parent 3e2fa16e1d
commit 16f3e313da
2 changed files with 81 additions and 1 deletions
+8 -1
View File
@@ -2,7 +2,7 @@
import { page } from '$app/stores';
import { goto } from '$app/navigation';
import { api } from '$lib/api';
import { ChevronRight, ChevronDown, FolderOpen, FolderTree, Inbox, Clock, Mail, Scale, StickyNote, GraduationCap, CalendarCheck, MessageCircle } from 'lucide-svelte';
import { ChevronRight, ChevronDown, FolderOpen, FolderTree, Inbox, Clock, Mail, Scale, StickyNote, GraduationCap, CalendarCheck, MessageCircle, Hash } from 'lucide-svelte';
let tree = $state([]);
let loading = $state(true);
@@ -195,6 +195,13 @@
>
<FolderTree size={14} /> 자료실
</a>
<a
href="/clause"
class="w-full flex items-center gap-2 px-3 py-1.5 rounded-md text-sm transition-colors
{$page.url.pathname === '/clause' ? 'bg-accent/15 text-accent' : 'text-dim hover:bg-surface hover:text-text'}"
>
<Hash size={14} /> 절 바로가기
</a>
</div>
<!-- 메모 & Inbox -->
+73
View File
@@ -0,0 +1,73 @@
<script>
// 절(clause) 바로가기 — ASME 절 식별자(예: UG-79)로 크로스-doc 위치를 조회해 읽기뷰로 이동 (U-1).
// 절은 in_corpus=false(의미검색 비활성)라 일반 검색으론 안 잡히므로 라벨 정확지목 전용 진입점.
import { api } from '$lib/api';
import { goto } from '$app/navigation';
let label = $state('');
let hits = $state([]);
let loading = $state(false);
let searched = $state(false);
let error = $state('');
async function lookup() {
const q = label.trim();
if (!q) return;
loading = true;
error = '';
try {
const res = await api(`/documents/clause-lookup?label=${encodeURIComponent(q)}`);
hits = res?.hits ?? [];
searched = true;
} catch (e) {
error = '조회에 실패했습니다.';
hits = [];
} finally {
loading = false;
}
}
</script>
<div class="mx-auto max-w-3xl px-6 py-10">
<h1 class="mb-1 text-2xl font-bold text-base">절 바로가기</h1>
<p class="mb-6 text-sm text-dim">
ASME 절 식별자(예: <code class="text-accent">UG-79</code>, <code class="text-accent">PG-5</code>)로 문서·위치를 찾아 이동합니다.
</p>
<form onsubmit={(e) => { e.preventDefault(); lookup(); }} class="mb-6 flex gap-2">
<input
bind:value={label}
placeholder="절 식별자 (UG-79, PG-5.6, A-1 …)"
autocomplete="off"
class="flex-1 rounded-lg border border-default bg-surface px-4 py-2.5 text-base outline-none focus:border-accent"
/>
<button
type="submit"
disabled={loading || !label.trim()}
class="rounded-lg bg-accent px-5 py-2.5 font-medium text-white hover:bg-accent-hover disabled:opacity-50"
>
{loading ? '조회 중…' : '찾기'}
</button>
</form>
{#if error}
<p class="text-sm text-accent">{error}</p>
{:else if searched && hits.length === 0}
<p class="text-sm text-dim">'{label}' 에 해당하는 절을 찾지 못했습니다. (절은 분해된 코드 문서에만 존재합니다)</p>
{:else if hits.length > 0}
<div class="space-y-2">
{#if hits.length > 1}
<p class="text-xs text-dim">{hits.length}개 문서에 존재 — 에디션/부록을 선택하세요.</p>
{/if}
{#each hits as hit (hit.chunk_id)}
<button
onclick={() => goto(`/documents/${hit.doc_id}`)}
class="block w-full rounded-lg border border-default bg-surface px-4 py-3 text-left transition hover:border-accent hover:bg-surface-hover"
>
<div class="font-medium text-base">{hit.section_title}</div>
<div class="mt-0.5 text-xs text-dim">{hit.doc_title}</div>
</button>
{/each}
</div>
{/if}
</div>