feat: refactor component preview

This commit is contained in:
shadcn
2026-01-22 20:59:59 +04:00
parent 598f17812d
commit ee88d296f4
11 changed files with 66 additions and 34 deletions

View File

@@ -1,9 +1,9 @@
"use client"
import * as React from "react"
import { Button } from "@/examples/base/ui/button"
import { cn } from "@/lib/utils"
import { Button } from "@/registry/new-york-v4/ui/button"
export function ComponentPreviewTabs({
className,
@@ -13,6 +13,7 @@ export function ComponentPreviewTabs({
chromeLessOnMobile = false,
component,
source,
sourcePreview,
...props
}: React.ComponentProps<"div"> & {
previewClassName?: string
@@ -21,11 +22,13 @@ export function ComponentPreviewTabs({
chromeLessOnMobile?: boolean
component: React.ReactNode
source: React.ReactNode
sourcePreview?: React.ReactNode
}) {
const [isMobileCodeVisible, setIsMobileCodeVisible] = React.useState(false)
return (
<div
data-slot="component-preview"
className={cn(
"group relative mt-4 mb-12 flex flex-col gap-2 overflow-hidden rounded-xl border",
className
@@ -47,33 +50,33 @@ export function ComponentPreviewTabs({
<div
data-slot="code"
data-mobile-code-visible={isMobileCodeVisible}
className="relative overflow-hidden data-[mobile-code-visible=false]:max-h-24 [&_[data-rehype-pretty-code-figure]]:!m-0 [&_[data-rehype-pretty-code-figure]]:rounded-t-none [&_[data-rehype-pretty-code-figure]]:border-t [&_pre]:max-h-72"
style={{
contentVisibility: "auto",
containIntrinsicSize: "auto 96px",
}}
className="relative overflow-hidden [&_[data-rehype-pretty-code-figure]]:!m-0 [&_[data-rehype-pretty-code-figure]]:rounded-t-none [&_[data-rehype-pretty-code-figure]]:border-t [&_pre]:max-h-72"
>
{source}
{!isMobileCodeVisible && (
<div className="absolute inset-0 flex items-center justify-center">
<div
className="absolute inset-0"
style={{
background:
"linear-gradient(to top, var(--color-code), color-mix(in oklab, var(--color-code) 60%, transparent), transparent)",
}}
/>
<Button
type="button"
size="sm"
variant="outline"
className="bg-background text-foreground dark:bg-background dark:text-foreground relative z-10"
onClick={() => {
setIsMobileCodeVisible(true)
}}
>
View Code
</Button>
{isMobileCodeVisible ? (
source
) : (
<div className="relative">
{sourcePreview}
<div className="absolute inset-0 flex items-center justify-center pb-4">
<div
className="absolute inset-0"
style={{
background:
"linear-gradient(to top, var(--color-code), color-mix(in oklab, var(--color-code) 60%, transparent), transparent)",
}}
/>
<Button
type="button"
size="sm"
variant="outline"
className="bg-background text-foreground dark:bg-background dark:text-foreground hover:bg-muted dark:hover:bg-muted relative z-10"
onClick={() => {
setIsMobileCodeVisible(true)
}}
>
View Code
</Button>
</div>
</div>
)}
</div>

View File

@@ -77,6 +77,14 @@ export function ComponentPreview({
styleName={styleName}
/>
}
sourcePreview={
<ComponentSource
name={name}
collapsible={false}
styleName={styleName}
maxLines={3}
/>
}
chromeLessOnMobile={chromeLessOnMobile}
{...props}
/>

View File

@@ -18,6 +18,7 @@ export async function ComponentSource({
collapsible = true,
className,
styleName = "new-york-v4",
maxLines,
}: React.ComponentProps<"div"> & {
name?: string
src?: string
@@ -25,6 +26,7 @@ export async function ComponentSource({
language?: string
collapsible?: boolean
styleName?: string
maxLines?: number
}) {
if (!name && !src) {
return null
@@ -51,6 +53,11 @@ export async function ComponentSource({
code = await formatCode(code, styleName)
code = code.replaceAll("/* eslint-disable react/no-children-prop */\n", "")
// Truncate code if maxLines is set.
if (maxLines) {
code = code.split("\n").slice(0, maxLines).join("\n")
}
const lang = language ?? title?.split(".").pop() ?? "tsx"
const highlightedCode = await highlightCode(code, lang)

View File

@@ -34,21 +34,21 @@ Here's what it looks like:
<ComponentPreview
name="spinner-basic"
className="[&_.preview]:h-[250px] [&_pre]:!h-[250px]"
/>
Here's what it looks like in a button:
<ComponentPreview
name="spinner-button"
className="[&_.preview]:h-[250px] [&_pre]:!h-[250px]"
/>
You can edit the code and replace it with your own spinner.
<ComponentPreview
name="spinner-custom"
className="[&_.preview]:h-[250px] [&_pre]:!h-[250px]"
/>
### Kbd
@@ -74,7 +74,7 @@ Use `KbdGroup` to group keyboard keys together.
<ComponentPreview
name="kbd-demo"
className="[&_.preview]:h-[250px] [&_pre]:!h-[250px]"
/>
You can add it to buttons, tooltips, input groups, and more.
@@ -85,7 +85,7 @@ I got a lot of requests for this one: Button Group. It's a container that groups
<ComponentPreview
name="button-group-demo"
className="[&_.preview]:h-[250px] [&_pre]:!h-[250px]"
/>
Here's the code:
@@ -120,14 +120,14 @@ Use `ButtonGroupSeparator` to create split buttons. Classic dropdown pattern.
<ComponentPreview
name="button-group-dropdown"
className="[&_.preview]:h-[250px] [&_pre]:!h-[250px]"
/>
You can also use it to add prefix or suffix buttons and text to inputs.
<ComponentPreview
name="button-group-select"
className="[&_.preview]:h-[250px] [&_pre]:!h-[250px]"
/>
```tsx showLineNumbers

View File

@@ -1,3 +1,5 @@
"use client"
import { Avatar, AvatarFallback, AvatarImage } from "@/examples/base/ui/avatar"
import { Button } from "@/examples/base/ui/button"
import {

View File

@@ -1,3 +1,5 @@
"use client"
import { Button } from "@/examples/base/ui/button"
import {
DropdownMenu,

View File

@@ -1,3 +1,5 @@
"use client"
import { Button } from "@/examples/base/ui/button"
import {
DropdownMenu,

View File

@@ -1,3 +1,5 @@
"use client"
import { Button } from "@/examples/base/ui/button"
import {
DropdownMenu,

View File

@@ -1,3 +1,5 @@
"use client"
import { Button } from "@/examples/base/ui/button"
import {
DropdownMenu,

View File

@@ -1,3 +1,5 @@
"use client"
import { Button } from "@/examples/base/ui/button"
import {
DropdownMenu,

View File

@@ -1,3 +1,5 @@
"use client"
import { Button } from "@/examples/base/ui/button"
import {
DropdownMenu,