feat(core,view): input cards with change tracking (plan B1 · C2)

- Three values per pier: defaults (as imported), input (generated), draft
  (current cards). Overrides = draft vs defaults; pending = draft vs input.
- Editable now: 코핑 폭, 코핑 길이, 말뚝 길이. Changing a card does not touch the
  3D view until 다시 생성; the header and the card show 변경 n.
- Revert puts a field back to its imported default.
- Project files store defaults and draft (optional; v1 files still open).
- Tests: 코핑 폭 3100 → 3300 gives one override and one pending change;
  regenerating clears pending but keeps the override; revert; file round trip.
- Not verified in a browser (no debuggable Chrome in this session).

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-10-22 09:48:47 +09:00
1 parent f5303e4c2b
commit 0b62f694c5
7 files changed
+239 -9

No files matched your search

+10 -1
View File
@@ -14,8 +14,12 @@ export interface ProjectInfo {
export interface ProjectPier {
id: string;
/** Input as read from the spreadsheet. The 3D model is not stored; it is regenerated on open (spec §8). */
/** Generated input: the values the 3D model was built from. The model is not stored; it is regenerated on open (spec §8). */
input: PierInput;
/** Values as imported from the sheet (기본값). Missing in files saved before change tracking: input is used. */
defaults?: PierInput;
/** Values currently in the cards (현재 입력). Missing in older files: input is used. */
draft?: PierInput;
}
export interface ProjectFile {
@@ -54,6 +58,11 @@ export function parseProject(text: string): ProjectFile {
if (typeof input.name !== 'string' || !Array.isArray(input.ips) || !Array.isArray(input.bearings)) {
throw new Error(`교각 ${i + 1}(${String(input.name)}): 입력 형식이 맞지 않습니다.`);
}
for (const extra of [p.defaults, p.draft]) {
if (extra !== undefined && (typeof extra !== 'object' || extra === null || typeof extra.name !== 'string')) {
throw new Error(`교각 ${i + 1}(${input.name}): defaults 또는 draft 형식이 맞지 않습니다.`);
}
}
});
return obj as ProjectFile;
}