refactor(B08·B09): 자체 변종 → 부품 상자 — 탭 줄 · 분할 고르기 · 배지 칩 · 도구줄 · 떠 있는 판 · 보조 글 (PLAN 553-3)

- 위 · 보조 탭 줄 = 부품 탭(fillTabs · 밑줄 · 알약) · B09 좌측 스위치 = 분할 고르기
- 연결 칩 · 검사 탭 이름 · 끌기 태그 = 배지 · 이정표 도구 · 머리 줄 · 저장 줄 = 도구줄 · 구간 고침 · 행 고름 창 = 떠 있는 판
- 안내 · 빈 줄 · 상태 글 = 보조 글 · 운반 칸 = 카드 · 인쇄 미리보기 좌측 줄 = B09 dock 한 벌 · 쪽 체크 = 라디오 · 체크 부품
- 시험 흉내 틀 · 문구 맞춤

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-26 22:33:35 +09:00
co-authored by Claude Sonnet 5.5
parent b114616505
commit 361ce51659
38 changed files with 392 additions and 478 deletions
+2 -47
View File
@@ -10,14 +10,7 @@
}
.b09-print__status {
margin: 0;
min-height: 1.4em;
font-size: var(--text-caption);
color: var(--color-text-secondary);
}
.b09-print__status.is-error {
color: var(--color-danger);
min-height: 1.4em; /* 글이 비어도 줄 높이 유지 */
}
.b09-print__frame {
@@ -30,9 +23,7 @@
}
.b09-print__areas {
display: flex;
flex-wrap: wrap;
gap: var(--spacing-4);
flex-wrap: wrap; /* 부품 보조 탭 줄 */
}
.b09-print__list {
@@ -42,39 +33,3 @@
max-height: 50vh;
overflow: auto;
}
.b09-print__item {
display: flex;
align-items: center;
gap: var(--spacing-8);
font-size: var(--text-body-sm);
cursor: pointer;
}
/* 좌측 하단 두 줄(302-5 · B09 Dock 꼴) — 단추는 줄 폭을 나눠 가짐 · 가로 넘침 없음 */
.b09-print__actions.ui-sidebar-actions {
flex-direction: column;
}
.b09-print__actions.ui-sidebar-actions > * {
flex: none;
}
.b09-print__actions .b09-print__row {
display: flex;
gap: var(--btn-group-gap);
min-width: 0;
}
.ui-sidebar-actions.b09-print__actions .b09-print__row > .ui-btn:not(.ui-help-btn) {
flex: 1 1 0;
min-width: 0;
padding-inline: var(--spacing-4);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.b09-print__actions .b09-print__row > .ui-btn[hidden] {
display: none;
}
+27 -31
View File
@@ -11,14 +11,18 @@
* ========================================================================== */
import "@ui/ui_template_general_layout.css";
import "../B09_Estimation_UI_Page.css"; // 좌측 하단 단추 줄(b09-dock) 규칙 한 벌
import "./B09_Draft_Print_Page.css";
import { API_BASE_URL, CURRENT_PROJECT_ID_KEY, ROUTES } from "@config/config_frontend";
import { attachCollapsible, createPanelCard } from "@ui/ui_template_collapsible";
import { createCheckbox } from "@ui/ui_template_checkbox";
import { createButton } from "@ui/ui_template_elements";
import { createText } from "@ui/ui_template_text";
import { createWorkflowLayout } from "@ui/ui_template_workflow_layout";
import type { MountedPage } from "../../A00_Common/router";
import { navigateTo } from "../../A00_Common/router";
import { workflowSteps } from "../../A00_Common/b_page_scaffold";
import { fillTabs } from "../../A00_Common/b_page_tabs";
import { goToWorkflowStage, WORKFLOW_STEP_ROUTES } from "../../A00_Common/b_workflow_nav";
import { inlineImages, pdfBody, xlsxBody } from "./B09_Draft_Print_Table";
import type {
@@ -114,8 +118,8 @@ function save(blob: Blob, name: string): void {
export function renderB09Print(root: HTMLElement): MountedPage {
const projectId = localStorage.getItem(CURRENT_PROJECT_ID_KEY);
const status = document.createElement("p");
status.className = "b09-print__status";
const status = createText("", "muted");
status.className += " b09-print__status";
status.dataset.b09PrintStatus = "";
const frame = document.createElement("iframe");
frame.className = "b09-print__frame";
@@ -144,6 +148,8 @@ export function renderB09Print(root: HTMLElement): MountedPage {
const say = (text: string, error = false) => {
status.textContent = text;
status.classList.toggle("is-error", error);
status.classList.toggle("ui-text--error", error);
status.classList.toggle("ui-text--muted", !error);
};
const picked = () => (area?.items ?? []).map((it) => it.id).filter((id) => !off.has(id));
const clearFrame = () => {
@@ -213,21 +219,16 @@ export function renderB09Print(root: HTMLElement): MountedPage {
const drawList = () => {
list.replaceChildren(
...(area?.items ?? []).map((it) => {
const row = document.createElement("label");
row.className = "b09-print__item";
const box = document.createElement("input");
box.type = "checkbox";
box.checked = !off.has(it.id);
box.dataset.b09PrintItem = it.id;
box.addEventListener("change", () => {
if (box.checked) off.delete(it.id);
else off.add(it.id);
later();
const row = createCheckbox(it.name, {
checked: !off.has(it.id),
onChange: (on) => {
if (on) off.delete(it.id);
else off.add(it.id);
later();
},
});
const name = document.createElement("span");
name.textContent = it.name;
row.append(box, name);
return row;
row.input.dataset.b09PrintItem = it.id;
return row.root;
}),
);
};
@@ -238,18 +239,13 @@ export function renderB09Print(root: HTMLElement): MountedPage {
off = new Set();
const my = ++seq;
clearFrame();
areaRow.replaceChildren(
...AREAS.map((a) => {
const b = createButton({
label: a.label,
size: "sm",
variant: a.id === id ? "filled" : "ghost",
onClick: () => a.id !== areaId && pickArea(a.id),
});
b.dataset.b09PrintArea = a.id;
return b;
}),
);
fillTabs(areaRow, {
tabs: AREAS.map((a) => ({ key: a.id, label: a.label })),
value: id,
kind: "pill",
data: "b09PrintArea",
onChange: (key) => pickArea(key as AreaId),
});
xlsxBtn.hidden = id === "drawings";
drawList();
if (!projectId) return say("현재 프로젝트가 없습니다.", true);
@@ -270,14 +266,14 @@ export function renderB09Print(root: HTMLElement): MountedPage {
// 두 줄(302-5) — 위 = 내려받기 · 아래 = [?](도움말 줄) · 돌아가기 — 패널 폭 넘침 없음
const files = document.createElement("div");
files.className = "b09-print__row";
files.className = "b09-dock__row b09-print__row";
files.append(pdfBtn, xlsxBtn);
const nav = document.createElement("div");
nav.className = "b09-print__row";
nav.className = "b09-dock__row b09-print__row";
nav.dataset.helpRow = "";
nav.append(back);
const actions = document.createElement("div");
actions.className = "ui-sidebar-actions b09-print__actions";
actions.className = "ui-sidebar-actions b09-dock b09-print__actions";
actions.append(files, nav);
const left = document.createElement("div");
left.className = "ui-sidebar-panel b09-print__panel";