Skip to content

Commit 941d6c4

Browse files
os-zhuangclaude
andauthored
fix(showcase): command-center html page off Tailwind — structured props + style objects (ADR-0065) (#2496)
The last kind:'html' showcase page still used Tailwind className (48 of them), which the new ADR-0065 guardrail flags: page source is runtime metadata the build never scans, so the classes silently no-op (and the light-theme slate/indigo palette was wrong for the dark console anyway). Rewrite with the html tier's real primitives: - layout via the components' own structured props (<flex direction gap>, <grid columns>); - color/size via inline JSON `style` objects with hsl(var(--token)) theme colors; - text via native <div style> (the <text> renderer only applies `style` when a className/designer-id is also present — a real html-tier limitation — so styled text uses native passthrough tags instead); - the throughput bars via <grid columns={7}> (a nested <flex> bar with flex:1 collapsed to width:0; a grid track gives each bar width). os validate passes (ADR-0080 parse gate + the ADR-0065 guardrail both clean). The <flex>/grid/card/color rendering was browser-verified in the html tier; the native-div text + grid bars use the same confirmed style-passthrough path. Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent ec7175d commit 941d6c4

1 file changed

Lines changed: 55 additions & 56 deletions

File tree

examples/app-showcase/src/pages/command-center-jsx.page.ts

Lines changed: 55 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,75 +3,74 @@
33
import { definePage } from '@objectstack/spec/ui';
44

55
/**
6-
* Command Center — a `kind:'html'` page (ADR-0080; formerly `kind:'jsx'`).
7-
* The entire layout is authored as a constrained JSX/HTML + Tailwind *string*;
8-
* at save time
9-
* `@objectstack/sdui-parser` compiles it (parse, never execute) into the SDUI
10-
* tree, which the normal PageRenderer / SchemaRenderer renders. Every tag is a
11-
* real registered component — `flex`, `grid`, `card`, `text`, `badge`, `stack`.
6+
* Command Center — a `kind:'html'` page (ADR-0080): constrained JSX compiled to
7+
* the SDUI tree, parsed-never-executed. It composes registered components with
8+
* structured layout — the html tier's actual purpose.
129
*
13-
* Demonstrates what the fixed page schema cannot: Tailwind-freeform layout that
14-
* still composes the platform's real components. Browser-verified.
10+
* Styling (ADR-0065): a page's source is runtime metadata the build's Tailwind
11+
* never scans, so utility `className`s silently no-op. So this page uses NO
12+
* Tailwind: layout is the components' own structured props (`<flex direction gap>`,
13+
* `<grid columns>`), and any custom CSS is a JSON `style` object with
14+
* `hsl(var(--token))` theme colors (quoted keys/values — a JS-style object is
15+
* parsed as a deferred expression and won't apply).
1516
*/
1617
export const CommandCenterJsxPage = definePage({
1718
name: 'showcase_command_center_jsx',
1819
label: 'Command Center (HTML)',
1920
type: 'home',
2021
kind: 'html',
2122
source: `
22-
<flex direction="col" className="min-h-screen gap-10 bg-gradient-to-br from-slate-50 via-white to-indigo-50 p-10">
23+
<flex direction="col" gap={8} style={{"padding":"40px"}}>
2324
24-
<flex direction="col" className="gap-3">
25-
<badge className="w-fit rounded-full bg-indigo-100 px-3 py-1 text-xs font-semibold uppercase tracking-widest text-indigo-700" label="Operations · JSX-source page" />
26-
<text className="block text-5xl font-bold tracking-tight text-slate-900" content="Command Center" />
27-
<text className="block max-w-2xl text-base leading-relaxed text-slate-500" content="This whole page is authored as constrained JSX + Tailwind and compiled to the SDUI tree — parsed, never executed. Every card is a real registered component." />
25+
<flex direction="col" gap={2}>
26+
<div style={{"fontSize":"12px","fontWeight":"600","letterSpacing":"0.12em","textTransform":"uppercase","color":"hsl(var(--primary))"}}>Operations · HTML-source page</div>
27+
<div style={{"fontSize":"36px","fontWeight":"700","letterSpacing":"-0.02em","color":"hsl(var(--foreground))"}}>Command Center</div>
28+
<div style={{"maxWidth":"640px","fontSize":"15px","lineHeight":"1.6","color":"hsl(var(--muted-foreground))"}}>Authored as constrained JSX and compiled to the SDUI tree — parsed, never executed. Layout is structured component props; color is an inline style object with theme tokens. No Tailwind.</div>
2829
</flex>
2930
30-
<grid columns={4} className="gap-5">
31-
<card className="rounded-2xl border border-slate-200 bg-white p-6 shadow-sm">
32-
<text className="block text-sm font-medium text-slate-500" content="Open Tasks" />
33-
<text className="mt-3 block text-4xl font-bold text-slate-900" content="128" />
34-
<text className="mt-2 block text-xs font-semibold text-emerald-600" content="▲ 12% vs last week" />
35-
</card>
36-
<card className="rounded-2xl border border-slate-200 bg-white p-6 shadow-sm">
37-
<text className="block text-sm font-medium text-slate-500" content="In Progress" />
38-
<text className="mt-3 block text-4xl font-bold text-slate-900" content="47" />
39-
<text className="mt-2 block text-xs font-semibold text-amber-600" content="● 9 due today" />
40-
</card>
41-
<card className="rounded-2xl border border-slate-200 bg-white p-6 shadow-sm">
42-
<text className="block text-sm font-medium text-slate-500" content="Completed" />
43-
<text className="mt-3 block text-4xl font-bold text-slate-900" content="1,902" />
44-
<text className="mt-2 block text-xs font-semibold text-emerald-600" content="▲ 4% this month" />
45-
</card>
46-
<card className="rounded-2xl border border-indigo-300 bg-gradient-to-br from-indigo-500 to-violet-600 p-6 shadow-md">
47-
<text className="block text-sm font-medium text-indigo-100" content="Cycle Time" />
48-
<text className="mt-3 block text-4xl font-bold text-white" content="2.4d" />
49-
<text className="mt-2 block text-xs font-semibold text-indigo-100" content="▼ 18% faster" />
50-
</card>
31+
<grid columns={4} gap={5}>
32+
<flex direction="col" gap={2} style={{"background":"hsl(var(--card))","border":"1px solid hsl(var(--border))","borderRadius":"var(--radius)","padding":"24px"}}>
33+
<div style={{"fontSize":"13px","fontWeight":"500","color":"hsl(var(--muted-foreground))"}}>Open Tasks</div>
34+
<div style={{"fontSize":"34px","fontWeight":"700","color":"hsl(var(--foreground))"}}>128</div>
35+
<div style={{"fontSize":"12px","fontWeight":"600","color":"hsl(142 70% 45%)"}}>▲ 12% vs last week</div>
36+
</flex>
37+
<flex direction="col" gap={2} style={{"background":"hsl(var(--card))","border":"1px solid hsl(var(--border))","borderRadius":"var(--radius)","padding":"24px"}}>
38+
<div style={{"fontSize":"13px","fontWeight":"500","color":"hsl(var(--muted-foreground))"}}>In Progress</div>
39+
<div style={{"fontSize":"34px","fontWeight":"700","color":"hsl(var(--foreground))"}}>47</div>
40+
<div style={{"fontSize":"12px","fontWeight":"600","color":"hsl(38 92% 50%)"}}>● 9 due today</div>
41+
</flex>
42+
<flex direction="col" gap={2} style={{"background":"hsl(var(--card))","border":"1px solid hsl(var(--border))","borderRadius":"var(--radius)","padding":"24px"}}>
43+
<div style={{"fontSize":"13px","fontWeight":"500","color":"hsl(var(--muted-foreground))"}}>Completed</div>
44+
<div style={{"fontSize":"34px","fontWeight":"700","color":"hsl(var(--foreground))"}}>1,902</div>
45+
<div style={{"fontSize":"12px","fontWeight":"600","color":"hsl(142 70% 45%)"}}>▲ 4% this month</div>
46+
</flex>
47+
<flex direction="col" gap={2} style={{"background":"hsl(var(--primary))","border":"1px solid hsl(var(--primary))","borderRadius":"var(--radius)","padding":"24px"}}>
48+
<div style={{"fontSize":"13px","fontWeight":"500","color":"hsl(var(--primary-foreground))"}}>Cycle Time</div>
49+
<div style={{"fontSize":"34px","fontWeight":"700","color":"hsl(var(--primary-foreground))"}}>2.4d</div>
50+
<div style={{"fontSize":"12px","fontWeight":"600","color":"hsl(var(--primary-foreground))"}}>▼ 18% faster</div>
51+
</flex>
5152
</grid>
5253
53-
<grid columns={3} className="gap-5">
54-
<card className="col-span-2 rounded-2xl border border-slate-200 bg-white p-6 shadow-sm">
55-
<text className="block text-lg font-semibold text-slate-900" content="Weekly Throughput" />
56-
<flex direction="row" className="mt-8 items-end gap-4">
57-
<flex className="h-12 w-full rounded-lg bg-indigo-400" />
58-
<flex className="h-20 w-full rounded-lg bg-indigo-500" />
59-
<flex className="h-16 w-full rounded-lg bg-indigo-400" />
60-
<flex className="h-28 w-full rounded-lg bg-violet-500" />
61-
<flex className="h-14 w-full rounded-lg bg-indigo-400" />
62-
<flex className="h-24 w-full rounded-lg bg-indigo-500" />
63-
<flex className="h-10 w-full rounded-lg bg-indigo-300" />
64-
</flex>
65-
</card>
66-
<card className="rounded-2xl border border-slate-200 bg-white p-6 shadow-sm">
67-
<text className="block text-lg font-semibold text-slate-900" content="Recent Activity" />
68-
<stack className="mt-4 gap-3">
69-
<flex direction="row" className="items-center gap-3"><flex className="h-2 w-2 rounded-full bg-emerald-500" /><text className="text-sm text-slate-600" content="Onboarding flow shipped" /></flex>
70-
<flex direction="row" className="items-center gap-3"><flex className="h-2 w-2 rounded-full bg-indigo-500" /><text className="text-sm text-slate-600" content="12 tasks moved to Review" /></flex>
71-
<flex direction="row" className="items-center gap-3"><flex className="h-2 w-2 rounded-full bg-amber-500" /><text className="text-sm text-slate-600" content="SLA breach on #4821" /></flex>
72-
<flex direction="row" className="items-center gap-3"><flex className="h-2 w-2 rounded-full bg-slate-300" /><text className="text-sm text-slate-600" content="Sprint 42 planning" /></flex>
73-
</stack>
74-
</card>
54+
<grid columns={3} gap={5}>
55+
<flex direction="col" gap={6} style={{"gridColumn":"span 2","background":"hsl(var(--card))","border":"1px solid hsl(var(--border))","borderRadius":"var(--radius)","padding":"24px"}}>
56+
<div style={{"fontSize":"16px","fontWeight":"600","color":"hsl(var(--foreground))"}}>Weekly Throughput</div>
57+
<grid columns={7} gap={4} style={{"height":"140px","alignItems":"end"}}>
58+
<flex style={{"height":"48px","borderRadius":"8px","background":"hsl(var(--primary) / 0.55)"}} />
59+
<flex style={{"height":"86px","borderRadius":"8px","background":"hsl(var(--primary) / 0.7)"}} />
60+
<flex style={{"height":"64px","borderRadius":"8px","background":"hsl(var(--primary) / 0.55)"}} />
61+
<flex style={{"height":"120px","borderRadius":"8px","background":"hsl(var(--primary))"}} />
62+
<flex style={{"height":"58px","borderRadius":"8px","background":"hsl(var(--primary) / 0.55)"}} />
63+
<flex style={{"height":"100px","borderRadius":"8px","background":"hsl(var(--primary) / 0.7)"}} />
64+
<flex style={{"height":"40px","borderRadius":"8px","background":"hsl(var(--primary) / 0.4)"}} />
65+
</grid>
66+
</flex>
67+
<flex direction="col" gap={4} style={{"background":"hsl(var(--card))","border":"1px solid hsl(var(--border))","borderRadius":"var(--radius)","padding":"24px"}}>
68+
<div style={{"fontSize":"16px","fontWeight":"600","color":"hsl(var(--foreground))"}}>Recent Activity</div>
69+
<flex direction="row" gap={3} align="center"><flex style={{"width":"8px","height":"8px","borderRadius":"9999px","background":"hsl(142 70% 45%)"}} /><div style={{"fontSize":"14px","color":"hsl(var(--muted-foreground))"}}>Onboarding flow shipped</div></flex>
70+
<flex direction="row" gap={3} align="center"><flex style={{"width":"8px","height":"8px","borderRadius":"9999px","background":"hsl(var(--primary))"}} /><div style={{"fontSize":"14px","color":"hsl(var(--muted-foreground))"}}>12 tasks moved to Review</div></flex>
71+
<flex direction="row" gap={3} align="center"><flex style={{"width":"8px","height":"8px","borderRadius":"9999px","background":"hsl(38 92% 50%)"}} /><div style={{"fontSize":"14px","color":"hsl(var(--muted-foreground))"}}>SLA breach on #4821</div></flex>
72+
<flex direction="row" gap={3} align="center"><flex style={{"width":"8px","height":"8px","borderRadius":"9999px","background":"hsl(var(--muted-foreground))"}} /><div style={{"fontSize":"14px","color":"hsl(var(--muted-foreground))"}}>Sprint 42 planning</div></flex>
73+
</flex>
7574
</grid>
7675
</flex>`,
7776
});

0 commit comments

Comments
 (0)