style(frontend): look&feel v2 refinements — 70% gate modal, structured cards, mono labels

- ArtifactGateWidget: gate modal 90%→70% of viewport, larger heading, more padding.
- ArtifactView StructuredValue: depth-aware hierarchy (top-level hairline dividers,
  warm bg-muted card surfaces + shadow for object-array items).
- index.css: .thot-label micro-labels switched to the mono register (SF Mono) with
  tightened tracking, distinguishing labels/meta from sans body prose.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-06 23:29:49 +02:00
committed by Marco Pancotti
co-authored by Claude Opus 4.8
parent 9fe1c9321b
commit e9b2934ef7
3 changed files with 35 additions and 17 deletions
+24 -11
View File
@@ -77,8 +77,10 @@ function humanizeKey(k: string): string {
/** Renders any artifact payload as readable text — NEVER raw JSON. Objects become
* labelled sections, arrays become bullet lists, primitives become paragraphs;
* strings render as markdown. Nested structures recurse. */
function StructuredValue({ value }: { value: unknown }): ReactElement {
* strings render as markdown. Nested structures recurse. `depth` drives the
* visual hierarchy: top-level sections are split by hairline rules, nested fields
* sit tighter, and object-arrays become grouped cards. */
function StructuredValue({ value, depth = 0 }: { value: unknown; depth?: number }): ReactElement {
if (value === null || value === undefined || value === "") {
return <p className="text-sm text-muted-foreground">—</p>;
}
@@ -98,21 +100,32 @@ function StructuredValue({ value }: { value: unknown }): ReactElement {
return (
<div className="flex flex-col gap-3">
{value.map((item, i) => (
<div key={i} className="rounded-lg border border-border/60 p-3">
<StructuredValue value={item} />
<div
key={i}
className="rounded-xl border border-border/70 bg-muted/50 p-4 shadow-xs"
>
<StructuredValue value={item} depth={depth + 1} />
</div>
))}
</div>
);
}
const entries = Object.entries(value as Record<string, unknown>);
return (
<div className="flex flex-col gap-4">
{Object.entries(value as Record<string, unknown>).map(([k, v]) => (
<section key={k}>
<h4 className="thot-label mb-1.5">
{humanizeKey(k)}
</h4>
<StructuredValue value={v} />
<div className="flex flex-col">
{entries.map(([k, v], i) => (
<section
key={k}
className={
i === 0
? undefined
: depth === 0
? "mt-5 border-t border-border/50 pt-5"
: "mt-3"
}
>
<h4 className="thot-label mb-1.5">{humanizeKey(k)}</h4>
<StructuredValue value={v} depth={depth + 1} />
</section>
))}
</div>