/* ============================================================================= * ui_template_ui_kit.ts * 부품 모음 화면(552-1) — 대시보드 세부 페이지 `#/b01-account?view=ui-kit` · 시스템 관리자만. * 밝음 · 어두움을 나란히 — 칸마다 iframe(``)에 지금 페이지 CSS 를 옮겨 실제 테마 값으로 그림. * 부품 줄 = `ui_template_ui_kit_parts.ts` 목록 · 상태 다섯 칸(기본 · 마우스 · 눌림 · 막힘 · 오류) · 견본이 없으면 빈 자리. * 크기 자 = 단추 · 입력 높이 여덟 단(18 ~ 42) · 부품마다 `sizes` 가 있으면 여덟 단 한 줄. * ========================================================================== */ import { pageFrame } from "../B01_Dashboard/B01_Dashboard_UI_PageKit"; import { KIT_GROUP_LABEL, KIT_PARTS, KIT_SIZES, KIT_STATES, KIT_STATE_LABEL, type KitGroup, type KitPart, } from "./ui_template_ui_kit_parts"; import "./ui_template_ui_kit.css"; type Theme = "light" | "dark"; function node( tag: K, className: string, text?: string, ): HTMLElementTagNameMap[K] { const n = document.createElement(tag); n.className = className; if (text !== undefined) n.textContent = text; return n; } /** 크기 자 — 여덟 단 높이 상자 */ function sizeRuler(): HTMLElement { const box = node("section", "ui-kit__group"); box.append(node("h3", "ui-kit__group-title", "크기 여덟 단 (높이 px · data-size)")); const line = node("div", "ui-kit__sizes"); for (const h of KIT_SIZES) { const cell = node("div", "ui-kit__size", String(h)); cell.style.height = `${h}px`; cell.dataset.size = String(h); line.append(cell); } box.append(line); return box; } function partRow(part: KitPart): HTMLElement { const item = node("article", "ui-kit__part"); item.dataset.part = part.key; const head = node("header", "ui-kit__part-head"); head.append( node("strong", "ui-kit__part-name", part.name), node("span", "ui-kit__part-kinds", part.kinds), node("code", "ui-kit__part-file", part.file), ); if (part.legacy) head.append(node("span", "ui-kit__part-flag", "지금 꼴")); item.append(head); const states = node("div", "ui-kit__states"); const shown = KIT_STATES.map((s) => part.demo?.(s)); // null = 그 상태 없음 · undefined = 견본 없음 const onlyDefault = shown[0] && shown.slice(1).every((x) => x === null); KIT_STATES.forEach((s, i) => { if (onlyDefault && i > 0) return; const cell = node("div", `ui-kit__state${onlyDefault ? " ui-kit__state--wide" : ""}`); cell.dataset.state = s; cell.append(shown[i] ?? node("span", "ui-kit__slot", shown[i] === null ? "-" : "빈 자리")); states.append(cell); }); item.append(states); if (part.sizes) { const sizes = node("div", "ui-kit__part-sizes"); for (const z of KIT_SIZES) sizes.append(part.sizes(z)); item.append(sizes); } return item; } /** 한 테마 칸 내용 — 상태 머리 · 크기 자 · 묶음별 부품 줄 */ export function renderKit(): HTMLElement { // 셸 별칭(`--b01-*`)을 받으려고 .b01-shell 로 감쌈 — 배치 규칙은 CSS 에서 풂 const root = node("div", "b01-shell ui-kit__body"); const legend = node("div", "ui-kit__states ui-kit__legend"); for (const s of KIT_STATES) legend.append(node("span", "ui-kit__state", KIT_STATE_LABEL[s])); root.append(legend, sizeRuler()); for (const group of Object.keys(KIT_GROUP_LABEL) as KitGroup[]) { const box = node("section", "ui-kit__group"); box.dataset.group = group; box.append(node("h3", "ui-kit__group-title", KIT_GROUP_LABEL[group])); box.append(...KIT_PARTS.filter((p) => p.group === group).map(partRow)); root.append(box); } return root; } /** 테마 칸 — iframe 에 지금 문서의 CSS 를 옮기고 `` 를 박음 */ function themePane(theme: Theme): HTMLElement { const pane = node("div", "ui-kit__pane"); pane.dataset.theme = theme; pane.append(node("h3", "ui-kit__pane-title", theme === "light" ? "밝음" : "어두움")); const frame = node("iframe", "ui-kit__frame"); frame.title = `부품 모음 — ${theme === "light" ? "밝음" : "어두움"}`; pane.append(frame); frame.addEventListener("load", () => { const doc = frame.contentDocument; if (!doc) return; doc.documentElement.dataset.theme = theme; doc.documentElement.lang = "ko"; for (const css of document.head.querySelectorAll('style, link[rel="stylesheet"]')) doc.head.append(css.cloneNode(true)); doc.body.className = "ui-kit__doc"; doc.body.append(renderKit()); const fit = (): void => { frame.style.height = `${doc.documentElement.scrollHeight}px`; }; new ResizeObserver(fit).observe(doc.body); fit(); }); frame.srcdoc = ""; return pane; } export function mountUiKit(host: HTMLElement): void { const page = pageFrame( host, "부품 모음", "모든 화면이 다시 쓰는 부품 — 밝음 · 어두움 · 상태별 · 빈 자리는 552-2 ~ 552-4 가 채움", ); page.root.classList.add("ui-kit"); const panes = node("div", "ui-kit__panes"); panes.append(themePane("light"), themePane("dark")); page.body.append(panes); }