/* ============================================================================= * M02_DF_PillPanel.ts * 상세 내용 판 — 알약: 알약을 고르면 이름 · 값 · 단위 · 온 길(출처 사슬) · 가는 곳(이어진 선 · 받는 상자) · 끊김 까닭 * 모양은 `docs/raw/M01_쉬운단가/흐름도_정함.md` 정함 8 · 9 · M02_DF_Model 의 CfStep 그대로 · 읽기만(고치기는 선 · 상자 판에서) * 글 [한, 영] 짝은 아래 TEXT * ========================================================================== */ import { currentLanguageIndex } from "@ui/ui_template_locale"; import { createButton, el } from "@ui/ui_template_elements"; import type { CfLogic, CfStep } from "./M02_DF_Model"; import { boxOf, breakLines, evalSafe, isOut, labelOf, portText, showValue, trace, unitOf, valueOf, type DetailOptions, } from "./M02_DF_Detail"; import "./M02_DF_LinkPanel.css"; const TEXT = { Name: ["이름", "Name"], Value: ["값", "Value"], Unit: ["단위", "Unit"], Kind_out: ["내보내는 알약", "Sending pill"], Kind_in: ["받는 알약", "Receiving pill"], From: ["온 길", "Where it came from"], To: ["가는 곳", "Where it goes"], Start: ["여기서 시작 — 더 거슬러 갈 곳이 없음", "It starts here — nothing before it"], End: ["여기가 끝 — 더 가는 곳이 없음", "It ends here — nothing after it"], Breaks: ["끊긴 곳", "Breaks"], NoBreak: ["끊긴 곳 없음", "No breaks"], Open: ["이 상자 보기", "Open this box"], Line: ["선", "Line"], } as const; const tp = (key: keyof typeof TEXT): string => TEXT[key][currentLanguageIndex === 1 ? 1 : 0]; const line = (label: string, ...value: (HTMLElement | string)[]): HTMLElement => el("div", { className: "m02-dflink-row", children: [el("span", { className: "m02-dflink-label", text: label }), ...value], }); function steps( lg: CfLogic, list: CfStep[], arrow: string, empty: string, onBox?: (id: string) => void, ): HTMLElement { if (!list.length) return el("p", { className: "m02-dflink-note", text: empty }); return el("ol", { className: "m02-dfpill-list", children: list.map((s) => { const parts: (HTMLElement | string)[] = [ arrow, onBox ? createButton({ label: portText(lg, { box: s.box, name: s.port }), variant: "ghost", size: "sm", onClick: () => onBox(s.box), }) : portText(lg, { box: s.box, name: s.port }), ]; if (s.rule) parts.push(el("span", { className: "m02-dfpill-rule", text: labelOf(s.rule) })); return el("li", { className: "m02-dfpill-step", children: parts }); }), }); } /** 알약 판 그리기 — 알약을 고르면 부름 · on.pick 이 있으면 줄의 상자 이름을 눌러 그 상자로 감 */ export function renderPillPanel( host: HTMLElement, lg: CfLogic, boxId: string, port: string, on: { pick?(boxId: string): void } = {}, opts: DetailOptions = {}, ): void { host.classList.add("m02-dfpill"); const box = boxOf(lg, boxId); if (!box) return host.replaceChildren(); const ev = evalSafe(lg, opts); const out = isOut(box, port); // 받는 알약의 값 = 선 규칙을 지나 실제로 들어온 값(없으면 보낸 알약 값) const incoming = lg.links.find((l) => l.to.box === boxId && l.to.name === port); const value = out ? valueOf(ev, { box: boxId, name: port }) : (ev?.arrived?.[boxId]?.[port] ?? (incoming ? valueOf(ev, incoming.from) : undefined)); const unit = out ? unitOf(lg, { box: boxId, name: port }) : incoming ? unitOf(lg, incoming.from) : box.unit; const back = trace(lg, { box: boxId, name: port }, "in"); const forward = trace(lg, { box: boxId, name: port }, "out"); const breaks = breakLines(lg, boxId, port, opts); host.replaceChildren( el("div", { className: "m02-dflink-head", children: [ el("strong", { className: "m02-dfpill-title", text: `${box.name} › ${port}` }), el("span", { className: "m02-dflink-note", text: tp(out ? "Kind_out" : "Kind_in") }), ], }), line(tp("Name"), port), line(tp("Value"), el("span", { className: "m02-dflink-value", text: showValue(value) })), line(tp("Unit"), unit || "-"), el("div", { children: [ el("div", { className: "m02-dflink-label", text: tp("From") }), steps(lg, back, "◀", tp("Start"), on.pick), ], }), el("div", { children: [ el("div", { className: "m02-dflink-label", text: tp("To") }), steps(lg, forward, "▶", tp("End"), on.pick), ], }), el("div", { children: [ el("div", { className: "m02-dflink-label", text: tp("Breaks") }), ...(breaks.length ? breaks.map((b) => el("p", { className: "m02-dflink-warn", text: `⚠ ${b}` })) : [el("p", { className: "m02-dflink-note", text: tp("NoBreak") })]), ], }), ); }