feat(구조물표): 322-2 M02 표 화면 — 탭 셋(한눈 표 · 종류별 · 부품) · 반영 · 부품 · 알약 색 저장 · 목록 + enabled 함께 · 검사 짝(화면 = 서버 · 1-3 규칙 · 만든 뒤 고정) · 명세 폼 보임 따름 · 판 알림
- 한눈 표(M02_SO_Def_Table): 군 · 종류 ▲▼ · 이름 · 목록 · 자리꼴 · 정본(고정) · 횡단도 · 카드 이름 · 형상(+ 벽 기본 형태 · 물빼기) · 알약 색 · 3D · 검사 · 처음 값 = 흐림 「기본」 · 바꿈 = 진함 · [처음 값으로] - 종류별: 반영 칸 + 명세 이름 나무 줄마다 보임(컨테이너 = 그 안 칸) · 못 숨김 · 미리보기 숨김 따름 · 「안 씀」 = 목록 B06 만 - 부품 탭(M02_SO_Def_Parts): 부품 · 읽는 칸 · 자리꼴 · 정본 · 쓰는 종류 · 켬/끔(정의 부품 = 끈 것만) - 편집 손질(M02_SO_Def_Reflect): 처음 값이면 반영에서 지움 · [저장] 때 enabled = 목록 both 일 때만 참 - 검사 짝 M02_SO_Def_Check.ts ↔ M02_SO_Check.py(글까지 같음): 반영 · 부품 꼴 · 형상 none → 횡단도 none · 부품 자리꼴 · 정본 · 기본값 없는 읽는 칸 새로 숨김 금지(앞 판 숨김 그대로) · 종류 지우기 · 자리꼴 · 정본 · 군 글자 · 선택지 값 고정 · 서버 check(doc, 지금 판) · 앞 판 없으면 꼴만 - 명세 폼: 쓰는 옵션 키가 모두 숨긴 칸 · 상자는 안 그림(값 그대로) · B05 · B06 시설 · 구조물 명세 폼이 정의 「표시」를 따름 - 판 알림: GET 구조물 목록에 definition_version · structures.json 판 ≠ 지금 판이면 「구조물 정의가 판 N 으로 바뀜 — 저장하면 반영」 한 번 - 시험: test_322_2_check_mirror(거울 · 규칙 · 반영 손질 · 서버 저장 · 422) · 판 알림 · 옛 정의 화면 시험 = 선택지 값 대신 이름 표 · 못 숨김 아닌 칸 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD
This commit is contained in:
@@ -22,6 +22,8 @@ import {
|
||||
linkOf,
|
||||
readState,
|
||||
solveSplit,
|
||||
specContainerHidden,
|
||||
specItemHidden,
|
||||
TEXT_MAX,
|
||||
writeOptions,
|
||||
type SpecContainer,
|
||||
@@ -82,6 +84,8 @@ export interface SpecForm {
|
||||
groupNames?: Record<string, string>,
|
||||
/** 정의 기본값(저장 키 → 값) — 필수 상자 빈 고르기 칸이 받는 값(54-43). */
|
||||
defaults?: Record<string, string | number>,
|
||||
/** 숨긴 옵션 키(정의 「표시」 · 322-2) — 그 키만 쓰는 칸 · 상자는 안 그림(값은 그대로). */
|
||||
hidden?: ReadonlySet<string>,
|
||||
) => void;
|
||||
read: () => Record<string, string | number>;
|
||||
state: () => SpecState;
|
||||
@@ -104,6 +108,7 @@ export function createSpecForm(links: SpecLinks | null, hooks: SpecFormHooks = {
|
||||
let names: SpecNames = {};
|
||||
let groupNames: Record<string, string> = {};
|
||||
let defaults: Record<string, string | number> = {};
|
||||
let hidden: ReadonlySet<string> = new Set();
|
||||
const recent = new Map<Instance, SplitRole[]>();
|
||||
const slots = new Map<string, HTMLElement>();
|
||||
const rows: Array<{ key: string; set: (item: SummaryItem | null) => void }> = [];
|
||||
@@ -235,6 +240,7 @@ export function createSpecForm(links: SpecLinks | null, hooks: SpecFormHooks = {
|
||||
}
|
||||
const fields = c.items
|
||||
.filter((item) => item.kind === "auto" || !item.by || branchOf(item, view))
|
||||
.filter((item) => !specItemHidden(item, hidden))
|
||||
.map((item) => {
|
||||
const input = control(c, item, view, tags.get(item.id));
|
||||
const wrap = labeled(itemLabel(c, item, names), input);
|
||||
@@ -316,6 +322,7 @@ export function createSpecForm(links: SpecLinks | null, hooks: SpecFormHooks = {
|
||||
const fitted: SpecContainer[] = [];
|
||||
for (const c of spec?.containers ?? []) {
|
||||
const list = (state[c.id] ??= c.required ? [{}] : []);
|
||||
if (specContainerHidden(c, hidden)) continue; // 숨긴 상자 — 값은 그대로(322-2)
|
||||
if (fit(c, list)) fitted.push(c);
|
||||
shown(c, list).forEach((values, index) => boxes.push(instanceBox(c, values, index)));
|
||||
if (c.required || (c.max && list.length >= c.max) || hooks.count?.(c) !== undefined) continue;
|
||||
@@ -341,9 +348,10 @@ export function createSpecForm(links: SpecLinks | null, hooks: SpecFormHooks = {
|
||||
|
||||
return {
|
||||
root,
|
||||
write(next, options, nextNames = {}, nextGroups = {}, nextDefaults = {}) {
|
||||
write(next, options, nextNames = {}, nextGroups = {}, nextDefaults = {}, nextHidden) {
|
||||
spec = next;
|
||||
defaults = nextDefaults;
|
||||
hidden = nextHidden ?? new Set();
|
||||
names = nextNames;
|
||||
groupNames = nextGroups;
|
||||
state = readState(next, options);
|
||||
|
||||
@@ -120,6 +120,23 @@ export const linkOf = (c: SpecContainer, n: number): string =>
|
||||
const text = (value: unknown): string =>
|
||||
value === undefined || value === null ? "" : String(value);
|
||||
|
||||
/** 항목이 쓰는 정의 옵션 키 — 필수 상자 저장 키 · 갈래 키(선택 상자 인스턴스 키는 옵션 밖 · 322-2 보임). */
|
||||
export const specItemKeys = (item: SpecItem): string[] =>
|
||||
[item.key, ...Object.values(item.by?.map ?? {}).map((b) => b.key)].filter(
|
||||
(key): key is string => !!key,
|
||||
);
|
||||
|
||||
/** 숨긴 항목인가 — 쓰는 키가 있고 모두 숨김(정의 「표시」 · 322-2). */
|
||||
export const specItemHidden = (item: SpecItem, hidden: ReadonlySet<string>): boolean => {
|
||||
const keys = specItemKeys(item);
|
||||
return keys.length > 0 && keys.every((key) => hidden.has(key));
|
||||
};
|
||||
|
||||
/** 숨긴 상자인가 — 키 있는 항목이 하나 이상이고 모두 숨김. */
|
||||
export const specContainerHidden = (c: SpecContainer, hidden: ReadonlySet<string>): boolean =>
|
||||
c.items.some((item) => specItemKeys(item).length > 0) &&
|
||||
c.items.every((item) => !specItemKeys(item).length || specItemHidden(item, hidden));
|
||||
|
||||
/** 옵션 → 컨테이너 값. 필수는 한 벌(상위 항목 먼저 읽어 갈래 키를 앎) · 선택은 저장된 n 차례대로. */
|
||||
export function readState(
|
||||
spec: StructureSpec,
|
||||
|
||||
Reference in New Issue
Block a user