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,364 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import React, { useState } from "react";
|
|
4
|
-
import {
|
|
5
|
-
ArrowRight,
|
|
6
|
-
Check,
|
|
7
|
-
CheckCircle2,
|
|
8
|
-
Copy,
|
|
9
|
-
LayoutTemplate,
|
|
10
|
-
Sparkles,
|
|
11
|
-
TrendingUp,
|
|
12
|
-
Users,
|
|
13
|
-
} from "lucide-react";
|
|
14
|
-
import { Button } from "@/components/ui/button";
|
|
15
|
-
import {
|
|
16
|
-
Card,
|
|
17
|
-
CardContent,
|
|
18
|
-
CardDescription,
|
|
19
|
-
CardFooter,
|
|
20
|
-
CardHeader,
|
|
21
|
-
CardTitle,
|
|
22
|
-
type CardProps,
|
|
23
|
-
} from "@/components/ui/card";
|
|
24
|
-
import { Badge } from "@/components/ui/badge";
|
|
25
|
-
import { Tooltip } from "@/components/ui/tooltip";
|
|
26
|
-
import {
|
|
27
|
-
DocsAccessibility,
|
|
28
|
-
DocsApiSection,
|
|
29
|
-
DocsApiTable,
|
|
30
|
-
DocsPage,
|
|
31
|
-
DocsPageHeader,
|
|
32
|
-
DocsSection,
|
|
33
|
-
DocsSectionGrid,
|
|
34
|
-
DocsSimpleTable,
|
|
35
|
-
DocsSubsection,
|
|
36
|
-
} from "@/components/docs/docs-page";
|
|
37
|
-
import { cn } from "@/lib/cn";
|
|
38
|
-
|
|
39
|
-
const API_ROWS = [
|
|
40
|
-
{ prop: "variant", type: '"default" | "outline" | "elevated" | "interactive"', default: '"default"', description: "The visual style of the card" },
|
|
41
|
-
{ prop: "children", type: "ReactNode", default: "—", description: "Card content" },
|
|
42
|
-
{ prop: "className", type: "string", default: "—", description: "Additional CSS classes" },
|
|
43
|
-
];
|
|
44
|
-
|
|
45
|
-
const SUBCOMPONENT_ROWS = [
|
|
46
|
-
{ name: "CardHeader", description: "Top section for title and description" },
|
|
47
|
-
{ name: "CardTitle", description: "Primary heading inside the card" },
|
|
48
|
-
{ name: "CardDescription", description: "Supporting text below the title" },
|
|
49
|
-
{ name: "CardContent", description: "Main body content area" },
|
|
50
|
-
{ name: "CardFooter", description: "Bottom section for actions" },
|
|
51
|
-
];
|
|
52
|
-
|
|
53
|
-
const ACCESSIBILITY_ITEMS = [
|
|
54
|
-
"Use semantic headings inside cards for proper document structure.",
|
|
55
|
-
"Ensure interactive elements in card footers have accessible labels.",
|
|
56
|
-
"Don't rely on card borders alone to convey grouping — use headings.",
|
|
57
|
-
"Maintain sufficient contrast between card background and page background.",
|
|
58
|
-
"Keep card content concise and scannable.",
|
|
59
|
-
];
|
|
60
|
-
|
|
61
|
-
type Variant = NonNullable<CardProps["variant"]>;
|
|
62
|
-
|
|
63
|
-
const VARIANTS: { value: Variant; label: string }[] = [
|
|
64
|
-
{ value: "default", label: "Default" },
|
|
65
|
-
{ value: "outline", label: "Outline" },
|
|
66
|
-
{ value: "elevated", label: "Elevated" },
|
|
67
|
-
{ value: "interactive", label: "Interactive" },
|
|
68
|
-
];
|
|
69
|
-
|
|
70
|
-
function codeFor(variant: Variant, withFooter: boolean) {
|
|
71
|
-
const openProps = variant !== "default" ? ` variant="${variant}"` : "";
|
|
72
|
-
const footer = withFooter
|
|
73
|
-
? `\n <CardFooter>\n <Button size="sm">View report</Button>\n </CardFooter>`
|
|
74
|
-
: "";
|
|
75
|
-
return `<Card${openProps}>\n <CardHeader>\n <CardTitle>Weekly Performance</CardTitle>\n <CardDescription>Your team velocity compared to last week.</CardDescription>\n </CardHeader>\n <CardContent>...</CardContent>${footer}\n</Card>`;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export function CardDocPage() {
|
|
79
|
-
const [variant, setVariant] = useState<Variant>("default");
|
|
80
|
-
const [withFooter, setWithFooter] = useState(true);
|
|
81
|
-
const [copied, setCopied] = useState(false);
|
|
82
|
-
|
|
83
|
-
const snippet = codeFor(variant, withFooter);
|
|
84
|
-
|
|
85
|
-
function copySnippet() {
|
|
86
|
-
navigator.clipboard.writeText(snippet).catch(() => {});
|
|
87
|
-
setCopied(true);
|
|
88
|
-
setTimeout(() => setCopied(false), 1200);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return (
|
|
92
|
-
<DocsPage>
|
|
93
|
-
<DocsPageHeader
|
|
94
|
-
icon={LayoutTemplate}
|
|
95
|
-
title="Card"
|
|
96
|
-
description="Groups related content into a clear, scannable surface — ideal for dashboards, settings, and summaries."
|
|
97
|
-
/>
|
|
98
|
-
|
|
99
|
-
<DocsSection
|
|
100
|
-
first
|
|
101
|
-
title="Playground"
|
|
102
|
-
description="Build a card and copy the exact markup — every variant, live."
|
|
103
|
-
>
|
|
104
|
-
<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)]">
|
|
105
|
-
<div className="relative flex min-h-[14rem] items-center justify-center overflow-hidden bg-zinc-50 p-6 dark:bg-zinc-900/40">
|
|
106
|
-
<div
|
|
107
|
-
aria-hidden
|
|
108
|
-
className="pointer-events-none absolute inset-0 opacity-[0.4] dark:opacity-[0.15]"
|
|
109
|
-
style={{
|
|
110
|
-
backgroundImage:
|
|
111
|
-
"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)",
|
|
112
|
-
backgroundSize: "24px 24px",
|
|
113
|
-
}}
|
|
114
|
-
/>
|
|
115
|
-
<div
|
|
116
|
-
key={`${variant}-${withFooter}`}
|
|
117
|
-
className="relative w-full max-w-sm animate-[pagination-pop_0.2s_ease-out]"
|
|
118
|
-
>
|
|
119
|
-
<Card variant={variant}>
|
|
120
|
-
<CardHeader>
|
|
121
|
-
<div className="flex items-start justify-between gap-3">
|
|
122
|
-
<div className="flex h-10 w-10 items-center justify-center rounded-xl bg-zinc-100 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-200">
|
|
123
|
-
<TrendingUp className="h-5 w-5" />
|
|
124
|
-
</div>
|
|
125
|
-
<Badge variant="success">+12%</Badge>
|
|
126
|
-
</div>
|
|
127
|
-
<CardTitle className="mt-3">Weekly Performance</CardTitle>
|
|
128
|
-
<CardDescription>Your team velocity compared to last week.</CardDescription>
|
|
129
|
-
</CardHeader>
|
|
130
|
-
<CardContent>
|
|
131
|
-
<div className="grid grid-cols-2 gap-4">
|
|
132
|
-
<div>
|
|
133
|
-
<p className="text-xs text-zinc-500 dark:text-zinc-400">Tasks done</p>
|
|
134
|
-
<p className="mt-1 text-2xl font-semibold text-zinc-900 dark:text-white">24</p>
|
|
135
|
-
</div>
|
|
136
|
-
<div>
|
|
137
|
-
<p className="text-xs text-zinc-500 dark:text-zinc-400">In progress</p>
|
|
138
|
-
<p className="mt-1 text-2xl font-semibold text-zinc-900 dark:text-white">6</p>
|
|
139
|
-
</div>
|
|
140
|
-
</div>
|
|
141
|
-
</CardContent>
|
|
142
|
-
{withFooter && (
|
|
143
|
-
<CardFooter>
|
|
144
|
-
<Button size="sm">View report</Button>
|
|
145
|
-
</CardFooter>
|
|
146
|
-
)}
|
|
147
|
-
</Card>
|
|
148
|
-
</div>
|
|
149
|
-
</div>
|
|
150
|
-
|
|
151
|
-
<div className="flex flex-col gap-5 border-t border-zinc-200 p-5 dark:border-zinc-800">
|
|
152
|
-
<div className="flex flex-wrap items-start justify-between gap-6">
|
|
153
|
-
<div>
|
|
154
|
-
<p className="mb-2 text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
|
|
155
|
-
Variant
|
|
156
|
-
</p>
|
|
157
|
-
<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">
|
|
158
|
-
{VARIANTS.map((v) => (
|
|
159
|
-
<button
|
|
160
|
-
key={v.value}
|
|
161
|
-
type="button"
|
|
162
|
-
onClick={() => setVariant(v.value)}
|
|
163
|
-
className={cn(
|
|
164
|
-
"rounded-md px-3 py-1.5 text-xs font-medium transition-colors",
|
|
165
|
-
variant === v.value
|
|
166
|
-
? "bg-white text-zinc-900 shadow-sm dark:bg-zinc-800 dark:text-white"
|
|
167
|
-
: "text-zinc-500 hover:text-zinc-800 dark:text-zinc-400 dark:hover:text-zinc-200"
|
|
168
|
-
)}
|
|
169
|
-
>
|
|
170
|
-
{v.label}
|
|
171
|
-
</button>
|
|
172
|
-
))}
|
|
173
|
-
</div>
|
|
174
|
-
</div>
|
|
175
|
-
|
|
176
|
-
<div>
|
|
177
|
-
<p className="mb-2 text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
|
|
178
|
-
Footer
|
|
179
|
-
</p>
|
|
180
|
-
<button
|
|
181
|
-
type="button"
|
|
182
|
-
onClick={() => setWithFooter((v) => !v)}
|
|
183
|
-
className={cn(
|
|
184
|
-
"flex h-[2.125rem] items-center gap-2 rounded-lg border px-3 text-xs font-medium transition-colors",
|
|
185
|
-
withFooter
|
|
186
|
-
? "border-zinc-900 bg-zinc-900 text-white dark:border-white dark:bg-white dark:text-zinc-900"
|
|
187
|
-
: "border-zinc-200 text-zinc-500 hover:border-zinc-300 dark:border-zinc-700 dark:text-zinc-400"
|
|
188
|
-
)}
|
|
189
|
-
>
|
|
190
|
-
{withFooter ? "On" : "Off"}
|
|
191
|
-
</button>
|
|
192
|
-
</div>
|
|
193
|
-
</div>
|
|
194
|
-
|
|
195
|
-
<div className="flex items-center justify-between gap-3 rounded-xl bg-zinc-900 px-4 py-3 dark:bg-black">
|
|
196
|
-
<pre className="overflow-x-auto font-mono text-[13px] leading-relaxed text-zinc-100">
|
|
197
|
-
<code>{snippet}</code>
|
|
198
|
-
</pre>
|
|
199
|
-
<Tooltip content={copied ? "Copied!" : "Copy code"}>
|
|
200
|
-
<button
|
|
201
|
-
type="button"
|
|
202
|
-
onClick={copySnippet}
|
|
203
|
-
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"
|
|
204
|
-
>
|
|
205
|
-
{copied ? <Check className="h-4 w-4 text-emerald-400" /> : <Copy className="h-4 w-4" />}
|
|
206
|
-
</button>
|
|
207
|
-
</Tooltip>
|
|
208
|
-
</div>
|
|
209
|
-
</div>
|
|
210
|
-
</div>
|
|
211
|
-
</DocsSection>
|
|
212
|
-
|
|
213
|
-
<DocsSection
|
|
214
|
-
title="Default"
|
|
215
|
-
description="A balanced card with header, body, and a soft footer action area."
|
|
216
|
-
>
|
|
217
|
-
<div className="max-w-md">
|
|
218
|
-
<Card>
|
|
219
|
-
<CardHeader>
|
|
220
|
-
<div className="flex items-start justify-between gap-3">
|
|
221
|
-
<div className="flex h-10 w-10 items-center justify-center rounded-xl bg-zinc-100 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-200">
|
|
222
|
-
<TrendingUp className="h-5 w-5" />
|
|
223
|
-
</div>
|
|
224
|
-
<Badge variant="success">+12%</Badge>
|
|
225
|
-
</div>
|
|
226
|
-
<CardTitle className="mt-3">Weekly Performance</CardTitle>
|
|
227
|
-
<CardDescription>Your team velocity compared to last week.</CardDescription>
|
|
228
|
-
</CardHeader>
|
|
229
|
-
<CardContent>
|
|
230
|
-
<div className="grid grid-cols-2 gap-4">
|
|
231
|
-
<div>
|
|
232
|
-
<p className="text-xs text-zinc-500 dark:text-zinc-400">Tasks done</p>
|
|
233
|
-
<p className="mt-1 text-2xl font-semibold text-zinc-900 dark:text-white">24</p>
|
|
234
|
-
</div>
|
|
235
|
-
<div>
|
|
236
|
-
<p className="text-xs text-zinc-500 dark:text-zinc-400">In progress</p>
|
|
237
|
-
<p className="mt-1 text-2xl font-semibold text-zinc-900 dark:text-white">6</p>
|
|
238
|
-
</div>
|
|
239
|
-
</div>
|
|
240
|
-
</CardContent>
|
|
241
|
-
<CardFooter>
|
|
242
|
-
<Button size="sm">View report</Button>
|
|
243
|
-
<Button variant="ghost" size="sm">Share</Button>
|
|
244
|
-
</CardFooter>
|
|
245
|
-
</Card>
|
|
246
|
-
</div>
|
|
247
|
-
</DocsSection>
|
|
248
|
-
|
|
249
|
-
<DocsSection
|
|
250
|
-
title="Variants"
|
|
251
|
-
description="Pick the right surface weight for your layout hierarchy."
|
|
252
|
-
contentClassName="grid gap-4 sm:grid-cols-2 xl:grid-cols-4"
|
|
253
|
-
>
|
|
254
|
-
<Card variant="default">
|
|
255
|
-
<CardHeader>
|
|
256
|
-
<CardTitle>Default</CardTitle>
|
|
257
|
-
<CardDescription>Soft shadow for everyday content.</CardDescription>
|
|
258
|
-
</CardHeader>
|
|
259
|
-
</Card>
|
|
260
|
-
<Card variant="outline">
|
|
261
|
-
<CardHeader>
|
|
262
|
-
<CardTitle>Outline</CardTitle>
|
|
263
|
-
<CardDescription>Clean border, no elevation.</CardDescription>
|
|
264
|
-
</CardHeader>
|
|
265
|
-
</Card>
|
|
266
|
-
<Card variant="elevated">
|
|
267
|
-
<CardHeader>
|
|
268
|
-
<CardTitle>Elevated</CardTitle>
|
|
269
|
-
<CardDescription>Stronger depth for emphasis.</CardDescription>
|
|
270
|
-
</CardHeader>
|
|
271
|
-
</Card>
|
|
272
|
-
<Card variant="interactive">
|
|
273
|
-
<CardHeader>
|
|
274
|
-
<CardTitle className="flex items-center justify-between">
|
|
275
|
-
Interactive
|
|
276
|
-
<ArrowRight className="h-4 w-4 text-zinc-400" />
|
|
277
|
-
</CardTitle>
|
|
278
|
-
<CardDescription>Hover to lift — great for links.</CardDescription>
|
|
279
|
-
</CardHeader>
|
|
280
|
-
</Card>
|
|
281
|
-
</DocsSection>
|
|
282
|
-
|
|
283
|
-
<DocsSection>
|
|
284
|
-
<DocsSectionGrid className="lg:grid-cols-2">
|
|
285
|
-
<DocsSubsection title="Pricing Card">
|
|
286
|
-
<Card className="flex h-full max-w-sm flex-col">
|
|
287
|
-
<CardHeader>
|
|
288
|
-
<div className="flex items-center gap-2">
|
|
289
|
-
<Sparkles className="h-4 w-4 text-zinc-500" />
|
|
290
|
-
<Badge variant="info">Popular</Badge>
|
|
291
|
-
</div>
|
|
292
|
-
<CardTitle className="mt-2">Pro Plan</CardTitle>
|
|
293
|
-
<CardDescription>Everything you need to ship faster.</CardDescription>
|
|
294
|
-
</CardHeader>
|
|
295
|
-
<CardContent>
|
|
296
|
-
<div className="flex items-end gap-1">
|
|
297
|
-
<span className="text-4xl font-bold tracking-tight text-zinc-900 dark:text-white">$29</span>
|
|
298
|
-
<span className="mb-1 text-sm text-zinc-500 dark:text-zinc-400">/month</span>
|
|
299
|
-
</div>
|
|
300
|
-
<ul className="mt-5 space-y-2.5 text-sm text-zinc-600 dark:text-zinc-300">
|
|
301
|
-
<li className="flex items-center gap-2">
|
|
302
|
-
<CheckCircle2 className="h-4 w-4 shrink-0 text-green-500" />
|
|
303
|
-
Unlimited projects
|
|
304
|
-
</li>
|
|
305
|
-
<li className="flex items-center gap-2">
|
|
306
|
-
<CheckCircle2 className="h-4 w-4 shrink-0 text-green-500" />
|
|
307
|
-
Priority support
|
|
308
|
-
</li>
|
|
309
|
-
<li className="flex items-center gap-2">
|
|
310
|
-
<CheckCircle2 className="h-4 w-4 shrink-0 text-green-500" />
|
|
311
|
-
Advanced analytics
|
|
312
|
-
</li>
|
|
313
|
-
</ul>
|
|
314
|
-
</CardContent>
|
|
315
|
-
<CardFooter className="mt-auto">
|
|
316
|
-
<Button size="sm" className="w-full">Get started</Button>
|
|
317
|
-
</CardFooter>
|
|
318
|
-
</Card>
|
|
319
|
-
</DocsSubsection>
|
|
320
|
-
|
|
321
|
-
<DocsSubsection title="Team Card">
|
|
322
|
-
<Card className="flex h-full max-w-sm flex-col">
|
|
323
|
-
<CardHeader>
|
|
324
|
-
<div className="flex items-center gap-3">
|
|
325
|
-
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-zinc-900 text-white dark:bg-zinc-100 dark:text-zinc-900">
|
|
326
|
-
<Users className="h-5 w-5" />
|
|
327
|
-
</div>
|
|
328
|
-
<div>
|
|
329
|
-
<CardTitle>Design Team</CardTitle>
|
|
330
|
-
<CardDescription>5 members · 3 active now</CardDescription>
|
|
331
|
-
</div>
|
|
332
|
-
</div>
|
|
333
|
-
</CardHeader>
|
|
334
|
-
<CardContent>
|
|
335
|
-
<div className="flex -space-x-2">
|
|
336
|
-
{["ZK", "AM", "JR", "LS", "PN"].map((initials) => (
|
|
337
|
-
<div
|
|
338
|
-
key={initials}
|
|
339
|
-
className="flex h-8 w-8 items-center justify-center rounded-full border-2 border-white bg-zinc-200 text-[10px] font-semibold text-zinc-700 dark:border-zinc-900 dark:bg-zinc-700 dark:text-zinc-200"
|
|
340
|
-
>
|
|
341
|
-
{initials}
|
|
342
|
-
</div>
|
|
343
|
-
))}
|
|
344
|
-
</div>
|
|
345
|
-
<p className="mt-4 text-sm leading-relaxed text-zinc-600 dark:text-zinc-300">
|
|
346
|
-
Collaborate on UI components, design tokens, and documentation.
|
|
347
|
-
</p>
|
|
348
|
-
</CardContent>
|
|
349
|
-
<CardFooter className="mt-auto">
|
|
350
|
-
<Button variant="ghost" size="sm">Manage team</Button>
|
|
351
|
-
</CardFooter>
|
|
352
|
-
</Card>
|
|
353
|
-
</DocsSubsection>
|
|
354
|
-
</DocsSectionGrid>
|
|
355
|
-
</DocsSection>
|
|
356
|
-
|
|
357
|
-
<DocsApiSection>
|
|
358
|
-
<DocsApiTable title="API Reference — Card" rows={API_ROWS} />
|
|
359
|
-
<DocsSimpleTable title="Subcomponents" rows={SUBCOMPONENT_ROWS} />
|
|
360
|
-
<DocsAccessibility items={ACCESSIBILITY_ITEMS} />
|
|
361
|
-
</DocsApiSection>
|
|
362
|
-
</DocsPage>
|
|
363
|
-
);
|
|
364
|
-
}
|
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import React, { useState } from "react";
|
|
4
|
-
import { Check, Copy, SquareCheck } from "lucide-react";
|
|
5
|
-
import { Checkbox } from "@/components/ui/checkbox";
|
|
6
|
-
import { Tooltip } from "@/components/ui/tooltip";
|
|
7
|
-
import {
|
|
8
|
-
DocsAccessibility,
|
|
9
|
-
DocsApiSection,
|
|
10
|
-
DocsApiTable,
|
|
11
|
-
DocsPage,
|
|
12
|
-
DocsPageHeader,
|
|
13
|
-
DocsSection,
|
|
14
|
-
DocsSectionGrid,
|
|
15
|
-
DocsSubsection,
|
|
16
|
-
} from "@/components/docs/docs-page";
|
|
17
|
-
import { cn } from "@/lib/cn";
|
|
18
|
-
|
|
19
|
-
const API_ROWS = [
|
|
20
|
-
{ prop: "checked", type: "boolean", default: "false", description: "Controlled checked state" },
|
|
21
|
-
{ prop: "defaultChecked", type: "boolean", default: "false", description: "Uncontrolled initial checked state" },
|
|
22
|
-
{ prop: "onChange", type: "(event) => void", default: "—", description: "Change event handler" },
|
|
23
|
-
{ prop: "disabled", type: "boolean", default: "false", description: "Disables the checkbox" },
|
|
24
|
-
{ prop: "size", type: '"sm" | "md" | "lg"', default: '"md"', description: "The size of the checkbox" },
|
|
25
|
-
{ prop: "variant", type: '"inline" | "card"', default: '"inline"', description: "Layout style — card auto-applies when description is set" },
|
|
26
|
-
{ prop: "label", type: "string", default: "—", description: "Label text displayed beside the checkbox" },
|
|
27
|
-
{ prop: "description", type: "string", default: "—", description: "Helper text below the label" },
|
|
28
|
-
{ prop: "className", type: "string", default: "—", description: "Additional CSS classes" },
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
const ACCESSIBILITY_ITEMS = [
|
|
32
|
-
"Always pair checkboxes with a visible label.",
|
|
33
|
-
"Use fieldset and legend for groups of related checkboxes.",
|
|
34
|
-
"Ensure focus states are clearly visible.",
|
|
35
|
-
"Don't rely on color alone to indicate checked state.",
|
|
36
|
-
"Support keyboard interaction with Space to toggle.",
|
|
37
|
-
];
|
|
38
|
-
|
|
39
|
-
type Size = "sm" | "md" | "lg";
|
|
40
|
-
type Variant = "inline" | "card";
|
|
41
|
-
|
|
42
|
-
const SIZES: Size[] = ["sm", "md", "lg"];
|
|
43
|
-
|
|
44
|
-
const VARIANTS: { value: Variant; label: string }[] = [
|
|
45
|
-
{ value: "inline", label: "Inline" },
|
|
46
|
-
{ value: "card", label: "Card" },
|
|
47
|
-
];
|
|
48
|
-
|
|
49
|
-
function codeFor(variant: Variant, size: Size, disabled: boolean, checked: boolean) {
|
|
50
|
-
const props = [
|
|
51
|
-
size !== "md" && `size="${size}"`,
|
|
52
|
-
variant !== "inline" && `variant="${variant}"`,
|
|
53
|
-
checked && "defaultChecked",
|
|
54
|
-
disabled && "disabled",
|
|
55
|
-
]
|
|
56
|
-
.filter(Boolean)
|
|
57
|
-
.join(" ");
|
|
58
|
-
const descriptionLine = variant === "card" ? '\n description="A helper line of detail."' : "";
|
|
59
|
-
const labelLine = `\n label="Accept terms"`;
|
|
60
|
-
return `<Checkbox${labelLine}${descriptionLine}${props ? `\n ${props}` : ""}\n/>`;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function CheckboxDocPage() {
|
|
64
|
-
const [notifications, setNotifications] = React.useState({
|
|
65
|
-
email: true,
|
|
66
|
-
sms: false,
|
|
67
|
-
push: true,
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
const [variant, setVariant] = useState<Variant>("inline");
|
|
71
|
-
const [size, setSize] = useState<Size>("md");
|
|
72
|
-
const [disabled, setDisabled] = useState(false);
|
|
73
|
-
const [checked, setChecked] = useState(true);
|
|
74
|
-
const [copied, setCopied] = useState(false);
|
|
75
|
-
|
|
76
|
-
const snippet = codeFor(variant, size, disabled, checked);
|
|
77
|
-
|
|
78
|
-
function copySnippet() {
|
|
79
|
-
navigator.clipboard.writeText(snippet).catch(() => {});
|
|
80
|
-
setCopied(true);
|
|
81
|
-
setTimeout(() => setCopied(false), 1200);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return (
|
|
85
|
-
<DocsPage>
|
|
86
|
-
<DocsPageHeader
|
|
87
|
-
icon={SquareCheck}
|
|
88
|
-
title="Checkbox"
|
|
89
|
-
description="Allows users to select one or more options from a set of choices."
|
|
90
|
-
/>
|
|
91
|
-
|
|
92
|
-
<DocsSection
|
|
93
|
-
first
|
|
94
|
-
title="Playground"
|
|
95
|
-
description="Build a checkbox and copy the exact markup — every combination, live."
|
|
96
|
-
>
|
|
97
|
-
<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)]">
|
|
98
|
-
<div className="relative flex min-h-[11rem] items-center justify-center overflow-hidden bg-zinc-50 p-8 dark:bg-zinc-900/40">
|
|
99
|
-
<div
|
|
100
|
-
aria-hidden
|
|
101
|
-
className="pointer-events-none absolute inset-0 opacity-[0.4] dark:opacity-[0.15]"
|
|
102
|
-
style={{
|
|
103
|
-
backgroundImage:
|
|
104
|
-
"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)",
|
|
105
|
-
backgroundSize: "24px 24px",
|
|
106
|
-
}}
|
|
107
|
-
/>
|
|
108
|
-
<div className="relative w-full max-w-xs" key={`${variant}-${size}-${disabled}-${checked}`}>
|
|
109
|
-
<Checkbox
|
|
110
|
-
variant={variant}
|
|
111
|
-
size={size}
|
|
112
|
-
disabled={disabled}
|
|
113
|
-
checked={checked}
|
|
114
|
-
onChange={(e) => setChecked(e.target.checked)}
|
|
115
|
-
label="Accept terms"
|
|
116
|
-
description={variant === "card" ? "A helper line of detail." : undefined}
|
|
117
|
-
className="items-center animate-[pagination-pop_0.25s_ease-out]"
|
|
118
|
-
/>
|
|
119
|
-
</div>
|
|
120
|
-
</div>
|
|
121
|
-
|
|
122
|
-
<div className="flex flex-col gap-5 border-t border-zinc-200 p-5 dark:border-zinc-800">
|
|
123
|
-
<div className="flex flex-wrap items-start justify-between gap-6">
|
|
124
|
-
<div>
|
|
125
|
-
<p className="mb-2 text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
|
|
126
|
-
Variant
|
|
127
|
-
</p>
|
|
128
|
-
<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">
|
|
129
|
-
{VARIANTS.map((v) => (
|
|
130
|
-
<button
|
|
131
|
-
key={v.value}
|
|
132
|
-
type="button"
|
|
133
|
-
onClick={() => setVariant(v.value)}
|
|
134
|
-
className={cn(
|
|
135
|
-
"rounded-md px-3 py-1.5 text-xs font-medium transition-colors",
|
|
136
|
-
variant === v.value
|
|
137
|
-
? "bg-white text-zinc-900 shadow-sm dark:bg-zinc-800 dark:text-white"
|
|
138
|
-
: "text-zinc-500 hover:text-zinc-800 dark:text-zinc-400 dark:hover:text-zinc-200"
|
|
139
|
-
)}
|
|
140
|
-
>
|
|
141
|
-
{v.label}
|
|
142
|
-
</button>
|
|
143
|
-
))}
|
|
144
|
-
</div>
|
|
145
|
-
</div>
|
|
146
|
-
|
|
147
|
-
<div>
|
|
148
|
-
<p className="mb-2 text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
|
|
149
|
-
Size
|
|
150
|
-
</p>
|
|
151
|
-
<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">
|
|
152
|
-
{SIZES.map((s) => (
|
|
153
|
-
<button
|
|
154
|
-
key={s}
|
|
155
|
-
type="button"
|
|
156
|
-
onClick={() => setSize(s)}
|
|
157
|
-
className={cn(
|
|
158
|
-
"rounded-md px-3 py-1.5 text-xs font-medium uppercase tracking-wide transition-colors",
|
|
159
|
-
size === s
|
|
160
|
-
? "bg-white text-zinc-900 shadow-sm dark:bg-zinc-800 dark:text-white"
|
|
161
|
-
: "text-zinc-500 hover:text-zinc-800 dark:text-zinc-400 dark:hover:text-zinc-200"
|
|
162
|
-
)}
|
|
163
|
-
>
|
|
164
|
-
{s}
|
|
165
|
-
</button>
|
|
166
|
-
))}
|
|
167
|
-
</div>
|
|
168
|
-
</div>
|
|
169
|
-
|
|
170
|
-
<div>
|
|
171
|
-
<p className="mb-2 text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
|
|
172
|
-
State
|
|
173
|
-
</p>
|
|
174
|
-
<button
|
|
175
|
-
type="button"
|
|
176
|
-
onClick={() => setDisabled((v) => !v)}
|
|
177
|
-
className={cn(
|
|
178
|
-
"flex h-[2.125rem] items-center gap-2 rounded-lg border px-3 text-xs font-medium transition-colors",
|
|
179
|
-
disabled
|
|
180
|
-
? "border-zinc-900 bg-zinc-900 text-white dark:border-white dark:bg-white dark:text-zinc-900"
|
|
181
|
-
: "border-zinc-200 text-zinc-500 hover:border-zinc-300 dark:border-zinc-700 dark:text-zinc-400"
|
|
182
|
-
)}
|
|
183
|
-
>
|
|
184
|
-
<SquareCheck className="h-3.5 w-3.5" />
|
|
185
|
-
{disabled ? "Disabled" : "Enabled"}
|
|
186
|
-
</button>
|
|
187
|
-
</div>
|
|
188
|
-
</div>
|
|
189
|
-
|
|
190
|
-
<div className="flex items-center justify-between gap-3 rounded-xl bg-zinc-900 px-4 py-3 dark:bg-black">
|
|
191
|
-
<pre className="overflow-x-auto font-mono text-[13px] leading-relaxed text-zinc-100">
|
|
192
|
-
<code>{snippet}</code>
|
|
193
|
-
</pre>
|
|
194
|
-
<Tooltip content={copied ? "Copied!" : "Copy code"}>
|
|
195
|
-
<button
|
|
196
|
-
type="button"
|
|
197
|
-
onClick={copySnippet}
|
|
198
|
-
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"
|
|
199
|
-
>
|
|
200
|
-
{copied ? <Check className="h-4 w-4 text-emerald-400" /> : <Copy className="h-4 w-4" />}
|
|
201
|
-
</button>
|
|
202
|
-
</Tooltip>
|
|
203
|
-
</div>
|
|
204
|
-
</div>
|
|
205
|
-
</div>
|
|
206
|
-
</DocsSection>
|
|
207
|
-
|
|
208
|
-
<DocsSection>
|
|
209
|
-
<DocsSectionGrid>
|
|
210
|
-
<DocsSubsection title="Sizes">
|
|
211
|
-
<div className="flex flex-col gap-2.5">
|
|
212
|
-
<Checkbox size="sm" label="Small" defaultChecked />
|
|
213
|
-
<Checkbox size="md" label="Medium" defaultChecked />
|
|
214
|
-
<Checkbox size="lg" label="Large" defaultChecked />
|
|
215
|
-
</div>
|
|
216
|
-
</DocsSubsection>
|
|
217
|
-
<DocsSubsection title="Disabled">
|
|
218
|
-
<div className="flex flex-col gap-2.5">
|
|
219
|
-
<Checkbox label="Disabled unchecked" disabled />
|
|
220
|
-
<Checkbox label="Disabled checked" defaultChecked disabled />
|
|
221
|
-
</div>
|
|
222
|
-
</DocsSubsection>
|
|
223
|
-
</DocsSectionGrid>
|
|
224
|
-
</DocsSection>
|
|
225
|
-
|
|
226
|
-
<DocsSection
|
|
227
|
-
title="With Description"
|
|
228
|
-
description="Card layout automatically applies for options with helper text."
|
|
229
|
-
>
|
|
230
|
-
<Checkbox
|
|
231
|
-
label="Accept terms and conditions"
|
|
232
|
-
description="You agree to our Terms of Service and Privacy Policy."
|
|
233
|
-
/>
|
|
234
|
-
</DocsSection>
|
|
235
|
-
|
|
236
|
-
<DocsSection
|
|
237
|
-
title="Notification Preferences"
|
|
238
|
-
description="Card-style checkboxes make multi-option settings easy to scan and tap."
|
|
239
|
-
>
|
|
240
|
-
<div className="flex max-w-md flex-col gap-2.5">
|
|
241
|
-
<Checkbox
|
|
242
|
-
variant="card"
|
|
243
|
-
label="Email notifications"
|
|
244
|
-
description="Receive updates and alerts in your inbox."
|
|
245
|
-
checked={notifications.email}
|
|
246
|
-
onChange={(e) =>
|
|
247
|
-
setNotifications((prev) => ({ ...prev, email: e.target.checked }))
|
|
248
|
-
}
|
|
249
|
-
/>
|
|
250
|
-
<Checkbox
|
|
251
|
-
variant="card"
|
|
252
|
-
label="SMS notifications"
|
|
253
|
-
description="Get text messages for urgent updates."
|
|
254
|
-
checked={notifications.sms}
|
|
255
|
-
onChange={(e) =>
|
|
256
|
-
setNotifications((prev) => ({ ...prev, sms: e.target.checked }))
|
|
257
|
-
}
|
|
258
|
-
/>
|
|
259
|
-
<Checkbox
|
|
260
|
-
variant="card"
|
|
261
|
-
label="Push notifications"
|
|
262
|
-
description="Instant alerts delivered to your device."
|
|
263
|
-
checked={notifications.push}
|
|
264
|
-
onChange={(e) =>
|
|
265
|
-
setNotifications((prev) => ({ ...prev, push: e.target.checked }))
|
|
266
|
-
}
|
|
267
|
-
/>
|
|
268
|
-
</div>
|
|
269
|
-
</DocsSection>
|
|
270
|
-
|
|
271
|
-
<DocsApiSection>
|
|
272
|
-
<DocsApiTable title="API Reference" rows={API_ROWS} />
|
|
273
|
-
<DocsAccessibility items={ACCESSIBILITY_ITEMS} />
|
|
274
|
-
</DocsApiSection>
|
|
275
|
-
</DocsPage>
|
|
276
|
-
);
|
|
277
|
-
}
|