Implement M1 authoring loop: library, editor, live preview, persistence

M1 MVP from docs/IMPLEMENTATION-PLAN.md, with the /alignment pass applied.

- core: Snippet model + factory; prepareSpecForRender (copy-not-mutate); per-theme Vega chart config
- state/orchestration: SnippetStore with debounced auto-save; IndexedDB adapter + read-time migration; startup hydration + write-through persistence
- ui: SnippetLibrary, SpecEditor (Monaco edcore.main — full editor features, JSON-only languages), LivePreview
- build: Monaco/Vega manual chunks; raised PWA precache ceiling
- alignment: flush a valid draft on snippet switch (+regression tests); TODO breadcrumbs for the preview render race and the window.confirm delete
- housekeeping: gitignore .claude/projects/
This commit is contained in:
2026-06-05 00:16:24 +03:00
parent 056644450c
commit ca54bb66b1
34 changed files with 1557 additions and 74 deletions
+10 -7
View File
@@ -1,12 +1,15 @@
import { LivePreview } from './components/LivePreview';
import { SnippetLibrary } from './components/SnippetLibrary';
import { SpecEditor } from './components/SpecEditor';
import styles from './App.module.css';
/**
* Application shell — the three-pane workspace from spec §01A
* (library · editor · preview) under a fixed header.
*
* This is the skeleton: panes are placeholders. Each milestone fills one in
* (see docs/IMPLEMENTATION-PLAN.md). Resizing, toggling, modals, routing, and
* shortcuts arrive in later milestones.
* M1 fills the panes with the MVP authoring loop. Pane resizing/toggling,
* modals, routing, and shortcuts arrive in later milestones (see
* docs/IMPLEMENTATION-PLAN.md).
*/
export function App() {
return (
@@ -19,13 +22,13 @@ export function App() {
<main className={styles.panes}>
<section className={styles.pane} aria-label="Snippet library">
<div className={styles.paneLabel}>Library</div>
<SnippetLibrary />
</section>
<section className={styles.pane} aria-label="Spec editor">
<div className={styles.paneLabel}>Editor</div>
<section className={styles.paneEditor} aria-label="Spec editor">
<SpecEditor />
</section>
<section className={styles.pane} aria-label="Live preview">
<div className={styles.paneLabel}>Preview</div>
<LivePreview />
</section>
</main>
</div>