Files
Socrates/docs/design-source/socrata/project/text-canvas.jsx
dtoro f1c4566576 Initial commit — design docs + Phase 0 validation harness
Sets up the Socrata project repo with:

docs/ — strategy and design documents
  - idea.md: full product vision
  - implementation-plan.md: Phase 0 + Phase 1 MVP plan
  - phase-0-validation.md: 2-week validation experiment strategy
  - phase-0-plan.md: concrete Phase 0 build plan
  - phase-0-results.md: Phase 0 gate outcome — GO for MVP
  - sysml-modeling.md: metamodel + SE discipline + validation rules
  - socrates.md: agent character, surfaces, modes, prompts, lifecycle
  - sync.md: bidirectional text↔diagram sync engineering
  - design-source/: HTML/CSS/JS handoff bundle from Claude Design

phase-0/ — validated harness (CLI, no UI, no DB)
  - LM Studio (local OpenAI-compatible) generation + detection + judge
  - PlantUML rendering for SysML model visualization
  - 10-seed corpus (8 working + 2 holdouts)
  - 5 corpus runs with iteration history in reports/
  - Final gate: 10/10 pass, mean 4.32/5, holdouts validated

Phase 1 MVP scope and milestones documented in implementation-plan.md.
2026-04-28 22:07:38 +02:00

100 lines
3.4 KiB
JavaScript

// TextCanvas — narrative editor surface with markup chips, headings, prose.
// Renders chips per markupStyle: "pill" | "underline" | "bracket" | "color".
const CHIP_TYPE_LABEL = {
block: "block",
property: "property",
association: "assoc",
requirement: "req",
};
function Chip({ kind, id, label, markupStyle, onHover, onClick, focused }) {
const cls = `chip chip-${kind} chip-style-${markupStyle}${focused ? " chip-focus" : ""}`;
const handlers = {
onMouseEnter: () => onHover && onHover(id),
onMouseLeave: () => onHover && onHover(null),
onClick: () => onClick && onClick(id, kind),
};
if (markupStyle === "bracket") {
return (
<span className={cls} {...handlers}>
<span className="chip-bracket">[</span>
<span className="chip-kind">{CHIP_TYPE_LABEL[kind]}:</span>
<span className="chip-label">{label}</span>
<span className="chip-bracket">]</span>
</span>
);
}
if (markupStyle === "underline") {
return (
<span className={cls} {...handlers}>
<span className="chip-glyph">{kindGlyph(kind)}</span>
<span className="chip-label">{label}</span>
</span>
);
}
// pill (default) and color both render as filled chips, color uses kind color, pill is muted.
return (
<span className={cls} {...handlers}>
<span className="chip-glyph">{kindGlyph(kind)}</span>
<span className="chip-label">{label}</span>
</span>
);
}
function kindGlyph(kind) {
switch (kind) {
case "block": return "▢";
case "property": return "·";
case "association": return "→";
case "requirement": return "§";
default: return "·";
}
}
function TextCanvas({ data, density, markupStyle, focusBlockId, setFocusBlockId, gutter }) {
const padY = density === "compact" ? 10 : 18;
return (
<div className="text-canvas" style={{ padding: `${padY}px ${density === "compact" ? 22 : 36}px` }}>
{gutter}
{data.narrative.map((node, i) => {
if (node.type === "h1") return <h1 key={i} className="t-h1">{node.text}</h1>;
if (node.type === "h2") return <h2 key={i} className="t-h2">{node.text}</h2>;
if (node.type === "p") {
return (
<p key={i} className="t-p">
{node.children.map((c, j) => {
if (c.t === "text") return <span key={j}>{c.v}</span>;
if (c.t === "chip") return (
<Chip key={j} kind={c.kind} id={c.id} label={c.label}
markupStyle={markupStyle}
focused={focusBlockId === c.id}
onHover={setFocusBlockId}
onClick={(id) => setFocusBlockId(id)}
/>
);
return null;
})}
</p>
);
}
return null;
})}
{/* a Socrates inline annotation (margin note) */}
<div className="margin-note">
<span className="margin-note-glyph">Σ</span>
<span>
<span className="margin-note-who">Socrates · margin</span>
<span className="margin-note-text">
"Refuses to produce solutions" is a strong constraint. Have you decided what counts as a "solution" vs. a "scaffold"? This boundary will determine whether the refusal policy is enforceable.
</span>
</span>
</div>
</div>
);
}
window.TextCanvas = TextCanvas;
window.Chip = Chip;