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.
Files changed (118) hide show
  1. package/dist/index.d.mts +51 -0
  2. package/dist/index.d.ts +51 -0
  3. package/dist/index.js +534 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/index.mjs +498 -0
  6. package/dist/index.mjs.map +1 -0
  7. package/package.json +21 -2
  8. package/AGENTS.md +0 -9
  9. package/CLAUDE.md +0 -1
  10. package/app/docs/[slug]/page.tsx +0 -147
  11. package/app/docs/layout.tsx +0 -26
  12. package/app/docs/page.tsx +0 -148
  13. package/app/favicon.ico +0 -0
  14. package/app/globals.css +0 -168
  15. package/app/icon.png +0 -0
  16. package/app/layout.tsx +0 -90
  17. package/app/opengraph-image.tsx +0 -10
  18. package/app/page.tsx +0 -34
  19. package/app/twitter-image.tsx +0 -10
  20. package/components/docs/accordion-doc-page.tsx +0 -352
  21. package/components/docs/alert-doc-page.tsx +0 -293
  22. package/components/docs/allinput-doc-page.tsx +0 -183
  23. package/components/docs/avatar-doc-page.tsx +0 -424
  24. package/components/docs/badge-doc-page.tsx +0 -363
  25. package/components/docs/button-doc-page.tsx +0 -406
  26. package/components/docs/card-doc-page.tsx +0 -364
  27. package/components/docs/checkbox-doc-page.tsx +0 -277
  28. package/components/docs/colors-doc-page.tsx +0 -430
  29. package/components/docs/dialog-doc-page.tsx +0 -364
  30. package/components/docs/docs-footer.tsx +0 -11
  31. package/components/docs/docs-mobile-menu-bar.tsx +0 -22
  32. package/components/docs/docs-mobile-nav-context.tsx +0 -27
  33. package/components/docs/docs-page.tsx +0 -263
  34. package/components/docs/docs-search.tsx +0 -303
  35. package/components/docs/docs-sidebar.tsx +0 -165
  36. package/components/docs/docs-topbar.tsx +0 -32
  37. package/components/docs/dropdown-doc-page.tsx +0 -522
  38. package/components/docs/getting-started-doc-page.tsx +0 -205
  39. package/components/docs/label-doc-page.tsx +0 -173
  40. package/components/docs/loaders-doc-page.tsx +0 -244
  41. package/components/docs/menu-doc-page.tsx +0 -373
  42. package/components/docs/modal-doc-page.tsx +0 -436
  43. package/components/docs/next-steps.tsx +0 -53
  44. package/components/docs/pagination-doc-page.tsx +0 -316
  45. package/components/docs/progress-doc-page.tsx +0 -387
  46. package/components/docs/radio-doc-page.tsx +0 -270
  47. package/components/docs/skeleton-doc-page.tsx +0 -230
  48. package/components/docs/stepper-doc-page.tsx +0 -309
  49. package/components/docs/switch-doc-page.tsx +0 -264
  50. package/components/docs/table-doc-page.tsx +0 -689
  51. package/components/docs/tabs-doc-page.tsx +0 -359
  52. package/components/docs/theming-doc-page.tsx +0 -243
  53. package/components/docs/tooltip-doc-page.tsx +0 -357
  54. package/components/docs/usage-section.tsx +0 -21
  55. package/components/icons/discord.tsx +0 -9
  56. package/components/icons/github.tsx +0 -9
  57. package/components/icons/x.tsx +0 -9
  58. package/components/installation-section.tsx +0 -34
  59. package/components/landing/feature-highlights.tsx +0 -105
  60. package/components/landing/footer-strip.tsx +0 -45
  61. package/components/landing/hero-card.tsx +0 -14
  62. package/components/landing/hero-spotlight.tsx +0 -126
  63. package/components/landing/hero.tsx +0 -64
  64. package/components/landing/navbar.tsx +0 -44
  65. package/components/landing/quick-start-section.tsx +0 -59
  66. package/components/landing/site-footer.tsx +0 -55
  67. package/components/theme-provider.tsx +0 -60
  68. package/components/ui/accordion.tsx +0 -174
  69. package/components/ui/alert.tsx +0 -103
  70. package/components/ui/allinput.tsx +0 -210
  71. package/components/ui/avatar.tsx +0 -179
  72. package/components/ui/badge.tsx +0 -52
  73. package/components/ui/button.tsx +0 -75
  74. package/components/ui/card.tsx +0 -105
  75. package/components/ui/checkbox.tsx +0 -130
  76. package/components/ui/code-block.tsx +0 -60
  77. package/components/ui/data-table.tsx +0 -235
  78. package/components/ui/dialog.tsx +0 -173
  79. package/components/ui/dropdown.tsx +0 -78
  80. package/components/ui/feature-card.tsx +0 -38
  81. package/components/ui/input.tsx +0 -44
  82. package/components/ui/label.tsx +0 -110
  83. package/components/ui/loaders.tsx +0 -139
  84. package/components/ui/menu.tsx +0 -118
  85. package/components/ui/modal.tsx +0 -399
  86. package/components/ui/package-manager-tabs.tsx +0 -40
  87. package/components/ui/pagination.tsx +0 -200
  88. package/components/ui/progress.tsx +0 -134
  89. package/components/ui/radio.tsx +0 -262
  90. package/components/ui/skeleton.tsx +0 -102
  91. package/components/ui/steppers.tsx +0 -309
  92. package/components/ui/switch.tsx +0 -153
  93. package/components/ui/table.tsx +0 -58
  94. package/components/ui/tabs.tsx +0 -166
  95. package/components/ui/theme-toggle.tsx +0 -60
  96. package/components/ui/tooltip.tsx +0 -238
  97. package/data/color-palette.ts +0 -35
  98. package/data/docs-nav.ts +0 -84
  99. package/eslint.config.mjs +0 -18
  100. package/index.ts +0 -8
  101. package/lib/cn.ts +0 -4
  102. package/lib/color.ts +0 -85
  103. package/lib/og-image.tsx +0 -138
  104. package/lib/theme.ts +0 -33
  105. package/next.config.ts +0 -7
  106. package/postcss.config.mjs +0 -7
  107. package/public/dark.png +0 -0
  108. package/public/dark1.png +0 -0
  109. package/public/dark2.png +0 -0
  110. package/public/file.svg +0 -1
  111. package/public/globe.svg +0 -1
  112. package/public/light.png +0 -0
  113. package/public/light1.png +0 -0
  114. package/public/next.svg +0 -1
  115. package/public/vercel.svg +0 -1
  116. package/public/video/hero-demo.mp4 +0 -0
  117. package/public/window.svg +0 -1
  118. package/tsconfig.json +0 -34
@@ -1,60 +0,0 @@
1
- "use client";
2
-
3
- import { useSyncExternalStore } from "react";
4
- import { useTheme } from "@/components/theme-provider";
5
- import { Moon, Sun } from "lucide-react";
6
- import { cn } from "@/lib/cn";
7
-
8
- const emptySubscribe = () => () => {};
9
- function useMounted() {
10
- return useSyncExternalStore(emptySubscribe, () => true, () => false);
11
- }
12
-
13
- export function ThemeToggle({ inverted = false }: { inverted?: boolean }) {
14
- const { theme, setTheme } = useTheme();
15
- const mounted = useMounted();
16
- const current = mounted ? theme : "light";
17
-
18
- const track = inverted ? "bg-zinc-800" : "bg-zinc-100 dark:bg-zinc-800";
19
- const inactive = inverted
20
- ? "text-zinc-400 hover:text-zinc-200"
21
- : "text-zinc-400 hover:text-zinc-600 dark:text-zinc-500 dark:hover:text-zinc-300";
22
- const active = inverted
23
- ? "bg-zinc-700 text-white"
24
- : "bg-white text-zinc-900 shadow-sm dark:bg-zinc-950 dark:text-zinc-50";
25
-
26
- return (
27
- <div
28
- className={cn("inline-flex items-center gap-0.5 rounded-full p-0.5", track)}
29
- role="radiogroup"
30
- aria-label="Theme"
31
- >
32
- <button
33
- type="button"
34
- role="radio"
35
- aria-checked={current === "light"}
36
- aria-label="Light theme"
37
- onClick={() => setTheme("light")}
38
- className={cn(
39
- "flex h-6 w-6 items-center justify-center rounded-full transition-colors",
40
- current === "light" ? active : inactive,
41
- )}
42
- >
43
- <Sun className="h-3.5 w-3.5" />
44
- </button>
45
- <button
46
- type="button"
47
- role="radio"
48
- aria-checked={current === "dark"}
49
- aria-label="Dark theme"
50
- onClick={() => setTheme("dark")}
51
- className={cn(
52
- "flex h-6 w-6 items-center justify-center rounded-full transition-colors",
53
- current === "dark" ? active : inactive,
54
- )}
55
- >
56
- <Moon className="h-3.5 w-3.5" />
57
- </button>
58
- </div>
59
- );
60
- }
@@ -1,238 +0,0 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
- import { createPortal } from "react-dom";
5
- import { cva, type VariantProps } from "class-variance-authority";
6
- import { cn } from "@/lib/cn";
7
-
8
- const tooltipVariants = cva(
9
- [
10
- "pointer-events-none fixed z-50 max-w-[260px] rounded-lg px-3 py-2",
11
- "text-[13px] font-medium leading-normal tracking-tight",
12
- "bg-zinc-900 text-zinc-50",
13
- "shadow-[0_4px_16px_rgba(0,0,0,0.14),0_0_0_1px_rgba(255,255,255,0.06)]",
14
- "dark:bg-zinc-100 dark:text-zinc-900",
15
- "dark:shadow-[0_4px_16px_rgba(0,0,0,0.35),0_0_0_1px_rgba(0,0,0,0.06)]",
16
- "transition-[opacity,transform] duration-200 ease-[cubic-bezier(0.16,1,0.3,1)]",
17
- "will-change-[opacity,transform]",
18
- ],
19
- {
20
- variants: {
21
- visible: {
22
- true: "opacity-100 scale-100",
23
- false: "opacity-0 scale-[0.97]",
24
- },
25
- side: {
26
- top: "origin-bottom",
27
- bottom: "origin-top",
28
- left: "origin-right",
29
- right: "origin-left",
30
- },
31
- },
32
- defaultVariants: { visible: false, side: "top" },
33
- },
34
- );
35
-
36
- type TooltipSide = "top" | "bottom" | "left" | "right";
37
- type TooltipAlign = "start" | "center" | "end";
38
-
39
- const VIEWPORT_PADDING = 10;
40
- const ARROW_SIZE = 6;
41
-
42
- export interface TooltipProps extends VariantProps<typeof tooltipVariants> {
43
- content: React.ReactNode;
44
- children: React.ReactNode;
45
- side?: TooltipSide;
46
- align?: TooltipAlign;
47
- sideOffset?: number;
48
- delayDuration?: number;
49
- disabled?: boolean;
50
- className?: string;
51
- }
52
-
53
- function getTooltipPosition(
54
- triggerRect: DOMRect,
55
- tooltipRect: DOMRect,
56
- side: TooltipSide,
57
- align: TooltipAlign,
58
- sideOffset: number,
59
- ) {
60
- const offset = sideOffset + ARROW_SIZE;
61
- let top = 0;
62
- let left = 0;
63
-
64
- if (side === "top") {
65
- top = triggerRect.top - tooltipRect.height - offset;
66
- left = alignTooltipHorizontal(triggerRect, tooltipRect, align);
67
- } else if (side === "bottom") {
68
- top = triggerRect.bottom + offset;
69
- left = alignTooltipHorizontal(triggerRect, tooltipRect, align);
70
- } else if (side === "left") {
71
- top = alignTooltipVertical(triggerRect, tooltipRect, align);
72
- left = triggerRect.left - tooltipRect.width - offset;
73
- } else {
74
- top = alignTooltipVertical(triggerRect, tooltipRect, align);
75
- left = triggerRect.right + offset;
76
- }
77
-
78
- const maxLeft = window.innerWidth - tooltipRect.width - VIEWPORT_PADDING;
79
- const maxTop = window.innerHeight - tooltipRect.height - VIEWPORT_PADDING;
80
-
81
- return {
82
- top: Math.min(Math.max(top, VIEWPORT_PADDING), maxTop),
83
- left: Math.min(Math.max(left, VIEWPORT_PADDING), maxLeft),
84
- };
85
- }
86
-
87
- function alignTooltipHorizontal(
88
- triggerRect: DOMRect,
89
- tooltipRect: DOMRect,
90
- align: TooltipAlign,
91
- ) {
92
- if (align === "start") return triggerRect.left;
93
- if (align === "end") return triggerRect.right - tooltipRect.width;
94
- return triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;
95
- }
96
-
97
- function alignTooltipVertical(
98
- triggerRect: DOMRect,
99
- tooltipRect: DOMRect,
100
- align: TooltipAlign,
101
- ) {
102
- if (align === "start") return triggerRect.top;
103
- if (align === "end") return triggerRect.bottom - tooltipRect.height;
104
- return triggerRect.top + triggerRect.height / 2 - tooltipRect.height / 2;
105
- }
106
-
107
- function TooltipArrow({ side }: { side: TooltipSide }) {
108
- const position = {
109
- top: "bottom-0 left-1/2 -translate-x-1/2 translate-y-[calc(100%-1px)]",
110
- bottom: "top-0 left-1/2 -translate-x-1/2 -translate-y-[calc(100%-1px)] rotate-180",
111
- left: "right-0 top-1/2 -translate-y-1/2 translate-x-[calc(100%-1px)] -rotate-90",
112
- right: "left-0 top-1/2 -translate-y-1/2 -translate-x-[calc(100%-1px)] rotate-90",
113
- }[side];
114
-
115
- return (
116
- <svg
117
- aria-hidden
118
- width="10"
119
- height="5"
120
- viewBox="0 0 10 5"
121
- className={cn(
122
- "absolute text-zinc-900 dark:text-zinc-100",
123
- position,
124
- )}
125
- >
126
- <path fill="currentColor" d="M0 0h10L5 5 0 0z" />
127
- </svg>
128
- );
129
- }
130
-
131
- function Tooltip({
132
- content,
133
- children,
134
- side = "top",
135
- align = "center",
136
- sideOffset = 8,
137
- delayDuration = 250,
138
- disabled = false,
139
- className,
140
- }: TooltipProps) {
141
- const [open, setOpen] = React.useState(false);
142
- const [visible, setVisible] = React.useState(false);
143
- const [mounted, setMounted] = React.useState(false);
144
- const [position, setPosition] = React.useState({ top: -9999, left: -9999 });
145
- const timeoutRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);
146
- const triggerRef = React.useRef<HTMLSpanElement>(null);
147
- const tooltipRef = React.useRef<HTMLDivElement>(null);
148
- const id = React.useId();
149
-
150
- React.useEffect(() => setMounted(true), []);
151
-
152
- const clearTimer = () => {
153
- if (timeoutRef.current) {
154
- clearTimeout(timeoutRef.current);
155
- timeoutRef.current = null;
156
- }
157
- };
158
-
159
- const updatePosition = React.useCallback(() => {
160
- const trigger = triggerRef.current;
161
- const tooltip = tooltipRef.current;
162
- if (!trigger || !tooltip) return;
163
-
164
- const triggerRect = trigger.getBoundingClientRect();
165
- const tooltipRect = tooltip.getBoundingClientRect();
166
- setPosition(getTooltipPosition(triggerRect, tooltipRect, side, align, sideOffset));
167
- requestAnimationFrame(() => setVisible(true));
168
- }, [side, align, sideOffset]);
169
-
170
- const show = () => {
171
- if (disabled) return;
172
- clearTimer();
173
- timeoutRef.current = setTimeout(() => {
174
- setVisible(false);
175
- setOpen(true);
176
- }, delayDuration);
177
- };
178
-
179
- const hide = () => {
180
- clearTimer();
181
- setVisible(false);
182
- setOpen(false);
183
- };
184
-
185
- React.useEffect(() => clearTimer, []);
186
-
187
- React.useLayoutEffect(() => {
188
- if (!open) return;
189
- updatePosition();
190
- const handleUpdate = () => updatePosition();
191
- window.addEventListener("scroll", handleUpdate, true);
192
- window.addEventListener("resize", handleUpdate);
193
- return () => {
194
- window.removeEventListener("scroll", handleUpdate, true);
195
- window.removeEventListener("resize", handleUpdate);
196
- };
197
- }, [open, updatePosition, content]);
198
-
199
- const child = React.Children.only(children);
200
- const trigger = React.isValidElement(child)
201
- ? React.cloneElement(
202
- child as React.ReactElement<{ "aria-describedby"?: string }>,
203
- { "aria-describedby": open && visible ? id : undefined },
204
- )
205
- : children;
206
-
207
- const tooltipNode = open ? (
208
- <div
209
- ref={tooltipRef}
210
- id={id}
211
- role="tooltip"
212
- aria-hidden={!visible}
213
- style={{ top: position.top, left: position.left }}
214
- className={cn(tooltipVariants({ visible, side }), className)}
215
- >
216
- {content}
217
- <TooltipArrow side={side} />
218
- </div>
219
- ) : null;
220
-
221
- return (
222
- <>
223
- <span
224
- ref={triggerRef}
225
- className="inline-flex"
226
- onMouseEnter={show}
227
- onMouseLeave={hide}
228
- onFocus={show}
229
- onBlur={hide}
230
- >
231
- {trigger}
232
- </span>
233
- {mounted && tooltipNode ? createPortal(tooltipNode, document.body) : null}
234
- </>
235
- );
236
- }
237
-
238
- export { Tooltip, tooltipVariants };
@@ -1,35 +0,0 @@
1
- export interface ColorShade {
2
- step: number;
3
- hex: string;
4
- }
5
-
6
- export interface ColorHue {
7
- name: string;
8
- shades: ColorShade[];
9
- }
10
-
11
- const STEPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
12
-
13
- function hue(name: string, hexes: string[]): ColorHue {
14
- return {
15
- name,
16
- shades: STEPS.map((step, i) => ({ step, hex: hexes[i] })),
17
- };
18
- }
19
-
20
- /**
21
- * Curated primary set — one clearly distinct hue per color family,
22
- * so the overview strip never shows two near-identical colors side by side.
23
- */
24
- export const COLOR_PALETTE: ColorHue[] = [
25
- hue("Red", ["#fef2f2", "#fee2e2", "#fecaca", "#fca5a5", "#f87171", "#ef4444", "#dc2626", "#b91c1c", "#991b1b", "#7f1d1d", "#450a0a"]),
26
- hue("Orange", ["#fff7ed", "#ffedd5", "#fed7aa", "#fdba74", "#fb923c", "#f97316", "#ea580c", "#c2410c", "#9a3412", "#7c2d12", "#431407"]),
27
- hue("Yellow", ["#fefce8", "#fef9c3", "#fef08a", "#fde047", "#facc15", "#eab308", "#ca8a04", "#a16207", "#854d0e", "#713f12", "#422006"]),
28
- hue("Green", ["#f0fdf4", "#dcfce7", "#bbf7d0", "#86efac", "#4ade80", "#22c55e", "#16a34a", "#15803d", "#166534", "#14532d", "#052e16"]),
29
- hue("Teal", ["#f0fdfa", "#ccfbf1", "#99f6e4", "#5eead4", "#2dd4bf", "#14b8a6", "#0d9488", "#0f766e", "#115e59", "#134e4a", "#042f2e"]),
30
- hue("Blue", ["#eff6ff", "#dbeafe", "#bfdbfe", "#93c5fd", "#60a5fa", "#3b82f6", "#2563eb", "#1d4ed8", "#1e40af", "#1e3a8a", "#172554"]),
31
- hue("Indigo", ["#eef2ff", "#e0e7ff", "#c7d2fe", "#a5b4fc", "#818cf8", "#6366f1", "#4f46e5", "#4338ca", "#3730a3", "#312e81", "#1e1b4b"]),
32
- hue("Purple", ["#faf5ff", "#f3e8ff", "#e9d5ff", "#d8b4fe", "#c084fc", "#a855f7", "#9333ea", "#7e22ce", "#6b21a8", "#581c87", "#3b0764"]),
33
- hue("Pink", ["#fdf2f8", "#fce7f3", "#fbcfe8", "#f9a8d4", "#f472b6", "#ec4899", "#db2777", "#be185d", "#9d174d", "#831843", "#500724"]),
34
- hue("Gray", ["#fafafa", "#f4f4f5", "#e4e4e7", "#d4d4d8", "#a1a1aa", "#71717a", "#52525b", "#3f3f46", "#27272a", "#18181b", "#09090b"]),
35
- ];
package/data/docs-nav.ts DELETED
@@ -1,84 +0,0 @@
1
- import {
2
- AppWindow,
3
- BadgeCheck,
4
- ChevronDown,
5
- ChevronsUpDown,
6
- CircleDot,
7
- CircleUserRound,
8
- Columns3,
9
- Compass,
10
- GaugeCircle,
11
- Home,
12
- Layers,
13
- LayoutTemplate,
14
- ListFilter,
15
- Loader2,
16
- Menu,
17
- MessageCircle,
18
- MessageSquareText,
19
- MoreHorizontal,
20
- MousePointerClick,
21
- Move,
22
- Palette,
23
- Pipette,
24
- Rows3,
25
- Shapes,
26
- SquareCheck,
27
- Table2,
28
- Tag,
29
- TextCursorInput,
30
- TextQuote,
31
- ToggleLeft,
32
- TriangleAlert,
33
- type LucideIcon,
34
- } from "lucide-react";
35
-
36
- export interface DocsNavItem {
37
- title: string;
38
- slug: string;
39
- icon: LucideIcon;
40
- }
41
-
42
- export interface DocsNavGroup {
43
- title: string;
44
- items: DocsNavItem[];
45
- }
46
-
47
- export const DOCS_NAV: DocsNavGroup[] = [
48
- {
49
- title: "Components",
50
- items: [
51
- { title: "Introduction", slug: "", icon: Home },
52
- { title: "Getting Started", slug: "getting-started", icon: Compass },
53
- { title: "Accordion", slug: "accordion", icon: ChevronsUpDown },
54
- { title: "Alert", slug: "alert", icon: TriangleAlert },
55
- { title: "Avatar", slug: "avatar", icon: CircleUserRound },
56
- { title: "Badge", slug: "badge", icon: BadgeCheck },
57
- { title: "Button", slug: "button", icon: MousePointerClick },
58
- { title: "Card", slug: "card", icon: LayoutTemplate },
59
- { title: "Checkbox", slug: "checkbox", icon: SquareCheck },
60
- { title: "Dialog", slug: "dialog", icon: AppWindow },
61
- { title: "Loader", slug: "loader", icon: Loader2 },
62
- { title: "Dropdown", slug: "dropdown", icon: ChevronDown },
63
- { title: "Input", slug: "input", icon: TextCursorInput },
64
- { title: "Label", slug: "label", icon: Tag },
65
- { title: "Modal", slug: "modal", icon: Layers },
66
- { title: "Pagination", slug: "pagination", icon: MoreHorizontal },
67
- { title: "Progress", slug: "progress", icon: GaugeCircle },
68
- { title: "Radio", slug: "radio", icon: CircleDot },
69
- { title: "Skeleton", slug: "skeleton", icon: Rows3 },
70
- { title: "Switch", slug: "switch", icon: ToggleLeft },
71
- { title: "Table", slug: "table", icon: Table2 },
72
- { title: "Tabs", slug: "tabs", icon: Columns3 },
73
- { title: "Stepper", slug: "stepper", icon: TextQuote },
74
- { title: "Tooltip", slug: "tooltip", icon: MessageCircle },
75
- ],
76
- },
77
- {
78
- title: "Theming",
79
- items: [
80
- { title: "Theming", slug: "theming", icon: Palette },
81
- { title: "Colors", slug: "colors", icon: Pipette },
82
- ],
83
- },
84
- ];
package/eslint.config.mjs DELETED
@@ -1,18 +0,0 @@
1
- import { defineConfig, globalIgnores } from "eslint/config";
2
- import nextVitals from "eslint-config-next/core-web-vitals";
3
- import nextTs from "eslint-config-next/typescript";
4
-
5
- const eslintConfig = defineConfig([
6
- ...nextVitals,
7
- ...nextTs,
8
- // Override default ignores of eslint-config-next.
9
- globalIgnores([
10
- // Default ignores of eslint-config-next:
11
- ".next/**",
12
- "out/**",
13
- "build/**",
14
- "next-env.d.ts",
15
- ]),
16
- ]);
17
-
18
- export default eslintConfig;
package/index.ts DELETED
@@ -1,8 +0,0 @@
1
- export { Progress } from "./components/ui/progress";
2
- export type { ProgressProps } from "./components/ui/progress";
3
-
4
- export { Switch } from "./components/ui/switch";
5
- export type { SwitchProps } from "./components/ui/switch";
6
-
7
- export { Tooltip } from "./components/ui/tooltip";
8
- export type { TooltipProps } from "./components/ui/tooltip";
package/lib/cn.ts DELETED
@@ -1,4 +0,0 @@
1
- import { clsx, type ClassValue } from "clsx";
2
- import { twMerge } from "tailwind-merge";
3
-
4
- export const cn = (...inputs: ClassValue[]) => twMerge(clsx(inputs));
package/lib/color.ts DELETED
@@ -1,85 +0,0 @@
1
- export function hexToRgb(hex: string): [number, number, number] {
2
- const clean = hex.replace("#", "");
3
- const r = parseInt(clean.slice(0, 2), 16);
4
- const g = parseInt(clean.slice(2, 4), 16);
5
- const b = parseInt(clean.slice(4, 6), 16);
6
- return [r, g, b];
7
- }
8
-
9
- function rgbToHsl(r: number, g: number, b: number): [number, number, number] {
10
- const rn = r / 255;
11
- const gn = g / 255;
12
- const bn = b / 255;
13
- const max = Math.max(rn, gn, bn);
14
- const min = Math.min(rn, gn, bn);
15
- const l = (max + min) / 2;
16
-
17
- if (max === min) return [0, 0, Math.round(l * 100)];
18
-
19
- const d = max - min;
20
- const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
21
-
22
- let h = 0;
23
- switch (max) {
24
- case rn:
25
- h = (gn - bn) / d + (gn < bn ? 6 : 0);
26
- break;
27
- case gn:
28
- h = (bn - rn) / d + 2;
29
- break;
30
- default:
31
- h = (rn - gn) / d + 4;
32
- }
33
- h /= 6;
34
-
35
- return [Math.round(h * 360), Math.round(s * 100), Math.round(l * 100)];
36
- }
37
-
38
- export type ColorFormat = "hex" | "rgb" | "hsl" | "css";
39
-
40
- export function formatColor(hex: string, format: ColorFormat): string {
41
- const [r, g, b] = hexToRgb(hex);
42
-
43
- switch (format) {
44
- case "hex":
45
- return hex.toUpperCase();
46
- case "rgb":
47
- return `rgb(${r}, ${g}, ${b})`;
48
- case "hsl": {
49
- const [h, s, l] = rgbToHsl(r, g, b);
50
- return `hsl(${h}, ${s}%, ${l}%)`;
51
- }
52
- case "css":
53
- return `rgb(${r} ${g} ${b} / 1)`;
54
- }
55
- }
56
-
57
- function getLuminance(hex: string): number {
58
- const [r, g, b] = hexToRgb(hex).map((channel) => {
59
- const s = channel / 255;
60
- return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
61
- });
62
- return 0.2126 * r + 0.7152 * g + 0.0722 * b;
63
- }
64
-
65
- export function getContrastRatio(hexA: string, hexB: string): number {
66
- const a = getLuminance(hexA);
67
- const b = getLuminance(hexB);
68
- const lighter = Math.max(a, b);
69
- const darker = Math.min(a, b);
70
- return (lighter + 0.05) / (darker + 0.05);
71
- }
72
-
73
- export type ContrastLabel = "AAA" | "AA" | "Fail";
74
-
75
- export function contrastLabel(ratio: number): ContrastLabel {
76
- if (ratio >= 7) return "AAA";
77
- if (ratio >= 4.5) return "AA";
78
- return "Fail";
79
- }
80
-
81
- export function readableTextColor(hex: string): "#000000" | "#ffffff" {
82
- return getContrastRatio(hex, "#000000") >= getContrastRatio(hex, "#ffffff")
83
- ? "#000000"
84
- : "#ffffff";
85
- }
package/lib/og-image.tsx DELETED
@@ -1,138 +0,0 @@
1
- import { ImageResponse } from "next/og";
2
- import { readFile } from "node:fs/promises";
3
- import { join } from "node:path";
4
-
5
- export const ogSize = { width: 1200, height: 630 };
6
-
7
- export const ogAlt =
8
- "Ruler.ui — A sharper way to build interfaces. Precision-crafted React components for modern products.";
9
-
10
- async function loadGoogleFont(family: string, weight: number) {
11
- const query = family.replace(/ /g, "+");
12
- const css = await fetch(
13
- `https://fonts.googleapis.com/css2?family=${query}:wght@${weight}&display=swap`,
14
- {
15
- headers: {
16
- "User-Agent":
17
- "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1",
18
- },
19
- }
20
- ).then((res) => res.text());
21
-
22
- const match = css.match(/src: url\((.+?)\) format\('(opentype|truetype)'\)/);
23
- if (!match) {
24
- throw new Error(`Could not load ${family}`);
25
- }
26
-
27
- return fetch(match[1]).then((res) => res.arrayBuffer());
28
- }
29
-
30
- export async function createOgImage() {
31
- const [iconData, orbitron, inter] = await Promise.all([
32
- readFile(join(process.cwd(), "app/icon.png")),
33
- loadGoogleFont("Orbitron", 700),
34
- loadGoogleFont("Inter", 500),
35
- ]);
36
- const iconSrc = `data:image/png;base64,${iconData.toString("base64")}`;
37
-
38
- return new ImageResponse(
39
- (
40
- <div
41
- style={{
42
- width: "100%",
43
- height: "100%",
44
- display: "flex",
45
- alignItems: "center",
46
- justifyContent: "center",
47
- backgroundColor: "#09090b",
48
- backgroundImage:
49
- "linear-gradient(to right, rgba(255,255,255,0.05) 1px, transparent 1px), linear-gradient(to bottom, rgba(255,255,255,0.05) 1px, transparent 1px)",
50
- backgroundSize: "56px 56px",
51
- }}
52
- >
53
- <div
54
- style={{
55
- display: "flex",
56
- flexDirection: "column",
57
- alignItems: "center",
58
- width: 1040,
59
- }}
60
- >
61
- <div
62
- style={{
63
- display: "flex",
64
- width: 112,
65
- height: 112,
66
- borderRadius: 28,
67
- overflow: "hidden",
68
- marginBottom: 36,
69
- boxShadow: "0 12px 48px rgba(0,0,0,0.5)",
70
- }}
71
- >
72
- {/* eslint-disable-next-line @next/next/no-img-element */}
73
- <img src={iconSrc} width={112} height={112} alt="" />
74
- </div>
75
-
76
- <div
77
- style={{
78
- display: "flex",
79
- fontFamily: "Orbitron",
80
- fontSize: 84,
81
- fontWeight: 700,
82
- color: "#fafafa",
83
- letterSpacing: "0.04em",
84
- lineHeight: 1,
85
- }}
86
- >
87
- Ruler.ui
88
- </div>
89
-
90
- <div
91
- style={{
92
- display: "flex",
93
- marginTop: 28,
94
- fontFamily: "Inter",
95
- fontSize: 34,
96
- fontWeight: 500,
97
- color: "#e4e4e7",
98
- letterSpacing: "-0.03em",
99
- lineHeight: 1.2,
100
- }}
101
- >
102
- A sharper way to build interfaces.
103
- </div>
104
-
105
- <div
106
- style={{
107
- display: "flex",
108
- marginTop: 12,
109
- fontFamily: "Inter",
110
- fontSize: 24,
111
- color: "#a1a1aa",
112
- letterSpacing: "-0.01em",
113
- }}
114
- >
115
- Precision-crafted React components for modern products.
116
- </div>
117
- </div>
118
- </div>
119
- ),
120
- {
121
- ...ogSize,
122
- fonts: [
123
- {
124
- name: "Orbitron",
125
- data: orbitron,
126
- style: "normal",
127
- weight: 700,
128
- },
129
- {
130
- name: "Inter",
131
- data: inter,
132
- style: "normal",
133
- weight: 500,
134
- },
135
- ],
136
- }
137
- );
138
- }