refactor(M01): 표 · 모달 · 띠 알림 · 배지 · 알약 · 보조 글 · 빈 상태를 부품으로 (PLAN 553-5)

- 표 둘 = 표 부품(m01-master__grid = 일반표 · m01-logic__grid = 데이터표) · 페이지 CSS 는 폭 · 머리 고정 · 칸 상태만
- 손 모달 다섯(조달 찾기 · 요소 고르기 · 표 바꾸기 · 복사 시트 · 표 고르기) = 모달 부품 openModal
- 알림 띠 · 막힘 까닭 = 띠 알림 · 태그 = 배지 · 알약 · × · 삭제 · 로직 키 = 단추 부품 · muted 세 벌 = 보조 글 · 빈 줄 = 빈 상태
- M02 가 빌린 M01 클래스(표 · muted · 고르기 창)도 같은 부품으로 · 죽은 CSS 걷음 · 지킴 시험 test_553_5_m01_m02

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-26 22:57:33 +09:00
co-authored by Claude Opus 5.5
parent 6d8b38b518
commit 022eff69f5
34 changed files with 367 additions and 559 deletions
+13 -14
View File
@@ -17,6 +17,9 @@ import type {
NamedFormula,
} from "./M01_MasterData_UI_Logic_Api";
import { tx } from "./M01_MasterData_UI_Logic_Text";
import { createBadge } from "@ui/ui_template_badge";
import { createText } from "@ui/ui_template_text";
import { createIconButton } from "@ui/ui_template_button";
export type PickMode = "element" | "table";
export type PickDone = (item: ElementBrief, column?: string) => void;
@@ -81,12 +84,8 @@ function choice(
}
function dropButton(onClick: () => void): HTMLButtonElement {
const button = el("button", {
className: "m01-logic__drop",
text: "×",
attrs: { type: "button", title: tx("DeleteRow") },
});
button.addEventListener("click", onClick);
const button = createIconButton({ glyph: "×", title: tx("DeleteRow"), size: 20, onClick });
button.classList.add("m01-logic__drop");
return button;
}
@@ -100,7 +99,7 @@ function section(title: string, body: HTMLElement, onAdd?: () => void): HTMLElem
}
function grid(headers: string[], rows: HTMLElement[][], className: string): HTMLElement {
const table = el("table", { className: `m01-logic__grid ${className}` });
const table = el("table", { className: `ui-table ui-table--data m01-logic__grid ${className}` });
table.append(
el("thead", { children: [el("tr", { children: headers.map((h) => el("th", { text: h })) })] }),
);
@@ -133,7 +132,7 @@ export function buildEditor(host: HTMLElement, ctx: EditContext): void {
if (ctx.reasons.length) {
host.append(
el("div", {
className: "m01-logic__reasons",
className: "ui-banner ui-banner--danger m01-logic__reasons",
children: [
el("strong", { text: tx("Head_Blocked") }),
...ctx.reasons.map((r) => el("div", { text: r })),
@@ -191,7 +190,7 @@ function head(ctx: EditContext, set: (p: () => void) => void, rerender: () => vo
field(tx("Head_File"), file, true),
field(
tx("Head_Key"),
el("span", { className: "m01-logic__muted", text: row.키 || tx("New_Key") }),
el("span", { className: "ui-text ui-text--muted", text: row.키 || tx("New_Key") }),
),
field(
tx("Head_Number"),
@@ -276,11 +275,11 @@ function priceCell(ctx: EditContext, item: HoLine, i: number): HTMLElement {
const line = ctx.lines?.[i];
if (line) return el("span", { className: "m01-logic__money", text: formatNumber(line.단가) });
if (item.종류 === "로직" || item.요소.includes("{")) {
return el("span", { className: "m01-logic__muted", text: tx("Ho_PriceLater") });
return el("span", { className: "ui-text ui-text--muted", text: tx("Ho_PriceLater") });
}
const brief = ctx.prices[item.요소];
if (brief === undefined) return el("span", { className: "m01-logic__muted", text: "" });
if (brief === null) return el("span", { className: "m01-logic__bad", text: tx("Ho_Missing") });
if (brief === undefined) return el("span", { className: "ui-text ui-text--muted", text: "" });
if (brief === null) return createText(tx("Ho_Missing"), "error");
return el("span", { className: "m01-logic__money", text: formatNumber(brief.값) });
}
@@ -314,7 +313,7 @@ function hoSection(
set(() => (item.수량 = v));
tag.textContent = qtyKind(v);
});
const tag = el("span", { className: "m01-logic__tag", text: qtyKind(item.수량) });
const tag = createBadge(qtyKind(item.수량), "accent");
const table = createButton({
label: tx("Ho_PickTable"),
variant: "ghost",
@@ -339,7 +338,7 @@ function hoSection(
className: "m01-logic__stack",
children: [
textBox(item.이름 ?? "", (v) => set(() => (item.이름 = v))),
el("span", { className: "m01-logic__muted", text: spec }),
el("span", { className: "ui-text ui-text--muted", text: spec }),
],
}),
textBox(item.단위 ?? "", (v) => set(() => (item.단위 = v)), "m01-logic__unit"),