mirror of
https://github.com/hanzoai/shadcn.git
synced 2026-11-03 03:18:52 +00:00
Squash merge of shadcn-ui/ui main branch into hanzo/ui, bringing in: - [email protected] through [email protected] releases - New apps/v4 directory structure - Registry system improvements and MCP server - Framework support (Vue, Svelte, React Native) - New templates (vite-app, monorepo-next, laravel) - Zod 4 compatibility (scoped override for zod@>4) - Test fixture corrections for alias resolution All 867 merge conflicts resolved preserving Hanzo customizations. 1020/1020 shadcn tests pass.
74 lines
5.7 KiB
JSON
74 lines
5.7 KiB
JSON
{
|
|
"name": "app-01",
|
|
"type": "registry:block",
|
|
"description": "A simple task app.",
|
|
"dependencies": [
|
|
"swr"
|
|
],
|
|
"registryDependencies": [
|
|
"card",
|
|
"input",
|
|
"button",
|
|
"skeleton",
|
|
"label"
|
|
],
|
|
"files": [
|
|
{
|
|
"path": "blocks/app-01/page.tsx",
|
|
"content": "import { AddTaskForm } from \"@/registry/new-york/blocks/app-01/components/add-task-form\"\nimport { TasksList } from \"@/registry/new-york/blocks/app-01/components/tasks-list\"\nimport {\n Card,\n CardContent,\n CardFooter,\n CardHeader,\n CardTitle,\n} from \"@/registry/new-york/ui/card\"\n\nexport default function AppPage() {\n return (\n <div className=\"h-screen flex flex-col items-center justify-center\">\n <Card className=\"w-full max-w-md\">\n <CardHeader>\n <CardTitle>Add Task</CardTitle>\n </CardHeader>\n <CardContent>\n <TasksList />\n </CardContent>\n <CardFooter>\n <AddTaskForm />\n </CardFooter>\n </Card>\n </div>\n )\n}\n",
|
|
"type": "registry:page",
|
|
"target": "app/page.tsx"
|
|
},
|
|
{
|
|
"path": "blocks/app-01/api/tasks/route.ts",
|
|
"content": "import { NextResponse } from \"next/server\"\n\nimport { API_URL } from \"@/registry/new-york/blocks/app-01/lib/constants\"\n\nexport async function GET() {\n const response = await fetch(API_URL)\n const data = await response.json()\n return NextResponse.json(data)\n}\n",
|
|
"type": "registry:page",
|
|
"target": "app/api/tasks/route.ts"
|
|
},
|
|
{
|
|
"path": "blocks/app-01/components/add-task-form.tsx",
|
|
"content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { Label } from \"@/registry/default/ui/label\"\nimport { SubmitButton } from \"@/registry/new-york/blocks/app-01/components/submit-button\"\nimport { useTasks } from \"@/registry/new-york/blocks/app-01/hooks/use-tasks\"\nimport { saveTask } from \"@/registry/new-york/blocks/app-01/lib/actions\"\nimport { Input } from \"@/registry/new-york/ui/input\"\n\nexport function AddTaskForm() {\n const { mutate } = useTasks()\n const formRef = React.useRef<HTMLFormElement>(null)\n\n return (\n <form\n action={async (formData) => {\n await saveTask(formData)\n void mutate()\n formRef.current?.reset()\n }}\n className=\"w-full\"\n ref={formRef}\n >\n <div className=\"flex flex-col gap-2\">\n <Label htmlFor=\"name\" className=\"sr-only\">\n Task Name\n </Label>\n <Input\n type=\"text\"\n name=\"name\"\n required\n autoComplete=\"off\"\n placeholder=\"Remember the milk\"\n />\n <SubmitButton className=\"w-full\">Add Task</SubmitButton>\n </div>\n </form>\n )\n}\n",
|
|
"type": "registry:component",
|
|
"target": ""
|
|
},
|
|
{
|
|
"path": "blocks/app-01/components/submit-button.tsx",
|
|
"content": "\"use client\"\n\nimport { Loader2 } from \"lucide-react\"\nimport { useFormStatus } from \"react-dom\"\n\nimport { Button } from \"@/registry/new-york/ui/button\"\n\nexport function SubmitButton({\n children,\n ...props\n}: React.ComponentProps<typeof Button>) {\n const { pending } = useFormStatus()\n\n return (\n <Button type=\"submit\" disabled={pending} {...props}>\n {pending && <Loader2 className=\"animate-spin\" />}\n {children}\n </Button>\n )\n}\n",
|
|
"type": "registry:component",
|
|
"target": ""
|
|
},
|
|
{
|
|
"path": "blocks/app-01/components/tasks-list.tsx",
|
|
"content": "\"use client\"\n\nimport { useTasks } from \"@/registry/new-york/blocks/app-01/hooks/use-tasks\"\nimport { Skeleton } from \"@/registry/new-york/ui/skeleton\"\n\nexport function TasksList() {\n const { tasks, isLoading } = useTasks()\n\n if (isLoading)\n return (\n <div className=\"grid gap-2\">\n {Array.from({ length: 5 }).map((_, index) => (\n <Skeleton className=\"h-5 w-full\" key={index} />\n ))}\n </div>\n )\n\n return (\n <div className=\"grid gap-2\">\n {tasks.map((task, index) => (\n <div key={index} className=\"h-5 text-sm\">\n {task}\n </div>\n ))}\n </div>\n )\n}\n",
|
|
"type": "registry:component",
|
|
"target": ""
|
|
},
|
|
{
|
|
"path": "blocks/app-01/hooks/use-tasks.ts",
|
|
"content": "\"use client\"\n\nimport useSWR from \"swr\"\n\nimport { API_URL } from \"@/registry/new-york/blocks/app-01/lib/constants\"\n\nexport function useTasks() {\n const { data, isLoading, mutate } = useSWR<{ tasks: string[] }>(\n \"/api/tasks\",\n async () => {\n const response = await fetch(API_URL)\n return response.json()\n }\n )\n\n return { tasks: data?.tasks || [], isLoading, mutate }\n}\n",
|
|
"type": "registry:hook",
|
|
"target": ""
|
|
},
|
|
{
|
|
"path": "blocks/app-01/lib/constants.ts",
|
|
"content": "export const API_URL = \"https://api.npoint.io/40ac2c2a67c912fa2120\"\n",
|
|
"type": "registry:lib",
|
|
"target": ""
|
|
},
|
|
{
|
|
"path": "blocks/app-01/lib/actions.ts",
|
|
"content": "\"use server\"\n\nimport { API_URL } from \"@/registry/new-york/blocks/app-01/lib/constants\"\n\nexport async function saveTask(formData: FormData) {\n const name = formData.get(\"name\")\n\n // Get current tasks\n const response = await fetch(API_URL)\n const data = await response.json()\n const tasks = data.tasks || []\n\n // Add new task to array\n tasks.push(name)\n\n // Save updated tasks array\n await fetch(API_URL, {\n method: \"POST\",\n body: JSON.stringify({ tasks }),\n })\n\n return { success: true }\n}\n",
|
|
"type": "registry:lib",
|
|
"target": ""
|
|
}
|
|
],
|
|
"cssVars": {
|
|
"light": {
|
|
"primary": "224.3 76.3% 48%",
|
|
"primary-foreground": "0 0% 100%"
|
|
}
|
|
},
|
|
"categories": [
|
|
"apps"
|
|
]
|
|
} |