uniqueui-cli 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,178 @@
1
+ # UniqueUI CLI
2
+
3
+ > Add beautiful, animated UI components to your React project with a single command.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/uniqueui-cli.svg)](https://www.npmjs.com/package/uniqueui-cli)
6
+ [![license](https://img.shields.io/npm/l/uniqueui-cli.svg)](https://github.com/pras75299/uniqueui/blob/main/LICENSE)
7
+
8
+ UniqueUI is a collection of **copy-paste animated components** built with React, Tailwind CSS, and Motion. The CLI fetches components from the registry and drops them directly into your project — no runtime dependency on UniqueUI itself.
9
+
10
+ ---
11
+
12
+ ## Quick Start
13
+
14
+ ### 1. Initialize your project
15
+
16
+ ```bash
17
+ npx uniqueui-cli init
18
+ ```
19
+
20
+ This creates a `components.json` config file with your preferences:
21
+
22
+ - Component install directory (default: `components/ui`)
23
+ - TypeScript support
24
+ - Tailwind config path
25
+
26
+ ### 2. Add a component
27
+
28
+ ```bash
29
+ npx uniqueui-cli add moving-border
30
+ ```
31
+
32
+ The CLI will:
33
+ - Fetch the component source code from the registry
34
+ - Install required dependencies (`motion`, `clsx`, `tailwind-merge`)
35
+ - Update your Tailwind config with any needed animations/keyframes
36
+ - Write the component file to your configured directory
37
+
38
+ ---
39
+
40
+ ## Installation
41
+
42
+ You can use `npx` directly (no install needed):
43
+
44
+ ```bash
45
+ npx uniqueui-cli <command>
46
+ ```
47
+
48
+ Or install globally:
49
+
50
+ ```bash
51
+ npm install -g uniqueui-cli
52
+ ```
53
+
54
+ ---
55
+
56
+ ## Commands
57
+
58
+ ### `init`
59
+
60
+ Configure your project for UniqueUI.
61
+
62
+ ```bash
63
+ uniqueui init
64
+ ```
65
+
66
+ You'll be prompted for:
67
+
68
+ | Prompt | Default | Description |
69
+ |---|---|---|
70
+ | Components directory | `components/ui` | Where component files are saved |
71
+ | TypeScript | `yes` | Whether to use `.tsx` files |
72
+ | Tailwind config path | `tailwind.config.ts` | Path to your Tailwind config |
73
+
74
+ ### `add <component>`
75
+
76
+ Add a component to your project.
77
+
78
+ ```bash
79
+ uniqueui add <component-name>
80
+ ```
81
+
82
+ **Options:**
83
+
84
+ | Flag | Default | Description |
85
+ |---|---|---|
86
+ | `--url <url>` | GitHub registry | Custom registry URL |
87
+
88
+ ---
89
+
90
+ ## Available Components
91
+
92
+ | Component | Description |
93
+ |---|---|
94
+ | `moving-border` | Animated glowing border that follows a path |
95
+ | `typewriter-text` | Text that types itself character by character |
96
+ | `3d-tilt-card` | Card that tilts on hover with 3D perspective |
97
+ | `spotlight-card` | Card with a spotlight effect following the cursor |
98
+ | `aurora-background` | Animated aurora borealis gradient background |
99
+ | `animated-tabs` | Tab navigation with smooth animated indicator |
100
+ | `magnetic-button` | Button that magnetically follows cursor on hover |
101
+ | `infinite-marquee` | Continuously scrolling horizontal content |
102
+ | `scroll-reveal` | Elements that animate in on scroll |
103
+ | `skeleton-shimmer` | Loading skeleton with shimmer animation |
104
+ | `morphing-modal` | Modal with smooth morphing open/close transitions |
105
+ | `gradient-text-reveal` | Text with animated gradient color reveal |
106
+ | `scramble-text` | Text that scrambles/unscrambles on hover |
107
+ | `meteors-card` | Card with animated falling meteor effects |
108
+ | `flip-card` | Card that flips to reveal back content |
109
+ | `dot-grid-background` | Animated dot grid pattern background |
110
+ | `floating-dock` | macOS‑style floating dock navigation |
111
+ | `confetti-burst` | Confetti particle burst animation |
112
+ | `drawer-slide` | Slide-in drawer panel with smooth transitions |
113
+ | `notification-stack` | Stacked notification cards with animations |
114
+ | `animated-timeline` | Vertical timeline with scroll-triggered animations |
115
+
116
+ ---
117
+
118
+ ## Requirements
119
+
120
+ - **Node.js** ≥ 18
121
+ - **React** ≥ 18
122
+ - **Tailwind CSS** ≥ 3
123
+
124
+ ---
125
+
126
+ ## How It Works
127
+
128
+ UniqueUI follows the **copy-paste component** model (similar to shadcn/ui):
129
+
130
+ 1. Components live in a public GitHub registry
131
+ 2. The CLI fetches component source code at install time
132
+ 3. Files are written directly into your project — you own the code
133
+ 4. No runtime dependency on UniqueUI
134
+
135
+ This means you can freely customize every component after adding it.
136
+
137
+ ---
138
+
139
+ ## Example
140
+
141
+ ```bash
142
+ # Initialize
143
+ npx uniqueui-cli init
144
+
145
+ # Add components
146
+ npx uniqueui-cli add aurora-background
147
+ npx uniqueui-cli add magnetic-button
148
+ npx uniqueui-cli add animated-tabs
149
+ ```
150
+
151
+ Then use in your React code:
152
+
153
+ ```tsx
154
+ import { AuroraBackground } from "@/components/ui/aurora-background";
155
+ import { MagneticButton } from "@/components/ui/magnetic-button";
156
+
157
+ export default function Hero() {
158
+ return (
159
+ <AuroraBackground>
160
+ <h1>Welcome to my site</h1>
161
+ <MagneticButton>Get Started</MagneticButton>
162
+ </AuroraBackground>
163
+ );
164
+ }
165
+ ```
166
+
167
+ ---
168
+
169
+ ## Links
170
+
171
+ - [GitHub Repository](https://github.com/pras75299/uniqueui)
172
+ - [Report an Issue](https://github.com/pras75299/uniqueui/issues)
173
+
174
+ ---
175
+
176
+ ## License
177
+
178
+ MIT © [pras75299](https://github.com/pras75299)
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ const program = new commander_1.Command();
8
8
  program
9
9
  .name("uniqueui")
10
10
  .description("Add components from UniqueUI to your project")
11
- .version("0.1.0");
11
+ .version("0.1.1");
12
12
  program
13
13
  .command("init")
14
14
  .description("Configure your project for UniqueUI")
package/package.json CHANGED
@@ -1,19 +1,51 @@
1
1
  {
2
2
  "name": "uniqueui-cli",
3
- "version": "0.1.0",
4
- "description": "CLI for UniqueUI",
3
+ "version": "0.1.2",
4
+ "description": "CLI to add beautiful animated UI components from UniqueUI to your React project",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
7
  "uniqueui": "./dist/index.js"
8
8
  },
9
+ "files": [
10
+ "dist",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
9
14
  "scripts": {
10
15
  "build": "tsc",
11
16
  "start": "node dist/index.js",
12
- "dev": "ts-node src/index.ts"
17
+ "dev": "ts-node src/index.ts",
18
+ "prepublishOnly": "npm run build"
19
+ },
20
+ "keywords": [
21
+ "ui",
22
+ "components",
23
+ "react",
24
+ "animated",
25
+ "tailwindcss",
26
+ "motion",
27
+ "cli",
28
+ "design-system",
29
+ "uniqueui"
30
+ ],
31
+ "author": "pras75299",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/pras75299/uniqueui.git",
36
+ "directory": "packages/cli"
37
+ },
38
+ "homepage": "https://github.com/pras75299/uniqueui#readme",
39
+ "bugs": {
40
+ "url": "https://github.com/pras75299/uniqueui/issues"
41
+ },
42
+ "engines": {
43
+ "node": ">=18"
13
44
  },
14
45
  "dependencies": {
15
46
  "commander": "^11.1.0",
16
47
  "chalk": "^4.1.2",
48
+ "fs-extra": "^11.2.0",
17
49
  "ts-morph": "^21.0.1",
18
50
  "zod": "^3.22.4",
19
51
  "node-fetch": "^3.3.2",
@@ -24,7 +56,6 @@
24
56
  "@types/node": "^20.10.0",
25
57
  "typescript": "^5.3.3",
26
58
  "@types/prompts": "^2.4.9",
27
- "@types/fs-extra": "^11.0.4",
28
- "fs-extra": "^11.2.0"
59
+ "@types/fs-extra": "^11.0.4"
29
60
  }
30
61
  }
@@ -1,184 +0,0 @@
1
-
2
- import { Command } from "commander";
3
- import fetch from "node-fetch";
4
- import path from "path";
5
- import fs from "fs-extra";
6
- import chalk from "chalk";
7
- import { Project, SyntaxKind, QuoteKind } from "ts-morph";
8
- import { execSync } from "child_process";
9
-
10
- // Type definition for Registry (matching what we built)
11
- type RegistryItem = {
12
- name: string;
13
- dependencies: string[];
14
- files: Array<{ path: string; type: string; content: string }>;
15
- tailwindConfig?: Record<string, any>;
16
- };
17
-
18
- export async function add(componentName: string, options: { url: string }) {
19
- console.log(`Fetching ${componentName} from ${options.url}...`);
20
-
21
- // 1. Load config
22
- let config;
23
- try {
24
- config = await fs.readJson("components.json");
25
- } catch (e) {
26
- console.error(chalk.red("components.json not found. Run 'init' first."));
27
- process.exit(1);
28
- }
29
-
30
- // 2. Fetch registry
31
- let registry: RegistryItem[];
32
- try {
33
- // For local testing, if url is a file path, read it
34
- if (options.url.startsWith(".")) {
35
- registry = await fs.readJson(options.url);
36
- } else {
37
- const res = await fetch(`${options.url}/registry.json`);
38
- if (!res.ok) throw new Error("Failed to fetch registry");
39
- registry = await res.json() as RegistryItem[];
40
- }
41
- } catch (e) {
42
- console.error(chalk.red("Could not fetch registry.json"), e);
43
- process.exit(1);
44
- }
45
-
46
- const item = registry.find((c) => c.name === componentName);
47
- if (!item) {
48
- console.error(chalk.red(`Component ${componentName} not found.`));
49
- process.exit(1);
50
- }
51
-
52
- // 3. Install dependencies
53
- if (item.dependencies.length) {
54
- console.log(chalk.cyan(`Installing dependencies: ${item.dependencies.join(", ")}`));
55
- try {
56
- // Detect package manager - simplified
57
- const pm = fs.existsSync("pnpm-lock.yaml") ? "pnpm" : fs.existsSync("yarn.lock") ? "yarn" : "npm";
58
- const cmd = pm === "npm" ? "install" : "add"; // yarn add, pnpm add
59
- execSync(`${pm} ${cmd} ${item.dependencies.join(" ")}`, { stdio: "inherit" });
60
- } catch (e) {
61
- console.warn(chalk.yellow("Failed to install dependencies automatically. Please install them manually."));
62
- }
63
- }
64
-
65
- // 4. Update Tailwind Config
66
- if (item.tailwindConfig) {
67
- console.log(chalk.cyan("Updating tailwind.config..."));
68
- await updateTailwindConfig(config.tailwind.config, item.tailwindConfig);
69
- }
70
-
71
- // 5. Write Files
72
- const targetDir = path.resolve(config.paths.components || "components/ui");
73
- await fs.ensureDir(targetDir);
74
-
75
- for (const file of item.files) {
76
- // We only handle ui components for now
77
- if (file.type === "registry:ui") {
78
- const fileName = path.basename(file.path);
79
- const targetPath = path.join(targetDir, fileName);
80
- await fs.writeFile(targetPath, file.content);
81
- console.log(chalk.green(`Created ${fileName}`));
82
- }
83
- // Handle utils if needed, or other types
84
- }
85
- }
86
-
87
- async function updateTailwindConfig(configPath: string, newConfig: any) {
88
- const project = new Project({
89
- manipulationSettings: {
90
- quoteKind: QuoteKind.Double,
91
- }
92
- });
93
-
94
- // Attempt to add the file
95
- const sourceFile = project.addSourceFileAtPath(configPath);
96
-
97
- // Simplistic handling: look for export default or module.exports
98
- // We expect the config to be an object literal.
99
-
100
- // We need to merge `newConfig.theme.extend` into the existing config.
101
- // logic: find 'theme' property -> find 'extend' property -> merge properties.
102
-
103
- const exportAssignment = sourceFile.getExportAssignment((e) => !e.isExportEquals()); // export default
104
- let objectLiteral;
105
-
106
- if (exportAssignment) {
107
- objectLiteral = exportAssignment.getExpression().asKind(SyntaxKind.ObjectLiteralExpression);
108
- } else {
109
- // try module.exports
110
- const stmt = sourceFile.getStatement((s) => {
111
- if (s.getKind() === SyntaxKind.ExpressionStatement) {
112
- const expr = s.asKind(SyntaxKind.ExpressionStatement)?.getExpression();
113
- if (expr && expr.getKind() === SyntaxKind.BinaryExpression) {
114
- const binary = expr.asKind(SyntaxKind.BinaryExpression);
115
- const left = binary?.getLeft();
116
- if (left?.getText() === "module.exports") return true;
117
- }
118
- }
119
- return false;
120
- });
121
- if (stmt) {
122
- const binary = stmt.asKind(SyntaxKind.ExpressionStatement)!.getExpression().asKind(SyntaxKind.BinaryExpression)!;
123
- objectLiteral = binary.getRight().asKind(SyntaxKind.ObjectLiteralExpression);
124
- }
125
- }
126
-
127
- if (!objectLiteral) {
128
- console.warn(chalk.yellow("Could not parse tailwind config object. Skipping update."));
129
- return;
130
- }
131
-
132
- // Heuristics:
133
- // newConfig is { theme: { extend: { animation: {...}, keyframes: {...} } } }
134
-
135
- // Helper to get or create property object
136
- const getOrCreateObjectProperty = (parentObj: any, name: string) => {
137
- let prop = parentObj.getProperty(name);
138
- if (!prop) {
139
- parentObj.addPropertyAssignment({ name, initializer: "{}" });
140
- prop = parentObj.getProperty(name);
141
- }
142
- const init = prop?.asKind(SyntaxKind.PropertyAssignment)?.getInitializer();
143
- return init?.asKind(SyntaxKind.ObjectLiteralExpression);
144
- };
145
-
146
- if (newConfig.theme?.extend) {
147
- const themeObj = getOrCreateObjectProperty(objectLiteral, "theme");
148
- if (themeObj) {
149
- const extendObj = getOrCreateObjectProperty(themeObj, "extend");
150
- if (extendObj) {
151
- // Merge animations
152
- const animations = newConfig.theme.extend.animation;
153
- if (animations) {
154
- const animObj = getOrCreateObjectProperty(extendObj, "animation");
155
- if (animObj) {
156
- for (const [key, value] of Object.entries(animations)) {
157
- if (!animObj.getProperty(key)) {
158
- animObj.addPropertyAssignment({ name: `"${key}"`, initializer: `"${value}"` });
159
- }
160
- }
161
- }
162
- }
163
-
164
- // Merge keyframes
165
- const keyframes = newConfig.theme.extend.keyframes;
166
- if (keyframes) {
167
- const keyframesObj = getOrCreateObjectProperty(extendObj, "keyframes");
168
- if (keyframesObj) {
169
- for (const [key, value] of Object.entries(keyframes)) {
170
- if (!keyframesObj.getProperty(key)) {
171
- // value is an object, strictly JSON stringify might be valid JS valid object literal needed?
172
- // "JSON.stringify(value)" produces valid JSON which is valid JS object literal initializer if keys are quoted.
173
- keyframesObj.addPropertyAssignment({ name: `"${key}"`, initializer: JSON.stringify(value) });
174
- }
175
- }
176
- }
177
- }
178
- }
179
- }
180
- }
181
-
182
- await sourceFile.save();
183
- console.log(chalk.green("Tailwind config updated successfully."));
184
- }
@@ -1,62 +0,0 @@
1
-
2
- import { promises as fs } from "fs";
3
- import path from "path";
4
- import prompts from "prompts";
5
- import chalk from "chalk";
6
-
7
- export async function init() {
8
- console.log(chalk.bold.green("Initializing UniqueUI..."));
9
-
10
- const cwd = process.cwd();
11
-
12
- const response = await prompts([
13
- {
14
- type: "text",
15
- name: "componentsDir",
16
- message: "Where would you like to install components?",
17
- initial: "components/ui",
18
- },
19
- {
20
- type: "toggle",
21
- name: "typescript",
22
- message: "Are you using TypeScript?",
23
- initial: true,
24
- active: "yes",
25
- inactive: "no",
26
- },
27
- {
28
- type: "text",
29
- name: "tailwindConfig",
30
- message: "Where is your tailwind.config.js located?",
31
- initial: "tailwind.config.ts",
32
- },
33
- ]);
34
-
35
- const config = {
36
- $schema: "https://uniqueui.com/schema.json",
37
- style: "default",
38
- rsc: true,
39
- tsx: response.typescript,
40
- tailwind: {
41
- config: response.tailwindConfig,
42
- css: "app/globals.css", // simplifying assumption or could ask
43
- baseColor: "slate",
44
- cssVariables: true,
45
- },
46
- aliases: {
47
- components: "@/components",
48
- utils: "@/lib/utils",
49
- },
50
- paths: {
51
- components: response.componentsDir,
52
- lib: "lib" // simplifying
53
- }
54
- };
55
-
56
- await fs.writeFile(
57
- path.join(cwd, "components.json"),
58
- JSON.stringify(config, null, 2)
59
- );
60
-
61
- console.log(chalk.green("Configuration saved to components.json"));
62
- }
package/src/index.ts DELETED
@@ -1,25 +0,0 @@
1
- #!/usr/bin/env node
2
- import { Command } from "commander";
3
- import { init } from "./commands/init";
4
- import { add } from "./commands/add";
5
-
6
- const program = new Command();
7
-
8
- program
9
- .name("uniqueui")
10
- .description("Add components from UniqueUI to your project")
11
- .version("0.1.0");
12
-
13
- program
14
- .command("init")
15
- .description("Configure your project for UniqueUI")
16
- .action(init);
17
-
18
- program
19
- .command("add")
20
- .description("Add a component to your project")
21
- .argument("<component>", "the component to add")
22
- .option("--url <url>", "the base URL of the registry", "https://raw.githubusercontent.com/prashantkumarsingh/uniqueui/main")
23
- .action(add);
24
-
25
- program.parse();
package/tsconfig.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- "outDir": "./dist",
5
- "rootDir": "./src"
6
- },
7
- "include": [
8
- "src/**/*"
9
- ]
10
- }