ruler-components 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +51 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.js +534 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +498 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +21 -2
- package/AGENTS.md +0 -9
- package/CLAUDE.md +0 -1
- package/app/docs/[slug]/page.tsx +0 -147
- package/app/docs/layout.tsx +0 -26
- package/app/docs/page.tsx +0 -148
- package/app/favicon.ico +0 -0
- package/app/globals.css +0 -168
- package/app/icon.png +0 -0
- package/app/layout.tsx +0 -90
- package/app/opengraph-image.tsx +0 -10
- package/app/page.tsx +0 -34
- package/app/twitter-image.tsx +0 -10
- package/components/docs/accordion-doc-page.tsx +0 -352
- package/components/docs/alert-doc-page.tsx +0 -293
- package/components/docs/allinput-doc-page.tsx +0 -183
- package/components/docs/avatar-doc-page.tsx +0 -424
- package/components/docs/badge-doc-page.tsx +0 -363
- package/components/docs/button-doc-page.tsx +0 -406
- package/components/docs/card-doc-page.tsx +0 -364
- package/components/docs/checkbox-doc-page.tsx +0 -277
- package/components/docs/colors-doc-page.tsx +0 -430
- package/components/docs/dialog-doc-page.tsx +0 -364
- package/components/docs/docs-footer.tsx +0 -11
- package/components/docs/docs-mobile-menu-bar.tsx +0 -22
- package/components/docs/docs-mobile-nav-context.tsx +0 -27
- package/components/docs/docs-page.tsx +0 -263
- package/components/docs/docs-search.tsx +0 -303
- package/components/docs/docs-sidebar.tsx +0 -165
- package/components/docs/docs-topbar.tsx +0 -32
- package/components/docs/dropdown-doc-page.tsx +0 -522
- package/components/docs/getting-started-doc-page.tsx +0 -205
- package/components/docs/label-doc-page.tsx +0 -173
- package/components/docs/loaders-doc-page.tsx +0 -244
- package/components/docs/menu-doc-page.tsx +0 -373
- package/components/docs/modal-doc-page.tsx +0 -436
- package/components/docs/next-steps.tsx +0 -53
- package/components/docs/pagination-doc-page.tsx +0 -316
- package/components/docs/progress-doc-page.tsx +0 -387
- package/components/docs/radio-doc-page.tsx +0 -270
- package/components/docs/skeleton-doc-page.tsx +0 -230
- package/components/docs/stepper-doc-page.tsx +0 -309
- package/components/docs/switch-doc-page.tsx +0 -264
- package/components/docs/table-doc-page.tsx +0 -689
- package/components/docs/tabs-doc-page.tsx +0 -359
- package/components/docs/theming-doc-page.tsx +0 -243
- package/components/docs/tooltip-doc-page.tsx +0 -357
- package/components/docs/usage-section.tsx +0 -21
- package/components/icons/discord.tsx +0 -9
- package/components/icons/github.tsx +0 -9
- package/components/icons/x.tsx +0 -9
- package/components/installation-section.tsx +0 -34
- package/components/landing/feature-highlights.tsx +0 -105
- package/components/landing/footer-strip.tsx +0 -45
- package/components/landing/hero-card.tsx +0 -14
- package/components/landing/hero-spotlight.tsx +0 -126
- package/components/landing/hero.tsx +0 -64
- package/components/landing/navbar.tsx +0 -44
- package/components/landing/quick-start-section.tsx +0 -59
- package/components/landing/site-footer.tsx +0 -55
- package/components/theme-provider.tsx +0 -60
- package/components/ui/accordion.tsx +0 -174
- package/components/ui/alert.tsx +0 -103
- package/components/ui/allinput.tsx +0 -210
- package/components/ui/avatar.tsx +0 -179
- package/components/ui/badge.tsx +0 -52
- package/components/ui/button.tsx +0 -75
- package/components/ui/card.tsx +0 -105
- package/components/ui/checkbox.tsx +0 -130
- package/components/ui/code-block.tsx +0 -60
- package/components/ui/data-table.tsx +0 -235
- package/components/ui/dialog.tsx +0 -173
- package/components/ui/dropdown.tsx +0 -78
- package/components/ui/feature-card.tsx +0 -38
- package/components/ui/input.tsx +0 -44
- package/components/ui/label.tsx +0 -110
- package/components/ui/loaders.tsx +0 -139
- package/components/ui/menu.tsx +0 -118
- package/components/ui/modal.tsx +0 -399
- package/components/ui/package-manager-tabs.tsx +0 -40
- package/components/ui/pagination.tsx +0 -200
- package/components/ui/progress.tsx +0 -134
- package/components/ui/radio.tsx +0 -262
- package/components/ui/skeleton.tsx +0 -102
- package/components/ui/steppers.tsx +0 -309
- package/components/ui/switch.tsx +0 -153
- package/components/ui/table.tsx +0 -58
- package/components/ui/tabs.tsx +0 -166
- package/components/ui/theme-toggle.tsx +0 -60
- package/components/ui/tooltip.tsx +0 -238
- package/data/color-palette.ts +0 -35
- package/data/docs-nav.ts +0 -84
- package/eslint.config.mjs +0 -18
- package/index.ts +0 -8
- package/lib/cn.ts +0 -4
- package/lib/color.ts +0 -85
- package/lib/og-image.tsx +0 -138
- package/lib/theme.ts +0 -33
- package/next.config.ts +0 -7
- package/postcss.config.mjs +0 -7
- package/public/dark.png +0 -0
- package/public/dark1.png +0 -0
- package/public/dark2.png +0 -0
- package/public/file.svg +0 -1
- package/public/globe.svg +0 -1
- package/public/light.png +0 -0
- package/public/light1.png +0 -0
- package/public/next.svg +0 -1
- package/public/vercel.svg +0 -1
- package/public/video/hero-demo.mp4 +0 -0
- package/public/window.svg +0 -1
- package/tsconfig.json +0 -34
|
@@ -1,689 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import React, { useState } from "react";
|
|
4
|
-
import { Table2, User, ArrowUpRight, MoreHorizontal, Check, X, Copy } from "lucide-react";
|
|
5
|
-
import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell, ExpandableRow } from "@/components/ui/table";
|
|
6
|
-
import { Badge, type BadgeProps } from "@/components/ui/badge";
|
|
7
|
-
import { Card } from "@/components/ui/card";
|
|
8
|
-
import { DataTable, type DataTableColumn } from "@/components/ui/data-table";
|
|
9
|
-
import { Pagination } from "@/components/ui/pagination";
|
|
10
|
-
import { Tooltip } from "@/components/ui/tooltip";
|
|
11
|
-
import {
|
|
12
|
-
DocsAccessibility,
|
|
13
|
-
DocsApiSection,
|
|
14
|
-
DocsApiTable,
|
|
15
|
-
DocsPage,
|
|
16
|
-
DocsPageHeader,
|
|
17
|
-
DocsSection,
|
|
18
|
-
DocsSectionGrid,
|
|
19
|
-
DocsSimpleTable,
|
|
20
|
-
DocsSubsection,
|
|
21
|
-
} from "@/components/docs/docs-page";
|
|
22
|
-
import { cn } from "@/lib/cn";
|
|
23
|
-
|
|
24
|
-
interface Member {
|
|
25
|
-
name: string;
|
|
26
|
-
email: string;
|
|
27
|
-
role: "Admin" | "Editor" | "Viewer";
|
|
28
|
-
status: "Active" | "Invited" | "Suspended";
|
|
29
|
-
projects: number;
|
|
30
|
-
joined: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function statusVariant(status: string): BadgeProps["variant"] {
|
|
34
|
-
switch (status) {
|
|
35
|
-
case "Active":
|
|
36
|
-
case "Paid":
|
|
37
|
-
return "success";
|
|
38
|
-
case "Invited":
|
|
39
|
-
return "info";
|
|
40
|
-
case "Pending":
|
|
41
|
-
case "Paused":
|
|
42
|
-
return "warning";
|
|
43
|
-
case "Suspended":
|
|
44
|
-
case "Overdue":
|
|
45
|
-
case "Error":
|
|
46
|
-
return "error";
|
|
47
|
-
default:
|
|
48
|
-
return "default";
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
interface Invoice {
|
|
53
|
-
id: string;
|
|
54
|
-
customer: string;
|
|
55
|
-
amount: string;
|
|
56
|
-
status: "Paid" | "Pending" | "Overdue";
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const INVOICES: Invoice[] = [
|
|
60
|
-
{ id: "INV-1042", customer: "Bright Path Studio", amount: "$1,240.00", status: "Paid" },
|
|
61
|
-
{ id: "INV-1041", customer: "Northwind Traders", amount: "$860.50", status: "Paid" },
|
|
62
|
-
{ id: "INV-1040", customer: "Vertex Analytics", amount: "$2,310.00", status: "Pending" },
|
|
63
|
-
{ id: "INV-1039", customer: "Solstice Media", amount: "$540.00", status: "Paid" },
|
|
64
|
-
{ id: "INV-1038", customer: "Anchor & Co.", amount: "$3,120.75", status: "Overdue" },
|
|
65
|
-
{ id: "INV-1037", customer: "Glide Robotics", amount: "$975.20", status: "Paid" },
|
|
66
|
-
{ id: "INV-1036", customer: "Fable Interiors", amount: "$410.00", status: "Pending" },
|
|
67
|
-
{ id: "INV-1035", customer: "Harbor Logistics", amount: "$1,890.00", status: "Paid" },
|
|
68
|
-
{ id: "INV-1034", customer: "Quiet Forge", amount: "$260.00", status: "Overdue" },
|
|
69
|
-
{ id: "INV-1033", customer: "Lumen Health", amount: "$4,050.00", status: "Paid" },
|
|
70
|
-
{ id: "INV-1032", customer: "Cedar & Vine", amount: "$725.00", status: "Pending" },
|
|
71
|
-
{ id: "INV-1031", customer: "Pace Robotics", amount: "$1,150.00", status: "Paid" },
|
|
72
|
-
];
|
|
73
|
-
|
|
74
|
-
const INVOICE_PAGE_SIZE = 5;
|
|
75
|
-
|
|
76
|
-
const MEMBERS: Member[] = [
|
|
77
|
-
{ name: "Ava Whitfield", email: "ava@ruler.dev", role: "Admin", status: "Active", projects: 12, joined: "2023-02-14" },
|
|
78
|
-
{ name: "Noah Bianchi", email: "noah@ruler.dev", role: "Editor", status: "Active", projects: 8, joined: "2023-05-30" },
|
|
79
|
-
{ name: "Lena Kowalski", email: "lena@ruler.dev", role: "Viewer", status: "Invited", projects: 0, joined: "2024-01-09" },
|
|
80
|
-
{ name: "Marcus Reed", email: "marcus@ruler.dev", role: "Editor", status: "Active", projects: 15, joined: "2022-11-02" },
|
|
81
|
-
{ name: "Priya Nandakumar", email: "priya@ruler.dev", role: "Admin", status: "Active", projects: 21, joined: "2022-08-18" },
|
|
82
|
-
{ name: "Diego Ferreira", email: "diego@ruler.dev", role: "Viewer", status: "Suspended", projects: 3, joined: "2023-09-25" },
|
|
83
|
-
{ name: "Hana Suzuki", email: "hana@ruler.dev", role: "Editor", status: "Active", projects: 6, joined: "2024-03-11" },
|
|
84
|
-
{ name: "Owen Fitzgerald", email: "owen@ruler.dev", role: "Viewer", status: "Invited", projects: 1, joined: "2024-04-02" },
|
|
85
|
-
{ name: "Zara Ahmed", email: "zara@ruler.dev", role: "Admin", status: "Active", projects: 18, joined: "2022-06-07" },
|
|
86
|
-
{ name: "Leo Moretti", email: "leo@ruler.dev", role: "Editor", status: "Active", projects: 9, joined: "2023-07-19" },
|
|
87
|
-
{ name: "Ines Duarte", email: "ines@ruler.dev", role: "Viewer", status: "Suspended", projects: 2, joined: "2023-12-01" },
|
|
88
|
-
{ name: "Felix Bergman", email: "felix@ruler.dev", role: "Editor", status: "Active", projects: 11, joined: "2023-03-27" },
|
|
89
|
-
];
|
|
90
|
-
|
|
91
|
-
const MEMBER_COLUMNS: DataTableColumn<Member>[] = [
|
|
92
|
-
{
|
|
93
|
-
key: "name",
|
|
94
|
-
header: "Member",
|
|
95
|
-
sortable: true,
|
|
96
|
-
render: (row) => (
|
|
97
|
-
<div className="flex items-center gap-3">
|
|
98
|
-
<div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-zinc-100 text-xs font-bold text-zinc-600 dark:bg-zinc-800 dark:text-zinc-300">
|
|
99
|
-
{row.name.split(" ").map((part) => part[0]).join("")}
|
|
100
|
-
</div>
|
|
101
|
-
<div>
|
|
102
|
-
<p className="text-sm font-semibold text-zinc-900 dark:text-white">{row.name}</p>
|
|
103
|
-
<p className="text-xs text-zinc-500 dark:text-zinc-400">{row.email}</p>
|
|
104
|
-
</div>
|
|
105
|
-
</div>
|
|
106
|
-
),
|
|
107
|
-
},
|
|
108
|
-
{ key: "role", header: "Role", filterOptions: ["Admin", "Editor", "Viewer"] },
|
|
109
|
-
{
|
|
110
|
-
key: "status",
|
|
111
|
-
header: "Status",
|
|
112
|
-
filterOptions: ["Active", "Invited", "Suspended"],
|
|
113
|
-
render: (row) => <Badge variant={statusVariant(row.status)}>{row.status}</Badge>,
|
|
114
|
-
},
|
|
115
|
-
{ key: "projects", header: "Projects", sortable: true, align: "right" },
|
|
116
|
-
{
|
|
117
|
-
key: "joined",
|
|
118
|
-
header: "Joined",
|
|
119
|
-
sortable: true,
|
|
120
|
-
render: (row) => new Date(row.joined).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }),
|
|
121
|
-
},
|
|
122
|
-
];
|
|
123
|
-
|
|
124
|
-
const DATA_TABLE_API_ROWS = [
|
|
125
|
-
{ prop: "data", type: "T[]", default: "—", description: "Array of row objects to render" },
|
|
126
|
-
{ prop: "columns", type: "DataTableColumn<T>[]", default: "—", description: "Column definitions — sorting, filtering, alignment, and custom rendering" },
|
|
127
|
-
{ prop: "searchPlaceholder", type: "string", default: '"Search..."', description: "Placeholder text for the built-in search input" },
|
|
128
|
-
{ prop: "pageSize", type: "number", default: "5", description: "Number of rows shown per page" },
|
|
129
|
-
{ prop: "className", type: "string", default: "—", description: "Additional CSS classes for the outer container" },
|
|
130
|
-
];
|
|
131
|
-
|
|
132
|
-
const SUBCOMPONENT_ROWS = [
|
|
133
|
-
{ name: "Table", description: "Root scroll container and <table> element." },
|
|
134
|
-
{ name: "TableHeader", description: "Wraps the header row(s) in a <thead>." },
|
|
135
|
-
{ name: "TableBody", description: "Wraps data rows in a <tbody> with row dividers." },
|
|
136
|
-
{ name: "TableRow", description: "A single row with a subtle hover state." },
|
|
137
|
-
{ name: "TableHead", description: "A header cell with uppercase, muted styling." },
|
|
138
|
-
{ name: "TableCell", description: "A standard data cell." },
|
|
139
|
-
{ name: "ExpandableRow", description: "A row that toggles open to reveal extra details." },
|
|
140
|
-
];
|
|
141
|
-
|
|
142
|
-
const ACCESSIBILITY_ITEMS = [
|
|
143
|
-
"Use TableHead cells for column headers so screen readers announce them correctly.",
|
|
144
|
-
"Keep an accessible label on icon-only actions like row menus and pagination controls.",
|
|
145
|
-
"Don't rely on color alone to convey status — pair badges with text.",
|
|
146
|
-
"Expandable rows should reflect their open/closed state to assistive tech.",
|
|
147
|
-
"Prefer numeric alignment (text-right) for scannable, comparable metrics.",
|
|
148
|
-
];
|
|
149
|
-
|
|
150
|
-
interface Product {
|
|
151
|
-
name: string;
|
|
152
|
-
category: string;
|
|
153
|
-
status: "Active" | "Paused" | "Error";
|
|
154
|
-
price: string;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const PRODUCTS: Product[] = [
|
|
158
|
-
{ name: "Aurora Desk Lamp", category: "Lighting", status: "Active", price: "$48.00" },
|
|
159
|
-
{ name: "Cedar Notebook", category: "Stationery", status: "Active", price: "$14.00" },
|
|
160
|
-
{ name: "Mono Backpack", category: "Bags", status: "Paused", price: "$92.00" },
|
|
161
|
-
{ name: "Slate Water Bottle", category: "Outdoor", status: "Active", price: "$22.00" },
|
|
162
|
-
{ name: "Nimbus Headphones", category: "Audio", status: "Error", price: "$128.00" },
|
|
163
|
-
{ name: "Birch Wall Clock", category: "Home", status: "Active", price: "$36.00" },
|
|
164
|
-
{ name: "Ridge Trail Tent", category: "Outdoor", status: "Paused", price: "$210.00" },
|
|
165
|
-
{ name: "Quartz Desk Mat", category: "Office", status: "Active", price: "$18.00" },
|
|
166
|
-
];
|
|
167
|
-
|
|
168
|
-
const ROW_COUNTS = [3, 5, 8] as const;
|
|
169
|
-
type RowCount = (typeof ROW_COUNTS)[number];
|
|
170
|
-
|
|
171
|
-
function playgroundCodeFor(rowCount: RowCount, expandable: boolean) {
|
|
172
|
-
if (expandable) {
|
|
173
|
-
return `<Table>
|
|
174
|
-
<TableHeader>
|
|
175
|
-
<TableRow>
|
|
176
|
-
<TableHead></TableHead>
|
|
177
|
-
<TableHead>Product</TableHead>
|
|
178
|
-
<TableHead>Category</TableHead>
|
|
179
|
-
<TableHead>Status</TableHead>
|
|
180
|
-
</TableRow>
|
|
181
|
-
</TableHeader>
|
|
182
|
-
<TableBody>
|
|
183
|
-
<ExpandableRow
|
|
184
|
-
title="${PRODUCTS[0].name}"
|
|
185
|
-
details={<div>Price: ${PRODUCTS[0].price}</div>}
|
|
186
|
-
>
|
|
187
|
-
<TableCell className="font-medium">${PRODUCTS[0].name}</TableCell>
|
|
188
|
-
<TableCell>${PRODUCTS[0].category}</TableCell>
|
|
189
|
-
<TableCell>
|
|
190
|
-
<Badge variant="success">${PRODUCTS[0].status}</Badge>
|
|
191
|
-
</TableCell>
|
|
192
|
-
</ExpandableRow>
|
|
193
|
-
{/* ...${rowCount - 1} more rows */}
|
|
194
|
-
</TableBody>
|
|
195
|
-
</Table>`;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
return `<Table>
|
|
199
|
-
<TableHeader>
|
|
200
|
-
<TableRow>
|
|
201
|
-
<TableHead>Product</TableHead>
|
|
202
|
-
<TableHead>Category</TableHead>
|
|
203
|
-
<TableHead>Status</TableHead>
|
|
204
|
-
<TableHead className="text-right">Price</TableHead>
|
|
205
|
-
</TableRow>
|
|
206
|
-
</TableHeader>
|
|
207
|
-
<TableBody>
|
|
208
|
-
<TableRow>
|
|
209
|
-
<TableCell className="font-medium">${PRODUCTS[0].name}</TableCell>
|
|
210
|
-
<TableCell>${PRODUCTS[0].category}</TableCell>
|
|
211
|
-
<TableCell>
|
|
212
|
-
<Badge variant="success">${PRODUCTS[0].status}</Badge>
|
|
213
|
-
</TableCell>
|
|
214
|
-
<TableCell className="text-right font-mono">${PRODUCTS[0].price}</TableCell>
|
|
215
|
-
</TableRow>
|
|
216
|
-
{/* ...${rowCount - 1} more rows */}
|
|
217
|
-
</TableBody>
|
|
218
|
-
</Table>`;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export function TableDocPage() {
|
|
222
|
-
const data = [
|
|
223
|
-
{ channel: "Direct", sessions: "39,443", bounce: "38.47%", status: "Active" },
|
|
224
|
-
{ channel: "Organic Search", sessions: "18,199", bounce: "37.06%", status: "Paused" },
|
|
225
|
-
{ channel: "Social", sessions: "13,268", bounce: "55.54%", status: "Error" },
|
|
226
|
-
];
|
|
227
|
-
|
|
228
|
-
const [invoicePage, setInvoicePage] = React.useState(1);
|
|
229
|
-
const invoiceTotalPages = Math.ceil(INVOICES.length / INVOICE_PAGE_SIZE);
|
|
230
|
-
const pagedInvoices = INVOICES.slice(
|
|
231
|
-
(invoicePage - 1) * INVOICE_PAGE_SIZE,
|
|
232
|
-
invoicePage * INVOICE_PAGE_SIZE,
|
|
233
|
-
);
|
|
234
|
-
|
|
235
|
-
const [rowCount, setRowCount] = useState<RowCount>(5);
|
|
236
|
-
const [expandable, setExpandable] = useState(false);
|
|
237
|
-
const [copied, setCopied] = useState(false);
|
|
238
|
-
|
|
239
|
-
const playgroundRows = PRODUCTS.slice(0, rowCount);
|
|
240
|
-
const playgroundSnippet = playgroundCodeFor(rowCount, expandable);
|
|
241
|
-
|
|
242
|
-
function copyPlaygroundSnippet() {
|
|
243
|
-
navigator.clipboard.writeText(playgroundSnippet).catch(() => {});
|
|
244
|
-
setCopied(true);
|
|
245
|
-
setTimeout(() => setCopied(false), 1200);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
return (
|
|
249
|
-
<DocsPage>
|
|
250
|
-
<DocsPageHeader
|
|
251
|
-
icon={Table2}
|
|
252
|
-
title="Table"
|
|
253
|
-
description="Full-width data tables for every use case — from a fully interactive data grid to lightweight static styles."
|
|
254
|
-
/>
|
|
255
|
-
|
|
256
|
-
<DocsSection
|
|
257
|
-
first
|
|
258
|
-
title="Playground"
|
|
259
|
-
description="Compose a table from the real building blocks and copy the exact markup — live."
|
|
260
|
-
>
|
|
261
|
-
<div className="overflow-hidden rounded-2xl border border-zinc-200 shadow-[0_2px_8px_rgba(0,0,0,0.04)] dark:border-zinc-800 dark:shadow-[0_2px_8px_rgba(0,0,0,0.2)]">
|
|
262
|
-
<div className="relative flex min-h-[18rem] items-start justify-center overflow-hidden bg-zinc-50 p-6 dark:bg-zinc-900/40">
|
|
263
|
-
<div
|
|
264
|
-
aria-hidden
|
|
265
|
-
className="pointer-events-none absolute inset-0 opacity-[0.4] dark:opacity-[0.15]"
|
|
266
|
-
style={{
|
|
267
|
-
backgroundImage:
|
|
268
|
-
"linear-gradient(to right, rgb(161 161 170 / 0.35) 1px, transparent 1px), linear-gradient(to bottom, rgb(161 161 170 / 0.35) 1px, transparent 1px)",
|
|
269
|
-
backgroundSize: "24px 24px",
|
|
270
|
-
}}
|
|
271
|
-
/>
|
|
272
|
-
<div
|
|
273
|
-
key={`${rowCount}-${expandable}`}
|
|
274
|
-
className="relative w-full animate-[pagination-pop_0.2s_ease-out] overflow-hidden rounded-xl border border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-950"
|
|
275
|
-
>
|
|
276
|
-
<Table>
|
|
277
|
-
<TableHeader>
|
|
278
|
-
<TableRow>
|
|
279
|
-
{expandable && <TableHead></TableHead>}
|
|
280
|
-
<TableHead>Product</TableHead>
|
|
281
|
-
<TableHead>Category</TableHead>
|
|
282
|
-
<TableHead>Status</TableHead>
|
|
283
|
-
{!expandable && <TableHead className="text-right">Price</TableHead>}
|
|
284
|
-
</TableRow>
|
|
285
|
-
</TableHeader>
|
|
286
|
-
<TableBody>
|
|
287
|
-
{expandable
|
|
288
|
-
? playgroundRows.map((p) => (
|
|
289
|
-
<ExpandableRow
|
|
290
|
-
key={p.name}
|
|
291
|
-
title={p.name}
|
|
292
|
-
colSpan={3}
|
|
293
|
-
details={
|
|
294
|
-
<div className="text-zinc-500 dark:text-zinc-400">Price: {p.price}</div>
|
|
295
|
-
}
|
|
296
|
-
>
|
|
297
|
-
<TableCell className="font-medium">{p.name}</TableCell>
|
|
298
|
-
<TableCell>{p.category}</TableCell>
|
|
299
|
-
<TableCell>
|
|
300
|
-
<Badge variant={statusVariant(p.status)}>{p.status}</Badge>
|
|
301
|
-
</TableCell>
|
|
302
|
-
</ExpandableRow>
|
|
303
|
-
))
|
|
304
|
-
: playgroundRows.map((p) => (
|
|
305
|
-
<TableRow key={p.name}>
|
|
306
|
-
<TableCell className="font-medium">{p.name}</TableCell>
|
|
307
|
-
<TableCell>{p.category}</TableCell>
|
|
308
|
-
<TableCell>
|
|
309
|
-
<Badge variant={statusVariant(p.status)}>{p.status}</Badge>
|
|
310
|
-
</TableCell>
|
|
311
|
-
<TableCell className="text-right font-mono">{p.price}</TableCell>
|
|
312
|
-
</TableRow>
|
|
313
|
-
))}
|
|
314
|
-
</TableBody>
|
|
315
|
-
</Table>
|
|
316
|
-
</div>
|
|
317
|
-
</div>
|
|
318
|
-
|
|
319
|
-
<div className="flex flex-col gap-5 border-t border-zinc-200 p-5 dark:border-zinc-800">
|
|
320
|
-
<div className="flex flex-wrap items-start justify-between gap-6">
|
|
321
|
-
<div>
|
|
322
|
-
<p className="mb-2 text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
|
|
323
|
-
Row count
|
|
324
|
-
</p>
|
|
325
|
-
<div className="flex flex-wrap items-center gap-1 rounded-lg border border-zinc-200 bg-zinc-50 p-1 dark:border-zinc-800 dark:bg-zinc-900/60">
|
|
326
|
-
{ROW_COUNTS.map((n) => (
|
|
327
|
-
<button
|
|
328
|
-
key={n}
|
|
329
|
-
type="button"
|
|
330
|
-
onClick={() => setRowCount(n)}
|
|
331
|
-
className={cn(
|
|
332
|
-
"rounded-md px-3 py-1.5 text-xs font-medium uppercase tracking-wide transition-colors",
|
|
333
|
-
rowCount === n
|
|
334
|
-
? "bg-white text-zinc-900 shadow-sm dark:bg-zinc-800 dark:text-white"
|
|
335
|
-
: "text-zinc-500 hover:text-zinc-800 dark:text-zinc-400 dark:hover:text-zinc-200"
|
|
336
|
-
)}
|
|
337
|
-
>
|
|
338
|
-
{n}
|
|
339
|
-
</button>
|
|
340
|
-
))}
|
|
341
|
-
</div>
|
|
342
|
-
</div>
|
|
343
|
-
|
|
344
|
-
<div>
|
|
345
|
-
<p className="mb-2 text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
|
|
346
|
-
Expandable rows
|
|
347
|
-
</p>
|
|
348
|
-
<button
|
|
349
|
-
type="button"
|
|
350
|
-
onClick={() => setExpandable((v) => !v)}
|
|
351
|
-
className={cn(
|
|
352
|
-
"flex h-[2.125rem] items-center gap-2 rounded-lg border px-3 text-xs font-medium transition-colors",
|
|
353
|
-
expandable
|
|
354
|
-
? "border-zinc-900 bg-zinc-900 text-white dark:border-white dark:bg-white dark:text-zinc-900"
|
|
355
|
-
: "border-zinc-200 text-zinc-500 hover:border-zinc-300 dark:border-zinc-700 dark:text-zinc-400"
|
|
356
|
-
)}
|
|
357
|
-
>
|
|
358
|
-
{expandable ? "On" : "Off"}
|
|
359
|
-
</button>
|
|
360
|
-
</div>
|
|
361
|
-
</div>
|
|
362
|
-
|
|
363
|
-
<div className="flex items-center justify-between gap-3 rounded-xl bg-zinc-900 px-4 py-3 dark:bg-black">
|
|
364
|
-
<pre className="overflow-x-auto font-mono text-[13px] leading-relaxed text-zinc-100">
|
|
365
|
-
<code>{playgroundSnippet}</code>
|
|
366
|
-
</pre>
|
|
367
|
-
<Tooltip content={copied ? "Copied!" : "Copy code"}>
|
|
368
|
-
<button
|
|
369
|
-
type="button"
|
|
370
|
-
onClick={copyPlaygroundSnippet}
|
|
371
|
-
className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-zinc-400 transition-colors hover:bg-white/10 hover:text-white"
|
|
372
|
-
>
|
|
373
|
-
{copied ? <Check className="h-4 w-4 text-emerald-400" /> : <Copy className="h-4 w-4" />}
|
|
374
|
-
</button>
|
|
375
|
-
</Tooltip>
|
|
376
|
-
</div>
|
|
377
|
-
</div>
|
|
378
|
-
</div>
|
|
379
|
-
</DocsSection>
|
|
380
|
-
|
|
381
|
-
<DocsSection
|
|
382
|
-
title="Data Table"
|
|
383
|
-
description="A complete, self-contained table with search, sortable columns, dropdown filters, and pagination."
|
|
384
|
-
>
|
|
385
|
-
<Card className="p-6">
|
|
386
|
-
<DataTable data={MEMBERS} columns={MEMBER_COLUMNS} searchPlaceholder="Search members..." pageSize={5} />
|
|
387
|
-
</Card>
|
|
388
|
-
</DocsSection>
|
|
389
|
-
|
|
390
|
-
<DocsSection title="Basic & Striped" description="Standard rows, or zebra-striping for easier scanning.">
|
|
391
|
-
<DocsSectionGrid>
|
|
392
|
-
<DocsSubsection title="Basic">
|
|
393
|
-
<Table>
|
|
394
|
-
<TableHeader>
|
|
395
|
-
<TableRow>
|
|
396
|
-
<TableHead>Channel</TableHead>
|
|
397
|
-
<TableHead>Sessions</TableHead>
|
|
398
|
-
<TableHead>Bounce Rate</TableHead>
|
|
399
|
-
</TableRow>
|
|
400
|
-
</TableHeader>
|
|
401
|
-
<TableBody>
|
|
402
|
-
{data.map((r) => (
|
|
403
|
-
<TableRow key={r.channel}>
|
|
404
|
-
<TableCell className="font-medium">{r.channel}</TableCell>
|
|
405
|
-
<TableCell>{r.sessions}</TableCell>
|
|
406
|
-
<TableCell>{r.bounce}</TableCell>
|
|
407
|
-
</TableRow>
|
|
408
|
-
))}
|
|
409
|
-
</TableBody>
|
|
410
|
-
</Table>
|
|
411
|
-
</DocsSubsection>
|
|
412
|
-
|
|
413
|
-
<DocsSubsection title="Striped">
|
|
414
|
-
<Table className="[&_tr:nth-child(even)]:bg-zinc-50 dark:[&_tr:nth-child(even)]:bg-zinc-900/50">
|
|
415
|
-
<TableHeader>
|
|
416
|
-
<TableRow>
|
|
417
|
-
<TableHead>Channel</TableHead>
|
|
418
|
-
<TableHead>Sessions</TableHead>
|
|
419
|
-
</TableRow>
|
|
420
|
-
</TableHeader>
|
|
421
|
-
<TableBody>
|
|
422
|
-
{data.map((r) => (
|
|
423
|
-
<TableRow key={r.channel}>
|
|
424
|
-
<TableCell>{r.channel}</TableCell>
|
|
425
|
-
<TableCell>{r.sessions}</TableCell>
|
|
426
|
-
</TableRow>
|
|
427
|
-
))}
|
|
428
|
-
</TableBody>
|
|
429
|
-
</Table>
|
|
430
|
-
</DocsSubsection>
|
|
431
|
-
</DocsSectionGrid>
|
|
432
|
-
</DocsSection>
|
|
433
|
-
|
|
434
|
-
<DocsSection title="Bordered & Compact" description="Full cell borders for clarity, or tight padding for dense data.">
|
|
435
|
-
<DocsSectionGrid>
|
|
436
|
-
<DocsSubsection title="Bordered">
|
|
437
|
-
<div className="overflow-hidden rounded-xl border border-zinc-200 dark:border-zinc-800">
|
|
438
|
-
<Table className="[&_td]:border-r [&_th]:border-r last:[&_td]:border-r-0 last:[&_th]:border-r-0">
|
|
439
|
-
<TableHeader>
|
|
440
|
-
<TableRow>
|
|
441
|
-
<TableHead>Channel</TableHead>
|
|
442
|
-
<TableHead>Sessions</TableHead>
|
|
443
|
-
<TableHead>Bounce Rate</TableHead>
|
|
444
|
-
</TableRow>
|
|
445
|
-
</TableHeader>
|
|
446
|
-
<TableBody>
|
|
447
|
-
{data.map((r) => (
|
|
448
|
-
<TableRow key={r.channel}>
|
|
449
|
-
<TableCell className="font-medium">{r.channel}</TableCell>
|
|
450
|
-
<TableCell>{r.sessions}</TableCell>
|
|
451
|
-
<TableCell>{r.bounce}</TableCell>
|
|
452
|
-
</TableRow>
|
|
453
|
-
))}
|
|
454
|
-
</TableBody>
|
|
455
|
-
</Table>
|
|
456
|
-
</div>
|
|
457
|
-
</DocsSubsection>
|
|
458
|
-
|
|
459
|
-
<DocsSubsection title="Compact">
|
|
460
|
-
<Table>
|
|
461
|
-
<TableBody>
|
|
462
|
-
{data.map((r) => (
|
|
463
|
-
<TableRow key={r.channel}>
|
|
464
|
-
<TableCell className="py-1.5">{r.channel}</TableCell>
|
|
465
|
-
<TableCell className="py-1.5 text-right font-mono">{r.sessions}</TableCell>
|
|
466
|
-
</TableRow>
|
|
467
|
-
))}
|
|
468
|
-
</TableBody>
|
|
469
|
-
</Table>
|
|
470
|
-
</DocsSubsection>
|
|
471
|
-
</DocsSectionGrid>
|
|
472
|
-
</DocsSection>
|
|
473
|
-
|
|
474
|
-
<DocsSection title="Paginated Table" description="Slice a larger dataset into pages with simple, reusable pagination controls.">
|
|
475
|
-
<div className="overflow-hidden rounded-xl border border-zinc-200 dark:border-zinc-800">
|
|
476
|
-
<Table>
|
|
477
|
-
<TableHeader>
|
|
478
|
-
<TableRow>
|
|
479
|
-
<TableHead>Invoice</TableHead>
|
|
480
|
-
<TableHead>Customer</TableHead>
|
|
481
|
-
<TableHead className="text-right">Amount</TableHead>
|
|
482
|
-
<TableHead>Status</TableHead>
|
|
483
|
-
</TableRow>
|
|
484
|
-
</TableHeader>
|
|
485
|
-
<TableBody>
|
|
486
|
-
{pagedInvoices.map((invoice) => (
|
|
487
|
-
<TableRow key={invoice.id}>
|
|
488
|
-
<TableCell className="font-mono text-xs text-zinc-500 dark:text-zinc-400">{invoice.id}</TableCell>
|
|
489
|
-
<TableCell className="font-medium">{invoice.customer}</TableCell>
|
|
490
|
-
<TableCell className="text-right font-mono">{invoice.amount}</TableCell>
|
|
491
|
-
<TableCell>
|
|
492
|
-
<Badge variant={statusVariant(invoice.status)}>{invoice.status}</Badge>
|
|
493
|
-
</TableCell>
|
|
494
|
-
</TableRow>
|
|
495
|
-
))}
|
|
496
|
-
</TableBody>
|
|
497
|
-
</Table>
|
|
498
|
-
</div>
|
|
499
|
-
|
|
500
|
-
<div className="flex flex-col-reverse items-center justify-between gap-3 pt-4 sm:flex-row">
|
|
501
|
-
<p className="text-xs text-zinc-500 dark:text-zinc-400">
|
|
502
|
-
Showing {(invoicePage - 1) * INVOICE_PAGE_SIZE + 1}–
|
|
503
|
-
{Math.min(invoicePage * INVOICE_PAGE_SIZE, INVOICES.length)} of {INVOICES.length}
|
|
504
|
-
</p>
|
|
505
|
-
<Pagination page={invoicePage} totalPages={invoiceTotalPages} onPageChange={setInvoicePage} />
|
|
506
|
-
</div>
|
|
507
|
-
</DocsSection>
|
|
508
|
-
|
|
509
|
-
<DocsSection title="Minimal & Comparison" description="A borderless style for quiet lists, or side-by-side plan comparisons.">
|
|
510
|
-
<DocsSectionGrid>
|
|
511
|
-
<DocsSubsection title="Minimal">
|
|
512
|
-
<Table className="border-none">
|
|
513
|
-
<TableBody>
|
|
514
|
-
{data.map((r) => (
|
|
515
|
-
<TableRow key={r.channel} className="hover:bg-transparent">
|
|
516
|
-
<TableCell className="px-0 font-medium">{r.channel}</TableCell>
|
|
517
|
-
<TableCell className="px-0 text-right opacity-70">{r.sessions}</TableCell>
|
|
518
|
-
</TableRow>
|
|
519
|
-
))}
|
|
520
|
-
</TableBody>
|
|
521
|
-
</Table>
|
|
522
|
-
</DocsSubsection>
|
|
523
|
-
|
|
524
|
-
<DocsSubsection title="Comparison">
|
|
525
|
-
<Table className="border border-zinc-200 dark:border-zinc-800">
|
|
526
|
-
<TableHeader>
|
|
527
|
-
<TableRow>
|
|
528
|
-
<TableHead className="w-[30%]">Feature</TableHead>
|
|
529
|
-
<TableHead className="bg-zinc-50 text-center dark:bg-zinc-900">Personal</TableHead>
|
|
530
|
-
<TableHead className="text-center">Team</TableHead>
|
|
531
|
-
</TableRow>
|
|
532
|
-
</TableHeader>
|
|
533
|
-
<TableBody>
|
|
534
|
-
<TableRow>
|
|
535
|
-
<TableCell>API access</TableCell>
|
|
536
|
-
<TableCell className="text-center">
|
|
537
|
-
<X size={16} className="mx-auto text-red-500" />
|
|
538
|
-
</TableCell>
|
|
539
|
-
<TableCell className="text-center">
|
|
540
|
-
<Check size={16} className="mx-auto text-emerald-500" />
|
|
541
|
-
</TableCell>
|
|
542
|
-
</TableRow>
|
|
543
|
-
<TableRow>
|
|
544
|
-
<TableCell>Custom domain</TableCell>
|
|
545
|
-
<TableCell className="text-center">
|
|
546
|
-
<Check size={16} className="mx-auto text-emerald-500" />
|
|
547
|
-
</TableCell>
|
|
548
|
-
<TableCell className="text-center">
|
|
549
|
-
<Check size={16} className="mx-auto text-emerald-500" />
|
|
550
|
-
</TableCell>
|
|
551
|
-
</TableRow>
|
|
552
|
-
</TableBody>
|
|
553
|
-
</Table>
|
|
554
|
-
</DocsSubsection>
|
|
555
|
-
</DocsSectionGrid>
|
|
556
|
-
</DocsSection>
|
|
557
|
-
|
|
558
|
-
<DocsSection title="Expandable Rows" description="Toggle a row open to reveal more detailed information.">
|
|
559
|
-
<Table>
|
|
560
|
-
<TableHeader>
|
|
561
|
-
<TableRow>
|
|
562
|
-
<TableHead></TableHead>
|
|
563
|
-
<TableHead>Project Name</TableHead>
|
|
564
|
-
<TableHead>Status</TableHead>
|
|
565
|
-
</TableRow>
|
|
566
|
-
</TableHeader>
|
|
567
|
-
<TableBody>
|
|
568
|
-
<ExpandableRow
|
|
569
|
-
title="Project X"
|
|
570
|
-
details={
|
|
571
|
-
<div className="p-2 text-zinc-500 dark:text-zinc-400">
|
|
572
|
-
Project internal ID: #9901. Team: Analytics. Priority: High.
|
|
573
|
-
</div>
|
|
574
|
-
}
|
|
575
|
-
>
|
|
576
|
-
<TableCell className="font-semibold">Project X</TableCell>
|
|
577
|
-
<TableCell>
|
|
578
|
-
<Badge variant="success">Active</Badge>
|
|
579
|
-
</TableCell>
|
|
580
|
-
</ExpandableRow>
|
|
581
|
-
<ExpandableRow
|
|
582
|
-
title="Project Y"
|
|
583
|
-
details={
|
|
584
|
-
<div className="p-2 text-zinc-500 dark:text-zinc-400">
|
|
585
|
-
Project internal ID: #9902. Team: Marketing. Priority: Low.
|
|
586
|
-
</div>
|
|
587
|
-
}
|
|
588
|
-
>
|
|
589
|
-
<TableCell className="font-semibold">Project Y</TableCell>
|
|
590
|
-
<TableCell>
|
|
591
|
-
<Badge variant="warning">Pending</Badge>
|
|
592
|
-
</TableCell>
|
|
593
|
-
</ExpandableRow>
|
|
594
|
-
</TableBody>
|
|
595
|
-
</Table>
|
|
596
|
-
</DocsSection>
|
|
597
|
-
|
|
598
|
-
<DocsSection title="Status Table" description="Highlight state changes across rows using badges.">
|
|
599
|
-
<Table>
|
|
600
|
-
<TableHeader>
|
|
601
|
-
<TableRow>
|
|
602
|
-
<TableHead>Channel</TableHead>
|
|
603
|
-
<TableHead>Status</TableHead>
|
|
604
|
-
<TableHead>Sessions</TableHead>
|
|
605
|
-
</TableRow>
|
|
606
|
-
</TableHeader>
|
|
607
|
-
<TableBody>
|
|
608
|
-
{data.map((r) => (
|
|
609
|
-
<TableRow key={r.channel}>
|
|
610
|
-
<TableCell className="font-medium">{r.channel}</TableCell>
|
|
611
|
-
<TableCell>
|
|
612
|
-
<Badge variant={statusVariant(r.status)}>{r.status}</Badge>
|
|
613
|
-
</TableCell>
|
|
614
|
-
<TableCell>{r.sessions}</TableCell>
|
|
615
|
-
</TableRow>
|
|
616
|
-
))}
|
|
617
|
-
</TableBody>
|
|
618
|
-
</Table>
|
|
619
|
-
</DocsSection>
|
|
620
|
-
|
|
621
|
-
<DocsSection title="Card Table" description="A table contained within a rounded, elevated surface.">
|
|
622
|
-
<Card className="overflow-hidden">
|
|
623
|
-
<Table>
|
|
624
|
-
<TableHeader>
|
|
625
|
-
<TableRow>
|
|
626
|
-
<TableHead>Source</TableHead>
|
|
627
|
-
<TableHead className="text-right">Value</TableHead>
|
|
628
|
-
</TableRow>
|
|
629
|
-
</TableHeader>
|
|
630
|
-
<TableBody>
|
|
631
|
-
{data.map((r) => (
|
|
632
|
-
<TableRow key={r.channel}>
|
|
633
|
-
<TableCell>{r.channel}</TableCell>
|
|
634
|
-
<TableCell className="text-right">{r.sessions}</TableCell>
|
|
635
|
-
</TableRow>
|
|
636
|
-
))}
|
|
637
|
-
</TableBody>
|
|
638
|
-
</Table>
|
|
639
|
-
</Card>
|
|
640
|
-
</DocsSection>
|
|
641
|
-
|
|
642
|
-
<DocsSection title="Dashboard Table" description="A rich dashboard view with avatars, growth metrics, and row actions.">
|
|
643
|
-
<Card className="overflow-hidden">
|
|
644
|
-
<Table>
|
|
645
|
-
<TableHeader>
|
|
646
|
-
<TableRow>
|
|
647
|
-
<TableHead>Project Lead</TableHead>
|
|
648
|
-
<TableHead>Growth</TableHead>
|
|
649
|
-
<TableHead>Status</TableHead>
|
|
650
|
-
<TableHead className="text-right">Action</TableHead>
|
|
651
|
-
</TableRow>
|
|
652
|
-
</TableHeader>
|
|
653
|
-
<TableBody>
|
|
654
|
-
{data.map((r) => (
|
|
655
|
-
<TableRow key={r.channel}>
|
|
656
|
-
<TableCell>
|
|
657
|
-
<div className="flex items-center gap-3">
|
|
658
|
-
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-zinc-100 text-zinc-500 dark:bg-zinc-800">
|
|
659
|
-
<User size={14} />
|
|
660
|
-
</div>
|
|
661
|
-
<span className="text-sm font-semibold text-zinc-900 dark:text-white">{r.channel}</span>
|
|
662
|
-
</div>
|
|
663
|
-
</TableCell>
|
|
664
|
-
<TableCell>
|
|
665
|
-
<span className="flex items-center gap-1 text-sm font-bold text-emerald-500">
|
|
666
|
-
+14.5% <ArrowUpRight size={14} />
|
|
667
|
-
</span>
|
|
668
|
-
</TableCell>
|
|
669
|
-
<TableCell>
|
|
670
|
-
<Badge variant={statusVariant(r.status)}>{r.status}</Badge>
|
|
671
|
-
</TableCell>
|
|
672
|
-
<TableCell className="text-right">
|
|
673
|
-
<MoreHorizontal size={16} className="ml-auto cursor-pointer opacity-50 hover:opacity-100" />
|
|
674
|
-
</TableCell>
|
|
675
|
-
</TableRow>
|
|
676
|
-
))}
|
|
677
|
-
</TableBody>
|
|
678
|
-
</Table>
|
|
679
|
-
</Card>
|
|
680
|
-
</DocsSection>
|
|
681
|
-
|
|
682
|
-
<DocsApiSection>
|
|
683
|
-
<DocsApiTable title="API Reference — DataTable" rows={DATA_TABLE_API_ROWS} />
|
|
684
|
-
<DocsSimpleTable title="Building Blocks" rows={SUBCOMPONENT_ROWS} />
|
|
685
|
-
<DocsAccessibility items={ACCESSIBILITY_ITEMS} />
|
|
686
|
-
</DocsApiSection>
|
|
687
|
-
</DocsPage>
|
|
688
|
-
);
|
|
689
|
-
}
|