Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions docs/app/(home)/components/BuildChatSection.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"use client";

import { useEffect, useRef, useState } from "react";
import Image from "next/image";
import dashboardImg from "@/public/images/home/d67b5e94653944c1d0d4998c6b169c37f98060ad.png";
import { CopyIcon } from "./shared";

const dashboardImg = "/images/home/d67b5e94653944c1d0d4998c6b169c37f98060ad.png";

// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -96,10 +96,11 @@ function CtaButton() {

function DashboardIllustration() {
return (
<img
<Image
src={dashboardImg}
alt="AI chat dashboard illustration"
className="w-full h-auto rounded-[12px] object-contain"
className="w-full h-auto rounded-xl object-contain"
placeholder="blur"
/>
);
}
Expand Down
115 changes: 39 additions & 76 deletions docs/app/docs/chat/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Button } from "@/components/button";
import { HeroBadge } from "@/components/hero-badge";
import { Card, Cards } from "fumadocs-ui/components/card";
import { FeatureCard, FeatureCards } from "@/components/overview-components";
import { CodeBlock } from "@/components/overview-components";
import {
Code2,
Database,
Expand All @@ -20,6 +21,26 @@ export const metadata = {
"Production-ready chat UI for AI agents. Drop-in layouts, streaming, and state management.",
};

const headlessCode = `import { useChat } from '@openuidev/react';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

react-headless. I will fix this in next pass.


function CustomChat() {
const { messages, append, isLoading } = useChat();

return (
<div>
{messages.map(m => (
<div key={m.id}>
{m.content}
</div>
))}

<input
onChange={e => append(e.target.value)}
/>
</div>
);
}`;

export default function ChatOverviewPage() {
return (
<div className="max-w-5xl mx-auto py-10 px-6 space-y-20">
Expand Down Expand Up @@ -47,104 +68,46 @@ export default function ChatOverviewPage() {
{/* --- Layouts Showcase --- */}
<section>
<div className="flex items-center gap-2 mb-8">
<Layout className="text-blue-600" />
<h2 className="text-2xl font-bold text-slate-900 dark:text-white">
Batteries-Included Layouts
</h2>
<Layout className="text-fd-foreground" />
<h2 className="text-2xl font-bold">Batteries-Included Layouts</h2>
</div>

<Cards className="lg:grid-cols-3">
<Card
icon={<PanelRightOpen className="text-slate-600 dark:text-slate-400" size={20} />}
title="Copilot"
description="A sidebar assistant that lives alongside your main application content."
href="/docs/chat/copilot"
/>
<Card
icon={<Maximize2 className="text-slate-600 dark:text-slate-400" size={20} />}
title="Full Screen"
description="A standalone, immersive chat page similar to ChatGPT or Claude."
href="/docs/chat/fullscreen"
/>
<Card
icon={<MessageCircle className="text-slate-600 dark:text-slate-400" size={20} />}
title="Bottom Tray"
description="A floating support-style widget that expands from the bottom corner."
href="/docs/chat/bottom-tray"
/>
</Cards>
<FeatureCards>
<FeatureCard icon={<PanelRightOpen />} title="Copilot" description="A sidebar assistant that lives alongside your main application content." href="/docs/chat/copilot" />
<FeatureCard icon={<Maximize2 />} title="Full Screen" description="A standalone, immersive chat page similar to ChatGPT or Claude." href="/docs/chat/fullscreen" />
<FeatureCard icon={<MessageCircle />} title="Bottom Tray" description="A floating support-style widget that expands from the bottom corner." href="/docs/chat/bottom-tray" />
</FeatureCards>
</section>

{/* --- Headless / Features Split --- */}
<section className="grid lg:grid-cols-2 gap-12 items-start">
{/* Left: Core Features */}
<div className="space-y-8">
<div className="flex items-center gap-2">
<Zap className="text-amber-500" />
<h2 className="text-2xl font-bold text-slate-900 dark:text-white">Core Capabilities</h2>
<Zap className="text-fd-foreground" />
<h2 className="text-2xl font-bold">Core Capabilities</h2>
</div>

<Cards>
<Card
icon={<MessageSquare className="text-slate-400" size={20} />}
title="Streaming Native"
description="Handles text deltas, optimistic updates, and loading states automatically."
/>
<Card
icon={<Database className="text-slate-400" size={20} />}
title="Thread Persistence"
description="Built-in support for saving and loading conversation history via simple API contracts."
/>
<Card
icon={<Palette className="text-slate-400" size={20} />}
title="Theming"
description="Customize every color, radius, and font using CSS variables or Tailwind."
/>
</Cards>
<FeatureCards direction="horizontal">
<FeatureCard direction="horizontal" icon={<MessageSquare />} title="Streaming Native" description="Handles text deltas, optimistic updates, and loading states automatically." />
<FeatureCard direction="horizontal" icon={<Database />} title="Thread Persistence" description="Built-in support for saving and loading conversation history via simple API contracts." />
<FeatureCard direction="horizontal" icon={<Palette />} title="Theming" description="Customize every color, radius, and font using CSS variables or Tailwind." />
</FeatureCards>
</div>

{/* Right: Headless Code Snippet */}
<div className="space-y-6">
<div className="flex items-center gap-2">
<Code2 className="text-purple-500" />
<h2 className="text-2xl font-bold text-slate-900 dark:text-white">Go Headless</h2>
<Code2 className="text-fd-foreground" />
<h2 className="text-2xl font-bold">Go Headless</h2>
</div>

<p className="text-slate-600 dark:text-slate-400">
Need full control? Use the `useChat` hook to build your own UI while we handle the
state.
</p>

<div className="relative rounded-xl overflow-hidden bg-slate-900 shadow-xl border border-slate-800">
<div className="flex items-center gap-2 px-4 py-3 border-b border-slate-800 bg-slate-900/50">
<div className="w-3 h-3 rounded-full bg-red-500/20 border border-red-500/50" />
<div className="w-3 h-3 rounded-full bg-yellow-500/20 border border-yellow-500/50" />
<div className="w-3 h-3 rounded-full bg-green-500/20 border border-green-500/50" />
</div>
<div className="p-4 overflow-x-auto">
<pre className="text-sm font-mono text-slate-300">
{`import { useChat } from '@openuidev/react';

function CustomChat() {
const { messages, append, isLoading } = useChat();

return (
<div>
{messages.map(m => (
<div key={m.id}>
{m.content}
</div>
))}

<input
onChange={e => append(e.target.value)}
/>
</div>
);
}`}
</pre>
</div>
</div>
<CodeBlock code={headlessCode} title="CustomChat.tsx" />

<div className="text-right">
<Link
Expand Down
8 changes: 8 additions & 0 deletions docs/app/docs/introduction/page.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
:global(#nd-docs-layout:not(:has(#nd-sidebar))) {
grid-template-columns: 1fr !important;
grid-template-areas: "main" !important;
}

:global(#nd-docs-layout:not(:has(#nd-sidebar))) > * {
grid-area: main !important;
}
1 change: 1 addition & 0 deletions docs/app/docs/introduction/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "@/app/docs/introduction/page.module.css";
import { OverviewPage } from "@/components/overview-components/overview-page";

export const metadata = {
Expand Down
121 changes: 48 additions & 73 deletions docs/app/docs/openui-lang/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ import {
Waves,
Zap,
} from "lucide-react";
import {
FeatureCard,
FeatureCards,
} from "@/components/overview-components";
import Link from "next/link";
import { useState } from "react";

const steps = [
Expand Down Expand Up @@ -62,9 +67,6 @@ export default function OpenUILangOverview() {
{/* Introduction */}
<div className="mb-12 sm:mb-20">
<div className="mb-4 flex items-start gap-3 sm:mb-6 sm:gap-4">
<div className="flex size-10 shrink-0 items-center justify-center rounded-lg bg-emerald-50 sm:size-12 dark:bg-emerald-900/30">
<Code2 className="size-5 text-emerald-600 sm:size-6 dark:text-emerald-400" />
</div>
<div>
<h1 className="mb-1 text-3xl font-bold sm:mb-2 sm:text-4xl">OpenUI Lang</h1>
<p className="text-sm text-slate-500 sm:text-base dark:text-slate-400">
Expand All @@ -75,23 +77,23 @@ export default function OpenUILangOverview() {

<p className="mb-6 text-sm text-slate-600 sm:mb-8 sm:text-base dark:text-slate-400">
An alternative to{" "}
<a
href="https://json-render.dev/"
<Link
href="https://json-render.dev"
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 underline hover:no-underline dark:text-blue-400"
className="underline hover:no-underline"
>
Vercel JSON renderer
</a>{" "}
</Link>{" "}
and{" "}
<a
<Link
href="https://a2ui.org/"
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 underline hover:no-underline dark:text-blue-400"
className=" underline hover:no-underline"
>
A2UI
</a>{" "}
</Link>{" "}
that uses ~52% fewer tokens than equivalent JSON structures. Define your component library
with Zod schemas and parse LLM responses into renderable components.
</p>
Expand All @@ -116,34 +118,23 @@ export default function OpenUILangOverview() {
<div className="mb-12 sm:mb-20">
<h2 className="mb-6 text-2xl font-bold sm:mb-8 sm:text-3xl">Key Features</h2>

<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
<SimpleCard className="p-6">
<Waves className="mb-4 size-8 text-amber-500" />
<h3 className="mb-2 text-lg font-semibold">Streaming Native</h3>
<p className="text-sm text-slate-500 dark:text-slate-400">
Line-oriented syntax means the UI renders line-by-line. No waiting for valid JSON
closing braces.
</p>
</SimpleCard>

<SimpleCard className="p-6">
<Zap className="mb-4 size-8 text-blue-500" />
<h3 className="mb-2 text-lg font-semibold">Token Efficient</h3>
<p className="text-sm text-slate-500 dark:text-slate-400">
Uses ~52% fewer tokens than equivalent JSON structures, significantly reducing
inference cost and latency.
</p>
</SimpleCard>

<SimpleCard className="p-6">
<Shield className="mb-4 size-8 text-emerald-500" />
<h3 className="mb-2 text-lg font-semibold">Hallucination Resistant</h3>
<p className="text-sm text-slate-500 dark:text-slate-400">
Strictly typed against your Zod schemas. If the generated code does not match your
definition, it does not render.
</p>
</SimpleCard>
</div>
<FeatureCards>
<FeatureCard
icon={<Waves />}
title="Streaming Native"
description="Line-oriented syntax means the UI renders line-by-line. No waiting for valid JSON closing braces."
/>
<FeatureCard
icon={<Zap />}
title="Token Efficient"
description="Uses ~52% fewer tokens than equivalent JSON structures, significantly reducing inference cost and latency."
/>
<FeatureCard
icon={<Shield />}
title="Hallucination Resistant"
description="Strictly typed against your Zod schemas. If the generated code does not match your definition, it does not render."
/>
</FeatureCards>
</div>

<Separator className="my-8 sm:my-16" />
Expand Down Expand Up @@ -399,10 +390,8 @@ cancelBtn = Button("Cancel", "action:cancel_contact", "secondary")`}
<SimpleCard className="p-4 sm:p-6">
<div className="mb-4">
<div className="mb-2 flex items-center gap-3">
<div className="flex size-8 items-center justify-center rounded-lg bg-blue-50 dark:bg-blue-900/30">
<span className="text-sm font-semibold text-blue-600 dark:text-blue-400">
{activeStep + 1}
</span>
<div className="flex size-8 items-center justify-center rounded-lg bg-fd-muted dark:bg-fd-muted">
<span className="text-sm font-semibold text-fd-foreground">{activeStep + 1}</span>
</div>
<div>
<h3 className="text-base font-semibold sm:text-lg">{steps[activeStep].title}</h3>
Expand Down Expand Up @@ -442,37 +431,23 @@ cancelBtn = Button("Cancel", "action:cancel_contact", "secondary")`}
Real-world applications where OpenUI Lang excels
</p>

<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
<SimpleCard className="p-4 sm:p-6">
<div className="mb-3 flex size-10 items-center justify-center rounded-lg bg-blue-50 sm:mb-4 sm:size-12 dark:bg-blue-900/30">
<BarChart3 className="size-5 text-blue-500 sm:size-6" />
</div>
<h3 className="mb-2 text-base font-semibold sm:text-lg">Analytics Dashboards</h3>
<p className="mb-4 text-sm text-slate-500 dark:text-slate-400">
Generate complex data visualizations and metric cards from natural language queries.
</p>
</SimpleCard>

<SimpleCard className="p-4 sm:p-6">
<div className="mb-3 flex size-10 items-center justify-center rounded-lg bg-emerald-50 sm:mb-4 sm:size-12 dark:bg-emerald-900/30">
<MessageSquare className="size-5 text-emerald-500 sm:size-6" />
</div>
<h3 className="mb-2 text-base font-semibold sm:text-lg">AI Chat Interfaces</h3>
<p className="mb-4 text-sm text-slate-500 dark:text-slate-400">
Stream UI components in real-time as the LLM generates responses.
</p>
</SimpleCard>

<SimpleCard className="p-4 sm:p-6">
<div className="mb-3 flex size-10 items-center justify-center rounded-lg bg-purple-50 sm:mb-4 sm:size-12 dark:bg-purple-900/30">
<FileText className="size-5 text-purple-500 sm:size-6" />
</div>
<h3 className="mb-2 text-base font-semibold sm:text-lg">Dynamic Forms</h3>
<p className="mb-4 text-sm text-slate-500 dark:text-slate-400">
Build adaptive forms that change based on user input or context.
</p>
</SimpleCard>
</div>
<FeatureCards>
<FeatureCard
icon={<BarChart3 />}
title="Analytics Dashboards"
description="Generate complex data visualizations and metric cards from natural language queries."
/>
<FeatureCard
icon={<MessageSquare />}
title="AI Chat Interfaces"
description="Stream UI components in real-time as the LLM generates responses."
/>
<FeatureCard
icon={<FileText />}
title="Dynamic Forms"
description="Build adaptive forms that change based on user input or context."
/>
</FeatureCards>
</div>
</div>
);
Expand Down
Loading