page.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. import Link from "next/link";
  2. import { Code } from "@/components/code";
  3. export const metadata = {
  4. title: "Specs | json-render",
  5. };
  6. export default function SpecsPage() {
  7. return (
  8. <article>
  9. <h1 className="text-3xl font-bold mb-4">Specs</h1>
  10. <p className="text-muted-foreground mb-8">
  11. A spec is a JSON document that describes your UI.
  12. </p>
  13. <h2 className="text-xl font-semibold mt-12 mb-4">What is a Spec?</h2>
  14. <p className="text-sm text-muted-foreground mb-4">
  15. A spec (specification) is the actual JSON that describes a UI. It
  16. conforms to a{" "}
  17. <Link href="/docs/schemas" className="text-foreground hover:underline">
  18. schema
  19. </Link>{" "}
  20. and uses components from a{" "}
  21. <Link href="/docs/catalog" className="text-foreground hover:underline">
  22. catalog
  23. </Link>
  24. . Specs can be:
  25. </p>
  26. <ul className="list-disc list-inside text-sm text-muted-foreground space-y-1 mb-4">
  27. <li>Generated by AI in real-time</li>
  28. <li>Stored in a database</li>
  29. <li>Streamed progressively from a server</li>
  30. <li>Hand-authored as JSON files</li>
  31. </ul>
  32. <p className="text-sm text-muted-foreground mb-4">
  33. json-render is schema-agnostic — your specs can follow any JSON
  34. structure you choose.
  35. </p>
  36. <h2 className="text-xl font-semibold mt-12 mb-4">Example Specs</h2>
  37. <h3 className="text-lg font-medium mt-8 mb-3">Simple Spec</h3>
  38. <p className="text-sm text-muted-foreground mb-4">
  39. A basic spec using the{" "}
  40. <code className="text-foreground">@json-render/react</code> schema. Note
  41. the flat structure with a <code className="text-foreground">root</code>{" "}
  42. key and <code className="text-foreground">elements</code> map:
  43. </p>
  44. <Code lang="json">{`{
  45. "root": "card-1",
  46. "elements": {
  47. "card-1": {
  48. "key": "card-1",
  49. "type": "Card",
  50. "props": { "title": "Welcome" },
  51. "children": ["text-1"],
  52. "parentKey": ""
  53. },
  54. "text-1": {
  55. "key": "text-1",
  56. "type": "Text",
  57. "props": { "content": "Hello, $data.user.name!" },
  58. "children": [],
  59. "parentKey": "card-1"
  60. }
  61. }
  62. }`}</Code>
  63. <h3 className="text-lg font-medium mt-8 mb-3">Complex Spec</h3>
  64. <p className="text-sm text-muted-foreground mb-4">
  65. A more complex spec with multiple nested elements:
  66. </p>
  67. <Code lang="json">{`{
  68. "root": "card-1",
  69. "elements": {
  70. "card-1": {
  71. "key": "card-1",
  72. "type": "Card",
  73. "props": { "title": "User Profile", "padding": "md" },
  74. "children": ["row-1", "button-1"],
  75. "parentKey": ""
  76. },
  77. "row-1": {
  78. "key": "row-1",
  79. "type": "Row",
  80. "props": { "gap": "md" },
  81. "children": ["avatar-1", "stack-1"],
  82. "parentKey": "card-1"
  83. },
  84. "avatar-1": {
  85. "key": "avatar-1",
  86. "type": "Avatar",
  87. "props": { "src": "$data.user.avatar", "alt": "$data.user.name" },
  88. "children": [],
  89. "parentKey": "row-1"
  90. },
  91. "stack-1": {
  92. "key": "stack-1",
  93. "type": "Stack",
  94. "props": { "gap": "sm" },
  95. "children": ["name-text", "email-text"],
  96. "parentKey": "row-1"
  97. },
  98. "name-text": {
  99. "key": "name-text",
  100. "type": "Text",
  101. "props": { "content": "$data.user.name", "variant": "heading" },
  102. "children": [],
  103. "parentKey": "stack-1"
  104. },
  105. "email-text": {
  106. "key": "email-text",
  107. "type": "Text",
  108. "props": { "content": "$data.user.email", "variant": "caption" },
  109. "children": [],
  110. "parentKey": "stack-1"
  111. },
  112. "button-1": {
  113. "key": "button-1",
  114. "type": "Button",
  115. "props": { "label": "Edit Profile" },
  116. "children": [],
  117. "parentKey": "card-1"
  118. }
  119. }
  120. }`}</Code>
  121. <h3 className="text-lg font-medium mt-8 mb-3">Block-Level Spec</h3>
  122. <p className="text-sm text-muted-foreground mb-4">
  123. A high-level spec using semantic blocks for page layouts:
  124. </p>
  125. <Code lang="json">{`{
  126. "root": "page",
  127. "elements": {
  128. "page": {
  129. "key": "page",
  130. "type": "Page",
  131. "props": {},
  132. "children": ["header", "hero", "features", "footer"],
  133. "parentKey": ""
  134. },
  135. "header": {
  136. "key": "header",
  137. "type": "Header",
  138. "props": { "logo": "/logo.svg", "navItems": ["Products", "Pricing", "Docs"] },
  139. "children": [],
  140. "parentKey": "page"
  141. },
  142. "hero": {
  143. "key": "hero",
  144. "type": "Hero",
  145. "props": {
  146. "title": "Build UIs with JSON",
  147. "subtitle": "Let AI generate your interfaces",
  148. "ctaLabel": "Get Started",
  149. "ctaHref": "/docs"
  150. },
  151. "children": [],
  152. "parentKey": "page"
  153. },
  154. "features": {
  155. "key": "features",
  156. "type": "Features",
  157. "props": { "columns": 3 },
  158. "children": ["feature-1", "feature-2", "feature-3"],
  159. "parentKey": "page"
  160. },
  161. "feature-1": {
  162. "key": "feature-1",
  163. "type": "Feature",
  164. "props": { "icon": "zap", "title": "Fast", "description": "Render UIs in milliseconds" },
  165. "children": [],
  166. "parentKey": "features"
  167. },
  168. "feature-2": {
  169. "key": "feature-2",
  170. "type": "Feature",
  171. "props": { "icon": "shield", "title": "Secure", "description": "Validate all specs against your catalog" },
  172. "children": [],
  173. "parentKey": "features"
  174. },
  175. "feature-3": {
  176. "key": "feature-3",
  177. "type": "Feature",
  178. "props": { "icon": "sparkles", "title": "AI-Ready", "description": "Generate prompts from your catalog" },
  179. "children": [],
  180. "parentKey": "features"
  181. },
  182. "footer": {
  183. "key": "footer",
  184. "type": "Footer",
  185. "props": { "copyright": "2025 Acme Inc", "links": ["Privacy", "Terms", "Contact"] },
  186. "children": [],
  187. "parentKey": "page"
  188. }
  189. }
  190. }`}</Code>
  191. <h2 className="text-xl font-semibold mt-12 mb-4">Spec Anatomy</h2>
  192. <h3 className="text-lg font-medium mt-8 mb-3">Root and Elements</h3>
  193. <p className="text-sm text-muted-foreground mb-4">
  194. Every spec has a <code className="text-foreground">root</code> key
  195. pointing to the entry element, and an{" "}
  196. <code className="text-foreground">elements</code> map containing all
  197. elements:
  198. </p>
  199. <Code lang="json">{`{
  200. "root": "card-1",
  201. "elements": {
  202. "card-1": {
  203. "key": "card-1",
  204. "type": "Card",
  205. "props": { "title": "My Card" },
  206. "children": ["text-1"],
  207. "parentKey": ""
  208. },
  209. "text-1": { ... }
  210. }
  211. }`}</Code>
  212. <h3 className="text-lg font-medium mt-8 mb-3">Element Structure</h3>
  213. <p className="text-sm text-muted-foreground mb-4">
  214. Each element in the map has a consistent shape:
  215. </p>
  216. <Code lang="json">{`{
  217. "key": "unique-id",
  218. "type": "ComponentName",
  219. "props": { "label": "Hello" },
  220. "children": ["child-1", "child-2"],
  221. "parentKey": "parent-id"
  222. }`}</Code>
  223. <ul className="list-disc list-inside text-sm text-muted-foreground space-y-1 mt-3 mb-4">
  224. <li>
  225. <code className="text-foreground">key</code> — Unique identifier for
  226. this element
  227. </li>
  228. <li>
  229. <code className="text-foreground">type</code> — Component type from
  230. your catalog
  231. </li>
  232. <li>
  233. <code className="text-foreground">props</code> — Component properties
  234. </li>
  235. <li>
  236. <code className="text-foreground">children</code> — Array of child
  237. element keys
  238. </li>
  239. <li>
  240. <code className="text-foreground">parentKey</code> — Key of parent
  241. element (empty string for root)
  242. </li>
  243. </ul>
  244. <h3 className="text-lg font-medium mt-8 mb-3">Dynamic Data</h3>
  245. <p className="text-sm text-muted-foreground mb-4">
  246. Props can reference data using{" "}
  247. <code className="text-foreground">$data</code> paths:
  248. </p>
  249. <Code lang="json">{`{
  250. "key": "metric-1",
  251. "type": "Metric",
  252. "props": {
  253. "label": "Total Revenue",
  254. "value": "$data.metrics.revenue",
  255. "change": "$data.metrics.revenueChange"
  256. },
  257. "children": [],
  258. "parentKey": "dashboard"
  259. }`}</Code>
  260. <h3 className="text-lg font-medium mt-8 mb-3">Conditional Visibility</h3>
  261. <p className="text-sm text-muted-foreground mb-4">
  262. Control when elements appear using the{" "}
  263. <code className="text-foreground">visible</code> property:
  264. </p>
  265. <Code lang="json">{`{
  266. "key": "alert-1",
  267. "type": "Alert",
  268. "props": {
  269. "message": "You have unsaved changes"
  270. },
  271. "children": [],
  272. "parentKey": "form",
  273. "visible": {
  274. "path": "$data.form.isDirty",
  275. "operator": "eq",
  276. "value": true
  277. }
  278. }`}</Code>
  279. <h2 className="text-xl font-semibold mt-12 mb-4">Working with Specs</h2>
  280. <h3 className="text-lg font-medium mt-8 mb-3">Rendering a Spec</h3>
  281. <Code lang="tsx">{`import { Renderer } from '@json-render/react';
  282. function MyApp({ spec, data }) {
  283. return (
  284. <Renderer
  285. spec={spec}
  286. data={data}
  287. registry={registry}
  288. />
  289. );
  290. }`}</Code>
  291. <h3 className="text-lg font-medium mt-8 mb-3">Validating a Spec</h3>
  292. <Code lang="typescript">{`import { validate } from '@json-render/core';
  293. const result = validate(spec, catalog);
  294. if (!result.valid) {
  295. console.error('Invalid spec:', result.errors);
  296. }`}</Code>
  297. <h3 className="text-lg font-medium mt-8 mb-3">Streaming Specs</h3>
  298. <p className="text-sm text-muted-foreground mb-4">
  299. Specs can be streamed incrementally for progressive rendering:
  300. </p>
  301. <Code lang="tsx">{`import { useUIStream } from '@json-render/react';
  302. function GenerativeUI() {
  303. const { spec, isStreaming } = useUIStream({
  304. api: '/api/generate',
  305. });
  306. return (
  307. <Renderer
  308. spec={spec}
  309. registry={registry}
  310. loading={isStreaming}
  311. />
  312. );
  313. }`}</Code>
  314. <h2 className="text-xl font-semibold mt-12 mb-4">Spec Sources</h2>
  315. <p className="text-sm text-muted-foreground mb-4">
  316. Specs can come from various sources:
  317. </p>
  318. <ul className="list-disc list-inside text-sm text-muted-foreground space-y-1 mb-4">
  319. <li>
  320. <strong className="text-foreground">AI Generation</strong> — LLMs
  321. generate specs based on prompts and catalog
  322. </li>
  323. <li>
  324. <strong className="text-foreground">Database</strong> — Store specs as
  325. JSON and load dynamically
  326. </li>
  327. <li>
  328. <strong className="text-foreground">API Response</strong> — Server
  329. returns specs based on user/context
  330. </li>
  331. <li>
  332. <strong className="text-foreground">Static Files</strong> — Pre-built
  333. specs for known UI patterns
  334. </li>
  335. </ul>
  336. <h2 className="text-xl font-semibold mt-12 mb-4">Next</h2>
  337. <p className="text-sm text-muted-foreground">
  338. Learn about{" "}
  339. <Link href="/docs/catalog" className="text-foreground hover:underline">
  340. catalogs
  341. </Link>{" "}
  342. — the vocabulary of components available in your specs.
  343. </p>
  344. </article>
  345. );
  346. }