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/AGENTS.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<!-- BEGIN:nextjs-agent-rules -->
|
|
2
|
+
|
|
3
|
+
# This is NOT the Next.js you know
|
|
4
|
+
|
|
5
|
+
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices.
|
|
6
|
+
|
|
7
|
+
This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.
|
|
8
|
+
|
|
9
|
+
<!-- END:nextjs-agent-rules -->
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zuhaib Shahid
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# ruler.ui
|
|
2
|
+
|
|
3
|
+
Marketing site + docs shell for **ruler.ui**, a planned React component
|
|
4
|
+
library. This repo currently contains a hardcoded front-end for the design
|
|
5
|
+
(landing page + docs shell) — no published package, tokens system, or real
|
|
6
|
+
component implementations yet. See `component-library-roadmap.pdf` for the
|
|
7
|
+
full multi-phase plan this scaffold is a preview of.
|
|
8
|
+
|
|
9
|
+
## Stack
|
|
10
|
+
|
|
11
|
+
Next.js (App Router) · TypeScript · Tailwind CSS v4 · next-themes · lucide-react
|
|
12
|
+
|
|
13
|
+
## Structure
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
app/
|
|
17
|
+
page.tsx landing page
|
|
18
|
+
docs/
|
|
19
|
+
layout.tsx docs shell (topbar + sidebar + footer)
|
|
20
|
+
page.tsx "Introduction" content
|
|
21
|
+
[slug]/page.tsx placeholder page for every other sidebar item
|
|
22
|
+
components/
|
|
23
|
+
landing/ hero, navbar, feature highlights, quick start, footer
|
|
24
|
+
docs/ docs topbar, sidebar, footer, next-steps, usage
|
|
25
|
+
ui/ Button, CodeBlock, FeatureCard, PackageManagerTabs, ThemeToggle
|
|
26
|
+
icons/ brand icons not in lucide (GitHub)
|
|
27
|
+
data/
|
|
28
|
+
docs-nav.ts hardcoded sidebar nav (groups, labels, icons)
|
|
29
|
+
lib/
|
|
30
|
+
cn.ts className merge helper (clsx + tailwind-merge)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Colors are plain Tailwind utility classes (violet accent, zinc neutrals) —
|
|
34
|
+
not yet backed by a CSS-variable token system. The sidebar links to a real
|
|
35
|
+
`[slug]` route for every component, but only `Introduction` has real content;
|
|
36
|
+
everything else renders a "coming soon" placeholder.
|
|
37
|
+
|
|
38
|
+
## Getting started
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install
|
|
42
|
+
npm run dev
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Open [http://localhost:3000](http://localhost:3000).
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { notFound } from "next/navigation";
|
|
2
|
+
import { Construction } from "lucide-react";
|
|
3
|
+
import { DOCS_NAV } from "@/data/docs-nav";
|
|
4
|
+
import { DocsPage as DocsPageLayout, DocsPageHeader, DocsSection } from "@/components/docs/docs-page";
|
|
5
|
+
import { AlertDocPage } from "@/components/docs/alert-doc-page";
|
|
6
|
+
import { AvatarDocPage } from "@/components/docs/avatar-doc-page";
|
|
7
|
+
import { BadgeDocPage } from "@/components/docs/badge-doc-page";
|
|
8
|
+
import { ButtonDocPage } from "@/components/docs/button-doc-page";
|
|
9
|
+
import { CardDocPage } from "@/components/docs/card-doc-page";
|
|
10
|
+
import { CheckboxDocPage } from "@/components/docs/checkbox-doc-page";
|
|
11
|
+
import { LabelDocPage } from "@/components/docs/label-doc-page";
|
|
12
|
+
import { MenuDocPage } from "@/components/docs/menu-doc-page";
|
|
13
|
+
import { ModalDocPage } from "@/components/docs/modal-doc-page";
|
|
14
|
+
import { ProgressDocPage } from "@/components/docs/progress-doc-page";
|
|
15
|
+
import { RadioDocPage } from "@/components/docs/radio-doc-page";
|
|
16
|
+
import { SwitchDocPage } from "@/components/docs/switch-doc-page";
|
|
17
|
+
import { TooltipDocPage } from "@/components/docs/tooltip-doc-page";
|
|
18
|
+
import { AccordionDocPage } from "@/components/docs/accordion-doc-page";
|
|
19
|
+
import { SkeletonDocPage } from "@/components/docs/skeleton-doc-page";
|
|
20
|
+
import { DialogDocPage } from "@/components/docs/dialog-doc-page";
|
|
21
|
+
import { TableDocPage } from "@/components/docs/table-doc-page";
|
|
22
|
+
import { DropdownDocPage } from "@/components/docs/dropdown-doc-page";
|
|
23
|
+
import { InputDocPage } from "@/components/docs/allinput-doc-page";
|
|
24
|
+
import { TabsDocPage } from "@/components/docs/tabs-doc-page";
|
|
25
|
+
import { PaginationDocPage } from "@/components/docs/pagination-doc-page";
|
|
26
|
+
import { LoadersDocPage } from "@/components/docs/loaders-doc-page";
|
|
27
|
+
import { StepperDocPage } from "@/components/docs/stepper-doc-page";
|
|
28
|
+
import { ColorsDocPage } from "@/components/docs/colors-doc-page";
|
|
29
|
+
import { ThemingDocPage } from "@/components/docs/theming-doc-page";
|
|
30
|
+
import { GettingStartedDocPage } from "@/components/docs/getting-started-doc-page";
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
export default async function DocsPage({
|
|
35
|
+
params,
|
|
36
|
+
}: {
|
|
37
|
+
params: Promise<{ slug: string }>;
|
|
38
|
+
}) {
|
|
39
|
+
const { slug } = await params;
|
|
40
|
+
|
|
41
|
+
const item = DOCS_NAV.flatMap((group) => group.items).find(
|
|
42
|
+
(entry) => entry.slug === slug,
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
if (!item) notFound();
|
|
46
|
+
|
|
47
|
+
switch (slug) {
|
|
48
|
+
case "alert":
|
|
49
|
+
return <AlertDocPage />;
|
|
50
|
+
|
|
51
|
+
case "avatar":
|
|
52
|
+
return <AvatarDocPage />;
|
|
53
|
+
|
|
54
|
+
case "badge":
|
|
55
|
+
return <BadgeDocPage />;
|
|
56
|
+
|
|
57
|
+
case "button":
|
|
58
|
+
return <ButtonDocPage />;
|
|
59
|
+
|
|
60
|
+
case "card":
|
|
61
|
+
return <CardDocPage />;
|
|
62
|
+
|
|
63
|
+
case "checkbox":
|
|
64
|
+
return <CheckboxDocPage />;
|
|
65
|
+
|
|
66
|
+
case "label":
|
|
67
|
+
return <LabelDocPage />;
|
|
68
|
+
|
|
69
|
+
case "menu":
|
|
70
|
+
return <MenuDocPage />;
|
|
71
|
+
|
|
72
|
+
case "modal":
|
|
73
|
+
return <ModalDocPage />;
|
|
74
|
+
|
|
75
|
+
case "progress":
|
|
76
|
+
return <ProgressDocPage />;
|
|
77
|
+
|
|
78
|
+
case "radio":
|
|
79
|
+
return <RadioDocPage />;
|
|
80
|
+
|
|
81
|
+
case "switch":
|
|
82
|
+
return <SwitchDocPage />;
|
|
83
|
+
|
|
84
|
+
case "tooltip":
|
|
85
|
+
return <TooltipDocPage />;
|
|
86
|
+
|
|
87
|
+
case "accordion":
|
|
88
|
+
return <AccordionDocPage />;
|
|
89
|
+
|
|
90
|
+
case "skeleton":
|
|
91
|
+
return <SkeletonDocPage />;
|
|
92
|
+
|
|
93
|
+
case "dialog":
|
|
94
|
+
return <DialogDocPage />;
|
|
95
|
+
|
|
96
|
+
case "table":
|
|
97
|
+
return <TableDocPage />;
|
|
98
|
+
|
|
99
|
+
case "dropdown":
|
|
100
|
+
return <DropdownDocPage />;
|
|
101
|
+
|
|
102
|
+
case "input":
|
|
103
|
+
return <InputDocPage />;
|
|
104
|
+
|
|
105
|
+
case "tabs":
|
|
106
|
+
return <TabsDocPage />;
|
|
107
|
+
|
|
108
|
+
case "pagination":
|
|
109
|
+
return <PaginationDocPage />;
|
|
110
|
+
|
|
111
|
+
case "loader":
|
|
112
|
+
return <LoadersDocPage />;
|
|
113
|
+
|
|
114
|
+
case "stepper":
|
|
115
|
+
return <StepperDocPage />;
|
|
116
|
+
|
|
117
|
+
case "colors":
|
|
118
|
+
return <ColorsDocPage />;
|
|
119
|
+
|
|
120
|
+
case "theming":
|
|
121
|
+
return <ThemingDocPage />;
|
|
122
|
+
|
|
123
|
+
case "getting-started":
|
|
124
|
+
return <GettingStartedDocPage />;
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<DocsPageLayout>
|
|
132
|
+
<DocsPageHeader
|
|
133
|
+
icon={item.icon}
|
|
134
|
+
title={item.title}
|
|
135
|
+
description={`Documentation for the ${item.title} component is coming soon.`}
|
|
136
|
+
/>
|
|
137
|
+
<DocsSection
|
|
138
|
+
contentClassName="flex flex-col items-center gap-3 rounded-xl border border-dashed border-zinc-300 py-16 text-center dark:border-zinc-700"
|
|
139
|
+
>
|
|
140
|
+
<Construction className="h-6 w-6 text-zinc-400" />
|
|
141
|
+
<p className="text-sm text-zinc-500 dark:text-zinc-400">
|
|
142
|
+
The {item.title} docs page is coming soon.
|
|
143
|
+
</p>
|
|
144
|
+
</DocsSection>
|
|
145
|
+
</DocsPageLayout>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { DocsTopbar } from "@/components/docs/docs-topbar";
|
|
3
|
+
import { DocsSidebar } from "@/components/docs/docs-sidebar";
|
|
4
|
+
import { DocsFooter } from "@/components/docs/docs-footer";
|
|
5
|
+
import { DocsMobileNavProvider } from "@/components/docs/docs-mobile-nav-context";
|
|
6
|
+
import { DocsMobileMenuBar } from "@/components/docs/docs-mobile-menu-bar";
|
|
7
|
+
|
|
8
|
+
export default function DocsLayout({ children }: { children: ReactNode }) {
|
|
9
|
+
return (
|
|
10
|
+
<DocsMobileNavProvider>
|
|
11
|
+
<div className="docs-shell-glow relative min-h-screen bg-white dark:bg-zinc-950" id="docs-shell">
|
|
12
|
+
<DocsTopbar />
|
|
13
|
+
<DocsMobileMenuBar />
|
|
14
|
+
<div className="flex min-w-0">
|
|
15
|
+
<DocsSidebar />
|
|
16
|
+
<div className="relative z-10 min-w-0 flex-1 overflow-x-clip px-4 py-8 sm:px-10 sm:py-10 xl:px-16 2xl:px-24">
|
|
17
|
+
{children}
|
|
18
|
+
<div className="mx-auto max-w-5xl">
|
|
19
|
+
<DocsFooter />
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
</DocsMobileNavProvider>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import Link from "next/link";
|
|
2
|
+
import { Rocket, ShieldCheck, SwatchBook, Wand2 } from "lucide-react";
|
|
3
|
+
import { Badge } from "@/components/ui/badge";
|
|
4
|
+
import { InstallationSection } from "@/components/installation-section";
|
|
5
|
+
import { UsageSection } from "@/components/docs/usage-section";
|
|
6
|
+
import { NextSteps } from "@/components/docs/next-steps";
|
|
7
|
+
import { DocsPage, DocsPageHeader, DocsSection } from "@/components/docs/docs-page";
|
|
8
|
+
import { DOCS_NAV } from "@/data/docs-nav";
|
|
9
|
+
|
|
10
|
+
const COMPONENT_COUNT = DOCS_NAV[0].items.filter((item) => item.slug).length;
|
|
11
|
+
|
|
12
|
+
export default function DocsIntroductionPage() {
|
|
13
|
+
return (
|
|
14
|
+
<DocsPage>
|
|
15
|
+
{/* --- NEW HEADER SECTION (Based on Image) --- */}
|
|
16
|
+
<div className="mb-10 space-y-3">
|
|
17
|
+
<h1 className="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
|
|
18
|
+
Welcome to ruler.ui
|
|
19
|
+
</h1>
|
|
20
|
+
<p className="max-w-3xl text-[16px] leading-relaxed text-zinc-600 dark:text-zinc-400">
|
|
21
|
+
ruler.ui is a collective resource of global UI design patterns and components,
|
|
22
|
+
to help maintain a cohesive user experience across all of your products and applications.
|
|
23
|
+
</p>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
{/* --- STATS ROW --- */}
|
|
27
|
+
<div className="mt-6 flex flex-wrap items-center gap-3">
|
|
28
|
+
{/* Component Count Badge */}
|
|
29
|
+
<div className="inline-flex items-center rounded-md border border-zinc-200 bg-white px-3 py-1.5 text-sm text-zinc-600 dark:border-zinc-800 dark:bg-zinc-950 dark:text-zinc-400">
|
|
30
|
+
<span className="mr-1 font-semibold text-zinc-900 dark:text-white">{COMPONENT_COUNT}</span>
|
|
31
|
+
components
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
{/* TypeScript Badge */}
|
|
35
|
+
<div className="inline-flex items-center rounded-md border border-zinc-200 bg-white px-3 py-1.5 text-sm text-zinc-600 dark:border-zinc-800 dark:bg-zinc-950 dark:text-zinc-400">
|
|
36
|
+
Written in TypeScript
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
{/* Accessibility Badge */}
|
|
40
|
+
<div className="inline-flex items-center rounded-md border border-zinc-200 bg-white px-3 py-1.5 text-sm text-zinc-600 dark:border-zinc-800 dark:bg-zinc-950 dark:text-zinc-400">
|
|
41
|
+
WAI-ARIA accessible
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
{/* --- HOW IT WORKS SECTION (Based on Image) --- */}
|
|
46
|
+
<div className="relative my-8">
|
|
47
|
+
<div className="relative overflow-hidden border rounded-md border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-950">
|
|
48
|
+
|
|
49
|
+
{/* TOP-LEFT SLANTED ACCENT */}
|
|
50
|
+
<div
|
|
51
|
+
className="absolute left-0 top-0 h-[5px] w-24 bg-black"
|
|
52
|
+
style={{
|
|
53
|
+
clipPath: "polygon(0 0, 100% 0, 90% 100%, 0 100%)",
|
|
54
|
+
}}
|
|
55
|
+
/>
|
|
56
|
+
|
|
57
|
+
{/* BOTTOM-RIGHT SLANTED ACCENT */}
|
|
58
|
+
<div
|
|
59
|
+
className="absolute bottom-0 right-0 h-[5px] w-24 bg-black"
|
|
60
|
+
style={{
|
|
61
|
+
clipPath: "polygon(10% 0, 100% 0, 100% 100%, 0 100%)",
|
|
62
|
+
}}
|
|
63
|
+
/>
|
|
64
|
+
|
|
65
|
+
<div className="px-6 py-5 md:px-7 md:py-6">
|
|
66
|
+
<h2 className="mb-4 text-[16px] leading-relaxed text-zinc-600 dark:text-zinc-400">
|
|
67
|
+
How It Works
|
|
68
|
+
</h2>
|
|
69
|
+
|
|
70
|
+
<div>
|
|
71
|
+
{/* Feature 1 */}
|
|
72
|
+
<div className="pb-4">
|
|
73
|
+
<p className="text-[14px] leading-6 text-zinc-700 dark:text-zinc-300">
|
|
74
|
+
<span className="font-bold text-zinc-900 dark:text-white">
|
|
75
|
+
Simple access
|
|
76
|
+
</span>{" "}
|
|
77
|
+
to universal and reusable components & patterns available whenever
|
|
78
|
+
you need them.
|
|
79
|
+
</p>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<div className="border-t border-dashed border-zinc-200 dark:border-zinc-800" />
|
|
83
|
+
|
|
84
|
+
{/* Feature 2 */}
|
|
85
|
+
<div className="py-4">
|
|
86
|
+
<p className="text-[14px] leading-6 text-zinc-700 dark:text-zinc-300">
|
|
87
|
+
<span className="font-bold text-zinc-900 dark:text-white">
|
|
88
|
+
Instructions and guidance
|
|
89
|
+
</span>{" "}
|
|
90
|
+
to help you understand how elements are intended to behave, what
|
|
91
|
+
they look like and how they are coded.
|
|
92
|
+
</p>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<div className="border-t border-dashed border-zinc-200 dark:border-zinc-800" />
|
|
96
|
+
|
|
97
|
+
{/* Feature 3 */}
|
|
98
|
+
<div className="pt-4">
|
|
99
|
+
<p className="text-[14px] leading-6 text-zinc-700 dark:text-zinc-300">
|
|
100
|
+
{" "}
|
|
101
|
+
<span className="font-bold text-zinc-900 dark:text-white">
|
|
102
|
+
dedicated team
|
|
103
|
+
</span>{" "}
|
|
104
|
+
of designers and developers who manage the UI library and are here
|
|
105
|
+
to provide assistance when needed.
|
|
106
|
+
</p>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
{/* --- ORIGINAL REMAINING SECTIONS (No changes below this) --- */}
|
|
114
|
+
<DocsSection
|
|
115
|
+
title="Explore every component"
|
|
116
|
+
description={`${COMPONENT_COUNT} components, fully typed and ready to import.`}
|
|
117
|
+
>
|
|
118
|
+
<div className="grid grid-cols-2 gap-2 sm:grid-cols-3 lg:grid-cols-4">
|
|
119
|
+
{DOCS_NAV[0].items
|
|
120
|
+
.filter((item) => item.slug)
|
|
121
|
+
.map((item) => (
|
|
122
|
+
<Link
|
|
123
|
+
key={item.slug}
|
|
124
|
+
href={`/docs/${item.slug}`}
|
|
125
|
+
className="group flex items-center gap-3 rounded-xl border border-zinc-200 p-3.5 transition-colors hover:border-zinc-300 hover:bg-zinc-50 dark:border-zinc-800 dark:hover:border-zinc-700 dark:hover:bg-zinc-900/40"
|
|
126
|
+
>
|
|
127
|
+
<span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-zinc-200 bg-zinc-50 text-zinc-500 transition-colors group-hover:text-zinc-900 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-400 dark:group-hover:text-white">
|
|
128
|
+
<item.icon className="h-4 w-4" />
|
|
129
|
+
</span>
|
|
130
|
+
<span className="text-sm font-medium text-zinc-700 group-hover:text-zinc-900 dark:text-zinc-300 dark:group-hover:text-white">
|
|
131
|
+
{item.title}
|
|
132
|
+
</span>
|
|
133
|
+
</Link>
|
|
134
|
+
))}
|
|
135
|
+
</div>
|
|
136
|
+
</DocsSection>
|
|
137
|
+
|
|
138
|
+
<DocsSection>
|
|
139
|
+
<div className="rounded-3xl border border-zinc-200/70 bg-gradient-to-b from-zinc-50/80 to-white p-8 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">
|
|
140
|
+
<InstallationSection as="h2" />
|
|
141
|
+
</div>
|
|
142
|
+
</DocsSection>
|
|
143
|
+
|
|
144
|
+
<UsageSection />
|
|
145
|
+
<NextSteps />
|
|
146
|
+
</DocsPage>
|
|
147
|
+
);
|
|
148
|
+
}
|
package/app/favicon.ico
ADDED
|
Binary file
|
package/app/globals.css
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
|
|
3
|
+
@custom-variant dark (&:where(.dark, .dark *));
|
|
4
|
+
|
|
5
|
+
:root {
|
|
6
|
+
--background: #ffffff;
|
|
7
|
+
--foreground: #09090b;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.dark {
|
|
11
|
+
--background: #09090b;
|
|
12
|
+
--foreground: #fafafa;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@theme inline {
|
|
16
|
+
--color-background: var(--background);
|
|
17
|
+
--color-foreground: var(--foreground);
|
|
18
|
+
--font-sans: var(--font-poppins), ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
19
|
+
--font-mono: var(--font-geist-mono), ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
20
|
+
--font-brand: var(--font-orbitron), var(--font-poppins), ui-sans-serif, sans-serif;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
html {
|
|
24
|
+
overflow-x: clip;
|
|
25
|
+
max-width: 100%;
|
|
26
|
+
-webkit-text-size-adjust: 100%;
|
|
27
|
+
text-size-adjust: 100%;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
body {
|
|
31
|
+
background: var(--background);
|
|
32
|
+
color: var(--foreground);
|
|
33
|
+
min-width: 0;
|
|
34
|
+
max-width: 100%;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@layer base {
|
|
38
|
+
img {
|
|
39
|
+
max-width: 100%;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@layer utilities {
|
|
44
|
+
.docs-scrollbar {
|
|
45
|
+
scrollbar-width: thin;
|
|
46
|
+
scrollbar-color: rgb(161 161 170 / 0.35) transparent;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.docs-scrollbar::-webkit-scrollbar {
|
|
50
|
+
width: 6px;
|
|
51
|
+
height: 6px;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.docs-scrollbar::-webkit-scrollbar-track {
|
|
55
|
+
background: transparent;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.docs-scrollbar::-webkit-scrollbar-thumb {
|
|
59
|
+
background-color: rgb(161 161 170 / 0.35);
|
|
60
|
+
border-radius: 9999px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.docs-scrollbar::-webkit-scrollbar-thumb:hover {
|
|
64
|
+
background-color: rgb(161 161 170 / 0.55);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.docs-shell-glow {
|
|
68
|
+
background-image:
|
|
69
|
+
radial-gradient(circle 620px at 12% -10%, rgb(0 0 0 / 0.05), transparent 60%),
|
|
70
|
+
radial-gradient(circle 560px at 100% 0%, rgb(0 0 0 / 0.035), transparent 55%);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.dark .docs-shell-glow {
|
|
74
|
+
background-image:
|
|
75
|
+
radial-gradient(circle 620px at 12% -10%, rgb(255 255 255 / 0.05), transparent 60%),
|
|
76
|
+
radial-gradient(circle 560px at 100% 0%, rgb(255 255 255 / 0.03), transparent 55%);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.hero-spotlight-grid {
|
|
80
|
+
background-image:
|
|
81
|
+
linear-gradient(to right, rgb(255 255 255 / 0.3) 1px, transparent 1px),
|
|
82
|
+
linear-gradient(to bottom, rgb(255 255 255 / 0.3) 1px, transparent 1px);
|
|
83
|
+
background-size: 40px 40px;
|
|
84
|
+
opacity: 0;
|
|
85
|
+
will-change: mask-position, opacity;
|
|
86
|
+
-webkit-mask-image: radial-gradient(circle 280px at 280px 280px, black, transparent 72%);
|
|
87
|
+
mask-image: radial-gradient(circle 280px at 280px 280px, black, transparent 72%);
|
|
88
|
+
-webkit-mask-repeat: no-repeat;
|
|
89
|
+
mask-repeat: no-repeat;
|
|
90
|
+
-webkit-mask-size: 560px 560px;
|
|
91
|
+
mask-size: 560px 560px;
|
|
92
|
+
-webkit-mask-position: var(--mask-x, calc(50% - 280px)) var(--mask-y, -280px);
|
|
93
|
+
mask-position: var(--mask-x, calc(50% - 280px)) var(--mask-y, -280px);
|
|
94
|
+
transition:
|
|
95
|
+
opacity 800ms ease,
|
|
96
|
+
-webkit-mask-position 900ms cubic-bezier(0.16, 1, 0.3, 1),
|
|
97
|
+
mask-position 900ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.hero-spotlight-grid.is-active {
|
|
101
|
+
opacity: 1;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Fluid type scale — smooth clamp() growth instead of hard breakpoint jumps */
|
|
105
|
+
.text-fluid-h1 {
|
|
106
|
+
font-size: clamp(2.25rem, 1.7rem + 2vw, 3.75rem);
|
|
107
|
+
line-height: 1.1;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.text-fluid-h2 {
|
|
111
|
+
font-size: clamp(1.875rem, 1.5rem + 1.4vw, 2.75rem);
|
|
112
|
+
line-height: 1.15;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.hero-particle {
|
|
116
|
+
position: absolute;
|
|
117
|
+
margin: -2px;
|
|
118
|
+
border-radius: 9999px;
|
|
119
|
+
background: white;
|
|
120
|
+
filter: blur(0.3px);
|
|
121
|
+
pointer-events: none;
|
|
122
|
+
opacity: 0;
|
|
123
|
+
animation: hero-particle-drift var(--dur, 2200ms) ease-out forwards;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@keyframes hero-particle-drift {
|
|
128
|
+
0% {
|
|
129
|
+
transform: translate(0, 0);
|
|
130
|
+
opacity: 0;
|
|
131
|
+
}
|
|
132
|
+
15% {
|
|
133
|
+
opacity: var(--peak-opacity, 0.7);
|
|
134
|
+
}
|
|
135
|
+
50% {
|
|
136
|
+
transform: translate(var(--dx1, 10px), var(--dy1, 20px));
|
|
137
|
+
}
|
|
138
|
+
100% {
|
|
139
|
+
transform: translate(var(--dx2, 15px), var(--dy2, 60px));
|
|
140
|
+
opacity: 0;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
@keyframes progress-indeterminate {
|
|
145
|
+
0% {
|
|
146
|
+
transform: translateX(-120%);
|
|
147
|
+
}
|
|
148
|
+
100% {
|
|
149
|
+
transform: translateX(350%);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
@keyframes pagination-pop {
|
|
154
|
+
from {
|
|
155
|
+
opacity: 0;
|
|
156
|
+
transform: scale(0.85);
|
|
157
|
+
}
|
|
158
|
+
to {
|
|
159
|
+
opacity: 1;
|
|
160
|
+
transform: scale(1);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
::view-transition-group(*) {
|
|
165
|
+
animation-duration: 220ms;
|
|
166
|
+
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
|
167
|
+
}
|
|
168
|
+
|
package/app/icon.png
ADDED
|
Binary file
|
package/app/layout.tsx
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { Metadata, Viewport } from "next";
|
|
2
|
+
import { cookies } from "next/headers";
|
|
3
|
+
import { Geist_Mono, Orbitron, Poppins } from "next/font/google";
|
|
4
|
+
import { ThemeProvider } from "@/components/theme-provider";
|
|
5
|
+
import { parseTheme, THEME_COOKIE_KEY } from "@/lib/theme";
|
|
6
|
+
import "./globals.css";
|
|
7
|
+
|
|
8
|
+
const poppins = Poppins({
|
|
9
|
+
variable: "--font-poppins",
|
|
10
|
+
subsets: ["latin"],
|
|
11
|
+
weight: ["400", "500", "600", "700"],
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const geistMono = Geist_Mono({
|
|
15
|
+
variable: "--font-geist-mono",
|
|
16
|
+
subsets: ["latin"],
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const orbitron = Orbitron({
|
|
20
|
+
variable: "--font-orbitron",
|
|
21
|
+
subsets: ["latin"],
|
|
22
|
+
weight: ["600", "700"],
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const SITE_URL = "https://ruler-ui.vercel.app";
|
|
26
|
+
const SITE_TITLE = "Ruler.ui";
|
|
27
|
+
const SITE_DESCRIPTION =
|
|
28
|
+
"A sharper way to build interfaces. Precision-crafted React components for modern products.";
|
|
29
|
+
|
|
30
|
+
export const viewport: Viewport = {
|
|
31
|
+
width: "device-width",
|
|
32
|
+
initialScale: 1,
|
|
33
|
+
maximumScale: 5,
|
|
34
|
+
viewportFit: "cover",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const metadata: Metadata = {
|
|
38
|
+
metadataBase: new URL(SITE_URL),
|
|
39
|
+
title: {
|
|
40
|
+
default: SITE_TITLE,
|
|
41
|
+
template: `%s · ${SITE_TITLE}`,
|
|
42
|
+
},
|
|
43
|
+
description: SITE_DESCRIPTION,
|
|
44
|
+
openGraph: {
|
|
45
|
+
title: SITE_TITLE,
|
|
46
|
+
description: SITE_DESCRIPTION,
|
|
47
|
+
url: SITE_URL,
|
|
48
|
+
siteName: SITE_TITLE,
|
|
49
|
+
type: "website",
|
|
50
|
+
images: [
|
|
51
|
+
{
|
|
52
|
+
url: "/opengraph-image",
|
|
53
|
+
width: 1200,
|
|
54
|
+
height: 630,
|
|
55
|
+
alt: "Ruler.ui — A sharper way to build interfaces.",
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
twitter: {
|
|
60
|
+
card: "summary_large_image",
|
|
61
|
+
title: SITE_TITLE,
|
|
62
|
+
description: SITE_DESCRIPTION,
|
|
63
|
+
images: ["/twitter-image"],
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export default async function RootLayout({
|
|
68
|
+
children,
|
|
69
|
+
}: Readonly<{
|
|
70
|
+
children: React.ReactNode;
|
|
71
|
+
}>) {
|
|
72
|
+
const cookieStore = await cookies();
|
|
73
|
+
const theme = parseTheme(cookieStore.get(THEME_COOKIE_KEY)?.value);
|
|
74
|
+
const isDark = theme === "dark";
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<html
|
|
78
|
+
lang="en"
|
|
79
|
+
className={`${poppins.variable} ${geistMono.variable} ${orbitron.variable} max-w-full antialiased${isDark ? " dark" : ""}`}
|
|
80
|
+
suppressHydrationWarning
|
|
81
|
+
>
|
|
82
|
+
<body
|
|
83
|
+
className="min-h-dvh min-w-0 max-w-full bg-white text-zinc-900 dark:bg-zinc-950 dark:text-zinc-50"
|
|
84
|
+
suppressHydrationWarning
|
|
85
|
+
>
|
|
86
|
+
<ThemeProvider defaultTheme={theme}>{children}</ThemeProvider>
|
|
87
|
+
</body>
|
|
88
|
+
</html>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
@@ -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
|
+
}
|