"use client"
/**
* Catalog detail-pane previews โ compose real DS components (no bespoke stand-ins).
*/
import * as React from "react"
import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from "recharts"
import {
ChartCard,
ChartLeoPlotInsightOverlay,
CATALOG_PREVIEW_CHART_LEO,
type ChartCardVariant,
} from "@/components/charts-overview"
import { KeyMetrics, type MetricItem } from "@/components/key-metrics"
import { LibraryBoardCard, LibraryBoardView, LibraryListRowCard } from "@/components/library-board-view"
import { buildLibraryHubColumnDefs } from "@/components/library-table"
import { PageHeader } from "@/components/page-header"
import { Button } from "@/components/ui/button"
import { ColumnTypesRuleDemoTable } from "@/components/column-types-rule-demo-client"
import { DataTable } from "@/components/data-table"
import { useTableState } from "@/components/data-table/use-table-state"
import type { ColumnDef } from "@/components/data-table/types"
import { HubTable } from "@/components/data-views"
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart"
import { ViewSegmentedControl } from "@/components/ui/view-segmented-control"
import { CHART_AXIS_TICK } from "@/lib/chart-typography"
import { toggleLibraryItemFavorite } from "@/lib/library-nav"
import { LIBRARY_ITEMS, type LibraryItem } from "@/lib/mock/library"
import { cn } from "@/lib/utils"
const CATALOG_LIBRARY_ROWS: LibraryItem[] = LIBRARY_ITEMS.slice(0, 9)
const CATALOG_METRICS: MetricItem[] = [
{
id: "published",
label: "Published",
value: 128,
delta: "+6",
trend: "up",
trendPolarity: "higher_is_better",
href: "#published",
chart: {
kind: "sparkline",
series: [
{ value: 98, label: "Jan" },
{ value: 104, label: "Feb" },
{ value: 110, label: "Mar" },
{ value: 116, label: "Apr" },
{ value: 122, label: "May" },
{ value: 128, label: "Jun" },
],
},
},
{
id: "draft",
label: "Draft",
value: 14,
delta: "-2",
trend: "down",
trendPolarity: "higher_is_better",
href: "#draft",
chart: {
kind: "bars",
tone: "info",
series: [
{ value: 18, label: "Mon" },
{ value: 16, label: "Tue" },
{ value: 15, label: "Wed" },
{ value: 17, label: "Thu" },
{ value: 14, label: "Fri" },
{ value: 14, label: "Sat" },
{ value: 14, label: "Sun" },
],
},
},
{
id: "review",
label: "In review",
value: 9,
delta: "",
trend: "neutral",
trendPolarity: "informational",
href: "#review",
progress: 45,
},
{
id: "flags",
label: "Review flags",
value: 2,
delta: "+1",
trend: "up",
trendPolarity: "lower_is_better",
href: "#flags",
alert: "danger",
chart: {
kind: "sparkline",
tone: "danger",
series: [
{ value: 1, label: "Week 1" },
{ value: 0, label: "Week 2" },
{ value: 1, label: "Week 3" },
{ value: 1, label: "Week 4" },
{ value: 2, label: "Week 5" },
],
},
},
]
const CATALOG_CHART_DATA = [
{ month: "Jan", placements: 42 },
{ month: "Feb", placements: 58 },
{ month: "Mar", placements: 74 },
{ month: "Apr", placements: 68 },
{ month: "May", placements: 81 },
]
const catalogChartConfig = {
placements: { label: "Placements", color: "var(--brand-color)" },
} as const
const CATALOG_CHART_FILTER_OPTIONS = [
{ value: "30d", label: "Last 30 days" },
{ value: "90d", label: "Last quarter" },
{ value: "1y", label: "Last year" },
]
const CATALOG_CHART_VARIANT_OPTIONS: {
value: ChartCardVariant
label: string
icon: string
}[] = [
{ value: "normal", label: "Normal", icon: "fa-light fa-chart-column" },
{ value: "tabs", label: "Tabs", icon: "fa-light fa-table-columns" },
{ value: "selector", label: "Selector", icon: "fa-light fa-filter" },
{ value: "metrics-tabs", label: "Metrics", icon: "fa-light fa-gauge-high" },
{ value: "kpi-chart", label: "KPI", icon: "fa-light fa-hashtag" },
]
function CatalogMiniBarChart() {
return (
} />
)
}
const CATALOG_CHART_MINI_METRICS = [
{ label: "Placements", value: "128", trend: "up" as const, trendPolarity: "higher_is_better" as const },
{ label: "Applications", value: "214", trend: "up" as const, trendPolarity: "informational" as const },
{ label: "Reviews", value: "42", trend: "neutral" as const, trendPolarity: "informational" as const },
]
export function CatalogChartCardVariantPreview({
variant,
className,
}: {
variant: ChartCardVariant
className?: string
}) {
const needsMiniMetrics = variant === "metrics-tabs" || variant === "kpi-chart"
const needsSelectorFilter = variant === "selector"
return (
)
}
export function CatalogChartCardPreview({ className }: { className?: string }) {
const [variant, setVariant] = React.useState("metrics-tabs")
return (
setVariant(v as ChartCardVariant)}
aria-label="ChartCard variant"
options={CATALOG_CHART_VARIANT_OPTIONS}
/>
)
}
export function CatalogKeyMetricsPreview({ className }: { className?: string }) {
const [variant, setVariant] = React.useState<"cards" | "card" | "flat">("cards")
const [size, setSize] = React.useState<"sm" | "md" | "lg">("md")
return (
)
}
export function CatalogPageHeaderPreview() {
return (
New question
}
/>
)
}
export function CatalogBoardCardPreview() {
return (
{}}
/>
)
}
export function CatalogLibraryListRowPreview() {
return (
{}}
/>
)
}
function CatalogLibraryHubTablePreview({
rows,
onRowsChange,
}: {
rows: LibraryItem[]
onRowsChange: React.Dispatch>
}) {
const toggleFavorite = React.useCallback(
(row: LibraryItem) => {
onRowsChange((prev) =>
prev.map((item) => (item.id === row.id ? toggleLibraryItemFavorite(item) : item)),
)
},
[onRowsChange],
)
const columns = React.useMemo(
() => buildLibraryHubColumnDefs(rows, toggleFavorite),
[rows, toggleFavorite],
)
return (
rows={rows}
columns={columns}
view="table"
hubLabel="Question bank"
lifecycleTabLabel="All questions"
searchAriaLabel="Search questions"
getRowId={(row) => row.id}
getRowSelectionLabel={(row) => row.stem}
defaultSort={{ key: "stem", dir: "asc" }}
emptyState="No questions."
renderers={{}}
supportedViewTypes={["table"]}
persistKey="catalog-preview:library-hub-table"
pagination={false}
/>
)
}
export function CatalogLibraryHubLivePreview({ className }: { className?: string }) {
const [view, setView] = React.useState<"table" | "board">("board")
const [rows, setRows] = React.useState(CATALOG_LIBRARY_ROWS)
const toggleFavorite = React.useCallback((row: LibraryItem) => {
setRows((prev) =>
prev.map((item) => (item.id === row.id ? toggleLibraryItemFavorite(item) : item)),
)
}, [])
return (
{view === "board" ? (
) : (
)}
)
}
export function CatalogHubTablePreview({ className }: { className?: string }) {
return (
)
}
type CatalogGridRow = {
id: string
name: string
status: string
updated: string
} & Record
const CATALOG_GRID_ROWS: CatalogGridRow[] = [
{ id: "q_101", name: "Diaphragm innervation", status: "Published", updated: "2026-06-01" },
{ id: "q_102", name: "Brachial plexus roots", status: "Draft", updated: "2026-06-02" },
{ id: "q_103", name: "Cranial nerve functions", status: "In review", updated: "2026-06-03" },
{ id: "q_104", name: "Lower limb dermatomes", status: "Published", updated: "2026-06-04" },
{ id: "q_105", name: "Spinal cord tracts", status: "Draft", updated: "2026-06-05" },
]
const CATALOG_GRID_COLUMNS: ColumnDef[] = [
{
key: "name",
label: "Question",
width: 280,
filter: { type: "text" },
},
{
key: "status",
label: "Status",
width: 120,
filter: {
type: "select",
options: [
{ value: "Published", label: "Published" },
{ value: "Draft", label: "Draft" },
{ value: "In review", label: "In review" },
],
},
},
{
key: "updated",
label: "Updated",
width: 120,
filter: { type: "date" },
},
]
/** Core grid only โ sort, filters, resize. Hubs wrap this in HubTable (+ Properties, views). */
export function CatalogDataTablePreview({ className }: { className?: string }) {
const columns = React.useMemo(() => CATALOG_GRID_COLUMNS, [])
const state = useTableState(CATALOG_GRID_ROWS, columns, { key: "name", dir: "asc" })
return (
DataTable โ the grid primitive. List hubs compose it
via HubTable (toolbar + Properties + board/list/dashboard).
row.id}
getRowSelectionLabel={(row) => row.name}
state={state}
defaultSort={{ key: "name", dir: "asc" }}
emptyState="No questions match your filters."
/>
)
}