feat(813-0b): 원문 패널 — 제목 한 줄로 통합 · 표 글자 16

- 제목 = 책 부문 + 절 번호 + 절 제목(개정 꼬리 포함) 한 줄 · 본문 안 원문 제목 줄은 화면에서만 숨김(절 여럿이면 절마다 번호 이름 줄)
- 기초 찾기로 고른 뒤 남던 작은 글 줄 지움
- 표 머리 · 칸 글자 = 본문과 같은 --text-body(16) · [주] 는 14 그대로

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-09 20:43:15 +09:00
co-authored by Claude Sonnet 5.5
parent c1872fe41b
commit ad9a50c584
3 changed files with 26 additions and 5 deletions
@@ -18,9 +18,7 @@
.m01lab-src__title {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
overflow-wrap: anywhere; /* 제목 한 줄이 길면 접음 */
}
.m01lab-src__body {
@@ -61,6 +59,11 @@
white-space: pre;
}
/* 표 머리 · 칸 = 본문과 같은 16 — 좁으면 둘레 칸(m01-logic__scroll)이 가로로 굴림 */
.m01lab-src .m01lab-src__table :is(td, th) {
font-size: var(--text-body);
}
/* 출처가 가리킨 항 · 주 — 옅은 바탕 + 왼쪽 막대 */
.m01lab-src__hit {
background: color-mix(in srgb, var(--color-accent) 14%, transparent);
@@ -38,6 +38,9 @@ interface Found {
item?: string;
}
/** 절 제목 블록의 글만 「번호 이름」 꼴로 */
const headFixed = (b: Block): Block => (b.h ? { ...b, text: headText(b.text ?? "") } : b);
function blockNode(b: Block): HTMLElement {
const node = rawNode(b);
if (b.hit) node.classList.add("m01lab-src__hit");
@@ -65,6 +68,15 @@ function rawNode(b: Block): HTMLElement {
return el("p", { className: "m01lab-src__p", text: b.p ?? "" });
}
/** 출처 글에서 첫 번호 앞까지 = 책 · 부문(예 「건설품셈 공통」) — 제목 한 줄의 앞 */
const prefixOf = (src: string): string => {
const at = src.search(/\d+(?:-\d+)+/);
return (at < 0 ? src : src.slice(0, at)).trim();
};
/** 절 제목 줄 「9-7-1. 이름」 → 「9-7-1 이름」 */
const headText = (t: string): string => t.replace(/^(\d+(?:-\d+)*)\.\s*/, "$1 ");
/** 「[주]」 줄부터 다음 제목 앞까지 글 줄 = 한 단 작은 글자(`m01lab-src__note`) */
function noteMarked(blocks: Block[]): HTMLElement[] {
let inNote = false;
@@ -133,6 +145,12 @@ export function createSourceView(opts: SourceViewOptions = {}): SourceView {
.then(({ found }) => {
if (shown !== src) return;
if (!found.length) return none();
// 제목 한 줄 = 「책 부문 + 절 번호 · 이름(개정 꼬리)」 — 절 하나면 원문 제목 줄을 숨김 · 여럿이면 절마다 번호 · 이름 줄 둠
const lone = found.length === 1 && found[0].blocks[0]?.h ? found[0] : null;
if (found.length > 1 || lone) {
const pre = prefixOf(src);
title.textContent = lone ? `${pre} ${headText(lone.blocks[0].text ?? "")}`.trim() : pre;
}
body.replaceChildren(
...found.flatMap((f) => {
// 파일 경로는 안 보임 — 가까운 절 · 항 안내만
@@ -146,7 +164,7 @@ export function createSourceView(opts: SourceViewOptions = {}): SourceView {
...(note
? [el("p", { className: "ui-text ui-text--muted m01lab-src__file", text: note })]
: []),
...noteMarked(f.blocks),
...noteMarked(f === lone ? f.blocks.slice(1) : f.blocks.map(headFixed)),
];
}),
);
@@ -77,7 +77,7 @@ export function createSourceFind(opts: {
unit: x.결과단위 ?? "",
onPick: () => {
find.setRows([]);
find.hint.textContent = `${x.원문번호 || x.키} ${x.이름}`;
find.hint.textContent = ""; // 고른 기초 이름은 원문 제목 한 줄이 보임
opts.onPick(x);
},
})),