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();