/* ============================================================================= * M02_DF_InputPanel_Logic.ts * 입력 판 — 입력 갈래 「다른 로직」: 저장한 흐름도 로직(또는 견본)을 찾아 고르면 * 그 로직의 출력 = 내보내는 알약 · 설계 때 정할 것 = 받는 알약(이어 주지 않으면 그 로직의 예시값) * 글 [한, 영] 짝은 아래 TEXT · 단추는 공용 작은 크기 * ========================================================================== */ import { currentLanguageIndex } from "@ui/ui_template_locale"; import { createButton, createInputField, el, showToast } from "@ui/ui_template_elements"; import { cfGet, cfList, cfPlain, type CfListItem } from "./M02_DF_Api"; import type { CfLogic } from "./M02_DF_Model"; import { logicRefOf, setKind, setLogicInput } from "./M02_DF_InputPanel_Build"; const TEXT = { Help: [ "저장한 로직이나 견본을 불러와 그 결과를 이 상자의 알약으로 씀", "Use a saved logic or sample as an input", ], Search: ["로직 이름으로 찾기", "Search by name"], Loading: ["찾는 중…", "Searching…"], None: ["찾는 로직 없음", "No logic found"], Sample: ["견본", "Sample"], Mine: ["내가 만든 것", "Mine"], Chosen: ["고른 로직", "Chosen logic"], Outs: ["내보내는 알약 — 그 로직의 출력", "Pills it sends — its outputs"], Designs: [ "받는 알약 — 그 로직의 설계 때 정할 것(이어 주지 않으면 그 로직의 예시값)", "Pills it takes — its design inputs", ], NoOut: ["출력 상자가 없음", "No output box"], NoDesign: ["설계 때 정할 것이 없음", "Nothing to decide"], Change: ["다른 로직 고르기", "Pick another"], Remove: ["빼기", "Remove"], Self: ["이 로직 자신은 못 씀", "Can't use itself"], Failed: ["불러오지 못함", "Could not load"], } as const; type TKey = keyof typeof TEXT; const t = (key: TKey): string => TEXT[key][currentLanguageIndex] as string; const plain = (e: unknown): string => { try { return cfPlain(e); } catch { return e instanceof Error ? e.message : t("Failed"); } }; /** 다른 로직 입력 판 */ export function renderLogicInput( host: HTMLElement, lg: CfLogic, boxId: string, on: { change(lg: CfLogic): void }, ): void { const ref = lg.boxes.find((b) => b.id === boxId)?.input?.logic; if (ref) return void showChosen(host, lg, boxId, ref, on); const q = createInputField({ type: "search", placeholder: t("Search"), compact: true }); const list = el("div", { className: "m02-dfip__list" }); let all: CfListItem[] = []; const draw = (): void => { const word = q.input.value.trim().toLowerCase(); const rows = all.filter( (i) => i.key !== lg.key && (!word || i.name.toLowerCase().includes(word)), ); list.replaceChildren( ...(rows.length ? rows.map((i) => { const b = el("button", { className: "m02-dfip__row", attrs: { type: "button" }, children: [ el("span", { className: "m02-dfip__name", children: [ el("strong", { text: i.name }), el("span", { className: "m02-dfip__tag", text: i.sample ? t("Sample") : t("Mine"), }), ], }), el("span", { className: "m02-dfip__muted", text: i.resultUnit }), ], }); b.addEventListener("click", () => void pick(i)); return b; }) : [el("p", { className: "m02-dfip__muted", text: t("None") })]), ); }; const pick = async (i: CfListItem): Promise => { try { const other = await cfGet(i.key); const next = setLogicInput(lg, boxId, logicRefOf(i.key, other)); // 기본 이름이면 고른 로직 이름으로 on.change({ ...next, boxes: next.boxes.map((b) => b.id === boxId && /^(입력|새)/.test(b.name) ? { ...b, name: other.name || b.name } : b, ), }); } catch (e) { showToast(plain(e), "error"); } }; q.input.addEventListener("input", draw); list.replaceChildren(el("p", { className: "m02-dfip__muted", text: t("Loading") })); host.replaceChildren(el("p", { className: "m02-dfip__muted", text: t("Help") }), q.root, list); void cfList().then( (items) => ((all = items), draw()), (e) => list.replaceChildren(el("p", { className: "m02-dfip__muted", text: plain(e) })), ); } /** 고른 로직 — 내보내는 알약 · 받는 알약 */ function showChosen( host: HTMLElement, lg: CfLogic, boxId: string, ref: NonNullable["logic"], on: { change(lg: CfLogic): void }, ): void { if (!ref) return; const pillLine = (p: { name: string; unit: string }): HTMLElement => el("div", { className: "m02-dfip__item", children: [ el("span", { className: "m02-dfip__name", text: p.name }), el("span", { className: "m02-dfip__muted", text: p.unit || "-" }), ], }); host.replaceChildren( el("h5", { text: `${t("Chosen")} — ${ref.name ?? ref.key}` }), el("h5", { text: `${t("Outs")} · ${ref.outputs.length}` }), ...(ref.outputs.length ? ref.outputs.map(pillLine) : [el("p", { className: "m02-dfip__muted", text: t("NoOut") })]), el("h5", { text: `${t("Designs")} · ${ref.designs.length}` }), ...(ref.designs.length ? ref.designs.map(pillLine) : [el("p", { className: "m02-dfip__muted", text: t("NoDesign") })]), el("div", { className: "m02-dfip__chips", children: [ createButton({ label: t("Change"), variant: "ghost", size: "sm", onClick: () => on.change(setKind(lg, boxId, "다른 로직")), }), createButton({ label: t("Remove"), variant: "ghost", size: "sm", onClick: () => on.change(setLogicInput(lg, boxId, null)), }), ], }), ); }