ruler-components 0.1.0
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/AGENTS.md +9 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +21 -0
- package/README.md +45 -0
- package/app/docs/[slug]/page.tsx +147 -0
- package/app/docs/layout.tsx +26 -0
- package/app/docs/page.tsx +148 -0
- package/app/favicon.ico +0 -0
- package/app/globals.css +168 -0
- package/app/icon.png +0 -0
- package/app/layout.tsx +90 -0
- package/app/opengraph-image.tsx +10 -0
- package/app/page.tsx +34 -0
- package/app/twitter-image.tsx +10 -0
- package/components/docs/accordion-doc-page.tsx +352 -0
- package/components/docs/alert-doc-page.tsx +293 -0
- package/components/docs/allinput-doc-page.tsx +183 -0
- package/components/docs/avatar-doc-page.tsx +424 -0
- package/components/docs/badge-doc-page.tsx +363 -0
- package/components/docs/button-doc-page.tsx +406 -0
- package/components/docs/card-doc-page.tsx +364 -0
- package/components/docs/checkbox-doc-page.tsx +277 -0
- package/components/docs/colors-doc-page.tsx +430 -0
- package/components/docs/dialog-doc-page.tsx +364 -0
- package/components/docs/docs-footer.tsx +11 -0
- package/components/docs/docs-mobile-menu-bar.tsx +22 -0
- package/components/docs/docs-mobile-nav-context.tsx +27 -0
- package/components/docs/docs-page.tsx +263 -0
- package/components/docs/docs-search.tsx +303 -0
- package/components/docs/docs-sidebar.tsx +165 -0
- package/components/docs/docs-topbar.tsx +32 -0
- package/components/docs/dropdown-doc-page.tsx +522 -0
- package/components/docs/getting-started-doc-page.tsx +205 -0
- package/components/docs/label-doc-page.tsx +173 -0
- package/components/docs/loaders-doc-page.tsx +244 -0
- package/components/docs/menu-doc-page.tsx +373 -0
- package/components/docs/modal-doc-page.tsx +436 -0
- package/components/docs/next-steps.tsx +53 -0
- package/components/docs/pagination-doc-page.tsx +316 -0
- package/components/docs/progress-doc-page.tsx +387 -0
- package/components/docs/radio-doc-page.tsx +270 -0
- package/components/docs/skeleton-doc-page.tsx +230 -0
- package/components/docs/stepper-doc-page.tsx +309 -0
- package/components/docs/switch-doc-page.tsx +264 -0
- package/components/docs/table-doc-page.tsx +689 -0
- package/components/docs/tabs-doc-page.tsx +359 -0
- package/components/docs/theming-doc-page.tsx +243 -0
- package/components/docs/tooltip-doc-page.tsx +357 -0
- package/components/docs/usage-section.tsx +21 -0
- package/components/icons/discord.tsx +9 -0
- package/components/icons/github.tsx +9 -0
- package/components/icons/x.tsx +9 -0
- package/components/installation-section.tsx +34 -0
- package/components/landing/feature-highlights.tsx +105 -0
- package/components/landing/footer-strip.tsx +45 -0
- package/components/landing/hero-card.tsx +14 -0
- package/components/landing/hero-spotlight.tsx +126 -0
- package/components/landing/hero.tsx +64 -0
- package/components/landing/navbar.tsx +44 -0
- package/components/landing/quick-start-section.tsx +59 -0
- package/components/landing/site-footer.tsx +55 -0
- package/components/theme-provider.tsx +60 -0
- package/components/ui/accordion.tsx +174 -0
- package/components/ui/alert.tsx +103 -0
- package/components/ui/allinput.tsx +210 -0
- package/components/ui/avatar.tsx +179 -0
- package/components/ui/badge.tsx +52 -0
- package/components/ui/button.tsx +75 -0
- package/components/ui/card.tsx +105 -0
- package/components/ui/checkbox.tsx +130 -0
- package/components/ui/code-block.tsx +60 -0
- package/components/ui/data-table.tsx +235 -0
- package/components/ui/dialog.tsx +173 -0
- package/components/ui/dropdown.tsx +78 -0
- package/components/ui/feature-card.tsx +38 -0
- package/components/ui/input.tsx +44 -0
- package/components/ui/label.tsx +110 -0
- package/components/ui/loaders.tsx +139 -0
- package/components/ui/menu.tsx +118 -0
- package/components/ui/modal.tsx +399 -0
- package/components/ui/package-manager-tabs.tsx +40 -0
- package/components/ui/pagination.tsx +200 -0
- package/components/ui/progress.tsx +134 -0
- package/components/ui/radio.tsx +262 -0
- package/components/ui/skeleton.tsx +102 -0
- package/components/ui/steppers.tsx +309 -0
- package/components/ui/switch.tsx +153 -0
- package/components/ui/table.tsx +58 -0
- package/components/ui/tabs.tsx +166 -0
- package/components/ui/theme-toggle.tsx +60 -0
- package/components/ui/tooltip.tsx +238 -0
- package/data/color-palette.ts +35 -0
- package/data/docs-nav.ts +84 -0
- package/eslint.config.mjs +18 -0
- package/index.ts +8 -0
- package/lib/cn.ts +4 -0
- package/lib/color.ts +85 -0
- package/lib/og-image.tsx +138 -0
- package/lib/theme.ts +33 -0
- package/next.config.ts +7 -0
- package/package.json +30 -0
- package/postcss.config.mjs +7 -0
- package/public/dark.png +0 -0
- package/public/dark1.png +0 -0
- package/public/dark2.png +0 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/light.png +0 -0
- package/public/light1.png +0 -0
- package/public/next.svg +1 -0
- package/public/vercel.svg +1 -0
- package/public/video/hero-demo.mp4 +0 -0
- package/public/window.svg +1 -0
- package/tsconfig.json +34 -0
package/app/page.tsx
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { HeroCard } from "@/components/landing/hero-card";
|
|
2
|
+
import { FeatureHighlights } from "@/components/landing/feature-highlights";
|
|
3
|
+
import { InstallationSection } from "@/components/installation-section";
|
|
4
|
+
import { QuickStartSection } from "@/components/landing/quick-start-section";
|
|
5
|
+
import { FooterStrip } from "@/components/landing/footer-strip";
|
|
6
|
+
import { SiteFooter } from "@/components/landing/site-footer";
|
|
7
|
+
|
|
8
|
+
export default function Home() {
|
|
9
|
+
return (
|
|
10
|
+
<main className="min-w-0 overflow-x-clip bg-white dark:bg-zinc-950">
|
|
11
|
+
<div className="px-3 pt-3 sm:px-6 sm:pt-4 lg:px-8 xl:px-12">
|
|
12
|
+
<HeroCard />
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<FeatureHighlights />
|
|
16
|
+
|
|
17
|
+
<div className="mx-auto max-w-7xl px-6 sm:px-8 lg:px-10 xl:px-12">
|
|
18
|
+
<div className="py-10 sm:py-14">
|
|
19
|
+
<div className="rounded-3xl border border-zinc-200/70 bg-gradient-to-b from-zinc-50/80 to-white p-5 shadow-[0_2px_8px_rgba(0,0,0,0.04)] dark:border-zinc-800/70 dark:from-zinc-900/30 dark:to-zinc-950 dark:shadow-[0_2px_8px_rgba(0,0,0,0.2)] sm:p-12">
|
|
20
|
+
<InstallationSection
|
|
21
|
+
caption="ruler.ui is built with TypeScript and works with React 18+."
|
|
22
|
+
/>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
<QuickStartSection />
|
|
26
|
+
<FooterStrip />
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<div className="mx-auto max-w-7xl px-6 sm:px-8 lg:px-10 xl:px-12">
|
|
30
|
+
<SiteFooter />
|
|
31
|
+
</div>
|
|
32
|
+
</main>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createOgImage, ogAlt, ogSize } from "@/lib/og-image";
|
|
2
|
+
|
|
3
|
+
export const runtime = "nodejs";
|
|
4
|
+
export const alt = ogAlt;
|
|
5
|
+
export const size = ogSize;
|
|
6
|
+
export const contentType = "image/png";
|
|
7
|
+
|
|
8
|
+
export default async function Image() {
|
|
9
|
+
return createOgImage();
|
|
10
|
+
}
|
|
@@ -0,0 +1,352 @@
|
|
|
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
|
+
}
|