Skip to content

Commit

Permalink
Open in v0 (shadcn-ui#4613)
Browse files Browse the repository at this point in the history
* feat: edit in v0

* feat: update edit sources

* fix: edit button

* feat: rename to open in v0
  • Loading branch information
shadcn committed Aug 21, 2024
1 parent 9f156a1 commit 259a9ff
Show file tree
Hide file tree
Showing 35 changed files with 215 additions and 85 deletions.
40 changes: 34 additions & 6 deletions apps/www/actions/edit-in-v0.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,59 @@
"use server"

import { track } from "@vercel/analytics/server"

const EDIT_IN_V0_SOURCE = "ui.shadcn.com"
import { capitalCase } from "change-case"

export async function editInV0({
name,
title,
description,
style,
code,
url,
}: {
name: string
title?: string
description: string
style: string
code: string
url: string
}) {
try {
title =
title ??
capitalCase(
name.replace(/\d+/g, "").replace("-demo", "").replace("-", " ")
)

await track("edit_in_v0", {
name,
title,
description,
style,
url,
})

// Replace "use client" in the code.
// v0 will handle this for us.
code = code.replace(`"use client"`, "")
// code = code.replace(`"use client"`, "")

const payload = {
title,
description,
code,
source: {
title: "shadcn/ui",
url,
},
meta: {
project: capitalCase(name.replace(/\d+/g, "")),
file: `${name}.tsx`,
},
}

const response = await fetch(`${process.env.V0_URL}/api/edit`, {
const response = await fetch(`${process.env.V0_URL}/chat/api/open-in-v0`, {
method: "POST",
body: JSON.stringify({ description, code, source: EDIT_IN_V0_SOURCE }),
body: JSON.stringify(payload),
headers: {
"x-v0-edit-secret": process.env.V0_EDIT_SECRET!,
"x-vercel-protection-bypass":
Expand All @@ -42,16 +67,19 @@ export async function editInV0({
throw new Error("Unauthorized")
}

console.error(response.statusText)

throw new Error("Something went wrong. Please try again later.")
}

const result = await response.json()

return {
...result,
url: `${process.env.V0_URL}/edit/${result.id}`,
url: `${process.env.V0_URL}/chat/api/open-in-v0/${result.id}`,
}
} catch (error) {
console.error(error)
if (error instanceof Error) {
return { error: error.message }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,10 @@ function ModelItem({ model, isSelected, onSelect, onPeek }: ModelItemProps) {
mutation.attributeName === "aria-selected" &&
ref.current?.getAttribute("aria-selected") === "true"
) {
onPeek(model);
onPeek(model)
}
});
});

})
})

return (
<CommandItem
Expand Down
17 changes: 12 additions & 5 deletions apps/www/components/v0-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function V0Tooltip({
{style === "new-york" ? (
<>Not available in New York</>
) : (
<>Edit in v0</>
<>Open in v0</>
)}
</TooltipContent>
</Tooltip>
Expand All @@ -57,11 +57,17 @@ export function V0Button({
block: Pick<Block, "name" | "description" | "code" | "style">
size?: Size
} & ButtonProps) {
const [url, setUrl] = React.useState("https://ui.shadcn.com")

React.useEffect(() => {
setUrl(window.location.href)
}, [])

if (block.style === "new-york") {
return (
<V0Tooltip size={size} style={block.style}>
<Button
aria-label="Edit in v0"
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",
Expand All @@ -86,7 +92,7 @@ export function V0Button({
<V0Logo className="h-4 w-4" />
) : (
<>
Edit in <V0Logo />
Open in <V0Logo />
</>
)}
</Button>
Expand All @@ -102,6 +108,7 @@ export function V0Button({
description: block.description || "",
code: block.code,
style: block.style,
url,
})

if (result?.error) {
Expand Down Expand Up @@ -141,7 +148,7 @@ function Form({
return (
<V0Tooltip size={size}>
<Button
aria-label="Edit in v0"
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",
Expand All @@ -161,7 +168,7 @@ function Form({
) : (
<>
{pending && <Loader2 className="h-3.5 w-3.5 animate-spin" />}
Edit in <V0Logo />
Open in <V0Logo />
</>
)}
</Button>
Expand Down
2 changes: 1 addition & 1 deletion apps/www/content/docs/components/accordion.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ links:
<ComponentPreview
name="accordion-demo"
className="[&_.preview>[data-orientation=vertical]]:sm:max-w-[70%]"
description="An accordion with items"
description="An accordion with three items"
/>

## Installation
Expand Down
1 change: 1 addition & 0 deletions apps/www/content/docs/components/alert-dialog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ links:

<ComponentPreview
name="alert-dialog-demo"
title="An alert dialog with cancel and continue buttons."
description="An alert dialog with cancel and continue buttons."
/>

Expand Down
3 changes: 3 additions & 0 deletions apps/www/content/docs/components/alert.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ component: true

<ComponentPreview
name="alert-demo"
title="An alert with an icon, title and description."
description="An alert with an icon, title and description. The title says 'Heads up!' and the description is 'You can add components to your app using the cli.'."
/>

Expand Down Expand Up @@ -63,12 +64,14 @@ import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"

<ComponentPreview
name="alert-demo"
title="An alert with an icon, title and description."
description="An alert with an icon, title and description. The title says 'Heads up!' and the description is 'You can add components to your app using the cli.'."
/>

### Destructive

<ComponentPreview
name="alert-destructive"
title="An alert with a destructive variant."
description="An alert with a destructive variant. The title says 'Delete this item?' and the description is 'This action cannot be undone.'."
/>
6 changes: 5 additions & 1 deletion apps/www/content/docs/components/aspect-ratio.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ links:
api: https://www.radix-ui.com/docs/primitives/components/aspect-ratio#api-reference
---

<ComponentPreview name="aspect-ratio-demo" />
<ComponentPreview
name="aspect-ratio-demo"
title="Aspect Ratio"
description="A component that displays an image with a 16:9 aspect ratio."
/>

## Installation

Expand Down
6 changes: 5 additions & 1 deletion apps/www/content/docs/components/avatar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ links:
api: https://www.radix-ui.com/docs/primitives/components/avatar#api-reference
---

<ComponentPreview name="avatar-demo" description="An avatar with a fallback." />
<ComponentPreview
name="avatar-demo"
title="Avatar"
description="An avatar with a fallback."
/>

## Installation

Expand Down
14 changes: 12 additions & 2 deletions apps/www/content/docs/components/badge.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ description: Displays a badge or a component that looks like a badge.
component: true
---

<ComponentPreview name="badge-demo" description="A badge" />
<ComponentPreview
name="badge-demo"
title="Badge"
description="A default badge"
/>

## Installation

Expand Down Expand Up @@ -64,14 +68,19 @@ import { badgeVariants } from "@/components/ui/badge"

### Default

<ComponentPreview name="badge-demo" description="A badge" />
<ComponentPreview
name="badge-demo"
title="Badge"
description="A default badge"
/>

---

### Secondary

<ComponentPreview
name="badge-secondary"
title="Badge"
description="A badge using secondary as variant."
/>

Expand All @@ -81,6 +90,7 @@ import { badgeVariants } from "@/components/ui/badge"

<ComponentPreview
name="badge-outline"
title="Badge"
description="A badge using outline as variant."
/>

Expand Down
6 changes: 5 additions & 1 deletion apps/www/content/docs/components/calendar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ links:
doc: https://react-day-picker.js.org
---

<ComponentPreview name="calendar-demo" />
<ComponentPreview
name="calendar-demo"
title="Calendar"
description="A calendar showing the current date."
/>

## About

Expand Down
36 changes: 30 additions & 6 deletions apps/www/content/docs/components/carousel.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ links:
api: https://www.embla-carousel.com/api
---

<ComponentPreview name="carousel-demo" />
<ComponentPreview
name="carousel-demo"
title="Carousel"
description="A carousel with 5 items and a previous and next button."
/>

## About

Expand Down Expand Up @@ -82,7 +86,11 @@ import {

To set the size of the items, you can use the `basis` utility class on the `<CarouselItem />`.

<ComponentPreview name="carousel-size" />
<ComponentPreview
name="carousel-size"
title="Carousel"
description="A carousel with 3 active items of equal size."
/>

```tsx title="Example" showLineNumbers {4-6}
// 33% of the carousel width.
Expand Down Expand Up @@ -120,7 +128,11 @@ You can always adjust this in your own project if you need to.

</Callout>

<ComponentPreview name="carousel-spacing" />
<ComponentPreview
name="carousel-spacing"
title="Carousel"
description="A carousel with 3 items with a spacing of 1rem."
/>

```tsx title="Example" showLineNumbers /-ml-4/ /pl-4/
<Carousel>
Expand All @@ -146,7 +158,11 @@ You can always adjust this in your own project if you need to.

Use the `orientation` prop to set the orientation of the carousel.

<ComponentPreview name="carousel-orientation" />
<ComponentPreview
name="carousel-orientation"
title="Carousel"
description="A vertical carousel."
/>

```tsx showLineNumbers /vertical | horizontal/
<Carousel orientation="vertical | horizontal">
Expand Down Expand Up @@ -181,7 +197,11 @@ You can pass options to the carousel using the `opts` prop. See the [Embla Carou

Use a state and the `setApi` props to get an instance of the carousel API.

<ComponentPreview name="carousel-api" />
<ComponentPreview
name="carousel-api"
title="Carousel"
description="A carousel with a slide counter."
/>

```tsx showLineNumbers {1,4,22}
import { type CarouselApi } from "@/components/ui/carousel"
Expand Down Expand Up @@ -272,6 +292,10 @@ export function Example() {
}
```

<ComponentPreview name="carousel-plugin" />
<ComponentPreview
name="carousel-plugin"
title="Carousel"
description="A carousel with the autoplay plugin."
/>

See the [Embla Carousel docs](https://www.embla-carousel.com/api/plugins/) for more information on using plugins.
15 changes: 12 additions & 3 deletions apps/www/content/docs/components/combobox.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ description: Autocomplete input and command palette with a list of suggestions.
component: true
---

<ComponentPreview name="combobox-demo" />
<ComponentPreview
name="combobox-demo"
description="A combobox with a list of frameworks."
/>

## Installation

Expand Down Expand Up @@ -115,15 +118,21 @@ export function ComboboxDemo() {

### Combobox

<ComponentPreview name="combobox-demo" />
<ComponentPreview
name="combobox-demo"
description="A combobox with a list of frameworks."
/>

### Popover

<ComponentPreview name="combobox-popover" />

### Dropdown menu

<ComponentPreview name="combobox-dropdown-menu" />
<ComponentPreview
name="combobox-dropdown-menu"
description="A combobox in a dropdown menu"
/>

### Responsive

Expand Down
Loading

0 comments on commit 259a9ff

Please sign in to comment.