mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-06-26 14:16:08 +00:00
feat: update open in v0
This commit is contained in:
@@ -16,7 +16,8 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A simple sidebar with navigation grouped by section."
|
||||
export const description =
|
||||
"A simple sidebar with navigation grouped by section."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar with collapsible sections."
|
||||
export const description = "A sidebar with collapsible sections."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar with submenus."
|
||||
export const description = "A sidebar with submenus."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A floating sidebar with submenus."
|
||||
export const description = "A floating sidebar with submenus."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar with collapsible submenus."
|
||||
export const description = "A sidebar with collapsible submenus."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar with submenus as dropdowns."
|
||||
export const description = "A sidebar with submenus as dropdowns."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar that collapses to icons."
|
||||
export const description = "A sidebar that collapses to icons."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "An inset sidebar with secondary navigation."
|
||||
export const description = "An inset sidebar with secondary navigation."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "Collapsible nested sidebars"
|
||||
export const description = "Collapsible nested sidebars"
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar in a popover."
|
||||
export const description = "A sidebar in a popover."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar with a collapsible file tree."
|
||||
export const description = "A sidebar with a collapsible file tree."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar with a calendar."
|
||||
export const description = "A sidebar with a calendar."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -2,7 +2,7 @@ import { SettingsDialog } from "@/registry/default/block/sidebar-13/components/s
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar in a dialog."
|
||||
export const description = "A sidebar in a dialog."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar on the right."
|
||||
export const description = "A sidebar on the right."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A left and right sidebar."
|
||||
export const description = "A left and right sidebar."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,7 @@
|
||||
import { LoginForm } from "@/registry/new-york/block/login-01/components/login-form"
|
||||
|
||||
export const description = "A simple login form."
|
||||
|
||||
export const iframeHeight = "870px"
|
||||
|
||||
export const containerClassName = "w-full h-full"
|
||||
|
||||
@@ -16,7 +16,8 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A simple sidebar with navigation grouped by section."
|
||||
export const description =
|
||||
"A simple sidebar with navigation grouped by section."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar with collapsible sections."
|
||||
export const description = "A sidebar with collapsible sections."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar with submenus."
|
||||
export const description = "A sidebar with submenus."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A floating sidebar with submenus."
|
||||
export const description = "A floating sidebar with submenus."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar with collapsible submenus."
|
||||
export const description = "A sidebar with collapsible submenus."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar with submenus as dropdowns."
|
||||
export const description = "A sidebar with submenus as dropdowns."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar that collapses to icons."
|
||||
export const description = "A sidebar that collapses to icons."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "An inset sidebar with secondary navigation."
|
||||
export const description = "An inset sidebar with secondary navigation."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "Collapsible nested sidebars."
|
||||
export const description = "Collapsible nested sidebars."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar in a popover."
|
||||
export const description = "A sidebar in a popover."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar with a collapsible file tree."
|
||||
export const description = "A sidebar with a collapsible file tree."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar with a calendar."
|
||||
export const description = "A sidebar with a calendar."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -2,7 +2,7 @@ import { SettingsDialog } from "@/registry/new-york/block/sidebar-13/components/
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar in a dialog."
|
||||
export const description = "A sidebar in a dialog."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A sidebar on the right."
|
||||
export const description = "A sidebar on the right."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
|
||||
export const iframeHeight = "800px"
|
||||
|
||||
export const teaser = "A left and right sidebar."
|
||||
export const description = "A left and right sidebar."
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
||||
@@ -2,28 +2,69 @@
|
||||
|
||||
import { track } from "@vercel/analytics/server"
|
||||
import { capitalCase } from "change-case"
|
||||
import { z } from "zod"
|
||||
|
||||
import { Style } from "@/registry/registry-styles"
|
||||
import { registryEntrySchema, registryItemTypeSchema } from "@/registry/schema"
|
||||
|
||||
async function getRegistryItem(name: string, style: Style["name"]) {
|
||||
const registryURL = new URL(
|
||||
`${process.env.NEXT_PUBLIC_APP_URL}/r/styles/${style}/${name}.json`
|
||||
)
|
||||
const response = await fetch(registryURL)
|
||||
|
||||
if (!response.ok) {
|
||||
return null
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
const result = registryEntrySchema
|
||||
.extend({
|
||||
files: z.array(
|
||||
z.object({
|
||||
path: z.string(),
|
||||
content: z.string().optional(),
|
||||
type: registryItemTypeSchema,
|
||||
target: z.string().optional(),
|
||||
})
|
||||
),
|
||||
})
|
||||
.safeParse(data)
|
||||
|
||||
if (!result.success) {
|
||||
console.error(result.error)
|
||||
return null
|
||||
}
|
||||
|
||||
return result.data
|
||||
}
|
||||
|
||||
export async function editInV0({
|
||||
name,
|
||||
title,
|
||||
description,
|
||||
style,
|
||||
code,
|
||||
url,
|
||||
}: {
|
||||
name: string
|
||||
title?: string
|
||||
description: string
|
||||
style: string
|
||||
code: string
|
||||
style: Style["name"]
|
||||
url: string
|
||||
}) {
|
||||
style = style ?? "new-york"
|
||||
try {
|
||||
title =
|
||||
title ??
|
||||
capitalCase(
|
||||
name.replace(/\d+/g, "").replace("-demo", "").replace("-", " ")
|
||||
)
|
||||
const registryItem = await getRegistryItem(name, style)
|
||||
|
||||
if (!registryItem) {
|
||||
return { error: "Something went wrong. Please try again later." }
|
||||
}
|
||||
|
||||
const title = capitalCase(
|
||||
registryItem.name
|
||||
.replace(/\d+/g, "")
|
||||
.replace("-demo", "")
|
||||
.replace("-", " ")
|
||||
)
|
||||
|
||||
const description = registryItem.description ?? title
|
||||
|
||||
await track("edit_in_v0", {
|
||||
name,
|
||||
@@ -33,12 +74,8 @@ export async function editInV0({
|
||||
url,
|
||||
})
|
||||
|
||||
// Replace "use client" in the code.
|
||||
// v0 will handle this for us.
|
||||
// code = code.replace(`"use client"`, "")
|
||||
|
||||
// Remove export const description = "..."
|
||||
code = code.replace(/export const description =\s*".*";?/, "")
|
||||
// TODO: support multiple files.
|
||||
let code = registryItem.files?.[0]?.content
|
||||
|
||||
const payload = {
|
||||
title,
|
||||
@@ -54,6 +91,8 @@ export async function editInV0({
|
||||
},
|
||||
}
|
||||
|
||||
console.log(payload)
|
||||
|
||||
const response = await fetch(`${process.env.V0_URL}/chat/api/open-in-v0`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload),
|
||||
|
||||
@@ -1,30 +1,27 @@
|
||||
import * as React from "react"
|
||||
import { unstable_cache } from "next/cache"
|
||||
|
||||
import { getAllBlockIds } from "@/lib/blocks"
|
||||
import { THEMES } from "@/lib/themes"
|
||||
import { BlockDisplay } from "@/components/block-display"
|
||||
import { ThemesSwitcher } from "@/components/themes-selector"
|
||||
|
||||
const BLOCKS_WHITELIST_PREFIXES = ["sidebar", "login"]
|
||||
|
||||
const getBlocks = unstable_cache(async () => {
|
||||
return (await getAllBlockIds()).filter((name) =>
|
||||
BLOCKS_WHITELIST_PREFIXES.some((prefix) => name.startsWith(prefix))
|
||||
)
|
||||
}, ["blocks"])
|
||||
|
||||
export default async function BlocksPage() {
|
||||
const blocks = (await getAllBlockIds()).filter(
|
||||
(name) =>
|
||||
!name.startsWith("chart-") &&
|
||||
!name.startsWith("sidebar-01") &&
|
||||
!name.startsWith("login-01")
|
||||
)
|
||||
|
||||
// These themes are not compatible with the blocks yet.
|
||||
const themes = THEMES.filter(
|
||||
(theme) => !["default-daylight", "default-midnight"].includes(theme.id)
|
||||
)
|
||||
const blocks = await getBlocks()
|
||||
|
||||
return (
|
||||
<div className="gap-3 md:flex md:flex-row-reverse md:items-start">
|
||||
<ThemesSwitcher
|
||||
themes={themes}
|
||||
className="fixed inset-x-0 bottom-0 z-40 mt-12 flex bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 lg:sticky lg:bottom-auto lg:top-20"
|
||||
/>
|
||||
<div className="grid flex-1 gap-24 lg:gap-48">
|
||||
{blocks.map((name, index) => (
|
||||
<BlockDisplay key={`${name}-${index}`} name={name} />
|
||||
<React.Suspense key={`${name}-${index}`}>
|
||||
<BlockDisplay name={name} />
|
||||
</React.Suspense>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,6 @@ import { getAllBlockIds, getBlock } from "@/lib/blocks"
|
||||
import { absoluteUrl, cn } from "@/lib/utils"
|
||||
import { BlockChunk } from "@/components/block-chunk"
|
||||
import { BlockWrapper } from "@/components/block-wrapper"
|
||||
import { ThemesStyle } from "@/components/themes-styles"
|
||||
import { Style, styles } from "@/registry/registry-styles"
|
||||
|
||||
import "@/styles/mdx.css"
|
||||
@@ -26,12 +25,15 @@ export async function generateMetadata({
|
||||
return {}
|
||||
}
|
||||
|
||||
const title = block.name
|
||||
const description = block.description
|
||||
|
||||
return {
|
||||
title: block.name,
|
||||
description: block.description,
|
||||
title,
|
||||
description,
|
||||
openGraph: {
|
||||
title: block.name,
|
||||
description: block.description,
|
||||
title,
|
||||
description,
|
||||
type: "article",
|
||||
url: absoluteUrl(`/blocks/${block.name}`),
|
||||
images: [
|
||||
@@ -45,8 +47,8 @@ export async function generateMetadata({
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: block.name,
|
||||
description: block.description,
|
||||
title,
|
||||
description,
|
||||
images: [siteConfig.ogImage],
|
||||
creator: "@shadcn",
|
||||
},
|
||||
|
||||
@@ -46,15 +46,7 @@ export function BlockChunk({
|
||||
name={chunk.name}
|
||||
code={chunk.code}
|
||||
/>
|
||||
<V0Button
|
||||
size="icon"
|
||||
block={{
|
||||
name: chunk.name,
|
||||
description: chunk.description || "",
|
||||
code: chunk.code,
|
||||
style: block.style,
|
||||
}}
|
||||
/>
|
||||
<V0Button size="icon" name={chunk.name} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,29 +1,32 @@
|
||||
import { unstable_cache } from "next/cache"
|
||||
|
||||
import { getBlock } from "@/lib/blocks"
|
||||
import { BlockPreview } from "@/components/block-preview"
|
||||
import { styles } from "@/registry/registry-styles"
|
||||
|
||||
const getBlockByName = unstable_cache(
|
||||
async (name: string) => {
|
||||
const block = await getBlock(name)
|
||||
|
||||
if (!block) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
name: block.name,
|
||||
style: block.style,
|
||||
description: block.description,
|
||||
container: block.container,
|
||||
}
|
||||
},
|
||||
["block"]
|
||||
)
|
||||
|
||||
export async function BlockDisplay({ name }: { name: string }) {
|
||||
const blocks = await Promise.all(
|
||||
styles.map(async (style) => {
|
||||
const block = await getBlock(name, style.name)
|
||||
const hasLiftMode = block?.chunks ? block?.chunks?.length > 0 : false
|
||||
const block = await getBlockByName(name)
|
||||
|
||||
// Cannot (and don't need to) pass to the client.
|
||||
delete block?.component
|
||||
delete block?.chunks
|
||||
|
||||
return {
|
||||
...block,
|
||||
hasLiftMode,
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
if (!blocks?.length) {
|
||||
if (!block) {
|
||||
return null
|
||||
}
|
||||
|
||||
return blocks.map((block) => (
|
||||
<BlockPreview key={`${block.style}-${block.name}`} block={block} />
|
||||
))
|
||||
return <BlockPreview key={block.name} block={block} />
|
||||
}
|
||||
|
||||
@@ -3,37 +3,24 @@
|
||||
import * as React from "react"
|
||||
import { ImperativePanelHandle } from "react-resizable-panels"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { useConfig } from "@/hooks/use-config"
|
||||
import { useLiftMode } from "@/hooks/use-lift-mode"
|
||||
import { BlockToolbar } from "@/components/block-toolbar"
|
||||
import { Icons } from "@/components/icons"
|
||||
import {
|
||||
ResizableHandle,
|
||||
ResizablePanel,
|
||||
ResizablePanelGroup,
|
||||
} from "@/registry/new-york/ui/resizable"
|
||||
import { Tabs, TabsContent } from "@/registry/new-york/ui/tabs"
|
||||
import { Block } from "@/registry/schema"
|
||||
import { type Block } from "@/registry/schema"
|
||||
|
||||
export function BlockPreview({
|
||||
block,
|
||||
}: {
|
||||
block: Block & { hasLiftMode: boolean }
|
||||
block: Pick<Block, "name" | "style" | "description" | "container">
|
||||
}) {
|
||||
const [config] = useConfig()
|
||||
const { isLiftMode } = useLiftMode(block.name)
|
||||
const [isLoading, setIsLoading] = React.useState(true)
|
||||
const ref = React.useRef<ImperativePanelHandle>(null)
|
||||
|
||||
if (config.style !== block.style) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
<div
|
||||
id={block.name}
|
||||
defaultValue="preview"
|
||||
className="relative grid w-full scroll-m-20 gap-4"
|
||||
style={
|
||||
{
|
||||
@@ -42,52 +29,22 @@ export function BlockPreview({
|
||||
}
|
||||
>
|
||||
<BlockToolbar block={block} resizablePanelRef={ref} />
|
||||
<TabsContent
|
||||
value="preview"
|
||||
className="relative after:absolute after:inset-0 after:right-3 after:z-0 after:rounded-lg after:bg-muted"
|
||||
>
|
||||
<ResizablePanelGroup direction="horizontal" className="relative z-10">
|
||||
<ResizablePanel
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative rounded-lg border bg-background",
|
||||
isLiftMode ? "border-border/50" : "border-border"
|
||||
)}
|
||||
defaultSize={100}
|
||||
minSize={30}
|
||||
>
|
||||
{isLoading ? (
|
||||
<div className="absolute inset-0 z-10 flex h-[--container-height] w-full items-center justify-center gap-2 bg-background text-sm text-muted-foreground">
|
||||
<Icons.spinner className="h-4 w-4 animate-spin" />
|
||||
Loading...
|
||||
</div>
|
||||
) : null}
|
||||
<iframe
|
||||
src={`/blocks/${block.style}/${block.name}`}
|
||||
height={block.container?.height ?? 450}
|
||||
className="chunk-mode relative z-20 w-full bg-background"
|
||||
onLoad={() => {
|
||||
setIsLoading(false)
|
||||
}}
|
||||
allowTransparency
|
||||
/>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle
|
||||
className={cn(
|
||||
"relative hidden w-3 bg-transparent p-0 after:absolute after:right-0 after:top-1/2 after:h-8 after:w-[6px] after:-translate-y-1/2 after:translate-x-[-1px] after:rounded-full after:bg-border after:transition-all after:hover:h-10 sm:block",
|
||||
isLiftMode && "invisible"
|
||||
)}
|
||||
<ResizablePanelGroup direction="horizontal" className="relative z-10">
|
||||
<ResizablePanel
|
||||
ref={ref}
|
||||
className="relative rounded-lg border bg-background"
|
||||
defaultSize={100}
|
||||
minSize={30}
|
||||
>
|
||||
<iframe
|
||||
src={`/blocks/${block.style}/${block.name}`}
|
||||
height={block.container?.height ?? 450}
|
||||
className="chunk-mode relative z-20 w-full bg-background"
|
||||
/>
|
||||
<ResizablePanel defaultSize={0} minSize={0} />
|
||||
</ResizablePanelGroup>
|
||||
</TabsContent>
|
||||
<TabsContent value="code">
|
||||
<div
|
||||
data-rehype-pretty-code-fragment
|
||||
dangerouslySetInnerHTML={{ __html: block.highlightedCode }}
|
||||
className="w-full overflow-hidden rounded-md [&_pre]:my-0 [&_pre]:h-[--container-height] [&_pre]:overflow-auto [&_pre]:whitespace-break-spaces [&_pre]:p-6 [&_pre]:font-mono [&_pre]:text-sm [&_pre]:leading-relaxed"
|
||||
/>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle className="relative hidden w-3 bg-transparent p-0 after:absolute after:right-0 after:top-1/2 after:h-8 after:w-[6px] after:-translate-y-1/2 after:translate-x-[-1px] after:rounded-full after:bg-border after:transition-all after:hover:h-10 sm:block" />
|
||||
<ResizablePanel defaultSize={0} minSize={0} />
|
||||
</ResizablePanelGroup>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,25 +1,21 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { CircleHelp, Monitor, Smartphone, Tablet } from "lucide-react"
|
||||
import Link from "next/link"
|
||||
import {
|
||||
Check,
|
||||
Fullscreen,
|
||||
Monitor,
|
||||
Smartphone,
|
||||
Tablet,
|
||||
Terminal,
|
||||
} from "lucide-react"
|
||||
import { ImperativePanelHandle } from "react-resizable-panels"
|
||||
|
||||
import { trackEvent } from "@/lib/events"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { useLiftMode } from "@/hooks/use-lift-mode"
|
||||
import { BlockCopyButton } from "@/components/block-copy-button"
|
||||
import { StyleSwitcher } from "@/components/style-switcher"
|
||||
import { useCopyToClipboard } from "@/hooks/use-copy-to-clipboard"
|
||||
import { V0Button } from "@/components/v0-button"
|
||||
import { Badge } from "@/registry/new-york/ui/badge"
|
||||
import { Label } from "@/registry/new-york/ui/label"
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/registry/new-york/ui/popover"
|
||||
import { Button } from "@/registry/new-york/ui/button"
|
||||
import { Separator } from "@/registry/new-york/ui/separator"
|
||||
import { Switch } from "@/registry/new-york/ui/switch"
|
||||
import { TabsList, TabsTrigger } from "@/registry/new-york/ui/tabs"
|
||||
import {
|
||||
ToggleGroup,
|
||||
ToggleGroupItem,
|
||||
@@ -30,172 +26,85 @@ export function BlockToolbar({
|
||||
block,
|
||||
resizablePanelRef,
|
||||
}: {
|
||||
block: Block & { hasLiftMode: boolean }
|
||||
block: Pick<Block, "name" | "style" | "description" | "container">
|
||||
resizablePanelRef: React.RefObject<ImperativePanelHandle>
|
||||
}) {
|
||||
const { isLiftMode, toggleLiftMode } = useLiftMode(block.name)
|
||||
const { copyToClipboard, isCopied } = useCopyToClipboard()
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<TabsList className="hidden h-7 rounded-md p-0 px-[calc(theme(spacing.1)_-_2px)] py-[theme(spacing.1)] sm:flex">
|
||||
<TabsTrigger
|
||||
value="preview"
|
||||
className="h-[1.45rem] rounded-sm px-2 text-xs"
|
||||
disabled={isLiftMode}
|
||||
>
|
||||
Preview
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="code"
|
||||
className="h-[1.45rem] rounded-sm px-2 text-xs"
|
||||
disabled={isLiftMode}
|
||||
>
|
||||
Code
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<Button asChild variant="link">
|
||||
<a href={`#${block.name}`}>{block.description}</a>
|
||||
</Button>
|
||||
<div className="ml-auto flex items-center gap-2 md:pr-[14px]">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-7 rounded-md border bg-muted shadow-none"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
copyToClipboard(`npx shadcn@latest add ${block.name}`)
|
||||
}}
|
||||
>
|
||||
{isCopied ? <Check /> : <Terminal />}
|
||||
npx shadcn add {block.name}
|
||||
</Button>
|
||||
<Separator orientation="vertical" className="mx-2 hidden h-4 md:flex" />
|
||||
<StyleSwitcher
|
||||
className="h-[calc(theme(spacing.7)_-_1px)] dark:h-7"
|
||||
disabled={isLiftMode}
|
||||
/>
|
||||
<Popover>
|
||||
<PopoverTrigger
|
||||
disabled={isLiftMode}
|
||||
className="hidden text-muted-foreground hover:text-foreground disabled:opacity-50 sm:flex"
|
||||
>
|
||||
<CircleHelp className="h-3.5 w-3.5" />
|
||||
<span className="sr-only">Block description</span>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
side="top"
|
||||
sideOffset={20}
|
||||
className="space-y-3 rounded-[0.5rem] text-sm"
|
||||
>
|
||||
<p className="font-medium">
|
||||
What is the difference between the New York and Default style?
|
||||
</p>
|
||||
<p>
|
||||
A style comes with its own set of components, animations, icons
|
||||
and more.
|
||||
</p>
|
||||
<p>
|
||||
The <span className="font-medium">Default</span> style has larger
|
||||
inputs, uses lucide-react for icons and tailwindcss-animate for
|
||||
animations.
|
||||
</p>
|
||||
<p>
|
||||
The <span className="font-medium">New York</span> style ships with
|
||||
smaller buttons and inputs. It also uses shadows on cards and
|
||||
buttons.
|
||||
</p>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<div className="hidden items-center gap-2 sm:flex">
|
||||
<Separator
|
||||
orientation="vertical"
|
||||
className="mx-2 mr-0 hidden h-4 md:flex"
|
||||
/>
|
||||
<div className="flex items-center gap-2">
|
||||
<a href={`#${block.name}`}>
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className={cn("bg-transparent", isLiftMode && "opacity-50")}
|
||||
>
|
||||
{block.name}
|
||||
</Badge>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{block.code && (
|
||||
<div className="ml-auto flex items-center gap-2 md:pr-[14px]">
|
||||
{block.hasLiftMode && (
|
||||
<>
|
||||
<div className="hidden h-7 items-center justify-between gap-2 md:flex">
|
||||
<Label htmlFor={`lift-mode-${block.name}`} className="text-xs">
|
||||
Lift Mode
|
||||
</Label>
|
||||
<Switch
|
||||
id={`lift-mode-${block.name}`}
|
||||
checked={isLiftMode}
|
||||
onCheckedChange={(value) => {
|
||||
resizablePanelRef.current?.resize(100)
|
||||
toggleLiftMode(block.name)
|
||||
|
||||
if (value) {
|
||||
trackEvent({
|
||||
name: "enable_lift_mode",
|
||||
properties: {
|
||||
name: block.name,
|
||||
},
|
||||
})
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Separator
|
||||
orientation="vertical"
|
||||
className="mx-2 hidden h-4 lg:inline-flex"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<div className="hidden h-[28px] items-center gap-1.5 rounded-md border p-[2px] shadow-sm md:flex">
|
||||
<ToggleGroup
|
||||
disabled={isLiftMode}
|
||||
type="single"
|
||||
defaultValue="100"
|
||||
onValueChange={(value) => {
|
||||
if (resizablePanelRef.current) {
|
||||
resizablePanelRef.current.resize(parseInt(value))
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ToggleGroupItem
|
||||
value="100"
|
||||
className="h-[22px] w-[22px] rounded-sm p-0"
|
||||
>
|
||||
<Monitor className="h-3.5 w-3.5" />
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
value="60"
|
||||
className="h-[22px] w-[22px] rounded-sm p-0"
|
||||
>
|
||||
<Tablet className="h-3.5 w-3.5" />
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
value="30"
|
||||
className="h-[22px] w-[22px] rounded-sm p-0"
|
||||
>
|
||||
<Smartphone className="h-3.5 w-3.5" />
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
<Separator
|
||||
orientation="vertical"
|
||||
className="mx-2 hidden h-4 md:flex"
|
||||
/>
|
||||
<BlockCopyButton
|
||||
event="copy_block_code"
|
||||
name={block.name}
|
||||
code={block.code}
|
||||
disabled={isLiftMode}
|
||||
/>
|
||||
<V0Button
|
||||
className="hidden md:flex"
|
||||
id={`v0-button-${block.name}`}
|
||||
disabled={
|
||||
isLiftMode || ["login-01", "sidebar-01"].includes(block.name)
|
||||
}
|
||||
block={{
|
||||
name: block.name,
|
||||
description: block.description || "Edit in v0",
|
||||
code: block.code,
|
||||
style: block.style,
|
||||
<div className="hidden h-7 items-center gap-1.5 rounded-md border p-[2px] shadow-none md:flex">
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
defaultValue="100"
|
||||
onValueChange={(value) => {
|
||||
if (resizablePanelRef.current) {
|
||||
resizablePanelRef.current.resize(parseInt(value))
|
||||
}
|
||||
}}
|
||||
/>
|
||||
>
|
||||
<ToggleGroupItem
|
||||
value="100"
|
||||
className="h-[22px] w-[22px] rounded-sm p-0"
|
||||
title="Desktop"
|
||||
>
|
||||
<Monitor className="h-3.5 w-3.5" />
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
value="60"
|
||||
className="h-[22px] w-[22px] rounded-sm p-0"
|
||||
title="Tablet"
|
||||
>
|
||||
<Tablet className="h-3.5 w-3.5" />
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
value="30"
|
||||
className="h-[22px] w-[22px] rounded-sm p-0"
|
||||
title="Mobile"
|
||||
>
|
||||
<Smartphone className="h-3.5 w-3.5" />
|
||||
</ToggleGroupItem>
|
||||
<Separator orientation="vertical" className="h-4" />
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
className="h-[22px] w-[22px] rounded-sm p-0"
|
||||
asChild
|
||||
title="Open in New Tab"
|
||||
>
|
||||
<Link
|
||||
href={`/blocks/${block.style}/${block.name}`}
|
||||
target="_blank"
|
||||
>
|
||||
<span className="sr-only">Open in New Tab</span>
|
||||
<Fullscreen className="h-3.5 w-3.5" />
|
||||
</Link>
|
||||
</Button>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
)}
|
||||
<Separator orientation="vertical" className="mx-2 hidden h-4 md:flex" />
|
||||
<V0Button
|
||||
className="hidden shadow-none md:flex"
|
||||
id={`v0-button-${block.name}`}
|
||||
name={block.name}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -92,12 +92,7 @@ ${Object.entries(themesConfig?.activeTheme.cssVars.dark || {})
|
||||
/>
|
||||
<V0Button
|
||||
id={`v0-button-${chart.name}`}
|
||||
block={{
|
||||
name: chart.name,
|
||||
description: chart.description || "Edit in v0",
|
||||
code: chart.code,
|
||||
style: "default",
|
||||
}}
|
||||
name={chart.name}
|
||||
className="h-7"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -116,16 +116,7 @@ export function ComponentPreview({
|
||||
<div className="flex items-center justify-between p-4">
|
||||
<StyleSwitcher />
|
||||
<div className="flex items-center gap-2">
|
||||
{config.style === "default" && description ? (
|
||||
<V0Button
|
||||
block={{
|
||||
code: codeString,
|
||||
name,
|
||||
style: config.style,
|
||||
description,
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
{description ? <V0Button name={name} /> : null}
|
||||
<CopyButton
|
||||
value={codeString}
|
||||
variant="outline"
|
||||
|
||||
@@ -13,7 +13,7 @@ export const Icons = {
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="16"
|
||||
strokeWidth="32"
|
||||
/>
|
||||
<line
|
||||
x1="192"
|
||||
@@ -24,7 +24,7 @@ export const Icons = {
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="16"
|
||||
strokeWidth="32"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
TooltipTrigger,
|
||||
} from "@/registry/new-york/ui/tooltip"
|
||||
import { Style } from "@/registry/registry-styles"
|
||||
import { Block } from "@/registry/schema"
|
||||
|
||||
type Size = "default" | "icon"
|
||||
|
||||
@@ -48,13 +47,13 @@ function V0Tooltip({
|
||||
}
|
||||
|
||||
export function V0Button({
|
||||
block,
|
||||
name,
|
||||
size = "default",
|
||||
disabled,
|
||||
className,
|
||||
...props
|
||||
}: {
|
||||
block: Pick<Block, "name" | "description" | "code" | "style">
|
||||
name: string
|
||||
size?: Size
|
||||
} & ButtonProps) {
|
||||
const [url, setUrl] = React.useState("https://ui.shadcn.com")
|
||||
@@ -63,51 +62,12 @@ export function V0Button({
|
||||
setUrl(window.location.href)
|
||||
}, [])
|
||||
|
||||
if (block.style === "new-york") {
|
||||
return (
|
||||
<V0Tooltip size={size} style={block.style}>
|
||||
<Button
|
||||
aria-label="Open in v0"
|
||||
className={cn(
|
||||
"z-50 h-[calc(theme(spacing.7)_-_1px)] gap-1 rounded-[6px] bg-black px-3 text-xs text-white hover:bg-black hover:text-white dark:bg-white dark:text-black",
|
||||
size === "icon" && "h-7 w-7 p-0",
|
||||
className
|
||||
)}
|
||||
onClick={() => {
|
||||
toast("New York not available.", {
|
||||
description: (
|
||||
<div className="flex items-center">
|
||||
Only the Default style is available in{" "}
|
||||
<V0Logo className="ml-1 text-foreground" aria-label="v0" />.
|
||||
</div>
|
||||
),
|
||||
})
|
||||
}}
|
||||
disabled={
|
||||
block.style === "new-york" && size === "icon" ? true : disabled
|
||||
}
|
||||
{...props}
|
||||
>
|
||||
{size === "icon" ? (
|
||||
<V0Logo className="h-4 w-4" />
|
||||
) : (
|
||||
<>
|
||||
Open in <V0Logo />
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</V0Tooltip>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<form
|
||||
action={async () => {
|
||||
try {
|
||||
const result = await editInV0({
|
||||
name: block.name,
|
||||
description: block.description || "",
|
||||
code: block.code,
|
||||
style: block.style,
|
||||
name,
|
||||
url,
|
||||
})
|
||||
|
||||
@@ -142,7 +102,7 @@ function Form({
|
||||
size = "default",
|
||||
className,
|
||||
...props
|
||||
}: Omit<React.ComponentProps<typeof V0Button>, "block">) {
|
||||
}: Omit<React.ComponentProps<typeof V0Button>, "name">) {
|
||||
const { pending } = useFormStatus()
|
||||
|
||||
return (
|
||||
|
||||
@@ -11,7 +11,7 @@ import { highlightCode } from "@/lib/highlight-code"
|
||||
import { Style } from "@/registry/registry-styles"
|
||||
import { BlockChunk, blockSchema, registryEntrySchema } from "@/registry/schema"
|
||||
|
||||
const DEFAULT_BLOCKS_STYLE = "default" satisfies Style["name"]
|
||||
const DEFAULT_BLOCKS_STYLE = "new-york" satisfies Style["name"]
|
||||
|
||||
const project = new Project({
|
||||
compilerOptions: {},
|
||||
@@ -32,44 +32,55 @@ export async function getBlock(
|
||||
|
||||
const content = await _getBlockContent(name, style)
|
||||
|
||||
const chunks = await Promise.all(
|
||||
entry.chunks?.map(async (chunk: BlockChunk) => {
|
||||
const code = await readFile(chunk.file)
|
||||
const chunks = entry?.chunks
|
||||
? await Promise.all(
|
||||
entry?.chunks?.map(async (chunk: BlockChunk) => {
|
||||
const code = await readFile(chunk.file)
|
||||
|
||||
const tempFile = await createTempSourceFile(`${chunk.name}.tsx`)
|
||||
const sourceFile = project.createSourceFile(tempFile, code, {
|
||||
scriptKind: ScriptKind.TSX,
|
||||
})
|
||||
const tempFile = await createTempSourceFile(`${chunk.name}.tsx`)
|
||||
const sourceFile = project.createSourceFile(tempFile, code, {
|
||||
scriptKind: ScriptKind.TSX,
|
||||
})
|
||||
|
||||
sourceFile
|
||||
.getDescendantsOfKind(SyntaxKind.JsxOpeningElement)
|
||||
.filter((node) => {
|
||||
return node.getAttribute("x-chunk") !== undefined
|
||||
})
|
||||
?.map((component) => {
|
||||
component
|
||||
.getAttribute("x-chunk")
|
||||
?.asKind(SyntaxKind.JsxAttribute)
|
||||
?.remove()
|
||||
sourceFile
|
||||
.getDescendantsOfKind(SyntaxKind.JsxOpeningElement)
|
||||
.filter((node) => {
|
||||
return node.getAttribute("x-chunk") !== undefined
|
||||
})
|
||||
?.map((component) => {
|
||||
component
|
||||
.getAttribute("x-chunk")
|
||||
?.asKind(SyntaxKind.JsxAttribute)
|
||||
?.remove()
|
||||
})
|
||||
|
||||
return {
|
||||
...chunk,
|
||||
code: sourceFile
|
||||
.getText()
|
||||
.replaceAll(`@/registry/${style}/`, "@/components/"),
|
||||
}
|
||||
})
|
||||
)
|
||||
: []
|
||||
|
||||
return {
|
||||
...chunk,
|
||||
code: sourceFile
|
||||
.getText()
|
||||
.replaceAll(`@/registry/${style}/`, "@/components/"),
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
return blockSchema.parse({
|
||||
const block = {
|
||||
style,
|
||||
highlightedCode: content.code ? await highlightCode(content.code) : "",
|
||||
...entry,
|
||||
...content,
|
||||
chunks,
|
||||
type: "registry:block",
|
||||
})
|
||||
}
|
||||
|
||||
const result = blockSchema.safeParse(block)
|
||||
|
||||
if (!result.success) {
|
||||
console.log(block)
|
||||
return null
|
||||
}
|
||||
|
||||
return result.data
|
||||
}
|
||||
|
||||
async function _getAllBlocks(style: Style["name"] = DEFAULT_BLOCKS_STYLE) {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"format:check": "prettier --check \"**/*.{ts,tsx,mdx}\" --cache"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/is-prop-valid": "^1.3.1",
|
||||
"@faker-js/faker": "^8.2.0",
|
||||
"@hookform/resolvers": "^3.1.0",
|
||||
"@radix-ui/react-accessible-icon": "^1.0.3",
|
||||
|
||||
BIN
apps/www/public/avatars/shadcn.jpg
Normal file
BIN
apps/www/public/avatars/shadcn.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
15
apps/www/public/r/styles/default/accordion-demo.json
Normal file
15
apps/www/public/r/styles/default/accordion-demo.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "accordion-demo",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"accordion"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/accordion-demo.tsx",
|
||||
"content": "import {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger,\n} from \"@/registry/default/ui/accordion\"\n\nexport default function AccordionDemo() {\n return (\n <Accordion type=\"single\" collapsible className=\"w-full\">\n <AccordionItem value=\"item-1\">\n <AccordionTrigger>Is it accessible?</AccordionTrigger>\n <AccordionContent>\n Yes. It adheres to the WAI-ARIA design pattern.\n </AccordionContent>\n </AccordionItem>\n <AccordionItem value=\"item-2\">\n <AccordionTrigger>Is it styled?</AccordionTrigger>\n <AccordionContent>\n Yes. It comes with default styles that matches the other\n components' aesthetic.\n </AccordionContent>\n </AccordionItem>\n <AccordionItem value=\"item-3\">\n <AccordionTrigger>Is it animated?</AccordionTrigger>\n <AccordionContent>\n Yes. It's animated by default, but you can disable it if you\n prefer.\n </AccordionContent>\n </AccordionItem>\n </Accordion>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/alert-demo.json
Normal file
15
apps/www/public/r/styles/default/alert-demo.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "alert-demo",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"alert"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/alert-demo.tsx",
|
||||
"content": "import { Terminal } from \"lucide-react\"\n\nimport {\n Alert,\n AlertDescription,\n AlertTitle,\n} from \"@/registry/default/ui/alert\"\n\nexport default function AlertDemo() {\n return (\n <Alert>\n <Terminal className=\"h-4 w-4\" />\n <AlertTitle>Heads up!</AlertTitle>\n <AlertDescription>\n You can add components to your app using the cli.\n </AlertDescription>\n </Alert>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/alert-destructive.json
Normal file
15
apps/www/public/r/styles/default/alert-destructive.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "alert-destructive",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"alert"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/alert-destructive.tsx",
|
||||
"content": "import { AlertCircle } from \"lucide-react\"\n\nimport {\n Alert,\n AlertDescription,\n AlertTitle,\n} from \"@/registry/default/ui/alert\"\n\nexport default function AlertDestructive() {\n return (\n <Alert variant=\"destructive\">\n <AlertCircle className=\"h-4 w-4\" />\n <AlertTitle>Error</AlertTitle>\n <AlertDescription>\n Your session has expired. Please log in again.\n </AlertDescription>\n </Alert>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
16
apps/www/public/r/styles/default/alert-dialog-demo.json
Normal file
16
apps/www/public/r/styles/default/alert-dialog-demo.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "alert-dialog-demo",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"alert-dialog",
|
||||
"button"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/alert-dialog-demo.tsx",
|
||||
"content": "import {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from \"@/registry/default/ui/alert-dialog\"\nimport { Button } from \"@/registry/default/ui/button\"\n\nexport default function AlertDialogDemo() {\n return (\n <AlertDialog>\n <AlertDialogTrigger asChild>\n <Button variant=\"outline\">Show Dialog</Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction>Continue</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/aspect-ratio-demo.json
Normal file
15
apps/www/public/r/styles/default/aspect-ratio-demo.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "aspect-ratio-demo",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"aspect-ratio"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/aspect-ratio-demo.tsx",
|
||||
"content": "import Image from \"next/image\"\n\nimport { AspectRatio } from \"@/registry/default/ui/aspect-ratio\"\n\nexport default function AspectRatioDemo() {\n return (\n <AspectRatio ratio={16 / 9} className=\"bg-muted\">\n <Image\n src=\"https://images.unsplash.com/photo-1588345921523-c2dcdb7f1dcd?w=800&dpr=2&q=80\"\n alt=\"Photo by Drew Beamer\"\n fill\n className=\"h-full w-full rounded-md object-cover\"\n />\n </AspectRatio>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/avatar-demo.json
Normal file
15
apps/www/public/r/styles/default/avatar-demo.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "avatar-demo",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"avatar"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/avatar-demo.tsx",
|
||||
"content": "import {\n Avatar,\n AvatarFallback,\n AvatarImage,\n} from \"@/registry/default/ui/avatar\"\n\nexport default function AvatarDemo() {\n return (\n <Avatar>\n <AvatarImage src=\"https://github.com/shadcn.png\" alt=\"@shadcn\" />\n <AvatarFallback>CN</AvatarFallback>\n </Avatar>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/badge-demo.json
Normal file
15
apps/www/public/r/styles/default/badge-demo.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "badge-demo",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"badge"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/badge-demo.tsx",
|
||||
"content": "import { Badge } from \"@/registry/default/ui/badge\"\n\nexport default function BadgeDemo() {\n return <Badge>Badge</Badge>\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/badge-destructive.json
Normal file
15
apps/www/public/r/styles/default/badge-destructive.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "badge-destructive",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"badge"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/badge-destructive.tsx",
|
||||
"content": "import { Badge } from \"@/registry/default/ui/badge\"\n\nexport default function BadgeDestructive() {\n return <Badge variant=\"destructive\">Destructive</Badge>\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/badge-outline.json
Normal file
15
apps/www/public/r/styles/default/badge-outline.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "badge-outline",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"badge"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/badge-outline.tsx",
|
||||
"content": "import { Badge } from \"@/registry/default/ui/badge\"\n\nexport default function BadgeOutline() {\n return <Badge variant=\"outline\">Outline</Badge>\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/badge-secondary.json
Normal file
15
apps/www/public/r/styles/default/badge-secondary.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "badge-secondary",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"badge"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/badge-secondary.tsx",
|
||||
"content": "import { Badge } from \"@/registry/default/ui/badge\"\n\nexport default function BadgeSecondary() {\n return <Badge variant=\"secondary\">Secondary</Badge>\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/breadcrumb-demo.json
Normal file
15
apps/www/public/r/styles/default/breadcrumb-demo.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "breadcrumb-demo",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"breadcrumb"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/breadcrumb-demo.tsx",
|
||||
"content": "import {\n Breadcrumb,\n BreadcrumbEllipsis,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@/registry/default/ui/breadcrumb\"\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@/registry/default/ui/dropdown-menu\"\n\nexport default function BreadcrumbDemo() {\n return (\n <Breadcrumb>\n <BreadcrumbList>\n <BreadcrumbItem>\n <BreadcrumbLink href=\"/\">Home</BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <DropdownMenu>\n <DropdownMenuTrigger className=\"flex items-center gap-1\">\n <BreadcrumbEllipsis className=\"h-4 w-4\" />\n <span className=\"sr-only\">Toggle menu</span>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n <DropdownMenuItem>Documentation</DropdownMenuItem>\n <DropdownMenuItem>Themes</DropdownMenuItem>\n <DropdownMenuItem>GitHub</DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbLink href=\"/docs/components\">Components</BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbPage>Breadcrumb</BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/breadcrumb-dropdown.json
Normal file
15
apps/www/public/r/styles/default/breadcrumb-dropdown.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "breadcrumb-dropdown",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"breadcrumb"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/breadcrumb-dropdown.tsx",
|
||||
"content": "import { ChevronDown, Slash } from \"lucide-react\"\n\nimport {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@/registry/default/ui/breadcrumb\"\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@/registry/default/ui/dropdown-menu\"\n\nexport default function BreadcrumbWithDropdown() {\n return (\n <Breadcrumb>\n <BreadcrumbList>\n <BreadcrumbItem>\n <BreadcrumbLink href=\"/\">Home</BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator>\n <Slash />\n </BreadcrumbSeparator>\n <BreadcrumbItem>\n <DropdownMenu>\n <DropdownMenuTrigger className=\"flex items-center gap-1\">\n Components\n <ChevronDown className=\"h-4 w-4\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n <DropdownMenuItem>Documentation</DropdownMenuItem>\n <DropdownMenuItem>Themes</DropdownMenuItem>\n <DropdownMenuItem>GitHub</DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </BreadcrumbItem>\n <BreadcrumbSeparator>\n <Slash />\n </BreadcrumbSeparator>\n <BreadcrumbItem>\n <BreadcrumbPage>Breadcrumb</BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/breadcrumb-ellipsis.json
Normal file
15
apps/www/public/r/styles/default/breadcrumb-ellipsis.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "breadcrumb-ellipsis",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"breadcrumb"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/breadcrumb-ellipsis.tsx",
|
||||
"content": "import Link from \"next/link\"\n\nimport {\n Breadcrumb,\n BreadcrumbEllipsis,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@/registry/default/ui/breadcrumb\"\n\nexport default function BreadcrumbCollapsed() {\n return (\n <Breadcrumb>\n <BreadcrumbList>\n <BreadcrumbItem>\n <BreadcrumbLink asChild>\n <Link href=\"/\">Home</Link>\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbEllipsis />\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbLink asChild>\n <Link href=\"/docs/components\">Components</Link>\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbPage>Breadcrumb</BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/breadcrumb-link.json
Normal file
15
apps/www/public/r/styles/default/breadcrumb-link.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "breadcrumb-link",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"breadcrumb"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/breadcrumb-link.tsx",
|
||||
"content": "import Link from \"next/link\"\n\nimport {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@/registry/default/ui/breadcrumb\"\n\nexport default function BreadcrumbWithCustomSeparator() {\n return (\n <Breadcrumb>\n <BreadcrumbList>\n <BreadcrumbItem>\n <BreadcrumbLink>\n <Link href=\"/\">Home</Link>\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbLink>\n <Link href=\"/components\">Components</Link>\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbPage>Breadcrumb</BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/breadcrumb-responsive.json
Normal file
15
apps/www/public/r/styles/default/breadcrumb-responsive.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "breadcrumb-responsive",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"breadcrumb"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/breadcrumb-responsive.tsx",
|
||||
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport Link from \"next/link\"\n\nimport { useMediaQuery } from \"@/hooks/use-media-query\"\nimport {\n Breadcrumb,\n BreadcrumbEllipsis,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@/registry/default/ui/breadcrumb\"\nimport { Button } from \"@/registry/default/ui/button\"\nimport {\n Drawer,\n DrawerClose,\n DrawerContent,\n DrawerDescription,\n DrawerFooter,\n DrawerHeader,\n DrawerTitle,\n DrawerTrigger,\n} from \"@/registry/default/ui/drawer\"\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@/registry/default/ui/dropdown-menu\"\n\nconst items = [\n { href: \"#\", label: \"Home\" },\n { href: \"#\", label: \"Documentation\" },\n { href: \"#\", label: \"Building Your Application\" },\n { href: \"#\", label: \"Data Fetching\" },\n { label: \"Caching and Revalidating\" },\n]\n\nconst ITEMS_TO_DISPLAY = 3\n\nexport default function BreadcrumbResponsive() {\n const [open, setOpen] = React.useState(false)\n const isDesktop = useMediaQuery(\"(min-width: 768px)\")\n\n return (\n <Breadcrumb>\n <BreadcrumbList>\n <BreadcrumbItem>\n <BreadcrumbLink href={items[0].href}>{items[0].label}</BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n {items.length > ITEMS_TO_DISPLAY ? (\n <>\n <BreadcrumbItem>\n {isDesktop ? (\n <DropdownMenu open={open} onOpenChange={setOpen}>\n <DropdownMenuTrigger\n className=\"flex items-center gap-1\"\n aria-label=\"Toggle menu\"\n >\n <BreadcrumbEllipsis className=\"h-4 w-4\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n {items.slice(1, -2).map((item, index) => (\n <DropdownMenuItem key={index}>\n <Link href={item.href ? item.href : \"#\"}>\n {item.label}\n </Link>\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n ) : (\n <Drawer open={open} onOpenChange={setOpen}>\n <DrawerTrigger aria-label=\"Toggle Menu\">\n <BreadcrumbEllipsis className=\"h-4 w-4\" />\n </DrawerTrigger>\n <DrawerContent>\n <DrawerHeader className=\"text-left\">\n <DrawerTitle>Navigate to</DrawerTitle>\n <DrawerDescription>\n Select a page to navigate to.\n </DrawerDescription>\n </DrawerHeader>\n <div className=\"grid gap-1 px-4\">\n {items.slice(1, -2).map((item, index) => (\n <Link\n key={index}\n href={item.href ? item.href : \"#\"}\n className=\"py-1 text-sm\"\n >\n {item.label}\n </Link>\n ))}\n </div>\n <DrawerFooter className=\"pt-4\">\n <DrawerClose asChild>\n <Button variant=\"outline\">Close</Button>\n </DrawerClose>\n </DrawerFooter>\n </DrawerContent>\n </Drawer>\n )}\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n </>\n ) : null}\n {items.slice(-ITEMS_TO_DISPLAY + 1).map((item, index) => (\n <BreadcrumbItem key={index}>\n {item.href ? (\n <>\n <BreadcrumbLink\n asChild\n className=\"max-w-20 truncate md:max-w-none\"\n >\n <Link href={item.href}>{item.label}</Link>\n </BreadcrumbLink>\n <BreadcrumbSeparator />\n </>\n ) : (\n <BreadcrumbPage className=\"max-w-20 truncate md:max-w-none\">\n {item.label}\n </BreadcrumbPage>\n )}\n </BreadcrumbItem>\n ))}\n </BreadcrumbList>\n </Breadcrumb>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/breadcrumb-separator.json
Normal file
15
apps/www/public/r/styles/default/breadcrumb-separator.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "breadcrumb-separator",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"breadcrumb"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/breadcrumb-separator.tsx",
|
||||
"content": "import { Slash } from \"lucide-react\"\n\nimport {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@/registry/default/ui/breadcrumb\"\n\nexport default function BreadcrumbWithCustomSeparator() {\n return (\n <Breadcrumb>\n <BreadcrumbList>\n <BreadcrumbItem>\n <BreadcrumbLink href=\"/\">Home</BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator>\n <Slash />\n </BreadcrumbSeparator>\n <BreadcrumbItem>\n <BreadcrumbLink href=\"/components\">Components</BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator>\n <Slash />\n </BreadcrumbSeparator>\n <BreadcrumbItem>\n <BreadcrumbPage>Breadcrumb</BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/button-as-child.json
Normal file
15
apps/www/public/r/styles/default/button-as-child.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "button-as-child",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"button"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/button-as-child.tsx",
|
||||
"content": "import Link from \"next/link\"\n\nimport { Button } from \"@/registry/default/ui/button\"\n\nexport default function ButtonAsChild() {\n return (\n <Button asChild>\n <Link href=\"/login\">Login</Link>\n </Button>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/button-demo.json
Normal file
15
apps/www/public/r/styles/default/button-demo.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "button-demo",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"button"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/button-demo.tsx",
|
||||
"content": "import { Button } from \"@/registry/default/ui/button\"\n\nexport default function ButtonDemo() {\n return <Button>Button</Button>\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/button-destructive.json
Normal file
15
apps/www/public/r/styles/default/button-destructive.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "button-destructive",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"button"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/button-destructive.tsx",
|
||||
"content": "import { Button } from \"@/registry/default/ui/button\"\n\nexport default function ButtonDestructive() {\n return <Button variant=\"destructive\">Destructive</Button>\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/button-ghost.json
Normal file
15
apps/www/public/r/styles/default/button-ghost.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "button-ghost",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"button"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/button-ghost.tsx",
|
||||
"content": "import { Button } from \"@/registry/default/ui/button\"\n\nexport default function ButtonGhost() {\n return <Button variant=\"ghost\">Ghost</Button>\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/button-icon.json
Normal file
15
apps/www/public/r/styles/default/button-icon.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "button-icon",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"button"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/button-icon.tsx",
|
||||
"content": "import { ChevronRight } from \"lucide-react\"\n\nimport { Button } from \"@/registry/default/ui/button\"\n\nexport default function ButtonIcon() {\n return (\n <Button variant=\"outline\" size=\"icon\">\n <ChevronRight className=\"h-4 w-4\" />\n </Button>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/button-link.json
Normal file
15
apps/www/public/r/styles/default/button-link.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "button-link",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"button"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/button-link.tsx",
|
||||
"content": "import { Button } from \"@/registry/default/ui/button\"\n\nexport default function ButtonLink() {\n return <Button variant=\"link\">Link</Button>\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/button-loading.json
Normal file
15
apps/www/public/r/styles/default/button-loading.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "button-loading",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"button"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/button-loading.tsx",
|
||||
"content": "import { Loader2 } from \"lucide-react\"\n\nimport { Button } from \"@/registry/default/ui/button\"\n\nexport default function ButtonLoading() {\n return (\n <Button disabled>\n <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" />\n Please wait\n </Button>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/button-outline.json
Normal file
15
apps/www/public/r/styles/default/button-outline.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "button-outline",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"button"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/button-outline.tsx",
|
||||
"content": "import { Button } from \"@/registry/default/ui/button\"\n\nexport default function ButtonOutline() {\n return <Button variant=\"outline\">Outline</Button>\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/button-secondary.json
Normal file
15
apps/www/public/r/styles/default/button-secondary.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "button-secondary",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"button"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/button-secondary.tsx",
|
||||
"content": "import { Button } from \"@/registry/default/ui/button\"\n\nexport default function ButtonSecondary() {\n return <Button variant=\"secondary\">Secondary</Button>\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/button-with-icon.json
Normal file
15
apps/www/public/r/styles/default/button-with-icon.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "button-with-icon",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"button"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/button-with-icon.tsx",
|
||||
"content": "import { Mail } from \"lucide-react\"\n\nimport { Button } from \"@/registry/default/ui/button\"\n\nexport default function ButtonWithIcon() {\n return (\n <Button>\n <Mail /> Login with Email\n </Button>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/calendar-demo.json
Normal file
15
apps/www/public/r/styles/default/calendar-demo.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "calendar-demo",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"calendar"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/calendar-demo.tsx",
|
||||
"content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { Calendar } from \"@/registry/default/ui/calendar\"\n\nexport default function CalendarDemo() {\n const [date, setDate] = React.useState<Date | undefined>(new Date())\n\n return (\n <Calendar\n mode=\"single\"\n selected={date}\n onSelect={setDate}\n className=\"rounded-md border\"\n />\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
17
apps/www/public/r/styles/default/calendar-form.json
Normal file
17
apps/www/public/r/styles/default/calendar-form.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "calendar-form",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"calendar",
|
||||
"form",
|
||||
"popover"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/calendar-form.tsx",
|
||||
"content": "\"use client\"\n\nimport { zodResolver } from \"@hookform/resolvers/zod\"\nimport { format } from \"date-fns\"\nimport { CalendarIcon } from \"lucide-react\"\nimport { useForm } from \"react-hook-form\"\nimport { z } from \"zod\"\n\nimport { cn } from \"@/lib/utils\"\nimport { toast } from \"@/registry/default/hooks/use-toast\"\nimport { Button } from \"@/registry/default/ui/button\"\nimport { Calendar } from \"@/registry/default/ui/calendar\"\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/registry/default/ui/form\"\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@/registry/default/ui/popover\"\n\nconst FormSchema = z.object({\n dob: z.date({\n required_error: \"A date of birth is required.\",\n }),\n})\n\nexport default function CalendarForm() {\n const form = useForm<z.infer<typeof FormSchema>>({\n resolver: zodResolver(FormSchema),\n })\n\n function onSubmit(data: z.infer<typeof FormSchema>) {\n toast({\n title: \"You submitted the following values:\",\n description: (\n <pre className=\"mt-2 w-[340px] rounded-md bg-slate-950 p-4\">\n <code className=\"text-white\">{JSON.stringify(data, null, 2)}</code>\n </pre>\n ),\n })\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-8\">\n <FormField\n control={form.control}\n name=\"dob\"\n render={({ field }) => (\n <FormItem className=\"flex flex-col\">\n <FormLabel>Date of birth</FormLabel>\n <Popover>\n <PopoverTrigger asChild>\n <FormControl>\n <Button\n variant={\"outline\"}\n className={cn(\n \"w-[240px] pl-3 text-left font-normal\",\n !field.value && \"text-muted-foreground\"\n )}\n >\n {field.value ? (\n format(field.value, \"PPP\")\n ) : (\n <span>Pick a date</span>\n )}\n <CalendarIcon className=\"ml-auto h-4 w-4 opacity-50\" />\n </Button>\n </FormControl>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto p-0\" align=\"start\">\n <Calendar\n mode=\"single\"\n selected={field.value}\n onSelect={field.onChange}\n disabled={(date) =>\n date > new Date() || date < new Date(\"1900-01-01\")\n }\n initialFocus\n />\n </PopoverContent>\n </Popover>\n <FormDescription>\n Your date of birth is used to calculate your age.\n </FormDescription>\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\">Submit</Button>\n </form>\n </Form>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
17
apps/www/public/r/styles/default/card-demo.json
Normal file
17
apps/www/public/r/styles/default/card-demo.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "card-demo",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"card",
|
||||
"button",
|
||||
"switch"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/card-demo.tsx",
|
||||
"content": "import { BellRing, Check } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/registry/default/ui/button\"\nimport {\n Card,\n CardContent,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from \"@/registry/default/ui/card\"\nimport { Switch } from \"@/registry/default/ui/switch\"\n\nconst notifications = [\n {\n title: \"Your call has been confirmed.\",\n description: \"1 hour ago\",\n },\n {\n title: \"You have a new message!\",\n description: \"1 hour ago\",\n },\n {\n title: \"Your subscription is expiring soon!\",\n description: \"2 hours ago\",\n },\n]\n\ntype CardProps = React.ComponentProps<typeof Card>\n\nexport default function CardDemo({ className, ...props }: CardProps) {\n return (\n <Card className={cn(\"w-[380px]\", className)} {...props}>\n <CardHeader>\n <CardTitle>Notifications</CardTitle>\n <CardDescription>You have 3 unread messages.</CardDescription>\n </CardHeader>\n <CardContent className=\"grid gap-4\">\n <div className=\" flex items-center space-x-4 rounded-md border p-4\">\n <BellRing />\n <div className=\"flex-1 space-y-1\">\n <p className=\"text-sm font-medium leading-none\">\n Push Notifications\n </p>\n <p className=\"text-sm text-muted-foreground\">\n Send notifications to device.\n </p>\n </div>\n <Switch />\n </div>\n <div>\n {notifications.map((notification, index) => (\n <div\n key={index}\n className=\"mb-4 grid grid-cols-[25px_1fr] items-start pb-4 last:mb-0 last:pb-0\"\n >\n <span className=\"flex h-2 w-2 translate-y-1 rounded-full bg-sky-500\" />\n <div className=\"space-y-1\">\n <p className=\"text-sm font-medium leading-none\">\n {notification.title}\n </p>\n <p className=\"text-sm text-muted-foreground\">\n {notification.description}\n </p>\n </div>\n </div>\n ))}\n </div>\n </CardContent>\n <CardFooter>\n <Button className=\"w-full\">\n <Check /> Mark all as read\n </Button>\n </CardFooter>\n </Card>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
19
apps/www/public/r/styles/default/card-with-form.json
Normal file
19
apps/www/public/r/styles/default/card-with-form.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "card-with-form",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"button",
|
||||
"card",
|
||||
"input",
|
||||
"label",
|
||||
"select"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/card-with-form.tsx",
|
||||
"content": "import * as React from \"react\"\n\nimport { Button } from \"@/registry/default/ui/button\"\nimport {\n Card,\n CardContent,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from \"@/registry/default/ui/card\"\nimport { Input } from \"@/registry/default/ui/input\"\nimport { Label } from \"@/registry/default/ui/label\"\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@/registry/default/ui/select\"\n\nexport default function CardWithForm() {\n return (\n <Card className=\"w-[350px]\">\n <CardHeader>\n <CardTitle>Create project</CardTitle>\n <CardDescription>Deploy your new project in one-click.</CardDescription>\n </CardHeader>\n <CardContent>\n <form>\n <div className=\"grid w-full items-center gap-4\">\n <div className=\"flex flex-col space-y-1.5\">\n <Label htmlFor=\"name\">Name</Label>\n <Input id=\"name\" placeholder=\"Name of your project\" />\n </div>\n <div className=\"flex flex-col space-y-1.5\">\n <Label htmlFor=\"framework\">Framework</Label>\n <Select>\n <SelectTrigger id=\"framework\">\n <SelectValue placeholder=\"Select\" />\n </SelectTrigger>\n <SelectContent position=\"popper\">\n <SelectItem value=\"next\">Next.js</SelectItem>\n <SelectItem value=\"sveltekit\">SvelteKit</SelectItem>\n <SelectItem value=\"astro\">Astro</SelectItem>\n <SelectItem value=\"nuxt\">Nuxt.js</SelectItem>\n </SelectContent>\n </Select>\n </div>\n </div>\n </form>\n </CardContent>\n <CardFooter className=\"flex justify-between\">\n <Button variant=\"outline\">Cancel</Button>\n <Button>Deploy</Button>\n </CardFooter>\n </Card>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/carousel-api.json
Normal file
15
apps/www/public/r/styles/default/carousel-api.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "carousel-api",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"carousel"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/carousel-api.tsx",
|
||||
"content": "import * as React from \"react\"\n\nimport { Card, CardContent } from \"@/registry/default/ui/card\"\nimport {\n Carousel,\n CarouselContent,\n CarouselItem,\n CarouselNext,\n CarouselPrevious,\n type CarouselApi,\n} from \"@/registry/default/ui/carousel\"\n\nexport default function CarouselDApiDemo() {\n const [api, setApi] = React.useState<CarouselApi>()\n const [current, setCurrent] = React.useState(0)\n const [count, setCount] = React.useState(0)\n\n React.useEffect(() => {\n if (!api) {\n return\n }\n\n setCount(api.scrollSnapList().length)\n setCurrent(api.selectedScrollSnap() + 1)\n\n api.on(\"select\", () => {\n setCurrent(api.selectedScrollSnap() + 1)\n })\n }, [api])\n\n return (\n <div className=\"mx-auto max-w-xs\">\n <Carousel setApi={setApi} className=\"w-full max-w-xs\">\n <CarouselContent>\n {Array.from({ length: 5 }).map((_, index) => (\n <CarouselItem key={index}>\n <Card>\n <CardContent className=\"flex aspect-square items-center justify-center p-6\">\n <span className=\"text-4xl font-semibold\">{index + 1}</span>\n </CardContent>\n </Card>\n </CarouselItem>\n ))}\n </CarouselContent>\n <CarouselPrevious />\n <CarouselNext />\n </Carousel>\n <div className=\"py-2 text-center text-sm text-muted-foreground\">\n Slide {current} of {count}\n </div>\n </div>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/carousel-demo.json
Normal file
15
apps/www/public/r/styles/default/carousel-demo.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "carousel-demo",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"carousel"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/carousel-demo.tsx",
|
||||
"content": "import * as React from \"react\"\n\nimport { Card, CardContent } from \"@/registry/default/ui/card\"\nimport {\n Carousel,\n CarouselContent,\n CarouselItem,\n CarouselNext,\n CarouselPrevious,\n} from \"@/registry/default/ui/carousel\"\n\nexport default function CarouselDemo() {\n return (\n <Carousel className=\"w-full max-w-xs\">\n <CarouselContent>\n {Array.from({ length: 5 }).map((_, index) => (\n <CarouselItem key={index}>\n <div className=\"p-1\">\n <Card>\n <CardContent className=\"flex aspect-square items-center justify-center p-6\">\n <span className=\"text-4xl font-semibold\">{index + 1}</span>\n </CardContent>\n </Card>\n </div>\n </CarouselItem>\n ))}\n </CarouselContent>\n <CarouselPrevious />\n <CarouselNext />\n </Carousel>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/carousel-orientation.json
Normal file
15
apps/www/public/r/styles/default/carousel-orientation.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "carousel-orientation",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"carousel"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/carousel-orientation.tsx",
|
||||
"content": "import * as React from \"react\"\n\nimport { Card, CardContent } from \"@/registry/default/ui/card\"\nimport {\n Carousel,\n CarouselContent,\n CarouselItem,\n CarouselNext,\n CarouselPrevious,\n} from \"@/registry/default/ui/carousel\"\n\nexport default function CarouselOrientation() {\n return (\n <Carousel\n opts={{\n align: \"start\",\n }}\n orientation=\"vertical\"\n className=\"w-full max-w-xs\"\n >\n <CarouselContent className=\"-mt-1 h-[200px]\">\n {Array.from({ length: 5 }).map((_, index) => (\n <CarouselItem key={index} className=\"pt-1 md:basis-1/2\">\n <div className=\"p-1\">\n <Card>\n <CardContent className=\"flex items-center justify-center p-6\">\n <span className=\"text-3xl font-semibold\">{index + 1}</span>\n </CardContent>\n </Card>\n </div>\n </CarouselItem>\n ))}\n </CarouselContent>\n <CarouselPrevious />\n <CarouselNext />\n </Carousel>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/carousel-plugin.json
Normal file
15
apps/www/public/r/styles/default/carousel-plugin.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "carousel-plugin",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"carousel"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/carousel-plugin.tsx",
|
||||
"content": "import * as React from \"react\"\nimport Autoplay from \"embla-carousel-autoplay\"\n\nimport { Card, CardContent } from \"@/registry/default/ui/card\"\nimport {\n Carousel,\n CarouselContent,\n CarouselItem,\n CarouselNext,\n CarouselPrevious,\n} from \"@/registry/default/ui/carousel\"\n\nexport default function CarouselPlugin() {\n const plugin = React.useRef(\n Autoplay({ delay: 2000, stopOnInteraction: true })\n )\n\n return (\n <Carousel\n plugins={[plugin.current]}\n className=\"w-full max-w-xs\"\n onMouseEnter={plugin.current.stop}\n onMouseLeave={plugin.current.reset}\n >\n <CarouselContent>\n {Array.from({ length: 5 }).map((_, index) => (\n <CarouselItem key={index}>\n <div className=\"p-1\">\n <Card>\n <CardContent className=\"flex aspect-square items-center justify-center p-6\">\n <span className=\"text-4xl font-semibold\">{index + 1}</span>\n </CardContent>\n </Card>\n </div>\n </CarouselItem>\n ))}\n </CarouselContent>\n <CarouselPrevious />\n <CarouselNext />\n </Carousel>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/carousel-size.json
Normal file
15
apps/www/public/r/styles/default/carousel-size.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "carousel-size",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"carousel"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/carousel-size.tsx",
|
||||
"content": "import * as React from \"react\"\n\nimport { Card, CardContent } from \"@/registry/default/ui/card\"\nimport {\n Carousel,\n CarouselContent,\n CarouselItem,\n CarouselNext,\n CarouselPrevious,\n} from \"@/registry/default/ui/carousel\"\n\nexport default function CarouselSize() {\n return (\n <Carousel\n opts={{\n align: \"start\",\n }}\n className=\"w-full max-w-sm\"\n >\n <CarouselContent>\n {Array.from({ length: 5 }).map((_, index) => (\n <CarouselItem key={index} className=\"md:basis-1/2 lg:basis-1/3\">\n <div className=\"p-1\">\n <Card>\n <CardContent className=\"flex aspect-square items-center justify-center p-6\">\n <span className=\"text-3xl font-semibold\">{index + 1}</span>\n </CardContent>\n </Card>\n </div>\n </CarouselItem>\n ))}\n </CarouselContent>\n <CarouselPrevious />\n <CarouselNext />\n </Carousel>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
15
apps/www/public/r/styles/default/carousel-spacing.json
Normal file
15
apps/www/public/r/styles/default/carousel-spacing.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "carousel-spacing",
|
||||
"type": "registry:example",
|
||||
"registryDependencies": [
|
||||
"carousel"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"path": "example/carousel-spacing.tsx",
|
||||
"content": "import * as React from \"react\"\n\nimport { Card, CardContent } from \"@/registry/default/ui/card\"\nimport {\n Carousel,\n CarouselContent,\n CarouselItem,\n CarouselNext,\n CarouselPrevious,\n} from \"@/registry/default/ui/carousel\"\n\nexport default function CarouselSpacing() {\n return (\n <Carousel className=\"w-full max-w-sm\">\n <CarouselContent className=\"-ml-1\">\n {Array.from({ length: 5 }).map((_, index) => (\n <CarouselItem key={index} className=\"pl-1 md:basis-1/2 lg:basis-1/3\">\n <div className=\"p-1\">\n <Card>\n <CardContent className=\"flex aspect-square items-center justify-center p-6\">\n <span className=\"text-2xl font-semibold\">{index + 1}</span>\n </CardContent>\n </Card>\n </div>\n </CarouselItem>\n ))}\n </CarouselContent>\n <CarouselPrevious />\n <CarouselNext />\n </Carousel>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "chart-area-axes",
|
||||
"type": "registry:block",
|
||||
"description": "An area chart with axes",
|
||||
"registryDependencies": [
|
||||
"card",
|
||||
"chart"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "chart-area-default",
|
||||
"type": "registry:block",
|
||||
"description": "A simple area chart",
|
||||
"registryDependencies": [
|
||||
"card",
|
||||
"chart"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "chart-area-gradient",
|
||||
"type": "registry:block",
|
||||
"description": "An area chart with gradient fill",
|
||||
"registryDependencies": [
|
||||
"card",
|
||||
"chart"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "chart-area-icons",
|
||||
"type": "registry:block",
|
||||
"description": "An area chart with icons",
|
||||
"registryDependencies": [
|
||||
"card",
|
||||
"chart"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "chart-area-interactive",
|
||||
"type": "registry:block",
|
||||
"description": "An interactive area chart",
|
||||
"registryDependencies": [
|
||||
"card",
|
||||
"chart",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "chart-area-legend",
|
||||
"type": "registry:block",
|
||||
"description": "An area chart with a legend",
|
||||
"registryDependencies": [
|
||||
"card",
|
||||
"chart"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "chart-area-linear",
|
||||
"type": "registry:block",
|
||||
"description": "A linear area chart",
|
||||
"registryDependencies": [
|
||||
"card",
|
||||
"chart"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "chart-area-stacked-expand",
|
||||
"type": "registry:block",
|
||||
"description": "A stacked area chart with expand stacking",
|
||||
"registryDependencies": [
|
||||
"card",
|
||||
"chart"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "chart-area-stacked",
|
||||
"type": "registry:block",
|
||||
"description": "A stacked area chart",
|
||||
"registryDependencies": [
|
||||
"card",
|
||||
"chart"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "chart-area-step",
|
||||
"type": "registry:block",
|
||||
"description": "A step area chart",
|
||||
"registryDependencies": [
|
||||
"card",
|
||||
"chart"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "chart-bar-active",
|
||||
"type": "registry:block",
|
||||
"description": "A bar chart with an active bar",
|
||||
"registryDependencies": [
|
||||
"card",
|
||||
"chart"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "chart-bar-default",
|
||||
"type": "registry:block",
|
||||
"description": "A bar chart",
|
||||
"registryDependencies": [
|
||||
"card",
|
||||
"chart"
|
||||
|
||||
12
apps/www/public/r/styles/default/chart-bar-demo-axis.json
Normal file
12
apps/www/public/r/styles/default/chart-bar-demo-axis.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "chart-bar-demo-axis",
|
||||
"type": "registry:example",
|
||||
"files": [
|
||||
{
|
||||
"path": "example/chart-bar-demo-axis.tsx",
|
||||
"content": "\"use client\"\n\nimport { Bar, BarChart, CartesianGrid, XAxis } from \"recharts\"\n\nimport { ChartConfig, ChartContainer } from \"@/registry/default/ui/chart\"\n\nconst chartData = [\n { month: \"January\", desktop: 186, mobile: 80 },\n { month: \"February\", desktop: 305, mobile: 200 },\n { month: \"March\", desktop: 237, mobile: 120 },\n { month: \"April\", desktop: 73, mobile: 190 },\n { month: \"May\", desktop: 209, mobile: 130 },\n { month: \"June\", desktop: 214, mobile: 140 },\n]\n\nconst chartConfig = {\n desktop: {\n label: \"Desktop\",\n color: \"#2563eb\",\n },\n mobile: {\n label: \"Mobile\",\n color: \"#60a5fa\",\n },\n} satisfies ChartConfig\n\nexport default function Component() {\n return (\n <ChartContainer config={chartConfig} className=\"min-h-[200px] w-full\">\n <BarChart accessibilityLayer data={chartData}>\n <CartesianGrid vertical={false} />\n <XAxis\n dataKey=\"month\"\n tickLine={false}\n tickMargin={10}\n axisLine={false}\n tickFormatter={(value) => value.slice(0, 3)}\n />\n <Bar dataKey=\"desktop\" fill=\"var(--color-desktop)\" radius={4} />\n <Bar dataKey=\"mobile\" fill=\"var(--color-mobile)\" radius={4} />\n </BarChart>\n </ChartContainer>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
12
apps/www/public/r/styles/default/chart-bar-demo-grid.json
Normal file
12
apps/www/public/r/styles/default/chart-bar-demo-grid.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "chart-bar-demo-grid",
|
||||
"type": "registry:example",
|
||||
"files": [
|
||||
{
|
||||
"path": "example/chart-bar-demo-grid.tsx",
|
||||
"content": "\"use client\"\n\nimport { Bar, BarChart, CartesianGrid } from \"recharts\"\n\nimport { ChartConfig, ChartContainer } from \"@/registry/default/ui/chart\"\n\nconst chartData = [\n { month: \"January\", desktop: 186, mobile: 80 },\n { month: \"February\", desktop: 305, mobile: 200 },\n { month: \"March\", desktop: 237, mobile: 120 },\n { month: \"April\", desktop: 73, mobile: 190 },\n { month: \"May\", desktop: 209, mobile: 130 },\n { month: \"June\", desktop: 214, mobile: 140 },\n]\n\nconst chartConfig = {\n desktop: {\n label: \"Desktop\",\n color: \"#2563eb\",\n },\n mobile: {\n label: \"Mobile\",\n color: \"#60a5fa\",\n },\n} satisfies ChartConfig\n\nexport default function Component() {\n return (\n <ChartContainer config={chartConfig} className=\"min-h-[200px] w-full\">\n <BarChart accessibilityLayer data={chartData}>\n <CartesianGrid vertical={false} />\n <Bar dataKey=\"desktop\" fill=\"var(--color-desktop)\" radius={4} />\n <Bar dataKey=\"mobile\" fill=\"var(--color-mobile)\" radius={4} />\n </BarChart>\n </ChartContainer>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
12
apps/www/public/r/styles/default/chart-bar-demo-legend.json
Normal file
12
apps/www/public/r/styles/default/chart-bar-demo-legend.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "chart-bar-demo-legend",
|
||||
"type": "registry:example",
|
||||
"files": [
|
||||
{
|
||||
"path": "example/chart-bar-demo-legend.tsx",
|
||||
"content": "\"use client\"\n\nimport { Bar, BarChart, CartesianGrid, XAxis } from \"recharts\"\n\nimport {\n ChartConfig,\n ChartContainer,\n ChartLegend,\n ChartLegendContent,\n ChartTooltip,\n ChartTooltipContent,\n} from \"@/registry/default/ui/chart\"\n\nconst chartData = [\n { month: \"January\", desktop: 186, mobile: 80 },\n { month: \"February\", desktop: 305, mobile: 200 },\n { month: \"March\", desktop: 237, mobile: 120 },\n { month: \"April\", desktop: 73, mobile: 190 },\n { month: \"May\", desktop: 209, mobile: 130 },\n { month: \"June\", desktop: 214, mobile: 140 },\n]\n\nconst chartConfig = {\n desktop: {\n label: \"Desktop\",\n color: \"#2563eb\",\n },\n mobile: {\n label: \"Mobile\",\n color: \"#60a5fa\",\n },\n} satisfies ChartConfig\n\nexport default function Component() {\n return (\n <ChartContainer config={chartConfig} className=\"min-h-[200px] w-full\">\n <BarChart accessibilityLayer data={chartData}>\n <CartesianGrid vertical={false} />\n <XAxis\n dataKey=\"month\"\n tickLine={false}\n tickMargin={10}\n axisLine={false}\n tickFormatter={(value) => value.slice(0, 3)}\n />\n <ChartTooltip content={<ChartTooltipContent />} />\n <ChartLegend content={<ChartLegendContent />} />\n <Bar dataKey=\"desktop\" fill=\"var(--color-desktop)\" radius={4} />\n <Bar dataKey=\"mobile\" fill=\"var(--color-mobile)\" radius={4} />\n </BarChart>\n </ChartContainer>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
12
apps/www/public/r/styles/default/chart-bar-demo-tooltip.json
Normal file
12
apps/www/public/r/styles/default/chart-bar-demo-tooltip.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "chart-bar-demo-tooltip",
|
||||
"type": "registry:example",
|
||||
"files": [
|
||||
{
|
||||
"path": "example/chart-bar-demo-tooltip.tsx",
|
||||
"content": "\"use client\"\n\nimport { Bar, BarChart, CartesianGrid, XAxis } from \"recharts\"\n\nimport {\n ChartConfig,\n ChartContainer,\n ChartTooltip,\n ChartTooltipContent,\n} from \"@/registry/default/ui/chart\"\n\nconst chartData = [\n { month: \"January\", desktop: 186, mobile: 80 },\n { month: \"February\", desktop: 305, mobile: 200 },\n { month: \"March\", desktop: 237, mobile: 120 },\n { month: \"April\", desktop: 73, mobile: 190 },\n { month: \"May\", desktop: 209, mobile: 130 },\n { month: \"June\", desktop: 214, mobile: 140 },\n]\n\nconst chartConfig = {\n desktop: {\n label: \"Desktop\",\n color: \"#2563eb\",\n },\n mobile: {\n label: \"Mobile\",\n color: \"#60a5fa\",\n },\n} satisfies ChartConfig\n\nexport default function Component() {\n return (\n <ChartContainer config={chartConfig} className=\"min-h-[200px] w-full\">\n <BarChart accessibilityLayer data={chartData}>\n <CartesianGrid vertical={false} />\n <XAxis\n dataKey=\"month\"\n tickLine={false}\n tickMargin={10}\n axisLine={false}\n tickFormatter={(value) => value.slice(0, 3)}\n />\n <ChartTooltip content={<ChartTooltipContent />} />\n <Bar dataKey=\"desktop\" fill=\"var(--color-desktop)\" radius={4} />\n <Bar dataKey=\"mobile\" fill=\"var(--color-mobile)\" radius={4} />\n </BarChart>\n </ChartContainer>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
12
apps/www/public/r/styles/default/chart-bar-demo.json
Normal file
12
apps/www/public/r/styles/default/chart-bar-demo.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "chart-bar-demo",
|
||||
"type": "registry:example",
|
||||
"files": [
|
||||
{
|
||||
"path": "example/chart-bar-demo.tsx",
|
||||
"content": "\"use client\"\n\nimport { Bar, BarChart } from \"recharts\"\n\nimport { ChartConfig, ChartContainer } from \"@/registry/default/ui/chart\"\n\nconst chartData = [\n { month: \"January\", desktop: 186, mobile: 80 },\n { month: \"February\", desktop: 305, mobile: 200 },\n { month: \"March\", desktop: 237, mobile: 120 },\n { month: \"April\", desktop: 73, mobile: 190 },\n { month: \"May\", desktop: 209, mobile: 130 },\n { month: \"June\", desktop: 214, mobile: 140 },\n]\n\nconst chartConfig = {\n desktop: {\n label: \"Desktop\",\n color: \"#2563eb\",\n },\n mobile: {\n label: \"Mobile\",\n color: \"#60a5fa\",\n },\n} satisfies ChartConfig\n\nexport default function Component() {\n return (\n <ChartContainer config={chartConfig} className=\"min-h-[200px] w-full\">\n <BarChart accessibilityLayer data={chartData}>\n <Bar dataKey=\"desktop\" fill=\"var(--color-desktop)\" radius={4} />\n <Bar dataKey=\"mobile\" fill=\"var(--color-mobile)\" radius={4} />\n </BarChart>\n </ChartContainer>\n )\n}\n",
|
||||
"type": "registry:example",
|
||||
"target": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "chart-bar-horizontal",
|
||||
"type": "registry:block",
|
||||
"description": "A horizontal bar chart",
|
||||
"registryDependencies": [
|
||||
"card",
|
||||
"chart"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user