test
This commit is contained in:
BIN
registry-template/app/favicon.ico
Normal file
BIN
registry-template/app/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
136
registry-template/app/globals.css
Normal file
136
registry-template/app/globals.css
Normal file
@@ -0,0 +1,136 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 240 10% 3.9%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 240 10% 3.9%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 240 10% 3.9%;
|
||||
--primary: 240 5.9% 10%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
--secondary: 240 4.8% 95.9%;
|
||||
--secondary-foreground: 240 5.9% 10%;
|
||||
--muted: 240 4.8% 95.9%;
|
||||
--muted-foreground: 240 3.8% 46.1%;
|
||||
--accent: 240 4.8% 95.9%;
|
||||
--accent-foreground: 240 5.9% 10%;
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 240 5.9% 90%;
|
||||
--input: 240 5.9% 90%;
|
||||
--ring: 240 10% 3.9%;
|
||||
--chart-1: 12 76% 61%;
|
||||
--chart-2: 173 58% 39%;
|
||||
--chart-3: 197 37% 24%;
|
||||
--chart-4: 43 74% 66%;
|
||||
--chart-5: 27 87% 67%;
|
||||
--radius: 0.5rem;
|
||||
--sidebar-background: 0 0% 98%;
|
||||
--sidebar-foreground: 240 5.3% 26.1%;
|
||||
--sidebar-primary: 240 5.9% 10%;
|
||||
--sidebar-primary-foreground: 0 0% 98%;
|
||||
--sidebar-accent: 240 4.8% 95.9%;
|
||||
--sidebar-accent-foreground: 240 5.9% 10%;
|
||||
--sidebar-border: 220 13% 91%;
|
||||
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||
}
|
||||
.dark {
|
||||
--background: 240 10% 3.9%;
|
||||
--foreground: 0 0% 98%;
|
||||
--card: 240 10% 3.9%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
--popover: 240 10% 3.9%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
--primary: 0 0% 98%;
|
||||
--primary-foreground: 240 5.9% 10%;
|
||||
--secondary: 240 3.7% 15.9%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
--muted: 240 3.7% 15.9%;
|
||||
--muted-foreground: 240 5% 64.9%;
|
||||
--accent: 240 3.7% 15.9%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 240 3.7% 15.9%;
|
||||
--input: 240 3.7% 15.9%;
|
||||
--ring: 240 4.9% 83.9%;
|
||||
--chart-1: 220 70% 50%;
|
||||
--chart-2: 160 60% 45%;
|
||||
--chart-3: 30 80% 55%;
|
||||
--chart-4: 280 65% 60%;
|
||||
--chart-5: 340 75% 55%;
|
||||
--sidebar-background: 240 5.9% 10%;
|
||||
--sidebar-foreground: 240 4.8% 95.9%;
|
||||
--sidebar-primary: 224.3 76.3% 48%;
|
||||
--sidebar-primary-foreground: 0 0% 100%;
|
||||
--sidebar-accent: 240 3.7% 15.9%;
|
||||
--sidebar-accent-foreground: 240 4.8% 95.9%;
|
||||
--sidebar-border: 240 3.7% 15.9%;
|
||||
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
[data-rehype-pretty-code-fragment] {
|
||||
@apply relative text-white;
|
||||
}
|
||||
|
||||
[data-rehype-pretty-code-fragment] code {
|
||||
@apply grid min-w-full break-words rounded-none border-0 bg-transparent p-0;
|
||||
counter-reset: line;
|
||||
box-decoration-break: clone;
|
||||
}
|
||||
|
||||
[data-rehype-pretty-code-fragment] .line {
|
||||
@apply px-4 min-h-[1rem] py-0.5 w-full inline-block;
|
||||
}
|
||||
|
||||
[data-rehype-pretty-code-fragment] [data-line-numbers] .line {
|
||||
@apply px-2;
|
||||
}
|
||||
|
||||
[data-rehype-pretty-code-fragment] [data-line-numbers] > .line::before {
|
||||
@apply text-zinc-50/40 text-xs;
|
||||
counter-increment: line;
|
||||
content: counter(line);
|
||||
display: inline-block;
|
||||
width: 1.8rem;
|
||||
margin-right: 1.4rem;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
[data-rehype-pretty-code-fragment] .line--highlighted {
|
||||
@apply bg-zinc-700/50;
|
||||
}
|
||||
|
||||
[data-rehype-pretty-code-fragment] .line-highlighted span {
|
||||
@apply relative;
|
||||
}
|
||||
|
||||
[data-rehype-pretty-code-fragment] .word--highlighted {
|
||||
@apply rounded-md bg-zinc-700/50 border-zinc-700/70 p-1;
|
||||
}
|
||||
|
||||
.dark [data-rehype-pretty-code-fragment] .word--highlighted {
|
||||
@apply bg-zinc-900;
|
||||
}
|
||||
|
||||
[data-rehype-pretty-code-title] {
|
||||
@apply mt-2 pt-6 px-4 text-sm font-medium text-foreground;
|
||||
}
|
||||
|
||||
[data-rehype-pretty-code-title] + pre {
|
||||
@apply mt-2;
|
||||
}
|
||||
34
registry-template/app/layout.tsx
Normal file
34
registry-template/app/layout.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
58
registry-template/app/page.tsx
Normal file
58
registry-template/app/page.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import * as React from "react"
|
||||
import { OpenInV0Button } from "@/components/open-in-v0-button"
|
||||
import { HelloWorld } from "@/registry/new-york/hello-world/hello-world"
|
||||
import { ExampleForm } from "@/registry/new-york/example-form/example-form"
|
||||
import PokemonPage from "@/registry/new-york/complex-component/page"
|
||||
|
||||
// This page displays items from the custom registry.
|
||||
// You are free to implement this with your own design as needed.
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="max-w-3xl mx-auto flex flex-col min-h-svh px-4 py-8 gap-8">
|
||||
<header className="flex flex-col gap-1">
|
||||
<h1 className="text-3xl font-bold tracking-tight">Custom Registry</h1>
|
||||
<p className="text-muted-foreground">
|
||||
A custom registry for distributing code using shadcn.
|
||||
</p>
|
||||
</header>
|
||||
<main className="flex flex-col flex-1 gap-8">
|
||||
<div className="flex flex-col gap-4 border rounded-lg p-4 min-h-[450px] relative">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-sm text-muted-foreground sm:pl-3">
|
||||
A simple hello world component
|
||||
</h2>
|
||||
<OpenInV0Button name="hello-world" className="w-fit" />
|
||||
</div>
|
||||
<div className="flex items-center justify-center min-h-[400px] relative">
|
||||
<HelloWorld />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-4 border rounded-lg p-4 min-h-[450px] relative">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-sm text-muted-foreground sm:pl-3">
|
||||
A contact form with Zod validation.
|
||||
</h2>
|
||||
<OpenInV0Button name="example-form" className="w-fit" />
|
||||
</div>
|
||||
<div className="flex items-center justify-center min-h-[500px] relative">
|
||||
<ExampleForm />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-4 border rounded-lg p-4 min-h-[450px] relative">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-sm text-muted-foreground sm:pl-3">
|
||||
A complex component showing hooks, libs and components.
|
||||
</h2>
|
||||
<OpenInV0Button name="complex-component" className="w-fit" />
|
||||
</div>
|
||||
<div className="flex items-center justify-center min-h-[400px] relative">
|
||||
<PokemonPage />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
64
registry-template/app/registry/[name]/route.ts
Normal file
64
registry-template/app/registry/[name]/route.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { NextResponse } from "next/server"
|
||||
import path from "path"
|
||||
import { promises as fs } from "fs"
|
||||
import { registryItemSchema } from "shadcn/registry"
|
||||
|
||||
// Use the registry.json file to generate static paths.
|
||||
export const generateStaticParams = async () => {
|
||||
const registryData = await import("@/registry.json");
|
||||
const registry = registryData.default;
|
||||
|
||||
return registry.items.map((item) => ({
|
||||
name: item.name,
|
||||
}));
|
||||
};
|
||||
|
||||
// This route shows an example for serving a component using a route handler.
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ name: string }> }
|
||||
) {
|
||||
try {
|
||||
const { name } = await params
|
||||
// Cache the registry import
|
||||
const registryData = await import("@/registry.json")
|
||||
const registry = registryData.default
|
||||
|
||||
// Find the component from the registry.
|
||||
const component = registry.items.find((c) => c.name === name)
|
||||
|
||||
// If the component is not found, return a 404 error.
|
||||
if (!component) {
|
||||
return NextResponse.json(
|
||||
{ error: "Component not found" },
|
||||
{ status: 404 }
|
||||
)
|
||||
}
|
||||
|
||||
// Validate before file operations.
|
||||
const registryItem = registryItemSchema.parse(component)
|
||||
|
||||
// If the component has no files, return a 400 error.
|
||||
if (!registryItem.files?.length) {
|
||||
return NextResponse.json(
|
||||
{ error: "Component has no files" },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
// Read all files in parallel.
|
||||
const filesWithContent = await Promise.all(
|
||||
registryItem.files.map(async (file) => {
|
||||
const filePath = path.join(process.cwd(), file.path)
|
||||
const content = await fs.readFile(filePath, "utf8")
|
||||
return { ...file, content }
|
||||
})
|
||||
)
|
||||
|
||||
// Return the component with the files.
|
||||
return NextResponse.json({ ...registryItem, files: filesWithContent })
|
||||
} catch (error) {
|
||||
console.error("Error processing component request:", error)
|
||||
return NextResponse.json({ error: "Something went wrong" }, { status: 500 })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user