ruler-components 0.1.1 → 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,359 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import React, { useState } from "react";
|
|
4
|
-
import { Bell, Check, Columns3, Copy, Home, Settings, Star, TrendingUp, Users } from "lucide-react";
|
|
5
|
-
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
|
|
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
|
-
DocsSectionGrid,
|
|
17
|
-
} from "@/components/docs/docs-page";
|
|
18
|
-
import { cn } from "@/lib/cn";
|
|
19
|
-
|
|
20
|
-
const TABS_API_ROWS = [
|
|
21
|
-
{ prop: "children", type: "ReactNode", default: "—", description: "A TabsList and one or more TabsContent panels" },
|
|
22
|
-
{ prop: "defaultValue", type: "string", default: "—", description: "Value of the tab active on mount" },
|
|
23
|
-
{
|
|
24
|
-
prop: "variant",
|
|
25
|
-
type: '"underline" | "pill" | "segmented" | "bordered" | "filled" | "icon" | "vertical" | "floating" | "scrollable" | "card"',
|
|
26
|
-
default: '"underline"',
|
|
27
|
-
description: "Visual style shared by the list and its triggers",
|
|
28
|
-
},
|
|
29
|
-
{ prop: "className", type: "string", default: "—", description: "Additional CSS classes for the root wrapper" },
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
const LIST_API_ROWS = [
|
|
33
|
-
{ prop: "children", type: "ReactNode", default: "—", description: "One or more TabsTrigger elements" },
|
|
34
|
-
{ prop: "className", type: "string", default: "—", description: "Additional CSS classes" },
|
|
35
|
-
];
|
|
36
|
-
|
|
37
|
-
const TRIGGER_API_ROWS = [
|
|
38
|
-
{ prop: "value", type: "string", default: "—", description: "Unique identifier matched against a TabsContent value" },
|
|
39
|
-
{ prop: "label", type: "string", default: "—", description: "Text shown on the trigger" },
|
|
40
|
-
{ prop: "icon", type: "LucideIcon", default: "—", description: "Optional leading icon" },
|
|
41
|
-
{ prop: "badge", type: "string | number", default: "—", description: "Optional badge shown after the label" },
|
|
42
|
-
{ prop: "className", type: "string", default: "—", description: "Additional CSS classes" },
|
|
43
|
-
];
|
|
44
|
-
|
|
45
|
-
const CONTENT_API_ROWS = [
|
|
46
|
-
{ prop: "value", type: "string", default: "—", description: "Matches the TabsTrigger value that reveals this panel" },
|
|
47
|
-
{ prop: "children", type: "ReactNode", default: "—", description: "Panel content" },
|
|
48
|
-
{ prop: "className", type: "string", default: "—", description: "Additional CSS classes" },
|
|
49
|
-
];
|
|
50
|
-
|
|
51
|
-
const ACCESSIBILITY_ITEMS = [
|
|
52
|
-
"TabsList carries role=\"tablist\" and each TabsTrigger carries role=\"tab\" with aria-selected reflecting the active tab.",
|
|
53
|
-
"Only the active trigger is in the tab order (tabIndex 0) — arrive with Tab, then switch panels with a click or Enter/Space.",
|
|
54
|
-
"Each TabsContent panel carries role=\"tabpanel\" and aria-labelledby, linking it back to its trigger for screen readers.",
|
|
55
|
-
"Icon-only or badge-heavy triggers should still include a readable label — label is always rendered, just style it visually hidden if needed.",
|
|
56
|
-
"Prefer the scrollable variant over shrinking text when a tab list won't fit — truncated labels are hard to scan.",
|
|
57
|
-
];
|
|
58
|
-
|
|
59
|
-
type Variant = "underline" | "pill" | "segmented" | "bordered" | "filled" | "floating";
|
|
60
|
-
|
|
61
|
-
const VARIANTS: { value: Variant; label: string }[] = [
|
|
62
|
-
{ value: "underline", label: "Underline" },
|
|
63
|
-
{ value: "pill", label: "Pill" },
|
|
64
|
-
{ value: "segmented", label: "Segmented" },
|
|
65
|
-
{ value: "bordered", label: "Bordered" },
|
|
66
|
-
{ value: "filled", label: "Filled" },
|
|
67
|
-
{ value: "floating", label: "Floating" },
|
|
68
|
-
];
|
|
69
|
-
|
|
70
|
-
function codeFor(variant: Variant) {
|
|
71
|
-
const props = variant !== "underline" ? ` variant="${variant}"` : "";
|
|
72
|
-
return `<Tabs defaultValue="overview"${props}>
|
|
73
|
-
<TabsList>
|
|
74
|
-
<TabsTrigger value="overview" label="Overview" />
|
|
75
|
-
<TabsTrigger value="analytics" label="Analytics" />
|
|
76
|
-
<TabsTrigger value="settings" label="Settings" />
|
|
77
|
-
</TabsList>
|
|
78
|
-
<TabsContent value="overview">
|
|
79
|
-
Snapshot of activity across your workspace.
|
|
80
|
-
</TabsContent>
|
|
81
|
-
<TabsContent value="analytics">
|
|
82
|
-
Traffic, conversion, and retention trends.
|
|
83
|
-
</TabsContent>
|
|
84
|
-
<TabsContent value="settings">
|
|
85
|
-
Manage preferences and integrations.
|
|
86
|
-
</TabsContent>
|
|
87
|
-
</Tabs>`;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export function TabsDocPage() {
|
|
91
|
-
const [variant, setVariant] = useState<Variant>("underline");
|
|
92
|
-
const [copied, setCopied] = useState(false);
|
|
93
|
-
|
|
94
|
-
const snippet = codeFor(variant);
|
|
95
|
-
|
|
96
|
-
function copySnippet() {
|
|
97
|
-
navigator.clipboard.writeText(snippet).catch(() => {});
|
|
98
|
-
setCopied(true);
|
|
99
|
-
setTimeout(() => setCopied(false), 1200);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return (
|
|
103
|
-
<DocsPage>
|
|
104
|
-
<DocsPageHeader
|
|
105
|
-
icon={Columns3}
|
|
106
|
-
title="Tabs"
|
|
107
|
-
description="Organizes related content into switchable panels — from minimal underlines to segmented, floating, and vertical layouts."
|
|
108
|
-
/>
|
|
109
|
-
|
|
110
|
-
<DocsSection
|
|
111
|
-
first
|
|
112
|
-
title="Playground"
|
|
113
|
-
description="Every variant, live — switch tabs, change the style, and copy the exact markup."
|
|
114
|
-
>
|
|
115
|
-
<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)]">
|
|
116
|
-
<div className="relative flex min-h-[12rem] items-center justify-center overflow-x-auto bg-zinc-50 p-4 dark:bg-zinc-900/40 sm:p-6">
|
|
117
|
-
<div
|
|
118
|
-
aria-hidden
|
|
119
|
-
className="pointer-events-none absolute inset-0 opacity-[0.4] dark:opacity-[0.15]"
|
|
120
|
-
style={{
|
|
121
|
-
backgroundImage:
|
|
122
|
-
"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)",
|
|
123
|
-
backgroundSize: "24px 24px",
|
|
124
|
-
}}
|
|
125
|
-
/>
|
|
126
|
-
<div key={variant} className="relative w-full min-w-0 max-w-md animate-[pagination-pop_0.2s_ease-out]">
|
|
127
|
-
<Tabs defaultValue="overview" variant={variant}>
|
|
128
|
-
<TabsList>
|
|
129
|
-
<TabsTrigger value="overview" label="Overview" />
|
|
130
|
-
<TabsTrigger value="analytics" label="Analytics" />
|
|
131
|
-
<TabsTrigger value="settings" label="Settings" />
|
|
132
|
-
</TabsList>
|
|
133
|
-
<TabsContent value="overview" className="pt-4 text-sm text-zinc-600 dark:text-zinc-300">
|
|
134
|
-
Snapshot of activity across your workspace.
|
|
135
|
-
</TabsContent>
|
|
136
|
-
<TabsContent value="analytics" className="pt-4 text-sm text-zinc-600 dark:text-zinc-300">
|
|
137
|
-
Traffic, conversion, and retention trends.
|
|
138
|
-
</TabsContent>
|
|
139
|
-
<TabsContent value="settings" className="pt-4 text-sm text-zinc-600 dark:text-zinc-300">
|
|
140
|
-
Manage preferences and integrations.
|
|
141
|
-
</TabsContent>
|
|
142
|
-
</Tabs>
|
|
143
|
-
</div>
|
|
144
|
-
</div>
|
|
145
|
-
|
|
146
|
-
<div className="flex flex-col gap-5 border-t border-zinc-200 p-5 dark:border-zinc-800">
|
|
147
|
-
<div className="flex flex-wrap items-start justify-between gap-6">
|
|
148
|
-
<div>
|
|
149
|
-
<p className="mb-2 text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
|
|
150
|
-
Variant
|
|
151
|
-
</p>
|
|
152
|
-
<div className="flex flex-wrap gap-1.5">
|
|
153
|
-
{VARIANTS.map((v) => (
|
|
154
|
-
<button
|
|
155
|
-
key={v.value}
|
|
156
|
-
type="button"
|
|
157
|
-
onClick={() => setVariant(v.value)}
|
|
158
|
-
className={cn(
|
|
159
|
-
"rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors",
|
|
160
|
-
variant === v.value
|
|
161
|
-
? "border-zinc-900 bg-zinc-900 text-white dark:border-white dark:bg-white dark:text-zinc-900"
|
|
162
|
-
: "border-zinc-200 text-zinc-500 hover:border-zinc-300 hover:text-zinc-800 dark:border-zinc-700 dark:text-zinc-400 dark:hover:border-zinc-600 dark:hover:text-zinc-200"
|
|
163
|
-
)}
|
|
164
|
-
>
|
|
165
|
-
{v.label}
|
|
166
|
-
</button>
|
|
167
|
-
))}
|
|
168
|
-
</div>
|
|
169
|
-
</div>
|
|
170
|
-
</div>
|
|
171
|
-
|
|
172
|
-
<div className="flex items-center justify-between gap-3 rounded-xl bg-zinc-900 px-4 py-3 dark:bg-black">
|
|
173
|
-
<pre className="overflow-x-auto font-mono text-[13px] leading-relaxed text-zinc-100">
|
|
174
|
-
<code>{snippet}</code>
|
|
175
|
-
</pre>
|
|
176
|
-
<Tooltip content={copied ? "Copied!" : "Copy code"}>
|
|
177
|
-
<button
|
|
178
|
-
type="button"
|
|
179
|
-
onClick={copySnippet}
|
|
180
|
-
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"
|
|
181
|
-
>
|
|
182
|
-
{copied ? <Check className="h-4 w-4 text-emerald-400" /> : <Copy className="h-4 w-4" />}
|
|
183
|
-
</button>
|
|
184
|
-
</Tooltip>
|
|
185
|
-
</div>
|
|
186
|
-
</div>
|
|
187
|
-
</div>
|
|
188
|
-
</DocsSection>
|
|
189
|
-
|
|
190
|
-
<DocsSection title="Default" description="Underline tabs switch between panels without leaving the page.">
|
|
191
|
-
<Card className="max-w-2xl">
|
|
192
|
-
<CardHeader className="border-b border-zinc-100 dark:border-zinc-800">
|
|
193
|
-
<div className="flex items-center justify-between gap-4">
|
|
194
|
-
<div>
|
|
195
|
-
<CardTitle>Project overview</CardTitle>
|
|
196
|
-
<CardDescription>Track progress, activity, and settings in one place.</CardDescription>
|
|
197
|
-
</div>
|
|
198
|
-
<Badge variant="outline">6 members</Badge>
|
|
199
|
-
</div>
|
|
200
|
-
</CardHeader>
|
|
201
|
-
<CardContent className="pt-5">
|
|
202
|
-
<Tabs defaultValue="overview">
|
|
203
|
-
<TabsList>
|
|
204
|
-
<TabsTrigger value="overview" label="Overview" />
|
|
205
|
-
<TabsTrigger value="activity" label="Activity" badge={3} />
|
|
206
|
-
<TabsTrigger value="settings" label="Settings" />
|
|
207
|
-
</TabsList>
|
|
208
|
-
<TabsContent value="overview" className="pt-4 text-sm text-zinc-600 dark:text-zinc-300">
|
|
209
|
-
12 of 20 tasks complete this sprint. The team is on track to ship by Friday.
|
|
210
|
-
</TabsContent>
|
|
211
|
-
<TabsContent value="activity" className="pt-4 text-sm text-zinc-600 dark:text-zinc-300">
|
|
212
|
-
3 new comments and 2 status changes since you last checked in.
|
|
213
|
-
</TabsContent>
|
|
214
|
-
<TabsContent value="settings" className="pt-4 text-sm text-zinc-600 dark:text-zinc-300">
|
|
215
|
-
Manage notifications, integrations, and who can access this project.
|
|
216
|
-
</TabsContent>
|
|
217
|
-
</Tabs>
|
|
218
|
-
</CardContent>
|
|
219
|
-
</Card>
|
|
220
|
-
</DocsSection>
|
|
221
|
-
|
|
222
|
-
<DocsSection title="Variants" description="Pill and segmented styles suit compact filters and toggles.">
|
|
223
|
-
<DocsSectionGrid>
|
|
224
|
-
<Card>
|
|
225
|
-
<CardHeader>
|
|
226
|
-
<CardTitle className="text-base">Pill</CardTitle>
|
|
227
|
-
<CardDescription>Rounded, high-contrast triggers for a feed or inbox filter.</CardDescription>
|
|
228
|
-
</CardHeader>
|
|
229
|
-
<CardContent>
|
|
230
|
-
<Tabs defaultValue="home" variant="pill">
|
|
231
|
-
<TabsList>
|
|
232
|
-
<TabsTrigger value="home" label="Home" />
|
|
233
|
-
<TabsTrigger value="following" label="Following" badge={2} />
|
|
234
|
-
</TabsList>
|
|
235
|
-
</Tabs>
|
|
236
|
-
</CardContent>
|
|
237
|
-
</Card>
|
|
238
|
-
|
|
239
|
-
<Card>
|
|
240
|
-
<CardHeader>
|
|
241
|
-
<CardTitle className="text-base">Segmented</CardTitle>
|
|
242
|
-
<CardDescription>An iOS-style control for switching between short, related options.</CardDescription>
|
|
243
|
-
</CardHeader>
|
|
244
|
-
<CardContent>
|
|
245
|
-
<Tabs defaultValue="day" variant="segmented">
|
|
246
|
-
<TabsList>
|
|
247
|
-
<TabsTrigger value="day" label="Day" />
|
|
248
|
-
<TabsTrigger value="week" label="Week" />
|
|
249
|
-
<TabsTrigger value="month" label="Month" />
|
|
250
|
-
</TabsList>
|
|
251
|
-
</Tabs>
|
|
252
|
-
</CardContent>
|
|
253
|
-
</Card>
|
|
254
|
-
</DocsSectionGrid>
|
|
255
|
-
</DocsSection>
|
|
256
|
-
|
|
257
|
-
<DocsSection title="Elevated & Bordered" description="A floating surface for prominent placement, or a quiet outline for secondary controls.">
|
|
258
|
-
<DocsSectionGrid>
|
|
259
|
-
<Card>
|
|
260
|
-
<CardHeader>
|
|
261
|
-
<CardTitle className="text-base">Floating</CardTitle>
|
|
262
|
-
<CardDescription>Sits above the page on its own elevated surface.</CardDescription>
|
|
263
|
-
</CardHeader>
|
|
264
|
-
<CardContent>
|
|
265
|
-
<Tabs defaultValue="all" variant="floating">
|
|
266
|
-
<TabsList>
|
|
267
|
-
<TabsTrigger value="all" label="All" />
|
|
268
|
-
<TabsTrigger value="featured" label="Featured" icon={Star} />
|
|
269
|
-
</TabsList>
|
|
270
|
-
</Tabs>
|
|
271
|
-
</CardContent>
|
|
272
|
-
</Card>
|
|
273
|
-
|
|
274
|
-
<Card>
|
|
275
|
-
<CardHeader>
|
|
276
|
-
<CardTitle className="text-base">Bordered</CardTitle>
|
|
277
|
-
<CardDescription>A visible outline for triggers that need clear boundaries.</CardDescription>
|
|
278
|
-
</CardHeader>
|
|
279
|
-
<CardContent>
|
|
280
|
-
<Tabs defaultValue="a" variant="bordered">
|
|
281
|
-
<TabsList>
|
|
282
|
-
<TabsTrigger value="a" label="Analytical" />
|
|
283
|
-
<TabsTrigger value="b" label="Behavioral" />
|
|
284
|
-
</TabsList>
|
|
285
|
-
</Tabs>
|
|
286
|
-
</CardContent>
|
|
287
|
-
</Card>
|
|
288
|
-
</DocsSectionGrid>
|
|
289
|
-
</DocsSection>
|
|
290
|
-
|
|
291
|
-
<DocsSection title="Layouts" description="Vertical tabs for settings sidebars, icon tabs for compact dashboards.">
|
|
292
|
-
<DocsSectionGrid>
|
|
293
|
-
<Card>
|
|
294
|
-
<CardHeader>
|
|
295
|
-
<CardTitle className="text-base">Vertical</CardTitle>
|
|
296
|
-
<CardDescription>Ideal for a settings page with several sections.</CardDescription>
|
|
297
|
-
</CardHeader>
|
|
298
|
-
<CardContent>
|
|
299
|
-
<Tabs defaultValue="profile" variant="vertical">
|
|
300
|
-
<TabsList>
|
|
301
|
-
<TabsTrigger value="profile" label="Profile" icon={Home} />
|
|
302
|
-
<TabsTrigger value="security" label="Security" icon={Settings} />
|
|
303
|
-
<TabsTrigger value="notifications" label="Notifications" icon={Bell} />
|
|
304
|
-
</TabsList>
|
|
305
|
-
<TabsContent value="profile" className="text-sm text-zinc-600 dark:text-zinc-300">
|
|
306
|
-
Manage your name, photo, and public profile details.
|
|
307
|
-
</TabsContent>
|
|
308
|
-
<TabsContent value="security" className="text-sm text-zinc-600 dark:text-zinc-300">
|
|
309
|
-
Update your password and two-factor authentication.
|
|
310
|
-
</TabsContent>
|
|
311
|
-
<TabsContent value="notifications" className="text-sm text-zinc-600 dark:text-zinc-300">
|
|
312
|
-
Choose what you're notified about, and where.
|
|
313
|
-
</TabsContent>
|
|
314
|
-
</Tabs>
|
|
315
|
-
</CardContent>
|
|
316
|
-
</Card>
|
|
317
|
-
|
|
318
|
-
<Card>
|
|
319
|
-
<CardHeader>
|
|
320
|
-
<CardTitle className="text-base">Icon</CardTitle>
|
|
321
|
-
<CardDescription>Compact, icon-first triggers for dashboards and bottom navigation.</CardDescription>
|
|
322
|
-
</CardHeader>
|
|
323
|
-
<CardContent>
|
|
324
|
-
<Tabs defaultValue="feed" variant="icon">
|
|
325
|
-
<TabsList>
|
|
326
|
-
<TabsTrigger value="feed" label="Feed" icon={TrendingUp} />
|
|
327
|
-
<TabsTrigger value="friends" label="Friends" icon={Users} badge="!" />
|
|
328
|
-
<TabsTrigger value="favs" label="Favs" icon={Star} />
|
|
329
|
-
</TabsList>
|
|
330
|
-
</Tabs>
|
|
331
|
-
</CardContent>
|
|
332
|
-
</Card>
|
|
333
|
-
</DocsSectionGrid>
|
|
334
|
-
</DocsSection>
|
|
335
|
-
|
|
336
|
-
<DocsSection title="Scrollable" description="Overflows horizontally instead of wrapping — ideal for narrow or mobile viewports.">
|
|
337
|
-
<Card className="max-w-md">
|
|
338
|
-
<CardContent className="pt-6">
|
|
339
|
-
<Tabs defaultValue="Analytics" variant="scrollable">
|
|
340
|
-
<TabsList>
|
|
341
|
-
{["Analytics", "Operations", "Inventory", "Logistics", "Marketing", "Sales"].map((t) => (
|
|
342
|
-
<TabsTrigger key={t} value={t} label={t} />
|
|
343
|
-
))}
|
|
344
|
-
</TabsList>
|
|
345
|
-
</Tabs>
|
|
346
|
-
</CardContent>
|
|
347
|
-
</Card>
|
|
348
|
-
</DocsSection>
|
|
349
|
-
|
|
350
|
-
<DocsApiSection>
|
|
351
|
-
<DocsApiTable title="API Reference — Tabs" rows={TABS_API_ROWS} />
|
|
352
|
-
<DocsApiTable title="API Reference — TabsList" rows={LIST_API_ROWS} />
|
|
353
|
-
<DocsApiTable title="API Reference — TabsTrigger" rows={TRIGGER_API_ROWS} />
|
|
354
|
-
<DocsApiTable title="API Reference — TabsContent" rows={CONTENT_API_ROWS} />
|
|
355
|
-
<DocsAccessibility items={ACCESSIBILITY_ITEMS} />
|
|
356
|
-
</DocsApiSection>
|
|
357
|
-
</DocsPage>
|
|
358
|
-
);
|
|
359
|
-
}
|
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useState } from "react";
|
|
4
|
-
import Link from "next/link";
|
|
5
|
-
import { ArrowRight, Check, Copy, Palette } from "lucide-react";
|
|
6
|
-
import { Button } from "@/components/ui/button";
|
|
7
|
-
import { Badge } from "@/components/ui/badge";
|
|
8
|
-
import { Tooltip } from "@/components/ui/tooltip";
|
|
9
|
-
import { DocsPage, DocsPageHeader, DocsSection, DocsSectionGrid } from "@/components/docs/docs-page";
|
|
10
|
-
import { COLOR_PALETTE } from "@/data/color-palette";
|
|
11
|
-
import { cn } from "@/lib/cn";
|
|
12
|
-
|
|
13
|
-
const TOKENS = [
|
|
14
|
-
{ name: "--background", light: "#ffffff", dark: "#09090b", usage: "Page background" },
|
|
15
|
-
{ name: "--foreground", light: "#09090b", dark: "#fafafa", usage: "Default text color" },
|
|
16
|
-
];
|
|
17
|
-
|
|
18
|
-
const FONTS: { token: string; family: string; sample: string; usage: string; className: string }[] = [
|
|
19
|
-
{ token: "font-sans", family: "Poppins", sample: "The quick brown fox jumps.", usage: "Body copy & UI text", className: "font-sans" },
|
|
20
|
-
{ token: "font-mono", family: "Geist Mono", sample: "const theme = \"dark\";", usage: "Code & data", className: "font-mono" },
|
|
21
|
-
{ token: "font-brand", family: "Orbitron", sample: "ruler.ui", usage: "Wordmark & headings", className: "font-brand" },
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
const SNIPPET = `:root {
|
|
25
|
-
--background: #ffffff;
|
|
26
|
-
--foreground: #09090b;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.dark {
|
|
30
|
-
--background: #09090b;
|
|
31
|
-
--foreground: #fafafa;
|
|
32
|
-
}`;
|
|
33
|
-
|
|
34
|
-
function ThemeSample({ mode }: { mode: "light" | "dark" }) {
|
|
35
|
-
const isDark = mode === "dark";
|
|
36
|
-
return (
|
|
37
|
-
<div
|
|
38
|
-
className={cn(
|
|
39
|
-
isDark && "dark",
|
|
40
|
-
"flex flex-col gap-4 rounded-2xl border p-5",
|
|
41
|
-
isDark ? "border-zinc-800 bg-zinc-950" : "border-zinc-200 bg-white"
|
|
42
|
-
)}
|
|
43
|
-
>
|
|
44
|
-
<div className="flex items-center justify-between">
|
|
45
|
-
<span className={cn("text-xs font-semibold uppercase tracking-wide", isDark ? "text-zinc-500" : "text-zinc-400")}>
|
|
46
|
-
{mode}
|
|
47
|
-
</span>
|
|
48
|
-
<Badge variant="success">
|
|
49
|
-
<Check className="h-3 w-3" />
|
|
50
|
-
Active
|
|
51
|
-
</Badge>
|
|
52
|
-
</div>
|
|
53
|
-
<div>
|
|
54
|
-
<p className={cn("text-sm font-semibold", isDark ? "text-white" : "text-zinc-900")}>Workspace settings</p>
|
|
55
|
-
<p className={cn("mt-1 text-xs leading-relaxed", isDark ? "text-zinc-400" : "text-zinc-500")}>
|
|
56
|
-
Same components, same markup — only the CSS variables change.
|
|
57
|
-
</p>
|
|
58
|
-
</div>
|
|
59
|
-
<div className="flex items-center gap-2">
|
|
60
|
-
<Button size="sm">Save changes</Button>
|
|
61
|
-
<Button variant="outline" size="sm">
|
|
62
|
-
Cancel
|
|
63
|
-
</Button>
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export function ThemingDocPage() {
|
|
70
|
-
const [copied, setCopied] = useState<string | null>(null);
|
|
71
|
-
|
|
72
|
-
function copy(value: string) {
|
|
73
|
-
navigator.clipboard.writeText(value).catch(() => {});
|
|
74
|
-
setCopied(value);
|
|
75
|
-
setTimeout(() => setCopied((prev) => (prev === value ? null : prev)), 1200);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return (
|
|
79
|
-
<DocsPage>
|
|
80
|
-
<DocsPageHeader
|
|
81
|
-
icon={Palette}
|
|
82
|
-
title="Theming"
|
|
83
|
-
description="Every component reads from two CSS variables and a single .dark class — no theme provider, no runtime cost."
|
|
84
|
-
/>
|
|
85
|
-
|
|
86
|
-
<DocsSection
|
|
87
|
-
first
|
|
88
|
-
title="Light & dark, side by side"
|
|
89
|
-
description="Both panels below render the exact same JSX. The only difference is a .dark class on the wrapper."
|
|
90
|
-
>
|
|
91
|
-
<div className="grid gap-4 sm:grid-cols-2">
|
|
92
|
-
<ThemeSample mode="light" />
|
|
93
|
-
<ThemeSample mode="dark" />
|
|
94
|
-
</div>
|
|
95
|
-
</DocsSection>
|
|
96
|
-
|
|
97
|
-
<DocsSection
|
|
98
|
-
title="Design tokens"
|
|
99
|
-
description="Two variables drive the entire surface — everything else is computed from them via Tailwind's dark: variant."
|
|
100
|
-
>
|
|
101
|
-
<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)]">
|
|
102
|
-
<table className="w-full text-left text-sm">
|
|
103
|
-
<thead>
|
|
104
|
-
<tr className="border-b border-zinc-200 bg-zinc-50/70 dark:border-zinc-800 dark:bg-zinc-900/40">
|
|
105
|
-
<th className="px-4 py-2.5 font-medium text-zinc-500 dark:text-zinc-400">Token</th>
|
|
106
|
-
<th className="px-4 py-2.5 font-medium text-zinc-500 dark:text-zinc-400">Light</th>
|
|
107
|
-
<th className="px-4 py-2.5 font-medium text-zinc-500 dark:text-zinc-400">Dark</th>
|
|
108
|
-
<th className="px-4 py-2.5 font-medium text-zinc-500 dark:text-zinc-400">Used for</th>
|
|
109
|
-
</tr>
|
|
110
|
-
</thead>
|
|
111
|
-
<tbody>
|
|
112
|
-
{TOKENS.map((token) => (
|
|
113
|
-
<tr
|
|
114
|
-
key={token.name}
|
|
115
|
-
className="border-b border-zinc-200 last:border-0 dark:border-zinc-800"
|
|
116
|
-
>
|
|
117
|
-
<td className="px-4 py-3">
|
|
118
|
-
<Tooltip content={copied === token.name ? "Copied!" : "Copy variable name"}>
|
|
119
|
-
<button
|
|
120
|
-
type="button"
|
|
121
|
-
onClick={() => copy(token.name)}
|
|
122
|
-
className="group flex items-center gap-2 rounded-md font-mono text-xs text-zinc-700 transition-colors hover:text-zinc-900 dark:text-zinc-300 dark:hover:text-white"
|
|
123
|
-
>
|
|
124
|
-
{token.name}
|
|
125
|
-
{copied === token.name ? (
|
|
126
|
-
<Check className="h-3 w-3 text-green-500" />
|
|
127
|
-
) : (
|
|
128
|
-
<Copy className="h-3 w-3 opacity-0 transition-opacity group-hover:opacity-100" />
|
|
129
|
-
)}
|
|
130
|
-
</button>
|
|
131
|
-
</Tooltip>
|
|
132
|
-
</td>
|
|
133
|
-
<td className="px-4 py-3">
|
|
134
|
-
<span className="flex items-center gap-2">
|
|
135
|
-
<span
|
|
136
|
-
className="h-4 w-4 shrink-0 rounded-full border border-black/10"
|
|
137
|
-
style={{ backgroundColor: token.light }}
|
|
138
|
-
/>
|
|
139
|
-
<span className="font-mono text-xs text-zinc-500 dark:text-zinc-400">{token.light}</span>
|
|
140
|
-
</span>
|
|
141
|
-
</td>
|
|
142
|
-
<td className="px-4 py-3">
|
|
143
|
-
<span className="flex items-center gap-2">
|
|
144
|
-
<span
|
|
145
|
-
className="h-4 w-4 shrink-0 rounded-full border border-white/10"
|
|
146
|
-
style={{ backgroundColor: token.dark }}
|
|
147
|
-
/>
|
|
148
|
-
<span className="font-mono text-xs text-zinc-500 dark:text-zinc-400">{token.dark}</span>
|
|
149
|
-
</span>
|
|
150
|
-
</td>
|
|
151
|
-
<td className="px-4 py-3 text-zinc-600 dark:text-zinc-300">{token.usage}</td>
|
|
152
|
-
</tr>
|
|
153
|
-
))}
|
|
154
|
-
</tbody>
|
|
155
|
-
</table>
|
|
156
|
-
</div>
|
|
157
|
-
</DocsSection>
|
|
158
|
-
|
|
159
|
-
<DocsSection title="Typography" description="Three font tokens, each mapped to a Tailwind utility class.">
|
|
160
|
-
<DocsSectionGrid className="sm:grid-cols-3">
|
|
161
|
-
{FONTS.map((font) => (
|
|
162
|
-
<div
|
|
163
|
-
key={font.token}
|
|
164
|
-
className="flex flex-col justify-between gap-4 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"
|
|
165
|
-
>
|
|
166
|
-
<div>
|
|
167
|
-
<p className="text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
|
|
168
|
-
{font.family}
|
|
169
|
-
</p>
|
|
170
|
-
<p className={cn("mt-2 text-xl text-zinc-900 dark:text-white", font.className)}>{font.sample}</p>
|
|
171
|
-
</div>
|
|
172
|
-
<div className="flex items-center justify-between">
|
|
173
|
-
<span className="text-xs text-zinc-500 dark:text-zinc-400">{font.usage}</span>
|
|
174
|
-
<Tooltip content={copied === font.token ? "Copied!" : "Copy class name"}>
|
|
175
|
-
<button
|
|
176
|
-
type="button"
|
|
177
|
-
onClick={() => copy(font.token)}
|
|
178
|
-
className="group flex items-center gap-1.5 rounded-md font-mono text-xs text-zinc-500 transition-colors hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white"
|
|
179
|
-
>
|
|
180
|
-
{font.token}
|
|
181
|
-
{copied === font.token ? (
|
|
182
|
-
<Check className="h-3 w-3 text-green-500" />
|
|
183
|
-
) : (
|
|
184
|
-
<Copy className="h-3 w-3 opacity-0 transition-opacity group-hover:opacity-100" />
|
|
185
|
-
)}
|
|
186
|
-
</button>
|
|
187
|
-
</Tooltip>
|
|
188
|
-
</div>
|
|
189
|
-
</div>
|
|
190
|
-
))}
|
|
191
|
-
</DocsSectionGrid>
|
|
192
|
-
</DocsSection>
|
|
193
|
-
|
|
194
|
-
<DocsSection title="Color palette" description="Every hue and shade lives on its own page, with contrast built in.">
|
|
195
|
-
<Link
|
|
196
|
-
href="/docs/colors"
|
|
197
|
-
className="group flex items-center justify-between gap-4 overflow-hidden rounded-2xl border border-zinc-200 bg-white p-5 shadow-[0_1px_2px_rgba(0,0,0,0.03)] transition-colors hover:border-zinc-300 dark:border-zinc-800 dark:bg-zinc-950 dark:hover:border-zinc-700"
|
|
198
|
-
>
|
|
199
|
-
<div className="flex items-center gap-4">
|
|
200
|
-
<div className="flex h-11 -space-x-2">
|
|
201
|
-
{COLOR_PALETTE.slice(0, 6).map((hue) => (
|
|
202
|
-
<span
|
|
203
|
-
key={hue.name}
|
|
204
|
-
className="h-11 w-11 shrink-0 rounded-full ring-2 ring-white dark:ring-zinc-950"
|
|
205
|
-
style={{ backgroundColor: hue.shades[5].hex }}
|
|
206
|
-
/>
|
|
207
|
-
))}
|
|
208
|
-
</div>
|
|
209
|
-
<div>
|
|
210
|
-
<p className="text-sm font-semibold text-zinc-900 dark:text-white">
|
|
211
|
-
{COLOR_PALETTE.length} hues · {COLOR_PALETTE.length * 11} shades
|
|
212
|
-
</p>
|
|
213
|
-
<p className="text-xs text-zinc-500 dark:text-zinc-400">
|
|
214
|
-
HEX, RGB, HSL, and CSS — copy any value.
|
|
215
|
-
</p>
|
|
216
|
-
</div>
|
|
217
|
-
</div>
|
|
218
|
-
<ArrowRight className="h-4 w-4 shrink-0 text-zinc-400 transition-transform group-hover:translate-x-1 dark:text-zinc-500" />
|
|
219
|
-
</Link>
|
|
220
|
-
</DocsSection>
|
|
221
|
-
|
|
222
|
-
<DocsSection
|
|
223
|
-
title="Bring your own brand"
|
|
224
|
-
description="Override the two root variables anywhere above ruler.ui's components and everything repaints — no rebuild, no config."
|
|
225
|
-
>
|
|
226
|
-
<div className="flex items-center justify-between gap-3 rounded-xl bg-zinc-900 px-4 py-3 dark:bg-black">
|
|
227
|
-
<pre className="overflow-x-auto font-mono text-[13px] leading-relaxed text-zinc-100">
|
|
228
|
-
<code>{SNIPPET}</code>
|
|
229
|
-
</pre>
|
|
230
|
-
<Tooltip content={copied === SNIPPET ? "Copied!" : "Copy CSS"}>
|
|
231
|
-
<button
|
|
232
|
-
type="button"
|
|
233
|
-
onClick={() => copy(SNIPPET)}
|
|
234
|
-
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"
|
|
235
|
-
>
|
|
236
|
-
{copied === SNIPPET ? <Check className="h-4 w-4 text-emerald-400" /> : <Copy className="h-4 w-4" />}
|
|
237
|
-
</button>
|
|
238
|
-
</Tooltip>
|
|
239
|
-
</div>
|
|
240
|
-
</DocsSection>
|
|
241
|
-
</DocsPage>
|
|
242
|
-
);
|
|
243
|
-
}
|