Files
Aislo/A00_Common/spreadsheet/spreadsheet_sheet_extra.ts
T
eomsangdonandClaude Sonnet 5.5 2a378eb5c8 fix(버튼): 357-3 서술형 버튼 이름 → 명사형 · 「단추」 → 「버튼」 (A06 · A07 · B01 · B03 · B09 · B11 · M01 · 열린 물음 · 스프레드시트 · 도움말)
- 저장 후 넘어감 → 저장 · 버리고 넘어감 → 폐기 · 다시 불러오기 → 새로고침 · 지우기 → 삭제 등
- test_303 · test_ui_loading 글 맞춤

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013QyNXY2TUKXCFMwAca2APG
2026-10-16 20:38:55 +09:00

114 lines
4.7 KiB
TypeScript

/* =============================================================================
* spreadsheet_sheet_extra.ts (3단계 · 주인 sub_laptop_4)
* 시트 숨기기 · 보이기 · 시트 탭 색. 저장 자리 `Sheet.숨김` · `Sheet.탭색`(0 계약에 방금 더함).
* 이 파일은 관리 창(전체 시트 목록 + 숨김 · 색 조작)만 그림 — 실제 탭 줄(`spreadsheet_tabs.ts`,
* E 파일)을 안 건드림.
*
* 잇는 법(E `spreadsheet_tabs.ts` · sub7 — 지금은 하나도 안 이어짐):
* 1) `mountTabs` 의 `render()` 가 `ctx.book.시트` 를 돌 때 `숨김` 인 시트는 탭을 안 그림.
* 2) 탭 엘리먼트에 `sheet.탭색` 이 있으면 밑줄 · 배경을 그 색으로(엑셀처럼).
* 3) 숨은 시트를 다시 보이려면 탭 우클릭 메뉴에 [숨긴 시트 보이기] 항목을 두고 이 파일의
* `createSheetExtraPanel(ctx)` 를 열거나, `showSheet(ctx, id)` 를 바로 부름.
* ========================================================================== */
import { createButton, el } from "@ui/ui_template_elements";
import type { Sheet } from "./spreadsheet_types";
import type { PartHandle, SpreadsheetContext } from "./spreadsheet_view_types";
// css 는 stage3.css 에 얹음(잇는 법 머리 참고) — 실제로 붙일 때 `import "./spreadsheet_stage3.css";` 더함.
function applySheet(ctx: SpreadsheetContext, sheetId: string, next: Sheet): void {
ctx.dispatch({ 종류: "시트통째", 시트: { ...next, id: sheetId } });
}
/** 시트를 숨김 — 마지막 보이는 시트는 못 숨김(까닭 글 돌려줌 · 되면 null). 활성 시트를 숨기면
* 다른 보이는 시트로 활성을 옮김. */
export function hideSheet(ctx: SpreadsheetContext, id: string): string | null {
const others = ctx.book.시트.filter((s) => s.id !== id && !s.숨김);
if (!others.length) return "마지막 보이는 시트는 못 숨김";
const sheet = ctx.book.시트.find((s) => s.id === id);
if (!sheet || sheet.숨김) return null;
applySheet(ctx, id, { ...sheet, 숨김: true });
if (ctx.book.활성 === id) ctx.showSheet(others[0].id);
return null;
}
/** 숨긴 시트를 다시 보임. */
export function unhideSheet(ctx: SpreadsheetContext, id: string): void {
const sheet = ctx.book.시트.find((s) => s.id === id);
if (!sheet || !sheet.숨김) return;
applySheet(ctx, id, { ...sheet, 숨김: false });
}
/** 탭 색 — `color` 가 null 이면 색을 지움(기본 탭 색으로). */
export function setSheetTabColor(ctx: SpreadsheetContext, id: string, color: string | null): void {
const sheet = ctx.book.시트.find((s) => s.id === id);
if (!sheet) return;
const next: Sheet = { ...sheet };
if (color) next.탭색 = color;
else delete next.탭색;
applySheet(ctx, id, next);
}
/** 시트 관리 창 — 전체 시트 목록 + 숨김 토글 · 탭 색 고르기. */
export function createSheetExtraPanel(ctx: SpreadsheetContext): PartHandle {
const root = el("div", { className: "ss-sheetextra" });
const list = el("ul", { className: "ss-sheetextra__list" });
let error: HTMLElement | null = null;
const showError = (msg: string | null): void => {
error?.remove();
error = null;
if (!msg) return;
error = el("p", { text: msg });
error.style.color = "var(--color-danger, red)";
root.append(error);
};
function render(): void {
list.replaceChildren(
...ctx.book.시트.map((sheet) => {
const li = el("li", { className: "ss-sheetextra__row" });
const label = el("span", { text: sheet.이름 + (sheet.숨김 ? "(숨김)" : "") });
const colorInput = el("input", {
attrs: { type: "color", value: sheet.탭색 ?? "#ffffff" },
}) as HTMLInputElement;
colorInput.addEventListener("change", () =>
setSheetTabColor(ctx, sheet.id, colorInput.value),
);
const colorClear = createButton({ label: "색 삭제", variant: "ghost" });
colorClear.addEventListener("click", () => {
setSheetTabColor(ctx, sheet.id, null);
render();
});
const toggle = createButton({
label: sheet.숨김 ? "보이기" : "숨기기",
variant: "ghost",
});
toggle.addEventListener("click", () => {
if (sheet.숨김) {
unhideSheet(ctx, sheet.id);
showError(null);
} else {
showError(hideSheet(ctx, sheet.id));
}
render();
});
li.append(label, colorInput, colorClear, toggle);
return li;
}),
);
}
root.append(el("h4", { text: "시트 관리" }), list);
render();
return {
root,
refresh: render,
destroy(): void {
root.remove();
},
};
}