ruler-components 0.1.1 → 0.1.3

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 +458 -0
  2. package/dist/index.d.ts +458 -0
  3. package/dist/index.js +3618 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/index.mjs +3467 -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,210 +0,0 @@
1
- "use client";
2
-
3
- import React, { useState } from "react";
4
- import { Search, Eye, EyeOff, Check, type LucideIcon } from "lucide-react";
5
- import { cn } from "@/lib/cn";
6
-
7
- const fieldText =
8
- "text-sm text-zinc-900 outline-none transition-all duration-150 placeholder:text-zinc-400 dark:text-zinc-100 dark:placeholder:text-zinc-500";
9
-
10
- const fieldSurface =
11
- "border-zinc-200 hover:border-zinc-300 focus:border-zinc-900 focus:ring-4 focus:ring-zinc-900/5 dark:border-zinc-800 dark:hover:border-zinc-700 dark:focus:border-zinc-400 dark:focus:ring-zinc-300/10";
12
-
13
- export const InputStandard = ({ className, ...props }: React.InputHTMLAttributes<HTMLInputElement>) => (
14
- <input
15
- {...props}
16
- className={cn("w-full rounded-xl border bg-white px-4 py-2.5 dark:bg-zinc-900", fieldText, fieldSurface, className)}
17
- />
18
- );
19
-
20
- export const InputFilled = ({ className, ...props }: React.InputHTMLAttributes<HTMLInputElement>) => (
21
- <input
22
- {...props}
23
- className={cn(
24
- "w-full rounded-xl border border-transparent bg-zinc-100 px-4 py-3 hover:bg-zinc-200/70 focus:border-zinc-900 focus:bg-white focus:ring-4 focus:ring-zinc-900/5 dark:bg-zinc-800 dark:hover:bg-zinc-700/70 dark:focus:border-zinc-400 dark:focus:bg-zinc-900 dark:focus:ring-zinc-300/10",
25
- fieldText,
26
- className,
27
- )}
28
- />
29
- );
30
-
31
- export const InputUnderline = ({ className, ...props }: React.InputHTMLAttributes<HTMLInputElement>) => (
32
- <div className="group relative">
33
- <input
34
- {...props}
35
- className={cn(
36
- "w-full border-b border-zinc-200 bg-transparent py-2 focus:border-zinc-900 dark:border-zinc-700 dark:focus:border-white",
37
- fieldText,
38
- className,
39
- )}
40
- />
41
- <div className="absolute bottom-0 left-0 h-[2px] w-0 bg-zinc-900 transition-all duration-300 group-focus-within:w-full dark:bg-white" />
42
- </div>
43
- );
44
-
45
- export const InputFloating = ({
46
- label,
47
- className,
48
- ...props
49
- }: { label: string } & React.InputHTMLAttributes<HTMLInputElement>) => {
50
- const [value, setValue] = useState("");
51
- const filled = Boolean(value || props.defaultValue);
52
-
53
- return (
54
- <div className="relative pt-4">
55
- <input
56
- {...props}
57
- onChange={(e) => {
58
- setValue(e.target.value);
59
- props.onChange?.(e);
60
- }}
61
- className={cn(
62
- "peer w-full border-b-2 border-zinc-200 bg-transparent py-2 focus:border-zinc-900 dark:border-zinc-700 dark:focus:border-white",
63
- fieldText,
64
- className,
65
- )}
66
- />
67
- <label
68
- className={cn(
69
- "absolute left-0 transition-all duration-200",
70
- filled
71
- ? "-top-1 text-xs font-bold text-zinc-900 dark:text-white"
72
- : "top-5 text-sm text-zinc-400 peer-focus:-top-1 peer-focus:text-xs peer-focus:font-bold peer-focus:text-zinc-900 dark:peer-focus:text-white",
73
- )}
74
- >
75
- {label}
76
- </label>
77
- </div>
78
- );
79
- };
80
-
81
- export const InputSearch = ({ className, ...props }: React.InputHTMLAttributes<HTMLInputElement>) => (
82
- <div className="group relative">
83
- <Search
84
- size={16}
85
- className="absolute left-4 top-1/2 -translate-y-1/2 text-zinc-400 transition-colors group-focus-within:text-zinc-900 dark:group-focus-within:text-white"
86
- />
87
- <input
88
- {...props}
89
- type="text"
90
- className={cn(
91
- "w-full rounded-full border bg-zinc-50 py-2.5 pl-11 pr-4 focus:bg-white dark:bg-zinc-900 dark:focus:bg-zinc-950",
92
- fieldText,
93
- fieldSurface,
94
- className,
95
- )}
96
- />
97
- </div>
98
- );
99
-
100
- export const InputPassword = ({ className, ...props }: React.InputHTMLAttributes<HTMLInputElement>) => {
101
- const [show, setShow] = useState(false);
102
-
103
- return (
104
- <div className="relative">
105
- <input
106
- {...props}
107
- type={show ? "text" : "password"}
108
- className={cn("w-full rounded-xl border bg-white px-4 py-2.5 pr-11 dark:bg-zinc-900", fieldText, fieldSurface, className)}
109
- />
110
- <button
111
- type="button"
112
- onClick={() => setShow(!show)}
113
- aria-label={show ? "Hide password" : "Show password"}
114
- className="absolute right-3 top-1/2 -translate-y-1/2 text-zinc-400 transition-colors hover:text-zinc-900 dark:hover:text-white"
115
- >
116
- {show ? <EyeOff size={18} /> : <Eye size={18} />}
117
- </button>
118
- </div>
119
- );
120
- };
121
-
122
- export const InputAddon = ({
123
- prefix,
124
- suffix,
125
- className,
126
- ...props
127
- }: { prefix?: string; suffix?: string } & React.InputHTMLAttributes<HTMLInputElement>) => (
128
- <div
129
- className={cn(
130
- "flex w-full overflow-hidden rounded-xl border border-zinc-200 bg-white transition-all focus-within:border-zinc-900 focus-within:ring-4 focus-within:ring-zinc-900/5 dark:border-zinc-800 dark:bg-zinc-900 dark:focus-within:border-zinc-400 dark:focus-within:ring-zinc-300/10",
131
- className,
132
- )}
133
- >
134
- {prefix && (
135
- <span className="flex items-center border-r border-zinc-200 bg-zinc-50 px-3 text-sm font-medium text-zinc-500 dark:border-zinc-800 dark:bg-zinc-800 dark:text-zinc-400">
136
- {prefix}
137
- </span>
138
- )}
139
- <input {...props} className={cn("flex-1 bg-transparent px-4 py-2.5", fieldText)} />
140
- {suffix && (
141
- <span className="flex items-center border-l border-zinc-200 bg-zinc-50 px-3 text-sm font-medium text-zinc-500 dark:border-zinc-800 dark:bg-zinc-800 dark:text-zinc-400">
142
- {suffix}
143
- </span>
144
- )}
145
- </div>
146
- );
147
-
148
- export const InputIcon = ({
149
- icon: Icon,
150
- position = "left",
151
- className,
152
- ...props
153
- }: { icon: LucideIcon; position?: "left" | "right" } & React.InputHTMLAttributes<HTMLInputElement>) => (
154
- <div className="relative">
155
- <div
156
- className={cn(
157
- "pointer-events-none absolute top-1/2 -translate-y-1/2 text-zinc-400",
158
- position === "left" ? "left-3.5" : "right-3.5",
159
- )}
160
- >
161
- <Icon size={18} strokeWidth={1.5} />
162
- </div>
163
- <input
164
- {...props}
165
- className={cn(
166
- "w-full rounded-xl border bg-white py-2.5 shadow-sm dark:bg-zinc-900",
167
- position === "left" ? "pl-10 pr-4" : "pl-4 pr-10",
168
- fieldText,
169
- fieldSurface,
170
- className,
171
- )}
172
- />
173
- </div>
174
- );
175
-
176
- export const InputOTP = () => (
177
- <div className="flex gap-2.5">
178
- {[1, 2, 3, 4].map((i) => (
179
- <input
180
- key={i}
181
- maxLength={1}
182
- aria-label={`Digit ${i}`}
183
- className="h-12 w-12 rounded-xl border-2 border-zinc-200 bg-white text-center text-lg font-bold text-zinc-900 outline-none transition-all focus:border-zinc-900 focus:ring-4 focus:ring-zinc-900/5 dark:border-zinc-800 dark:bg-zinc-900 dark:text-white dark:focus:border-zinc-400 dark:focus:ring-zinc-300/10"
184
- />
185
- ))}
186
- </div>
187
- );
188
-
189
- export const InputAutocomplete = ({
190
- suggestions,
191
- className,
192
- ...props
193
- }: { suggestions: string[] } & React.InputHTMLAttributes<HTMLInputElement>) => (
194
- <div className="relative">
195
- <input
196
- {...props}
197
- className={cn("w-full rounded-xl border bg-white px-4 py-2.5 dark:bg-zinc-900", fieldText, fieldSurface, className)}
198
- />
199
- <div className="absolute top-[calc(100%+0.5rem)] z-50 w-full rounded-xl border border-zinc-200 bg-white p-1 shadow-xl dark:border-zinc-800 dark:bg-zinc-900">
200
- {suggestions.map((s) => (
201
- <div
202
- key={s}
203
- className="flex cursor-pointer items-center justify-between rounded-lg px-3 py-2 text-sm text-zinc-700 hover:bg-zinc-50 dark:text-zinc-200 dark:hover:bg-zinc-800"
204
- >
205
- {s} <Check size={14} className="text-zinc-400" />
206
- </div>
207
- ))}
208
- </div>
209
- </div>
210
- );
@@ -1,179 +0,0 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
- import { cva, type VariantProps } from "class-variance-authority";
5
- import { cn } from "@/lib/cn";
6
-
7
- const AVATAR_GRADIENTS = [
8
- "from-violet-500 to-indigo-600",
9
- "from-sky-500 to-blue-600",
10
- "from-emerald-500 to-teal-600",
11
- "from-amber-500 to-orange-500",
12
- "from-rose-500 to-pink-600",
13
- "from-fuchsia-500 to-purple-600",
14
- "from-cyan-500 to-blue-500",
15
- "from-lime-500 to-emerald-600",
16
- ];
17
-
18
- const avatarVariants = cva(
19
- [
20
- "relative inline-flex shrink-0 select-none items-center justify-center overflow-hidden rounded-full",
21
- "ring-1 ring-zinc-900/5 shadow-sm shadow-zinc-900/10",
22
- "dark:ring-white/10 dark:shadow-black/30",
23
- ],
24
- {
25
- variants: {
26
- size: {
27
- sm: "h-8 w-8 text-[10px]",
28
- md: "h-10 w-10 text-xs",
29
- lg: "h-12 w-12 text-sm",
30
- xl: "h-16 w-16 text-base",
31
- },
32
- variant: {
33
- default: "",
34
- outline: "ring-2 ring-white dark:ring-zinc-950",
35
- },
36
- },
37
- defaultVariants: {
38
- size: "md",
39
- variant: "default",
40
- },
41
- },
42
- );
43
-
44
- const statusVariants = cva(
45
- [
46
- "absolute rounded-full ring-2 ring-white dark:ring-zinc-950",
47
- "shadow-sm",
48
- ],
49
- {
50
- variants: {
51
- status: {
52
- online: "bg-emerald-500",
53
- offline: "bg-zinc-400 dark:bg-zinc-500",
54
- busy: "bg-amber-500",
55
- },
56
- size: {
57
- sm: "bottom-0 right-0 h-2 w-2",
58
- md: "bottom-0 right-0 h-2.5 w-2.5",
59
- lg: "bottom-0.5 right-0.5 h-2.5 w-2.5",
60
- xl: "bottom-1 right-1 h-3 w-3",
61
- },
62
- },
63
- },
64
- );
65
-
66
- function getInitials(name: string) {
67
- const parts = name.trim().split(/\s+/).filter(Boolean);
68
- if (parts.length === 0) return "?";
69
- if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
70
- return `${parts[0][0]}${parts[parts.length - 1][0]}`.toUpperCase();
71
- }
72
-
73
- function getGradientFromName(name: string) {
74
- let hash = 0;
75
- for (let i = 0; i < name.length; i += 1) {
76
- hash = name.charCodeAt(i) + ((hash << 5) - hash);
77
- }
78
- return AVATAR_GRADIENTS[Math.abs(hash) % AVATAR_GRADIENTS.length];
79
- }
80
-
81
- export interface AvatarProps
82
- extends React.HTMLAttributes<HTMLSpanElement>,
83
- VariantProps<typeof avatarVariants> {
84
- src?: string;
85
- alt?: string;
86
- name?: string;
87
- status?: "online" | "offline" | "busy" | null;
88
- }
89
-
90
- const Avatar = React.forwardRef<HTMLSpanElement, AvatarProps>(
91
- ({ className, size, variant, src, alt, name, status, children, ...props }, ref) => {
92
- const [imageError, setImageError] = React.useState(false);
93
- const showImage = src && !imageError;
94
- const fallbackText = name ? getInitials(name) : children;
95
- const gradient = name ? getGradientFromName(name) : "from-zinc-400 to-zinc-500";
96
-
97
- return (
98
- <span
99
- ref={ref}
100
- className={cn(avatarVariants({ size, variant }), className)}
101
- {...props}
102
- >
103
- {showImage ? (
104
- // eslint-disable-next-line @next/next/no-img-element
105
- <img
106
- src={src}
107
- alt={alt ?? name ?? "Avatar"}
108
- className="h-full w-full object-cover"
109
- onError={() => setImageError(true)}
110
- />
111
- ) : (
112
- <span
113
- className={cn(
114
- "flex h-full w-full items-center justify-center bg-gradient-to-br font-semibold uppercase tracking-tight text-white",
115
- gradient,
116
- )}
117
- >
118
- {fallbackText ?? "?"}
119
- </span>
120
- )}
121
- {status && (
122
- <span
123
- className={cn(statusVariants({ status, size }))}
124
- aria-hidden
125
- />
126
- )}
127
- </span>
128
- );
129
- },
130
- );
131
- Avatar.displayName = "Avatar";
132
-
133
- export interface AvatarGroupProps extends React.HTMLAttributes<HTMLDivElement> {
134
- max?: number;
135
- size?: VariantProps<typeof avatarVariants>["size"];
136
- }
137
-
138
- function AvatarGroup({
139
- className,
140
- max = 5,
141
- size = "md",
142
- children,
143
- ...props
144
- }: AvatarGroupProps) {
145
- const avatars = React.Children.toArray(children).filter(React.isValidElement);
146
- const visible = avatars.slice(0, max);
147
- const remaining = avatars.length - visible.length;
148
-
149
- return (
150
- <div className={cn("flex items-center", className)} {...props}>
151
- {visible.map((child, index) => (
152
- <div
153
- key={index}
154
- className={cn(
155
- "relative transition-transform duration-200 hover:z-10 hover:scale-110",
156
- index > 0 && "-ml-3",
157
- )}
158
- >
159
- {child}
160
- </div>
161
- ))}
162
- {remaining > 0 && (
163
- <span
164
- className={cn(
165
- "-ml-3",
166
- avatarVariants({ variant: "outline", size }),
167
- "bg-zinc-100 text-zinc-600 ring-2 ring-white dark:bg-zinc-800 dark:text-zinc-200 dark:ring-zinc-950",
168
- )}
169
- >
170
- <span className="flex h-full w-full items-center justify-center text-[10px] font-semibold">
171
- +{remaining}
172
- </span>
173
- </span>
174
- )}
175
- </div>
176
- );
177
- }
178
-
179
- export { Avatar, AvatarGroup, avatarVariants, getInitials, getGradientFromName };
@@ -1,52 +0,0 @@
1
- import * as React from "react";
2
- import { cva, type VariantProps } from "class-variance-authority";
3
- import { cn } from "@/lib/cn";
4
-
5
- const badgeVariants = cva(
6
- "inline-flex items-center gap-1 rounded-md font-medium transition-colors",
7
- {
8
- variants: {
9
- variant: {
10
- default:
11
- "bg-zinc-100 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-200",
12
- info: "bg-[#0070BA]/10 text-[#0070BA] dark:bg-[#0070BA]/20 dark:text-[#4DA3E0]",
13
- success:
14
- "bg-[#28A745]/10 text-[#28A745] dark:bg-[#28A745]/20 dark:text-[#5CC975]",
15
- warning:
16
- "bg-[#E58E00]/10 text-[#E58E00] dark:bg-[#E58E00]/20 dark:text-[#F5B84A]",
17
- error:
18
- "bg-[#D93025]/10 text-[#D93025] dark:bg-[#D93025]/20 dark:text-[#F06B62]",
19
- outline:
20
- "border border-zinc-200 bg-transparent text-zinc-700 dark:border-zinc-700 dark:text-zinc-300",
21
- },
22
- size: {
23
- sm: "px-1.5 py-0.5 text-[10px]",
24
- md: "px-2 py-0.5 text-[11px]",
25
- lg: "px-2.5 py-1 text-xs",
26
- },
27
- },
28
- defaultVariants: {
29
- variant: "default",
30
- size: "md",
31
- },
32
- },
33
- );
34
-
35
- export interface BadgeProps
36
- extends React.HTMLAttributes<HTMLSpanElement>,
37
- VariantProps<typeof badgeVariants> {}
38
-
39
- const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(
40
- ({ className, variant, size, ...props }, ref) => {
41
- return (
42
- <span
43
- ref={ref}
44
- className={cn(badgeVariants({ variant, size }), className)}
45
- {...props}
46
- />
47
- );
48
- },
49
- );
50
- Badge.displayName = "Badge";
51
-
52
- export { Badge, badgeVariants };
@@ -1,75 +0,0 @@
1
- import * as React from "react";
2
- import { cva, type VariantProps } from "class-variance-authority";
3
- import { cn } from "@/lib/cn";
4
-
5
- const buttonVariants = cva(
6
- [
7
- "inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-xl",
8
- "text-sm font-medium tracking-tight",
9
- "transition-[color,background-color,border-color,box-shadow,transform] duration-200 ease-[cubic-bezier(0.16,1,0.3,1)]",
10
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900/15 focus-visible:ring-offset-2 focus-visible:ring-offset-white",
11
- "active:scale-[0.97] active:transition-[transform] active:duration-100",
12
- "disabled:pointer-events-none disabled:opacity-40 disabled:shadow-none disabled:active:scale-100",
13
- "dark:focus-visible:ring-white/20 dark:focus-visible:ring-offset-zinc-950",
14
- "select-none",
15
- ],
16
- {
17
- variants: {
18
- variant: {
19
- primary: [
20
- "bg-zinc-900 text-white",
21
- "shadow-[0_1px_2px_rgba(0,0,0,0.06),0_4px_12px_rgba(0,0,0,0.08)]",
22
- "hover:bg-zinc-800 hover:-translate-y-0.5",
23
- "hover:shadow-[0_2px_4px_rgba(0,0,0,0.06),0_8px_20px_rgba(0,0,0,0.12)]",
24
- "dark:bg-zinc-100 dark:text-zinc-900",
25
- "dark:shadow-[0_1px_2px_rgba(255,255,255,0.06),0_4px_16px_rgba(0,0,0,0.35)]",
26
- "dark:hover:bg-white dark:hover:shadow-[0_2px_8px_rgba(0,0,0,0.25),0_8px_24px_rgba(0,0,0,0.2)]",
27
- ],
28
- white: [
29
- "border border-zinc-200/80 bg-white text-zinc-900",
30
- "shadow-[0_1px_2px_rgba(0,0,0,0.04),0_4px_12px_rgba(0,0,0,0.06)]",
31
- "hover:border-zinc-300 hover:bg-zinc-50 hover:-translate-y-0.5",
32
- "hover:shadow-[0_2px_4px_rgba(0,0,0,0.04),0_8px_20px_rgba(0,0,0,0.1)]",
33
- ],
34
- outline: [
35
- "border border-zinc-200 bg-white/70 text-zinc-700 backdrop-blur-sm",
36
- "shadow-[0_1px_2px_rgba(0,0,0,0.03)]",
37
- "hover:border-zinc-300 hover:bg-white hover:text-zinc-900 hover:-translate-y-0.5",
38
- "hover:shadow-[0_2px_8px_rgba(0,0,0,0.06)]",
39
- "dark:border-zinc-700 dark:bg-zinc-900/40 dark:text-zinc-200 dark:shadow-none",
40
- "dark:hover:border-zinc-500 dark:hover:bg-zinc-800/80 dark:hover:text-white",
41
- ],
42
- ghost: [
43
- "text-zinc-600",
44
- "hover:bg-zinc-100/90 hover:text-zinc-900",
45
- "dark:text-zinc-400 dark:hover:bg-zinc-800/70 dark:hover:text-zinc-100",
46
- ],
47
- },
48
- size: {
49
- sm: "h-8 gap-1.5 rounded-lg px-3.5 text-xs",
50
- md: "h-10 px-4",
51
- lg: "h-11 px-5 text-[15px]",
52
- },
53
- },
54
- defaultVariants: { variant: "primary", size: "md" },
55
- },
56
- );
57
-
58
- export interface ButtonProps
59
- extends React.ComponentPropsWithoutRef<"button">,
60
- VariantProps<typeof buttonVariants> {}
61
-
62
- export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
63
- ({ className, variant, size, ...props }, ref) => {
64
- return (
65
- <button
66
- ref={ref}
67
- className={cn(buttonVariants({ variant, size }), className)}
68
- {...props}
69
- />
70
- );
71
- },
72
- );
73
- Button.displayName = "Button";
74
-
75
- export { buttonVariants };
@@ -1,105 +0,0 @@
1
- import * as React from "react";
2
- import { cva, type VariantProps } from "class-variance-authority";
3
- import { cn } from "@/lib/cn";
4
-
5
- const cardVariants = cva(
6
- "rounded-2xl border bg-white text-zinc-900 transition-all duration-200 dark:bg-zinc-900 dark:text-zinc-100",
7
- {
8
- variants: {
9
- variant: {
10
- default:
11
- "border-zinc-200/70 shadow-[0_2px_8px_rgba(0,0,0,0.06)] dark:border-zinc-800/80 dark:shadow-[0_2px_8px_rgba(0,0,0,0.25)]",
12
- outline: "border-zinc-200 shadow-none dark:border-zinc-800",
13
- elevated:
14
- "border-zinc-200 shadow-[0_8px_30px_rgba(0,0,0,0.08)] dark:border-zinc-800 dark:shadow-[0_8px_30px_rgba(0,0,0,0.35)]",
15
- interactive:
16
- "cursor-pointer border-zinc-200/70 shadow-[0_2px_8px_rgba(0,0,0,0.06)] hover:-translate-y-0.5 hover:border-zinc-300 hover:shadow-[0_8px_24px_rgba(0,0,0,0.1)] dark:border-zinc-800/80 dark:shadow-[0_2px_8px_rgba(0,0,0,0.25)] dark:hover:border-zinc-700 dark:hover:shadow-[0_8px_24px_rgba(0,0,0,0.4)]",
17
- },
18
- },
19
- defaultVariants: { variant: "default" },
20
- },
21
- );
22
-
23
- export interface CardProps
24
- extends React.HTMLAttributes<HTMLDivElement>,
25
- VariantProps<typeof cardVariants> {}
26
-
27
- const Card = React.forwardRef<HTMLDivElement, CardProps>(
28
- ({ className, variant, ...props }, ref) => (
29
- <div
30
- ref={ref}
31
- className={cn(cardVariants({ variant }), className)}
32
- {...props}
33
- />
34
- ),
35
- );
36
- Card.displayName = "Card";
37
-
38
- const CardHeader = React.forwardRef<
39
- HTMLDivElement,
40
- React.HTMLAttributes<HTMLDivElement>
41
- >(({ className, ...props }, ref) => (
42
- <div
43
- ref={ref}
44
- className={cn("flex flex-col gap-1.5 p-6", className)}
45
- {...props}
46
- />
47
- ));
48
- CardHeader.displayName = "CardHeader";
49
-
50
- const CardTitle = React.forwardRef<
51
- HTMLHeadingElement,
52
- React.HTMLAttributes<HTMLHeadingElement>
53
- >(({ className, ...props }, ref) => (
54
- <h3
55
- ref={ref}
56
- className={cn("text-base font-semibold leading-none tracking-tight text-zinc-900 dark:text-white", className)}
57
- {...props}
58
- />
59
- ));
60
- CardTitle.displayName = "CardTitle";
61
-
62
- const CardDescription = React.forwardRef<
63
- HTMLParagraphElement,
64
- React.HTMLAttributes<HTMLParagraphElement>
65
- >(({ className, ...props }, ref) => (
66
- <p
67
- ref={ref}
68
- className={cn("text-sm leading-relaxed text-zinc-500 dark:text-zinc-400", className)}
69
- {...props}
70
- />
71
- ));
72
- CardDescription.displayName = "CardDescription";
73
-
74
- const CardContent = React.forwardRef<
75
- HTMLDivElement,
76
- React.HTMLAttributes<HTMLDivElement>
77
- >(({ className, ...props }, ref) => (
78
- <div ref={ref} className={cn("px-6 pb-6 pt-0", className)} {...props} />
79
- ));
80
- CardContent.displayName = "CardContent";
81
-
82
- const CardFooter = React.forwardRef<
83
- HTMLDivElement,
84
- React.HTMLAttributes<HTMLDivElement>
85
- >(({ className, ...props }, ref) => (
86
- <div
87
- ref={ref}
88
- className={cn(
89
- "flex items-center gap-2 border-t border-zinc-100 bg-zinc-50/60 px-6 py-4 dark:border-zinc-800 dark:bg-zinc-800/30",
90
- className,
91
- )}
92
- {...props}
93
- />
94
- ));
95
- CardFooter.displayName = "CardFooter";
96
-
97
- export {
98
- Card,
99
- CardHeader,
100
- CardTitle,
101
- CardDescription,
102
- CardContent,
103
- CardFooter,
104
- cardVariants,
105
- };