From 2033125fecf4855934b42c927145387cf5b2bd6a Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 26 Oct 2026 22:00:37 +0900 Subject: [PATCH] =?UTF-8?q?style(spreadsheet):=20=EB=8F=84=EA=B5=AC?= =?UTF-8?q?=EC=A4=84=20=EB=8B=A8=EC=B6=94=20=C2=B7=20=EC=B9=B8=20=C2=B7=20?= =?UTF-8?q?=EC=8B=9C=ED=8A=B8=20=ED=83=AD=20[+]=20=EB=A5=BC=20=EB=B6=80?= =?UTF-8?q?=ED=92=88=20=EB=8B=A8=EC=B6=94=2024=20=C2=B7=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20=C2=B7=20=EA=B3=A0=EB=A5=B4=EA=B8=B0=2028=20=C2=B7?= =?UTF-8?q?=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EB=8B=A8=EC=B6=94=EB=A1=9C=20?= =?UTF-8?q?(PLAN=20553-6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 도구줄 단추 23 → 부품 단추 24 · 글꼴 · 크기 · 표시 형식 칸 → 부품 입력 28 · 정렬 고르기 → 부품 고르기 28 - 색 지우기 ✕ → 아이콘 단추 18 · 시트 탭 [+] → 아이콘 단추(선) 22 · 켬(is-on) 색 = 공통 값(옛 보라 별칭 걷음) - 메모 창 뒷막 = --color-scrim · 자체 단추 · 칸 CSS 지움(폭만 남김) - 격자 · 시트 탭 꼴 · 배치 그대로 — 도구줄 안 단추만 3 px 넓어짐(줄바꿈 0) Co-Authored-By: Claude Opus 5.5 --- A00_Common/spreadsheet/spreadsheet_tabs.ts | 12 +-- .../spreadsheet/spreadsheet_toolbar.css | 53 ++----------- A00_Common/spreadsheet/spreadsheet_toolbar.ts | 76 ++++++++++++------- 3 files changed, 61 insertions(+), 80 deletions(-) diff --git a/A00_Common/spreadsheet/spreadsheet_tabs.ts b/A00_Common/spreadsheet/spreadsheet_tabs.ts index f4cc8a551..efdb0fe82 100644 --- a/A00_Common/spreadsheet/spreadsheet_tabs.ts +++ b/A00_Common/spreadsheet/spreadsheet_tabs.ts @@ -12,7 +12,7 @@ * ========================================================================== */ import { createMapContextMenu, type MapContextMenuItem } from "@ui/ui_template_context_menu"; -import { el, showConfirmDialog, showToast } from "@ui/ui_template_elements"; +import { createIconButton, el, showConfirmDialog, showToast } from "@ui/ui_template_elements"; import { emptySheet } from "./spreadsheet_commands"; import { hideSheet, unhideSheet } from "./spreadsheet_sheet_extra"; import { st } from "./spreadsheet_text"; @@ -164,11 +164,13 @@ export function mountTabs(ctx: SpreadsheetContext): PartHandle { } function addButton(): HTMLElement { - const btn = el("button", { - className: "ss-tabs__add", - text: "+", - attrs: { type: "button", title: st("SheetAdd") }, + const btn = createIconButton({ + glyph: "+", + title: st("SheetAdd"), + variant: "outline", + size: 22, }); + btn.classList.add("ss-tabs__add"); btn.addEventListener("click", () => { const name = nextSheetName(ctx.book, "Sheet"); const sheet = emptySheet(nextSheetId(ctx.book), name); diff --git a/A00_Common/spreadsheet/spreadsheet_toolbar.css b/A00_Common/spreadsheet/spreadsheet_toolbar.css index fc0ffa84f..92606abe7 100644 --- a/A00_Common/spreadsheet/spreadsheet_toolbar.css +++ b/A00_Common/spreadsheet/spreadsheet_toolbar.css @@ -27,24 +27,10 @@ border-right: 0; } -.ss-toolbar .ui-btn { - padding: 4px 8px; - font-size: 0.82rem; -} - +/* 단추 · 칸 = 부품 단추(24) · 입력 · 고르기(28) — 여기는 켬 · 폭만(553-6) */ .ss-toolbar .ui-btn.is-on { - background: var(--color-mist-violet); - box-shadow: inset 0 0 0 1px var(--color-royal-amethyst); -} - -.ss-toolbar__select { - height: 28px; - padding: 0 4px; - border: 1px solid var(--color-border); - border-radius: var(--radius-sm); - background: var(--color-canvas); - color: var(--color-text-body); - font-size: 0.8rem; + background: var(--color-accent-soft); + box-shadow: inset 0 0 0 1px var(--color-accent); } .ss-toolbar__select option { @@ -53,14 +39,7 @@ } .ss-toolbar__input { - height: 28px; width: 72px; - padding: 0 4px; - border: 1px solid var(--color-border); - border-radius: var(--radius-sm); - background: var(--color-canvas); - color: var(--color-text-body); - font-size: 0.8rem; } .ss-toolbar__input--font { @@ -85,15 +64,6 @@ cursor: pointer; } -.ss-toolbar__clear { - padding: 0 4px; - border: 0; - background: none; - color: var(--color-text-secondary); - font-size: 0.72rem; - cursor: pointer; -} - .ss-toolbar__popover { position: absolute; top: calc(100% + 4px); @@ -138,7 +108,7 @@ .ss-toolbar__unit-label { margin-bottom: var(--spacing-4); color: var(--color-text-muted); - font-size: 0.72rem; + font-size: var(--text-caption); } .ss-toolbar__unit-grid { @@ -147,9 +117,9 @@ gap: var(--spacing-4); } -.ss-toolbar__unit-btn { +.ss-toolbar__unit-grid > .ui-btn[data-size] { min-width: 0; - padding: 4px 2px; + padding-inline: 2px; } .ss-toolbar__hint { @@ -232,15 +202,6 @@ font: inherit; } -.ss-tabs__add { - padding: 2px 8px; - border: 1px solid var(--color-border); - border-radius: var(--radius-sm); - background: var(--color-canvas); - color: var(--color-text-secondary); - cursor: pointer; -} - /* ── 우클릭 메뉴(그리드 · 탭 공용, `ui_template_context_menu.ts`) — 모양 · 자리는 공용 `.ui-ctx-menu` ── */ .ss__context-menu-item.is-danger { @@ -261,7 +222,7 @@ display: flex; align-items: center; justify-content: center; - background: rgb(0 0 0 / 35%); + background: var(--color-scrim); } .ss-comment-editor__panel { diff --git a/A00_Common/spreadsheet/spreadsheet_toolbar.ts b/A00_Common/spreadsheet/spreadsheet_toolbar.ts index d9fccdb72..7ebda5a32 100644 --- a/A00_Common/spreadsheet/spreadsheet_toolbar.ts +++ b/A00_Common/spreadsheet/spreadsheet_toolbar.ts @@ -10,7 +10,7 @@ * 스스로 구독하지 않음. `destroy()` 는 부품을 뗄 때. * ========================================================================== */ -import { createButton, el } from "@ui/ui_template_elements"; +import { createButton, createIconButton, el, setUiSize } from "@ui/ui_template_elements"; import { confirmMerge } from "./spreadsheet_actions"; import { colName, rangeToA1, toA1 } from "./spreadsheet_address"; import { shownHAlign, shownVAlign } from "./spreadsheet_cellstyle"; @@ -144,14 +144,25 @@ export function mountToolbar(ctx: SpreadsheetContext): PartHandle { }; // ── 되돌리기 · 다시 ──────────────────────────────────────────────────── - const undoBtn = createButton({ label: "↶", variant: "ghost", onClick: () => ctx.undo() }); + const undoBtn = createButton({ + label: "↶", + variant: "ghost", + size: 24, + onClick: () => ctx.undo(), + }); undoBtn.title = st("Undo"); - const redoBtn = createButton({ label: "↷", variant: "ghost", onClick: () => ctx.redo() }); + const redoBtn = createButton({ + label: "↷", + variant: "ghost", + size: 24, + onClick: () => ctx.redo(), + }); redoBtn.title = st("Redo"); // 손가락 — 우클릭 대신 활성 칸 메뉴를 여는 ⋯(기기대응 3-5 · 터치 모드에서만 보임) const moreBtn = createButton({ label: "⋯", variant: "ghost", + size: 24, onClick: () => { const { r, c } = ctx.selection.활성; const { box } = ctx.grid.editorSlot(r, c); @@ -175,7 +186,7 @@ export function mountToolbar(ctx: SpreadsheetContext): PartHandle { // ── 글꼴 · 크기 ──────────────────────────────────────────────────────── const fontInput = el("input", { - className: "ss-toolbar__input ss-toolbar__input--font", + className: "ui-input ss-toolbar__input ss-toolbar__input--font", attrs: { list: "ss-toolbar-fonts", "aria-label": st("FontName") }, }) as HTMLInputElement; const fontList = el("datalist", { @@ -187,7 +198,7 @@ export function mountToolbar(ctx: SpreadsheetContext): PartHandle { fontInput.addEventListener("change", commitFont); const sizeInput = el("input", { - className: "ss-toolbar__input ss-toolbar__input--size", + className: "ui-input ss-toolbar__input ss-toolbar__input--size", attrs: { type: "number", min: "1", max: "409", step: "0.5", "aria-label": st("FontSize") }, }) as HTMLInputElement; sizeInput.addEventListener("change", () => { @@ -196,13 +207,13 @@ export function mountToolbar(ctx: SpreadsheetContext): PartHandle { }); // ── 굵게 · 기울임 · 밑줄 · 취소선 ────────────────────────────────────── - const boldBtn = createButton({ label: "B", variant: "ghost" }); + const boldBtn = createButton({ label: "B", variant: "ghost", size: 24 }); boldBtn.title = st("Bold"); - const italicBtn = createButton({ label: "I", variant: "ghost" }); + const italicBtn = createButton({ label: "I", variant: "ghost", size: 24 }); italicBtn.title = st("Italic"); - const underlineBtn = createButton({ label: "U", variant: "ghost" }); + const underlineBtn = createButton({ label: "U", variant: "ghost", size: 24 }); underlineBtn.title = st("Underline"); - const strikeBtn = createButton({ label: "S", variant: "ghost" }); + const strikeBtn = createButton({ label: "S", variant: "ghost", size: 24 }); strikeBtn.title = st("Strike"); const toggles: [HTMLButtonElement, keyof CellStyle][] = [ [boldBtn, "굵게"], @@ -220,11 +231,8 @@ export function mountToolbar(ctx: SpreadsheetContext): PartHandle { attrs: { type: "color", "aria-label": st("TextColor"), value: "#000000" }, }) as HTMLInputElement; textColor.addEventListener("change", () => patch({ 글자색: textColor.value })); - const textColorClear = el("button", { - className: "ss-toolbar__clear", - text: "✕", - attrs: { type: "button", title: st("ColorClear") }, - }); + const textColorClear = createIconButton({ glyph: "✕", title: st("ColorClear"), size: 18 }); + textColorClear.classList.add("ss-toolbar__clear"); textColorClear.addEventListener("click", () => patch({ 글자색: null })); const fillColor = el("input", { @@ -232,11 +240,8 @@ export function mountToolbar(ctx: SpreadsheetContext): PartHandle { attrs: { type: "color", "aria-label": st("FillColor"), value: "#ffffff" }, }) as HTMLInputElement; fillColor.addEventListener("change", () => patch({ 채움: fillColor.value })); - const fillColorClear = el("button", { - className: "ss-toolbar__clear", - text: "✕", - attrs: { type: "button", title: st("ColorClear") }, - }); + const fillColorClear = createIconButton({ glyph: "✕", title: st("ColorClear"), size: 18 }); + fillColorClear.classList.add("ss-toolbar__clear"); fillColorClear.addEventListener("click", () => patch({ 채움: null })); // ── 가로 · 세로 정렬 · 줄 바꿈 ───────────────────────────────────────── @@ -255,7 +260,7 @@ export function mountToolbar(ctx: SpreadsheetContext): PartHandle { } as const; const hAlignSelect = el("select", { - className: "ss-toolbar__select", + className: "ui-select ss-toolbar__select", attrs: { "aria-label": st("HAlign") }, children: (Object.keys(HALIGN_LABEL) as (keyof typeof HALIGN_LABEL)[]).map((v) => el("option", { attrs: { value: v }, text: HALIGN_LABEL[v] }), @@ -266,7 +271,7 @@ export function mountToolbar(ctx: SpreadsheetContext): PartHandle { ); const vAlignSelect = el("select", { - className: "ss-toolbar__select", + className: "ui-select ss-toolbar__select", attrs: { "aria-label": st("VAlign") }, children: (Object.keys(VALIGN_LABEL) as (keyof typeof VALIGN_LABEL)[]).map((v) => el("option", { attrs: { value: v }, text: VALIGN_LABEL[v] }), @@ -276,11 +281,11 @@ export function mountToolbar(ctx: SpreadsheetContext): PartHandle { patch({ 세로: vAlignSelect.value as CellStyle["세로"] }), ); - const wrapBtn = createButton({ label: st("Wrap"), variant: "ghost" }); + const wrapBtn = createButton({ label: st("Wrap"), variant: "ghost", size: 24 }); wrapBtn.addEventListener("click", () => patch({ 줄바꿈: !wrapBtn.classList.contains("is-on") })); // ── 병합 ─────────────────────────────────────────────────────────────── - const mergeBtn = createButton({ label: st("Merge"), variant: "ghost" }); + const mergeBtn = createButton({ label: st("Merge"), variant: "ghost", size: 24 }); mergeBtn.addEventListener("click", async () => { const range = ctx.selection.범위[0]; if (!range) return; @@ -290,10 +295,10 @@ export function mountToolbar(ctx: SpreadsheetContext): PartHandle { }); // ── 테두리 ─────────────────────────────────────────────────────────── - const borderBtn = createButton({ label: st("Border"), variant: "ghost" }); + const borderBtn = createButton({ label: st("Border"), variant: "ghost", size: 24 }); const borderPop = el("div", { className: "ss-toolbar__popover", attrs: { hidden: "true" } }); const lineSelect = el("select", { - className: "ss-toolbar__select", + className: "ui-select ss-toolbar__select", children: BORDER_LINES.map((v) => el("option", { attrs: { value: v }, text: v })), }) as HTMLSelectElement; const lineColor = el("input", { @@ -314,6 +319,7 @@ export function mountToolbar(ctx: SpreadsheetContext): PartHandle { const b = createButton({ label, variant: "ghost", + size: 24, onClick: () => { applyBorderPreset(preset); borderPop.hidden = true; @@ -393,7 +399,7 @@ export function mountToolbar(ctx: SpreadsheetContext): PartHandle { // ── 숫자 형식 ───────────────────────────────────────────────────────── const numfmtInput = el("input", { - className: "ss-toolbar__input ss-toolbar__input--numfmt", + className: "ui-input ss-toolbar__input ss-toolbar__input--numfmt", attrs: { list: "ss-toolbar-numfmt", "aria-label": st("NumberFormat"), @@ -414,7 +420,7 @@ export function mountToolbar(ctx: SpreadsheetContext): PartHandle { numfmtInput.addEventListener("change", () => patch({ 형식: numfmtInput.value || null })); // ── 단위 기호 ───────────────────────────────────────────────────────── - const unitBtn = createButton({ label: `${st("Unit")} ▾`, variant: "ghost" }); + const unitBtn = createButton({ label: `${st("Unit")} ▾`, variant: "ghost", size: 24 }); const unitPop = el("div", { className: "ss-toolbar__popover ss-toolbar__unit-pop", attrs: { hidden: "true" }, @@ -472,7 +478,12 @@ export function mountToolbar(ctx: SpreadsheetContext): PartHandle { recentGrid.textContent = ""; recentSection.hidden = list.length === 0; for (const u of list) { - const b = createButton({ label: u, variant: "ghost", onClick: () => insertUnit(u) }); + const b = createButton({ + label: u, + variant: "ghost", + size: 24, + onClick: () => insertUnit(u), + }); b.className += " ss-toolbar__unit-btn"; recentGrid.append(b); } @@ -483,7 +494,12 @@ export function mountToolbar(ctx: SpreadsheetContext): PartHandle { for (const [labelKey, items] of UNIT_GROUPS) { const grid = el("div", { className: "ss-toolbar__unit-grid" }); for (const u of items) { - const b = createButton({ label: u, variant: "ghost", onClick: () => insertUnit(u) }); + const b = createButton({ + label: u, + variant: "ghost", + size: 24, + onClick: () => insertUnit(u), + }); b.className += " ss-toolbar__unit-btn"; grid.append(b); } @@ -536,6 +552,8 @@ export function mountToolbar(ctx: SpreadsheetContext): PartHandle { group(unitBtn, unitPop), formulaHint, ); + // 칸 크기 단(553-6) — 단추 24 · 칸 28 + for (const f of root.querySelectorAll(".ui-input, .ui-select")) setUiSize(f, 28); function refresh(): void { undoBtn.disabled = !ctx.history.canUndo();