vibe-ui-suite 4.0.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.
- package/README.md +151 -0
- package/build.js +23 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +278 -0
- package/dist/cli.mjs +243 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.js +152 -0
- package/dist/index.mjs +147 -0
- package/dist/registry/components.d.ts +11 -0
- package/dist/registry/components.js +223 -0
- package/dist/registry/components.mjs +220 -0
- package/dist/tailwind.d.ts +11 -0
- package/dist/tailwind.js +54 -0
- package/dist/tailwind.mjs +50 -0
- package/dist/v4.css +39 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# vibe-ui-suite
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<strong>Deterministic design contracts, component recipes, and WCAG evaluation gates for AI coding agents.</strong>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/vibe-ui-suite"><img src="https://img.shields.io/npm/v/vibe-ui-suite?color=blue&style=flat-square" alt="NPM Version" /></a>
|
|
9
|
+
<a href="https://marketplace.visualstudio.com/items?itemName=omid-io.vibe-ui-vscode"><img src="https://img.shields.io/visual-studio-marketplace/v/omid-io.vibe-ui-vscode?color=blue&style=flat-square&logo=visual-studio-code" alt="VS Code Marketplace" /></a>
|
|
10
|
+
<a href="https://open-vsx.org/extension/omid-io/vibe-ui-vscode"><img src="https://img.shields.io/open-vsx/v/omid-io/vibe-ui-vscode?color=blue&style=flat-square" alt="Open-VSX Version" /></a>
|
|
11
|
+
<a href="https://github.com/omid-io/vibe-ui-suite/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="License" /></a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## ⚡ What is Vibe UI Suite?
|
|
17
|
+
|
|
18
|
+
Modern AI coding agents (Cursor, Claude Code, Windsurf, v0) are fast, but they often produce **"AI Slop"**:
|
|
19
|
+
- Clichéd, low-contrast purple/indigo gradients that fail basic accessibility (WCAG AA).
|
|
20
|
+
- Uncalibrated spacing, broken mobile layouts, and excessive blur overlays.
|
|
21
|
+
- Broken bidirectional text (RTL/BiDi) and inverted business formulas.
|
|
22
|
+
|
|
23
|
+
**`vibe-ui-suite`** acts as a **machine-verifiable design linter and contrast gatekeeper**. It equips your project with typed OKLCH color spaces, physics animation curves, accessible component recipes, and automated editor rule contracts (`.cursorrules`, `CLAUDE.md`, `.windsurfrules`).
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 🚀 Quick Start (3 Seconds)
|
|
28
|
+
|
|
29
|
+
### 1. Initialize Workspace Contracts (`init`)
|
|
30
|
+
|
|
31
|
+
Scaffold AI editor contracts and OKLCH CSS variables in your project with zero manual configuration:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx vibe-ui-suite init
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
This interactive command sets up:
|
|
38
|
+
- `.cursorrules` / `CLAUDE.md` / `.windsurfrules` with strict anti-slop invariants.
|
|
39
|
+
- 5 distinct visual chemistry themes (Minimalist SaaS, Swiss Editorial, Neobrutalism, Luxury Glass 2.0, Stripe Crisp Light).
|
|
40
|
+
- Native Tailwind CSS v4 variables or Tailwind v3 configuration.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
### 2. Add Accessible Component Primitives (`add`)
|
|
45
|
+
|
|
46
|
+
Add verified, zero-emoji, accessible React 19 component templates directly into your codebase (`components/vibe-ui/`):
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Add an expandable reasoning / thinking trace drawer
|
|
50
|
+
npx vibe-ui-suite add thinking-drawer
|
|
51
|
+
|
|
52
|
+
# Add a dense telemetry HUD with live metric formatting
|
|
53
|
+
npx vibe-ui-suite add telemetry-hud
|
|
54
|
+
|
|
55
|
+
# Add a real-time WCAG AAA contrast indicator badge
|
|
56
|
+
npx vibe-ui-suite add contrast-badge
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 3. List Registry Components (`list`)
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npx vibe-ui-suite list
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 🎨 Programmatic Usage
|
|
68
|
+
|
|
69
|
+
### 1. Native Tailwind CSS v4 (`@theme`) — Recommended
|
|
70
|
+
|
|
71
|
+
In your global stylesheet (e.g. `app/globals.css` or `src/index.css`):
|
|
72
|
+
|
|
73
|
+
```css
|
|
74
|
+
@import "tailwindcss";
|
|
75
|
+
@import "vibe-ui-suite/v4.css";
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Zero JavaScript configuration files required. Instantly unlocks:
|
|
79
|
+
- **Semantic Color Utilities:** `bg-vibe-canvas`, `bg-vibe-surface`, `text-vibe-primary`, `border-vibe-border`
|
|
80
|
+
- **Physics Springs:** `transition-vibe-spring`, `transition-vibe-snap`, `transition-vibe-glide`
|
|
81
|
+
- **Surface Elevation:** `shadow-vibe-brutal`, `shadow-vibe-glass`
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
### 2. Direct Token Imports (TypeScript / JavaScript)
|
|
86
|
+
|
|
87
|
+
Access typed OKLCH color spaces and mathematical contrast verification utilities:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { VISUAL_CHEMISTRIES, MOTION_CURVES, getContrastRatio } from 'vibe-ui-suite';
|
|
91
|
+
|
|
92
|
+
// Access typed OKLCH color tokens
|
|
93
|
+
const saasColors = VISUAL_CHEMISTRIES.MINIMALIST_SAAS.colors;
|
|
94
|
+
console.log(saasColors.primaryAccent); // 'oklch(0.65 0.22 260)'
|
|
95
|
+
|
|
96
|
+
// Verify real-time WCAG contrast mathematics
|
|
97
|
+
const contrast = getContrastRatio('#0F172A', '#F8FAFC');
|
|
98
|
+
console.log(`Contrast ratio: ${contrast.toFixed(2)}:1`); // e.g. 15.8:1 (AAA Certified)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
### 3. Tailwind CSS v3 Legacy Plugin (Backward Compatible)
|
|
104
|
+
|
|
105
|
+
In your `tailwind.config.js` or `tailwind.config.ts`:
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
import vibeUiPlugin from 'vibe-ui-suite/tailwind';
|
|
109
|
+
|
|
110
|
+
export default {
|
|
111
|
+
content: ['./app/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
|
|
112
|
+
plugins: [vibeUiPlugin],
|
|
113
|
+
};
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 🛠️ CLI Command Reference
|
|
119
|
+
|
|
120
|
+
| Command | Description |
|
|
121
|
+
| :--- | :--- |
|
|
122
|
+
| `npx vibe-ui-suite init` | Interactively scaffold AI editor contracts & OKLCH variables |
|
|
123
|
+
| `npx vibe-ui-suite init --dry-run` | Preview file operations without modifying disk |
|
|
124
|
+
| `npx vibe-ui-suite add <name>` | Copy an accessible component primitive into `components/vibe-ui/` |
|
|
125
|
+
| `npx vibe-ui-suite add <name> -f` | Overwrite existing component with automated `.bak` backup |
|
|
126
|
+
| `npx vibe-ui-suite list` | List all available component primitives in the registry |
|
|
127
|
+
| `npx vibe-ui-suite -v` | Display installed version |
|
|
128
|
+
| `npx vibe-ui-suite -h` | Display full help menu |
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 🧩 Companion IDE Extensions
|
|
133
|
+
|
|
134
|
+
Install the companion extension for real-time contrast auditing, instant color inspection, and 1-click component templates right inside your editor:
|
|
135
|
+
|
|
136
|
+
- **VS Code Marketplace:** [`omid-io.vibe-ui-vscode`](https://marketplace.visualstudio.com/items?itemName=omid-io.vibe-ui-vscode)
|
|
137
|
+
- **Open-VSX Registry:** [`omid-io.vibe-ui-vscode`](https://open-vsx.org/extension/omid-io/vibe-ui-vscode) (for Cursor, Windsurf, VSCodium)
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 🌐 Community & Ecosystem
|
|
142
|
+
|
|
143
|
+
- **Documentation & Live Showcase:** [https://omid-io.github.io/vibe-ui-suite/](https://omid-io.github.io/vibe-ui-suite/)
|
|
144
|
+
- **GitHub Repository:** [https://github.com/omid-io/vibe-ui-suite](https://github.com/omid-io/vibe-ui-suite)
|
|
145
|
+
- **Issue Tracker:** [https://github.com/omid-io/vibe-ui-suite/issues](https://github.com/omid-io/vibe-ui-suite/issues)
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## 📄 License
|
|
150
|
+
|
|
151
|
+
MIT © [Omid Zaferi](https://github.com/omid-io)
|
package/build.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const srcDistDir = path.resolve(__dirname, '../tokens/dist');
|
|
5
|
+
const targetDistDir = path.resolve(__dirname, 'dist');
|
|
6
|
+
|
|
7
|
+
if (!fs.existsSync(srcDistDir)) {
|
|
8
|
+
console.error('Error: ../tokens/dist does not exist. Please build @omid-io/tokens first.');
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Copy recursively from tokens/dist to vibe-ui-suite/dist
|
|
13
|
+
fs.cpSync(srcDistDir, targetDistDir, { recursive: true });
|
|
14
|
+
|
|
15
|
+
// Ensure executable permission on dist/cli.js
|
|
16
|
+
const cliPath = path.join(targetDistDir, 'cli.js');
|
|
17
|
+
if (fs.existsSync(cliPath)) {
|
|
18
|
+
try {
|
|
19
|
+
fs.chmodSync(cliPath, 0o755);
|
|
20
|
+
} catch (e) {}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
console.log('✅ vibe-ui-suite build complete: synchronized dist/ from tokens package.');
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const readline = __importStar(require("readline"));
|
|
40
|
+
const components_1 = require("./registry/components");
|
|
41
|
+
const index_1 = require("./index");
|
|
42
|
+
const VERSION = '4.0.0';
|
|
43
|
+
function printBanner() {
|
|
44
|
+
console.log(`
|
|
45
|
+
\x1b[35m ▲ VIBE UI CLI v${VERSION}\x1b[0m
|
|
46
|
+
\x1b[90mDeterministic UI contracts & component primitives for AI coding assistants\x1b[0m
|
|
47
|
+
`);
|
|
48
|
+
}
|
|
49
|
+
function printHelp() {
|
|
50
|
+
printBanner();
|
|
51
|
+
console.log(`\x1b[1mUSAGE:\x1b[0m
|
|
52
|
+
npx vibe-ui-suite <command> [options]
|
|
53
|
+
npx @omid-io/tokens <command> [options]
|
|
54
|
+
vibe-ui <command> [options]
|
|
55
|
+
|
|
56
|
+
\x1b[1mCOMMANDS:\x1b[0m
|
|
57
|
+
\x1b[32minit\x1b[0m Initialize Vibe UI contracts, OKLCH tokens & AI rules in current project
|
|
58
|
+
\x1b[32madd <component>\x1b[0m Add an accessible, AI-native component template to your project
|
|
59
|
+
\x1b[32mlist\x1b[0m List all available component primitives in the registry
|
|
60
|
+
|
|
61
|
+
\x1b[1mOPTIONS:\x1b[0m
|
|
62
|
+
-f, --force Overwrite existing files (creates automated .bak backups)
|
|
63
|
+
--dry-run Preview file operations without making actual modifications
|
|
64
|
+
-v, --version Show CLI version
|
|
65
|
+
-h, --help Show help menu
|
|
66
|
+
|
|
67
|
+
\x1b[1mEXAMPLES:\x1b[0m
|
|
68
|
+
npx vibe-ui-suite init
|
|
69
|
+
npx vibe-ui-suite init --dry-run
|
|
70
|
+
npx vibe-ui-suite add thinking-drawer
|
|
71
|
+
npx vibe-ui-suite add thinking-drawer --force
|
|
72
|
+
`);
|
|
73
|
+
}
|
|
74
|
+
function prompt(rl, query) {
|
|
75
|
+
return new Promise((resolve) => rl.question(query, resolve));
|
|
76
|
+
}
|
|
77
|
+
function safeWriteFile(filePath, content, options) {
|
|
78
|
+
const relPath = path.relative(process.cwd(), filePath);
|
|
79
|
+
if (options.dryRun) {
|
|
80
|
+
console.log(` \x1b[34m[dry-run]\x1b[0m Would write: ${relPath}`);
|
|
81
|
+
return { written: false, skipped: false };
|
|
82
|
+
}
|
|
83
|
+
if (fs.existsSync(filePath) && !options.force) {
|
|
84
|
+
console.log(` \x1b[33m[skip]\x1b[0m ${relPath} already exists. (Use --force to overwrite)`);
|
|
85
|
+
return { written: false, skipped: true };
|
|
86
|
+
}
|
|
87
|
+
if (fs.existsSync(filePath) && options.force) {
|
|
88
|
+
const backupPath = `${filePath}.bak`;
|
|
89
|
+
fs.copyFileSync(filePath, backupPath);
|
|
90
|
+
fs.writeFileSync(filePath, content, 'utf-8');
|
|
91
|
+
console.log(` \x1b[35m[backup]\x1b[0m Backed up existing file to ${path.relative(process.cwd(), backupPath)}`);
|
|
92
|
+
return { written: true, skipped: false, backup: backupPath };
|
|
93
|
+
}
|
|
94
|
+
fs.writeFileSync(filePath, content, 'utf-8');
|
|
95
|
+
return { written: true, skipped: false };
|
|
96
|
+
}
|
|
97
|
+
const CONTRACT_RULES = `# Vibe UI Design & Code Quality Contract
|
|
98
|
+
# Generated via npx vibe-ui-suite init
|
|
99
|
+
|
|
100
|
+
Follow strict anti-slop guidelines:
|
|
101
|
+
- Zero raw unicode emojis (use inline SVGs only)
|
|
102
|
+
- Strict WCAG 2.2 AA contrast (>= 4.5:1 body, >= 3.0:1 headings)
|
|
103
|
+
- Use typed OKLCH color spaces for perceptual accuracy
|
|
104
|
+
- Strict maximum of 3 backdrop-filter / glass layers
|
|
105
|
+
- Semantic RTL: preserve physical macro coordinate stability
|
|
106
|
+
`;
|
|
107
|
+
async function handleInit(options) {
|
|
108
|
+
printBanner();
|
|
109
|
+
if (options.dryRun) {
|
|
110
|
+
console.log('\x1b[34m[DRY-RUN MODE ACTIVATED: No files will be modified on disk]\x1b[0m\n');
|
|
111
|
+
}
|
|
112
|
+
const rl = readline.createInterface({
|
|
113
|
+
input: process.stdin,
|
|
114
|
+
output: process.stdout,
|
|
115
|
+
});
|
|
116
|
+
try {
|
|
117
|
+
console.log('\x1b[1mInitialize Vibe UI in current workspace:\x1b[0m\n');
|
|
118
|
+
// 1. Select Visual Chemistry
|
|
119
|
+
console.log('\x1b[36m1. Select Visual Chemistry:\x1b[0m');
|
|
120
|
+
console.log(' [1] Minimalist SaaS (Monochrome restraint, high signal - Recommended)');
|
|
121
|
+
console.log(' [2] Luxury Glass 2.0 (Specular Fresnel, deep dark, gold accents)');
|
|
122
|
+
console.log(' [3] Neobrutalism (Hard 3px black offset shadows, bold high saturation)');
|
|
123
|
+
console.log(' [4] Swiss Editorial (Asymmetric grid, typography-first, high contrast)');
|
|
124
|
+
console.log(' [5] Stripe Crisp Light (Developer docs, precision micro-borders)');
|
|
125
|
+
const chemChoice = (await prompt(rl, 'Choice [1-5] (default: 1): ')).trim() || '1';
|
|
126
|
+
const chemMap = {
|
|
127
|
+
'1': 'MINIMALIST_SAAS',
|
|
128
|
+
'2': 'LUXURY_GLASS_2',
|
|
129
|
+
'3': 'NEOBRUTALISM',
|
|
130
|
+
'4': 'SWISS_EDITORIAL',
|
|
131
|
+
'5': 'STRIPE_CRISP_LIGHT',
|
|
132
|
+
};
|
|
133
|
+
const selectedChemKey = chemMap[chemChoice] || 'MINIMALIST_SAAS';
|
|
134
|
+
const selectedChem = index_1.VISUAL_CHEMISTRIES[selectedChemKey];
|
|
135
|
+
// 2. Select AI Editor
|
|
136
|
+
console.log('\n\x1b[36m2. Select AI Coding Environment:\x1b[0m');
|
|
137
|
+
console.log(' [1] Cursor (.cursorrules - Recommended)');
|
|
138
|
+
console.log(' [2] Claude Code (CLAUDE.md)');
|
|
139
|
+
console.log(' [3] Windsurf (.windsurfrules)');
|
|
140
|
+
console.log(' [4] All of the above');
|
|
141
|
+
const editorChoice = (await prompt(rl, 'Choice [1-4] (default: 1): ')).trim() || '1';
|
|
142
|
+
// 3. Write contract rules safely
|
|
143
|
+
const cwd = process.cwd();
|
|
144
|
+
const createdFiles = [];
|
|
145
|
+
if (editorChoice === '1' || editorChoice === '4') {
|
|
146
|
+
const res = safeWriteFile(path.join(cwd, '.cursorrules'), CONTRACT_RULES, options);
|
|
147
|
+
if (res.written)
|
|
148
|
+
createdFiles.push('.cursorrules');
|
|
149
|
+
}
|
|
150
|
+
if (editorChoice === '2' || editorChoice === '4') {
|
|
151
|
+
const claudePath = path.join(cwd, 'CLAUDE.md');
|
|
152
|
+
if (options.dryRun) {
|
|
153
|
+
console.log(' \x1b[34m[dry-run]\x1b[0m Would update CLAUDE.md');
|
|
154
|
+
}
|
|
155
|
+
else if (fs.existsSync(claudePath)) {
|
|
156
|
+
fs.appendFileSync(claudePath, `\n\n${CONTRACT_RULES}`, 'utf-8');
|
|
157
|
+
createdFiles.push('CLAUDE.md (appended)');
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
const res = safeWriteFile(claudePath, CONTRACT_RULES, options);
|
|
161
|
+
if (res.written)
|
|
162
|
+
createdFiles.push('CLAUDE.md');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (editorChoice === '3' || editorChoice === '4') {
|
|
166
|
+
const res = safeWriteFile(path.join(cwd, '.windsurfrules'), CONTRACT_RULES, options);
|
|
167
|
+
if (res.written)
|
|
168
|
+
createdFiles.push('.windsurfrules');
|
|
169
|
+
}
|
|
170
|
+
// 4. Generate CSS Tokens file safely
|
|
171
|
+
const cssContent = `:root {
|
|
172
|
+
/* Vibe UI Chemistry: ${selectedChem.name} (${selectedChem.id}) */
|
|
173
|
+
--vibe-canvas: ${selectedChem.colors.canvas};
|
|
174
|
+
--vibe-surface: ${selectedChem.colors.surface};
|
|
175
|
+
--vibe-border: ${selectedChem.colors.border};
|
|
176
|
+
--vibe-primary-accent: ${selectedChem.colors.primaryAccent};
|
|
177
|
+
--vibe-text-primary: ${selectedChem.colors.textPrimary};
|
|
178
|
+
--vibe-text-muted: ${selectedChem.colors.textMuted};
|
|
179
|
+
--vibe-ring: ${selectedChem.colors.ring};
|
|
180
|
+
}
|
|
181
|
+
`;
|
|
182
|
+
const cssPath = path.join(cwd, 'vibe-tokens.css');
|
|
183
|
+
const cssRes = safeWriteFile(cssPath, cssContent, options);
|
|
184
|
+
if (cssRes.written)
|
|
185
|
+
createdFiles.push('vibe-tokens.css');
|
|
186
|
+
console.log('\n\x1b[32m✔ Initialized successfully!\x1b[0m');
|
|
187
|
+
if (createdFiles.length > 0) {
|
|
188
|
+
console.log('\x1b[90mGenerated/Updated files:\x1b[0m');
|
|
189
|
+
createdFiles.forEach((f) => console.log(` + ${f}`));
|
|
190
|
+
}
|
|
191
|
+
console.log(`
|
|
192
|
+
\x1b[1mNext Steps:\x1b[0m
|
|
193
|
+
1. Import \x1b[35mvibe-tokens.css\x1b[0m into your layout or globals.css
|
|
194
|
+
2. Run \x1b[32mnpx @omid-io/tokens add thinking-drawer\x1b[0m to add your first AI component
|
|
195
|
+
`);
|
|
196
|
+
}
|
|
197
|
+
finally {
|
|
198
|
+
rl.close();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function handleAdd(componentName, options = { force: false, dryRun: false }) {
|
|
202
|
+
if (!componentName) {
|
|
203
|
+
console.log('\x1b[33mError: Please specify a component to add.\x1b[0m\n');
|
|
204
|
+
handleList();
|
|
205
|
+
console.log('\nUsage: npx @omid-io/tokens add <component> [--force]');
|
|
206
|
+
process.exit(1);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const comp = components_1.COMPONENT_REGISTRY[componentName.toLowerCase()];
|
|
210
|
+
if (!comp) {
|
|
211
|
+
console.log(`\x1b[31mError: Unknown component "${componentName}".\x1b[0m\n`);
|
|
212
|
+
handleList();
|
|
213
|
+
process.exit(1);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const cwd = process.cwd();
|
|
217
|
+
const targetDir = path.join(cwd, 'components', 'vibe-ui');
|
|
218
|
+
if (!options.dryRun) {
|
|
219
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
220
|
+
}
|
|
221
|
+
const targetFile = path.join(targetDir, comp.filename);
|
|
222
|
+
const writeRes = safeWriteFile(targetFile, comp.code, options);
|
|
223
|
+
if (writeRes.skipped) {
|
|
224
|
+
console.log(`\n\x1b[33mWarning: Component already exists at components/vibe-ui/${comp.filename}\x1b[0m`);
|
|
225
|
+
console.log(`To overwrite with automated .bak backup, re-run with:`);
|
|
226
|
+
console.log(` \x1b[32mnpx @omid-io/tokens add ${componentName} --force\x1b[0m\n`);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
if (writeRes.written) {
|
|
230
|
+
console.log(`\x1b[32m✔ Added component "${comp.name}"!\x1b[0m`);
|
|
231
|
+
console.log(` \x1b[90mLocation:\x1b[0m components/vibe-ui/${comp.filename}`);
|
|
232
|
+
console.log(` \x1b[90mDescription:\x1b[0m ${comp.description}\n`);
|
|
233
|
+
console.log(`\x1b[1mUsage in your page or view:\x1b[0m`);
|
|
234
|
+
console.log(` import { ${comp.filename.replace('.tsx', '')} } from '@/components/vibe-ui/${comp.filename.replace('.tsx', '')}';\n`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
function handleList() {
|
|
238
|
+
console.log('\x1b[1mAvailable Vibe UI Components:\x1b[0m');
|
|
239
|
+
Object.values(components_1.COMPONENT_REGISTRY).forEach((comp) => {
|
|
240
|
+
console.log(` \x1b[32m${comp.name.padEnd(18)}\x1b[0m \x1b[90m${comp.description}\x1b[0m`);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
async function main() {
|
|
244
|
+
const rawArgs = process.argv.slice(2);
|
|
245
|
+
const force = rawArgs.includes('--force') || rawArgs.includes('-f');
|
|
246
|
+
const dryRun = rawArgs.includes('--dry-run');
|
|
247
|
+
const filteredArgs = rawArgs.filter((a) => !['--force', '-f', '--dry-run'].includes(a));
|
|
248
|
+
const cmd = filteredArgs[0]?.toLowerCase();
|
|
249
|
+
const options = { force, dryRun };
|
|
250
|
+
if (!cmd || cmd === '--help' || cmd === '-h') {
|
|
251
|
+
printHelp();
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (cmd === '--version' || cmd === '-v') {
|
|
255
|
+
console.log(`v${VERSION}`);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
switch (cmd) {
|
|
259
|
+
case 'init':
|
|
260
|
+
await handleInit(options);
|
|
261
|
+
break;
|
|
262
|
+
case 'add':
|
|
263
|
+
handleAdd(filteredArgs[1], options);
|
|
264
|
+
break;
|
|
265
|
+
case 'list':
|
|
266
|
+
printBanner();
|
|
267
|
+
handleList();
|
|
268
|
+
break;
|
|
269
|
+
default:
|
|
270
|
+
console.log(`\x1b[31mUnknown command "${cmd}".\x1b[0m`);
|
|
271
|
+
printHelp();
|
|
272
|
+
process.exit(1);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
main().catch((err) => {
|
|
276
|
+
console.error('\x1b[31mFatal CLI error:\x1b[0m', err);
|
|
277
|
+
process.exit(1);
|
|
278
|
+
});
|