style(spreadsheet): 도구줄 단추 · 칸 · 시트 탭 [+] 를 부품 단추 24 · 입력 · 고르기 28 · 아이콘 단추로 (PLAN 553-6)

- 도구줄 단추 23 → 부품 단추 24 · 글꼴 · 크기 · 표시 형식 칸 → 부품 입력 28 · 정렬 고르기 → 부품 고르기 28
- 색 지우기 ✕ → 아이콘 단추 18 · 시트 탭 [+] → 아이콘 단추(선) 22 · 켬(is-on) 색 = 공통 값(옛 보라 별칭 걷음)
- 메모 창 뒷막 = --color-scrim · 자체 단추 · 칸 CSS 지움(폭만 남김)
- 격자 · 시트 탭 꼴 · 배치 그대로 — 도구줄 안 단추만 3 px 넓어짐(줄바꿈 0)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-26 22:00:37 +09:00
co-authored by Claude Opus 5.5
parent 9729892a3d
commit 2033125fec
3 changed files with 61 additions and 80 deletions
+7 -5
View File
@@ -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);
+7 -46
View File
@@ -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 {
+47 -29
View File
@@ -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<HTMLElement>(".ui-input, .ui-select")) setUiSize(f, 28);
function refresh(): void {
undoBtn.disabled = !ctx.history.canUndo();