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,352 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useState } from "react";
|
|
4
|
-
import { Check, ChevronsUpDown, Copy, HelpCircle, PanelLeft, Truck } from "lucide-react";
|
|
5
|
-
import { Accordion, AccordionItem, AccordionNested, AccordionLink } from "@/components/ui/accordion";
|
|
6
|
-
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/ui/card";
|
|
7
|
-
import { Badge } from "@/components/ui/badge";
|
|
8
|
-
import { Tooltip } from "@/components/ui/tooltip";
|
|
9
|
-
import {
|
|
10
|
-
DocsAccessibility,
|
|
11
|
-
DocsApiSection,
|
|
12
|
-
DocsApiTable,
|
|
13
|
-
DocsPage,
|
|
14
|
-
DocsPageHeader,
|
|
15
|
-
DocsSection,
|
|
16
|
-
} from "@/components/docs/docs-page";
|
|
17
|
-
import { cn } from "@/lib/cn";
|
|
18
|
-
|
|
19
|
-
const ACCORDION_API_ROWS = [
|
|
20
|
-
{ prop: "children", type: "ReactNode", default: "—", description: "One or more AccordionItem elements" },
|
|
21
|
-
{ prop: "defaultValue", type: "string | null", default: "null", description: "Value of the item expanded on mount" },
|
|
22
|
-
{ prop: "className", type: "string", default: "—", description: "Additional CSS classes for the wrapper" },
|
|
23
|
-
];
|
|
24
|
-
|
|
25
|
-
const ITEM_API_ROWS = [
|
|
26
|
-
{ prop: "value", type: "string", default: "—", description: "Unique identifier used to track open state" },
|
|
27
|
-
{ prop: "title", type: "string", default: "—", description: "Text shown in the trigger row" },
|
|
28
|
-
{ prop: "children", type: "ReactNode", default: "—", description: "Panel content revealed when open" },
|
|
29
|
-
{ prop: "variant", type: '"plus" | "chevron"', default: '"plus"', description: "Icon and trigger style" },
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
const NESTED_API_ROWS = [
|
|
33
|
-
{ prop: "title", type: "string", default: "—", description: "Label for the branch node" },
|
|
34
|
-
{ prop: "children", type: "ReactNode", default: "—", description: "Nested AccordionNested / AccordionLink items" },
|
|
35
|
-
{ prop: "level", type: "number", default: "0", description: "Indentation depth — increment for each nested level" },
|
|
36
|
-
];
|
|
37
|
-
|
|
38
|
-
const LINK_API_ROWS = [
|
|
39
|
-
{ prop: "title", type: "string", default: "—", description: "Label for the leaf navigation item" },
|
|
40
|
-
{ prop: "level", type: "number", default: "0", description: "Indentation depth — match the parent's level + 1" },
|
|
41
|
-
];
|
|
42
|
-
|
|
43
|
-
const ACCESSIBILITY_ITEMS = [
|
|
44
|
-
"Every trigger renders as a native <button>, so it's reachable and activatable via keyboard by default.",
|
|
45
|
-
"aria-expanded reflects open state and aria-controls links each trigger to its panel for screen readers.",
|
|
46
|
-
"Panels animate by measuring scrollHeight rather than toggling display, so content never clips mid-transition.",
|
|
47
|
-
"Only one item stays open at a time within an Accordion — keeps focus narrow for FAQ-style content.",
|
|
48
|
-
"Nested menus support arbitrary depth via the level prop and indent children automatically.",
|
|
49
|
-
];
|
|
50
|
-
|
|
51
|
-
const FAQ = [
|
|
52
|
-
{
|
|
53
|
-
value: "1",
|
|
54
|
-
title: "Can I change my plan later?",
|
|
55
|
-
answer: "Yes — upgrade or downgrade at any time from your billing settings. Changes are prorated automatically.",
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
value: "2",
|
|
59
|
-
title: "Do you offer a free trial?",
|
|
60
|
-
answer: "Every plan includes a 14-day trial with full feature access, no credit card required.",
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
value: "3",
|
|
64
|
-
title: "Is my data encrypted?",
|
|
65
|
-
answer: "All data is encrypted in transit with TLS 1.3 and at rest with AES-256, on every plan.",
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
value: "4",
|
|
69
|
-
title: "What happens if I cancel?",
|
|
70
|
-
answer: "Your workspace stays active until the end of the current billing period, then moves to the free tier automatically.",
|
|
71
|
-
},
|
|
72
|
-
];
|
|
73
|
-
|
|
74
|
-
type PlaygroundVariant = "plus" | "chevron";
|
|
75
|
-
|
|
76
|
-
const PLAYGROUND_VARIANTS: { value: PlaygroundVariant; label: string }[] = [
|
|
77
|
-
{ value: "plus", label: "Plus" },
|
|
78
|
-
{ value: "chevron", label: "Chevron" },
|
|
79
|
-
];
|
|
80
|
-
|
|
81
|
-
const ITEM_COUNTS = [2, 3] as const;
|
|
82
|
-
|
|
83
|
-
function codeFor(variant: PlaygroundVariant, itemCount: (typeof ITEM_COUNTS)[number], defaultOpen: boolean) {
|
|
84
|
-
const items = FAQ.slice(0, itemCount);
|
|
85
|
-
const props = [variant !== "plus" && `variant="${variant}"`].filter(Boolean).join(" ");
|
|
86
|
-
const openProp = defaultOpen ? ` defaultValue="${items[0].value}"` : "";
|
|
87
|
-
const children = items
|
|
88
|
-
.map((item) => {
|
|
89
|
-
const itemProps = [`value="${item.value}"`, `title="${item.title}"`, props].filter(Boolean).join(" ");
|
|
90
|
-
return ` <AccordionItem ${itemProps}>\n ${item.answer}\n </AccordionItem>`;
|
|
91
|
-
})
|
|
92
|
-
.join("\n");
|
|
93
|
-
return `<Accordion${openProp}>\n${children}\n</Accordion>`;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export function AccordionDocPage() {
|
|
97
|
-
const [variant, setVariant] = useState<"plus" | "chevron">("plus");
|
|
98
|
-
const [playgroundVariant, setPlaygroundVariant] = useState<PlaygroundVariant>("plus");
|
|
99
|
-
const [itemCount, setItemCount] = useState<(typeof ITEM_COUNTS)[number]>(3);
|
|
100
|
-
const [defaultOpen, setDefaultOpen] = useState(true);
|
|
101
|
-
const [copied, setCopied] = useState(false);
|
|
102
|
-
|
|
103
|
-
const snippet = codeFor(playgroundVariant, itemCount, defaultOpen);
|
|
104
|
-
const playgroundItems = FAQ.slice(0, itemCount);
|
|
105
|
-
|
|
106
|
-
function copySnippet() {
|
|
107
|
-
navigator.clipboard.writeText(snippet).catch(() => {});
|
|
108
|
-
setCopied(true);
|
|
109
|
-
setTimeout(() => setCopied(false), 1200);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return (
|
|
113
|
-
<DocsPage>
|
|
114
|
-
<DocsPageHeader
|
|
115
|
-
icon={ChevronsUpDown}
|
|
116
|
-
title="Accordion"
|
|
117
|
-
description="A vertically stacked list of items that can be expanded or collapsed to reveal more content."
|
|
118
|
-
/>
|
|
119
|
-
|
|
120
|
-
<DocsSection
|
|
121
|
-
first
|
|
122
|
-
title="Playground"
|
|
123
|
-
description="Pick a trigger style and item count, then copy the exact markup — live."
|
|
124
|
-
>
|
|
125
|
-
<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)]">
|
|
126
|
-
<div className="relative flex min-h-[11rem] items-center justify-center overflow-hidden bg-zinc-50 p-6 dark:bg-zinc-900/40">
|
|
127
|
-
<div
|
|
128
|
-
aria-hidden
|
|
129
|
-
className="pointer-events-none absolute inset-0 opacity-[0.4] dark:opacity-[0.15]"
|
|
130
|
-
style={{
|
|
131
|
-
backgroundImage:
|
|
132
|
-
"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)",
|
|
133
|
-
backgroundSize: "24px 24px",
|
|
134
|
-
}}
|
|
135
|
-
/>
|
|
136
|
-
<div
|
|
137
|
-
key={`${playgroundVariant}-${itemCount}-${defaultOpen}`}
|
|
138
|
-
className="relative w-full max-w-md animate-[pagination-pop_0.2s_ease-out] rounded-xl border border-zinc-200 bg-white px-5 dark:border-zinc-800 dark:bg-zinc-950"
|
|
139
|
-
>
|
|
140
|
-
<Accordion defaultValue={defaultOpen ? playgroundItems[0].value : null}>
|
|
141
|
-
{playgroundItems.map((item) => (
|
|
142
|
-
<AccordionItem key={item.value} value={item.value} title={item.title} variant={playgroundVariant}>
|
|
143
|
-
{item.answer}
|
|
144
|
-
</AccordionItem>
|
|
145
|
-
))}
|
|
146
|
-
</Accordion>
|
|
147
|
-
</div>
|
|
148
|
-
</div>
|
|
149
|
-
|
|
150
|
-
<div className="flex flex-col gap-5 border-t border-zinc-200 p-5 dark:border-zinc-800">
|
|
151
|
-
<div className="flex flex-wrap items-start justify-between gap-6">
|
|
152
|
-
<div>
|
|
153
|
-
<p className="mb-2 text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
|
|
154
|
-
Variant
|
|
155
|
-
</p>
|
|
156
|
-
<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">
|
|
157
|
-
{PLAYGROUND_VARIANTS.map((v) => (
|
|
158
|
-
<button
|
|
159
|
-
key={v.value}
|
|
160
|
-
type="button"
|
|
161
|
-
onClick={() => setPlaygroundVariant(v.value)}
|
|
162
|
-
className={cn(
|
|
163
|
-
"rounded-md px-3 py-1.5 text-xs font-medium transition-colors",
|
|
164
|
-
playgroundVariant === v.value
|
|
165
|
-
? "bg-white text-zinc-900 shadow-sm dark:bg-zinc-800 dark:text-white"
|
|
166
|
-
: "text-zinc-500 hover:text-zinc-800 dark:text-zinc-400 dark:hover:text-zinc-200"
|
|
167
|
-
)}
|
|
168
|
-
>
|
|
169
|
-
{v.label}
|
|
170
|
-
</button>
|
|
171
|
-
))}
|
|
172
|
-
</div>
|
|
173
|
-
</div>
|
|
174
|
-
|
|
175
|
-
<div>
|
|
176
|
-
<p className="mb-2 text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
|
|
177
|
-
Items
|
|
178
|
-
</p>
|
|
179
|
-
<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">
|
|
180
|
-
{ITEM_COUNTS.map((count) => (
|
|
181
|
-
<button
|
|
182
|
-
key={count}
|
|
183
|
-
type="button"
|
|
184
|
-
onClick={() => setItemCount(count)}
|
|
185
|
-
className={cn(
|
|
186
|
-
"rounded-md px-3 py-1.5 text-xs font-medium transition-colors",
|
|
187
|
-
itemCount === count
|
|
188
|
-
? "bg-white text-zinc-900 shadow-sm dark:bg-zinc-800 dark:text-white"
|
|
189
|
-
: "text-zinc-500 hover:text-zinc-800 dark:text-zinc-400 dark:hover:text-zinc-200"
|
|
190
|
-
)}
|
|
191
|
-
>
|
|
192
|
-
{count}
|
|
193
|
-
</button>
|
|
194
|
-
))}
|
|
195
|
-
</div>
|
|
196
|
-
</div>
|
|
197
|
-
|
|
198
|
-
<div>
|
|
199
|
-
<p className="mb-2 text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
|
|
200
|
-
Default open
|
|
201
|
-
</p>
|
|
202
|
-
<button
|
|
203
|
-
type="button"
|
|
204
|
-
onClick={() => setDefaultOpen((v) => !v)}
|
|
205
|
-
className={cn(
|
|
206
|
-
"flex h-[2.125rem] items-center gap-2 rounded-lg border px-3 text-xs font-medium transition-colors",
|
|
207
|
-
defaultOpen
|
|
208
|
-
? "border-zinc-900 bg-zinc-900 text-white dark:border-white dark:bg-white dark:text-zinc-900"
|
|
209
|
-
: "border-zinc-200 text-zinc-500 hover:border-zinc-300 dark:border-zinc-700 dark:text-zinc-400"
|
|
210
|
-
)}
|
|
211
|
-
>
|
|
212
|
-
{defaultOpen ? "On" : "Off"}
|
|
213
|
-
</button>
|
|
214
|
-
</div>
|
|
215
|
-
</div>
|
|
216
|
-
|
|
217
|
-
<div className="flex items-center justify-between gap-3 rounded-xl bg-zinc-900 px-4 py-3 dark:bg-black">
|
|
218
|
-
<pre className="overflow-x-auto font-mono text-[13px] leading-relaxed text-zinc-100">
|
|
219
|
-
<code>{snippet}</code>
|
|
220
|
-
</pre>
|
|
221
|
-
<Tooltip content={copied ? "Copied!" : "Copy code"}>
|
|
222
|
-
<button
|
|
223
|
-
type="button"
|
|
224
|
-
onClick={copySnippet}
|
|
225
|
-
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"
|
|
226
|
-
>
|
|
227
|
-
{copied ? <Check className="h-4 w-4 text-emerald-400" /> : <Copy className="h-4 w-4" />}
|
|
228
|
-
</button>
|
|
229
|
-
</Tooltip>
|
|
230
|
-
</div>
|
|
231
|
-
</div>
|
|
232
|
-
</div>
|
|
233
|
-
</DocsSection>
|
|
234
|
-
|
|
235
|
-
<DocsSection
|
|
236
|
-
title="Try it"
|
|
237
|
-
description="One trigger style, swapped live — pick whichever matches your layout's density."
|
|
238
|
-
>
|
|
239
|
-
<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)]">
|
|
240
|
-
<div className="flex flex-wrap items-center justify-between gap-4 border-b border-zinc-200 bg-zinc-50/70 px-5 py-4 dark:border-zinc-800 dark:bg-zinc-900/40">
|
|
241
|
-
<div className="flex items-center gap-3">
|
|
242
|
-
<span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-zinc-200 bg-white text-zinc-500 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-400">
|
|
243
|
-
<HelpCircle className="h-4 w-4" />
|
|
244
|
-
</span>
|
|
245
|
-
<div>
|
|
246
|
-
<p className="text-sm font-semibold text-zinc-900 dark:text-white">Frequently asked questions</p>
|
|
247
|
-
<p className="text-xs text-zinc-500 dark:text-zinc-400">Billing and account basics.</p>
|
|
248
|
-
</div>
|
|
249
|
-
</div>
|
|
250
|
-
|
|
251
|
-
<div className="flex flex-wrap items-center gap-1 rounded-lg border border-zinc-200 bg-white p-1 dark:border-zinc-700 dark:bg-zinc-950">
|
|
252
|
-
{(["plus", "chevron"] as const).map((v) => (
|
|
253
|
-
<button
|
|
254
|
-
key={v}
|
|
255
|
-
type="button"
|
|
256
|
-
onClick={() => setVariant(v)}
|
|
257
|
-
className={cn(
|
|
258
|
-
"rounded-md px-3 py-1.5 text-xs font-medium capitalize transition-colors",
|
|
259
|
-
variant === v
|
|
260
|
-
? "bg-zinc-900 text-white dark:bg-white dark:text-zinc-900"
|
|
261
|
-
: "text-zinc-500 hover:text-zinc-800 dark:text-zinc-400 dark:hover:text-zinc-200"
|
|
262
|
-
)}
|
|
263
|
-
>
|
|
264
|
-
{v}
|
|
265
|
-
</button>
|
|
266
|
-
))}
|
|
267
|
-
</div>
|
|
268
|
-
</div>
|
|
269
|
-
|
|
270
|
-
<div className="bg-white px-5 dark:bg-zinc-950">
|
|
271
|
-
<Accordion defaultValue="1">
|
|
272
|
-
{FAQ.map((item) => (
|
|
273
|
-
<AccordionItem key={item.value} value={item.value} title={item.title} variant={variant}>
|
|
274
|
-
{item.answer}
|
|
275
|
-
</AccordionItem>
|
|
276
|
-
))}
|
|
277
|
-
</Accordion>
|
|
278
|
-
</div>
|
|
279
|
-
</div>
|
|
280
|
-
</DocsSection>
|
|
281
|
-
|
|
282
|
-
<DocsSection
|
|
283
|
-
title="Hierarchical / Nested"
|
|
284
|
-
description="A menu-like tree with unlimited depth — ideal for sidebar and docs navigation."
|
|
285
|
-
>
|
|
286
|
-
<Card className="max-w-md overflow-hidden p-0">
|
|
287
|
-
<div className="flex items-center gap-2 border-b border-zinc-100 bg-zinc-50/80 px-4 py-3 dark:border-zinc-800 dark:bg-zinc-900/40">
|
|
288
|
-
<PanelLeft className="h-3.5 w-3.5 text-zinc-400 dark:text-zinc-500" />
|
|
289
|
-
<span className="text-xs font-medium text-zinc-500 dark:text-zinc-400">Documentation</span>
|
|
290
|
-
</div>
|
|
291
|
-
<div className="p-3">
|
|
292
|
-
<AccordionNested title="Getting Started">
|
|
293
|
-
<AccordionLink title="Introduction" level={1} />
|
|
294
|
-
<AccordionLink title="Installation" level={1} />
|
|
295
|
-
</AccordionNested>
|
|
296
|
-
<AccordionNested title="Components">
|
|
297
|
-
<AccordionLink title="Button" level={1} />
|
|
298
|
-
<AccordionNested title="Overlays" level={1}>
|
|
299
|
-
<AccordionLink title="Dialog" level={2} />
|
|
300
|
-
<AccordionLink title="Modal" level={2} />
|
|
301
|
-
</AccordionNested>
|
|
302
|
-
</AccordionNested>
|
|
303
|
-
<AccordionLink title="Theming" />
|
|
304
|
-
</div>
|
|
305
|
-
</Card>
|
|
306
|
-
</DocsSection>
|
|
307
|
-
|
|
308
|
-
<DocsSection
|
|
309
|
-
title="In context"
|
|
310
|
-
description="A shipping & returns block, the way it'd actually ship on a product page."
|
|
311
|
-
>
|
|
312
|
-
<Card className="max-w-2xl overflow-hidden p-0">
|
|
313
|
-
<CardHeader className="flex-row items-center gap-3 border-b border-zinc-100 dark:border-zinc-800">
|
|
314
|
-
<span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-zinc-900 text-white dark:bg-white dark:text-zinc-900">
|
|
315
|
-
<Truck className="h-4 w-4" />
|
|
316
|
-
</span>
|
|
317
|
-
<div>
|
|
318
|
-
<CardTitle className="text-base">Shipping & Returns</CardTitle>
|
|
319
|
-
<CardDescription>Everything covered under our standard policy.</CardDescription>
|
|
320
|
-
</div>
|
|
321
|
-
<Badge variant="outline" className="ml-auto">
|
|
322
|
-
Policy v2
|
|
323
|
-
</Badge>
|
|
324
|
-
</CardHeader>
|
|
325
|
-
<CardContent className="pt-2">
|
|
326
|
-
<Accordion defaultValue="ship">
|
|
327
|
-
<AccordionItem value="ship" title="How long does shipping take?">
|
|
328
|
-
Orders ship within 1 business day and arrive in 3–5 business days domestically, or 7–14 days
|
|
329
|
-
internationally.
|
|
330
|
-
</AccordionItem>
|
|
331
|
-
<AccordionItem value="return" title="What's your return policy?">
|
|
332
|
-
Unused items in original packaging can be returned within 30 days for a full refund — no restocking
|
|
333
|
-
fee.
|
|
334
|
-
</AccordionItem>
|
|
335
|
-
<AccordionItem value="warranty" title="Is there a warranty?">
|
|
336
|
-
Every order includes a 1-year limited warranty covering manufacturing defects.
|
|
337
|
-
</AccordionItem>
|
|
338
|
-
</Accordion>
|
|
339
|
-
</CardContent>
|
|
340
|
-
</Card>
|
|
341
|
-
</DocsSection>
|
|
342
|
-
|
|
343
|
-
<DocsApiSection>
|
|
344
|
-
<DocsApiTable title="API Reference — Accordion" rows={ACCORDION_API_ROWS} />
|
|
345
|
-
<DocsApiTable title="API Reference — AccordionItem" rows={ITEM_API_ROWS} />
|
|
346
|
-
<DocsApiTable title="API Reference — AccordionNested" rows={NESTED_API_ROWS} />
|
|
347
|
-
<DocsApiTable title="API Reference — AccordionLink" rows={LINK_API_ROWS} />
|
|
348
|
-
<DocsAccessibility items={ACCESSIBILITY_ITEMS} />
|
|
349
|
-
</DocsApiSection>
|
|
350
|
-
</DocsPage>
|
|
351
|
-
);
|
|
352
|
-
}
|
|
@@ -1,293 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useState } from "react";
|
|
4
|
-
import { Check, Copy, RotateCcw, TriangleAlert } from "lucide-react";
|
|
5
|
-
import { Alert } from "@/components/ui/alert";
|
|
6
|
-
import { Button } from "@/components/ui/button";
|
|
7
|
-
import { Tooltip } from "@/components/ui/tooltip";
|
|
8
|
-
import {
|
|
9
|
-
DocsAccessibility,
|
|
10
|
-
DocsApiSection,
|
|
11
|
-
DocsApiTable,
|
|
12
|
-
DocsPage,
|
|
13
|
-
DocsPageHeader,
|
|
14
|
-
DocsSection,
|
|
15
|
-
DocsSectionGrid,
|
|
16
|
-
} from "@/components/docs/docs-page";
|
|
17
|
-
import { cn } from "@/lib/cn";
|
|
18
|
-
|
|
19
|
-
const API_ROWS = [
|
|
20
|
-
{ prop: "variant", type: '"info" | "success" | "warning" | "error"', default: '"info"', description: "The style variant" },
|
|
21
|
-
{ prop: "title", type: "string", default: "—", description: "The title text" },
|
|
22
|
-
{ prop: "description", type: "string", default: "—", description: "The description text" },
|
|
23
|
-
{ prop: "dismissible", type: "boolean", default: "false", description: "Shows close button" },
|
|
24
|
-
{ prop: "onDismiss", type: "() => void", default: "—", description: "Dismiss callback" },
|
|
25
|
-
{ prop: "action", type: "ReactNode", default: "—", description: "Trailing action, e.g. a button" },
|
|
26
|
-
{ prop: "children", type: "ReactNode", default: "—", description: "Custom content" },
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
const ACCESSIBILITY_ITEMS = [
|
|
30
|
-
"Use appropriate semantic markup.",
|
|
31
|
-
"Important alerts should use an appropriate ARIA role.",
|
|
32
|
-
"Don't rely on color alone to communicate status.",
|
|
33
|
-
"Provide meaningful text for screen readers.",
|
|
34
|
-
"Dismiss buttons should have an accessible label.",
|
|
35
|
-
];
|
|
36
|
-
|
|
37
|
-
type Variant = "info" | "success" | "warning" | "error";
|
|
38
|
-
|
|
39
|
-
const VARIANTS: { value: Variant; label: string; swatch: string }[] = [
|
|
40
|
-
{ value: "info", label: "Info", swatch: "bg-[#0070BA]" },
|
|
41
|
-
{ value: "success", label: "Success", swatch: "bg-[#28A745]" },
|
|
42
|
-
{ value: "warning", label: "Warning", swatch: "bg-[#E58E00]" },
|
|
43
|
-
{ value: "error", label: "Error", swatch: "bg-[#D93025]" },
|
|
44
|
-
];
|
|
45
|
-
|
|
46
|
-
const COPY: Record<Variant, { title: string; description: string }> = {
|
|
47
|
-
info: { title: "Information", description: "This is an informational message for the user." },
|
|
48
|
-
success: { title: "Success", description: "Your changes have been saved successfully." },
|
|
49
|
-
warning: { title: "Warning", description: "This action may affect your existing data." },
|
|
50
|
-
error: { title: "Error", description: "Something went wrong. Please try again." },
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
function codeFor(variant: Variant, dismissible: boolean, withAction: boolean) {
|
|
54
|
-
const { title, description } = COPY[variant];
|
|
55
|
-
const lines = [
|
|
56
|
-
variant !== "info" ? `variant="${variant}"` : null,
|
|
57
|
-
`title="${title}"`,
|
|
58
|
-
`description="${description}"`,
|
|
59
|
-
dismissible ? "dismissible" : null,
|
|
60
|
-
withAction ? "action={<Button size=\"sm\">Action</Button>}" : null,
|
|
61
|
-
].filter(Boolean);
|
|
62
|
-
return `<Alert\n ${lines.join("\n ")}\n/>`;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const ACTION_BUTTON_CLASS =
|
|
66
|
-
"h-7 cursor-pointer whitespace-nowrap border border-zinc-300 px-2 text-[10px] text-zinc-500 transition-colors hover:bg-zinc-100 hover:text-zinc-700 dark:border-zinc-700 dark:text-zinc-300 dark:hover:bg-zinc-800 dark:hover:text-white";
|
|
67
|
-
|
|
68
|
-
const NOTIFICATIONS = [
|
|
69
|
-
{ id: 1, variant: "info" as const, title: "Scheduled maintenance", description: "Search will be briefly unavailable tonight at 2 AM UTC." },
|
|
70
|
-
{ id: 2, variant: "success" as const, title: "Payment received", description: "Your invoice #4471 has been paid in full." },
|
|
71
|
-
{ id: 3, variant: "warning" as const, title: "Storage almost full", description: "You've used 92% of your workspace storage." },
|
|
72
|
-
{ id: 4, variant: "error" as const, title: "Sync failed", description: "3 files couldn't be uploaded. Check your connection." },
|
|
73
|
-
];
|
|
74
|
-
|
|
75
|
-
export function AlertDocPage() {
|
|
76
|
-
const [variant, setVariant] = useState<Variant>("warning");
|
|
77
|
-
const [dismissible, setDismissible] = useState(false);
|
|
78
|
-
const [withAction, setWithAction] = useState(true);
|
|
79
|
-
const [dismissed, setDismissed] = useState(false);
|
|
80
|
-
const [copied, setCopied] = useState(false);
|
|
81
|
-
const [dismissedIds, setDismissedIds] = useState<number[]>([]);
|
|
82
|
-
|
|
83
|
-
const snippet = codeFor(variant, dismissible, withAction);
|
|
84
|
-
const visibleNotifications = NOTIFICATIONS.filter((n) => !dismissedIds.includes(n.id));
|
|
85
|
-
|
|
86
|
-
function copySnippet() {
|
|
87
|
-
navigator.clipboard.writeText(snippet).catch(() => {});
|
|
88
|
-
setCopied(true);
|
|
89
|
-
setTimeout(() => setCopied(false), 1200);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return (
|
|
93
|
-
<DocsPage>
|
|
94
|
-
<DocsPageHeader
|
|
95
|
-
icon={TriangleAlert}
|
|
96
|
-
title="Alert"
|
|
97
|
-
description="Displays a prominent message to inform users about important changes, warnings, or system status."
|
|
98
|
-
/>
|
|
99
|
-
|
|
100
|
-
<DocsSection
|
|
101
|
-
first
|
|
102
|
-
title="Playground"
|
|
103
|
-
description="Every variant, with or without a dismiss button and action — live, with the exact markup to match."
|
|
104
|
-
>
|
|
105
|
-
<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)]">
|
|
106
|
-
<div className="relative flex min-h-[11rem] items-center justify-center overflow-hidden bg-zinc-50 p-6 dark:bg-zinc-900/40">
|
|
107
|
-
<div
|
|
108
|
-
aria-hidden
|
|
109
|
-
className="pointer-events-none absolute inset-0 opacity-[0.4] dark:opacity-[0.15]"
|
|
110
|
-
style={{
|
|
111
|
-
backgroundImage:
|
|
112
|
-
"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)",
|
|
113
|
-
backgroundSize: "24px 24px",
|
|
114
|
-
}}
|
|
115
|
-
/>
|
|
116
|
-
{dismissed ? (
|
|
117
|
-
<button
|
|
118
|
-
type="button"
|
|
119
|
-
onClick={() => setDismissed(false)}
|
|
120
|
-
className="relative flex items-center gap-2 rounded-lg border border-dashed border-zinc-300 px-4 py-2.5 text-sm font-medium text-zinc-500 transition-colors hover:border-zinc-400 hover:text-zinc-700 dark:border-zinc-700 dark:text-zinc-400 dark:hover:border-zinc-600 dark:hover:text-zinc-200"
|
|
121
|
-
>
|
|
122
|
-
<RotateCcw className="h-3.5 w-3.5" />
|
|
123
|
-
Dismissed — show it again
|
|
124
|
-
</button>
|
|
125
|
-
) : (
|
|
126
|
-
<div
|
|
127
|
-
key={`${variant}-${dismissible}-${withAction}`}
|
|
128
|
-
className="relative w-full max-w-md animate-[pagination-pop_0.2s_ease-out]"
|
|
129
|
-
>
|
|
130
|
-
<Alert
|
|
131
|
-
variant={variant}
|
|
132
|
-
title={COPY[variant].title}
|
|
133
|
-
description={COPY[variant].description}
|
|
134
|
-
dismissible={dismissible}
|
|
135
|
-
onDismiss={dismissible ? () => setDismissed(true) : undefined}
|
|
136
|
-
action={withAction ? <Button variant="outline" size="sm" className={ACTION_BUTTON_CLASS}>Action</Button> : undefined}
|
|
137
|
-
/>
|
|
138
|
-
</div>
|
|
139
|
-
)}
|
|
140
|
-
</div>
|
|
141
|
-
|
|
142
|
-
<div className="flex flex-col gap-5 border-t border-zinc-200 p-5 dark:border-zinc-800">
|
|
143
|
-
<div className="flex flex-wrap items-start justify-between gap-6">
|
|
144
|
-
<div>
|
|
145
|
-
<p className="mb-2 text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
|
|
146
|
-
Variant
|
|
147
|
-
</p>
|
|
148
|
-
<div className="flex flex-wrap gap-1.5">
|
|
149
|
-
{VARIANTS.map((v) => (
|
|
150
|
-
<Tooltip key={v.value} content={v.label}>
|
|
151
|
-
<button
|
|
152
|
-
type="button"
|
|
153
|
-
onClick={() => setVariant(v.value)}
|
|
154
|
-
aria-label={v.label}
|
|
155
|
-
className={cn(
|
|
156
|
-
"flex h-8 w-8 items-center justify-center rounded-lg border transition-all",
|
|
157
|
-
variant === v.value
|
|
158
|
-
? "border-zinc-900 ring-2 ring-zinc-900 ring-offset-2 ring-offset-zinc-50 dark:border-white dark:ring-white dark:ring-offset-zinc-900"
|
|
159
|
-
: "border-zinc-200 hover:border-zinc-300 dark:border-zinc-700 dark:hover:border-zinc-600"
|
|
160
|
-
)}
|
|
161
|
-
>
|
|
162
|
-
<span className={cn("h-3.5 w-3.5 rounded-full", v.swatch)} />
|
|
163
|
-
</button>
|
|
164
|
-
</Tooltip>
|
|
165
|
-
))}
|
|
166
|
-
</div>
|
|
167
|
-
</div>
|
|
168
|
-
|
|
169
|
-
<div>
|
|
170
|
-
<p className="mb-2 text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
|
|
171
|
-
Dismissible
|
|
172
|
-
</p>
|
|
173
|
-
<button
|
|
174
|
-
type="button"
|
|
175
|
-
onClick={() => setDismissible((v) => !v)}
|
|
176
|
-
className={cn(
|
|
177
|
-
"flex h-[2.125rem] items-center gap-2 rounded-lg border px-3 text-xs font-medium transition-colors",
|
|
178
|
-
dismissible
|
|
179
|
-
? "border-zinc-900 bg-zinc-900 text-white dark:border-white dark:bg-white dark:text-zinc-900"
|
|
180
|
-
: "border-zinc-200 text-zinc-500 hover:border-zinc-300 dark:border-zinc-700 dark:text-zinc-400"
|
|
181
|
-
)}
|
|
182
|
-
>
|
|
183
|
-
{dismissible ? "On" : "Off"}
|
|
184
|
-
</button>
|
|
185
|
-
</div>
|
|
186
|
-
|
|
187
|
-
<div>
|
|
188
|
-
<p className="mb-2 text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
|
|
189
|
-
Action
|
|
190
|
-
</p>
|
|
191
|
-
<button
|
|
192
|
-
type="button"
|
|
193
|
-
onClick={() => setWithAction((v) => !v)}
|
|
194
|
-
className={cn(
|
|
195
|
-
"flex h-[2.125rem] items-center gap-2 rounded-lg border px-3 text-xs font-medium transition-colors",
|
|
196
|
-
withAction
|
|
197
|
-
? "border-zinc-900 bg-zinc-900 text-white dark:border-white dark:bg-white dark:text-zinc-900"
|
|
198
|
-
: "border-zinc-200 text-zinc-500 hover:border-zinc-300 dark:border-zinc-700 dark:text-zinc-400"
|
|
199
|
-
)}
|
|
200
|
-
>
|
|
201
|
-
{withAction ? "On" : "Off"}
|
|
202
|
-
</button>
|
|
203
|
-
</div>
|
|
204
|
-
</div>
|
|
205
|
-
|
|
206
|
-
<div className="flex items-center justify-between gap-3 rounded-xl bg-zinc-900 px-4 py-3 dark:bg-black">
|
|
207
|
-
<pre className="overflow-x-auto font-mono text-[13px] leading-relaxed text-zinc-100">
|
|
208
|
-
<code>{snippet}</code>
|
|
209
|
-
</pre>
|
|
210
|
-
<Tooltip content={copied ? "Copied!" : "Copy code"}>
|
|
211
|
-
<button
|
|
212
|
-
type="button"
|
|
213
|
-
onClick={copySnippet}
|
|
214
|
-
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"
|
|
215
|
-
>
|
|
216
|
-
{copied ? <Check className="h-4 w-4 text-emerald-400" /> : <Copy className="h-4 w-4" />}
|
|
217
|
-
</button>
|
|
218
|
-
</Tooltip>
|
|
219
|
-
</div>
|
|
220
|
-
</div>
|
|
221
|
-
</div>
|
|
222
|
-
</DocsSection>
|
|
223
|
-
|
|
224
|
-
<DocsSection
|
|
225
|
-
title="In context"
|
|
226
|
-
description="Alerts rarely stand alone — here's how they read inside real UI."
|
|
227
|
-
>
|
|
228
|
-
<DocsSectionGrid className="lg:grid-cols-[1.2fr_1fr]">
|
|
229
|
-
<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)]">
|
|
230
|
-
<div className="flex items-center justify-between border-b border-zinc-200 bg-zinc-50/70 px-4 py-2.5 dark:border-zinc-800 dark:bg-zinc-900/40">
|
|
231
|
-
<p className="text-sm font-semibold text-zinc-900 dark:text-white">Notification center</p>
|
|
232
|
-
{dismissedIds.length > 0 && (
|
|
233
|
-
<button
|
|
234
|
-
type="button"
|
|
235
|
-
onClick={() => setDismissedIds([])}
|
|
236
|
-
className="flex items-center gap-1 text-xs font-medium text-zinc-500 transition-colors hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white"
|
|
237
|
-
>
|
|
238
|
-
<RotateCcw className="h-3 w-3" />
|
|
239
|
-
Restore all
|
|
240
|
-
</button>
|
|
241
|
-
)}
|
|
242
|
-
</div>
|
|
243
|
-
<div className="flex flex-col gap-3 p-4">
|
|
244
|
-
{visibleNotifications.length === 0 ? (
|
|
245
|
-
<p className="py-8 text-center text-sm text-zinc-400 dark:text-zinc-600">
|
|
246
|
-
All caught up — nothing left to review.
|
|
247
|
-
</p>
|
|
248
|
-
) : (
|
|
249
|
-
visibleNotifications.map((n) => (
|
|
250
|
-
<Alert
|
|
251
|
-
key={n.id}
|
|
252
|
-
variant={n.variant}
|
|
253
|
-
title={n.title}
|
|
254
|
-
description={n.description}
|
|
255
|
-
dismissible
|
|
256
|
-
onDismiss={() => setDismissedIds((ids) => [...ids, n.id])}
|
|
257
|
-
/>
|
|
258
|
-
))
|
|
259
|
-
)}
|
|
260
|
-
</div>
|
|
261
|
-
</div>
|
|
262
|
-
|
|
263
|
-
<div className="flex flex-col gap-4">
|
|
264
|
-
<div className="rounded-2xl border border-zinc-200 bg-white p-5 shadow-[0_1px_2px_rgba(0,0,0,0.03)] dark:border-zinc-800 dark:bg-zinc-950">
|
|
265
|
-
<p className="text-sm font-semibold text-zinc-900 dark:text-white">Invite teammates</p>
|
|
266
|
-
<label className="mt-3 block text-xs font-medium text-zinc-500 dark:text-zinc-400">
|
|
267
|
-
Email address
|
|
268
|
-
</label>
|
|
269
|
-
<input
|
|
270
|
-
readOnly
|
|
271
|
-
value="not-an-email"
|
|
272
|
-
className="mt-1.5 w-full rounded-lg border border-red-300 bg-red-50/50 px-3 py-2 text-sm text-zinc-700 outline-none dark:border-red-900/60 dark:bg-red-950/20 dark:text-zinc-200"
|
|
273
|
-
/>
|
|
274
|
-
<div className="mt-2">
|
|
275
|
-
<Alert variant="error" description="Enter a valid email address to continue." />
|
|
276
|
-
</div>
|
|
277
|
-
</div>
|
|
278
|
-
|
|
279
|
-
<div className="rounded-2xl border border-zinc-200 bg-white p-5 shadow-[0_1px_2px_rgba(0,0,0,0.03)] dark:border-zinc-800 dark:bg-zinc-950">
|
|
280
|
-
<p className="mb-3 text-sm font-semibold text-zinc-900 dark:text-white">Plain, no title</p>
|
|
281
|
-
<Alert variant="info" description="This is a simple informational alert without a title." />
|
|
282
|
-
</div>
|
|
283
|
-
</div>
|
|
284
|
-
</DocsSectionGrid>
|
|
285
|
-
</DocsSection>
|
|
286
|
-
|
|
287
|
-
<DocsApiSection>
|
|
288
|
-
<DocsApiTable title="API Reference" rows={API_ROWS} />
|
|
289
|
-
<DocsAccessibility items={ACCESSIBILITY_ITEMS} />
|
|
290
|
-
</DocsApiSection>
|
|
291
|
-
</DocsPage>
|
|
292
|
-
);
|
|
293
|
-
}
|