page.tsx 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  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. "type": "Card",
  49. "props": { "title": "Welcome" },
  50. "children": ["text-1"]
  51. },
  52. "text-1": {
  53. "type": "Text",
  54. "props": { "content": "Hello, $data.user.name!" },
  55. "children": []
  56. }
  57. }
  58. }`}</Code>
  59. <h3 className="text-lg font-medium mt-8 mb-3">Complex Spec</h3>
  60. <p className="text-sm text-muted-foreground mb-4">
  61. A more complex spec with multiple nested elements:
  62. </p>
  63. <Code lang="json">{`{
  64. "root": "card-1",
  65. "elements": {
  66. "card-1": {
  67. "type": "Card",
  68. "props": { "title": "User Profile", "padding": "md" },
  69. "children": ["row-1", "button-1"]
  70. },
  71. "row-1": {
  72. "type": "Row",
  73. "props": { "gap": "md" },
  74. "children": ["avatar-1", "stack-1"]
  75. },
  76. "avatar-1": {
  77. "type": "Avatar",
  78. "props": { "src": "$data.user.avatar", "alt": "$data.user.name" },
  79. "children": []
  80. },
  81. "stack-1": {
  82. "type": "Stack",
  83. "props": { "gap": "sm" },
  84. "children": ["name-text", "email-text"]
  85. },
  86. "name-text": {
  87. "type": "Text",
  88. "props": { "content": "$data.user.name", "variant": "heading" },
  89. "children": []
  90. },
  91. "email-text": {
  92. "type": "Text",
  93. "props": { "content": "$data.user.email", "variant": "caption" },
  94. "children": []
  95. },
  96. "button-1": {
  97. "type": "Button",
  98. "props": { "label": "Edit Profile" },
  99. "children": []
  100. }
  101. }
  102. }`}</Code>
  103. <h3 className="text-lg font-medium mt-8 mb-3">Block-Level Spec</h3>
  104. <p className="text-sm text-muted-foreground mb-4">
  105. A high-level spec using semantic blocks for page layouts:
  106. </p>
  107. <Code lang="json">{`{
  108. "root": "page",
  109. "elements": {
  110. "page": {
  111. "type": "Page",
  112. "props": {},
  113. "children": ["header", "hero", "features", "footer"]
  114. },
  115. "header": {
  116. "type": "Header",
  117. "props": { "logo": "/logo.svg", "navItems": ["Products", "Pricing", "Docs"] },
  118. "children": []
  119. },
  120. "hero": {
  121. "type": "Hero",
  122. "props": {
  123. "title": "Build UIs with JSON",
  124. "subtitle": "Let AI generate your interfaces",
  125. "ctaLabel": "Get Started",
  126. "ctaHref": "/docs"
  127. },
  128. "children": []
  129. },
  130. "features": {
  131. "type": "Features",
  132. "props": { "columns": 3 },
  133. "children": ["feature-1", "feature-2", "feature-3"]
  134. },
  135. "feature-1": {
  136. "type": "Feature",
  137. "props": { "icon": "zap", "title": "Fast", "description": "Render UIs in milliseconds" },
  138. "children": []
  139. },
  140. "feature-2": {
  141. "type": "Feature",
  142. "props": { "icon": "shield", "title": "Secure", "description": "Validate all specs against your catalog" },
  143. "children": []
  144. },
  145. "feature-3": {
  146. "type": "Feature",
  147. "props": { "icon": "sparkles", "title": "AI-Ready", "description": "Generate prompts from your catalog" },
  148. "children": []
  149. },
  150. "footer": {
  151. "type": "Footer",
  152. "props": { "copyright": "2025 Acme Inc", "links": ["Privacy", "Terms", "Contact"] },
  153. "children": []
  154. }
  155. }
  156. }`}</Code>
  157. <h2 className="text-xl font-semibold mt-12 mb-4">Spec Anatomy</h2>
  158. <h3 className="text-lg font-medium mt-8 mb-3">Root and Elements</h3>
  159. <p className="text-sm text-muted-foreground mb-4">
  160. Every spec has a <code className="text-foreground">root</code> key
  161. pointing to the entry element, and an{" "}
  162. <code className="text-foreground">elements</code> map containing all
  163. elements:
  164. </p>
  165. <Code lang="json">{`{
  166. "root": "card-1",
  167. "elements": {
  168. "card-1": {
  169. "type": "Card",
  170. "props": { "title": "My Card" },
  171. "children": ["text-1"]
  172. },
  173. "text-1": { ... }
  174. }
  175. }`}</Code>
  176. <h3 className="text-lg font-medium mt-8 mb-3">Element Structure</h3>
  177. <p className="text-sm text-muted-foreground mb-4">
  178. Each element in the map has a consistent shape:
  179. </p>
  180. <Code lang="json">{`{
  181. "type": "ComponentName",
  182. "props": { "label": "Hello" },
  183. "children": ["child-1", "child-2"]
  184. }`}</Code>
  185. <ul className="list-disc list-inside text-sm text-muted-foreground space-y-1 mt-3 mb-4">
  186. <li>
  187. <code className="text-foreground">type</code> — Component type from
  188. your catalog
  189. </li>
  190. <li>
  191. <code className="text-foreground">props</code> — Component properties
  192. </li>
  193. <li>
  194. <code className="text-foreground">children</code> — Array of child
  195. element keys
  196. </li>
  197. </ul>
  198. <h3 className="text-lg font-medium mt-8 mb-3">Dynamic Data</h3>
  199. <p className="text-sm text-muted-foreground mb-4">
  200. Props can reference data using{" "}
  201. <code className="text-foreground">$data</code> paths:
  202. </p>
  203. <Code lang="json">{`{
  204. "type": "Metric",
  205. "props": {
  206. "label": "Total Revenue",
  207. "value": "$data.metrics.revenue",
  208. "change": "$data.metrics.revenueChange"
  209. },
  210. "children": []
  211. }`}</Code>
  212. <h3 className="text-lg font-medium mt-8 mb-3">Conditional Visibility</h3>
  213. <p className="text-sm text-muted-foreground mb-4">
  214. Control when elements appear using the{" "}
  215. <code className="text-foreground">visible</code> property:
  216. </p>
  217. <Code lang="json">{`{
  218. "type": "Alert",
  219. "props": {
  220. "message": "You have unsaved changes"
  221. },
  222. "children": [],
  223. "visible": {
  224. "path": "$data.form.isDirty",
  225. "operator": "eq",
  226. "value": true
  227. }
  228. }`}</Code>
  229. <h2 className="text-xl font-semibold mt-12 mb-4">Working with Specs</h2>
  230. <h3 className="text-lg font-medium mt-8 mb-3">Rendering a Spec</h3>
  231. <Code lang="tsx">{`import { Renderer } from '@json-render/react';
  232. function MyApp({ spec, data }) {
  233. return (
  234. <Renderer
  235. spec={spec}
  236. data={data}
  237. registry={registry}
  238. />
  239. );
  240. }`}</Code>
  241. <h3 className="text-lg font-medium mt-8 mb-3">Validating a Spec</h3>
  242. <Code lang="typescript">{`import { validate } from '@json-render/core';
  243. const result = validate(spec, catalog);
  244. if (!result.valid) {
  245. console.error('Invalid spec:', result.errors);
  246. }`}</Code>
  247. <h3 className="text-lg font-medium mt-8 mb-3">Streaming Specs</h3>
  248. <p className="text-sm text-muted-foreground mb-4">
  249. Specs can be streamed incrementally for progressive rendering:
  250. </p>
  251. <Code lang="tsx">{`import { useUIStream } from '@json-render/react';
  252. function GenerativeUI() {
  253. const { spec, isStreaming } = useUIStream({
  254. api: '/api/generate',
  255. });
  256. return (
  257. <Renderer
  258. spec={spec}
  259. registry={registry}
  260. loading={isStreaming}
  261. />
  262. );
  263. }`}</Code>
  264. <h2 className="text-xl font-semibold mt-12 mb-4">Spec Sources</h2>
  265. <p className="text-sm text-muted-foreground mb-4">
  266. Specs can come from various sources:
  267. </p>
  268. <ul className="list-disc list-inside text-sm text-muted-foreground space-y-1 mb-4">
  269. <li>
  270. <strong className="text-foreground">AI Generation</strong> — LLMs
  271. generate specs based on prompts and catalog
  272. </li>
  273. <li>
  274. <strong className="text-foreground">Database</strong> — Store specs as
  275. JSON and load dynamically
  276. </li>
  277. <li>
  278. <strong className="text-foreground">API Response</strong> — Server
  279. returns specs based on user/context
  280. </li>
  281. <li>
  282. <strong className="text-foreground">Static Files</strong> — Pre-built
  283. specs for known UI patterns
  284. </li>
  285. </ul>
  286. <h2 className="text-xl font-semibold mt-12 mb-4">Next</h2>
  287. <p className="text-sm text-muted-foreground">
  288. Learn about{" "}
  289. <Link href="/docs/catalog" className="text-foreground hover:underline">
  290. catalogs
  291. </Link>{" "}
  292. — the vocabulary of components available in your specs.
  293. </p>
  294. </article>
  295. );
  296. }