omnidesign 1.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.
Files changed (77) hide show
  1. package/LICENSE +21 -0
  2. package/QUICKREF.md +150 -0
  3. package/README.md +576 -0
  4. package/bin/cli.js +390 -0
  5. package/bin/detect-ide.js +50 -0
  6. package/bin/install.js +8 -0
  7. package/logo.jpg +0 -0
  8. package/package.json +84 -0
  9. package/recipes/components/README.md +29 -0
  10. package/recipes/components/agent-card.md +314 -0
  11. package/recipes/components/ai-chat.md +252 -0
  12. package/recipes/components/bento-grid.md +186 -0
  13. package/recipes/components/code-block.md +503 -0
  14. package/recipes/components/file-upload.md +483 -0
  15. package/recipes/components/forms.md +238 -0
  16. package/recipes/components/hero-section.md +161 -0
  17. package/recipes/components/navbar.md +214 -0
  18. package/recipes/components/prompt-input.md +293 -0
  19. package/recipes/components/thinking-indicator.md +372 -0
  20. package/recipes/motion/README.md +3 -0
  21. package/recipes/motion/motion-system.md +437 -0
  22. package/recipes/patterns/README.md +3 -0
  23. package/skills/aider/omnidesign.md +67 -0
  24. package/skills/amp/SKILL.md +114 -0
  25. package/skills/antigravity/SKILL.md +114 -0
  26. package/skills/claude/omnidesign.md +111 -0
  27. package/skills/continue/omnidesign.yaml +29 -0
  28. package/skills/cursor/omnidesign.md +110 -0
  29. package/skills/kilo/SKILL.md +114 -0
  30. package/skills/opencode/omnidesign.md +110 -0
  31. package/skills/vscode/package.json +66 -0
  32. package/skills/zed/omnidesign.json +7 -0
  33. package/tokens/motion/README.md +3 -0
  34. package/tokens/primitives/README.md +3 -0
  35. package/tokens/primitives/color.json +219 -0
  36. package/tokens/primitives/motion.json +56 -0
  37. package/tokens/primitives/radii.json +37 -0
  38. package/tokens/primitives/shadows.json +34 -0
  39. package/tokens/primitives/spacing.json +67 -0
  40. package/tokens/primitives/typography.json +127 -0
  41. package/tokens/semantic/README.md +3 -0
  42. package/tokens/semantic/color.json +114 -0
  43. package/tokens/semantic/motion.json +44 -0
  44. package/tokens/semantic/radii.json +29 -0
  45. package/tokens/semantic/shadows.json +24 -0
  46. package/tokens/semantic/spacing.json +69 -0
  47. package/tokens/semantic/typography.json +118 -0
  48. package/tokens/shadows/README.md +3 -0
  49. package/tokens/themes/README.md +3 -0
  50. package/tokens/themes/berry.json +143 -0
  51. package/tokens/themes/brutalist.json +143 -0
  52. package/tokens/themes/coral.json +143 -0
  53. package/tokens/themes/corporate.json +143 -0
  54. package/tokens/themes/cream.json +143 -0
  55. package/tokens/themes/cyberpunk.json +143 -0
  56. package/tokens/themes/daylight.json +143 -0
  57. package/tokens/themes/deep-space.json +143 -0
  58. package/tokens/themes/forest.json +143 -0
  59. package/tokens/themes/graphite.json +143 -0
  60. package/tokens/themes/lavender.json +143 -0
  61. package/tokens/themes/midnight.json +143 -0
  62. package/tokens/themes/mint.json +143 -0
  63. package/tokens/themes/navy.json +143 -0
  64. package/tokens/themes/noir.json +143 -0
  65. package/tokens/themes/obsidian.json +143 -0
  66. package/tokens/themes/ocean.json +143 -0
  67. package/tokens/themes/paper.json +143 -0
  68. package/tokens/themes/ruby.json +143 -0
  69. package/tokens/themes/slate.json +143 -0
  70. package/tokens/themes/snow.json +143 -0
  71. package/tokens/themes/solar.json +143 -0
  72. package/tokens/themes/spring.json +143 -0
  73. package/tokens/themes/starry-night.json +143 -0
  74. package/tokens/themes/sunset.json +143 -0
  75. package/tokens/typography/FONT_GUIDE.md +381 -0
  76. package/tokens/typography/README.md +37 -0
  77. package/tokens/typography/font-collection.json +221 -0
@@ -0,0 +1,483 @@
1
+ # File Upload for AI
2
+
3
+ Drag-and-drop file upload with AI-specific features like context preview and file type indicators.
4
+
5
+ ## When to Use
6
+ - Uploading documents for AI analysis
7
+ - Attaching files to chat messages
8
+ - Adding context to AI prompts
9
+ - Knowledge base uploads
10
+
11
+ ## Anatomy
12
+
13
+ ```
14
+ ┌─────────────────────────────────────────────────────────────┐
15
+ │ FileUpload │
16
+ │ ├─ DropZone (drag target with visual feedback) │
17
+ │ │ ├─ Upload Icon │
18
+ │ │ ├─ Instructions (drag here or click) │
19
+ │ │ └─ File Type Hints (PDF, images, etc.) │
20
+ │ ├─ FileList (uploaded files with previews) │
21
+ │ │ ├─ FileChip (thumbnail + name + remove) │
22
+ │ │ └─ FileProgress (upload progress bar) │
23
+ │ └─ UploadActions (clear all, upload button) │
24
+ └─────────────────────────────────────────────────────────────┘
25
+ ```
26
+
27
+ ## Token Usage
28
+
29
+ ```css
30
+ /* Drop Zone */
31
+ .drop-zone {
32
+ display: flex;
33
+ flex-direction: column;
34
+ align-items: center;
35
+ justify-content: center;
36
+ padding: var(--spacing-xl);
37
+ background: var(--color-surface-raised);
38
+ border: 2px dashed var(--color-border-default);
39
+ border-radius: var(--radius-xl);
40
+ transition: all var(--duration-fast);
41
+ cursor: pointer;
42
+ }
43
+
44
+ .drop-zone:hover {
45
+ border-color: var(--color-interactive-primary);
46
+ background: rgba(37, 99, 235, 0.05);
47
+ }
48
+
49
+ .drop-zone.drag-over {
50
+ border-color: var(--color-interactive-primary);
51
+ background: rgba(37, 99, 235, 0.1);
52
+ transform: scale(1.02);
53
+ }
54
+
55
+ .drop-zone.error {
56
+ border-color: var(--color-status-error);
57
+ background: rgba(239, 68, 68, 0.05);
58
+ }
59
+
60
+ /* Upload Icon */
61
+ .upload-icon {
62
+ width: 48px;
63
+ height: 48px;
64
+ color: var(--color-text-muted);
65
+ margin-bottom: var(--spacing-md);
66
+ }
67
+
68
+ .drop-zone:hover .upload-icon {
69
+ color: var(--color-interactive-primary);
70
+ }
71
+
72
+ /* Instructions */
73
+ .upload-text {
74
+ color: var(--color-text-default);
75
+ font-weight: var(--font-weight-medium);
76
+ margin-bottom: var(--spacing-xs);
77
+ }
78
+
79
+ .upload-hint {
80
+ color: var(--color-text-muted);
81
+ font-size: var(--font-size-sm);
82
+ }
83
+
84
+ /* File Type Badges */
85
+ .file-types {
86
+ display: flex;
87
+ gap: var(--spacing-xs);
88
+ margin-top: var(--spacing-md);
89
+ }
90
+
91
+ .file-type-badge {
92
+ display: flex;
93
+ align-items: center;
94
+ gap: var(--spacing-2xs);
95
+ padding: var(--spacing-2xs) var(--spacing-xs);
96
+ background: var(--color-surface-sunken);
97
+ border-radius: var(--radius-sm);
98
+ font-size: var(--font-size-xs);
99
+ color: var(--color-text-muted);
100
+ }
101
+
102
+ /* File Chip */
103
+ .file-chip {
104
+ display: flex;
105
+ align-items: center;
106
+ gap: var(--spacing-sm);
107
+ padding: var(--spacing-sm);
108
+ background: var(--color-surface-raised);
109
+ border: 1px solid var(--color-border-default);
110
+ border-radius: var(--radius-lg);
111
+ max-width: 100%;
112
+ }
113
+
114
+ .file-thumbnail {
115
+ width: 40px;
116
+ height: 40px;
117
+ border-radius: var(--radius-md);
118
+ background: var(--color-surface-sunken);
119
+ display: flex;
120
+ align-items: center;
121
+ justify-content: center;
122
+ flex-shrink: 0;
123
+ }
124
+
125
+ .file-thumbnail img {
126
+ width: 100%;
127
+ height: 100%;
128
+ object-fit: cover;
129
+ border-radius: var(--radius-md);
130
+ }
131
+
132
+ .file-thumbnail-icon {
133
+ width: 20px;
134
+ height: 20px;
135
+ color: var(--color-interactive-primary);
136
+ }
137
+
138
+ .file-info {
139
+ flex: 1;
140
+ min-width: 0;
141
+ }
142
+
143
+ .file-name {
144
+ font-weight: var(--font-weight-medium);
145
+ color: var(--color-text-default);
146
+ white-space: nowrap;
147
+ overflow: hidden;
148
+ text-overflow: ellipsis;
149
+ }
150
+
151
+ .file-meta {
152
+ font-size: var(--font-size-xs);
153
+ color: var(--color-text-muted);
154
+ }
155
+
156
+ .file-remove {
157
+ display: flex;
158
+ align-items: center;
159
+ justify-content: center;
160
+ width: 28px;
161
+ height: 28px;
162
+ border: none;
163
+ background: transparent;
164
+ border-radius: var(--radius-md);
165
+ color: var(--color-text-muted);
166
+ cursor: pointer;
167
+ transition: all var(--duration-fast);
168
+ flex-shrink: 0;
169
+ }
170
+
171
+ .file-remove:hover {
172
+ background: rgba(239, 68, 68, 0.1);
173
+ color: var(--color-status-error);
174
+ }
175
+
176
+ /* Progress Bar */
177
+ .file-progress {
178
+ margin-top: var(--spacing-xs);
179
+ }
180
+
181
+ .progress-bar {
182
+ height: 4px;
183
+ background: var(--color-surface-sunken);
184
+ border-radius: var(--radius-full);
185
+ overflow: hidden;
186
+ }
187
+
188
+ .progress-fill {
189
+ height: 100%;
190
+ background: var(--color-interactive-primary);
191
+ border-radius: var(--radius-full);
192
+ transition: width var(--duration-fast);
193
+ }
194
+
195
+ /* Upload Actions */
196
+ .upload-actions {
197
+ display: flex;
198
+ justify-content: flex-end;
199
+ gap: var(--spacing-sm);
200
+ margin-top: var(--spacing-md);
201
+ padding-top: var(--spacing-md);
202
+ border-top: 1px solid var(--color-border-default);
203
+ }
204
+
205
+ /* Context Preview (AI Feature) */
206
+ .context-preview {
207
+ margin-top: var(--spacing-md);
208
+ padding: var(--spacing-md);
209
+ background: var(--color-surface-sunken);
210
+ border-radius: var(--radius-lg);
211
+ border-left: 3px solid var(--color-interactive-primary);
212
+ }
213
+
214
+ .context-preview h4 {
215
+ font-size: var(--font-size-xs);
216
+ font-weight: var(--font-weight-semibold);
217
+ color: var(--color-text-muted);
218
+ text-transform: uppercase;
219
+ letter-spacing: 0.05em;
220
+ margin-bottom: var(--spacing-xs);
221
+ }
222
+
223
+ .context-text {
224
+ font-size: var(--font-size-sm);
225
+ color: var(--color-text-default);
226
+ line-height: var(--line-height-relaxed);
227
+ max-height: 100px;
228
+ overflow-y: auto;
229
+ }
230
+ ```
231
+
232
+ ## State Matrix
233
+
234
+ | Element | Default | Hover | Drag Over | Error | Uploading |
235
+ |---------|---------|-------|-----------|-------|-----------|
236
+ | Drop Zone | border-default | border-primary + tint | border-primary + scale | border-error | - |
237
+ | Upload Icon | muted | primary | primary | error | - |
238
+ | File Chip | raised bg | border-strong | - | - | - |
239
+ | Remove Button | ghost | error tint | - | - | - |
240
+ | Progress Bar | - | - | - | - | fill animates |
241
+
242
+ ## Accessibility
243
+
244
+ ```html
245
+ <div
246
+ class="drop-zone"
247
+ role="button"
248
+ tabindex="0"
249
+ aria-label="Drop files here or click to upload"
250
+ onDragOver={handleDragOver}
251
+ onDrop={handleDrop}
252
+ onKeyDown={handleKeyDown}
253
+ >
254
+ <UploadIcon aria-hidden="true" />
255
+ <p class="upload-text">Drop files here or click to upload</p>
256
+ <p class="upload-hint">Supports PDF, images, text files up to 10MB</p>
257
+ </div>
258
+
259
+ <!-- File list -->
260
+ <ul class="file-list" role="list" aria-label="Uploaded files">
261
+ <li class="file-chip" role="listitem">
262
+ <div class="file-thumbnail">
263
+ <img src="preview.jpg" alt="Preview of document.pdf" />
264
+ </div>
265
+ <div class="file-info">
266
+ <p class="file-name">document.pdf</p>
267
+ <p class="file-meta">2.4 MB • Ready to analyze</p>
268
+ </div>
269
+ <button
270
+ class="file-remove"
271
+ aria-label="Remove document.pdf"
272
+ onClick={handleRemove}
273
+ >
274
+ <CloseIcon aria-hidden="true" />
275
+ </button>
276
+ </li>
277
+ </ul>
278
+
279
+ <!-- Screen reader announcements -->
280
+ <div aria-live="polite" aria-atomic="true" class="sr-only">
281
+ File uploaded: document.pdf
282
+ </div>
283
+ ```
284
+
285
+ ## Example: AI File Upload
286
+
287
+ ```tsx
288
+ function AIFileUpload({ onUpload, acceptedTypes = ['pdf', 'jpg', 'png', 'txt'] }) {
289
+ const [files, setFiles] = useState([]);
290
+ const [isDragging, setIsDragging] = useState(false);
291
+
292
+ const handleDrop = (e) => {
293
+ e.preventDefault();
294
+ setIsDragging(false);
295
+ const droppedFiles = Array.from(e.dataTransfer.files);
296
+ processFiles(droppedFiles);
297
+ };
298
+
299
+ const processFiles = async (newFiles) => {
300
+ for (const file of newFiles) {
301
+ const fileWithPreview = {
302
+ id: Math.random().toString(36),
303
+ file,
304
+ preview: file.type.startsWith('image/') ? URL.createObjectURL(file) : null,
305
+ progress: 0,
306
+ status: 'uploading'
307
+ };
308
+
309
+ setFiles(prev => [...prev, fileWithPreview]);
310
+
311
+ // Simulate upload progress
312
+ await uploadFile(fileWithPreview);
313
+ }
314
+ };
315
+
316
+ const uploadFile = async (fileItem) => {
317
+ // Upload logic here
318
+ for (let progress = 0; progress <= 100; progress += 10) {
319
+ await new Promise(r => setTimeout(r, 200));
320
+ setFiles(prev => prev.map(f =>
321
+ f.id === fileItem.id ? { ...f, progress } : f
322
+ ));
323
+ }
324
+
325
+ setFiles(prev => prev.map(f =>
326
+ f.id === fileItem.id ? { ...f, status: 'ready', progress: 100 } : f
327
+ ));
328
+
329
+ onUpload?.(fileItem.file);
330
+ };
331
+
332
+ const removeFile = (id) => {
333
+ setFiles(prev => {
334
+ const file = prev.find(f => f.id === id);
335
+ if (file?.preview) URL.revokeObjectURL(file.preview);
336
+ return prev.filter(f => f.id !== id);
337
+ });
338
+ };
339
+
340
+ return (
341
+ <div className="file-upload">
342
+ <div
343
+ className={`drop-zone ${isDragging ? 'drag-over' : ''}`}
344
+ onDragOver={(e) => { e.preventDefault(); setIsDragging(true); }}
345
+ onDragLeave={() => setIsDragging(false)}
346
+ onDrop={handleDrop}
347
+ onClick={() => inputRef.current?.click()}
348
+ >
349
+ <UploadIcon className="upload-icon" />
350
+ <p className="upload-text">Drop files here or click to upload</p>
351
+ <p className="upload-hint">
352
+ Supports {acceptedTypes.join(', ')} up to 10MB
353
+ </p>
354
+
355
+ <div className="file-types">
356
+ {acceptedTypes.map(type => (
357
+ <span key={type} className="file-type-badge">
358
+ <FileIcon /> {type.toUpperCase()}
359
+ </span>
360
+ ))}
361
+ </div>
362
+ </div>
363
+
364
+ <input
365
+ ref={inputRef}
366
+ type="file"
367
+ multiple
368
+ accept={acceptedTypes.map(t => `.${t}`).join(',')}
369
+ onChange={(e) => processFiles(Array.from(e.target.files))}
370
+ hidden
371
+ />
372
+
373
+ {files.length > 0 && (
374
+ <ul className="file-list">
375
+ {files.map(file => (
376
+ <li key={file.id} className="file-chip">
377
+ <div className="file-thumbnail">
378
+ {file.preview ? (
379
+ <img src={file.preview} alt="" />
380
+ ) : (
381
+ <FileIcon className="file-thumbnail-icon" />
382
+ )}
383
+ </div>
384
+
385
+ <div className="file-info">
386
+ <p className="file-name">{file.file.name}</p>
387
+ <p className="file-meta">
388
+ {formatSize(file.file.size)} •
389
+ {file.status === 'uploading' ? ` ${file.progress}%` : ' Ready'}
390
+ </p>
391
+ {file.status === 'uploading' && (
392
+ <div className="file-progress">
393
+ <div className="progress-bar">
394
+ <div
395
+ className="progress-fill"
396
+ style={{ width: `${file.progress}%` }}
397
+ />
398
+ </div>
399
+ </div>
400
+ )}
401
+ </div>
402
+
403
+ <button
404
+ className="file-remove"
405
+ onClick={() => removeFile(file.id)}
406
+ aria-label={`Remove ${file.file.name}`}
407
+ >
408
+ <CloseIcon />
409
+ </button>
410
+ </li>
411
+ ))}
412
+ </ul>
413
+ )}
414
+
415
+ {files.length > 0 && (
416
+ <div className="upload-actions">
417
+ <button onClick={() => setFiles([])}>Clear all</button>
418
+ <button className="primary">Analyze files</button>
419
+ </div>
420
+ )}
421
+ </div>
422
+ );
423
+ }
424
+ ```
425
+
426
+ ## Example: Inline File Attachments (Chat)
427
+
428
+ ```tsx
429
+ function FileAttachments({ files, onRemove }) {
430
+ if (files.length === 0) return null;
431
+
432
+ return (
433
+ <div className="attachment-list">
434
+ {files.map(file => (
435
+ <div key={file.id} className="attachment-chip">
436
+ {file.preview ? (
437
+ <img src={file.preview} alt="" className="attachment-thumb" />
438
+ ) : (
439
+ <FileIcon />
440
+ )}
441
+ <span className="attachment-name">{file.name}</span>
442
+ <button
443
+ className="attachment-remove"
444
+ onClick={() => onRemove(file.id)}
445
+ >
446
+ <CloseIcon />
447
+ </button>
448
+ </div>
449
+ ))}
450
+ </div>
451
+ );
452
+ }
453
+
454
+ // Usage in chat input
455
+ function ChatInputWithFiles() {
456
+ const [attachments, setAttachments] = useState([]);
457
+
458
+ return (
459
+ <div className="chat-input-container">
460
+ <FileAttachments
461
+ files={attachments}
462
+ onRemove={(id) => setAttachments(prev => prev.filter(f => f.id !== id))}
463
+ />
464
+
465
+ <div className="input-row">
466
+ <FileUploadButton
467
+ onFiles={(files) => setAttachments(prev => [...prev, ...files])}
468
+ />
469
+ <textarea placeholder="Ask about these files..." />
470
+ <SendButton />
471
+ </div>
472
+ </div>
473
+ );
474
+ }
475
+ ```
476
+
477
+ ## Tokens Used
478
+
479
+ - **color**: surface-raised, surface-sunken, interactive-primary, text-default, text-muted, border-default, border-strong, status-error
480
+ - **spacing**: 2xs, xs, sm, md, xl
481
+ - **radii**: sm, md, lg, xl, full
482
+ - **typography**: size-xs, size-sm, weight-medium, weight-semibold
483
+ - **motion**: duration-fast