This commit is contained in:
2025-05-06 02:13:23 +08:00
commit 22baba9e7b
52 changed files with 13258 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View 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;
}

View 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>
);
}

View 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>
)
}

View 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 })
}
}