/* ============================================================================= * design_dock.ts * B05 · B06 한 페이지 두 보기의 **좌측 패널 맨 아래 고정 영역**(계획서 24-1 · 24-2b). * * 구성 = [위에 놓을 것(구조물 목록)][구분선][단추 행]. 단추 넷은 두 보기가 **같다**: * [초기화] [저장] [확정] [보기 전환](종단 보기에서는 「횡단 보기」 · 횡단 보기에서는 * 「종단 보기」). 누르면 무엇을 하는지는 페이지가 `DesignDockActions` 로 건넨다 — 이 파일은 * 단추를 만들고 켜고 끄기만 한다(저장 흐름은 `design_save.ts` 몫). * ========================================================================== */ import { createButton } from "@ui/ui_template_elements"; import { currentLanguageIndex, ui_locales } from "@ui/ui_template_locale"; import "./design_dock.css"; /** 보기 이름 — 종단 보기(3D + 종단도) · 횡단 보기(종단도 + 횡단 카드). */ export type DesignView = "profile" | "cross"; /** 단추 하나의 동작 — `enabled` 가 거짓이면 눌리지 않고 `title` 이 까닭을 알린다. */ export interface DesignDockAction { run: () => void | Promise; enabled?: boolean; title?: string; } export interface DesignDockActions { reset: DesignDockAction; save: DesignDockAction; confirm: DesignDockAction; /** [보기 전환] — 지금은 주소 이동이다(2단계에서 같은 페이지 안 전환으로 바뀜). */ switchView: DesignDockAction; } export interface DesignDock { root: HTMLElement; /** 단추 넷의 켬·끔·설명을 다시 준다(자료가 늦게 오는 페이지가 부름). */ setActions: (actions: Partial) => void; /** 보기가 바뀌면 [보기 전환] 글자가 따라 바뀐다. */ setView: (view: DesignView) => void; } function label(key: keyof typeof ui_locales): string { return ui_locales[key][currentLanguageIndex]; } /** 보기 전환 단추 글자 — 가려는 **쪽** 이름이다. */ export function switchViewLabel(view: DesignView): string { return label(view === "profile" ? "Design_Btn_ToCross" : "Design_Btn_ToProfile"); } /** * 아래 고정 영역을 만든다. `above` 는 단추 행 위에 놓을 것(구조물 목록) — 목록을 「구조물 배치」 * 본문에 두면 고른 구조물의 폼 길이에 밀려 화면 밖으로 나갔다(2026-08-18 사용자 지시). */ export function createDesignDock( view: DesignView, above: ReadonlyArray, initial: DesignDockActions, ): DesignDock { let current = view; let actions = { ...initial }; const root = document.createElement("div"); root.className = "b05-route__dock ui-sidebar-actions"; const divider = document.createElement("hr"); divider.className = "b05-structure__divider"; const row = document.createElement("div"); row.className = view === "profile" ? "b05-route__actions" : "b06-profile__actions"; const press = (name: keyof DesignDockActions) => (): void => { void Promise.resolve(actions[name].run()); }; const resetButton = createButton({ label: label("Common_Btn_Reset"), variant: "danger", onClick: press("reset"), }); const saveButton = createButton({ label: label("B06_Profile_Btn_Save"), variant: "ghost", onClick: press("save"), }); const confirmButton = createButton({ label: label("B06_Profile_Btn_Confirm"), variant: "filled", onClick: press("confirm"), }); const switchButton = createButton({ label: switchViewLabel(view), variant: "ghost", onClick: press("switchView"), }); resetButton.dataset.dockAction = "reset"; saveButton.dataset.dockAction = "save"; confirmButton.dataset.dockAction = "confirm"; switchButton.dataset.dockAction = "switchView"; const buttons = { reset: resetButton, save: saveButton, confirm: confirmButton, switchView: switchButton, }; const sync = (): void => { (Object.keys(buttons) as Array).forEach((name) => { const action = actions[name]; buttons[name].disabled = action.enabled === false; if (action.title) buttons[name].title = action.title; else buttons[name].removeAttribute("title"); }); (switchButton.querySelector(".ui-btn__label") ?? switchButton).textContent = switchViewLabel(current); row.className = current === "profile" ? "b05-route__actions" : "b06-profile__actions"; }; row.append(resetButton, saveButton, confirmButton, switchButton); root.append(...above, divider, row); sync(); return { root, setActions: (next) => { actions = { ...actions, ...next }; sync(); }, setView: (next) => { current = next; sync(); }, }; }