From bb799071871f880e2dfa820fc1565f34ac331586 Mon Sep 17 00:00:00 2001 From: Matei Date: Thu, 11 Jun 2026 20:38:26 -0400 Subject: [PATCH] =?UTF-8?q?feat(mapgen-studio):=20config=20surface=20?= =?UTF-8?q?=E2=80=94=20elevation-based=20nesting=20+=20codified=20form=20r?= =?UTF-8?q?hythm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Groups inside stage cards become recessed wells (page-token tint, subtle border) replacing the border-l indent ladder; arrays unify onto the same well; surface nesting caps at card → well (depth ≥3 differentiates by eyebrow heading + rhythm only). Spacing rhythm codified in FORM.rhythm: 4px within field blocks, 8px between siblings, 12px between sections. Group headings invert to the eyebrow tier so field labels stay the brightest scan line. Verified both themes live (wells recess in dark AND light since background sits below card in both); 146 tests + tsc green. Co-Authored-By: Claude Fable 5 --- .../configOverrides/rjsfTemplates.tsx | 70 ++++++++++++++----- .../config/rjsfFieldTemplateErrors.test.tsx | 34 +++++++++ .../mapgen-studio-config-surface/tasks.md | 16 ++--- 3 files changed, 94 insertions(+), 26 deletions(-) diff --git a/apps/mapgen-studio/src/features/configOverrides/rjsfTemplates.tsx b/apps/mapgen-studio/src/features/configOverrides/rjsfTemplates.tsx index 7a995ab42f..701075874f 100644 --- a/apps/mapgen-studio/src/features/configOverrides/rjsfTemplates.tsx +++ b/apps/mapgen-studio/src/features/configOverrides/rjsfTemplates.tsx @@ -14,7 +14,13 @@ export type BrowserConfigFormContext = { // tokens (`card`/`muted`/`border`/`accent`/…), so there is no `lightMode` read. const FORM = { card: "bg-card border-border", - nested: "bg-muted/40 border-border-subtle", + // Group well: nesting is a surface, not an indent (Pass-3 config-surface + // spec). One recess below the stage card — tinted toward the page token so + // groups read as machined slots in the slate. `background` sits below `card` + // in BOTH themes (5%<9% dark, 96%<100% light), so the tint recesses in both. + // Two surface tiers maximum: card → well; deeper nesting adds headings and + // rhythm only, never a third surface. + well: "bg-background/40 border-border-subtle", divider: "border-border", // Field labels sit a full tier above prose (Pass-2 form hierarchy): labels are // foreground anchors the eye scans; descriptions/help/gs-comments recede on the @@ -25,6 +31,19 @@ const FORM = { text: "text-foreground", borderSubtle: "border-border-subtle", button: "bg-muted text-foreground border-border hover:bg-accent", + // Group headings are eyebrows: the well's geometry carries the grouping, so + // its caption recedes below field labels (the brightest scan line in a card). + groupHeading: "text-label font-semibold uppercase tracking-wider text-muted-foreground", + subGroupHeading: "text-label font-semibold uppercase tracking-wider text-muted-foreground/70", + // Rhythm on the 4px base (Pass-3): 4px inside a field block, 8px between + // sibling fields, 12px between groups/stage sections. Group wells carry + // `my-1`, which composes with the sibling gap to the 12px group step. + rhythm: { + field: "gap-1", + siblings: "gap-2", + sections: "gap-3", + groupPull: "my-1", + }, } as const; function humanizeSchemaLabel(label: string): string { @@ -85,7 +104,7 @@ export function BrowserConfigFieldTemplate( if (!showLabel) { return ( -
+
{children}
{description && !suppressDescription ?
{description}
: null} {renderGsComments({ schema: props.schema, className: labelClass })} @@ -96,7 +115,7 @@ export function BrowserConfigFieldTemplate( } return ( -
+