"use client";
import { ThemeProvider as BjorkDemoThemeProvider } from "next-themes";
import { useEffect, useState, type Dispatch, type SetStateAction } from "react";
import { ArtifactPanel, SAMPLE_ARTIFACT, type ArtifactVersion } from "@/components/ui/bjork-artifact-panel";
import { BjorkButton } from "@/components/ui/bjork-artifact-panel-utils/components-bjork-ui-primitives-button";
const BASE = SAMPLE_ARTIFACT.versions[2];
const NEXT_CODE = BASE.code
.replace(
'{plan.interval === "year" ? `Billed ${plan.price} yearly` : "Billed monthly"}',
'{plan.interval === "year" ? `Billed ${plan.price} yearly, save 20%` : "Billed monthly, cancel anytime"}',
)
.replace("// Yearly plans show", "// Yearly plans show a savings note and");
const POSED_CHARS = 560;
function Chat({ onOpen, open }: { onOpen: () => void; open: boolean }) {
return (
<div className="hidden w-[240px] shrink-0 flex-col gap-3 py-2 font-bjork-alpha @[640px]:flex">
<div className="self-end rounded-[14px] rounded-br-[6px] bg-[color:var(--bjork-surface-active)] px-3 py-2 text-[13px] leading-5 text-[color:var(--bjork-text)]">
Make a pricing card for the Studio plan. Yearly should show the monthly price.
</div>
<p className="text-[13px] leading-5 text-[color:var(--bjork-text-medium)]">
Here is a pricing card that takes a plan and shows the monthly equivalent for yearly billing.
</p>
<button
type="button"
onClick={onOpen}
aria-pressed={open}
className="flex h-10 cursor-pointer items-center justify-between gap-2 rounded-[10px] border border-[color:var(--bjork-border)] px-3 text-left text-[13px] font-medium text-[color:var(--bjork-text)] outline-none transition-colors hover:bg-[color:var(--bjork-surface-active)] focus-visible:ring-2 focus-visible:ring-[color:var(--bjork-accent)]"
>
Pricing card
<span className="font-mono text-[10px] uppercase tracking-[0.08em] text-[color:var(--bjork-text-faint)]">
{open ? "open" : "view"}
</span>
</button>
</div>
);
}
function Demo({ chars, setChars }: { chars: number | null; setChars: Dispatch<SetStateAction<number | null>> }) {
const isPreview = false;
const [open, setOpen] = useState(true);
useEffect(() => {
if (isPreview || chars === null || chars >= NEXT_CODE.length) return;
const id = window.setTimeout(() => setChars((c) => Math.min(NEXT_CODE.length, (c ?? 0) + 9)), 30);
return () => window.clearTimeout(id);
}, [isPreview, chars, setChars]);
const shown = isPreview ? POSED_CHARS : chars;
const streaming = shown !== null && shown < NEXT_CODE.length;
const versions: ArtifactVersion[] =
shown === null
? SAMPLE_ARTIFACT.versions
: [
...SAMPLE_ARTIFACT.versions,
{
id: "v4",
code: NEXT_CODE.slice(0, shown),
language: "tsx",
createdAt: 1_760_000_400_000,
preview: streaming ? undefined : BASE.preview,
},
];
return (
<div className="flex w-[min(720px,calc(100vw-56px))] flex-col items-stretch gap-5">
<div className="@container w-full">
<div className="flex h-[460px] gap-5">
<Chat open={open} onOpen={() => setOpen(true)} />
<div className="min-w-0 flex-1">
{open ? (
<ArtifactPanel
title={SAMPLE_ARTIFACT.title}
kind={SAMPLE_ARTIFACT.kind}
versions={versions}
streaming={streaming}
onClose={() => setOpen(false)}
/>
) : (
<div className="grid h-full place-items-center rounded-[14px] border border-dashed border-[color:var(--bjork-border)]">
<BjorkButton variant="secondary" size="sm" onClick={() => setOpen(true)}>
Open artifact
</BjorkButton>
</div>
)}
</div>
</div>
</div>
</div>
);
}
function SourceDemo(){
const [chars, setChars] = useState<number | null>(null);
const streaming = chars !== null && chars < NEXT_CODE.length;
return <>
<Demo chars={chars} setChars={setChars} />
</>;
}
export default function BjorkRegistryPreview(){return <BjorkDemoThemeProvider attribute="class" defaultTheme="dark" enableSystem={false} storageKey="bjork-review-demo-theme"><div data-component-demo className="dark flex min-h-screen w-full items-center justify-center bg-[var(--bjork-bg)] p-8 text-[var(--bjork-text)]"><div className="w-full max-w-[850px]"><SourceDemo/></div></div></BjorkDemoThemeProvider>}