/* ============================================================================= * M01_MasterData_UI_LogicLab_Flow.ts * 로직 상세 두 칸 — 왼쪽 지금 내용(보기) · 가운데 끌기 막대 · 오른쪽 흐름도 자리(패널은 LogicLab 이 붙임) * 너비 비율은 브라우저에 기억(localStorage · 막히면 기본 반반). 정함 `docs/raw/M01_쉬운단가/흐름도_적용_정함.md` 5 · 10 * ========================================================================== */ import { currentLanguageIndex } from "@ui/ui_template_locale"; import { el } from "@ui/ui_template_elements"; import "./M01_MasterData_UI_LogicLab_Flow.css"; const TEXT = { Resize: ["두 칸 너비 — 끌어서 조절", "Drag to resize the two columns"], Waiting: ["흐름도 자리", "Flow diagram"], } as const; export const tf = (key: keyof typeof TEXT): string => TEXT[key][currentLanguageIndex === 1 ? 1 : 0]; const STORE = "m01.logic.flowRatio"; const MIN = 0.25; const MAX = 0.75; const clamp = (r: number): number => Math.min(MAX, Math.max(MIN, r)); function readRatio(): number { try { const r = Number(localStorage.getItem(STORE)); return r ? clamp(r) : 0.5; } catch { return 0.5; } } export interface SplitHandle { root: HTMLElement; /** 오른쪽 칸 — 흐름도 패널을 붙이는 곳 */ right: HTMLElement; } /** 두 칸 만들기 — left 는 지금 화면 그대로 왼쪽에 둠 */ export function buildSplit(left: HTMLElement): SplitHandle { const right = el("div", { className: "m01lab-flow__right", children: [el("p", { className: "m01lab-flow__wait", text: tf("Waiting") })], }); const bar = el("div", { className: "m01lab-flow__bar", attrs: { role: "separator", "aria-orientation": "vertical", "aria-label": tf("Resize"), title: tf("Resize"), tabindex: "0", }, }); const leftCol = el("div", { className: "m01lab-flow__left", children: [left] }); const root = el("div", { className: "m01lab-flow", children: [leftCol, bar, right] }); let ratio = readRatio(); const apply = (): void => { root.style.gridTemplateColumns = `minmax(0, ${ratio}fr) auto minmax(0, ${1 - ratio}fr)`; }; const keep = (): void => { try { localStorage.setItem(STORE, String(ratio)); } catch { /* 기억 못 해도 지금 화면은 그대로 */ } }; bar.addEventListener("pointerdown", (ev) => { if (ev.button !== 0) return; ev.preventDefault(); const box = root.getBoundingClientRect(); const move = (m: PointerEvent): void => { ratio = clamp((m.clientX - box.left) / box.width); apply(); }; const up = (): void => { window.removeEventListener("pointermove", move); window.removeEventListener("pointerup", up); keep(); }; window.addEventListener("pointermove", move); window.addEventListener("pointerup", up); }); // 키보드 — 왼쪽 · 오른쪽 화살표로 조금씩 bar.addEventListener("keydown", (ev) => { const step = ev.key === "ArrowLeft" ? -0.05 : ev.key === "ArrowRight" ? 0.05 : 0; if (!step) return; ev.preventDefault(); ratio = clamp(ratio + step); apply(); keep(); }); apply(); return { root, right }; }