"use client";
import { ThemeProvider as BjorkDemoThemeProvider } from "next-themes";
import { useEffect, useRef, useState } from "react";
import { MessageBranch, SAMPLE_ASSISTANT_VERSIONS, SAMPLE_USER_VERSIONS, type MessageVersion } from "@/components/ui/bjork-message-branch";
const REWRITES = [
"Your drafts now live on your device first. Lose the connection mid-sentence and Fieldnotes simply carries on, then syncs the moment you're back.",
"New: offline drafts. Fieldnotes saves locally and syncs later, so a flaky connection never eats your work.",
"Write without a signal. Fieldnotes keeps drafts on your device and syncs them when you reconnect.",
];
function Demo() {
const [user, setUser] = useState<MessageVersion[]>(SAMPLE_USER_VERSIONS);
const [assistant, setAssistant] = useState<MessageVersion[]>(SAMPLE_ASSISTANT_VERSIONS);
const [writing, setWriting] = useState<{ id: string; text: string; shown: number } | null>(null);
const timers = useRef<number[]>([]);
const rewrites = useRef(0);
useEffect(() => () => timers.current.forEach((t) => window.clearTimeout(t)), []);
// Streams the pending rewrite into the newest assistant version, a few characters per tick.
useEffect(() => {
if (!writing) return;
if (writing.shown >= writing.text.length) {
const id = window.setTimeout(() => {
setAssistant((list) => list.map((v) => (v.id === writing.id ? { ...v, streaming: false } : v)));
setWriting(null);
}, 0);
return () => window.clearTimeout(id);
}
const id = window.setTimeout(() => {
const shown = Math.min(writing.text.length, writing.shown + 4);
setAssistant((list) =>
list.map((v) => (v.id === writing.id ? { ...v, content: writing.text.slice(0, shown) } : v)),
);
setWriting({ ...writing, shown });
}, 28);
return () => window.clearTimeout(id);
}, [writing]);
// A real backend would start a request here. The demo adds an empty streaming version after a short wait.
const startRewrite = () => {
const n = ++rewrites.current;
const t = window.setTimeout(() => {
const id = `rewrite-${n}`;
setAssistant((list) => [...list, { id, content: "", model: "Halcyon 3 Pro", createdAt: Date.now(), streaming: true }]);
setWriting({ id, text: REWRITES[(n - 1) % REWRITES.length], shown: 0 });
}, 900);
timers.current.push(t);
};
return (
<div className="flex w-[min(560px,calc(100vw-56px))] flex-col gap-5">
<MessageBranch
role="user"
versions={user}
onEdit={(content) => {
setUser((list) => [...list, { id: `u${list.length + 1}`, content, createdAt: Date.now() }]);
startRewrite();
}}
/>
<MessageBranch
role="assistant"
versions={assistant}
defaultIndex={1}
onRegenerate={startRewrite}
/>
</div>
);
}
function SourceDemo(){
const [session, setSession] = useState(0);
return <>
<Demo key={session} />
</>;
}
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>}