"use client"; import { useState, useCallback, useMemo } from "react"; import { DataProvider, ActionProvider, VisibilityProvider, useUIStream, Renderer, } from "@json-render/react"; import { componentRegistry } from "@/components/ui"; import { generateNextJSProject } from "@/lib/codegen"; import { CodeHighlight, getLanguageFromPath, } from "@/components/code-highlight"; const INITIAL_DATA = { analytics: { revenue: 125000, growth: 0.15, customers: 1234, orders: 567, salesByRegion: [ { label: "US", value: 45000 }, { label: "EU", value: 35000 }, { label: "Asia", value: 28000 }, { label: "Other", value: 17000 }, ], recentTransactions: [ { id: "TXN001", customer: "Acme Corp", amount: 1500, status: "completed", date: "2024-01-15", }, { id: "TXN002", customer: "Globex Inc", amount: 2300, status: "pending", date: "2024-01-14", }, { id: "TXN003", customer: "Initech", amount: 890, status: "completed", date: "2024-01-13", }, { id: "TXN004", customer: "Umbrella Co", amount: 4200, status: "completed", date: "2024-01-12", }, ], }, form: { dateRange: "", region: "", }, }; const ACTION_HANDLERS = { export_report: () => alert("Exporting report..."), refresh_data: () => alert("Refreshing data..."), view_details: (params: Record) => alert(`Details: ${JSON.stringify(params)}`), apply_filter: () => alert("Applying filters..."), }; function DashboardContent() { const [prompt, setPrompt] = useState(""); const [showCodeExport, setShowCodeExport] = useState(false); const [selectedFile, setSelectedFile] = useState(null); const { tree, isStreaming, error, send, clear } = useUIStream({ api: "/api/generate", onError: (err) => console.error("Generation error:", err), }); const exportedFiles = useMemo( () => tree ? generateNextJSProject(tree, { projectName: "my-dashboard", data: INITIAL_DATA, }) : [], [tree], ); const handleSubmit = useCallback( async (e: React.FormEvent) => { e.preventDefault(); if (!prompt.trim()) return; await send(prompt, { data: INITIAL_DATA }); }, [prompt, send], ); const downloadAllFiles = useCallback(() => { // Create a simple zip-like download by creating individual file downloads // For a real implementation, you'd use a library like JSZip const allContent = exportedFiles .map((f) => `// ========== ${f.path} ==========\n${f.content}`) .join("\n\n"); const blob = new Blob([allContent], { type: "text/plain" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = "my-dashboard-project.txt"; a.click(); URL.revokeObjectURL(url); }, [exportedFiles]); const copyFileContent = useCallback((content: string) => { navigator.clipboard.writeText(content); }, []); const examples = [ "Revenue dashboard with metrics and chart", "Recent transactions table", "Customer count with trend", ]; const hasElements = tree && Object.keys(tree.elements).length > 0; // Auto-select first file when modal opens const activeFile = selectedFile || (exportedFiles.length > 0 ? exportedFiles[0]?.path : null); const activeFileContent = exportedFiles.find( (f) => f.path === activeFile, )?.content; return (

Dashboard

Generate widgets from prompts. Constrained to your catalog.

setPrompt(e.target.value)} placeholder="Describe what you want..." disabled={isStreaming} style={{ flex: 1, padding: "12px 16px", background: "var(--card)", border: "1px solid var(--border)", borderRadius: "var(--radius)", color: "var(--foreground)", fontSize: 16, outline: "none", }} /> {hasElements && ( <> )}
{examples.map((ex) => ( ))}
{error && (
{error.message}
)}
{!hasElements && !isStreaming ? (

Enter a prompt to generate a widget

) : tree ? ( ) : null}
{hasElements && (
View JSON
            {JSON.stringify(tree, null, 2)}
          
)} {/* Code Export Modal */} {showCodeExport && (
setShowCodeExport(false)} >
e.stopPropagation()} > {/* Header */}

Export Next.js Project

{exportedFiles.length} files generated

{/* Content */}
{/* File List */}
{exportedFiles.map((file) => ( ))}
{/* File Content */}
{activeFile && ( <>
{activeFile}
)}
)}
); } export default function DashboardPage() { return ( ); }