diff --git a/docs/app/(home)/components/BuildChatSection.tsx b/docs/app/(home)/components/BuildChatSection.tsx index a40a62f95..77646b078 100644 --- a/docs/app/(home)/components/BuildChatSection.tsx +++ b/docs/app/(home)/components/BuildChatSection.tsx @@ -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 // --------------------------------------------------------------------------- @@ -96,10 +96,11 @@ function CtaButton() { function DashboardIllustration() { return ( - AI chat dashboard illustration ); } diff --git a/docs/app/docs/chat/page.tsx b/docs/app/docs/chat/page.tsx index 99d972f66..85f08d501 100644 --- a/docs/app/docs/chat/page.tsx +++ b/docs/app/docs/chat/page.tsx @@ -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, @@ -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'; + +function CustomChat() { + const { messages, append, isLoading } = useChat(); + + return ( +
+ {messages.map(m => ( +
+ {m.content} +
+ ))} + + append(e.target.value)} + /> +
+ ); +}`; + export default function ChatOverviewPage() { return (
@@ -47,32 +68,15 @@ export default function ChatOverviewPage() { {/* --- Layouts Showcase --- */}
- -

- Batteries-Included Layouts -

+ +

Batteries-Included Layouts

- - } - title="Copilot" - description="A sidebar assistant that lives alongside your main application content." - href="/docs/chat/copilot" - /> - } - title="Full Screen" - description="A standalone, immersive chat page similar to ChatGPT or Claude." - href="/docs/chat/fullscreen" - /> - } - title="Bottom Tray" - description="A floating support-style widget that expands from the bottom corner." - href="/docs/chat/bottom-tray" - /> - + + } title="Copilot" description="A sidebar assistant that lives alongside your main application content." href="/docs/chat/copilot" /> + } title="Full Screen" description="A standalone, immersive chat page similar to ChatGPT or Claude." href="/docs/chat/fullscreen" /> + } title="Bottom Tray" description="A floating support-style widget that expands from the bottom corner." href="/docs/chat/bottom-tray" /> +
{/* --- Headless / Features Split --- */} @@ -80,34 +84,22 @@ export default function ChatOverviewPage() { {/* Left: Core Features */}
- -

Core Capabilities

+ +

Core Capabilities

- - } - title="Streaming Native" - description="Handles text deltas, optimistic updates, and loading states automatically." - /> - } - title="Thread Persistence" - description="Built-in support for saving and loading conversation history via simple API contracts." - /> - } - title="Theming" - description="Customize every color, radius, and font using CSS variables or Tailwind." - /> - + + } title="Streaming Native" description="Handles text deltas, optimistic updates, and loading states automatically." /> + } title="Thread Persistence" description="Built-in support for saving and loading conversation history via simple API contracts." /> + } title="Theming" description="Customize every color, radius, and font using CSS variables or Tailwind." /> +
{/* Right: Headless Code Snippet */}
- -

Go Headless

+ +

Go Headless

@@ -115,36 +107,7 @@ export default function ChatOverviewPage() { state.

-
-
-
-
-
-
-
-
-                {`import { useChat } from '@openuidev/react';
-
-function CustomChat() {
-  const { messages, append, isLoading } = useChat();
-
-  return (
-    
- {messages.map(m => ( -
- {m.content} -
- ))} - - append(e.target.value)} - /> -
- ); -}`} -
-
-
+
* { + grid-area: main !important; +} diff --git a/docs/app/docs/introduction/page.tsx b/docs/app/docs/introduction/page.tsx index 70acfd79e..630bdcbbf 100644 --- a/docs/app/docs/introduction/page.tsx +++ b/docs/app/docs/introduction/page.tsx @@ -1,3 +1,4 @@ +import "@/app/docs/introduction/page.module.css"; import { OverviewPage } from "@/components/overview-components/overview-page"; export const metadata = { diff --git a/docs/app/docs/openui-lang/page.tsx b/docs/app/docs/openui-lang/page.tsx index d0e725e49..a29e1e09b 100644 --- a/docs/app/docs/openui-lang/page.tsx +++ b/docs/app/docs/openui-lang/page.tsx @@ -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 = [ @@ -62,9 +67,6 @@ export default function OpenUILangOverview() { {/* Introduction */}
-
- -

OpenUI Lang

@@ -75,23 +77,23 @@ export default function OpenUILangOverview() {

An alternative to{" "} - Vercel JSON renderer - {" "} + {" "} and{" "} - A2UI - {" "} + {" "} that uses ~52% fewer tokens than equivalent JSON structures. Define your component library with Zod schemas and parse LLM responses into renderable components.

@@ -116,34 +118,23 @@ export default function OpenUILangOverview() {

Key Features

-
- - -

Streaming Native

-

- Line-oriented syntax means the UI renders line-by-line. No waiting for valid JSON - closing braces. -

-
- - - -

Token Efficient

-

- Uses ~52% fewer tokens than equivalent JSON structures, significantly reducing - inference cost and latency. -

-
- - - -

Hallucination Resistant

-

- Strictly typed against your Zod schemas. If the generated code does not match your - definition, it does not render. -

-
-
+ + } + title="Streaming Native" + description="Line-oriented syntax means the UI renders line-by-line. No waiting for valid JSON closing braces." + /> + } + title="Token Efficient" + description="Uses ~52% fewer tokens than equivalent JSON structures, significantly reducing inference cost and latency." + /> + } + title="Hallucination Resistant" + description="Strictly typed against your Zod schemas. If the generated code does not match your definition, it does not render." + /> +
@@ -399,10 +390,8 @@ cancelBtn = Button("Cancel", "action:cancel_contact", "secondary")`}
-
- - {activeStep + 1} - +
+ {activeStep + 1}

{steps[activeStep].title}

@@ -442,37 +431,23 @@ cancelBtn = Button("Cancel", "action:cancel_contact", "secondary")`} Real-world applications where OpenUI Lang excels

-
- -
- -
-

Analytics Dashboards

-

- Generate complex data visualizations and metric cards from natural language queries. -

-
- - -
- -
-

AI Chat Interfaces

-

- Stream UI components in real-time as the LLM generates responses. -

-
- - -
- -
-

Dynamic Forms

-

- Build adaptive forms that change based on user input or context. -

-
-
+ + } + title="Analytics Dashboards" + description="Generate complex data visualizations and metric cards from natural language queries." + /> + } + title="AI Chat Interfaces" + description="Stream UI components in real-time as the LLM generates responses." + /> + } + title="Dynamic Forms" + description="Build adaptive forms that change based on user input or context." + /> +
); diff --git a/docs/app/global.css b/docs/app/global.css index 8d1ce10d6..8e47f0566 100644 --- a/docs/app/global.css +++ b/docs/app/global.css @@ -13,6 +13,27 @@ .light { --color-fd-background: hsl(0, 0%, 100%); + --color-doc-surface: #f8f8fa; + --color-doc-surface-raised: #ffffff; + --color-doc-surface-sunken: #f0f0f4; + --color-doc-border: rgba(0, 0, 0, 0.08); + --color-doc-code-bg: #f4f4f8; +} + +.dark { + --color-fd-background: #0b0b0f; + --color-fd-foreground: #e2e1e6; + --color-fd-muted: #141418; + --color-fd-popover: #131317; + --color-fd-card: #111115; + --color-fd-secondary: #141418; + + /* Doc component surface tokens */ + --color-doc-surface: #111115; + --color-doc-surface-raised: #16161b; + --color-doc-surface-sunken: #0e0e12; + --color-doc-border: rgba(255, 255, 255, 0.08); + --color-doc-code-bg: #0d0d11; } #nd-docs-layout { @@ -24,13 +45,8 @@ #nd-docs-layout:not(:has(#nd-sidebar)) { --fd-sidebar-width: 0px !important; --fd-toc-width: 0px !important; - grid-template-columns: 1fr !important; - grid-template-areas: "main" !important; } -#nd-docs-layout:not(:has(#nd-sidebar)) > * { - grid-area: main !important; -} #nd-sidebar { background-color: transparent !important; diff --git a/docs/app/og/docs/[...slug]/route.tsx b/docs/app/og/docs/[...slug]/route.tsx index d10cf1de5..7e98c015e 100644 --- a/docs/app/og/docs/[...slug]/route.tsx +++ b/docs/app/og/docs/[...slug]/route.tsx @@ -11,7 +11,7 @@ export async function GET(_req: Request, { params }: RouteContext<"/og/docs/[... if (!page) notFound(); return new ImageResponse( - , + , { width: 1200, height: 630, diff --git a/docs/components/brand-logo.tsx b/docs/components/brand-logo.tsx index d4bd75e1a..7cd4e6f62 100644 --- a/docs/components/brand-logo.tsx +++ b/docs/components/brand-logo.tsx @@ -1,8 +1,10 @@ "use client"; import mascotSvgPaths from "@/imports/svg-kl5jpwq8km"; +import mascotDarkSvgPaths from "@/imports/svg-mascot-dark"; import svgPaths from "@/imports/svg-urruvoh2be"; import { AnimatePresence, motion } from "motion/react"; +import Link from "next/link"; import { useEffect, useState } from "react"; const COUNT_UP_DURATION = 3000; @@ -86,27 +88,72 @@ export function OpenUILogo({ variant = "light" }: { variant?: LogoVariant }) { : "font-['Geist',sans-serif] font-semibold text-[15px] text-black leading-6"; return ( - + {/* Shiro mascot */}
- - - - - - - - - + {isDark ? ( + + + + + + + + + + + + ) : ( + + + + + + + + + + )}
OpenUI -
+ ); } diff --git a/docs/components/button.tsx b/docs/components/button.tsx index ab73bc301..d614acb82 100644 --- a/docs/components/button.tsx +++ b/docs/components/button.tsx @@ -14,7 +14,7 @@ export function Button({ href, text, size = "lg", variant = "primary" }: ButtonP const variantClasses = variant === "primary" ? "text-white bg-slate-900 rounded-lg hover:bg-slate-800 transition-colors dark:bg-white dark:text-slate-900 dark:hover:bg-slate-100" - : "text-slate-700 bg-white border border-slate-200 rounded-lg hover:bg-slate-50 transition-colors dark:bg-slate-900 dark:text-slate-300 dark:border-slate-800 dark:hover:bg-slate-800"; + : "text-slate-700 bg-white border border-slate-200 rounded-lg hover:bg-slate-50 transition-colors dark:bg-[var(--color-doc-surface)] dark:text-slate-300 dark:border-[var(--color-doc-border)] dark:hover:bg-[var(--color-doc-surface-raised)]"; return ( { - setIsMac(navigator.platform.toUpperCase().includes("MAC")); - }, []); + const [isMac, setIsMac] = useState( + () => typeof navigator !== "undefined" && /mac/i.test(navigator.userAgent), + ); useEffect(() => { const handler = (e: KeyboardEvent) => { @@ -66,11 +66,18 @@ function SearchBar() { export function DocsNavbar({ showSidebarToggle = false }: { showSidebarToggle?: boolean }) { const pathname = usePathname(); + const [isThesysHovered, setIsThesysHovered] = useState(false); + const { resolvedTheme } = useTheme(); + const [mounted, setMounted] = useState(false); + useEffect(() => { + setMounted(true); + }, []); + const logoVariant = mounted && resolvedTheme === "dark" ? "dark" : "light"; return (
{/* Top row: logo left, actions right */} -
+
{showSidebarToggle && ( - + + | +
{/* Actions */} -
+
{/* Discord */} @@ -123,12 +136,14 @@ export function DocsNavbar({ showSidebarToggle = false }: { showSidebarToggle?: + {/* Theme toggle */} +
{/* Bottom row: tabs */} -
+