page.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. import Link from "next/link";
  2. import { Code } from "@/components/code";
  3. export const metadata = {
  4. title: "Quick Start | json-render",
  5. };
  6. export default function QuickStartPage() {
  7. return (
  8. <article>
  9. <h1 className="text-3xl font-bold mb-4">Quick Start</h1>
  10. <p className="text-muted-foreground mb-8">
  11. Get up and running with json-render in 5 minutes.
  12. </p>
  13. <h2 className="text-xl font-semibold mt-12 mb-4">
  14. 1. Define your catalog
  15. </h2>
  16. <p className="text-sm text-muted-foreground mb-4">
  17. Create a catalog that defines what components AI can use:
  18. </p>
  19. <Code lang="typescript">{`// lib/catalog.ts
  20. import { createCatalog } from '@json-render/core';
  21. import { z } from 'zod';
  22. export const catalog = createCatalog({
  23. components: {
  24. Card: {
  25. props: z.object({
  26. title: z.string(),
  27. description: z.string().nullable(),
  28. }),
  29. hasChildren: true,
  30. },
  31. Button: {
  32. props: z.object({
  33. label: z.string(),
  34. action: z.string(),
  35. }),
  36. },
  37. Text: {
  38. props: z.object({
  39. content: z.string(),
  40. }),
  41. },
  42. },
  43. actions: {
  44. submit: {
  45. params: z.object({ formId: z.string() }),
  46. },
  47. navigate: {
  48. params: z.object({ url: z.string() }),
  49. },
  50. },
  51. });`}</Code>
  52. <h2 className="text-xl font-semibold mt-12 mb-4">
  53. 2. Create your components
  54. </h2>
  55. <p className="text-sm text-muted-foreground mb-4">
  56. Register React components that render each catalog type:
  57. </p>
  58. <Code lang="tsx">{`// components/registry.tsx
  59. export const registry = {
  60. Card: ({ element, children }) => (
  61. <div className="p-4 border rounded-lg">
  62. <h2 className="font-bold">{element.props.title}</h2>
  63. {element.props.description && (
  64. <p className="text-gray-600">{element.props.description}</p>
  65. )}
  66. {children}
  67. </div>
  68. ),
  69. Button: ({ element, onAction }) => (
  70. <button
  71. className="px-4 py-2 bg-blue-500 text-white rounded"
  72. onClick={() => onAction(element.props.action, {})}
  73. >
  74. {element.props.label}
  75. </button>
  76. ),
  77. Text: ({ element }) => (
  78. <p>{element.props.content}</p>
  79. ),
  80. };`}</Code>
  81. <h2 className="text-xl font-semibold mt-12 mb-4">
  82. 3. Create an API route
  83. </h2>
  84. <p className="text-sm text-muted-foreground mb-4">
  85. Set up a streaming API route for AI generation:
  86. </p>
  87. <Code lang="typescript">{`// app/api/generate/route.ts
  88. import { streamText } from 'ai';
  89. import { generateCatalogPrompt } from '@json-render/core';
  90. import { catalog } from '@/lib/catalog';
  91. export async function POST(req: Request) {
  92. const { prompt } = await req.json();
  93. const systemPrompt = generateCatalogPrompt(catalog);
  94. const result = streamText({
  95. model: 'anthropic/claude-opus-4.5',
  96. system: systemPrompt,
  97. prompt,
  98. });
  99. return new Response(result.textStream, {
  100. headers: { 'Content-Type': 'text/plain; charset=utf-8' },
  101. });
  102. }`}</Code>
  103. <h2 className="text-xl font-semibold mt-12 mb-4">4. Render the UI</h2>
  104. <p className="text-sm text-muted-foreground mb-4">
  105. Use the providers and renderer to display AI-generated UI:
  106. </p>
  107. <Code lang="tsx">{`// app/page.tsx
  108. 'use client';
  109. import { DataProvider, ActionProvider, VisibilityProvider, Renderer, useUIStream } from '@json-render/react';
  110. import { registry } from '@/components/registry';
  111. export default function Page() {
  112. const { tree, isLoading, generate } = useUIStream({
  113. endpoint: '/api/generate',
  114. });
  115. const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
  116. e.preventDefault();
  117. const formData = new FormData(e.currentTarget);
  118. generate(formData.get('prompt') as string);
  119. };
  120. return (
  121. <DataProvider initialData={{}}>
  122. <VisibilityProvider>
  123. <ActionProvider handlers={{
  124. submit: (params) => console.log('Submit:', params),
  125. navigate: (params) => console.log('Navigate:', params),
  126. }}>
  127. <form onSubmit={handleSubmit}>
  128. <input
  129. name="prompt"
  130. placeholder="Describe what you want..."
  131. className="border p-2 rounded"
  132. />
  133. <button type="submit" disabled={isLoading}>
  134. Generate
  135. </button>
  136. </form>
  137. <div className="mt-8">
  138. <Renderer tree={tree} registry={registry} />
  139. </div>
  140. </ActionProvider>
  141. </VisibilityProvider>
  142. </DataProvider>
  143. );
  144. }`}</Code>
  145. <h2 className="text-xl font-semibold mt-12 mb-4">Next steps</h2>
  146. <ul className="list-disc list-inside text-sm text-muted-foreground space-y-2">
  147. <li>
  148. Learn about{" "}
  149. <Link
  150. href="/docs/catalog"
  151. className="text-foreground hover:underline"
  152. >
  153. catalogs
  154. </Link>{" "}
  155. in depth
  156. </li>
  157. <li>
  158. Explore{" "}
  159. <Link
  160. href="/docs/data-binding"
  161. className="text-foreground hover:underline"
  162. >
  163. data binding
  164. </Link>{" "}
  165. for dynamic values
  166. </li>
  167. <li>
  168. Add{" "}
  169. <Link
  170. href="/docs/actions"
  171. className="text-foreground hover:underline"
  172. >
  173. actions
  174. </Link>{" "}
  175. for interactivity
  176. </li>
  177. <li>
  178. Implement{" "}
  179. <Link
  180. href="/docs/visibility"
  181. className="text-foreground hover:underline"
  182. >
  183. conditional visibility
  184. </Link>
  185. </li>
  186. </ul>
  187. </article>
  188. );
  189. }