vibe-ui-suite 4.0.0 → 4.8.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 +1 -1
- package/dist/cli.js +115 -78
- package/dist/cli.mjs +115 -78
- package/dist/index.d.ts +3 -0
- package/dist/index.js +65 -10
- package/dist/index.mjs +65 -10
- package/dist/registry/components.js +84 -0
- package/dist/registry/components.mjs +84 -0
- package/dist/tailwind.js +10 -0
- package/dist/tailwind.mjs +10 -0
- package/dist/v4.css +42 -10
- package/package.json +5 -1
- package/build.js +0 -23
package/README.md
CHANGED
|
@@ -77,7 +77,7 @@ In your global stylesheet (e.g. `app/globals.css` or `src/index.css`):
|
|
|
77
77
|
|
|
78
78
|
Zero JavaScript configuration files required. Instantly unlocks:
|
|
79
79
|
- **Semantic Color Utilities:** `bg-vibe-canvas`, `bg-vibe-surface`, `text-vibe-primary`, `border-vibe-border`
|
|
80
|
-
- **Physics Springs:** `
|
|
80
|
+
- **Physics Springs:** `ease-vibe-spring`, `ease-vibe-snap`, `ease-vibe-glide` (or utility `.vibe-spring`)
|
|
81
81
|
- **Surface Elevation:** `shadow-vibe-brutal`, `shadow-vibe-glass`
|
|
82
82
|
|
|
83
83
|
---
|
package/dist/cli.js
CHANGED
|
@@ -39,7 +39,7 @@ const path = __importStar(require("path"));
|
|
|
39
39
|
const readline = __importStar(require("readline"));
|
|
40
40
|
const components_1 = require("./registry/components");
|
|
41
41
|
const index_1 = require("./index");
|
|
42
|
-
const VERSION = '4.
|
|
42
|
+
const VERSION = '4.1.1';
|
|
43
43
|
function printBanner() {
|
|
44
44
|
console.log(`
|
|
45
45
|
\x1b[35m ▲ VIBE UI CLI v${VERSION}\x1b[0m
|
|
@@ -50,7 +50,6 @@ function printHelp() {
|
|
|
50
50
|
printBanner();
|
|
51
51
|
console.log(`\x1b[1mUSAGE:\x1b[0m
|
|
52
52
|
npx vibe-ui-suite <command> [options]
|
|
53
|
-
npx @omid-io/tokens <command> [options]
|
|
54
53
|
vibe-ui <command> [options]
|
|
55
54
|
|
|
56
55
|
\x1b[1mCOMMANDS:\x1b[0m
|
|
@@ -60,14 +59,19 @@ function printHelp() {
|
|
|
60
59
|
|
|
61
60
|
\x1b[1mOPTIONS:\x1b[0m
|
|
62
61
|
-f, --force Overwrite existing files (creates automated .bak backups)
|
|
62
|
+
-y, --yes Non-interactive mode (use defaults without prompting)
|
|
63
|
+
--chemistry <1-5> Select visual chemistry in non-interactive mode
|
|
64
|
+
--editor <1-4> Select target AI editor in non-interactive mode (1: Cursor, 2: Claude, 3: Windsurf, 4: All)
|
|
63
65
|
--dry-run Preview file operations without making actual modifications
|
|
64
66
|
-v, --version Show CLI version
|
|
65
67
|
-h, --help Show help menu
|
|
66
68
|
|
|
67
69
|
\x1b[1mEXAMPLES:\x1b[0m
|
|
68
70
|
npx vibe-ui-suite init
|
|
71
|
+
npx vibe-ui-suite init -y
|
|
69
72
|
npx vibe-ui-suite init --dry-run
|
|
70
73
|
npx vibe-ui-suite add thinking-drawer
|
|
74
|
+
npx vibe-ui-suite add theme-toggle
|
|
71
75
|
npx vibe-ui-suite add thinking-drawer --force
|
|
72
76
|
`);
|
|
73
77
|
}
|
|
@@ -109,100 +113,124 @@ async function handleInit(options) {
|
|
|
109
113
|
if (options.dryRun) {
|
|
110
114
|
console.log('\x1b[34m[DRY-RUN MODE ACTIVATED: No files will be modified on disk]\x1b[0m\n');
|
|
111
115
|
}
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
'
|
|
129
|
-
|
|
130
|
-
'
|
|
131
|
-
'
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
116
|
+
const isInteractive = !options.yes && Boolean(process.stdin.isTTY);
|
|
117
|
+
let chemChoice = options.chemistry || '1';
|
|
118
|
+
let editorChoice = options.editor || '4';
|
|
119
|
+
const chemMap = {
|
|
120
|
+
'1': 'MINIMALIST_SAAS',
|
|
121
|
+
'2': 'LUXURY_GLASS_2',
|
|
122
|
+
'3': 'NEOBRUTALISM',
|
|
123
|
+
'4': 'SWISS_EDITORIAL',
|
|
124
|
+
'5': 'STRIPE_CRISP_LIGHT',
|
|
125
|
+
};
|
|
126
|
+
if (isInteractive) {
|
|
127
|
+
const rl = readline.createInterface({
|
|
128
|
+
input: process.stdin,
|
|
129
|
+
output: process.stdout,
|
|
130
|
+
});
|
|
131
|
+
try {
|
|
132
|
+
console.log('\x1b[1mInitialize Vibe UI in current workspace:\x1b[0m\n');
|
|
133
|
+
// 1. Select Visual Chemistry
|
|
134
|
+
console.log('\x1b[36m1. Select Visual Chemistry:\x1b[0m');
|
|
135
|
+
console.log(' [1] Minimalist SaaS (Monochrome restraint, high signal - Recommended)');
|
|
136
|
+
console.log(' [2] Luxury Glass 2.0 (Specular Fresnel, deep dark, gold accents)');
|
|
137
|
+
console.log(' [3] Neobrutalism (Hard 3px black offset shadows, bold high saturation)');
|
|
138
|
+
console.log(' [4] Swiss Editorial (Asymmetric grid, typography-first, high contrast)');
|
|
139
|
+
console.log(' [5] Stripe Crisp Light (Developer docs, precision micro-borders)');
|
|
140
|
+
chemChoice = (await prompt(rl, 'Choice [1-5] (default: 1): ')).trim() || '1';
|
|
141
|
+
// 2. Select AI Editor
|
|
142
|
+
console.log('\n\x1b[36m2. Select AI Coding Environment:\x1b[0m');
|
|
143
|
+
console.log(' [1] Cursor (.cursorrules - Recommended)');
|
|
144
|
+
console.log(' [2] Claude Code (CLAUDE.md)');
|
|
145
|
+
console.log(' [3] Windsurf (.windsurfrules)');
|
|
146
|
+
console.log(' [4] All of the above');
|
|
147
|
+
editorChoice = (await prompt(rl, 'Choice [1-4] (default: 1): ')).trim() || '1';
|
|
148
|
+
}
|
|
149
|
+
finally {
|
|
150
|
+
rl.close();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
console.log('\x1b[36m [auto]\x1b[0m Non-interactive mode activated. Using defaults.');
|
|
155
|
+
}
|
|
156
|
+
const selectedChemKey = chemMap[chemChoice] || 'MINIMALIST_SAAS';
|
|
157
|
+
const selectedChem = index_1.VISUAL_CHEMISTRIES[selectedChemKey];
|
|
158
|
+
const darkColors = selectedChem.darkColors || selectedChem.colors;
|
|
159
|
+
console.log(` \x1b[32m✔\x1b[0m Visual Chemistry: \x1b[1m${selectedChem.name}\x1b[0m (Dual Light & Dark Themes)`);
|
|
160
|
+
// 3. Write contract rules safely
|
|
161
|
+
const cwd = process.cwd();
|
|
162
|
+
const createdFiles = [];
|
|
163
|
+
if (editorChoice === '1' || editorChoice === '4') {
|
|
164
|
+
const res = safeWriteFile(path.join(cwd, '.cursorrules'), CONTRACT_RULES, options);
|
|
165
|
+
if (res.written)
|
|
166
|
+
createdFiles.push('.cursorrules');
|
|
167
|
+
}
|
|
168
|
+
if (editorChoice === '2' || editorChoice === '4') {
|
|
169
|
+
const claudePath = path.join(cwd, 'CLAUDE.md');
|
|
170
|
+
if (options.dryRun) {
|
|
171
|
+
console.log(' \x1b[34m[dry-run]\x1b[0m Would update CLAUDE.md');
|
|
149
172
|
}
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
|
|
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
|
-
}
|
|
173
|
+
else if (fs.existsSync(claudePath)) {
|
|
174
|
+
fs.appendFileSync(claudePath, `\n\n${CONTRACT_RULES}`, 'utf-8');
|
|
175
|
+
createdFiles.push('CLAUDE.md (appended)');
|
|
164
176
|
}
|
|
165
|
-
|
|
166
|
-
const res = safeWriteFile(
|
|
177
|
+
else {
|
|
178
|
+
const res = safeWriteFile(claudePath, CONTRACT_RULES, options);
|
|
167
179
|
if (res.written)
|
|
168
|
-
createdFiles.push('.
|
|
180
|
+
createdFiles.push('CLAUDE.md');
|
|
169
181
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
182
|
+
}
|
|
183
|
+
if (editorChoice === '3' || editorChoice === '4') {
|
|
184
|
+
const res = safeWriteFile(path.join(cwd, '.windsurfrules'), CONTRACT_RULES, options);
|
|
185
|
+
if (res.written)
|
|
186
|
+
createdFiles.push('.windsurfrules');
|
|
187
|
+
}
|
|
188
|
+
// 4. Generate Dual-Theme CSS Tokens file safely
|
|
189
|
+
const cssContent = `:root {
|
|
190
|
+
/* Vibe UI Chemistry: ${selectedChem.name} (${selectedChem.id}) - Light Theme */
|
|
173
191
|
--vibe-canvas: ${selectedChem.colors.canvas};
|
|
174
192
|
--vibe-surface: ${selectedChem.colors.surface};
|
|
175
193
|
--vibe-border: ${selectedChem.colors.border};
|
|
176
194
|
--vibe-primary-accent: ${selectedChem.colors.primaryAccent};
|
|
195
|
+
--vibe-on-primary: ${selectedChem.colors.onPrimaryAccent};
|
|
177
196
|
--vibe-text-primary: ${selectedChem.colors.textPrimary};
|
|
178
197
|
--vibe-text-muted: ${selectedChem.colors.textMuted};
|
|
179
198
|
--vibe-ring: ${selectedChem.colors.ring};
|
|
180
199
|
}
|
|
200
|
+
|
|
201
|
+
.dark, [data-theme="dark"] {
|
|
202
|
+
/* Vibe UI Chemistry: ${selectedChem.name} (${selectedChem.id}) - Dark Theme */
|
|
203
|
+
--vibe-canvas: ${darkColors.canvas};
|
|
204
|
+
--vibe-surface: ${darkColors.surface};
|
|
205
|
+
--vibe-border: ${darkColors.border};
|
|
206
|
+
--vibe-primary-accent: ${darkColors.primaryAccent};
|
|
207
|
+
--vibe-on-primary: ${darkColors.onPrimaryAccent};
|
|
208
|
+
--vibe-text-primary: ${darkColors.textPrimary};
|
|
209
|
+
--vibe-text-muted: ${darkColors.textMuted};
|
|
210
|
+
--vibe-ring: ${darkColors.ring};
|
|
211
|
+
}
|
|
181
212
|
`;
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
213
|
+
const cssPath = path.join(cwd, 'vibe-tokens.css');
|
|
214
|
+
const cssRes = safeWriteFile(cssPath, cssContent, options);
|
|
215
|
+
if (cssRes.written)
|
|
216
|
+
createdFiles.push('vibe-tokens.css');
|
|
217
|
+
console.log('\n\x1b[32m✔ Initialized successfully!\x1b[0m');
|
|
218
|
+
if (createdFiles.length > 0) {
|
|
219
|
+
console.log('\x1b[90mGenerated/Updated files:\x1b[0m');
|
|
220
|
+
createdFiles.forEach((f) => console.log(` + ${f}`));
|
|
221
|
+
}
|
|
222
|
+
console.log(`
|
|
192
223
|
\x1b[1mNext Steps:\x1b[0m
|
|
193
224
|
1. Import \x1b[35mvibe-tokens.css\x1b[0m into your layout or globals.css
|
|
194
|
-
2. Run \x1b[32mnpx
|
|
225
|
+
2. Run \x1b[32mnpx vibe-ui-suite add thinking-drawer\x1b[0m to add your first AI component
|
|
226
|
+
3. Run \x1b[32mnpx vibe-ui-suite add theme-toggle\x1b[0m to add accessible Dark/Light theme switch
|
|
195
227
|
`);
|
|
196
|
-
}
|
|
197
|
-
finally {
|
|
198
|
-
rl.close();
|
|
199
|
-
}
|
|
200
228
|
}
|
|
201
229
|
function handleAdd(componentName, options = { force: false, dryRun: false }) {
|
|
202
230
|
if (!componentName) {
|
|
203
231
|
console.log('\x1b[33mError: Please specify a component to add.\x1b[0m\n');
|
|
204
232
|
handleList();
|
|
205
|
-
console.log('\nUsage: npx
|
|
233
|
+
console.log('\nUsage: npx vibe-ui-suite add <component> [--force]');
|
|
206
234
|
process.exit(1);
|
|
207
235
|
return;
|
|
208
236
|
}
|
|
@@ -223,7 +251,7 @@ function handleAdd(componentName, options = { force: false, dryRun: false }) {
|
|
|
223
251
|
if (writeRes.skipped) {
|
|
224
252
|
console.log(`\n\x1b[33mWarning: Component already exists at components/vibe-ui/${comp.filename}\x1b[0m`);
|
|
225
253
|
console.log(`To overwrite with automated .bak backup, re-run with:`);
|
|
226
|
-
console.log(` \x1b[32mnpx
|
|
254
|
+
console.log(` \x1b[32mnpx vibe-ui-suite add ${componentName} --force\x1b[0m\n`);
|
|
227
255
|
return;
|
|
228
256
|
}
|
|
229
257
|
if (writeRes.written) {
|
|
@@ -244,9 +272,18 @@ async function main() {
|
|
|
244
272
|
const rawArgs = process.argv.slice(2);
|
|
245
273
|
const force = rawArgs.includes('--force') || rawArgs.includes('-f');
|
|
246
274
|
const dryRun = rawArgs.includes('--dry-run');
|
|
247
|
-
const
|
|
275
|
+
const yes = rawArgs.includes('--yes') || rawArgs.includes('-y');
|
|
276
|
+
let chemistry;
|
|
277
|
+
let editor;
|
|
278
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
279
|
+
if (rawArgs[i] === '--chemistry' && rawArgs[i + 1])
|
|
280
|
+
chemistry = rawArgs[i + 1];
|
|
281
|
+
if (rawArgs[i] === '--editor' && rawArgs[i + 1])
|
|
282
|
+
editor = rawArgs[i + 1];
|
|
283
|
+
}
|
|
284
|
+
const filteredArgs = rawArgs.filter((a) => !['--force', '-f', '--dry-run', '--yes', '-y', '--chemistry', '--editor'].includes(a) && a !== chemistry && a !== editor);
|
|
248
285
|
const cmd = filteredArgs[0]?.toLowerCase();
|
|
249
|
-
const options = { force, dryRun };
|
|
286
|
+
const options = { force, dryRun, yes, chemistry, editor };
|
|
250
287
|
if (!cmd || cmd === '--help' || cmd === '-h') {
|
|
251
288
|
printHelp();
|
|
252
289
|
return;
|
package/dist/cli.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import * as path from 'path';
|
|
|
4
4
|
import * as readline from 'readline';
|
|
5
5
|
import { COMPONENT_REGISTRY } from './registry/components';
|
|
6
6
|
import { VISUAL_CHEMISTRIES } from './index';
|
|
7
|
-
const VERSION = '4.
|
|
7
|
+
const VERSION = '4.1.1';
|
|
8
8
|
function printBanner() {
|
|
9
9
|
console.log(`
|
|
10
10
|
\x1b[35m ▲ VIBE UI CLI v${VERSION}\x1b[0m
|
|
@@ -15,7 +15,6 @@ function printHelp() {
|
|
|
15
15
|
printBanner();
|
|
16
16
|
console.log(`\x1b[1mUSAGE:\x1b[0m
|
|
17
17
|
npx vibe-ui-suite <command> [options]
|
|
18
|
-
npx @omid-io/tokens <command> [options]
|
|
19
18
|
vibe-ui <command> [options]
|
|
20
19
|
|
|
21
20
|
\x1b[1mCOMMANDS:\x1b[0m
|
|
@@ -25,14 +24,19 @@ function printHelp() {
|
|
|
25
24
|
|
|
26
25
|
\x1b[1mOPTIONS:\x1b[0m
|
|
27
26
|
-f, --force Overwrite existing files (creates automated .bak backups)
|
|
27
|
+
-y, --yes Non-interactive mode (use defaults without prompting)
|
|
28
|
+
--chemistry <1-5> Select visual chemistry in non-interactive mode
|
|
29
|
+
--editor <1-4> Select target AI editor in non-interactive mode (1: Cursor, 2: Claude, 3: Windsurf, 4: All)
|
|
28
30
|
--dry-run Preview file operations without making actual modifications
|
|
29
31
|
-v, --version Show CLI version
|
|
30
32
|
-h, --help Show help menu
|
|
31
33
|
|
|
32
34
|
\x1b[1mEXAMPLES:\x1b[0m
|
|
33
35
|
npx vibe-ui-suite init
|
|
36
|
+
npx vibe-ui-suite init -y
|
|
34
37
|
npx vibe-ui-suite init --dry-run
|
|
35
38
|
npx vibe-ui-suite add thinking-drawer
|
|
39
|
+
npx vibe-ui-suite add theme-toggle
|
|
36
40
|
npx vibe-ui-suite add thinking-drawer --force
|
|
37
41
|
`);
|
|
38
42
|
}
|
|
@@ -74,100 +78,124 @@ async function handleInit(options) {
|
|
|
74
78
|
if (options.dryRun) {
|
|
75
79
|
console.log('\x1b[34m[DRY-RUN MODE ACTIVATED: No files will be modified on disk]\x1b[0m\n');
|
|
76
80
|
}
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
'
|
|
94
|
-
|
|
95
|
-
'
|
|
96
|
-
'
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const createdFiles = [];
|
|
110
|
-
if (editorChoice === '1' || editorChoice === '4') {
|
|
111
|
-
const res = safeWriteFile(path.join(cwd, '.cursorrules'), CONTRACT_RULES, options);
|
|
112
|
-
if (res.written)
|
|
113
|
-
createdFiles.push('.cursorrules');
|
|
81
|
+
const isInteractive = !options.yes && Boolean(process.stdin.isTTY);
|
|
82
|
+
let chemChoice = options.chemistry || '1';
|
|
83
|
+
let editorChoice = options.editor || '4';
|
|
84
|
+
const chemMap = {
|
|
85
|
+
'1': 'MINIMALIST_SAAS',
|
|
86
|
+
'2': 'LUXURY_GLASS_2',
|
|
87
|
+
'3': 'NEOBRUTALISM',
|
|
88
|
+
'4': 'SWISS_EDITORIAL',
|
|
89
|
+
'5': 'STRIPE_CRISP_LIGHT',
|
|
90
|
+
};
|
|
91
|
+
if (isInteractive) {
|
|
92
|
+
const rl = readline.createInterface({
|
|
93
|
+
input: process.stdin,
|
|
94
|
+
output: process.stdout,
|
|
95
|
+
});
|
|
96
|
+
try {
|
|
97
|
+
console.log('\x1b[1mInitialize Vibe UI in current workspace:\x1b[0m\n');
|
|
98
|
+
// 1. Select Visual Chemistry
|
|
99
|
+
console.log('\x1b[36m1. Select Visual Chemistry:\x1b[0m');
|
|
100
|
+
console.log(' [1] Minimalist SaaS (Monochrome restraint, high signal - Recommended)');
|
|
101
|
+
console.log(' [2] Luxury Glass 2.0 (Specular Fresnel, deep dark, gold accents)');
|
|
102
|
+
console.log(' [3] Neobrutalism (Hard 3px black offset shadows, bold high saturation)');
|
|
103
|
+
console.log(' [4] Swiss Editorial (Asymmetric grid, typography-first, high contrast)');
|
|
104
|
+
console.log(' [5] Stripe Crisp Light (Developer docs, precision micro-borders)');
|
|
105
|
+
chemChoice = (await prompt(rl, 'Choice [1-5] (default: 1): ')).trim() || '1';
|
|
106
|
+
// 2. Select AI Editor
|
|
107
|
+
console.log('\n\x1b[36m2. Select AI Coding Environment:\x1b[0m');
|
|
108
|
+
console.log(' [1] Cursor (.cursorrules - Recommended)');
|
|
109
|
+
console.log(' [2] Claude Code (CLAUDE.md)');
|
|
110
|
+
console.log(' [3] Windsurf (.windsurfrules)');
|
|
111
|
+
console.log(' [4] All of the above');
|
|
112
|
+
editorChoice = (await prompt(rl, 'Choice [1-4] (default: 1): ')).trim() || '1';
|
|
114
113
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (options.dryRun) {
|
|
118
|
-
console.log(' \x1b[34m[dry-run]\x1b[0m Would update CLAUDE.md');
|
|
119
|
-
}
|
|
120
|
-
else if (fs.existsSync(claudePath)) {
|
|
121
|
-
fs.appendFileSync(claudePath, `\n\n${CONTRACT_RULES}`, 'utf-8');
|
|
122
|
-
createdFiles.push('CLAUDE.md (appended)');
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
const res = safeWriteFile(claudePath, CONTRACT_RULES, options);
|
|
126
|
-
if (res.written)
|
|
127
|
-
createdFiles.push('CLAUDE.md');
|
|
128
|
-
}
|
|
114
|
+
finally {
|
|
115
|
+
rl.close();
|
|
129
116
|
}
|
|
130
|
-
|
|
131
|
-
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
console.log('\x1b[36m [auto]\x1b[0m Non-interactive mode activated. Using defaults.');
|
|
120
|
+
}
|
|
121
|
+
const selectedChemKey = chemMap[chemChoice] || 'MINIMALIST_SAAS';
|
|
122
|
+
const selectedChem = VISUAL_CHEMISTRIES[selectedChemKey];
|
|
123
|
+
const darkColors = selectedChem.darkColors || selectedChem.colors;
|
|
124
|
+
console.log(` \x1b[32m✔\x1b[0m Visual Chemistry: \x1b[1m${selectedChem.name}\x1b[0m (Dual Light & Dark Themes)`);
|
|
125
|
+
// 3. Write contract rules safely
|
|
126
|
+
const cwd = process.cwd();
|
|
127
|
+
const createdFiles = [];
|
|
128
|
+
if (editorChoice === '1' || editorChoice === '4') {
|
|
129
|
+
const res = safeWriteFile(path.join(cwd, '.cursorrules'), CONTRACT_RULES, options);
|
|
130
|
+
if (res.written)
|
|
131
|
+
createdFiles.push('.cursorrules');
|
|
132
|
+
}
|
|
133
|
+
if (editorChoice === '2' || editorChoice === '4') {
|
|
134
|
+
const claudePath = path.join(cwd, 'CLAUDE.md');
|
|
135
|
+
if (options.dryRun) {
|
|
136
|
+
console.log(' \x1b[34m[dry-run]\x1b[0m Would update CLAUDE.md');
|
|
137
|
+
}
|
|
138
|
+
else if (fs.existsSync(claudePath)) {
|
|
139
|
+
fs.appendFileSync(claudePath, `\n\n${CONTRACT_RULES}`, 'utf-8');
|
|
140
|
+
createdFiles.push('CLAUDE.md (appended)');
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
const res = safeWriteFile(claudePath, CONTRACT_RULES, options);
|
|
132
144
|
if (res.written)
|
|
133
|
-
createdFiles.push('.
|
|
145
|
+
createdFiles.push('CLAUDE.md');
|
|
134
146
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
147
|
+
}
|
|
148
|
+
if (editorChoice === '3' || editorChoice === '4') {
|
|
149
|
+
const res = safeWriteFile(path.join(cwd, '.windsurfrules'), CONTRACT_RULES, options);
|
|
150
|
+
if (res.written)
|
|
151
|
+
createdFiles.push('.windsurfrules');
|
|
152
|
+
}
|
|
153
|
+
// 4. Generate Dual-Theme CSS Tokens file safely
|
|
154
|
+
const cssContent = `:root {
|
|
155
|
+
/* Vibe UI Chemistry: ${selectedChem.name} (${selectedChem.id}) - Light Theme */
|
|
138
156
|
--vibe-canvas: ${selectedChem.colors.canvas};
|
|
139
157
|
--vibe-surface: ${selectedChem.colors.surface};
|
|
140
158
|
--vibe-border: ${selectedChem.colors.border};
|
|
141
159
|
--vibe-primary-accent: ${selectedChem.colors.primaryAccent};
|
|
160
|
+
--vibe-on-primary: ${selectedChem.colors.onPrimaryAccent};
|
|
142
161
|
--vibe-text-primary: ${selectedChem.colors.textPrimary};
|
|
143
162
|
--vibe-text-muted: ${selectedChem.colors.textMuted};
|
|
144
163
|
--vibe-ring: ${selectedChem.colors.ring};
|
|
145
164
|
}
|
|
165
|
+
|
|
166
|
+
.dark, [data-theme="dark"] {
|
|
167
|
+
/* Vibe UI Chemistry: ${selectedChem.name} (${selectedChem.id}) - Dark Theme */
|
|
168
|
+
--vibe-canvas: ${darkColors.canvas};
|
|
169
|
+
--vibe-surface: ${darkColors.surface};
|
|
170
|
+
--vibe-border: ${darkColors.border};
|
|
171
|
+
--vibe-primary-accent: ${darkColors.primaryAccent};
|
|
172
|
+
--vibe-on-primary: ${darkColors.onPrimaryAccent};
|
|
173
|
+
--vibe-text-primary: ${darkColors.textPrimary};
|
|
174
|
+
--vibe-text-muted: ${darkColors.textMuted};
|
|
175
|
+
--vibe-ring: ${darkColors.ring};
|
|
176
|
+
}
|
|
146
177
|
`;
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
178
|
+
const cssPath = path.join(cwd, 'vibe-tokens.css');
|
|
179
|
+
const cssRes = safeWriteFile(cssPath, cssContent, options);
|
|
180
|
+
if (cssRes.written)
|
|
181
|
+
createdFiles.push('vibe-tokens.css');
|
|
182
|
+
console.log('\n\x1b[32m✔ Initialized successfully!\x1b[0m');
|
|
183
|
+
if (createdFiles.length > 0) {
|
|
184
|
+
console.log('\x1b[90mGenerated/Updated files:\x1b[0m');
|
|
185
|
+
createdFiles.forEach((f) => console.log(` + ${f}`));
|
|
186
|
+
}
|
|
187
|
+
console.log(`
|
|
157
188
|
\x1b[1mNext Steps:\x1b[0m
|
|
158
189
|
1. Import \x1b[35mvibe-tokens.css\x1b[0m into your layout or globals.css
|
|
159
|
-
2. Run \x1b[32mnpx
|
|
190
|
+
2. Run \x1b[32mnpx vibe-ui-suite add thinking-drawer\x1b[0m to add your first AI component
|
|
191
|
+
3. Run \x1b[32mnpx vibe-ui-suite add theme-toggle\x1b[0m to add accessible Dark/Light theme switch
|
|
160
192
|
`);
|
|
161
|
-
}
|
|
162
|
-
finally {
|
|
163
|
-
rl.close();
|
|
164
|
-
}
|
|
165
193
|
}
|
|
166
194
|
function handleAdd(componentName, options = { force: false, dryRun: false }) {
|
|
167
195
|
if (!componentName) {
|
|
168
196
|
console.log('\x1b[33mError: Please specify a component to add.\x1b[0m\n');
|
|
169
197
|
handleList();
|
|
170
|
-
console.log('\nUsage: npx
|
|
198
|
+
console.log('\nUsage: npx vibe-ui-suite add <component> [--force]');
|
|
171
199
|
process.exit(1);
|
|
172
200
|
return;
|
|
173
201
|
}
|
|
@@ -188,7 +216,7 @@ function handleAdd(componentName, options = { force: false, dryRun: false }) {
|
|
|
188
216
|
if (writeRes.skipped) {
|
|
189
217
|
console.log(`\n\x1b[33mWarning: Component already exists at components/vibe-ui/${comp.filename}\x1b[0m`);
|
|
190
218
|
console.log(`To overwrite with automated .bak backup, re-run with:`);
|
|
191
|
-
console.log(` \x1b[32mnpx
|
|
219
|
+
console.log(` \x1b[32mnpx vibe-ui-suite add ${componentName} --force\x1b[0m\n`);
|
|
192
220
|
return;
|
|
193
221
|
}
|
|
194
222
|
if (writeRes.written) {
|
|
@@ -209,9 +237,18 @@ async function main() {
|
|
|
209
237
|
const rawArgs = process.argv.slice(2);
|
|
210
238
|
const force = rawArgs.includes('--force') || rawArgs.includes('-f');
|
|
211
239
|
const dryRun = rawArgs.includes('--dry-run');
|
|
212
|
-
const
|
|
240
|
+
const yes = rawArgs.includes('--yes') || rawArgs.includes('-y');
|
|
241
|
+
let chemistry;
|
|
242
|
+
let editor;
|
|
243
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
244
|
+
if (rawArgs[i] === '--chemistry' && rawArgs[i + 1])
|
|
245
|
+
chemistry = rawArgs[i + 1];
|
|
246
|
+
if (rawArgs[i] === '--editor' && rawArgs[i + 1])
|
|
247
|
+
editor = rawArgs[i + 1];
|
|
248
|
+
}
|
|
249
|
+
const filteredArgs = rawArgs.filter((a) => !['--force', '-f', '--dry-run', '--yes', '-y', '--chemistry', '--editor'].includes(a) && a !== chemistry && a !== editor);
|
|
213
250
|
const cmd = filteredArgs[0]?.toLowerCase();
|
|
214
|
-
const options = { force, dryRun };
|
|
251
|
+
const options = { force, dryRun, yes, chemistry, editor };
|
|
215
252
|
if (!cmd || cmd === '--help' || cmd === '-h') {
|
|
216
253
|
printHelp();
|
|
217
254
|
return;
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export interface ChemistryColors {
|
|
|
8
8
|
surface: string;
|
|
9
9
|
border: string;
|
|
10
10
|
primaryAccent: string;
|
|
11
|
+
/** Text color on primary accent guaranteeing >= 4.5:1 (AA) or >= 7:1 (AAA) contrast */
|
|
12
|
+
onPrimaryAccent: string;
|
|
11
13
|
textPrimary: string;
|
|
12
14
|
textMuted: string;
|
|
13
15
|
ring: string;
|
|
@@ -27,6 +29,7 @@ export interface VisualChemistry {
|
|
|
27
29
|
name: string;
|
|
28
30
|
tagline: string;
|
|
29
31
|
colors: ChemistryColors;
|
|
32
|
+
darkColors?: ChemistryColors;
|
|
30
33
|
typography: ChemistryTypography;
|
|
31
34
|
physics: ChemistryPhysics;
|
|
32
35
|
}
|
package/dist/index.js
CHANGED
|
@@ -13,17 +13,28 @@ exports.VISUAL_CHEMISTRIES = {
|
|
|
13
13
|
name: 'Minimalist SaaS',
|
|
14
14
|
tagline: 'High-signal B2B productivity with subtle borders and monochrome restraint',
|
|
15
15
|
colors: {
|
|
16
|
+
canvas: 'oklch(0.985 0.002 264)',
|
|
17
|
+
surface: 'oklch(1 0 0)',
|
|
18
|
+
border: 'oklch(0.90 0.008 264)',
|
|
19
|
+
primaryAccent: 'oklch(0.55 0.22 260)',
|
|
20
|
+
onPrimaryAccent: 'oklch(0.99 0 0)',
|
|
21
|
+
textPrimary: 'oklch(0.14 0.005 264)',
|
|
22
|
+
textMuted: 'oklch(0.48 0.015 264)',
|
|
23
|
+
ring: 'oklch(0.55 0.22 260)',
|
|
24
|
+
},
|
|
25
|
+
darkColors: {
|
|
16
26
|
canvas: 'oklch(0.14 0.005 264)',
|
|
17
27
|
surface: 'oklch(0.18 0.008 264)',
|
|
18
28
|
border: 'oklch(0.28 0.01 264)',
|
|
19
29
|
primaryAccent: 'oklch(0.65 0.22 260)',
|
|
30
|
+
onPrimaryAccent: 'oklch(0.99 0 0)',
|
|
20
31
|
textPrimary: 'oklch(0.98 0.002 264)',
|
|
21
32
|
textMuted: 'oklch(0.65 0.015 264)',
|
|
22
33
|
ring: 'oklch(0.65 0.22 260)',
|
|
23
34
|
},
|
|
24
35
|
typography: {
|
|
25
|
-
display: 'Inter, system-ui, sans-serif',
|
|
26
|
-
body: 'Inter, system-ui, sans-serif',
|
|
36
|
+
display: 'Vazirmatn, Inter, system-ui, sans-serif',
|
|
37
|
+
body: 'Vazirmatn, Inter, system-ui, sans-serif',
|
|
27
38
|
mono: 'JetBrains Mono, Menlo, monospace',
|
|
28
39
|
},
|
|
29
40
|
physics: {
|
|
@@ -37,17 +48,28 @@ exports.VISUAL_CHEMISTRIES = {
|
|
|
37
48
|
name: 'Luxury Glassmorphism 2.0',
|
|
38
49
|
tagline: 'Deep dark substrates with specular highlights and gold accents',
|
|
39
50
|
colors: {
|
|
51
|
+
canvas: 'oklch(0.97 0.01 85)',
|
|
52
|
+
surface: 'oklch(1 0 0 / 0.85)',
|
|
53
|
+
border: 'oklch(0.75 0.12 85 / 0.4)',
|
|
54
|
+
primaryAccent: 'oklch(0.65 0.18 85)',
|
|
55
|
+
onPrimaryAccent: 'oklch(0.12 0.02 85)',
|
|
56
|
+
textPrimary: 'oklch(0.16 0.02 85)',
|
|
57
|
+
textMuted: 'oklch(0.45 0.03 85)',
|
|
58
|
+
ring: 'oklch(0.65 0.18 85)',
|
|
59
|
+
},
|
|
60
|
+
darkColors: {
|
|
40
61
|
canvas: 'oklch(0.12 0.015 280)',
|
|
41
62
|
surface: 'oklch(0.18 0.02 280 / 0.75)',
|
|
42
63
|
border: 'oklch(0.75 0.15 85 / 0.35)',
|
|
43
64
|
primaryAccent: 'oklch(0.78 0.16 85)',
|
|
65
|
+
onPrimaryAccent: 'oklch(0.12 0.02 85)',
|
|
44
66
|
textPrimary: 'oklch(0.98 0.005 85)',
|
|
45
67
|
textMuted: 'oklch(0.70 0.03 85)',
|
|
46
68
|
ring: 'oklch(0.78 0.16 85)',
|
|
47
69
|
},
|
|
48
70
|
typography: {
|
|
49
|
-
display: 'Cinzel, Playfair Display, serif',
|
|
50
|
-
body: 'Plus Jakarta Sans, sans-serif',
|
|
71
|
+
display: 'Cinzel, Playfair Display, Vazirmatn, serif',
|
|
72
|
+
body: 'Vazirmatn, Plus Jakarta Sans, sans-serif',
|
|
51
73
|
mono: 'JetBrains Mono, monospace',
|
|
52
74
|
},
|
|
53
75
|
physics: {
|
|
@@ -65,13 +87,24 @@ exports.VISUAL_CHEMISTRIES = {
|
|
|
65
87
|
surface: 'oklch(0.99 0.002 95)',
|
|
66
88
|
border: 'oklch(0.15 0.01 95)',
|
|
67
89
|
primaryAccent: 'oklch(0.82 0.20 135)',
|
|
90
|
+
onPrimaryAccent: 'oklch(0.10 0.01 95)',
|
|
68
91
|
textPrimary: 'oklch(0.12 0.01 95)',
|
|
69
92
|
textMuted: 'oklch(0.35 0.02 95)',
|
|
70
93
|
ring: 'oklch(0.15 0.01 95)',
|
|
71
94
|
},
|
|
95
|
+
darkColors: {
|
|
96
|
+
canvas: 'oklch(0.15 0.01 95)',
|
|
97
|
+
surface: 'oklch(0.20 0.015 95)',
|
|
98
|
+
border: 'oklch(0.95 0.01 95)',
|
|
99
|
+
primaryAccent: 'oklch(0.82 0.20 135)',
|
|
100
|
+
onPrimaryAccent: 'oklch(0.10 0.01 95)',
|
|
101
|
+
textPrimary: 'oklch(0.96 0.01 95)',
|
|
102
|
+
textMuted: 'oklch(0.70 0.02 95)',
|
|
103
|
+
ring: 'oklch(0.82 0.20 135)',
|
|
104
|
+
},
|
|
72
105
|
typography: {
|
|
73
|
-
display: 'Space Grotesk, Syne, sans-serif',
|
|
74
|
-
body: 'Space Grotesk, sans-serif',
|
|
106
|
+
display: 'Space Grotesk, Syne, Vazirmatn, sans-serif',
|
|
107
|
+
body: 'Vazirmatn, Space Grotesk, sans-serif',
|
|
75
108
|
mono: 'Space Mono, monospace',
|
|
76
109
|
},
|
|
77
110
|
physics: {
|
|
@@ -89,13 +122,24 @@ exports.VISUAL_CHEMISTRIES = {
|
|
|
89
122
|
surface: 'oklch(0.93 0.008 80)',
|
|
90
123
|
border: 'oklch(0.20 0.005 80)',
|
|
91
124
|
primaryAccent: 'oklch(0.58 0.24 28)',
|
|
125
|
+
onPrimaryAccent: 'oklch(0.99 0 0)',
|
|
92
126
|
textPrimary: 'oklch(0.15 0.005 80)',
|
|
93
127
|
textMuted: 'oklch(0.42 0.01 80)',
|
|
94
128
|
ring: 'oklch(0.58 0.24 28)',
|
|
95
129
|
},
|
|
130
|
+
darkColors: {
|
|
131
|
+
canvas: 'oklch(0.13 0.005 80)',
|
|
132
|
+
surface: 'oklch(0.17 0.008 80)',
|
|
133
|
+
border: 'oklch(0.35 0.005 80)',
|
|
134
|
+
primaryAccent: 'oklch(0.68 0.22 28)',
|
|
135
|
+
onPrimaryAccent: 'oklch(0.12 0.005 80)',
|
|
136
|
+
textPrimary: 'oklch(0.95 0.005 80)',
|
|
137
|
+
textMuted: 'oklch(0.65 0.01 80)',
|
|
138
|
+
ring: 'oklch(0.68 0.22 28)',
|
|
139
|
+
},
|
|
96
140
|
typography: {
|
|
97
|
-
display: 'Helvetica Neue, Arial, sans-serif',
|
|
98
|
-
body: 'Newsreader, Georgia, serif',
|
|
141
|
+
display: 'Helvetica Neue, Arial, Vazirmatn, sans-serif',
|
|
142
|
+
body: 'Newsreader, Georgia, Vazirmatn, serif',
|
|
99
143
|
mono: 'Courier New, monospace',
|
|
100
144
|
},
|
|
101
145
|
physics: {
|
|
@@ -113,13 +157,24 @@ exports.VISUAL_CHEMISTRIES = {
|
|
|
113
157
|
surface: 'oklch(1 0 0)',
|
|
114
158
|
border: 'oklch(0.90 0.008 247.8)',
|
|
115
159
|
primaryAccent: 'oklch(0.55 0.22 265)',
|
|
160
|
+
onPrimaryAccent: 'oklch(0.99 0 0)',
|
|
116
161
|
textPrimary: 'oklch(0.20 0.02 265)',
|
|
117
162
|
textMuted: 'oklch(0.50 0.02 265)',
|
|
118
163
|
ring: 'oklch(0.55 0.22 265)',
|
|
119
164
|
},
|
|
165
|
+
darkColors: {
|
|
166
|
+
canvas: 'oklch(0.13 0.005 265)',
|
|
167
|
+
surface: 'oklch(0.17 0.008 265)',
|
|
168
|
+
border: 'oklch(0.26 0.01 265)',
|
|
169
|
+
primaryAccent: 'oklch(0.65 0.22 265)',
|
|
170
|
+
onPrimaryAccent: 'oklch(0.99 0 0)',
|
|
171
|
+
textPrimary: 'oklch(0.98 0 0)',
|
|
172
|
+
textMuted: 'oklch(0.65 0.01 265)',
|
|
173
|
+
ring: 'oklch(0.65 0.22 265)',
|
|
174
|
+
},
|
|
120
175
|
typography: {
|
|
121
|
-
display: 'Inter, system-ui, sans-serif',
|
|
122
|
-
body: 'Inter, system-ui, sans-serif',
|
|
176
|
+
display: 'Vazirmatn, Inter, system-ui, sans-serif',
|
|
177
|
+
body: 'Vazirmatn, Inter, system-ui, sans-serif',
|
|
123
178
|
mono: 'Fira Code, monospace',
|
|
124
179
|
},
|
|
125
180
|
physics: {
|
package/dist/index.mjs
CHANGED
|
@@ -8,17 +8,28 @@ export const VISUAL_CHEMISTRIES = {
|
|
|
8
8
|
name: 'Minimalist SaaS',
|
|
9
9
|
tagline: 'High-signal B2B productivity with subtle borders and monochrome restraint',
|
|
10
10
|
colors: {
|
|
11
|
+
canvas: 'oklch(0.985 0.002 264)',
|
|
12
|
+
surface: 'oklch(1 0 0)',
|
|
13
|
+
border: 'oklch(0.90 0.008 264)',
|
|
14
|
+
primaryAccent: 'oklch(0.55 0.22 260)',
|
|
15
|
+
onPrimaryAccent: 'oklch(0.99 0 0)',
|
|
16
|
+
textPrimary: 'oklch(0.14 0.005 264)',
|
|
17
|
+
textMuted: 'oklch(0.48 0.015 264)',
|
|
18
|
+
ring: 'oklch(0.55 0.22 260)',
|
|
19
|
+
},
|
|
20
|
+
darkColors: {
|
|
11
21
|
canvas: 'oklch(0.14 0.005 264)',
|
|
12
22
|
surface: 'oklch(0.18 0.008 264)',
|
|
13
23
|
border: 'oklch(0.28 0.01 264)',
|
|
14
24
|
primaryAccent: 'oklch(0.65 0.22 260)',
|
|
25
|
+
onPrimaryAccent: 'oklch(0.99 0 0)',
|
|
15
26
|
textPrimary: 'oklch(0.98 0.002 264)',
|
|
16
27
|
textMuted: 'oklch(0.65 0.015 264)',
|
|
17
28
|
ring: 'oklch(0.65 0.22 260)',
|
|
18
29
|
},
|
|
19
30
|
typography: {
|
|
20
|
-
display: 'Inter, system-ui, sans-serif',
|
|
21
|
-
body: 'Inter, system-ui, sans-serif',
|
|
31
|
+
display: 'Vazirmatn, Inter, system-ui, sans-serif',
|
|
32
|
+
body: 'Vazirmatn, Inter, system-ui, sans-serif',
|
|
22
33
|
mono: 'JetBrains Mono, Menlo, monospace',
|
|
23
34
|
},
|
|
24
35
|
physics: {
|
|
@@ -32,17 +43,28 @@ export const VISUAL_CHEMISTRIES = {
|
|
|
32
43
|
name: 'Luxury Glassmorphism 2.0',
|
|
33
44
|
tagline: 'Deep dark substrates with specular highlights and gold accents',
|
|
34
45
|
colors: {
|
|
46
|
+
canvas: 'oklch(0.97 0.01 85)',
|
|
47
|
+
surface: 'oklch(1 0 0 / 0.85)',
|
|
48
|
+
border: 'oklch(0.75 0.12 85 / 0.4)',
|
|
49
|
+
primaryAccent: 'oklch(0.65 0.18 85)',
|
|
50
|
+
onPrimaryAccent: 'oklch(0.12 0.02 85)',
|
|
51
|
+
textPrimary: 'oklch(0.16 0.02 85)',
|
|
52
|
+
textMuted: 'oklch(0.45 0.03 85)',
|
|
53
|
+
ring: 'oklch(0.65 0.18 85)',
|
|
54
|
+
},
|
|
55
|
+
darkColors: {
|
|
35
56
|
canvas: 'oklch(0.12 0.015 280)',
|
|
36
57
|
surface: 'oklch(0.18 0.02 280 / 0.75)',
|
|
37
58
|
border: 'oklch(0.75 0.15 85 / 0.35)',
|
|
38
59
|
primaryAccent: 'oklch(0.78 0.16 85)',
|
|
60
|
+
onPrimaryAccent: 'oklch(0.12 0.02 85)',
|
|
39
61
|
textPrimary: 'oklch(0.98 0.005 85)',
|
|
40
62
|
textMuted: 'oklch(0.70 0.03 85)',
|
|
41
63
|
ring: 'oklch(0.78 0.16 85)',
|
|
42
64
|
},
|
|
43
65
|
typography: {
|
|
44
|
-
display: 'Cinzel, Playfair Display, serif',
|
|
45
|
-
body: 'Plus Jakarta Sans, sans-serif',
|
|
66
|
+
display: 'Cinzel, Playfair Display, Vazirmatn, serif',
|
|
67
|
+
body: 'Vazirmatn, Plus Jakarta Sans, sans-serif',
|
|
46
68
|
mono: 'JetBrains Mono, monospace',
|
|
47
69
|
},
|
|
48
70
|
physics: {
|
|
@@ -60,13 +82,24 @@ export const VISUAL_CHEMISTRIES = {
|
|
|
60
82
|
surface: 'oklch(0.99 0.002 95)',
|
|
61
83
|
border: 'oklch(0.15 0.01 95)',
|
|
62
84
|
primaryAccent: 'oklch(0.82 0.20 135)',
|
|
85
|
+
onPrimaryAccent: 'oklch(0.10 0.01 95)',
|
|
63
86
|
textPrimary: 'oklch(0.12 0.01 95)',
|
|
64
87
|
textMuted: 'oklch(0.35 0.02 95)',
|
|
65
88
|
ring: 'oklch(0.15 0.01 95)',
|
|
66
89
|
},
|
|
90
|
+
darkColors: {
|
|
91
|
+
canvas: 'oklch(0.15 0.01 95)',
|
|
92
|
+
surface: 'oklch(0.20 0.015 95)',
|
|
93
|
+
border: 'oklch(0.95 0.01 95)',
|
|
94
|
+
primaryAccent: 'oklch(0.82 0.20 135)',
|
|
95
|
+
onPrimaryAccent: 'oklch(0.10 0.01 95)',
|
|
96
|
+
textPrimary: 'oklch(0.96 0.01 95)',
|
|
97
|
+
textMuted: 'oklch(0.70 0.02 95)',
|
|
98
|
+
ring: 'oklch(0.82 0.20 135)',
|
|
99
|
+
},
|
|
67
100
|
typography: {
|
|
68
|
-
display: 'Space Grotesk, Syne, sans-serif',
|
|
69
|
-
body: 'Space Grotesk, sans-serif',
|
|
101
|
+
display: 'Space Grotesk, Syne, Vazirmatn, sans-serif',
|
|
102
|
+
body: 'Vazirmatn, Space Grotesk, sans-serif',
|
|
70
103
|
mono: 'Space Mono, monospace',
|
|
71
104
|
},
|
|
72
105
|
physics: {
|
|
@@ -84,13 +117,24 @@ export const VISUAL_CHEMISTRIES = {
|
|
|
84
117
|
surface: 'oklch(0.93 0.008 80)',
|
|
85
118
|
border: 'oklch(0.20 0.005 80)',
|
|
86
119
|
primaryAccent: 'oklch(0.58 0.24 28)',
|
|
120
|
+
onPrimaryAccent: 'oklch(0.99 0 0)',
|
|
87
121
|
textPrimary: 'oklch(0.15 0.005 80)',
|
|
88
122
|
textMuted: 'oklch(0.42 0.01 80)',
|
|
89
123
|
ring: 'oklch(0.58 0.24 28)',
|
|
90
124
|
},
|
|
125
|
+
darkColors: {
|
|
126
|
+
canvas: 'oklch(0.13 0.005 80)',
|
|
127
|
+
surface: 'oklch(0.17 0.008 80)',
|
|
128
|
+
border: 'oklch(0.35 0.005 80)',
|
|
129
|
+
primaryAccent: 'oklch(0.68 0.22 28)',
|
|
130
|
+
onPrimaryAccent: 'oklch(0.12 0.005 80)',
|
|
131
|
+
textPrimary: 'oklch(0.95 0.005 80)',
|
|
132
|
+
textMuted: 'oklch(0.65 0.01 80)',
|
|
133
|
+
ring: 'oklch(0.68 0.22 28)',
|
|
134
|
+
},
|
|
91
135
|
typography: {
|
|
92
|
-
display: 'Helvetica Neue, Arial, sans-serif',
|
|
93
|
-
body: 'Newsreader, Georgia, serif',
|
|
136
|
+
display: 'Helvetica Neue, Arial, Vazirmatn, sans-serif',
|
|
137
|
+
body: 'Newsreader, Georgia, Vazirmatn, serif',
|
|
94
138
|
mono: 'Courier New, monospace',
|
|
95
139
|
},
|
|
96
140
|
physics: {
|
|
@@ -108,13 +152,24 @@ export const VISUAL_CHEMISTRIES = {
|
|
|
108
152
|
surface: 'oklch(1 0 0)',
|
|
109
153
|
border: 'oklch(0.90 0.008 247.8)',
|
|
110
154
|
primaryAccent: 'oklch(0.55 0.22 265)',
|
|
155
|
+
onPrimaryAccent: 'oklch(0.99 0 0)',
|
|
111
156
|
textPrimary: 'oklch(0.20 0.02 265)',
|
|
112
157
|
textMuted: 'oklch(0.50 0.02 265)',
|
|
113
158
|
ring: 'oklch(0.55 0.22 265)',
|
|
114
159
|
},
|
|
160
|
+
darkColors: {
|
|
161
|
+
canvas: 'oklch(0.13 0.005 265)',
|
|
162
|
+
surface: 'oklch(0.17 0.008 265)',
|
|
163
|
+
border: 'oklch(0.26 0.01 265)',
|
|
164
|
+
primaryAccent: 'oklch(0.65 0.22 265)',
|
|
165
|
+
onPrimaryAccent: 'oklch(0.99 0 0)',
|
|
166
|
+
textPrimary: 'oklch(0.98 0 0)',
|
|
167
|
+
textMuted: 'oklch(0.65 0.01 265)',
|
|
168
|
+
ring: 'oklch(0.65 0.22 265)',
|
|
169
|
+
},
|
|
115
170
|
typography: {
|
|
116
|
-
display: 'Inter, system-ui, sans-serif',
|
|
117
|
-
body: 'Inter, system-ui, sans-serif',
|
|
171
|
+
display: 'Vazirmatn, Inter, system-ui, sans-serif',
|
|
172
|
+
body: 'Vazirmatn, Inter, system-ui, sans-serif',
|
|
118
173
|
mono: 'Fira Code, monospace',
|
|
119
174
|
},
|
|
120
175
|
physics: {
|
|
@@ -218,6 +218,90 @@ export function ContrastBadge({ ratio, label = 'WCAG 2.2', className = '' }: Con
|
|
|
218
218
|
</span>
|
|
219
219
|
);
|
|
220
220
|
}
|
|
221
|
+
`,
|
|
222
|
+
},
|
|
223
|
+
'theme-toggle': {
|
|
224
|
+
name: 'theme-toggle',
|
|
225
|
+
filename: 'ThemeToggle.tsx',
|
|
226
|
+
description: 'Accessible dual-theme switch (light/dark) with SVG vector icons, focus ring, and localStorage persistence',
|
|
227
|
+
code: `'use client';
|
|
228
|
+
|
|
229
|
+
import React, { useEffect, useState } from 'react';
|
|
230
|
+
|
|
231
|
+
export interface ThemeToggleProps {
|
|
232
|
+
className?: string;
|
|
233
|
+
defaultTheme?: 'light' | 'dark' | 'system';
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export function ThemeToggle({ className = '', defaultTheme = 'system' }: ThemeToggleProps) {
|
|
237
|
+
const [theme, setTheme] = useState<'light' | 'dark'>('dark');
|
|
238
|
+
const [mounted, setMounted] = useState(false);
|
|
239
|
+
|
|
240
|
+
useEffect(() => {
|
|
241
|
+
setMounted(true);
|
|
242
|
+
const stored = localStorage.getItem('vibe-theme');
|
|
243
|
+
if (stored === 'light' || stored === 'dark') {
|
|
244
|
+
setTheme(stored);
|
|
245
|
+
document.documentElement.classList.toggle('dark', stored === 'dark');
|
|
246
|
+
document.documentElement.setAttribute('data-theme', stored);
|
|
247
|
+
} else {
|
|
248
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
249
|
+
const initial = defaultTheme === 'system' ? (prefersDark ? 'dark' : 'light') : defaultTheme;
|
|
250
|
+
setTheme(initial);
|
|
251
|
+
document.documentElement.classList.toggle('dark', initial === 'dark');
|
|
252
|
+
document.documentElement.setAttribute('data-theme', initial);
|
|
253
|
+
}
|
|
254
|
+
}, [defaultTheme]);
|
|
255
|
+
|
|
256
|
+
const toggleTheme = () => {
|
|
257
|
+
const next = theme === 'dark' ? 'light' : 'dark';
|
|
258
|
+
setTheme(next);
|
|
259
|
+
localStorage.setItem('vibe-theme', next);
|
|
260
|
+
document.documentElement.classList.toggle('dark', next === 'dark');
|
|
261
|
+
document.documentElement.setAttribute('data-theme', next);
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
if (!mounted) {
|
|
265
|
+
return (
|
|
266
|
+
<button
|
|
267
|
+
type="button"
|
|
268
|
+
aria-label="Toggle theme"
|
|
269
|
+
className={\`inline-flex items-center justify-center min-h-[44px] min-w-[44px] p-2.5 rounded-lg border border-neutral-800 bg-neutral-900/50 text-neutral-400 opacity-60 \${className}\`}
|
|
270
|
+
disabled
|
|
271
|
+
>
|
|
272
|
+
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
273
|
+
<circle cx="12" cy="12" r="4" strokeWidth="2" />
|
|
274
|
+
</svg>
|
|
275
|
+
</button>
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return (
|
|
280
|
+
<button
|
|
281
|
+
type="button"
|
|
282
|
+
onClick={toggleTheme}
|
|
283
|
+
aria-label={\`Switch to \${theme === 'dark' ? 'light' : 'dark'} mode\`}
|
|
284
|
+
className={\`inline-flex items-center justify-center min-h-[44px] min-w-[44px] p-2.5 rounded-lg border transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 \${
|
|
285
|
+
theme === 'dark'
|
|
286
|
+
? 'border-neutral-800 bg-neutral-900/80 text-neutral-200 hover:bg-neutral-800 hover:text-white'
|
|
287
|
+
: 'border-neutral-200 bg-white text-neutral-700 hover:bg-neutral-100 hover:text-neutral-900'
|
|
288
|
+
} \${className}\`}
|
|
289
|
+
>
|
|
290
|
+
{theme === 'dark' ? (
|
|
291
|
+
/* Sun Icon for switching to light mode */
|
|
292
|
+
<svg className="w-5 h-5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2" aria-hidden="true">
|
|
293
|
+
<circle cx="12" cy="12" r="4" />
|
|
294
|
+
<path strokeLinecap="round" d="M12 2v2m0 16v2M4.93 4.93l1.41 1.41m11.32 11.32l1.41 1.41M2 12h2m16 0h2M6.34 17.66l-1.41 1.41m14.14-14.14l-1.41 1.41" />
|
|
295
|
+
</svg>
|
|
296
|
+
) : (
|
|
297
|
+
/* Moon Icon for switching to dark mode */
|
|
298
|
+
<svg className="w-5 h-5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2" aria-hidden="true">
|
|
299
|
+
<path strokeLinecap="round" strokeLinejoin="round" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
|
300
|
+
</svg>
|
|
301
|
+
)}
|
|
302
|
+
</button>
|
|
303
|
+
);
|
|
304
|
+
}
|
|
221
305
|
`,
|
|
222
306
|
},
|
|
223
307
|
};
|
|
@@ -215,6 +215,90 @@ export function ContrastBadge({ ratio, label = 'WCAG 2.2', className = '' }: Con
|
|
|
215
215
|
</span>
|
|
216
216
|
);
|
|
217
217
|
}
|
|
218
|
+
`,
|
|
219
|
+
},
|
|
220
|
+
'theme-toggle': {
|
|
221
|
+
name: 'theme-toggle',
|
|
222
|
+
filename: 'ThemeToggle.tsx',
|
|
223
|
+
description: 'Accessible dual-theme switch (light/dark) with SVG vector icons, focus ring, and localStorage persistence',
|
|
224
|
+
code: `'use client';
|
|
225
|
+
|
|
226
|
+
import React, { useEffect, useState } from 'react';
|
|
227
|
+
|
|
228
|
+
export interface ThemeToggleProps {
|
|
229
|
+
className?: string;
|
|
230
|
+
defaultTheme?: 'light' | 'dark' | 'system';
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function ThemeToggle({ className = '', defaultTheme = 'system' }: ThemeToggleProps) {
|
|
234
|
+
const [theme, setTheme] = useState<'light' | 'dark'>('dark');
|
|
235
|
+
const [mounted, setMounted] = useState(false);
|
|
236
|
+
|
|
237
|
+
useEffect(() => {
|
|
238
|
+
setMounted(true);
|
|
239
|
+
const stored = localStorage.getItem('vibe-theme');
|
|
240
|
+
if (stored === 'light' || stored === 'dark') {
|
|
241
|
+
setTheme(stored);
|
|
242
|
+
document.documentElement.classList.toggle('dark', stored === 'dark');
|
|
243
|
+
document.documentElement.setAttribute('data-theme', stored);
|
|
244
|
+
} else {
|
|
245
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
246
|
+
const initial = defaultTheme === 'system' ? (prefersDark ? 'dark' : 'light') : defaultTheme;
|
|
247
|
+
setTheme(initial);
|
|
248
|
+
document.documentElement.classList.toggle('dark', initial === 'dark');
|
|
249
|
+
document.documentElement.setAttribute('data-theme', initial);
|
|
250
|
+
}
|
|
251
|
+
}, [defaultTheme]);
|
|
252
|
+
|
|
253
|
+
const toggleTheme = () => {
|
|
254
|
+
const next = theme === 'dark' ? 'light' : 'dark';
|
|
255
|
+
setTheme(next);
|
|
256
|
+
localStorage.setItem('vibe-theme', next);
|
|
257
|
+
document.documentElement.classList.toggle('dark', next === 'dark');
|
|
258
|
+
document.documentElement.setAttribute('data-theme', next);
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
if (!mounted) {
|
|
262
|
+
return (
|
|
263
|
+
<button
|
|
264
|
+
type="button"
|
|
265
|
+
aria-label="Toggle theme"
|
|
266
|
+
className={\`inline-flex items-center justify-center min-h-[44px] min-w-[44px] p-2.5 rounded-lg border border-neutral-800 bg-neutral-900/50 text-neutral-400 opacity-60 \${className}\`}
|
|
267
|
+
disabled
|
|
268
|
+
>
|
|
269
|
+
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
270
|
+
<circle cx="12" cy="12" r="4" strokeWidth="2" />
|
|
271
|
+
</svg>
|
|
272
|
+
</button>
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return (
|
|
277
|
+
<button
|
|
278
|
+
type="button"
|
|
279
|
+
onClick={toggleTheme}
|
|
280
|
+
aria-label={\`Switch to \${theme === 'dark' ? 'light' : 'dark'} mode\`}
|
|
281
|
+
className={\`inline-flex items-center justify-center min-h-[44px] min-w-[44px] p-2.5 rounded-lg border transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 \${
|
|
282
|
+
theme === 'dark'
|
|
283
|
+
? 'border-neutral-800 bg-neutral-900/80 text-neutral-200 hover:bg-neutral-800 hover:text-white'
|
|
284
|
+
: 'border-neutral-200 bg-white text-neutral-700 hover:bg-neutral-100 hover:text-neutral-900'
|
|
285
|
+
} \${className}\`}
|
|
286
|
+
>
|
|
287
|
+
{theme === 'dark' ? (
|
|
288
|
+
/* Sun Icon for switching to light mode */
|
|
289
|
+
<svg className="w-5 h-5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2" aria-hidden="true">
|
|
290
|
+
<circle cx="12" cy="12" r="4" />
|
|
291
|
+
<path strokeLinecap="round" d="M12 2v2m0 16v2M4.93 4.93l1.41 1.41m11.32 11.32l1.41 1.41M2 12h2m16 0h2M6.34 17.66l-1.41 1.41m14.14-14.14l-1.41 1.41" />
|
|
292
|
+
</svg>
|
|
293
|
+
) : (
|
|
294
|
+
/* Moon Icon for switching to dark mode */
|
|
295
|
+
<svg className="w-5 h-5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2" aria-hidden="true">
|
|
296
|
+
<path strokeLinecap="round" strokeLinejoin="round" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
|
297
|
+
</svg>
|
|
298
|
+
)}
|
|
299
|
+
</button>
|
|
300
|
+
);
|
|
301
|
+
}
|
|
218
302
|
`,
|
|
219
303
|
},
|
|
220
304
|
};
|
package/dist/tailwind.js
CHANGED
|
@@ -16,6 +16,7 @@ function createVibeUiPlugin(options = {}) {
|
|
|
16
16
|
'--vibe-surface': chem.colors.surface,
|
|
17
17
|
'--vibe-border': chem.colors.border,
|
|
18
18
|
'--vibe-primary': chem.colors.primaryAccent,
|
|
19
|
+
'--vibe-on-primary': chem.colors.onPrimaryAccent,
|
|
19
20
|
'--vibe-text-primary': chem.colors.textPrimary,
|
|
20
21
|
'--vibe-text-muted': chem.colors.textMuted,
|
|
21
22
|
'--vibe-ring': chem.colors.ring,
|
|
@@ -33,9 +34,18 @@ function createVibeUiPlugin(options = {}) {
|
|
|
33
34
|
'.vibe-spring': {
|
|
34
35
|
'transition-timing-function': index_1.MOTION_CURVES.naturalSpring,
|
|
35
36
|
},
|
|
37
|
+
'.ease-vibe-spring': {
|
|
38
|
+
'transition-timing-function': index_1.MOTION_CURVES.naturalSpring,
|
|
39
|
+
},
|
|
36
40
|
'.vibe-snap': {
|
|
37
41
|
'transition-timing-function': index_1.MOTION_CURVES.responsiveSnap,
|
|
38
42
|
},
|
|
43
|
+
'.ease-vibe-snap': {
|
|
44
|
+
'transition-timing-function': index_1.MOTION_CURVES.responsiveSnap,
|
|
45
|
+
},
|
|
46
|
+
'.ease-vibe-glide': {
|
|
47
|
+
'transition-timing-function': 'cubic-bezier(0.25, 1, 0.5, 1)',
|
|
48
|
+
},
|
|
39
49
|
'.vibe-glass': {
|
|
40
50
|
'backdrop-filter': 'blur(12px)',
|
|
41
51
|
'-webkit-backdrop-filter': 'blur(12px)',
|
package/dist/tailwind.mjs
CHANGED
|
@@ -12,6 +12,7 @@ export function createVibeUiPlugin(options = {}) {
|
|
|
12
12
|
'--vibe-surface': chem.colors.surface,
|
|
13
13
|
'--vibe-border': chem.colors.border,
|
|
14
14
|
'--vibe-primary': chem.colors.primaryAccent,
|
|
15
|
+
'--vibe-on-primary': chem.colors.onPrimaryAccent,
|
|
15
16
|
'--vibe-text-primary': chem.colors.textPrimary,
|
|
16
17
|
'--vibe-text-muted': chem.colors.textMuted,
|
|
17
18
|
'--vibe-ring': chem.colors.ring,
|
|
@@ -29,9 +30,18 @@ export function createVibeUiPlugin(options = {}) {
|
|
|
29
30
|
'.vibe-spring': {
|
|
30
31
|
'transition-timing-function': MOTION_CURVES.naturalSpring,
|
|
31
32
|
},
|
|
33
|
+
'.ease-vibe-spring': {
|
|
34
|
+
'transition-timing-function': MOTION_CURVES.naturalSpring,
|
|
35
|
+
},
|
|
32
36
|
'.vibe-snap': {
|
|
33
37
|
'transition-timing-function': MOTION_CURVES.responsiveSnap,
|
|
34
38
|
},
|
|
39
|
+
'.ease-vibe-snap': {
|
|
40
|
+
'transition-timing-function': MOTION_CURVES.responsiveSnap,
|
|
41
|
+
},
|
|
42
|
+
'.ease-vibe-glide': {
|
|
43
|
+
'transition-timing-function': 'cubic-bezier(0.25, 1, 0.5, 1)',
|
|
44
|
+
},
|
|
35
45
|
'.vibe-glass': {
|
|
36
46
|
'backdrop-filter': 'blur(12px)',
|
|
37
47
|
'-webkit-backdrop-filter': 'blur(12px)',
|
package/dist/v4.css
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* vibe-ui-suite/v4.css — Native Tailwind CSS v4 Theme Preset
|
|
3
3
|
* Provides zero-config @theme tokens with perceptual OKLCH color spaces and physics curves.
|
|
4
4
|
* Usage:
|
|
5
5
|
* @import "tailwindcss";
|
|
6
|
-
* @import "
|
|
6
|
+
* @import "vibe-ui-suite/v4.css";
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
@theme {
|
|
10
|
-
/* OKLCH Perceptual Colors — Semantic Palette */
|
|
11
|
-
--color-vibe-canvas: var(--vibe-canvas, oklch(0.
|
|
12
|
-
--color-vibe-surface: var(--vibe-surface, oklch(0
|
|
13
|
-
--color-vibe-border: var(--vibe-border, oklch(0.
|
|
14
|
-
--color-vibe-primary: var(--vibe-primary, oklch(0.
|
|
15
|
-
--color-vibe-
|
|
16
|
-
--color-vibe-text-
|
|
17
|
-
--color-vibe-
|
|
10
|
+
/* OKLCH Perceptual Colors — Semantic Palette (Defaults to Light Mode) */
|
|
11
|
+
--color-vibe-canvas: var(--vibe-canvas, oklch(0.985 0.002 264));
|
|
12
|
+
--color-vibe-surface: var(--vibe-surface, oklch(1 0 0));
|
|
13
|
+
--color-vibe-border: var(--vibe-border, oklch(0.90 0.008 264));
|
|
14
|
+
--color-vibe-primary: var(--vibe-primary-accent, var(--vibe-primary, oklch(0.55 0.22 260)));
|
|
15
|
+
--color-vibe-on-primary: var(--vibe-on-primary, oklch(0.99 0 0));
|
|
16
|
+
--color-vibe-text-primary: var(--vibe-text-primary, oklch(0.14 0.005 264));
|
|
17
|
+
--color-vibe-text-muted: var(--vibe-text-muted, oklch(0.48 0.015 264));
|
|
18
|
+
--color-vibe-ring: var(--vibe-ring, oklch(0.55 0.22 260));
|
|
19
|
+
|
|
20
|
+
/* Typography Stacks with Vazirmatn Persian Web Font */
|
|
21
|
+
--font-vibe-sans: Vazirmatn, Inter, system-ui, -apple-system, sans-serif;
|
|
22
|
+
--font-vibe-display: Vazirmatn, Inter, system-ui, sans-serif;
|
|
23
|
+
--font-vibe-mono: JetBrains Mono, Menlo, monospace;
|
|
18
24
|
|
|
19
25
|
/* Spring & Snap Physics Curves */
|
|
20
26
|
--ease-vibe-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
@@ -27,6 +33,19 @@
|
|
|
27
33
|
--shadow-vibe-glass: inset 0 1px 1px rgba(255, 255, 255, 0.15);
|
|
28
34
|
}
|
|
29
35
|
|
|
36
|
+
/* Fallback Dark Theme Variables when .dark or [data-theme="dark"] is applied */
|
|
37
|
+
.dark, [data-theme="dark"] {
|
|
38
|
+
--vibe-canvas: oklch(0.14 0.005 264);
|
|
39
|
+
--vibe-surface: oklch(0.18 0.008 264);
|
|
40
|
+
--vibe-border: oklch(0.28 0.01 264);
|
|
41
|
+
--vibe-primary: oklch(0.65 0.22 260);
|
|
42
|
+
--vibe-primary-accent: oklch(0.65 0.22 260);
|
|
43
|
+
--vibe-on-primary: oklch(0.99 0 0);
|
|
44
|
+
--vibe-text-primary: oklch(0.98 0 0);
|
|
45
|
+
--vibe-text-muted: oklch(0.65 0.015 264);
|
|
46
|
+
--vibe-ring: oklch(0.65 0.22 260);
|
|
47
|
+
}
|
|
48
|
+
|
|
30
49
|
/* BiDi Isolation Utility */
|
|
31
50
|
[dir="rtl"] {
|
|
32
51
|
letter-spacing: normal !important;
|
|
@@ -37,3 +56,16 @@
|
|
|
37
56
|
backdrop-filter: blur(12px);
|
|
38
57
|
-webkit-backdrop-filter: blur(12px);
|
|
39
58
|
}
|
|
59
|
+
|
|
60
|
+
/* Tailwind CSS v4 Motion & Transition Utilities */
|
|
61
|
+
@utility transition-vibe-spring {
|
|
62
|
+
transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@utility transition-vibe-snap {
|
|
66
|
+
transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@utility transition-vibe-glide {
|
|
70
|
+
transition-timing-function: cubic-bezier(0.25, 1, 0.5, 1);
|
|
71
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibe-ui-suite",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.8.0",
|
|
4
4
|
"description": "Deterministic design contracts, component recipes, and WCAG AA evaluation gates for AI coding agents (Cursor, Claude Code, Windsurf, Antigravity).",
|
|
5
5
|
"bin": {
|
|
6
6
|
"vibe-ui-suite": "./dist/cli.js",
|
|
@@ -23,6 +23,10 @@
|
|
|
23
23
|
"./v4": "./dist/v4.css",
|
|
24
24
|
"./v4.css": "./dist/v4.css"
|
|
25
25
|
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
26
30
|
"scripts": {
|
|
27
31
|
"build": "node build.js"
|
|
28
32
|
},
|
package/build.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
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.');
|