{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "data-table", "title": "Data Table", "description": "Sortable, filterable table with pagination on the glass Table.", "dependencies": [ "@phosphor-icons/react", "@tanstack/react-table" ], "registryDependencies": [ "@sistine/badge", "@sistine/button", "@sistine/input", "@sistine/table" ], "files": [ { "path": "components/blocks/data-table.tsx", "content": "\"use client\";\n\nimport { ArrowsDownUpIcon, CaretDownIcon, CaretUpIcon, MagnifyingGlassIcon } from \"@phosphor-icons/react\";\nimport {\n type Column,\n type ColumnDef,\n type ColumnFiltersState,\n flexRender,\n getCoreRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n type SortingState,\n useReactTable,\n} from \"@tanstack/react-table\";\nimport * as React from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from \"@/components/ui/table\";\nimport { cn } from \"@/lib/utils\";\n\ninterface Member {\n id: string;\n name: string;\n email: string;\n role: string;\n status: \"active\" | \"pending\" | \"inactive\";\n contributions: number;\n}\n\nconst data: Member[] = [\n {\n id: \"1\",\n name: \"Ada Lovelace\",\n email: \"ada@sistine.dev\",\n role: \"Owner\",\n status: \"active\",\n contributions: 312,\n },\n {\n id: \"2\",\n name: \"Alan Turing\",\n email: \"alan@sistine.dev\",\n role: \"Admin\",\n status: \"active\",\n contributions: 287,\n },\n {\n id: \"3\",\n name: \"Grace Hopper\",\n email: \"grace@sistine.dev\",\n role: \"Maintainer\",\n status: \"active\",\n contributions: 244,\n },\n {\n id: \"4\",\n name: \"Katherine Johnson\",\n email: \"katherine@sistine.dev\",\n role: \"Contributor\",\n status: \"pending\",\n contributions: 98,\n },\n {\n id: \"5\",\n name: \"Linus Torvalds\",\n email: \"linus@sistine.dev\",\n role: \"Maintainer\",\n status: \"active\",\n contributions: 401,\n },\n {\n id: \"6\",\n name: \"Margaret Hamilton\",\n email: \"margaret@sistine.dev\",\n role: \"Admin\",\n status: \"active\",\n contributions: 356,\n },\n {\n id: \"7\",\n name: \"Dennis Ritchie\",\n email: \"dennis@sistine.dev\",\n role: \"Contributor\",\n status: \"inactive\",\n contributions: 41,\n },\n {\n id: \"8\",\n name: \"Barbara Liskov\",\n email: \"barbara@sistine.dev\",\n role: \"Maintainer\",\n status: \"active\",\n contributions: 198,\n },\n {\n id: \"9\",\n name: \"Tim Berners-Lee\",\n email: \"tim@sistine.dev\",\n role: \"Contributor\",\n status: \"pending\",\n contributions: 73,\n },\n {\n id: \"10\",\n name: \"Donald Knuth\",\n email: \"don@sistine.dev\",\n role: \"Contributor\",\n status: \"active\",\n contributions: 165,\n },\n {\n id: \"11\",\n name: \"Edsger Dijkstra\",\n email: \"edsger@sistine.dev\",\n role: \"Contributor\",\n status: \"inactive\",\n contributions: 29,\n },\n {\n id: \"12\",\n name: \"John Carmack\",\n email: \"john@sistine.dev\",\n role: \"Admin\",\n status: \"active\",\n contributions: 220,\n },\n];\n\nconst statusStyles: Record = {\n active: \"border-green-500/40 text-green-600 dark:text-green-400\",\n pending: \"border-yellow-500/40 text-yellow-600 dark:text-yellow-400\",\n inactive: \"border-[var(--glass-border)] text-muted-foreground\",\n};\n\nfunction SortHeader({ column, children, className }: { column: Column; children: React.ReactNode; className?: string }) {\n const sorted = column.getIsSorted();\n return (\n column.toggleSorting(sorted === \"asc\")}\n className={cn(\"inline-flex items-center gap-1 transition-colors hover:text-foreground\", className)}\n >\n {children}\n {sorted === \"asc\" ? (\n \n ) : sorted === \"desc\" ? (\n \n ) : (\n \n )}\n \n );\n}\n\nconst columns: ColumnDef[] = [\n {\n accessorKey: \"name\",\n header: ({ column }) => Name,\n cell: ({ row }) => {row.getValue(\"name\")},\n },\n {\n accessorKey: \"email\",\n header: \"Email\",\n cell: ({ row }) => {row.getValue(\"email\")},\n },\n {\n accessorKey: \"role\",\n header: \"Role\",\n },\n {\n accessorKey: \"status\",\n header: \"Status\",\n cell: ({ row }) => {\n const status = row.getValue(\"status\");\n return {status};\n },\n },\n {\n accessorKey: \"contributions\",\n header: ({ column }) => (\n \n Contributions\n \n ),\n cell: ({ row }) =>
{row.getValue(\"contributions\")}
,\n },\n];\n\nexport function DataTableBlock() {\n const [sorting, setSorting] = React.useState([]);\n const [columnFilters, setColumnFilters] = React.useState([]);\n\n const table = useReactTable({\n data,\n columns,\n state: {\n sorting,\n columnFilters,\n },\n onSortingChange: setSorting,\n onColumnFiltersChange: setColumnFilters,\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n getFilteredRowModel: getFilteredRowModel(),\n getPaginationRowModel: getPaginationRowModel(),\n initialState: {\n pagination: {\n pageSize: 6,\n },\n },\n });\n\n return (\n
\n
\n

Members

\n

A sortable, filterable data table built on the glass Table primitive.

\n
\n\n
\n \n table.getColumn(\"name\")?.setFilterValue(event.target.value)}\n className=\"pl-9\"\n />\n
\n\n \n \n {table.getHeaderGroups().map((headerGroup) => (\n \n {headerGroup.headers.map((header) => (\n {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}\n ))}\n \n ))}\n \n \n {table.getRowModel().rows.length ? (\n table.getRowModel().rows.map((row) => (\n \n {row.getVisibleCells().map((cell) => (\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n ))}\n \n ))\n ) : (\n \n \n No results.\n \n \n )}\n \n
\n\n
\n

\n Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()} · {table.getFilteredRowModel().rows.length} members\n

\n
\n \n \n
\n
\n
\n );\n}\n", "type": "registry:component", "target": "components/blocks/data-table.tsx" } ], "type": "registry:block" }