nexoreui-cli 0.1.0 → 0.1.1

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.js CHANGED
@@ -26,6 +26,101 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  // src/commands/add.ts
27
27
  var fs3 = __toESM(require("fs"));
28
28
  var path3 = __toESM(require("path"));
29
+ var readline = __toESM(require("readline"));
30
+ var import_child_process = require("child_process");
31
+
32
+ // src/utils/detect.ts
33
+ var fs = __toESM(require("fs"));
34
+ var path = __toESM(require("path"));
35
+ function detectProject(cwd = process.cwd()) {
36
+ let packageManager = "npm";
37
+ let projectType = "unknown";
38
+ let hasSrcDir = false;
39
+ let currentDir = cwd;
40
+ let baseDir = cwd;
41
+ while (currentDir !== path.parse(currentDir).root) {
42
+ if (fs.existsSync(path.join(currentDir, "package.json"))) {
43
+ baseDir = currentDir;
44
+ break;
45
+ }
46
+ currentDir = path.dirname(currentDir);
47
+ }
48
+ if (fs.existsSync(path.join(baseDir, "pnpm-lock.yaml"))) {
49
+ packageManager = "pnpm";
50
+ } else if (fs.existsSync(path.join(baseDir, "yarn.lock"))) {
51
+ packageManager = "yarn";
52
+ } else if (fs.existsSync(path.join(baseDir, "bun.lockb")) || fs.existsSync(path.join(baseDir, "bun.lock"))) {
53
+ packageManager = "bun";
54
+ }
55
+ if (fs.existsSync(path.join(baseDir, "src"))) {
56
+ hasSrcDir = true;
57
+ }
58
+ try {
59
+ const packageJsonPath = path.join(baseDir, "package.json");
60
+ if (fs.existsSync(packageJsonPath)) {
61
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
62
+ const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
63
+ if (deps["next"]) {
64
+ projectType = "next";
65
+ } else if (deps["vite"] || deps["@tailwindcss/vite"]) {
66
+ projectType = "vite";
67
+ } else if (deps["react-scripts"]) {
68
+ projectType = "cra";
69
+ }
70
+ }
71
+ } catch (err) {
72
+ }
73
+ return {
74
+ packageManager,
75
+ projectType,
76
+ hasSrcDir,
77
+ baseDir
78
+ };
79
+ }
80
+
81
+ // src/utils/copy.ts
82
+ var fs2 = __toESM(require("fs"));
83
+ var path2 = __toESM(require("path"));
84
+ var CN_TEMPLATE = `import { type ClassValue, clsx } from "clsx"
85
+ import { twMerge } from "tailwind-merge"
86
+
87
+ export function cn(...inputs: ClassValue[]) {
88
+ return twMerge(clsx(inputs))
89
+ }
90
+ `;
91
+ function ensureDir(dirPath) {
92
+ if (!fs2.existsSync(dirPath)) {
93
+ fs2.mkdirSync(dirPath, { recursive: true });
94
+ }
95
+ }
96
+ function getRelativeImportPath(fromDir, toFile) {
97
+ let relativePath = path2.relative(fromDir, toFile);
98
+ relativePath = relativePath.replace(/\\/g, "/");
99
+ relativePath = relativePath.replace(/\.(ts|tsx|js|jsx)$/, "");
100
+ if (!relativePath.startsWith(".")) {
101
+ relativePath = "./" + relativePath;
102
+ }
103
+ return relativePath;
104
+ }
105
+ function ensureCnUtil(utilsPath) {
106
+ const dir = path2.dirname(utilsPath);
107
+ ensureDir(dir);
108
+ if (!fs2.existsSync(utilsPath)) {
109
+ fs2.writeFileSync(utilsPath, CN_TEMPLATE, "utf8");
110
+ return true;
111
+ }
112
+ return false;
113
+ }
114
+ function copyComponentFile(content, targetFilePath, utilsFilePath) {
115
+ const targetDir = path2.dirname(targetFilePath);
116
+ ensureDir(targetDir);
117
+ const relativeImport = getRelativeImportPath(targetDir, utilsFilePath);
118
+ const rewrittenContent = content.replace(
119
+ /['"]\.\.\/utils\/cn['"]/g,
120
+ `"${relativeImport}"`
121
+ );
122
+ fs2.writeFileSync(targetFilePath, rewrittenContent, "utf8");
123
+ }
29
124
 
30
125
  // src/registry/button.ts
31
126
  var button = {
@@ -34,7 +129,8 @@ var button = {
34
129
  "class-variance-authority",
35
130
  "clsx",
36
131
  "tailwind-merge",
37
- "framer-motion"
132
+ "framer-motion",
133
+ "lucide-react"
38
134
  ],
39
135
  fileName: "button.tsx",
40
136
  content: `'use client';
@@ -42,28 +138,34 @@ var button = {
42
138
  import * as React from 'react';
43
139
  import { cva, type VariantProps } from 'class-variance-authority';
44
140
  import { cn } from '../utils/cn';
45
- import { motion, HTMLMotionProps, AnimatePresence } from 'framer-motion';
141
+ import { motion, HTMLMotionProps } from 'framer-motion';
142
+ import { Loader2 } from 'lucide-react';
46
143
 
47
144
  const buttonVariants = cva(
48
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 active:scale-95",
145
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-xl text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 active:scale-95",
49
146
  {
50
147
  variants: {
51
148
  variant: {
52
- default: "bg-gradient-to-br from-primary to-primary/80 text-primary-foreground shadow-lg shadow-primary/20 hover:shadow-xl hover:shadow-primary/30",
149
+ default: "bg-gradient-to-br from-primary to-primary/80 text-primary-foreground shadow-lg shadow-primary/10 hover:shadow-xl hover:shadow-primary/20",
53
150
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 border border-border/50",
54
- destructive: "bg-gradient-to-br from-destructive to-destructive/80 text-destructive-foreground shadow-lg shadow-destructive/20 hover:shadow-xl hover:shadow-destructive/30",
151
+ destructive: "bg-gradient-to-br from-destructive to-destructive/80 text-destructive-foreground shadow-lg shadow-destructive/10 hover:shadow-xl hover:shadow-destructive/20",
55
152
  outline: "border-2 border-input bg-background hover:bg-accent hover:text-accent-foreground hover:border-accent",
56
153
  ghost: "hover:bg-accent hover:text-accent-foreground",
57
154
  link: "text-primary underline-offset-4 hover:underline",
58
- // New WOW Variants
155
+ // Premium variants
59
156
  premium: "bg-gradient-to-r from-violet-600 via-pink-600 to-orange-500 text-white shadow-lg shadow-purple-500/20 hover:shadow-xl hover:shadow-purple-500/30",
60
- neon: "bg-background border-2 border-primary text-foreground shadow-[0_0_15px_rgba(var(--primary-rgb),0.5)] hover:shadow-[0_0_25px_rgba(var(--primary-rgb),0.7)]",
157
+ neon: "bg-background border-2 border-primary text-foreground shadow-[0_0_15px_rgba(var(--primary-rgb),0.3)] hover:shadow-[0_0_25px_rgba(var(--primary-rgb),0.5)]",
61
158
  glass: "backdrop-blur-md bg-white/10 dark:bg-black/20 border border-white/20 dark:border-white/10 text-foreground hover:bg-white/20 dark:hover:bg-black/30 shadow-lg",
62
159
  shimmer: "relative overflow-hidden bg-slate-900 text-white dark:bg-white dark:text-black",
160
+ // New requested variants
161
+ gradient: "bg-gradient-to-r from-indigo-500 via-purple-500 to-violet-600 text-white shadow-lg shadow-indigo-500/20 hover:shadow-xl hover:shadow-indigo-500/30 hover:opacity-95",
162
+ glow: "bg-primary text-primary-foreground shadow-[0_0_12px_rgba(var(--primary-rgb),0.3)] hover:shadow-[0_0_24px_rgba(var(--primary-rgb),0.6)] border border-primary/20",
163
+ magnetic: "bg-gradient-to-br from-violet-600 to-indigo-600 text-white shadow-md hover:shadow-lg",
164
+ loading: "bg-primary/80 text-primary-foreground/80 pointer-events-none cursor-wait",
63
165
  },
64
166
  size: {
65
167
  default: "h-10 px-5 py-2",
66
- sm: "h-9 rounded-md px-3 text-xs",
168
+ sm: "h-9 rounded-lg px-3 text-xs",
67
169
  lg: "h-11 rounded-xl px-8 text-base",
68
170
  icon: "h-10 w-10 rounded-full",
69
171
  },
@@ -75,23 +177,70 @@ const buttonVariants = cva(
75
177
  }
76
178
  );
77
179
 
180
+ /**
181
+ * Props for the Button component
182
+ */
78
183
  export interface ButtonProps
79
184
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
80
185
  VariantProps<typeof buttonVariants> {
81
- /** Enable hover/tap motion animation @default true */
186
+ /**
187
+ * Enable hover/tap spring motion animation
188
+ * @default true
189
+ */
82
190
  animate?: boolean;
83
- /** Enable shimmer light effect across the button */
191
+ /**
192
+ * Enable shimmer light animation effect
193
+ * @default false
194
+ */
84
195
  shimmer?: boolean;
85
- /** Enable neon glow effect */
196
+ /**
197
+ * Enable neon glow effect
198
+ * @default false
199
+ */
86
200
  glow?: boolean;
87
- children?: React.ReactNode;
88
- className?: string;
201
+ /**
202
+ * Display loading spinner icon and disable actions
203
+ * @default false
204
+ */
205
+ isLoading?: boolean;
89
206
  }
90
207
 
91
208
  const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
92
- ({ className, variant, size, animate = true, shimmer = false, glow = false, children, ...props }, ref) => {
93
-
209
+ (
210
+ {
211
+ className,
212
+ variant,
213
+ size,
214
+ animate = true,
215
+ shimmer = false,
216
+ glow = false,
217
+ isLoading = false,
218
+ children,
219
+ ...props
220
+ },
221
+ ref
222
+ ) => {
94
223
  const isShimmer = variant === 'shimmer' || shimmer;
224
+ const isMagnetic = variant === 'magnetic';
225
+ const isGlow = variant === 'glow' || glow;
226
+
227
+ // Track mouse coords for magnetic hover movement
228
+ const [magneticPos, setMagneticPos] = React.useState({ x: 0, y: 0 });
229
+
230
+ const handleMouseMove = (e: React.MouseEvent<HTMLButtonElement>) => {
231
+ if (!isMagnetic) return;
232
+ const { clientX, clientY, currentTarget } = e;
233
+ const { left, top, width, height } = currentTarget.getBoundingClientRect();
234
+ const x = clientX - (left + width / 2);
235
+ const y = clientY - (top + height / 2);
236
+ // spring weight multiplier
237
+ setMagneticPos({ x: x * 0.35, y: y * 0.35 });
238
+ };
239
+
240
+ const handleMouseLeave = () => {
241
+ if (!isMagnetic) return;
242
+ setMagneticPos({ x: 0, y: 0 });
243
+ };
95
244
 
96
245
  const buttonContent = (
97
246
  <>
@@ -109,45 +258,240 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
109
258
  style={{ transform: 'skewX(-20deg)' }}
110
259
  />
111
260
  )}
112
- <span className="relative z-10 flex items-center gap-2">{children}</span>
261
+ <span className="relative z-10 flex items-center justify-center gap-2">
262
+ {isLoading && <Loader2 className="animate-spin h-4 w-4 shrink-0" />}
263
+ {children}
264
+ </span>
113
265
  </>
114
266
  );
115
267
 
268
+ const activeVariant = isLoading ? "loading" : variant;
269
+
270
+ // Disable button if loading
271
+ const disabledState = props.disabled || isLoading;
272
+
273
+ // Destructure custom props to avoid passing invalid props down to HTML element
274
+ const { ...htmlProps } = props;
275
+
276
+ // Setup base styles
277
+ const resolvedClassName = cn(
278
+ buttonVariants({ variant: activeVariant, size, className }),
279
+ isShimmer && "relative overflow-hidden",
280
+ isGlow && "shadow-[0_0_15px_rgba(var(--primary-rgb),0.4)]"
281
+ );
282
+
116
283
  if (!animate) {
117
284
  return (
118
285
  <button
119
- className={cn(buttonVariants({ variant, size, className }), isShimmer && "relative overflow-hidden")}
120
286
  ref={ref}
121
- {...props}
287
+ disabled={disabledState}
288
+ className={resolvedClassName}
289
+ {...(htmlProps as React.ButtonHTMLAttributes<HTMLButtonElement>)}
122
290
  >
123
291
  {buttonContent}
124
292
  </button>
125
293
  );
126
294
  }
127
295
 
128
- // Destructure HTML-only event handlers that shouldn't go to motion.button
129
- const { onDrag, onDragStart, onDragEnd, onAnimationStart, ...motionSafeProps } = props;
130
-
131
296
  return (
132
297
  <motion.button
133
- className={cn(buttonVariants({ variant, size, className }))}
134
298
  ref={ref}
135
- whileHover={{
136
- scale: 1.03,
137
- y: -1,
299
+ disabled={disabledState}
300
+ className={resolvedClassName}
301
+ onMouseMove={handleMouseMove}
302
+ onMouseLeave={handleMouseLeave}
303
+ animate={isMagnetic ? { x: magneticPos.x, y: magneticPos.y } : undefined}
304
+ whileHover={{
305
+ scale: isMagnetic ? 1.02 : 1.03,
306
+ y: isMagnetic ? 0 : -1.5,
307
+ shadow: isGlow ? "0 0 25px rgba(var(--primary-rgb), 0.7)" : undefined,
138
308
  }}
139
309
  whileTap={{ scale: 0.97 }}
140
- transition={{ type: "spring", stiffness: 400, damping: 15 }}
141
- {...motionSafeProps as HTMLMotionProps<"button">}
310
+ transition={{
311
+ type: "spring",
312
+ stiffness: 350,
313
+ damping: 20,
314
+ }}
315
+ {...(htmlProps as any)}
142
316
  >
143
317
  {buttonContent}
144
318
  </motion.button>
145
319
  );
146
320
  }
147
321
  );
322
+
148
323
  Button.displayName = "Button";
149
324
 
150
325
  export { Button, buttonVariants };
326
+
327
+ // ----------------------------------------------------
328
+ // Merged button components for backward compatibility
329
+ // ----------------------------------------------------
330
+
331
+ export const NeonButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
332
+ ({ children, ...props }, ref) => (
333
+ <Button ref={ref} variant="neon" glow={true} {...props}>
334
+ {children}
335
+ </Button>
336
+ )
337
+ );
338
+ NeonButton.displayName = "NeonButton";
339
+
340
+ export const ThreeDButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
341
+ ({ children, className, ...props }, ref) => (
342
+ <Button
343
+ ref={ref}
344
+ className={cn(
345
+ "shadow-[0_5px_0_hsl(var(--primary-dark,240_5.9%_30%))] hover:shadow-[0_2px_0_hsl(var(--primary-dark,240_5.9%_30%))] active:translate-y-[3px] active:shadow-[0_0px_0_transparent] transition-all",
346
+ className
347
+ )}
348
+ {...props}
349
+ >
350
+ {children}
351
+ </Button>
352
+ )
353
+ );
354
+ ThreeDButton.displayName = "ThreeDButton";
355
+
356
+ export const RippleButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
357
+ ({ children, className, ...props }, ref) => (
358
+ <Button
359
+ ref={ref}
360
+ className={cn(
361
+ "relative overflow-hidden group active:scale-95 transition-transform",
362
+ className
363
+ )}
364
+ {...props}
365
+ >
366
+ <span className="absolute inset-0 bg-white/20 scale-0 rounded-full group-active:scale-[2] transition-transform duration-500 origin-center"></span>
367
+ <span className="relative z-10">{children}</span>
368
+ </Button>
369
+ )
370
+ );
371
+ RippleButton.displayName = "RippleButton";
372
+
373
+ export const CyberpunkButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
374
+ ({ children, className, ...props }, ref) => (
375
+ <Button
376
+ ref={ref}
377
+ className={cn(
378
+ "bg-yellow-400 text-black font-extrabold uppercase tracking-widest border-2 border-black hover:bg-black hover:text-yellow-400 hover:border-yellow-400 transition-colors shadow-[4px_4px_0_0_#000] rounded-none hover:shadow-[4px_4px_0_0_#fff]",
379
+ className
380
+ )}
381
+ {...props}
382
+ >
383
+ {children}
384
+ </Button>
385
+ )
386
+ );
387
+ CyberpunkButton.displayName = "CyberpunkButton";
388
+
389
+ export const MagneticButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
390
+ ({ children, ...props }, ref) => (
391
+ <Button ref={ref} variant="magnetic" {...props}>
392
+ {children}
393
+ </Button>
394
+ )
395
+ );
396
+ MagneticButton.displayName = "MagneticButton";
397
+
398
+ export const ShimmerButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
399
+ ({ children, ...props }, ref) => (
400
+ <Button ref={ref} variant="shimmer" shimmer={true} {...props}>
401
+ {children}
402
+ </Button>
403
+ )
404
+ );
405
+ ShimmerButton.displayName = "ShimmerButton";
406
+
407
+ export const BorderBeamButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
408
+ ({ children, className, ...props }, ref) => (
409
+ <Button
410
+ ref={ref}
411
+ variant="outline"
412
+ className={cn(
413
+ "relative overflow-hidden border border-border group",
414
+ className
415
+ )}
416
+ {...props}
417
+ >
418
+ <div className="absolute inset-0 bg-gradient-to-r from-primary to-transparent opacity-0 group-hover:opacity-20 transition-opacity"></div>
419
+ <div className="absolute top-0 left-0 w-full h-[2px] bg-primary scale-x-0 group-hover:scale-x-100 transition-transform origin-left"></div>
420
+ <span className="relative z-10">{children}</span>
421
+ </Button>
422
+ )
423
+ );
424
+ BorderBeamButton.displayName = "BorderBeamButton";
425
+
426
+ export const LoadingButton = React.forwardRef<HTMLButtonElement, ButtonProps & { isLoading?: boolean }>(
427
+ ({ children, isLoading = true, ...props }, ref) => (
428
+ <Button ref={ref} isLoading={isLoading} {...props}>
429
+ {children}
430
+ </Button>
431
+ )
432
+ );
433
+ LoadingButton.displayName = "LoadingButton";
434
+
435
+ export const DestructiveGlowButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
436
+ ({ children, ...props }, ref) => (
437
+ <Button ref={ref} variant="destructive" glow={true} {...props}>
438
+ {children}
439
+ </Button>
440
+ )
441
+ );
442
+ DestructiveGlowButton.displayName = "DestructiveGlowButton";
443
+
444
+ export const GhostOutlineButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
445
+ ({ children, ...props }, ref) => (
446
+ <Button ref={ref} variant="outline" {...props}>
447
+ {children}
448
+ </Button>
449
+ )
450
+ );
451
+ GhostOutlineButton.displayName = "GhostOutlineButton";
452
+
453
+ export const GlowButton = React.forwardRef<HTMLButtonElement, ButtonProps & { glowColor?: string }>(
454
+ ({ children, glowColor = "rgba(139, 92, 246, 0.15)", className, ...props }, ref) => (
455
+ <div className="relative group inline-block">
456
+ <div
457
+ className="absolute -inset-0.5 bg-gradient-to-r from-primary to-purple-600 rounded-lg blur opacity-75 group-hover:opacity-100 transition duration-1000 group-hover:duration-200"
458
+ style={{ backgroundColor: glowColor }}
459
+ />
460
+ <Button ref={ref} className={cn("relative bg-background", className)} {...props}>
461
+ {children}
462
+ </Button>
463
+ </div>
464
+ )
465
+ );
466
+ GlowButton.displayName = "GlowButton";
467
+
468
+ export const ShinyButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
469
+ ({ children, ...props }, ref) => (
470
+ <Button ref={ref} shimmer={true} {...props}>
471
+ {children}
472
+ </Button>
473
+ )
474
+ );
475
+ ShinyButton.displayName = "ShinyButton";
476
+
477
+ export const GradientButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
478
+ ({ children, ...props }, ref) => (
479
+ <Button ref={ref} variant="gradient" {...props}>
480
+ {children}
481
+ </Button>
482
+ )
483
+ );
484
+ GradientButton.displayName = "GradientButton";
485
+
486
+ export const GlassButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
487
+ ({ children, ...props }, ref) => (
488
+ <Button ref={ref} variant="glass" {...props}>
489
+ {children}
490
+ </Button>
491
+ )
492
+ );
493
+ GlassButton.displayName = "GlassButton";
494
+
151
495
  `
152
496
  };
153
497
 
@@ -162,13 +506,15 @@ var modal = {
162
506
  "lucide-react",
163
507
  "framer-motion"
164
508
  ],
165
- componentsDependencies: ["button"],
509
+ componentsDependencies: [
510
+ "button"
511
+ ],
166
512
  fileName: "modal.tsx",
167
513
  content: `"use client"
168
514
 
169
515
  import * as React from "react"
170
516
  import * as DialogPrimitive from "@radix-ui/react-dialog"
171
- import { X, AlertTriangle, CheckCircle } from "lucide-react"
517
+ import { X, AlertTriangle, CheckCircle, Star } from "lucide-react"
172
518
  import { cn } from "../utils/cn"
173
519
  import { Button } from "./button"
174
520
 
@@ -198,7 +544,7 @@ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
198
544
  const DialogContent = React.forwardRef<
199
545
  React.ElementRef<typeof DialogPrimitive.Content>,
200
546
  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
201
- >((({ className, children, ...props }, ref) => (
547
+ >(({ className, children, ...props }, ref) => (
202
548
  <DialogPortal>
203
549
  <DialogOverlay />
204
550
  <DialogPrimitive.Content
@@ -416,6 +762,307 @@ export function Modal({
416
762
  </Dialog>
417
763
  )
418
764
  }
765
+
766
+ // ============================================
767
+ // Backward compatibility wrappers & variants
768
+ // ============================================
769
+
770
+ export interface BasicModalProps {
771
+ isOpen?: boolean;
772
+ onOpenChange?: (open: boolean) => void;
773
+ trigger?: React.ReactNode;
774
+ title?: string;
775
+ description?: string;
776
+ children?: React.ReactNode;
777
+ confirmText?: string;
778
+ cancelText?: string;
779
+ onConfirm?: () => void;
780
+ onCancel?: () => void;
781
+ className?: string;
782
+ }
783
+
784
+ export const BasicModal = ({
785
+ isOpen,
786
+ onOpenChange,
787
+ trigger,
788
+ title = "Basic Modal",
789
+ description = "This is a simple modal dialog that can be used for various purposes.",
790
+ children,
791
+ confirmText = "Confirm",
792
+ cancelText = "Cancel",
793
+ onConfirm,
794
+ onCancel,
795
+ className = ""
796
+ }: BasicModalProps) => {
797
+ return (
798
+ <Modal
799
+ isOpen={isOpen}
800
+ onOpenChange={onOpenChange}
801
+ trigger={trigger}
802
+ title={title}
803
+ description={description}
804
+ confirmText={confirmText}
805
+ cancelText={cancelText}
806
+ onConfirm={onConfirm}
807
+ onCancel={onCancel}
808
+ className={className}
809
+ variant="default"
810
+ >
811
+ {children}
812
+ </Modal>
813
+ )
814
+ }
815
+
816
+ export interface InteractiveGlassModalProps {
817
+ isOpen?: boolean;
818
+ onOpenChange?: (open: boolean) => void;
819
+ trigger?: React.ReactNode;
820
+ icon?: React.ReactNode;
821
+ title?: string;
822
+ description?: string;
823
+ children?: React.ReactNode;
824
+ confirmText?: string;
825
+ cancelText?: string;
826
+ onConfirm?: () => void;
827
+ onCancel?: () => void;
828
+ className?: string;
829
+ }
830
+
831
+ export const InteractiveGlassModal = ({
832
+ isOpen,
833
+ onOpenChange,
834
+ trigger,
835
+ icon = <Star className="w-6 h-6 text-yellow-300" />,
836
+ title = "Premium Glass Effect",
837
+ description = "This modal uses full glassmorphism for a stunning visual effect.",
838
+ children,
839
+ confirmText = "Upgrade Now",
840
+ cancelText = "Maybe Later",
841
+ onConfirm,
842
+ onCancel,
843
+ className = ""
844
+ }: InteractiveGlassModalProps) => {
845
+ return (
846
+ <Modal
847
+ isOpen={isOpen}
848
+ onOpenChange={onOpenChange}
849
+ trigger={trigger}
850
+ title={<span className="flex items-center gap-2">{icon} {title}</span>}
851
+ description={description}
852
+ confirmText={confirmText}
853
+ cancelText={cancelText}
854
+ onConfirm={onConfirm}
855
+ onCancel={onCancel}
856
+ className={className}
857
+ variant="glass"
858
+ >
859
+ {children}
860
+ </Modal>
861
+ )
862
+ }
863
+
864
+ export interface DangerModalProps {
865
+ isOpen?: boolean;
866
+ onOpenChange?: (open: boolean) => void;
867
+ trigger?: React.ReactNode;
868
+ icon?: React.ReactNode;
869
+ title?: string;
870
+ description?: string;
871
+ children?: React.ReactNode;
872
+ confirmText?: string;
873
+ cancelText?: string;
874
+ onConfirm?: () => void;
875
+ onCancel?: () => void;
876
+ className?: string;
877
+ }
878
+
879
+ export const DangerModal = ({
880
+ isOpen,
881
+ onOpenChange,
882
+ trigger,
883
+ icon = <X className="w-8 h-8" />,
884
+ title = "Are you absolutely sure?",
885
+ description = "This action cannot be undone. This will permanently delete your account and remove your data from our servers.",
886
+ children,
887
+ confirmText = "Delete",
888
+ cancelText = "Cancel",
889
+ onConfirm,
890
+ onCancel,
891
+ className = ""
892
+ }: DangerModalProps) => {
893
+ return (
894
+ <Modal
895
+ isOpen={isOpen}
896
+ onOpenChange={onOpenChange}
897
+ trigger={trigger}
898
+ title={title}
899
+ description={description}
900
+ confirmText={confirmText}
901
+ cancelText={cancelText}
902
+ onConfirm={onConfirm}
903
+ onCancel={onCancel}
904
+ className={className}
905
+ variant="destructive"
906
+ >
907
+ {children}
908
+ </Modal>
909
+ )
910
+ }
911
+
912
+ export interface GlassModalProps {
913
+ trigger?: React.ReactNode
914
+ title?: React.ReactNode
915
+ description?: React.ReactNode
916
+ children?: React.ReactNode
917
+ open?: boolean
918
+ onOpenChange?: (open: boolean) => void
919
+ }
920
+
921
+ export function GlassModal({ trigger, title = "Glass Modal", description, children, open, onOpenChange }: GlassModalProps) {
922
+ return (
923
+ <Modal
924
+ isOpen={open}
925
+ onOpenChange={onOpenChange}
926
+ trigger={trigger}
927
+ title={title}
928
+ description={description}
929
+ variant="glass"
930
+ >
931
+ {children}
932
+ </Modal>
933
+ )
934
+ }
935
+
936
+ export interface AlertModalProps {
937
+ trigger?: React.ReactNode
938
+ title?: string
939
+ description?: string
940
+ onConfirm?: () => void
941
+ onCancel?: () => void
942
+ confirmText?: string
943
+ cancelText?: string
944
+ children?: React.ReactNode
945
+ open?: boolean
946
+ onOpenChange?: (open: boolean) => void
947
+ }
948
+
949
+ export function AlertModal({
950
+ trigger,
951
+ title = "Are you absolutely sure?",
952
+ description,
953
+ onConfirm,
954
+ onCancel,
955
+ confirmText = "Confirm",
956
+ cancelText = "Cancel",
957
+ children,
958
+ open,
959
+ onOpenChange
960
+ }: AlertModalProps) {
961
+ return (
962
+ <Modal
963
+ isOpen={open}
964
+ onOpenChange={onOpenChange}
965
+ trigger={trigger}
966
+ title={title}
967
+ description={description}
968
+ confirmText={confirmText}
969
+ cancelText={cancelText}
970
+ onConfirm={onConfirm}
971
+ onCancel={onCancel}
972
+ variant="destructive"
973
+ >
974
+ {children}
975
+ </Modal>
976
+ )
977
+ }
978
+
979
+ export interface SuccessModalProps {
980
+ trigger?: React.ReactNode
981
+ title?: string
982
+ description?: string
983
+ children?: React.ReactNode
984
+ open?: boolean
985
+ onOpenChange?: (open: boolean) => void
986
+ confirmText?: string
987
+ onConfirm?: () => void
988
+ }
989
+
990
+ export function SuccessModal({
991
+ trigger,
992
+ title = "Success!",
993
+ description,
994
+ children,
995
+ open,
996
+ onOpenChange,
997
+ confirmText = "Awesome",
998
+ onConfirm
999
+ }: SuccessModalProps) {
1000
+ return (
1001
+ <Modal
1002
+ isOpen={open}
1003
+ onOpenChange={onOpenChange}
1004
+ trigger={trigger}
1005
+ title={title}
1006
+ description={description}
1007
+ confirmText={confirmText}
1008
+ onConfirm={onConfirm}
1009
+ variant="success"
1010
+ >
1011
+ {children}
1012
+ </Modal>
1013
+ )
1014
+ }
1015
+
1016
+ export interface CommandPaletteModalProps {
1017
+ trigger: React.ReactNode
1018
+ open?: boolean
1019
+ onOpenChange?: (open: boolean) => void
1020
+ }
1021
+
1022
+ export function CommandPaletteModal({ trigger, open, onOpenChange }: CommandPaletteModalProps) {
1023
+ return (
1024
+ <Dialog open={open} onOpenChange={onOpenChange}>
1025
+ <DialogTrigger asChild>{trigger}</DialogTrigger>
1026
+ <DialogContent className="p-0 overflow-hidden sm:max-w-[600px] gap-0">
1027
+ <div className="flex items-center border-b px-3">
1028
+ <svg className="mr-2 h-4 w-4 shrink-0 opacity-50" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>
1029
+ <input className="flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50" placeholder="Type a command or search..." />
1030
+ </div>
1031
+ <div className="max-h-[300px] overflow-y-auto p-2">
1032
+ <div className="px-2 py-1.5 text-xs font-medium text-muted-foreground">Suggestions</div>
1033
+ <div className="flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground hover:bg-accent/50">
1034
+ Calendar
1035
+ </div>
1036
+ <div className="flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground hover:bg-accent/50">
1037
+ Search Emoji
1038
+ </div>
1039
+ <div className="flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground hover:bg-accent/50">
1040
+ Calculator
1041
+ </div>
1042
+ </div>
1043
+ </DialogContent>
1044
+ </Dialog>
1045
+ )
1046
+ }
1047
+
1048
+ export interface BottomSheetSimulatedProps {
1049
+ trigger: React.ReactNode
1050
+ children?: React.ReactNode
1051
+ open?: boolean
1052
+ onOpenChange?: (open: boolean) => void
1053
+ }
1054
+
1055
+ export function BottomSheetSimulated({ trigger, children, open, onOpenChange }: BottomSheetSimulatedProps) {
1056
+ return (
1057
+ <Dialog open={open} onOpenChange={onOpenChange}>
1058
+ <DialogTrigger asChild>{trigger}</DialogTrigger>
1059
+ <DialogContent className="sm:max-w-full sm:h-[50vh] sm:rounded-b-none sm:rounded-t-[10px] fixed bottom-0 top-auto translate-y-0 data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom">
1060
+ <div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
1061
+ {children}
1062
+ </DialogContent>
1063
+ </Dialog>
1064
+ )
1065
+ }
419
1066
  `
420
1067
  };
421
1068
 
@@ -426,18 +1073,20 @@ var card = {
426
1073
  "class-variance-authority",
427
1074
  "clsx",
428
1075
  "tailwind-merge",
429
- "framer-motion"
1076
+ "framer-motion",
1077
+ "lucide-react"
430
1078
  ],
431
1079
  fileName: "card.tsx",
432
1080
  content: `'use client';
433
1081
 
434
1082
  import * as React from "react"
435
1083
  import { cn } from "../utils/cn"
436
- import { motion, HTMLMotionProps } from "framer-motion"
1084
+ import { motion, useMotionValue, useSpring, useTransform, HTMLMotionProps } from "framer-motion"
437
1085
  import { cva, type VariantProps } from "class-variance-authority"
1086
+ import { Heart, Share2, MapPin, Star } from "lucide-react"
438
1087
 
439
1088
  const cardVariants = cva(
440
- "rounded-2xl text-card-foreground transition-all duration-300",
1089
+ "rounded-2xl text-card-foreground transition-all duration-300 overflow-hidden",
441
1090
  {
442
1091
  variants: {
443
1092
  variant: {
@@ -445,11 +1094,16 @@ const cardVariants = cva(
445
1094
  glass: "backdrop-blur-md bg-white/10 dark:bg-black/20 border border-white/20 dark:border-white/10 shadow-lg",
446
1095
  gradient: "bg-gradient-to-br from-violet-500/10 via-pink-500/10 to-orange-500/10 border border-purple-500/20 shadow-lg shadow-purple-500/5",
447
1096
  glow: "bg-card border-2 border-primary/20 shadow-[0_0_15px_rgba(var(--primary-rgb),0.1)] hover:shadow-[0_0_25px_rgba(var(--primary-rgb),0.2)]",
1097
+ // New variants
1098
+ bento: "border border-border/60 bg-gradient-to-br from-card to-muted/20 text-card-foreground shadow-md hover:shadow-lg hover:border-primary/30 relative",
1099
+ spotlight: "border bg-card text-card-foreground relative hover:border-primary/20",
1100
+ flip: "bg-transparent border-0 shadow-none overflow-visible relative",
1101
+ tilt: "border bg-card text-card-foreground shadow-md",
448
1102
  },
449
1103
  hover: {
450
1104
  none: "",
451
- lift: "hover:-translate-y-1 hover:shadow-lg",
452
- glow: "hover:border-primary/50 hover:shadow-[0_0_20px_rgba(var(--primary-rgb),0.15)]",
1105
+ lift: "hover:-translate-y-1.5 hover:shadow-lg",
1106
+ glow: "hover:border-primary/50 hover:shadow-[0_0_25px_rgba(var(--primary-rgb),0.25)]",
453
1107
  }
454
1108
  },
455
1109
  defaultVariants: {
@@ -459,43 +1113,112 @@ const cardVariants = cva(
459
1113
  }
460
1114
  )
461
1115
 
1116
+ /**
1117
+ * Props for the Card component
1118
+ */
462
1119
  export interface CardProps
463
- extends Omit<React.HTMLAttributes<HTMLDivElement>, keyof HTMLMotionProps<"div">>,
1120
+ extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'>,
464
1121
  VariantProps<typeof cardVariants> {
465
1122
  /**
466
- * Whether to enable hover animations
1123
+ * Whether to enable hover spring animations
467
1124
  * @default true
468
1125
  */
469
1126
  animate?: boolean;
470
1127
  /**
471
- * The title of the card
1128
+ * The main title of the card
472
1129
  */
473
1130
  title?: React.ReactNode;
474
1131
  /**
475
- * The description of the card
1132
+ * The subtitle or description of the card
476
1133
  */
477
1134
  description?: React.ReactNode;
478
1135
  /**
479
- * The footer content of the card
1136
+ * Content to render in the card footer area
480
1137
  */
481
1138
  footer?: React.ReactNode;
482
1139
  /**
483
- * An image URL to display at the top of the card
1140
+ * An optional image URL to display at the top of the card
484
1141
  */
485
1142
  image?: string;
486
- }
487
-
488
- const Card = React.forwardRef<HTMLDivElement, CardProps & HTMLMotionProps<"div">>(
489
- ({ className, variant, hover, animate = true, title, description, footer, image, children, ...props }, ref) => {
1143
+ /**
1144
+ * HTML alternative text for the image
1145
+ */
1146
+ imageAlt?: string;
1147
+ /**
1148
+ * Back content displayed when using the \`flip\` variant on hover
1149
+ */
1150
+ backContent?: React.ReactNode;
1151
+ /**
1152
+ * Custom radial spotlight background color (e.g., rgba(168, 85, 247, 0.15))
1153
+ * @default "rgba(139, 92, 246, 0.15)"
1154
+ */
1155
+ spotlightColor?: string;
1156
+ }
1157
+
1158
+ const Card = React.forwardRef<HTMLDivElement, CardProps>(
1159
+ (
1160
+ {
1161
+ className,
1162
+ variant,
1163
+ hover,
1164
+ animate = true,
1165
+ title,
1166
+ description,
1167
+ footer,
1168
+ image,
1169
+ imageAlt,
1170
+ backContent,
1171
+ spotlightColor = "rgba(139, 92, 246, 0.15)",
1172
+ children,
1173
+ ...props
1174
+ },
1175
+ ref
1176
+ ) => {
490
1177
  const isCompound = !title && !description && !footer && !image;
491
1178
 
492
- const content = isCompound ? (
1179
+ // Feature toggles based on variants
1180
+ const isSpotlight = variant === "spotlight";
1181
+ const isFlip = variant === "flip";
1182
+ const isTilt = variant === "tilt";
1183
+
1184
+ // Spotlight mouse tracking state
1185
+ const [mousePos, setMousePos] = React.useState({ x: 0, y: 0 });
1186
+ const handleMouseMoveSpotlight = (e: React.MouseEvent<HTMLDivElement>) => {
1187
+ if (!isSpotlight) return;
1188
+ const { currentTarget, clientX, clientY } = e;
1189
+ const { left, top } = currentTarget.getBoundingClientRect();
1190
+ setMousePos({ x: clientX - left, y: clientY - top });
1191
+ };
1192
+
1193
+ // Tilt mouse tracking state
1194
+ const [tiltPos, setTiltPos] = React.useState({ rotateX: 0, rotateY: 0 });
1195
+ const handleMouseMoveTilt = (e: React.MouseEvent<HTMLDivElement>) => {
1196
+ if (!isTilt) return;
1197
+ const { currentTarget, clientX, clientY } = e;
1198
+ const { left, top, width, height } = currentTarget.getBoundingClientRect();
1199
+ const x = clientX - left;
1200
+ const y = clientY - top;
1201
+ const maxTilt = 12; // degrees max rotation
1202
+ const rotateX = ((y - height / 2) / (height / 2)) * -maxTilt;
1203
+ const rotateY = ((x - width / 2) / (width / 2)) * maxTilt;
1204
+ setTiltPos({ rotateX, rotateY });
1205
+ };
1206
+
1207
+ const handleMouseLeaveTilt = () => {
1208
+ if (!isTilt) return;
1209
+ setTiltPos({ rotateX: 0, rotateY: 0 });
1210
+ };
1211
+
1212
+ // Flip card hover state
1213
+ const [isFlipped, setIsFlipped] = React.useState(false);
1214
+
1215
+ const baseContent = isCompound ? (
493
1216
  children
494
1217
  ) : (
495
1218
  <>
496
1219
  {image && (
497
1220
  <div className="relative w-full h-48 overflow-hidden rounded-t-2xl">
498
- <img src={image} alt={typeof title === 'string' ? title : 'Card image'} className="object-cover w-full h-full" />
1221
+ <img src={image} alt={imageAlt || (typeof title === 'string' ? title : 'Card image')} className="object-cover w-full h-full transition-transform duration-300 hover:scale-105" />
499
1222
  </div>
500
1223
  )}
501
1224
  {(title || description) && (
@@ -509,16 +1232,78 @@ const Card = React.forwardRef<HTMLDivElement, CardProps & HTMLMotionProps<"div">
509
1232
  </>
510
1233
  );
511
1234
 
512
- if (animate) {
1235
+ // Destructure custom props to avoid DOM validation warnings
1236
+ const { ...htmlProps } = props;
1237
+
1238
+ // Flip Variant Render
1239
+ if (isFlip) {
1240
+ return (
1241
+ <div
1242
+ ref={ref}
1243
+ className={cn(cardVariants({ variant, hover, className }), "perspective-1000 w-full h-full")}
1244
+ onMouseEnter={() => setIsFlipped(true)}
1245
+ onMouseLeave={() => setIsFlipped(false)}
1246
+ {...(htmlProps as React.HTMLAttributes<HTMLDivElement>)}
1247
+ >
1248
+ <motion.div
1249
+ className="relative w-full h-full transition-all duration-500 preserve-3d"
1250
+ animate={{ rotateY: isFlipped ? 180 : 0 }}
1251
+ transition={{ type: "spring", stiffness: 300, damping: 22 }}
1252
+ >
1253
+ {/* Front Face */}
1254
+ <div className="absolute inset-0 backface-hidden border bg-card text-card-foreground rounded-2xl shadow-sm flex flex-col justify-between overflow-hidden">
1255
+ {baseContent}
1256
+ </div>
1257
+
1258
+ {/* Back Face */}
1259
+ <div className="absolute inset-0 backface-hidden rotate-y-180 border bg-gradient-to-br from-primary/10 to-primary/5 text-card-foreground rounded-2xl shadow-sm flex flex-col p-6 items-center justify-center text-center overflow-hidden">
1260
+ {backContent || (
1261
+ <div className="text-sm font-medium text-muted-foreground">
1262
+ Flip side content placeholder
1263
+ </div>
1264
+ )}
1265
+ </div>
1266
+ </motion.div>
1267
+ </div>
1268
+ );
1269
+ }
1270
+
1271
+ // Spotlight Variant Render Extra Element
1272
+ const spotlightEffect = isSpotlight && (
1273
+ <div
1274
+ className="pointer-events-none absolute -inset-px rounded-2xl opacity-0 hover:opacity-100 group-hover:opacity-100 transition-opacity duration-300"
1275
+ style={{
1276
+ background: \`radial-gradient(400px circle at \${mousePos.x}px \${mousePos.y}px, \${spotlightColor}, transparent 80%)\`,
1277
+ }}
1278
+ />
1279
+ );
1280
+
1281
+ // Build the resolved element attributes
1282
+ const cardClass = cn(cardVariants({ variant, hover: isFlip || isTilt ? "none" : hover, className }), isSpotlight && "group");
1283
+
1284
+ if (animate || isTilt) {
513
1285
  return (
514
1286
  <motion.div
515
1287
  ref={ref}
516
- className={cn(cardVariants({ variant, hover, className }))}
517
- whileHover={{ scale: 1.01 }}
1288
+ className={cardClass}
1289
+ onMouseMove={(e) => {
1290
+ if (isSpotlight) handleMouseMoveSpotlight(e);
1291
+ if (isTilt) handleMouseMoveTilt(e);
1292
+ }}
1293
+ onMouseLeave={() => {
1294
+ if (isTilt) handleMouseLeaveTilt();
1295
+ }}
1296
+ animate={
1297
+ isTilt
1298
+ ? { rotateX: tiltPos.rotateX, rotateY: tiltPos.rotateY }
1299
+ : undefined
1300
+ }
1301
+ whileHover={isTilt ? undefined : { scale: 1.015 }}
518
1302
  transition={{ type: "spring", stiffness: 300, damping: 20 }}
519
- {...props}
1303
+ {...(htmlProps as any)}
520
1304
  >
521
- {content as React.ReactNode}
1305
+ {spotlightEffect}
1306
+ {baseContent}
522
1307
  </motion.div>
523
1308
  );
524
1309
  }
@@ -526,10 +1311,10 @@ const Card = React.forwardRef<HTMLDivElement, CardProps & HTMLMotionProps<"div">
526
1311
  return (
527
1312
  <div
528
1313
  ref={ref}
529
- className={cn(cardVariants({ variant, hover, className }))}
530
- {...(props as React.HTMLAttributes<HTMLDivElement>)}
1314
+ className={cardClass}
1315
+ {...(htmlProps as React.HTMLAttributes<HTMLDivElement>)}
531
1316
  >
532
- {content as React.ReactNode}
1317
+ {baseContent}
533
1318
  </div>
534
1319
  );
535
1320
  }
@@ -554,7 +1339,7 @@ const CardTitle = React.forwardRef<
554
1339
  >(({ className, ...props }, ref) => (
555
1340
  <h3
556
1341
  ref={ref}
557
- className="font-semibold leading-none tracking-tight text-xl bg-gradient-to-br from-foreground to-foreground/70 bg-clip-text text-transparent"
1342
+ className={cn("font-semibold leading-none tracking-tight text-xl bg-gradient-to-br from-foreground to-foreground/75 bg-clip-text text-transparent", className)}
558
1343
  {...props}
559
1344
  />
560
1345
  ))
@@ -566,7 +1351,7 @@ const CardDescription = React.forwardRef<
566
1351
  >(({ className, ...props }, ref) => (
567
1352
  <p
568
1353
  ref={ref}
569
- className={cn("text-sm text-muted-foreground", className)}
1354
+ className={cn("text-sm text-muted-foreground leading-relaxed mt-1", className)}
570
1355
  {...props}
571
1356
  />
572
1357
  ))
@@ -576,7 +1361,7 @@ const CardContent = React.forwardRef<
576
1361
  HTMLDivElement,
577
1362
  React.HTMLAttributes<HTMLDivElement>
578
1363
  >(({ className, ...props }, ref) => (
579
- <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
1364
+ <div ref={ref} className={cn("p-6 pt-0 leading-relaxed text-sm text-foreground/90", className)} {...props} />
580
1365
  ))
581
1366
  CardContent.displayName = "CardContent"
582
1367
 
@@ -586,13 +1371,199 @@ const CardFooter = React.forwardRef<
586
1371
  >(({ className, ...props }, ref) => (
587
1372
  <div
588
1373
  ref={ref}
589
- className={cn("flex items-center p-6 pt-0", className)}
1374
+ className={cn("flex items-center p-6 pt-0 border-t border-border/10 mt-auto", className)}
590
1375
  {...props}
591
1376
  />
592
1377
  ))
593
1378
  CardFooter.displayName = "CardFooter"
594
1379
 
595
1380
  export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
1381
+
1382
+ export const GlassCard = React.forwardRef<HTMLDivElement, CardProps>(
1383
+ ({ children, ...props }, ref) => (
1384
+ <Card ref={ref} variant="glass" {...props}>
1385
+ {children}
1386
+ </Card>
1387
+ )
1388
+ );
1389
+ GlassCard.displayName = "GlassCard";
1390
+
1391
+ export const GlowCard = React.forwardRef<HTMLDivElement, CardProps>(
1392
+ ({ children, ...props }, ref) => (
1393
+ <Card ref={ref} variant="glow" {...props}>
1394
+ {children}
1395
+ </Card>
1396
+ )
1397
+ );
1398
+ GlowCard.displayName = "GlowCard";
1399
+
1400
+ export const GradientCard = React.forwardRef<HTMLDivElement, CardProps>(
1401
+ ({ children, ...props }, ref) => (
1402
+ <Card ref={ref} variant="gradient" {...props}>
1403
+ {children}
1404
+ </Card>
1405
+ )
1406
+ );
1407
+ GradientCard.displayName = "GradientCard";
1408
+
1409
+ export const HoverCard = React.forwardRef<HTMLDivElement, CardProps>(
1410
+ ({ children, ...props }, ref) => (
1411
+ <Card ref={ref} hover="lift" {...props}>
1412
+ {children}
1413
+ </Card>
1414
+ )
1415
+ );
1416
+ HoverCard.displayName = "HoverCard";
1417
+
1418
+ export const SpotlightCard = React.forwardRef<HTMLDivElement, CardProps>(
1419
+ ({ children, ...props }, ref) => (
1420
+ <Card ref={ref} variant="spotlight" {...props}>
1421
+ {children}
1422
+ </Card>
1423
+ )
1424
+ );
1425
+ SpotlightCard.displayName = "SpotlightCard";
1426
+
1427
+ // ============================================
1428
+ // Consolidated Legacy/Special Cards for Compatibility
1429
+ // ============================================
1430
+
1431
+ export const ImageCard = ({ src, title, subtitle, imageUrl, description }: any) => {
1432
+ const finalSrc = src || imageUrl;
1433
+ const finalTitle = title;
1434
+ const finalSubtitle = subtitle || description;
1435
+ return (
1436
+ <div className="group relative overflow-hidden rounded-xl border bg-card text-card-foreground">
1437
+ <div className="aspect-[4/3] w-full bg-muted overflow-hidden">
1438
+ {finalSrc ? (
1439
+ <img
1440
+ src={finalSrc}
1441
+ className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500"
1442
+ alt={typeof finalTitle === "string" ? finalTitle : "Image"}
1443
+ />
1444
+ ) : (
1445
+ <div className="w-full h-full bg-muted-foreground/20" />
1446
+ )}
1447
+ </div>
1448
+ <div className="p-4">
1449
+ <h3 className="font-semibold text-lg">{finalTitle}</h3>
1450
+ <p className="text-sm text-muted-foreground">{finalSubtitle}</p>
1451
+ </div>
1452
+ </div>
1453
+ );
1454
+ };
1455
+
1456
+ export const ProfileCard = ({ name, role, avatar }: any) => (
1457
+ <div className="flex flex-col items-center p-6 text-center rounded-xl border bg-card shadow-sm">
1458
+ <div className="w-24 h-24 rounded-full bg-muted mb-4 overflow-hidden border-4 border-background shadow-md">
1459
+ {avatar && <img src={avatar} className="w-full h-full object-cover" alt={name} />}
1460
+ </div>
1461
+ <h3 className="text-xl font-bold">{name}</h3>
1462
+ <p className="text-sm text-muted-foreground mb-4">{role}</p>
1463
+ <button className="px-6 py-2 bg-primary text-primary-foreground rounded-full font-medium w-full hover:bg-primary/90 transition-colors">Follow</button>
1464
+ </div>
1465
+ )
1466
+
1467
+ export const ProductCard = ({ title, price, category, src }: any) => (
1468
+ <div className="rounded-xl border bg-card p-4 flex flex-col gap-3 group">
1469
+ <div className="aspect-square w-full rounded-lg bg-muted overflow-hidden relative">
1470
+ {src && <img src={src} className="w-full h-full object-cover" alt={title} />}
1471
+ <button className="absolute top-2 right-2 p-2 bg-background/50 backdrop-blur rounded-full hover:bg-background transition-colors"><Heart className="w-4 h-4" /></button>
1472
+ </div>
1473
+ <div>
1474
+ <p className="text-xs text-muted-foreground mb-1">{category}</p>
1475
+ <h3 className="font-medium truncate">{title}</h3>
1476
+ <p className="font-bold text-lg mt-1">\${price}</p>
1477
+ </div>
1478
+ </div>
1479
+ )
1480
+
1481
+ export const ArticleCard = ({ title, excerpt, date }: any) => (
1482
+ <div className="p-6 rounded-xl border bg-card flex flex-col gap-4 hover:shadow-md transition-shadow cursor-pointer">
1483
+ <span className="text-xs font-medium text-primary">{date}</span>
1484
+ <h3 className="text-xl font-bold leading-tight">{title}</h3>
1485
+ <p className="text-muted-foreground line-clamp-3">{excerpt}</p>
1486
+ <div className="mt-auto pt-4 border-t flex items-center justify-between text-sm">
1487
+ <span className="font-medium">Read more \u2192</span>
1488
+ <button><Share2 className="w-4 h-4 text-muted-foreground hover:text-foreground" /></button>
1489
+ </div>
1490
+ </div>
1491
+ )
1492
+
1493
+ export const StatCardSimple = ({ label, value, trend }: any) => (
1494
+ <div className="p-5 rounded-xl border bg-card">
1495
+ <p className="text-sm font-medium text-muted-foreground mb-2">{label}</p>
1496
+ <div className="flex items-end justify-between">
1497
+ <h4 className="text-3xl font-bold">{value}</h4>
1498
+ <span className={\`text-sm font-medium \${trend?.startsWith('+') ? 'text-green-500' : 'text-red-500'}\`}>{trend}</span>
1499
+ </div>
1500
+ </div>
1501
+ )
1502
+
1503
+ export const PricingCardBasic = ({ name, price, features }: any) => (
1504
+ <div className="p-6 rounded-xl border bg-card flex flex-col items-center text-center">
1505
+ <h3 className="text-xl font-medium mb-2">{name}</h3>
1506
+ <div className="mb-6"><span className="text-4xl font-bold">\${price}</span><span className="text-muted-foreground">/mo</span></div>
1507
+ <ul className="space-y-3 w-full mb-8 text-sm">
1508
+ {features?.map((f: string, i: number) => <li key={i} className="text-muted-foreground border-b pb-2 last:border-0">{f}</li>)}
1509
+ </ul>
1510
+ <button className="w-full py-2 bg-primary text-primary-foreground rounded-lg font-medium mt-auto">Subscribe</button>
1511
+ </div>
1512
+ )
1513
+
1514
+ export const WeatherCard = ({ city, temp, condition }: any) => (
1515
+ <div className="p-6 rounded-xl border bg-gradient-to-br from-blue-500 to-cyan-400 text-white shadow-lg">
1516
+ <div className="flex justify-between items-start mb-8">
1517
+ <div>
1518
+ <h3 className="text-2xl font-bold">{city}</h3>
1519
+ <p className="opacity-80">{condition}</p>
1520
+ </div>
1521
+ <div className="text-5xl font-light">{temp}\xB0</div>
1522
+ </div>
1523
+ <div className="flex gap-4 opacity-90 text-sm">
1524
+ <span>H: {temp + 4}\xB0</span>
1525
+ <span>L: {temp - 3}\xB0</span>
1526
+ </div>
1527
+ </div>
1528
+ )
1529
+
1530
+ export const EventCard = ({ title, date, location }: any) => (
1531
+ <div className="flex p-4 rounded-xl border bg-card gap-4">
1532
+ <div className="flex flex-col items-center justify-center bg-primary/10 text-primary rounded-lg px-4 py-2 min-w-[70px]">
1533
+ <span className="text-xs uppercase font-bold">{date?.split(' ')[0]}</span>
1534
+ <span className="text-2xl font-black">{date?.split(' ')[1]}</span>
1535
+ </div>
1536
+ <div className="flex flex-col justify-center">
1537
+ <h3 className="font-bold text-lg leading-tight mb-1">{title}</h3>
1538
+ <div className="flex items-center text-sm text-muted-foreground gap-1">
1539
+ <MapPin className="w-3 h-3" /> {location}
1540
+ </div>
1541
+ </div>
1542
+ </div>
1543
+ )
1544
+
1545
+ export const TestimonialCardBasic = ({ text, author }: any) => (
1546
+ <div className="p-6 rounded-xl border bg-muted/30 italic relative">
1547
+ <span className="absolute top-4 left-4 text-4xl text-primary/20 font-serif">"</span>
1548
+ <p className="relative z-10 text-muted-foreground mb-4 pt-4">{text}</p>
1549
+ <div className="flex items-center gap-2">
1550
+ <div className="w-8 h-8 rounded-full bg-primary/20" />
1551
+ <span className="font-semibold text-sm not-italic">{author}</span>
1552
+ </div>
1553
+ </div>
1554
+ )
1555
+
1556
+ export const InteractiveCard = ({ title, description }: any) => (
1557
+ <div className="group p-6 rounded-xl border bg-card hover:bg-primary hover:text-primary-foreground transition-all duration-300 cursor-pointer">
1558
+ <div className="w-12 h-12 rounded-lg bg-primary/10 text-primary group-hover:bg-primary-foreground/20 group-hover:text-primary-foreground flex items-center justify-center mb-4 transition-colors">
1559
+ <Star className="w-6 h-6" />
1560
+ </div>
1561
+ <h3 className="text-xl font-bold mb-2">{title}</h3>
1562
+ <p className="text-muted-foreground group-hover:text-primary-foreground/80 transition-colors">{description}</p>
1563
+ </div>
1564
+ )
1565
+
1566
+
596
1567
  `
597
1568
  };
598
1569
 
@@ -603,7 +1574,8 @@ var alert = {
603
1574
  "class-variance-authority",
604
1575
  "clsx",
605
1576
  "tailwind-merge",
606
- "framer-motion"
1577
+ "framer-motion",
1578
+ "lucide-react"
607
1579
  ],
608
1580
  fileName: "alert.tsx",
609
1581
  content: `"use client"
@@ -611,10 +1583,11 @@ var alert = {
611
1583
  import * as React from "react"
612
1584
  import { cva, type VariantProps } from "class-variance-authority"
613
1585
  import { cn } from "../utils/cn"
614
- import { motion, HTMLMotionProps } from "framer-motion"
1586
+ import { motion, AnimatePresence } from "framer-motion"
1587
+ import { AlertCircle, Info, CheckCircle2, XCircle, Cookie, BellRing, WifiOff, AlertTriangle, X } from "lucide-react"
615
1588
 
616
1589
  const alertVariants = cva(
617
- "relative w-full rounded-xl border p-4 [&>svg~*]:pl-7 [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 transition-all duration-300",
1590
+ "relative w-full rounded-2xl border p-4 [&>svg~*]:pl-7 [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 transition-all duration-300 shadow-sm",
618
1591
  {
619
1592
  variants: {
620
1593
  variant: {
@@ -624,6 +1597,12 @@ const alertVariants = cva(
624
1597
  warning: "border-amber-500/20 bg-amber-500/10 text-amber-600 dark:text-amber-400 [&>svg]:text-amber-600 dark:[&>svg]:text-amber-400",
625
1598
  info: "border-blue-500/20 bg-blue-500/10 text-blue-600 dark:text-blue-400 [&>svg]:text-blue-600 dark:[&>svg]:text-blue-400",
626
1599
  glass: "backdrop-blur-md bg-white/5 dark:bg-black/20 border-white/10 dark:border-white/5 text-foreground",
1600
+ floating: "fixed bottom-5 right-5 z-50 max-w-sm bg-card/95 backdrop-blur-md border border-border/80 text-foreground shadow-[0_10px_30px_rgba(0,0,0,0.25)] animate-slide-up",
1601
+ minimal: "border-0 bg-muted/40 p-3 text-sm rounded-xl text-foreground hover:bg-muted/60 shadow-none [&>svg]:top-3.5",
1602
+ neon: "border-purple-500/50 bg-purple-500/10 text-purple-200 shadow-[0_0_15px_rgba(168,85,247,0.3)] [&>svg]:text-purple-400",
1603
+ cyberpunk: "border-l-4 border-yellow-400 bg-black text-yellow-400 shadow-[4px_4px_0_0_rgba(250,204,21,1)] rounded-none font-mono uppercase [&>svg]:text-yellow-400",
1604
+ gradient: "bg-gradient-to-r from-blue-500/10 to-indigo-500/10 border-blue-500/20 text-foreground [&>svg]:text-blue-500",
1605
+ banner: "w-full bg-indigo-600 text-white border-0 shadow-md rounded-none sm:rounded-xl [&>svg]:text-white",
627
1606
  },
628
1607
  },
629
1608
  defaultVariants: {
@@ -635,76 +1614,85 @@ const alertVariants = cva(
635
1614
  export interface AlertProps
636
1615
  extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'>,
637
1616
  VariantProps<typeof alertVariants> {
638
- /**
639
- * Whether to enable entry animations
640
- * @default true
641
- */
642
1617
  animate?: boolean;
643
- /**
644
- * The title of the alert
645
- */
646
1618
  title?: React.ReactNode;
647
- /**
648
- * The description of the alert
649
- */
650
1619
  description?: React.ReactNode;
651
- /**
652
- * An optional icon to display
653
- */
654
1620
  icon?: React.ReactNode;
655
- /**
656
- * Whether the alert can be dismissed
657
- */
658
1621
  dismissible?: boolean;
659
- /**
660
- * Callback function called when the alert is dismissed
661
- */
662
1622
  onDismiss?: () => void;
1623
+ actionText?: string;
1624
+ onAction?: () => void;
663
1625
  }
664
1626
 
665
1627
  const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
666
- ({ className, variant, animate = true, title, description, icon, dismissible, onDismiss, children, ...props }, ref) => {
667
- const isCompound = !title && !description && !icon;
1628
+ (
1629
+ {
1630
+ className,
1631
+ variant,
1632
+ animate = true,
1633
+ title,
1634
+ description,
1635
+ icon,
1636
+ dismissible = false,
1637
+ onDismiss,
1638
+ actionText,
1639
+ onAction,
1640
+ children,
1641
+ ...props
1642
+ },
1643
+ ref
1644
+ ) => {
668
1645
  const [isOpen, setIsOpen] = React.useState(true);
669
1646
 
670
1647
  if (!isOpen) return null;
671
1648
 
672
- const content = isCompound ? (
673
- children
674
- ) : (
1649
+ const isMinimal = variant === "minimal";
1650
+ const isBanner = variant === "banner";
1651
+
1652
+ const content = (
675
1653
  <>
676
- {icon && <div className="absolute left-4 top-4">{icon}</div>}
677
- <div className={cn(icon ? "pl-7" : "")}>
1654
+ {icon && <div className={cn("absolute left-4", isMinimal ? "top-3" : "top-4")}>{icon}</div>}
1655
+ <div className={cn(icon ? "pl-7" : "", "pr-8")}>
678
1656
  {title && <AlertTitle>{title}</AlertTitle>}
679
1657
  {description && <AlertDescription>{description}</AlertDescription>}
680
1658
  {!title && !description && children}
681
1659
  </div>
1660
+ {isBanner && actionText && (
1661
+ <button
1662
+ onClick={onAction}
1663
+ className="absolute right-12 top-1/2 -translate-y-1/2 text-xs font-bold bg-white text-indigo-600 px-3 py-1.5 rounded-md hover:bg-indigo-50 transition-colors"
1664
+ >
1665
+ {actionText}
1666
+ </button>
1667
+ )}
682
1668
  {dismissible && (
683
1669
  <button
684
1670
  onClick={() => {
685
1671
  setIsOpen(false);
686
1672
  onDismiss?.();
687
1673
  }}
688
- className="absolute right-4 top-4 opacity-70 hover:opacity-100 transition-opacity"
1674
+ className="absolute right-4 top-4 opacity-50 hover:opacity-100 transition-opacity p-0.5 rounded-md hover:bg-muted"
689
1675
  aria-label="Dismiss"
690
1676
  >
691
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
1677
+ <X className="h-4 w-4" />
692
1678
  </button>
693
1679
  )}
694
1680
  </>
695
1681
  );
696
1682
 
1683
+ const alertClass = cn(alertVariants({ variant }), className);
1684
+
697
1685
  if (animate) {
698
1686
  return (
699
1687
  <motion.div
700
1688
  ref={ref}
701
1689
  role="alert"
702
- initial={{ opacity: 0, y: 10 }}
703
- animate={{ opacity: 1, y: 0 }}
704
- exit={{ opacity: 0, y: 10 }}
705
- transition={{ duration: 0.3 }}
706
- className={cn(alertVariants({ variant }), className)}
707
- {...(props as unknown as HTMLMotionProps<"div">)}
1690
+ initial={{ opacity: 0, y: variant === "floating" ? 30 : 15, scale: variant === "floating" ? 0.95 : 1 }}
1691
+ animate={{ opacity: 1, y: 0, scale: 1 }}
1692
+ exit={{ opacity: 0, y: variant === "floating" ? 20 : 10, scale: 0.95 }}
1693
+ transition={{ type: "spring", stiffness: 350, damping: 24 }}
1694
+ className={alertClass}
1695
+ {...(props as any)}
708
1696
  >
709
1697
  {content}
710
1698
  </motion.div>
@@ -715,8 +1703,8 @@ const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
715
1703
  <div
716
1704
  ref={ref}
717
1705
  role="alert"
718
- className={cn(alertVariants({ variant }), className)}
719
- {...props}
1706
+ className={alertClass}
1707
+ {...(props as React.HTMLAttributes<HTMLDivElement>)}
720
1708
  >
721
1709
  {content}
722
1710
  </div>
@@ -731,7 +1719,7 @@ const AlertTitle = React.forwardRef<
731
1719
  >(({ className, ...props }, ref) => (
732
1720
  <h5
733
1721
  ref={ref}
734
- className={cn("mb-1 font-semibold leading-none tracking-tight text-base", className)}
1722
+ className={cn("mb-1 font-semibold leading-none tracking-tight text-base text-foreground", className)}
735
1723
  {...props}
736
1724
  />
737
1725
  ))
@@ -743,13 +1731,137 @@ const AlertDescription = React.forwardRef<
743
1731
  >(({ className, ...props }, ref) => (
744
1732
  <div
745
1733
  ref={ref}
746
- className={cn("text-sm opacity-90 [&_p]:leading-relaxed", className)}
1734
+ className={cn("text-sm text-muted-foreground leading-relaxed mt-1 opacity-90 [&_p]:leading-relaxed", className)}
747
1735
  {...props}
748
1736
  />
749
1737
  ))
750
1738
  AlertDescription.displayName = "AlertDescription"
751
1739
 
1740
+ // ----------------------------------------------------
1741
+ // Merged subcomponents and wrappers
1742
+ // ----------------------------------------------------
1743
+
1744
+ // 1. ToastAlertWrapper
1745
+ export const ToastAlertWrapper = ({ children, className, title, description, time }: any) => (
1746
+ <div className={cn("max-w-sm w-full bg-background border border-border/80 shadow-xl rounded-2xl p-4 flex gap-4 items-start relative", className)}>
1747
+ <CheckCircle2 className="h-5 w-5 text-green-500 shrink-0 mt-0.5" />
1748
+ <div className="flex-1">
1749
+ {title && <h4 className="font-semibold text-sm">{title}</h4>}
1750
+ {description && <p className="text-sm text-muted-foreground mt-1">{description}</p>}
1751
+ {children}
1752
+ </div>
1753
+ {time && <span className="text-xs text-muted-foreground/60">{time}</span>}
1754
+ </div>
1755
+ )
1756
+
1757
+ // 2. CookieAlert
1758
+ export const CookieAlert = ({ onAccept, onDecline }: { onAccept?: () => void; onDecline?: () => void }) => {
1759
+ const [visible, setVisible] = React.useState(true)
1760
+ if (!visible) return null
1761
+ return (
1762
+ <div className="max-w-md bg-card border rounded-2xl p-6 shadow-2xl space-y-4">
1763
+ <div className="flex items-center gap-3">
1764
+ <Cookie className="h-6 w-6 text-orange-500 animate-bounce" />
1765
+ <h4 className="font-bold text-lg">Cookie Preferences</h4>
1766
+ </div>
1767
+ <p className="text-sm text-muted-foreground">
1768
+ We use cookies to improve your experience. By continuing to visit this site you agree to our use of cookies.
1769
+ </p>
1770
+ <div className="flex gap-3 pt-2">
1771
+ <button
1772
+ onClick={() => { setVisible(false); onAccept?.(); }}
1773
+ className="flex-1 px-4 py-2 bg-primary text-primary-foreground hover:bg-primary/95 transition-colors rounded-xl text-sm font-semibold shadow-md shadow-primary/10"
1774
+ >
1775
+ Accept All
1776
+ </button>
1777
+ <button
1778
+ onClick={() => { setVisible(false); onDecline?.(); }}
1779
+ className="flex-1 px-4 py-2 border rounded-xl text-sm font-semibold hover:bg-muted transition-colors"
1780
+ >
1781
+ Decline
1782
+ </button>
1783
+ </div>
1784
+ </div>
1785
+ )
1786
+ }
1787
+
1788
+ // 3. OfflineBanner
1789
+ export const OfflineBanner = () => (
1790
+ <div className="w-full bg-red-600 text-white p-3.5 flex justify-center items-center gap-2 text-sm font-semibold shadow-md sm:rounded-xl">
1791
+ <WifiOff className="w-4 h-4 animate-pulse" /> You are currently offline. Some features may be unavailable.
1792
+ </div>
1793
+ )
1794
+
1795
+ // 4. RateLimitAlert
1796
+ export const RateLimitAlert = () => (
1797
+ <div className="border border-orange-500/30 bg-orange-500/10 p-5 rounded-2xl flex gap-3 items-start max-w-md shadow-sm">
1798
+ <AlertTriangle className="w-5 h-5 text-orange-500 shrink-0 mt-0.5 animate-pulse" />
1799
+ <div className="flex-1">
1800
+ <h4 className="font-bold text-orange-600 dark:text-orange-400">Rate Limit Exceeded</h4>
1801
+ <p className="text-sm text-orange-600/80 dark:text-orange-400/80 mt-1 mb-4">
1802
+ You have made too many requests. Please wait 45 seconds before trying again.
1803
+ </p>
1804
+ <div className="w-full h-1.5 bg-orange-500/20 rounded-full overflow-hidden">
1805
+ <motion.div animate={{ width: ["100%", "0%"] }} transition={{ duration: 45, ease: "linear" }} className="h-full bg-orange-500" />
1806
+ </div>
1807
+ </div>
1808
+ </div>
1809
+ )
1810
+
1811
+ // Re-export original/merged components
752
1812
  export { Alert, AlertTitle, AlertDescription }
1813
+ export const CyberAlert = ({ title, description, variant, ...props }: any) => (
1814
+ <Alert variant="cyberpunk" title={title} description={description} {...props} />
1815
+ )
1816
+ export const SoftAlert = ({ title, description, variant, ...props }: any) => (
1817
+ <Alert variant={variant === "success" ? "success" : "info"} title={title} description={description} {...props} />
1818
+ )
1819
+ export const MinimalAlert = ({ title, description, variant, ...props }: any) => (
1820
+ <Alert variant="minimal" title={title} description={description} {...props} />
1821
+ )
1822
+ export const LeftBorderAlert = ({ title, description, variant, ...props }: any) => (
1823
+ <Alert variant={variant === "warning" ? "warning" : "default"} className="border-l-4 border-l-primary" title={title} description={description} {...props} />
1824
+ )
1825
+ export const IconTopAlert = ({ title, description, variant, ...props }: any) => (
1826
+ <div className="flex flex-col items-center text-center p-6 bg-card border rounded-2xl" {...props}>
1827
+ <div className="h-12 w-12 rounded-full bg-destructive/10 text-destructive flex items-center justify-center mb-4">
1828
+ <AlertCircle className="h-6 w-6" />
1829
+ </div>
1830
+ <h4 className="font-bold text-lg mb-2">{title}</h4>
1831
+ <p className="text-sm text-muted-foreground">{description}</p>
1832
+ </div>
1833
+ )
1834
+ export const SolidAlert = ({ title, description, variant, ...props }: any) => {
1835
+ const bgClasses: Record<string, string> = {
1836
+ error: "bg-red-600 text-white border-0",
1837
+ success: "bg-emerald-600 text-white border-0",
1838
+ warning: "bg-amber-500 text-black border-0",
1839
+ default: "bg-primary text-primary-foreground border-0",
1840
+ }
1841
+ const bgClass = bgClasses[variant] || bgClasses.default
1842
+ return (
1843
+ <div className={cn("p-4 rounded-xl shadow-lg flex gap-3 items-start", bgClass)} {...props}>
1844
+ <Info className="h-5 w-5 shrink-0 mt-0.5" />
1845
+ <div>
1846
+ <h4 className="font-bold">{title}</h4>
1847
+ <p className="text-sm opacity-90 mt-1">{description}</p>
1848
+ </div>
1849
+ </div>
1850
+ )
1851
+ }
1852
+ export const BannerAlert = ({ message, variant, ...props }: any) => (
1853
+ <Alert variant="banner" title={message} {...props} />
1854
+ )
1855
+ export const NeonAlert = ({ title, description, variant, ...props }: any) => (
1856
+ <Alert variant="neon" title={title} description={description} {...props} />
1857
+ )
1858
+ export const GlassAlert = ({ title, description, variant, ...props }: any) => (
1859
+ <Alert variant="glass" title={title} description={description} {...props} />
1860
+ )
1861
+ export const DismissibleAlert = ({ variant, title, description, ...props }: any) => (
1862
+ <Alert variant={variant} title={title || "Attention"} description={description || "Action required"} dismissible={true} {...props} />
1863
+ )
1864
+
753
1865
  `
754
1866
  };
755
1867
 
@@ -760,7 +1872,8 @@ var badge = {
760
1872
  "class-variance-authority",
761
1873
  "clsx",
762
1874
  "tailwind-merge",
763
- "framer-motion"
1875
+ "framer-motion",
1876
+ "lucide-react"
764
1877
  ],
765
1878
  fileName: "badge.tsx",
766
1879
  content: `'use client';
@@ -768,7 +1881,7 @@ var badge = {
768
1881
  import * as React from "react"
769
1882
  import { cva, type VariantProps } from "class-variance-authority"
770
1883
  import { cn } from "../utils/cn"
771
- import { motion } from "framer-motion"
1884
+ import { Star } from "lucide-react"
772
1885
 
773
1886
  const badgeVariants = cva(
774
1887
  "inline-flex items-center gap-1 rounded-full border font-semibold transition-all focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 cursor-default",
@@ -779,9 +1892,8 @@ const badgeVariants = cva(
779
1892
  secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
780
1893
  destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
781
1894
  outline: "text-foreground border-border hover:bg-accent",
782
- // New WOW Variants
783
1895
  gradient: "border-transparent bg-gradient-to-r from-violet-500 to-pink-500 text-white shadow-sm",
784
- neon: "border-primary/50 bg-primary/10 text-primary shadow-[0_0_10px_rgba(var(--primary-rgb),0.3)]",
1896
+ neon: "border-purple-500/50 bg-purple-500/10 text-purple-400 shadow-[0_0_10px_rgba(168,85,247,0.3)]",
785
1897
  success: "border-transparent bg-emerald-500/20 text-emerald-600 dark:text-emerald-400",
786
1898
  },
787
1899
  size: {
@@ -800,19 +1912,12 @@ const badgeVariants = cva(
800
1912
  export interface BadgeProps
801
1913
  extends React.HTMLAttributes<HTMLDivElement>,
802
1914
  VariantProps<typeof badgeVariants> {
803
- /**
804
- * Whether to show a pulse animation on the dot
805
- * @default false
806
- */
807
1915
  pulse?: boolean;
808
- /**
809
- * Whether to show a dot indicator
810
- * @default false
811
- */
812
1916
  dot?: boolean;
1917
+ text?: string;
813
1918
  }
814
1919
 
815
- function Badge({ className, variant, size, pulse = false, dot = false, children, ...props }: BadgeProps) {
1920
+ function Badge({ className, variant, size, pulse = false, dot = false, children, text, ...props }: BadgeProps) {
816
1921
  const showDot = dot || pulse;
817
1922
 
818
1923
  return (
@@ -825,12 +1930,185 @@ function Badge({ className, variant, size, pulse = false, dot = false, children,
825
1930
  <span className="relative inline-flex rounded-full h-2 w-2 bg-current"></span>
826
1931
  </span>
827
1932
  )}
828
- {children}
1933
+ {children || text}
829
1934
  </div>
830
1935
  )
831
1936
  }
832
1937
 
833
1938
  export { Badge, badgeVariants }
1939
+
1940
+ // ----------------------------------------------------
1941
+ // Consolidated Badge Components
1942
+ // ----------------------------------------------------
1943
+
1944
+ export const GlowBadge = ({ children, className, ...props }: BadgeProps) => (
1945
+ <Badge variant="neon" className={className} {...props}>{children}</Badge>
1946
+ )
1947
+
1948
+ export const GlassBadge = ({ children, className, ...props }: BadgeProps) => (
1949
+ <Badge variant="outline" className={cn("backdrop-blur-md bg-white/10 dark:bg-black/20 border-white/20 dark:border-white/10", className)} {...props}>{children}</Badge>
1950
+ )
1951
+
1952
+ export const DotBadge = ({ children, className, ...props }: BadgeProps) => (
1953
+ <Badge dot={true} className={className} {...props}>{children}</Badge>
1954
+ )
1955
+
1956
+ export const GradientBadge = ({ children, className, ...props }: BadgeProps) => (
1957
+ <Badge variant="gradient" className={className} {...props}>{children}</Badge>
1958
+ )
1959
+
1960
+ export const OutlineGlowBadge = ({ children, className, ...props }: BadgeProps) => (
1961
+ <Badge variant="neon" className={cn("bg-transparent border border-purple-500/50", className)} {...props}>{children}</Badge>
1962
+ )
1963
+
1964
+ export const PulseBadge = ({ children, className, ...props }: BadgeProps) => (
1965
+ <Badge pulse={true} className={className} {...props}>{children}</Badge>
1966
+ )
1967
+
1968
+ export const SoftBadge = ({ children, className, ...props }: BadgeProps) => (
1969
+ <Badge variant="secondary" className={className} {...props}>{children}</Badge>
1970
+ )
1971
+
1972
+ export const TagBadge = ({ children, className, ...props }: BadgeProps) => (
1973
+ <Badge className={cn("rounded-md", className)} {...props}>{children}</Badge>
1974
+ )
1975
+
1976
+ export const PremiumBadge = ({ children, className, ...props }: BadgeProps) => (
1977
+ <Badge variant="gradient" className={cn("bg-gradient-to-r from-yellow-500 via-amber-500 to-orange-500", className)} {...props}>{children}</Badge>
1978
+ )
1979
+
1980
+ export const MinimalBadge = ({ children, className, ...props }: BadgeProps) => (
1981
+ <Badge size="sm" variant="outline" className={className} {...props}>{children}</Badge>
1982
+ )
1983
+
1984
+ export const NotificationBadge = ({ count, className }: { count: number; className?: string }) => (
1985
+ <div className={cn("flex h-5 min-w-[20px] px-1 items-center justify-center rounded-full bg-destructive text-[10px] font-bold text-destructive-foreground shadow-sm", className)}>
1986
+ {count}
1987
+ </div>
1988
+ )
1989
+
1990
+ export const RibbonBadge = ({ children, text, className }: { children?: React.ReactNode; text?: string; className?: string }) => (
1991
+ <div className={cn("absolute top-0 right-0 bg-primary text-primary-foreground text-[10px] font-bold px-3 py-1 rounded-bl-xl uppercase tracking-wider", className)}>
1992
+ {children || text}
1993
+ </div>
1994
+ )
1995
+
1996
+ export interface OutlineDotBadgeProps extends React.HTMLAttributes<HTMLDivElement> {
1997
+ status?: string;
1998
+ text?: string;
1999
+ }
2000
+
2001
+ export const OutlineDotBadge = ({ children, className, status, text, ...props }: OutlineDotBadgeProps) => {
2002
+ const statusColors: Record<string, string> = {
2003
+ online: "bg-emerald-500",
2004
+ offline: "bg-muted-foreground/50",
2005
+ away: "bg-amber-500",
2006
+ busy: "bg-red-500",
2007
+ }
2008
+ const dotColor = status ? statusColors[status] || "bg-emerald-500" : "bg-primary"
2009
+ return (
2010
+ <Badge variant="outline" className={className} {...props}>
2011
+ <span className={cn("h-1.5 w-1.5 rounded-full mr-1.5", dotColor)} />
2012
+ {children || text}
2013
+ </Badge>
2014
+ )
2015
+ }
2016
+
2017
+ export interface GradientOutlineBadgeProps extends React.HTMLAttributes<HTMLDivElement> {
2018
+ text?: string;
2019
+ }
2020
+
2021
+ export const GradientOutlineBadge = ({ children, text, className, ...props }: GradientOutlineBadgeProps) => (
2022
+ <Badge className={cn("p-[1px] bg-gradient-to-r from-violet-500 to-pink-500 rounded-full border-0", className)} {...props}>
2023
+ <div className="bg-background text-foreground rounded-full px-2.5 py-0.5 text-xs font-semibold">
2024
+ {children || text}
2025
+ </div>
2026
+ </Badge>
2027
+ )
2028
+
2029
+ export interface IconBadgeProps extends React.HTMLAttributes<HTMLDivElement> {
2030
+ icon?: React.ReactNode;
2031
+ text?: string;
2032
+ }
2033
+
2034
+ export const IconBadge = ({ children, icon, text, className, ...props }: IconBadgeProps) => {
2035
+ const renderIcon = () => {
2036
+ if (!icon) return null;
2037
+ if (typeof icon === "string") {
2038
+ if (icon.toLowerCase() === "star") {
2039
+ return <Star className="h-3 w-3 mr-1" />
2040
+ }
2041
+ return <span className="mr-1">{icon}</span>
2042
+ }
2043
+ return <span className="mr-1">{icon}</span>
2044
+ }
2045
+
2046
+ return (
2047
+ <Badge className={cn("inline-flex items-center gap-1", className)} {...props}>
2048
+ {renderIcon()}
2049
+ {children || text}
2050
+ </Badge>
2051
+ )
2052
+ }
2053
+
2054
+ export interface FloatingBadgeProps extends React.HTMLAttributes<HTMLDivElement> {
2055
+ text?: string;
2056
+ }
2057
+
2058
+ export const FloatingBadge = ({ children, text, className, ...props }: FloatingBadgeProps) => (
2059
+ <Badge className={cn("absolute -top-2 -right-2 z-10 animate-[bounce_3s_infinite]", className)} {...props}>
2060
+ {children || text}
2061
+ </Badge>
2062
+ )
2063
+
2064
+ export interface ProgressBadgeProps extends React.HTMLAttributes<HTMLDivElement> {
2065
+ progress?: number;
2066
+ text?: string;
2067
+ }
2068
+
2069
+ export const ProgressBadge = ({ children, progress = 50, text, className, ...props }: ProgressBadgeProps) => (
2070
+ <Badge variant="outline" className={cn("relative overflow-hidden", className)} {...props}>
2071
+ <div className="absolute inset-y-0 left-0 bg-primary/10 transition-all duration-300" style={{ width: \`\${progress}%\` }} />
2072
+ <span className="relative z-10">{children || (text ? \`\${text} (\${progress}%)\` : \`\${progress}%\`)}</span>
2073
+ </Badge>
2074
+ )
2075
+
2076
+ export interface StatusRingBadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
2077
+ status?: "success" | "error" | "warning" | "active" | string;
2078
+ }
2079
+
2080
+ export const StatusRingBadge = ({ status = "success", children, className, ...props }: StatusRingBadgeProps) => {
2081
+ const ringColors: Record<string, string> = {
2082
+ success: "border-emerald-500/30 ring-emerald-500/20 bg-emerald-500",
2083
+ active: "border-emerald-500/30 ring-emerald-500/20 bg-emerald-500",
2084
+ error: "border-red-500/30 ring-red-500/20 bg-red-500",
2085
+ warning: "border-amber-500/30 ring-amber-500/20 bg-amber-500",
2086
+ }
2087
+ const colorClass = ringColors[status] || ringColors.success;
2088
+ return (
2089
+ <span className={cn("relative flex h-2.5 w-2.5 rounded-full ring-4 border-2 border-transparent", colorClass, className)} {...props} />
2090
+ )
2091
+ }
2092
+
2093
+ export interface NeonOutlineBadgeProps extends React.HTMLAttributes<HTMLDivElement> {
2094
+ text?: string;
2095
+ }
2096
+
2097
+ export const NeonOutlineBadge = ({ children, text, className, ...props }: NeonOutlineBadgeProps) => (
2098
+ <Badge variant="outline" className={cn("border-2 border-primary text-primary shadow-[0_0_10px_rgba(var(--primary-rgb),0.4)] bg-transparent", className)} {...props}>
2099
+ {children || text}
2100
+ </Badge>
2101
+ )
2102
+
2103
+ export interface TagLabelProps extends React.HTMLAttributes<HTMLSpanElement> {
2104
+ text?: string;
2105
+ }
2106
+
2107
+ export const TagLabel = ({ children, text, className, ...props }: TagLabelProps) => (
2108
+ <span className={cn("px-2 py-1 bg-muted text-muted-foreground rounded-md text-xs font-medium text-muted-foreground hover:bg-muted/80 hover:text-foreground cursor-pointer transition-colors before:content-['#'] before:mr-0.5 before:opacity-50", className)} {...props}>
2109
+ {children || text}
2110
+ </span>
2111
+ )
834
2112
  `
835
2113
  };
836
2114
 
@@ -843,111 +2121,142 @@ var registry = {
843
2121
  badge
844
2122
  };
845
2123
 
846
- // src/utils/detect.ts
847
- var fs = __toESM(require("fs"));
848
- var path = __toESM(require("path"));
849
- function detectProject() {
850
- const cwd = process.cwd();
851
- if (fs.existsSync(path.join(cwd, "next.config.ts")) || fs.existsSync(path.join(cwd, "next.config.js")) || fs.existsSync(path.join(cwd, "next.config.mjs"))) {
852
- if (fs.existsSync(path.join(cwd, "app"))) {
853
- return { framework: "Next.js (App Router)", componentsDir: "app/components/ui" };
854
- }
855
- if (fs.existsSync(path.join(cwd, "src", "app"))) {
856
- return { framework: "Next.js (App Router)", componentsDir: "src/app/components/ui" };
857
- }
858
- return { framework: "Next.js (Pages Router)", componentsDir: "components/ui" };
859
- }
860
- if (fs.existsSync(path.join(cwd, "vite.config.ts")) || fs.existsSync(path.join(cwd, "vite.config.js"))) {
861
- if (fs.existsSync(path.join(cwd, "src"))) {
862
- return { framework: "Vite", componentsDir: "src/components/ui" };
863
- }
864
- return { framework: "Vite", componentsDir: "components/ui" };
865
- }
866
- if (fs.existsSync(path.join(cwd, "src"))) {
867
- return { framework: "React", componentsDir: "src/components/ui" };
868
- }
869
- return { framework: "Unknown", componentsDir: "components/ui" };
870
- }
871
-
872
- // src/utils/copy.ts
873
- var fs2 = __toESM(require("fs"));
874
- var path2 = __toESM(require("path"));
875
- function copyComponent(name, entry, outputDir) {
876
- const filePath = path2.join(outputDir, entry.fileName);
877
- const dir = path2.dirname(filePath);
878
- if (!fs2.existsSync(dir)) {
879
- fs2.mkdirSync(dir, { recursive: true });
880
- }
881
- fs2.writeFileSync(filePath, entry.content, "utf-8");
882
- }
883
-
884
2124
  // src/commands/add.ts
2125
+ function askQuestion(query) {
2126
+ const rl = readline.createInterface({
2127
+ input: process.stdin,
2128
+ output: process.stdout
2129
+ });
2130
+ return new Promise(
2131
+ (resolve2) => rl.question(query, (ans) => {
2132
+ rl.close();
2133
+ resolve2(ans);
2134
+ })
2135
+ );
2136
+ }
885
2137
  async function addCommand(components, options) {
886
2138
  if (components.length === 0) {
887
- console.error("\x1B[31mPlease specify at least one component to add.\x1B[0m");
888
- console.log("Example: npx nexoreui add button modal card");
889
- console.log("Run \x1B[32mnpx nexoreui list\x1B[0m to see all available components.");
890
- process.exit(1);
2139
+ console.error("\x1B[31mError: Please specify components to add.\x1B[0m");
2140
+ console.log("Example: npx nexoreui add button modal");
2141
+ return;
891
2142
  }
892
- const invalid = components.filter((c) => !registry[c]);
893
- if (invalid.length > 0) {
894
- console.error(`\x1B[31mUnknown component(s): ${invalid.join(", ")}\x1B[0m`);
2143
+ const project = detectProject(process.cwd());
2144
+ console.log(`
2145
+ \x1B[34mDetected project type:\x1B[0m ${project.projectType.toUpperCase()}`);
2146
+ console.log(`\x1B[34mDetected package manager:\x1B[0m ${project.packageManager}
2147
+ `);
2148
+ const componentsToInstall = /* @__PURE__ */ new Set();
2149
+ const invalidComponents = [];
2150
+ const queue = [...components];
2151
+ while (queue.length > 0) {
2152
+ const compName = queue.shift();
2153
+ const registryItem = registry[compName];
2154
+ if (!registryItem) {
2155
+ invalidComponents.push(compName);
2156
+ continue;
2157
+ }
2158
+ if (!componentsToInstall.has(compName)) {
2159
+ componentsToInstall.add(compName);
2160
+ if (registryItem.componentsDependencies) {
2161
+ for (const dep of registryItem.componentsDependencies) {
2162
+ queue.push(dep);
2163
+ }
2164
+ }
2165
+ }
2166
+ }
2167
+ if (invalidComponents.length > 0) {
2168
+ console.error(`\x1B[31mError: Component(s) not found in registry: ${invalidComponents.join(", ")}\x1B[0m`);
895
2169
  console.log("Run \x1B[32mnpx nexoreui list\x1B[0m to see all available components.");
896
- process.exit(1);
2170
+ return;
2171
+ }
2172
+ const defaultComponentsDir = project.hasSrcDir ? "src/components/ui" : "components/ui";
2173
+ const defaultUtilsFile = project.hasSrcDir ? "src/lib/utils.ts" : "lib/utils.ts";
2174
+ let componentsDirInput = "";
2175
+ let utilsFileInput = "";
2176
+ if (options.yes) {
2177
+ componentsDirInput = defaultComponentsDir;
2178
+ utilsFileInput = defaultUtilsFile;
2179
+ } else {
2180
+ const compPrompt = await askQuestion(`Where would you like to install the components? (default: ${defaultComponentsDir}): `);
2181
+ componentsDirInput = compPrompt.trim() || defaultComponentsDir;
2182
+ const utilsPrompt = await askQuestion(`Where should we create the utilities file (cn helper)? (default: ${defaultUtilsFile}): `);
2183
+ utilsFileInput = utilsPrompt.trim() || defaultUtilsFile;
897
2184
  }
898
- const projectInfo = detectProject();
899
- const outputDir = path3.resolve(process.cwd(), projectInfo.componentsDir);
2185
+ const absoluteComponentsDir = path3.resolve(project.baseDir, componentsDirInput);
2186
+ const absoluteUtilsFile = path3.resolve(project.baseDir, utilsFileInput);
900
2187
  console.log(`
901
- \x1B[34m\x1B[1mNexoreUI CLI\x1B[0m`);
902
- console.log(`Detected: \x1B[36m${projectInfo.framework}\x1B[0m project`);
903
- console.log(`Output: \x1B[36m${outputDir}\x1B[0m
2188
+ \x1B[33mInstalling components to:\x1B[0m ${absoluteComponentsDir}`);
2189
+ console.log(`\x1B[33mUsing cn helper from:\x1B[0m ${absoluteUtilsFile}
904
2190
  `);
905
- if (!fs3.existsSync(outputDir)) {
906
- fs3.mkdirSync(outputDir, { recursive: true });
2191
+ ensureDir(absoluteComponentsDir);
2192
+ const didCreateCn = ensureCnUtil(absoluteUtilsFile);
2193
+ if (didCreateCn) {
2194
+ console.log(`\x1B[32mCreated utilities file (cn helper) at:\x1B[0m ${utilsFileInput}`);
2195
+ } else {
2196
+ console.log(`\x1B[90mUtilities file already exists at:\x1B[0m ${utilsFileInput}`);
907
2197
  }
908
- let successCount = 0;
909
- for (const name of components) {
910
- const entry = registry[name];
911
- if (!entry) continue;
912
- try {
913
- copyComponent(name, entry, outputDir);
914
- console.log(` \x1B[32m\u2713\x1B[0m ${name} \u2192 ${entry.fileName}`);
915
- successCount++;
916
- } catch (err) {
917
- console.error(` \x1B[31m\u2717\x1B[0m ${name}: ${err.message}`);
918
- }
2198
+ const npmDependencies = /* @__PURE__ */ new Set();
2199
+ npmDependencies.add("clsx");
2200
+ npmDependencies.add("tailwind-merge");
2201
+ for (const compName of componentsToInstall) {
2202
+ const registryItem = registry[compName];
2203
+ const targetPath = path3.join(absoluteComponentsDir, registryItem.fileName);
2204
+ copyComponentFile(registryItem.content, targetPath, absoluteUtilsFile);
2205
+ console.log(`\x1B[32mAdded component:\x1B[0m ${compName} -> ${path3.join(componentsDirInput, registryItem.fileName)}`);
2206
+ registryItem.dependencies.forEach((dep) => npmDependencies.add(dep));
919
2207
  }
920
- const allDeps = /* @__PURE__ */ new Set();
921
- for (const name of components) {
922
- const entry = registry[name];
923
- if (entry?.dependencies) {
924
- entry.dependencies.forEach((d) => allDeps.add(d));
2208
+ const depsArray = Array.from(npmDependencies);
2209
+ let depsToInstall = [...depsArray];
2210
+ try {
2211
+ const packageJsonPath = path3.join(project.baseDir, "package.json");
2212
+ if (fs3.existsSync(packageJsonPath)) {
2213
+ const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf8"));
2214
+ const existingDeps = { ...packageJson.dependencies, ...packageJson.devDependencies };
2215
+ depsToInstall = depsArray.filter((dep) => !existingDeps[dep]);
925
2216
  }
2217
+ } catch (e) {
926
2218
  }
927
- console.log(`
928
- \x1B[32m${successCount} component(s) added successfully.\x1B[0m`);
929
- if (allDeps.size > 0) {
2219
+ if (depsToInstall.length > 0) {
930
2220
  console.log(`
931
- Install peer dependencies:`);
932
- console.log(` \x1B[36mpnpm add ${Array.from(allDeps).join(" ")}\x1B[0m
933
- `);
2221
+ \x1B[33mInstalling external dependencies:\x1B[0m ${depsToInstall.join(", ")}...`);
2222
+ let installCmd = "npm install";
2223
+ if (project.packageManager === "pnpm") {
2224
+ installCmd = "pnpm add";
2225
+ } else if (project.packageManager === "yarn") {
2226
+ installCmd = "yarn add";
2227
+ } else if (project.packageManager === "bun") {
2228
+ installCmd = "bun add";
2229
+ }
2230
+ try {
2231
+ (0, import_child_process.execSync)(`${installCmd} ${depsToInstall.join(" ")}`, {
2232
+ stdio: "inherit",
2233
+ cwd: project.baseDir
2234
+ });
2235
+ console.log("\x1B[32mDependencies installed successfully!\x1B[0m");
2236
+ } catch (err) {
2237
+ console.error("\x1B[31mFailed to install dependencies. Please run the command manually:\x1B[0m");
2238
+ console.log(` ${installCmd} ${depsToInstall.join(" ")}`);
2239
+ }
2240
+ } else {
2241
+ console.log("\n\x1B[90mAll external dependencies are already installed.\x1B[0m");
934
2242
  }
2243
+ console.log("\n\x1B[32m\x1B[1mDone! NexoreUI components are ready to use.\x1B[0m\n");
935
2244
  }
936
2245
 
937
2246
  // src/commands/list.ts
938
2247
  function listCommand() {
939
- const names = Object.keys(registry);
940
- console.log(`
941
- \x1B[34m\x1B[1mNexoreUI \u2014 Available Components\x1B[0m
942
- `);
943
- names.forEach((name) => {
944
- const entry = registry[name];
945
- console.log(` \x1B[32m${name.padEnd(15)}\x1B[0m \u2192 ${entry.fileName}`);
2248
+ console.log("\n\x1B[34m\x1B[1m=== Available NexoreUI Components ===\x1B[0m\n");
2249
+ Object.keys(registry).forEach((name) => {
2250
+ const item = registry[name];
2251
+ console.log(`- \x1B[32m\x1B[1m${name}\x1B[0m (${item.fileName})`);
2252
+ if (item.dependencies.length > 0) {
2253
+ console.log(` \x1B[90mDependencies: ${item.dependencies.join(", ")}\x1B[0m`);
2254
+ }
2255
+ if (item.componentsDependencies && item.componentsDependencies.length > 0) {
2256
+ console.log(` \x1B[33mRequires component: ${item.componentsDependencies.join(", ")}\x1B[0m`);
2257
+ }
2258
+ console.log("");
946
2259
  });
947
- console.log(`
948
- \x1B[90mTotal: ${names.length} components\x1B[0m`);
949
- console.log(`Usage: \x1B[36mnpx nexoreui add ${names[0]}\x1B[0m
950
- `);
951
2260
  }
952
2261
 
953
2262
  // src/index.ts