@nehal712521/inprogress 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ "use strict";var C=Object.create;var h=Object.defineProperty;var R=Object.getOwnPropertyDescriptor;var I=Object.getOwnPropertyNames;var E=Object.getPrototypeOf,D=Object.prototype.hasOwnProperty;var P=(n,t,s,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of I(t))!D.call(n,r)&&r!==s&&h(n,r,{get:()=>t[r],enumerable:!(i=R(t,r))||i.enumerable});return n};var g=(n,t,s)=>(s=n!=null?C(E(n)):{},P(t||!n||!n.__esModule?h(s,"default",{value:n,enumerable:!0}):s,n));var b=require("commander"),o=g(require("chalk")),c=g(require("fs-extra")),l=g(require("path")),$=g(require("readline")),S=c.default.readJsonSync(l.default.join(__dirname,"../package.json")),j=l.default.join(__dirname,"../registry"),w=l.default.join(j,"registry.json"),N=l.default.join(j,"components"),e={info:n=>console.log(o.default.cyan(" \u2139 "),n),success:n=>console.log(o.default.green(" \u2714 "),n),warn:n=>console.log(o.default.yellow(" \u26A0 "),n),error:n=>console.log(o.default.red(" \u2716 "),n),step:n=>console.log(o.default.cyan(" \u2192 "),n),blank:()=>console.log()};function k(n){let t=$.createInterface({input:process.stdin,output:process.stdout});return new Promise(s=>{t.question(n,i=>{t.close(),s(i.trim())})})}async function v(){if(!await c.default.pathExists(w))throw new Error(`Registry not found at ${w}`);return c.default.readJson(w)}function x(){console.log(),console.log(o.default.cyan.bold(" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557")),console.log(o.default.cyan.bold(" \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D")),console.log(o.default.cyan.bold(" \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557")),console.log(o.default.cyan.bold(" \u2588\u2588\u2554\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551")),console.log(o.default.cyan.bold(" \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551")),console.log(o.default.cyan.bold(" \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D")),console.log(),console.log(o.default.dim(" UI Components for React & Next.js \u2014 zero config, just copy & use")),console.log()}async function O(n){x();let t=process.cwd(),s=n.path||"components/ui",i=l.default.resolve(t,s);e.step(`Initializing your-ui in ${o.default.dim(s)}...`),await c.default.ensureDir(i),e.success(`Created directory ${o.default.dim(s)}`);let r=l.default.join(t,"components.json"),a={$schema:"https://ui.shadcn.com/schema.json",style:"default",rsc:!0,tsx:!0,tailwind:{config:"tailwind.config.ts",css:"app/globals.css",baseColor:"zinc",cssVariables:!0},aliases:{components:"@/components",utils:"@/lib/utils"}};if(await c.default.pathExists(r)&&!n.yes&&(await k(` ${o.default.yellow("\u26A0")} components.json already exists. Overwrite? ${o.default.dim("(y/N)")} `)).toLowerCase()!=="y"){e.warn("Skipped overwriting components.json");return}await c.default.writeJson(r,a,{spaces:2}),e.success("Created components.json"),e.blank(),e.success("Initialization complete!"),e.info(`Add components with: ${o.default.cyan("npx progress-ui add <component>")}`),e.blank()}async function T(n,t){console.log(),console.log(o.default.bold(`Adding ${o.default.cyan(n)} to your project...`)),e.blank();let s;try{s=await v()}catch(p){e.error(`Failed to load registry: ${p.message}`),process.exit(1)}let i=s.components[n];i||(e.error(`Component "${n}" not found.`),e.info(`Run ${o.default.cyan("npx progress-ui list")} to see available components.`),process.exit(1)),e.success(`Found ${o.default.white(i.displayName)}`),i.dependencies&&i.dependencies.length>0&&(e.blank(),e.warn(`This component has dependencies: ${o.default.white(i.dependencies.join(", "))}`),e.info(`Install them with: ${o.default.cyan(`npm install ${i.dependencies.join(" ")}`)}`));let r=process.cwd(),a=t.path||"components/ui",m=l.default.resolve(r,a);await c.default.ensureDir(m),e.blank();for(let p of i.files){let u=l.default.join(N,p),y=l.default.join(m,p),f=l.default.relative(r,y);if(!await c.default.pathExists(u)){e.error(`Source file not found: ${o.default.dim(u)}`);continue}if(await c.default.pathExists(y)&&!t.overwrite&&(await k(` ${o.default.yellow("\u26A0")} ${o.default.white(f)} already exists. Overwrite? ${o.default.dim("(y/N)")} `)).toLowerCase()!=="y"){e.warn(`Skipped ${f}`);continue}await c.default.copy(u,y),e.success(`Created ${o.default.white(f)}`)}e.blank(),console.log(o.default.green.bold(" Done!"),"Import it in your code:"),e.blank(),console.log(o.default.dim(` import ${i.displayName.replace(/\s/g,"")} from "@/${a}/${i.files[0].replace(".tsx","")}";`)),e.blank()}async function _(){var i,r;e.step("Fetching available components..."),e.blank();let n;try{n=await v()}catch(a){e.error(`Failed to load registry: ${a.message}`),process.exit(1)}let t=Object.values(n.components),s={};for(let a of t)((r=s[i=a.category])!=null?r:s[i]=[]).push(a);for(let[a,m]of Object.entries(s)){console.log(o.default.bold.white(` ${a}`));for(let p of m)console.log(` ${o.default.cyan(p.name.padEnd(20))}${o.default.dim(p.description)}`);e.blank()}console.log(o.default.dim(` Run ${o.default.cyan("npx progress-ui add <name>")} to install any component.`)),e.blank()}var d=new b.Command;d.name("progress-ui").description("CLI to add beautiful UI components to your project").version(S.version);d.command("init").description("Initialize your-ui in your project").option("-p, --path <path>","Target directory for components","components/ui").option("-y, --yes","Skip confirmation prompts").action(O);d.command("add <component>").description("Add a component to your project").option("-p, --path <path>","Target directory for components","components/ui").option("-o, --overwrite","Overwrite existing files without prompting").action(T);d.command("list").alias("ls").description("List all available components").action(_);d.argument("[command]","command to run").action(n=>{n||(x(),d.help())});d.parse();
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@nehal712521/inprogress",
3
+ "version": "0.2.0",
4
+ "description": "CLI to add beautiful UI components to your project",
5
+ "keywords": [
6
+ "inprogress",
7
+ "cli",
8
+ "components",
9
+ "react",
10
+ "nextjs",
11
+ "aceternity",
12
+ "shadcn",
13
+ "animations"
14
+ ],
15
+ "license": "MIT",
16
+ "main": "./dist/index.js",
17
+ "bin": {
18
+ "inprogress": "./dist/index.js"
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "registry"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsup src/index.ts --format cjs --dts --clean --minify",
26
+ "dev": "tsup src/index.ts --format cjs --dts --watch",
27
+ "prepublishOnly": "npm run build"
28
+ },
29
+ "dependencies": {
30
+ "chalk": "^5.6.2",
31
+ "commander": "^14.0.3",
32
+ "fs-extra": "^11.3.4"
33
+ },
34
+ "devDependencies": {
35
+ "@types/fs-extra": "^11.0.4",
36
+ "@types/node": "^20.19.35",
37
+ "tsup": "^8.5.1",
38
+ "typescript": "^5.9.3"
39
+ },
40
+ "engines": {
41
+ "node": ">=16.0.0"
42
+ }
43
+ }
@@ -0,0 +1,28 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+
5
+ type BadgeVariant = "default" | "secondary" | "outline" | "destructive";
6
+
7
+ interface BadgeProps {
8
+ children: React.ReactNode;
9
+ variant?: BadgeVariant;
10
+ className?: string;
11
+ }
12
+
13
+ const variantStyles: Record<BadgeVariant, string> = {
14
+ default: "bg-zinc-100 text-zinc-900 hover:bg-zinc-200",
15
+ secondary: "bg-zinc-800 text-zinc-100 hover:bg-zinc-700",
16
+ outline: "border border-zinc-700 text-zinc-100 hover:bg-zinc-800",
17
+ destructive: "bg-red-500/10 text-red-500 hover:bg-red-500/20",
18
+ };
19
+
20
+ export function Badge({ children, variant = "default", className = "" }: BadgeProps) {
21
+ return (
22
+ <span
23
+ className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium transition-colors ${variantStyles[variant]} ${className}`}
24
+ >
25
+ {children}
26
+ </span>
27
+ );
28
+ }
@@ -0,0 +1,170 @@
1
+ "use client";
2
+
3
+ import React, { useRef, MouseEvent, CSSProperties } from "react";
4
+
5
+ type ButtonVariant = "shimmer" | "glow" | "pulse" | "ripple";
6
+ type ButtonSize = "sm" | "md" | "lg";
7
+
8
+ interface AnimatedButtonProps {
9
+ children: React.ReactNode;
10
+ variant?: ButtonVariant;
11
+ size?: ButtonSize;
12
+ disabled?: boolean;
13
+ onClick?: (e: MouseEvent<HTMLButtonElement>) => void;
14
+ className?: string;
15
+ style?: CSSProperties;
16
+ type?: "button" | "submit" | "reset";
17
+ fullWidth?: boolean;
18
+ }
19
+
20
+ const sizeMap: Record<ButtonSize, string> = {
21
+ sm: "px-4 py-1.5 text-sm",
22
+ md: "px-6 py-2.5 text-sm",
23
+ lg: "px-8 py-3.5 text-base",
24
+ };
25
+
26
+ export default function AnimatedButton({
27
+ children,
28
+ variant = "shimmer",
29
+ size = "md",
30
+ disabled = false,
31
+ onClick,
32
+ className = "",
33
+ style,
34
+ type = "button",
35
+ fullWidth = false,
36
+ }: AnimatedButtonProps) {
37
+ const btnRef = useRef<HTMLButtonElement>(null);
38
+ const rippleRef = useRef<HTMLSpanElement>(null);
39
+
40
+ const handleRipple = (e: MouseEvent<HTMLButtonElement>) => {
41
+ if (variant !== "ripple" || !btnRef.current || !rippleRef.current) return;
42
+
43
+ const btn = btnRef.current;
44
+ const ripple = rippleRef.current;
45
+ const rect = btn.getBoundingClientRect();
46
+ const size = Math.max(rect.width, rect.height) * 2;
47
+
48
+ ripple.style.width = `${size}px`;
49
+ ripple.style.height = `${size}px`;
50
+ ripple.style.left = `${e.clientX - rect.left - size / 2}px`;
51
+ ripple.style.top = `${e.clientY - rect.top - size / 2}px`;
52
+
53
+ ripple.classList.remove("animate-ripple");
54
+ void ripple.offsetWidth;
55
+ ripple.classList.add("animate-ripple");
56
+ };
57
+
58
+ const handleClick = (e: MouseEvent<HTMLButtonElement>) => {
59
+ handleRipple(e);
60
+ onClick?.(e);
61
+ };
62
+
63
+ const base = `animated-btn relative inline-flex items-center justify-center font-semibold tracking-tight overflow-hidden rounded-xl cursor-pointer select-none transition-transform duration-150 active:scale-[0.97] disabled:opacity-40 disabled:pointer-events-none ${fullWidth ? "w-full" : ""} ${sizeMap[size]} ${className}`;
64
+
65
+ return (
66
+ <>
67
+ <style>{`
68
+ .animated-btn { outline: none; border: none; }
69
+
70
+ /* SHIMMER */
71
+ .btn-shimmer {
72
+ background: #0ea5e9;
73
+ color: #fff;
74
+ box-shadow: 0 0 20px rgba(14,165,233,0.35), 0 2px 8px rgba(0,0,0,0.4);
75
+ }
76
+ .btn-shimmer::before {
77
+ content: "";
78
+ position: absolute;
79
+ inset: 0;
80
+ background: linear-gradient(
81
+ 105deg,
82
+ transparent 30%,
83
+ rgba(255,255,255,0.55) 50%,
84
+ transparent 70%
85
+ );
86
+ transform: translateX(-100%);
87
+ animation: shimmer-slide 2.4s ease-in-out infinite;
88
+ }
89
+ .btn-shimmer:hover {
90
+ box-shadow: 0 0 30px rgba(14,165,233,0.6), 0 4px 16px rgba(0,0,0,0.5);
91
+ }
92
+ @keyframes shimmer-slide {
93
+ 0% { transform: translateX(-120%); }
94
+ 60% { transform: translateX(120%); }
95
+ 100% { transform: translateX(120%); }
96
+ }
97
+
98
+ /* GLOW */
99
+ .btn-glow {
100
+ background: transparent;
101
+ color: #0ea5e9;
102
+ border: 1.5px solid rgba(14,165,233,0.5);
103
+ box-shadow: 0 0 10px rgba(14,165,233,0.2) inset;
104
+ animation: glow-pulse 3s ease-in-out infinite;
105
+ }
106
+ .btn-glow:hover {
107
+ background: rgba(14,165,233,0.12);
108
+ border-color: #0ea5e9;
109
+ box-shadow: 0 0 24px rgba(14,165,233,0.55), 0 0 8px rgba(14,165,233,0.3) inset;
110
+ animation: none;
111
+ color: #fff;
112
+ }
113
+ @keyframes glow-pulse {
114
+ 0%, 100% { box-shadow: 0 0 8px rgba(14,165,233,0.2) inset, 0 0 6px rgba(14,165,233,0.15); }
115
+ 50% { box-shadow: 0 0 18px rgba(14,165,233,0.45) inset, 0 0 18px rgba(14,165,233,0.4); }
116
+ }
117
+
118
+ /* PULSE */
119
+ .btn-pulse {
120
+ background: linear-gradient(135deg, #0ea5e9 0%, #6366f1 100%);
121
+ color: #fff;
122
+ box-shadow: 0 0 0 0 rgba(14,165,233,0.7);
123
+ animation: pulse-ring 2s ease-out infinite;
124
+ }
125
+ .btn-pulse:hover { animation: none; box-shadow: 0 0 0 6px rgba(14,165,233,0); }
126
+ @keyframes pulse-ring {
127
+ 0% { box-shadow: 0 0 0 0 rgba(14,165,233,0.65); }
128
+ 70% { box-shadow: 0 0 0 10px rgba(14,165,233,0); }
129
+ 100% { box-shadow: 0 0 0 0 rgba(14,165,233,0); }
130
+ }
131
+
132
+ /* RIPPLE */
133
+ .btn-ripple {
134
+ background: #18181b;
135
+ color: #fff;
136
+ border: 1.5px solid rgba(255,255,255,0.08);
137
+ }
138
+ .btn-ripple:hover { background: #27272a; }
139
+ .ripple-dot {
140
+ position: absolute;
141
+ border-radius: 50%;
142
+ background: rgba(255,255,255,0.25);
143
+ pointer-events: none;
144
+ transform: scale(0);
145
+ opacity: 1;
146
+ }
147
+ .animate-ripple {
148
+ animation: ripple-expand 0.55s linear forwards;
149
+ }
150
+ @keyframes ripple-expand {
151
+ to { transform: scale(1); opacity: 0; }
152
+ }
153
+ `}</style>
154
+
155
+ <button
156
+ ref={btnRef}
157
+ type={type}
158
+ disabled={disabled}
159
+ onClick={handleClick}
160
+ style={style}
161
+ className={`${base} btn-${variant}`}
162
+ >
163
+ {variant === "ripple" && (
164
+ <span ref={rippleRef} className="ripple-dot" />
165
+ )}
166
+ <span className="relative z-10 flex items-center gap-2">{children}</span>
167
+ </button>
168
+ </>
169
+ );
170
+ }
@@ -0,0 +1,36 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+
5
+ interface CardProps {
6
+ children: React.ReactNode;
7
+ className?: string;
8
+ }
9
+
10
+ export function Card({ children, className = "" }: CardProps) {
11
+ return (
12
+ <div className={`rounded-xl border border-zinc-800 bg-zinc-900/50 p-6 ${className}`}>
13
+ {children}
14
+ </div>
15
+ );
16
+ }
17
+
18
+ export function CardHeader({ children, className = "" }: CardProps) {
19
+ return <div className={`mb-4 ${className}`}>{children}</div>;
20
+ }
21
+
22
+ export function CardTitle({ children, className = "" }: CardProps) {
23
+ return <h3 className={`text-lg font-semibold text-white ${className}`}>{children}</h3>;
24
+ }
25
+
26
+ export function CardDescription({ children, className = "" }: CardProps) {
27
+ return <p className={`text-sm text-zinc-400 ${className}`}>{children}</p>;
28
+ }
29
+
30
+ export function CardContent({ children, className = "" }: CardProps) {
31
+ return <div className={className}>{children}</div>;
32
+ }
33
+
34
+ export function CardFooter({ children, className = "" }: CardProps) {
35
+ return <div className={`mt-4 flex items-center gap-2 ${className}`}>{children}</div>;
36
+ }
@@ -0,0 +1,111 @@
1
+ "use client";
2
+
3
+ import React, { useState } from "react";
4
+ import { motion } from "framer-motion";
5
+
6
+ interface FlipCardProps {
7
+ front: React.ReactNode;
8
+ back: React.ReactNode;
9
+ className?: string;
10
+ width?: string;
11
+ height?: string;
12
+ }
13
+
14
+ export function FlipCard({
15
+ front,
16
+ back,
17
+ className = "",
18
+ width = "300px",
19
+ height = "400px"
20
+ }: FlipCardProps) {
21
+ const [isFlipped, setIsFlipped] = useState(false);
22
+
23
+ return (
24
+ <div
25
+ className={`relative cursor-pointer group ${className}`}
26
+ style={{ width, height, perspective: "1000px" }}
27
+ onClick={() => setIsFlipped(!isFlipped)}
28
+ >
29
+ <motion.div
30
+ className="w-full h-full relative preserve-3d"
31
+ animate={{ rotateY: isFlipped ? 180 : 0 }}
32
+ transition={{ duration: 0.6, type: "spring", stiffness: 260, damping: 20 }}
33
+ style={{ transformStyle: "preserve-3d" }}
34
+ >
35
+ {/* Front */}
36
+ <div
37
+ className="absolute inset-0 backface-hidden rounded-2xl overflow-hidden"
38
+ style={{ backfaceVisibility: "hidden" }}
39
+ >
40
+ {front}
41
+ </div>
42
+
43
+ {/* Back */}
44
+ <div
45
+ className="absolute inset-0 backface-hidden rounded-2xl overflow-hidden"
46
+ style={{
47
+ backfaceVisibility: "hidden",
48
+ transform: "rotateY(180deg)"
49
+ }}
50
+ >
51
+ {back}
52
+ </div>
53
+ </motion.div>
54
+
55
+ {/* Flip hint */}
56
+ <div className="absolute bottom-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity">
57
+ <span className="text-xs text-zinc-500 bg-zinc-900/80 px-2 py-1 rounded">
58
+ Click to flip
59
+ </span>
60
+ </div>
61
+ </div>
62
+ );
63
+ }
64
+
65
+ // Pre-styled card faces
66
+ export function FlipCardFront({
67
+ title,
68
+ subtitle,
69
+ image,
70
+ className = ""
71
+ }: {
72
+ title: string;
73
+ subtitle?: string;
74
+ image?: string;
75
+ className?: string;
76
+ }) {
77
+ return (
78
+ <div className={`w-full h-full bg-gradient-to-br from-zinc-800 to-zinc-900 p-6 flex flex-col justify-end relative overflow-hidden ${className}`}>
79
+ {image && (
80
+ <div
81
+ className="absolute inset-0 bg-cover bg-center opacity-50"
82
+ style={{ backgroundImage: `url(${image})` }}
83
+ />
84
+ )}
85
+ <div className="relative z-10">
86
+ <h3 className="text-2xl font-bold text-white mb-1">{title}</h3>
87
+ {subtitle && <p className="text-zinc-400 text-sm">{subtitle}</p>}
88
+ </div>
89
+ </div>
90
+ );
91
+ }
92
+
93
+ export function FlipCardBack({
94
+ title,
95
+ description,
96
+ action,
97
+ className = ""
98
+ }: {
99
+ title: string;
100
+ description: string;
101
+ action?: React.ReactNode;
102
+ className?: string;
103
+ }) {
104
+ return (
105
+ <div className={`w-full h-full bg-gradient-to-br from-zinc-900 to-zinc-950 p-6 flex flex-col justify-center border border-zinc-800 ${className}`}>
106
+ <h3 className="text-xl font-bold text-white mb-3">{title}</h3>
107
+ <p className="text-zinc-400 text-sm leading-relaxed mb-4">{description}</p>
108
+ {action && <div className="mt-auto">{action}</div>}
109
+ </div>
110
+ );
111
+ }
@@ -0,0 +1,77 @@
1
+ "use client";
2
+
3
+ import React, { useState } from "react";
4
+ import { motion } from "framer-motion";
5
+
6
+ interface DockItem {
7
+ icon: React.ReactNode;
8
+ label: string;
9
+ onClick?: () => void;
10
+ href?: string;
11
+ }
12
+
13
+ interface FloatingDockProps {
14
+ items: DockItem[];
15
+ className?: string;
16
+ }
17
+
18
+ export function FloatingDock({ items, className = "" }: FloatingDockProps) {
19
+ const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
20
+
21
+ return (
22
+ <div className={`fixed bottom-8 left-1/2 -translate-x-1/2 z-50 ${className}`}>
23
+ <motion.div
24
+ className="flex items-end gap-2 px-4 py-3 bg-zinc-900/80 backdrop-blur-xl rounded-2xl border border-zinc-800/50 shadow-2xl"
25
+ initial={{ y: 100, opacity: 0 }}
26
+ animate={{ y: 0, opacity: 1 }}
27
+ transition={{ type: "spring", stiffness: 300, damping: 30 }}
28
+ >
29
+ {items.map((item, index) => {
30
+ const isHovered = hoveredIndex === index;
31
+ const isNeighbor = hoveredIndex !== null && Math.abs(hoveredIndex - index) === 1;
32
+ const isFar = hoveredIndex !== null && Math.abs(hoveredIndex - index) === 2;
33
+
34
+ const scale = isHovered ? 1.5 : isNeighbor ? 1.2 : isFar ? 1.05 : 1;
35
+ const y = isHovered ? -20 : isNeighbor ? -10 : 0;
36
+
37
+ const content = (
38
+ <motion.button
39
+ onClick={item.onClick}
40
+ onMouseEnter={() => setHoveredIndex(index)}
41
+ onMouseLeave={() => setHoveredIndex(null)}
42
+ animate={{ scale, y }}
43
+ transition={{ type: "spring", stiffness: 400, damping: 25 }}
44
+ className="relative flex items-center justify-center w-12 h-12 rounded-xl bg-zinc-800/50 hover:bg-zinc-700/50 transition-colors group"
45
+ >
46
+ <span className="text-zinc-300 group-hover:text-white transition-colors">
47
+ {item.icon}
48
+ </span>
49
+
50
+ {/* Tooltip */}
51
+ <motion.span
52
+ initial={{ opacity: 0, y: 10 }}
53
+ animate={{
54
+ opacity: isHovered ? 1 : 0,
55
+ y: isHovered ? -40 : -30
56
+ }}
57
+ className="absolute -top-2 left-1/2 -translate-x-1/2 px-2 py-1 bg-zinc-800 text-zinc-200 text-xs rounded-md whitespace-nowrap pointer-events-none"
58
+ >
59
+ {item.label}
60
+ </motion.span>
61
+ </motion.button>
62
+ );
63
+
64
+ if (item.href) {
65
+ return (
66
+ <a key={index} href={item.href}>
67
+ {content}
68
+ </a>
69
+ );
70
+ }
71
+
72
+ return <div key={index}>{content}</div>;
73
+ })}
74
+ </motion.div>
75
+ </div>
76
+ );
77
+ }
@@ -0,0 +1,66 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { motion } from "framer-motion";
5
+
6
+ interface GradientTextProps {
7
+ children: React.ReactNode;
8
+ className?: string;
9
+ animate?: boolean;
10
+ colors?: string[];
11
+ }
12
+
13
+ export function GradientText({
14
+ children,
15
+ className = "",
16
+ animate = true,
17
+ colors = ["#3b82f6", "#8b5cf6", "#ec4899", "#3b82f6"]
18
+ }: GradientTextProps) {
19
+ const gradientStyle = {
20
+ backgroundImage: `linear-gradient(90deg, ${colors.join(", ")})`,
21
+ backgroundSize: animate ? "300% 100%" : "100% 100%",
22
+ };
23
+
24
+ return (
25
+ <motion.span
26
+ className={`bg-clip-text text-transparent inline-block ${className}`}
27
+ style={gradientStyle}
28
+ animate={animate ? {
29
+ backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
30
+ } : undefined}
31
+ transition={animate ? {
32
+ duration: 5,
33
+ repeat: Infinity,
34
+ ease: "linear",
35
+ } : undefined}
36
+ >
37
+ {children}
38
+ </motion.span>
39
+ );
40
+ }
41
+
42
+ // Shimmer effect text
43
+ export function ShimmerText({
44
+ children,
45
+ className = ""
46
+ }: {
47
+ children: React.ReactNode;
48
+ className?: string;
49
+ }) {
50
+ return (
51
+ <span className={`relative inline-block ${className}`}>
52
+ <span className="bg-gradient-to-r from-zinc-400 via-white to-zinc-400 bg-clip-text text-transparent bg-[length:200%_100%] animate-shimmer">
53
+ {children}
54
+ </span>
55
+ <style jsx>{`
56
+ @keyframes shimmer {
57
+ 0% { background-position: 200% 0; }
58
+ 100% { background-position: -200% 0; }
59
+ }
60
+ .animate-shimmer {
61
+ animation: shimmer 3s ease-in-out infinite;
62
+ }
63
+ `}</style>
64
+ </span>
65
+ );
66
+ }
@@ -0,0 +1,21 @@
1
+ "use client";
2
+
3
+ import React, { InputHTMLAttributes, forwardRef } from "react";
4
+
5
+ export interface InputProps extends InputHTMLAttributes<HTMLInputElement> {}
6
+
7
+ const Input = forwardRef<HTMLInputElement, InputProps>(
8
+ ({ className, type, ...props }, ref) => {
9
+ return (
10
+ <input
11
+ type={type}
12
+ className={`flex h-10 w-full rounded-lg border border-zinc-800 bg-zinc-900 px-3 py-2 text-sm text-white placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-700 focus:border-zinc-700 disabled:cursor-not-allowed disabled:opacity-50 ${className}`}
13
+ ref={ref}
14
+ {...props}
15
+ />
16
+ );
17
+ }
18
+ );
19
+ Input.displayName = "Input";
20
+
21
+ export { Input };
@@ -0,0 +1,88 @@
1
+ "use client";
2
+
3
+ import React, { useState, useRef } from "react";
4
+ import { motion } from "framer-motion";
5
+
6
+ interface SpotlightCardProps {
7
+ children: React.ReactNode;
8
+ className?: string;
9
+ spotlightColor?: string;
10
+ }
11
+
12
+ export function SpotlightCard({
13
+ children,
14
+ className = "",
15
+ spotlightColor = "rgba(255, 255, 255, 0.1)"
16
+ }: SpotlightCardProps) {
17
+ const divRef = useRef<HTMLDivElement>(null);
18
+ const [position, setPosition] = useState({ x: 0, y: 0 });
19
+ const [opacity, setOpacity] = useState(0);
20
+
21
+ const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
22
+ if (!divRef.current) return;
23
+
24
+ const rect = divRef.current.getBoundingClientRect();
25
+ setPosition({
26
+ x: e.clientX - rect.left,
27
+ y: e.clientY - rect.top,
28
+ });
29
+ };
30
+
31
+ const handleFocus = () => {
32
+ setOpacity(1);
33
+ };
34
+
35
+ const handleBlur = () => {
36
+ setOpacity(0);
37
+ };
38
+
39
+ const handleMouseEnter = () => {
40
+ setOpacity(1);
41
+ };
42
+
43
+ const handleMouseLeave = () => {
44
+ setOpacity(0);
45
+ };
46
+
47
+ return (
48
+ <motion.div
49
+ ref={divRef}
50
+ onMouseMove={handleMouseMove}
51
+ onFocus={handleFocus}
52
+ onBlur={handleBlur}
53
+ onMouseEnter={handleMouseEnter}
54
+ onMouseLeave={handleMouseLeave}
55
+ className={`relative overflow-hidden rounded-2xl border border-zinc-800 bg-zinc-900/50 p-8 ${className}`}
56
+ initial={{ opacity: 0, y: 20 }}
57
+ whileInView={{ opacity: 1, y: 0 }}
58
+ viewport={{ once: true }}
59
+ transition={{ duration: 0.5 }}
60
+ >
61
+ {/* Spotlight effect */}
62
+ <div
63
+ className="pointer-events-none absolute -inset-px transition-opacity duration-300"
64
+ style={{
65
+ opacity,
66
+ background: `radial-gradient(600px circle at ${position.x}px ${position.y}px, ${spotlightColor}, transparent 40%)`,
67
+ }}
68
+ />
69
+
70
+ {/* Border spotlight */}
71
+ <div
72
+ className="pointer-events-none absolute inset-0 rounded-2xl transition-opacity duration-300"
73
+ style={{
74
+ opacity,
75
+ background: `radial-gradient(300px circle at ${position.x}px ${position.y}px, rgba(255,255,255,0.2), transparent 40%)`,
76
+ WebkitMask: "linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)",
77
+ WebkitMaskComposite: "xor",
78
+ maskComposite: "exclude",
79
+ padding: "1px",
80
+ }}
81
+ />
82
+
83
+ <div className="relative z-10">
84
+ {children}
85
+ </div>
86
+ </motion.div>
87
+ );
88
+ }
@@ -0,0 +1,110 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { motion } from "framer-motion";
5
+
6
+ interface TextRevealProps {
7
+ text: string;
8
+ className?: string;
9
+ delay?: number;
10
+ }
11
+
12
+ export function TextReveal({ text, className = "", delay = 0 }: TextRevealProps) {
13
+ const words = text.split(" ");
14
+
15
+ const container = {
16
+ hidden: { opacity: 0 },
17
+ visible: (i = 1) => ({
18
+ opacity: 1,
19
+ transition: { staggerChildren: 0.12, delayChildren: delay },
20
+ }),
21
+ };
22
+
23
+ const child = {
24
+ hidden: {
25
+ opacity: 0,
26
+ y: 20,
27
+ rotateX: -90,
28
+ },
29
+ visible: {
30
+ opacity: 1,
31
+ y: 0,
32
+ rotateX: 0,
33
+ transition: {
34
+ type: "spring" as const,
35
+ damping: 12,
36
+ stiffness: 100,
37
+ },
38
+ },
39
+ };
40
+
41
+ return (
42
+ <motion.div
43
+ className={`overflow-hidden ${className}`}
44
+ variants={container}
45
+ initial="hidden"
46
+ animate="visible"
47
+ >
48
+ {words.map((word, index) => (
49
+ <motion.span
50
+ key={index}
51
+ className="inline-block mr-[0.25em]"
52
+ style={{ perspective: "1000px" }}
53
+ >
54
+ <motion.span
55
+ className="inline-block"
56
+ variants={child}
57
+ style={{ transformOrigin: "center bottom" }}
58
+ >
59
+ {word}
60
+ </motion.span>
61
+ </motion.span>
62
+ ))}
63
+ </motion.div>
64
+ );
65
+ }
66
+
67
+ // Character by character reveal
68
+ export function TextRevealByChar({ text, className = "", delay = 0 }: TextRevealProps) {
69
+ const characters = text.split("");
70
+
71
+ const container = {
72
+ hidden: { opacity: 0 },
73
+ visible: {
74
+ opacity: 1,
75
+ transition: { staggerChildren: 0.03, delayChildren: delay },
76
+ },
77
+ };
78
+
79
+ const child = {
80
+ hidden: { opacity: 0, y: 50 },
81
+ visible: {
82
+ opacity: 1,
83
+ y: 0,
84
+ transition: {
85
+ type: "spring" as const,
86
+ damping: 15,
87
+ stiffness: 200,
88
+ },
89
+ },
90
+ };
91
+
92
+ return (
93
+ <motion.span
94
+ className={`inline-block ${className}`}
95
+ variants={container}
96
+ initial="hidden"
97
+ animate="visible"
98
+ >
99
+ {characters.map((char, index) => (
100
+ <motion.span
101
+ key={index}
102
+ className="inline-block"
103
+ variants={child}
104
+ >
105
+ {char === " " ? "\u00A0" : char}
106
+ </motion.span>
107
+ ))}
108
+ </motion.span>
109
+ );
110
+ }
@@ -0,0 +1,114 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { motion } from "framer-motion";
5
+
6
+ interface TimelineItem {
7
+ title: string;
8
+ description?: string;
9
+ date?: string;
10
+ icon?: React.ReactNode;
11
+ }
12
+
13
+ interface TimelineProps {
14
+ items: TimelineItem[];
15
+ className?: string;
16
+ }
17
+
18
+ export function Timeline({ items, className = "" }: TimelineProps) {
19
+ return (
20
+ <div className={`relative ${className}`}>
21
+ {/* Vertical line */}
22
+ <div className="absolute left-4 top-0 bottom-0 w-px bg-gradient-to-b from-zinc-700 via-zinc-800 to-transparent" />
23
+
24
+ <div className="space-y-8">
25
+ {items.map((item, index) => (
26
+ <motion.div
27
+ key={index}
28
+ className="relative flex gap-6"
29
+ initial={{ opacity: 0, x: -20 }}
30
+ whileInView={{ opacity: 1, x: 0 }}
31
+ viewport={{ once: true }}
32
+ transition={{ delay: index * 0.1, duration: 0.5 }}
33
+ >
34
+ {/* Dot */}
35
+ <div className="relative z-10 flex-shrink-0">
36
+ <motion.div
37
+ className="w-8 h-8 rounded-full bg-zinc-900 border-2 border-zinc-700 flex items-center justify-center"
38
+ whileHover={{ scale: 1.1, borderColor: "#3b82f6" }}
39
+ transition={{ type: "spring", stiffness: 400, damping: 20 }}
40
+ >
41
+ {item.icon ? (
42
+ <span className="text-zinc-400 text-sm">{item.icon}</span>
43
+ ) : (
44
+ <div className="w-2 h-2 rounded-full bg-zinc-500" />
45
+ )}
46
+ </motion.div>
47
+ </div>
48
+
49
+ {/* Content */}
50
+ <div className="flex-1 pt-1">
51
+ <div className="flex items-center gap-3 mb-1">
52
+ <h3 className="text-white font-semibold">{item.title}</h3>
53
+ {item.date && (
54
+ <span className="text-xs text-zinc-500 bg-zinc-900 px-2 py-0.5 rounded">
55
+ {item.date}
56
+ </span>
57
+ )}
58
+ </div>
59
+ {item.description && (
60
+ <p className="text-zinc-400 text-sm leading-relaxed">
61
+ {item.description}
62
+ </p>
63
+ )}
64
+ </div>
65
+ </motion.div>
66
+ ))}
67
+ </div>
68
+ </div>
69
+ );
70
+ }
71
+
72
+ // Alternative horizontal timeline
73
+ export function TimelineHorizontal({ items, className = "" }: TimelineProps) {
74
+ return (
75
+ <div className={`relative ${className}`}>
76
+ <div className="flex items-start justify-between">
77
+ {items.map((item, index) => (
78
+ <motion.div
79
+ key={index}
80
+ className="relative flex-1 flex flex-col items-center text-center"
81
+ initial={{ opacity: 0, y: 20 }}
82
+ whileInView={{ opacity: 1, y: 0 }}
83
+ viewport={{ once: true }}
84
+ transition={{ delay: index * 0.15, duration: 0.5 }}
85
+ >
86
+ {/* Connector line */}
87
+ {index < items.length - 1 && (
88
+ <div className="absolute top-4 left-1/2 w-full h-px bg-zinc-800" />
89
+ )}
90
+
91
+ {/* Dot */}
92
+ <motion.div
93
+ className="relative z-10 w-8 h-8 rounded-full bg-zinc-900 border-2 border-zinc-700 flex items-center justify-center mb-3"
94
+ whileHover={{ scale: 1.1, borderColor: "#3b82f6" }}
95
+ >
96
+ <div className="w-2 h-2 rounded-full bg-zinc-500" />
97
+ </motion.div>
98
+
99
+ {/* Content */}
100
+ <h3 className="text-white font-semibold text-sm mb-1">{item.title}</h3>
101
+ {item.date && (
102
+ <span className="text-xs text-zinc-500 mb-1">{item.date}</span>
103
+ )}
104
+ {item.description && (
105
+ <p className="text-zinc-400 text-xs max-w-[150px]">
106
+ {item.description}
107
+ </p>
108
+ )}
109
+ </motion.div>
110
+ ))}
111
+ </div>
112
+ </div>
113
+ );
114
+ }
@@ -0,0 +1,85 @@
1
+ {
2
+ "name": "your-ui",
3
+ "components": {
4
+ "button": {
5
+ "name": "button",
6
+ "displayName": "Animated Button",
7
+ "description": "A highly customisable animated button with shimmer, glow, pulse, and ripple effects",
8
+ "category": "Components",
9
+ "dependencies": [],
10
+ "files": ["button.tsx"]
11
+ },
12
+ "card": {
13
+ "name": "card",
14
+ "displayName": "Card",
15
+ "description": "A card component with header, title, description, content, and footer",
16
+ "category": "Components",
17
+ "dependencies": [],
18
+ "files": ["card.tsx"]
19
+ },
20
+ "input": {
21
+ "name": "input",
22
+ "displayName": "Input",
23
+ "description": "A styled input component with focus states",
24
+ "category": "Components",
25
+ "dependencies": [],
26
+ "files": ["input.tsx"]
27
+ },
28
+ "badge": {
29
+ "name": "badge",
30
+ "displayName": "Badge",
31
+ "description": "A badge component with multiple variants",
32
+ "category": "Components",
33
+ "dependencies": [],
34
+ "files": ["badge.tsx"]
35
+ },
36
+ "floating-dock": {
37
+ "name": "floating-dock",
38
+ "displayName": "Floating Dock",
39
+ "description": "A macOS-style floating dock with hover animations and tooltips",
40
+ "category": "Animations",
41
+ "dependencies": ["framer-motion"],
42
+ "files": ["floating-dock.tsx"]
43
+ },
44
+ "text-reveal": {
45
+ "name": "text-reveal",
46
+ "displayName": "Text Reveal",
47
+ "description": "Animated text reveal with word-by-word or character-by-character animation",
48
+ "category": "Animations",
49
+ "dependencies": ["framer-motion"],
50
+ "files": ["text-reveal.tsx"]
51
+ },
52
+ "flip-card": {
53
+ "name": "flip-card",
54
+ "displayName": "Flip Card",
55
+ "description": "A 3D flip card with front and back faces, perfect for showcasing content",
56
+ "category": "Animations",
57
+ "dependencies": ["framer-motion"],
58
+ "files": ["flip-card.tsx"]
59
+ },
60
+ "gradient-text": {
61
+ "name": "gradient-text",
62
+ "displayName": "Gradient Text",
63
+ "description": "Animated gradient text with shimmer and color shift effects",
64
+ "category": "Animations",
65
+ "dependencies": ["framer-motion"],
66
+ "files": ["gradient-text.tsx"]
67
+ },
68
+ "spotlight-card": {
69
+ "name": "spotlight-card",
70
+ "displayName": "Spotlight Card",
71
+ "description": "A card with a spotlight effect that follows the mouse cursor",
72
+ "category": "Animations",
73
+ "dependencies": ["framer-motion"],
74
+ "files": ["spotlight-card.tsx"]
75
+ },
76
+ "timeline": {
77
+ "name": "timeline",
78
+ "displayName": "Timeline",
79
+ "description": "A vertical or horizontal timeline component with animations",
80
+ "category": "Components",
81
+ "dependencies": ["framer-motion"],
82
+ "files": ["timeline.tsx"]
83
+ }
84
+ }
85
+ }