"use client"
import * as React from "react"
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import {
Tabs,
TabsContent,
TabsCountBadge,
TabsList,
TabsTrigger,
TabsTriggerIcon,
TabsTriggerLabel,
} from "@/components/ui/tabs"
import { Tip } from "@/components/ui/tip"
import { FilterChipGroup } from "@/components/ui/filter-chip-group"
import { ViewSegmentedControl } from "@/components/ui/view-segmented-control"
import {
viewSegmentedButtonClass,
viewSegmentedToolbarClass,
} from "@/components/ui/view-segmented-control"
import { DS_DOC_TABLE_META } from "@/lib/design-system/doc-typography"
import { cn } from "@/lib/utils"
/* ── Doc layout helpers ─────────────────────────────────────────────────── */
function DocVariantStack({ children }: { children: React.ReactNode }) {
return
{children}
}
function DocVariantRow({
label,
children,
}: {
label: string
children: React.ReactNode
}) {
return (
)
}
/** Mount hidden panels so Radix tab triggers satisfy `aria-controls` in doc-only previews. */
function TabsDemoPanels({ values }: { values: string[] }) {
return (
<>
{values.map((value) => (
{value}
))}
>
)
}
function viewToolbarCountBadgeClass(filterId: string, isActive: boolean): string {
const palettes: Record = {
all: {
active: "bg-slate-600 text-white dark:bg-slate-500",
inactive: "bg-slate-100 text-slate-800 dark:bg-slate-800/70 dark:text-slate-100",
},
ongoing: {
active: "bg-blue-600 text-white",
inactive: "bg-blue-100 text-blue-950 dark:bg-blue-950/45 dark:text-blue-100",
},
}
const p = palettes[filterId] ?? palettes.all
return isActive ? p.active : p.inactive
}
/* ── Breadcrumb ─────────────────────────────────────────────────────────── */
export function BreadcrumbPreview() {
return (
Dashboard
Students
)
}
/* ── Default variant (pill) ─────────────────────────────────────────────── */
/*
* These rows carry `pinVariant`, which product surfaces must not: the compact
* shell renders an unpinned `default` row as `line`, so without it a page
* documenting the pill would quietly show an underline instead.
*/
export function TabsPrimaryVariantsPreview() {
return (
Tab one
Tab two
Tab three
Tab one
Tab two
Tab three
Tab one
Tab two
Tab three
)
}
/** @deprecated Use TabsPrimaryVariantsPreview — kept for catalog aliases */
export function TabsDefaultPreview() {
return (
Overview
Details
Default pill tablist
Second panel
)
}
/* ── Line variant (underline) ───────────────────────────────────────────── */
export function TabsSecondaryVariantsPreview() {
return (
Alpha
Beta
Alpha
Beta
Alpha
Beta
)
}
/** @deprecated Use TabsSecondaryVariantsPreview */
export function TabsLinePreview() {
return (
Chart
Trend
Chart panel body
Trend panel body
)
}
const RESPONSIVE_TABS = [
{ value: "chart", label: "Chart", icon: "fa-chart-mixed" },
{ value: "trend", label: "Trend", icon: "fa-chart-line" },
{ value: "table", label: "Table", icon: "fa-table" },
{ value: "notes", label: "Notes", icon: "fa-note-sticky" },
]
/**
* One resizable row. Trigger sizing is left to the variant, so the pill and the
* line row each collapse at their own scale rather than a shared override.
*/
function ResponsiveCollapseRow({
variant,
ariaLabel,
}: {
variant: "default" | "line"
ariaLabel: string
}) {
return (
{RESPONSIVE_TABS.map(tab => (
{tab.label}
))}
{RESPONSIVE_TABS.map(tab => (
{tab.label} panel body
))}
)
}
export function TabsResponsiveCollapsePreview() {
return (
Drag the lower right corner of either row to narrow it. Both variants shed
the same way, because the behaviour lives in the scroll region rather than
the chrome. Once the labels stop fitting, inactive tabs show their icon
alone and name themselves on hover or focus, while the selected tab keeps
its label. Narrower still, the tabs that no longer fit move into a menu at
the end of the row. Picking one there brings it back onto the row and sends
another tab into the menu, so the selected tab is always visible.
)
}
export function TabsPreview() {
return
}
/* ── View segmented control — hub views toolbar (ListPageTemplate) ─────── */
type HubViewTab = {
id: string
label: string
icon: string
filterId: string
count: number
}
const HUB_VIEW_TABS: HubViewTab[] = [
{ id: "questions", label: "Questions", icon: "fa-table", filterId: "all", count: 12 },
{ id: "board", label: "Board", icon: "fa-columns-3", filterId: "ongoing", count: 12 },
]
/**
* Full hub views toolbar — icon, label, count, chevron settings menu, and Add view.
* Matches `ListPageTemplate` views chrome; not Radix Tabs.
*/
export function ViewSegmentedHubToolbarPreview() {
const [activeId, setActiveId] = React.useState("board")
return (
{HUB_VIEW_TABS.map((tab) => {
const isActive = tab.id === activeId
const tabInner = (
<>
{tab.label}
{tab.count}
>
)
const viewSettingsMenu = (
View: {tab.label}
Rename
Edit
Duplicate
)
if (isActive) {
return (
setActiveId(tab.id)}
className={cn(
"inline-flex min-h-8 items-center gap-1.5 rounded-s-md rounded-e-none bg-transparent py-1 ps-2.5 pe-0.5 text-xs font-medium text-foreground",
"hover:bg-foreground/[0.04]",
"focus-visible:z-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
)}
>
{tabInner}
{viewSettingsMenu}
)
}
return (
setActiveId(tab.id)}
className={viewSegmentedButtonClass(false)}
>
{tabInner}
)
})}
Add a view
Table
Board
Dashboard
)
}
/** Simple labeled segments — compact hubs without saved views */
export function ViewSegmentedControlPreview() {
const [view, setView] = React.useState<"table" | "board" | "dashboard">("table")
return (
)
}
export function ViewSegmentedControlIconPreview() {
const [view, setView] = React.useState<"table" | "board">("table")
return (
)
}
const CATALOG_CHIP_OPTIONS = [
{ value: "all" as const, label: "All", count: 103 },
{ value: "token" as const, label: "Design tokens", count: 9, icon: "fa-light fa-droplet" },
{ value: "component" as const, label: "UI primitives", count: 40, icon: "fa-light fa-cube" },
]
const CHART_CHIP_OPTIONS = [
{ value: "trends" as const, label: "Trends" },
{ value: "bars" as const, label: "Bars" },
{ value: "distribution" as const, label: "Distribution" },
{ value: "relationship" as const, label: "Relationship" },
]
/** Brand variant — Design OS Catalog tier filter with icons and counts. */
export function FilterChipGroupBrandPreview() {
const [value, setValue] = React.useState<(typeof CATALOG_CHIP_OPTIONS)[number]["value"]>("all")
return (
)
}
/** Muted variant — in-content family pickers (chart types, doc filters). */
export function FilterChipGroupMutedPreview() {
const [value, setValue] = React.useState<(typeof CHART_CHIP_OPTIONS)[number]["value"]>("trends")
return (
)
}
/** Size comparison — default vs sm on muted variant. */
const FILTER_CHIP_GROUP_SIZES_OPTIONS = [
{ value: "trends", label: "Trends" },
{ value: "bars", label: "Bars" },
{ value: "flow", label: "Flow" },
] as const
export function FilterChipGroupSizesPreview() {
const [value, setValue] = React.useState("bars")
return (
)
}