From ff0d9775ec0b657872f01a5972bc5152e28f6ee5 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 28 Sep 2026 18:42:23 +0900 Subject: [PATCH] =?UTF-8?q?feat(ui):=20=EA=B3=B5=EC=9A=A9=20=EB=8B=A8?= =?UTF-8?q?=EC=B6=94=20=EC=9E=91=EC=9D=80=20=ED=81=AC=EA=B8=B0=20size=20sm?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20=C2=B7=20M01=20=ED=91=9C=20=EB=8B=A8?= =?UTF-8?q?=EC=B6=94=20=C2=B7=20M02=20=EB=8B=A8=EC=B6=94=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20=C2=B7=20M02=20=EC=83=81=EC=84=B8=20=EB=A8=B8?= =?UTF-8?q?=EB=A6=AC=20=EC=9D=B4=EB=A6=84=20=EC=A4=84=EB=B0=94=EA=BF=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - createButton 에 size: "sm"(글자 캡션 크기 · 위아래 여백 2px) — 다섯 모양 모두에 먹음 · 기본은 그대로 - M01 표 안 단추는 sm 으로 바꾸고 M01 자체 축소 규칙 삭제 - M02 좌측 새로 · 본떠 만들기 · 지우기 · 카드 수정 단추에 sm - M02 상세 화면 머리 번호 + 이름 잘림 없이 줄바꿈 · 집계표 카드 머리는 번호 · 수정 한 줄 + 이름 아래 전체 폭 Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01NWHNLQYPZN7kKf1rzrrRZq --- M01_MasterData/M01_MasterData_UI_Combo.ts | 17 ++++++++++++++--- M01_MasterData/M01_MasterData_UI_Rows.ts | 5 +++-- M01_MasterData/M01_MasterData_UI_Style.css | 6 ------ .../M02_MasterTemplete_Structure.css | 12 +++++++++--- .../M02_MasterTemplete_Structure.ts | 3 ++- .../M02_MasterTemplete_UI_Side.ts | 6 +++--- .../M02_MasterTemplete_UI_Style.css | 7 ++----- ui_template/ui_template_elements.ts | 5 ++++- ui_template/ui_template_elements_styles.ts | 6 ++++++ 9 files changed, 43 insertions(+), 24 deletions(-) diff --git a/M01_MasterData/M01_MasterData_UI_Combo.ts b/M01_MasterData/M01_MasterData_UI_Combo.ts index fa94820a..9eb01737 100644 --- a/M01_MasterData/M01_MasterData_UI_Combo.ts +++ b/M01_MasterData/M01_MasterData_UI_Combo.ts @@ -238,7 +238,7 @@ export function mountM01Combo( memo.input.value = row.메모 ?? ""; memo.input.addEventListener("input", () => (row.메모 = memo.input.value || null)); const name = el("button", { - className: "ui-btn ui-btn--ghost", + className: "ui-btn ui-btn--ghost ui-btn--sm", text: info?.이름 ?? row.로직, attrs: { type: "button", title: tc("Open") }, }); @@ -249,11 +249,22 @@ export function mountM01Combo( const btns = el("div", { className: "m01-logic__chips", children: [ - createButton({ label: tc("Up"), variant: "ghost", onClick: () => move(i, -1) }), - createButton({ label: tc("Down"), variant: "ghost", onClick: () => move(i, 1) }), + createButton({ + label: tc("Up"), + variant: "ghost", + size: "sm", + onClick: () => move(i, -1), + }), + createButton({ + label: tc("Down"), + variant: "ghost", + size: "sm", + onClick: () => move(i, 1), + }), createButton({ label: tc("Remove"), variant: "ghost", + size: "sm", onClick: () => { combo.담은로직.splice(i, 1); drawTable(); diff --git a/M01_MasterData/M01_MasterData_UI_Rows.ts b/M01_MasterData/M01_MasterData_UI_Rows.ts index 07f5b564..a3b5d24d 100644 --- a/M01_MasterData/M01_MasterData_UI_Rows.ts +++ b/M01_MasterData/M01_MasterData_UI_Rows.ts @@ -248,12 +248,13 @@ export function renderRows(host: HTMLElement, pick: Pick, q: string): () => void } function actionCell(label: string, onClick: () => void): HTMLTableCellElement { - return el("td", { children: [createButton({ label, variant: "ghost", onClick })] }); + return el("td", { children: [createButton({ label, variant: "ghost", size: "sm", onClick })] }); } type Put = (row: Row) => void; -const rowBtn = (label: string): HTMLButtonElement => createButton({ label, variant: "ghost" }); +const rowBtn = (label: string): HTMLButtonElement => + createButton({ label, variant: "ghost", size: "sm" }); /** 품셈재료 — 가격 연결(자재품목 키 · 후보 조건 · 없음) · 고르기 모달. */ function linkedCell(row: Row, cur: Row, put?: Put): HTMLTableCellElement { diff --git a/M01_MasterData/M01_MasterData_UI_Style.css b/M01_MasterData/M01_MasterData_UI_Style.css index 6d2983e3..2b909b1b 100644 --- a/M01_MasterData/M01_MasterData_UI_Style.css +++ b/M01_MasterData/M01_MasterData_UI_Style.css @@ -162,12 +162,6 @@ padding: 2px var(--spacing-4); } -/* 표 칸 안 공용 단추 — 줄 높이에 맞춰 작게 */ -.m01-master__grid .ui-btn { - padding: 2px var(--spacing-8); - font-size: var(--text-caption); -} - .m01-master__pager { display: flex; align-items: center; diff --git a/M02_MasterTemplete/M02_MasterTemplete_Structure.css b/M02_MasterTemplete/M02_MasterTemplete_Structure.css index 104ed6ac..e291744e 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Structure.css +++ b/M02_MasterTemplete/M02_MasterTemplete_Structure.css @@ -54,13 +54,19 @@ min-width: 0; } +/* 머리 = 번호 · [수정] 한 줄, 이름은 그 아래 전체 폭 — 긴 이름도 잘리지 않게 줄바꿈 */ +.m02-struct__head { + flex-wrap: wrap; +} + .m02-struct__title { + order: 1; + flex: 1 0 100%; + min-width: 0; margin: 0; - overflow: hidden; color: var(--color-text); font-size: var(--text-body); - text-overflow: ellipsis; - white-space: nowrap; + overflow-wrap: anywhere; /* 이름이 길어도 잘리지 않게 줄바꿈 */ } .m02-struct__no { diff --git a/M02_MasterTemplete/M02_MasterTemplete_Structure.ts b/M02_MasterTemplete/M02_MasterTemplete_Structure.ts index b95e356c..a52ae745 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Structure.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Structure.ts @@ -264,7 +264,7 @@ export function createStructurePanel(opts: StructurePanelOptions): StructurePane const columnName = el("span", { className: "m02-struct__title" }); const number = el("span", { className: "m02-struct__no" }); - const edit = createButton({ label: TEXT.edit, variant: "filled" }); + const edit = createButton({ label: TEXT.edit, variant: "filled", size: "sm" }); const previewHost = el("div", { className: "m02-struct__preview" }); const infoCard = card( TEXT.drawingInfo, @@ -288,6 +288,7 @@ export function createStructurePanel(opts: StructurePanelOptions): StructurePane const editButton = createButton({ label: fill(TEXT.editSheet, PARTS[kind].word), variant: "ghost", + size: "sm", }); const host = el("div", { className: "m02-struct__sheet" }); editButton.addEventListener("click", () => void openEdit(kind)); diff --git a/M02_MasterTemplete/M02_MasterTemplete_UI_Side.ts b/M02_MasterTemplete/M02_MasterTemplete_UI_Side.ts index 80b5c960..e1bbec82 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_UI_Side.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_UI_Side.ts @@ -119,9 +119,9 @@ export function buildSide(opt: SideOptions): SideHandle { const editButtons = new Map(); const actionRow = (kind: Kind): HTMLElement[] => { if (!canEdit(layer, opt.isAdmin)) return []; - const btnNew = createButton({ label: L("M02_New"), variant: "filled" }); - const copy = createButton({ label: L("M02_Copy"), variant: "ghost" }); - const del = createButton({ label: L("M02_Delete"), variant: "danger" }); + const btnNew = createButton({ label: L("M02_New"), variant: "filled", size: "sm" }); + const copy = createButton({ label: L("M02_Copy"), variant: "ghost", size: "sm" }); + const del = createButton({ label: L("M02_Delete"), variant: "danger", size: "sm" }); editButtons.set(kind, { copy, del }); btnNew.addEventListener("click", () => newTemplate(kind)); copy.addEventListener("click", copyTemplate); diff --git a/M02_MasterTemplete/M02_MasterTemplete_UI_Style.css b/M02_MasterTemplete/M02_MasterTemplete_UI_Style.css index 5c3ae7ed..cb26dc9c 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_UI_Style.css +++ b/M02_MasterTemplete/M02_MasterTemplete_UI_Style.css @@ -26,7 +26,7 @@ .m02-main__head { display: flex; - flex-wrap: nowrap; + flex-wrap: wrap; align-items: center; gap: var(--spacing-12); } @@ -34,10 +34,7 @@ .m02-main__title { flex: 0 1 auto; min-width: 3rem; - max-width: 9rem; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + overflow-wrap: anywhere; /* 번호 + 이름 — 잘리지 않게 줄바꿈 */ margin: 0; color: var(--color-text); font-size: var(--text-body); diff --git a/ui_template/ui_template_elements.ts b/ui_template/ui_template_elements.ts index cb8fc767..4bd498b4 100644 --- a/ui_template/ui_template_elements.ts +++ b/ui_template/ui_template_elements.ts @@ -24,11 +24,14 @@ export { el } from "./ui_template_elements_base"; * -------------------------------------------------------------------------- */ export type ButtonVariant = "filled" | "ghost" | "pill" | "danger" | "glass"; +export type ButtonSize = "md" | "sm"; export interface ButtonOptions { /** 표시 텍스트 (i18n 결과 문자열을 전달) */ label: string; variant?: ButtonVariant; + /** 크기 — 기본 md · sm = 표 칸·카드 머리용 작은 단추(글자 캡션 크기) */ + size?: ButtonSize; /** 이벤트 핸들러 (frontend.md §4: on[페이지]_[기능]_[액션] 명명) */ onClick?: (ev: MouseEvent) => void; disabled?: boolean; @@ -40,7 +43,7 @@ export interface ButtonOptions { export function createButton(opts: ButtonOptions): HTMLButtonElement { const variant = opts.variant ?? "filled"; const btn = el("button", { - className: `ui-btn ui-btn--${variant}`, + className: `ui-btn ui-btn--${variant}${opts.size === "sm" ? " ui-btn--sm" : ""}`, attrs: { type: opts.type ?? "button" }, }); if (opts.iconStart) { diff --git a/ui_template/ui_template_elements_styles.ts b/ui_template/ui_template_elements_styles.ts index 598b4df1..5a1dd3d1 100644 --- a/ui_template/ui_template_elements_styles.ts +++ b/ui_template/ui_template_elements_styles.ts @@ -33,6 +33,12 @@ const BASE_CSS = ` .ui-btn:disabled { opacity: 0.5; cursor: not-allowed; } .ui-btn__icon { display: inline-flex; width: 16px; height: 16px; } +/* 작은 크기 — 다섯 모양 모두에 먹음(padding · 글자만 바꿈) */ +.ui-btn--sm { + padding: 2px var(--spacing-8); + font-size: var(--text-caption); +} + .ui-btn--filled { background-color: var(--color-primary); color: var(--color-primary-text);