- 「식으로 새로 만들기」 단추 · 화면 길 지움(LogicLab_New 다섯 파일 — 쓰는 곳 없음) - 「시험판 ▾」 메뉴 · 시험판 단추 둘(CostFlow · DataFlow 입구) · 가져오기 줄 지움 - 「본떠 만들기」 → 「로직 복사/생성」 · 단추 차례 = ← 로직 목록 · 로직 복사/생성 · 로직 지우기 · 고친 것 버리기 · 저장 - 로직 상세 두 칸(LogicLab_Flow) — 왼쪽 지금 내용 · 오른쪽 흐름도 자리 · 끌기 막대 · 너비 비율 기억(localStorage · 25~75%) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016PSXsvyDxjNmufteN5bqmt
96 lines
3.2 KiB
TypeScript
96 lines
3.2 KiB
TypeScript
/* =============================================================================
|
|
* 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 };
|
|
}
|