feat(748-2): 텍스트 수식 — 행 고르기 걷음 · 변수 이름 · 값 하나하나 누르면 줄 모달(748-1) · 줄마다 옵션 값 칩 걷음(748-3 한 조각)
- 텍스트 수식 줄 hover · 누름 고정(행 단위 선택) 걷음 - 변수 이름 식 = 변수 이름마다 낮은 단추 · 값 든 식 = 수 하나하나 낮은 단추 → 같은 줄의 상세 모달(적용 · 삭제 · 닫기) - 변수가 시험 입력(옵션)이면 옵션 고르기 칩으로 - 공용 상세 `lineOpener` 새로 — M02 SK 상세 · M01 단가산출 기초 같은 길(M01 = 시험 고침 고리) - 상세 보기 줄마다 붙던 옵션 값 칩(`쓰는입력`) 걷음 — 위 옵션 칸이 대신(748-3) - 새 파일 `LogicLab_FormulaTokens`(조각 나누기 순수 셈) · 시험 test_748_2 · 낡은 시험 고침 test_722(inputChip 줄 걷음) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ import { optionGrid, varRow } from "../A00_Common/calc_sheet";
|
||||
import { formatMoney } from "./M01_MasterData_UI_Logic_Money";
|
||||
import { safeReason, tx } from "./M01_MasterData_UI_Logic_Text";
|
||||
import { tl } from "./M01_MasterData_UI_LogicLab_Text";
|
||||
import { nameTokens, tokenRow, valueTokens } from "./M01_MasterData_UI_LogicLab_FormulaTokens";
|
||||
import "./M01_MasterData_UI_LogicLab_Formula.css";
|
||||
|
||||
/** 로직 열자마자 값 없이 부른 미리보기 응답은 `계산됨` 을 false 로 표시 — [계산] 을 거친 응답은 안 붙어 true 취급 */
|
||||
@@ -26,6 +27,8 @@ export interface FormulaContext {
|
||||
inputs?: LogicInput[];
|
||||
values?: Record<string, string>;
|
||||
onInput?: (name: string, value: string) => void;
|
||||
/** 748-2 줄 → 그 줄 자료 모달 열기(변수 · 값을 누르면) — 없으면 글자만 */
|
||||
open?: (line: TextLine) => (() => void) | undefined;
|
||||
}
|
||||
|
||||
/* ── 순수 셈: 줄이 쓰는 입력 ── */
|
||||
@@ -128,7 +131,6 @@ export function buildFormula(host: HTMLElement, ctx: FormulaContext): void {
|
||||
el("strong", { text: tl("Formula_Right") }),
|
||||
],
|
||||
});
|
||||
const rows: HTMLElement[] = [];
|
||||
const specs = ctx.onInput ? (ctx.inputs ?? []) : [];
|
||||
// 737-2 옵션 칸 = 비목 상자 맨 위 — 그 상자 줄이 쓰는 입력 + 어느 줄도 안 쓰는 입력(공통 · 737-3)
|
||||
const names = specs.map((x) => x.이름);
|
||||
@@ -149,22 +151,41 @@ export function buildFormula(host: HTMLElement, ctx: FormulaContext): void {
|
||||
);
|
||||
};
|
||||
const calculated = text.계산됨 !== false; // [계산] 뒤 응답은 표식이 안 붙음 — 미리보기만 false
|
||||
const light = (pair: string, on: boolean): void =>
|
||||
rows.forEach((r) => r.dataset.pair === pair && r.classList.toggle("is-on", on));
|
||||
const onInput = ctx.onInput;
|
||||
/** 변수 이름이 시험 입력이면 옵션 고르기 · 아니면 그 줄 모달 */
|
||||
const spec = (name: string): LogicInput | undefined =>
|
||||
onInput ? specs.find((x) => x.이름 === name) : undefined;
|
||||
// 737-2 비목마다 구분 상자 — 맨 위 옵션 칸 · 아래 두 칸 식 줄들 · 소계
|
||||
const boxes = text.groups.map((g) => {
|
||||
const lines = g.줄.map((line, i) => {
|
||||
const pair = String(line.짝 ?? `${g.비목}${i}`);
|
||||
const row = el("div", {
|
||||
const open = ctx.open?.(line);
|
||||
return el("div", {
|
||||
className: `m01lab-fx__row m01lab__text${line.까닭 ? " m01lab__text--off" : ""}`,
|
||||
attrs: { "data-text-line": line.이름, "data-pair": pair },
|
||||
children: [
|
||||
el("div", { className: "m01lab-fx__cell", text: line.이름글 ?? line.이름 }),
|
||||
el("div", {
|
||||
className: "m01lab-fx__cell",
|
||||
children: [
|
||||
tokenRow(nameTokens(line.이름글 ?? line.이름), open, (name) => {
|
||||
const s = spec(name);
|
||||
return s && onInput
|
||||
? inputChip(s, ctx.values?.[name] ?? "", (v) => onInput(name, v))
|
||||
: null;
|
||||
}),
|
||||
],
|
||||
}),
|
||||
el("div", {
|
||||
className: "m01lab-fx__cell",
|
||||
children: calculated
|
||||
? [
|
||||
el("div", { text: `${line.이름} : ${line.글}` }),
|
||||
el("div", {
|
||||
className: "m01lab-fx__val",
|
||||
children: [
|
||||
el("span", { text: `${line.이름} :` }),
|
||||
tokenRow(valueTokens(line.글), open),
|
||||
],
|
||||
}),
|
||||
...(line.까닭
|
||||
? [
|
||||
el("div", {
|
||||
@@ -178,15 +199,6 @@ export function buildFormula(host: HTMLElement, ctx: FormulaContext): void {
|
||||
}),
|
||||
],
|
||||
});
|
||||
row.addEventListener("mouseenter", () => light(pair, true));
|
||||
row.addEventListener("mouseleave", () => light(pair, false));
|
||||
row.addEventListener("click", () => {
|
||||
const pinned = row.classList.toggle("is-pin");
|
||||
rows.forEach((r) => r !== row && r.classList.remove("is-pin"));
|
||||
if (!pinned) row.classList.remove("is-pin");
|
||||
});
|
||||
rows.push(row);
|
||||
return row;
|
||||
});
|
||||
const card = createCard({
|
||||
title: g.비목,
|
||||
|
||||
Reference in New Issue
Block a user