ux-toolkit 0.1.0 → 0.4.1

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 (44) hide show
  1. package/README.md +113 -7
  2. package/agents/card-reviewer.md +173 -0
  3. package/agents/comparison-reviewer.md +143 -0
  4. package/agents/density-reviewer.md +207 -0
  5. package/agents/detail-page-reviewer.md +143 -0
  6. package/agents/editor-reviewer.md +165 -0
  7. package/agents/form-reviewer.md +156 -0
  8. package/agents/game-ui-reviewer.md +181 -0
  9. package/agents/list-page-reviewer.md +132 -0
  10. package/agents/navigation-reviewer.md +145 -0
  11. package/agents/panel-reviewer.md +182 -0
  12. package/agents/replay-reviewer.md +174 -0
  13. package/agents/settings-reviewer.md +166 -0
  14. package/agents/ux-auditor.md +145 -45
  15. package/agents/ux-engineer.md +211 -38
  16. package/dist/cli.js +172 -5
  17. package/dist/cli.js.map +1 -1
  18. package/dist/index.cjs +172 -5
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +128 -4
  21. package/dist/index.d.ts +128 -4
  22. package/dist/index.js +172 -5
  23. package/dist/index.js.map +1 -1
  24. package/package.json +6 -4
  25. package/skills/canvas-grid-patterns/SKILL.md +367 -0
  26. package/skills/comparison-patterns/SKILL.md +354 -0
  27. package/skills/data-density-patterns/SKILL.md +493 -0
  28. package/skills/detail-page-patterns/SKILL.md +522 -0
  29. package/skills/drag-drop-patterns/SKILL.md +406 -0
  30. package/skills/editor-workspace-patterns/SKILL.md +552 -0
  31. package/skills/event-timeline-patterns/SKILL.md +542 -0
  32. package/skills/form-patterns/SKILL.md +608 -0
  33. package/skills/info-card-patterns/SKILL.md +531 -0
  34. package/skills/keyboard-shortcuts-patterns/SKILL.md +365 -0
  35. package/skills/list-page-patterns/SKILL.md +351 -0
  36. package/skills/modal-patterns/SKILL.md +750 -0
  37. package/skills/navigation-patterns/SKILL.md +476 -0
  38. package/skills/page-structure-patterns/SKILL.md +271 -0
  39. package/skills/playback-replay-patterns/SKILL.md +695 -0
  40. package/skills/react-ux-patterns/SKILL.md +434 -0
  41. package/skills/split-panel-patterns/SKILL.md +609 -0
  42. package/skills/status-visualization-patterns/SKILL.md +635 -0
  43. package/skills/toast-notification-patterns/SKILL.md +207 -0
  44. package/skills/turn-based-ui-patterns/SKILL.md +506 -0
@@ -0,0 +1,493 @@
1
+ ---
2
+ name: data-density-patterns
3
+ description: Patterns for displaying dense information on screens without overlap, with proper scrolling, z-index management, and responsive condensing
4
+ license: MIT
5
+ ---
6
+
7
+ # Data Density UX Patterns
8
+
9
+ When screens need to display a lot of information, proper density management prevents overlap, ensures readability, and maintains usability.
10
+
11
+ ## Core Principles
12
+
13
+ ### The Density Hierarchy
14
+ ```
15
+ 1. Essential information visible immediately (no scroll)
16
+ 2. Important information accessible with minimal scroll
17
+ 3. Secondary information in collapsible sections
18
+ 4. Tertiary information behind "show more" or modals
19
+ ```
20
+
21
+ ### Screen Real Estate Budget
22
+ | Screen Size | Visible Height | Recommended Sections |
23
+ |-------------|----------------|---------------------|
24
+ | Mobile (< 640px) | ~500px | 2-3 collapsed sections |
25
+ | Tablet (768px) | ~600px | 3-4 sections with scrolling |
26
+ | Desktop (1024px+) | ~700px | Multi-column layout |
27
+ | Large (1440px+) | ~800px | Dashboard-style grid |
28
+
29
+ ## Preventing Overlap
30
+
31
+ ### Z-Index Scale (MUST FOLLOW)
32
+ ```css
33
+ /* Establish consistent z-index layers */
34
+ :root {
35
+ --z-base: 0;
36
+ --z-dropdown: 10; /* Dropdowns, tooltips */
37
+ --z-sticky: 20; /* Sticky headers, navigation */
38
+ --z-overlay: 30; /* Page overlays */
39
+ --z-modal: 40; /* Modal dialogs */
40
+ --z-popover: 50; /* Popovers on modals */
41
+ --z-toast: 60; /* Toast notifications */
42
+ --z-tooltip: 70; /* Tooltips (always on top) */
43
+ }
44
+ ```
45
+
46
+ ### Stacking Context Rules
47
+ ```tsx
48
+ // RULE: Each layer creates a stacking context
49
+ // Avoid z-index wars by using proper containment
50
+
51
+ // BAD: Random z-index values
52
+ <div style={{ zIndex: 9999 }}>...</div>
53
+
54
+ // GOOD: Semantic layer classes
55
+ <div className="z-dropdown">...</div>
56
+ <div className="z-modal">...</div>
57
+ ```
58
+
59
+ ### Overlap Prevention Checklist
60
+ - [ ] Fixed/sticky elements don't overlap content
61
+ - [ ] Dropdowns don't get cut off by containers
62
+ - [ ] Modals appear above all page content
63
+ - [ ] Tooltips appear above modals when needed
64
+ - [ ] Toasts don't block important UI
65
+
66
+ ## Ensuring Nothing Is Off-Screen
67
+
68
+ ### Viewport-Aware Positioning
69
+ ```tsx
70
+ function useViewportAwarePosition(elementRef: RefObject<HTMLElement>) {
71
+ const [position, setPosition] = useState({ x: 0, y: 0 });
72
+
73
+ useEffect(() => {
74
+ if (!elementRef.current) return;
75
+
76
+ const rect = elementRef.current.getBoundingClientRect();
77
+ const viewport = {
78
+ width: window.innerWidth,
79
+ height: window.innerHeight,
80
+ };
81
+
82
+ let x = position.x;
83
+ let y = position.y;
84
+
85
+ // Prevent right overflow
86
+ if (rect.right > viewport.width) {
87
+ x -= (rect.right - viewport.width + 16);
88
+ }
89
+ // Prevent bottom overflow
90
+ if (rect.bottom > viewport.height) {
91
+ y -= (rect.bottom - viewport.height + 16);
92
+ }
93
+ // Prevent left overflow
94
+ if (rect.left < 0) {
95
+ x += Math.abs(rect.left) + 16;
96
+ }
97
+ // Prevent top overflow
98
+ if (rect.top < 0) {
99
+ y += Math.abs(rect.top) + 16;
100
+ }
101
+
102
+ setPosition({ x, y });
103
+ }, [elementRef]);
104
+
105
+ return position;
106
+ }
107
+ ```
108
+
109
+ ### Container Scroll Handling
110
+ ```tsx
111
+ // RULE: Content containers must have explicit overflow handling
112
+
113
+ // Dense content area with scroll
114
+ <div className="
115
+ max-h-[calc(100vh-200px)] /* Account for header/footer */
116
+ overflow-y-auto
117
+ overflow-x-hidden
118
+ scrollbar-thin scrollbar-thumb-border scrollbar-track-transparent
119
+ ">
120
+ {/* Dense content */}
121
+ </div>
122
+
123
+ // Horizontal scroll for wide tables
124
+ <div className="overflow-x-auto -mx-4 px-4">
125
+ <table className="min-w-[800px]">...</table>
126
+ </div>
127
+ ```
128
+
129
+ ### Safe Area Insets (Mobile)
130
+ ```css
131
+ /* Account for notches, home indicators */
132
+ .page-container {
133
+ padding-left: max(1rem, env(safe-area-inset-left));
134
+ padding-right: max(1rem, env(safe-area-inset-right));
135
+ padding-bottom: max(1rem, env(safe-area-inset-bottom));
136
+ }
137
+ ```
138
+
139
+ ## Readability in Dense Layouts
140
+
141
+ ### Minimum Spacing Rules
142
+ ```css
143
+ /* NEVER go below these minimums */
144
+ --min-touch-target: 44px; /* Minimum tappable area */
145
+ --min-text-spacing: 4px; /* Between text lines */
146
+ --min-element-gap: 8px; /* Between UI elements */
147
+ --min-section-gap: 16px; /* Between sections */
148
+ ```
149
+
150
+ ### Typography for Dense Data
151
+ ```tsx
152
+ // Data-dense typography scale
153
+ const denseTypography = {
154
+ heading: 'text-base font-semibold', // Smaller than normal
155
+ label: 'text-xs font-medium uppercase tracking-wide text-text-muted',
156
+ value: 'text-sm font-mono', // Mono for data alignment
157
+ secondary: 'text-xs text-text-secondary',
158
+ };
159
+
160
+ // Example: Dense stat display
161
+ <div className="grid grid-cols-4 gap-2">
162
+ <div className="p-2 bg-surface-raised rounded">
163
+ <span className={denseTypography.label}>Speed</span>
164
+ <span className={denseTypography.value}>142</span>
165
+ </div>
166
+ </div>
167
+ ```
168
+
169
+ ### Color Contrast in Dense UI
170
+ ```tsx
171
+ // High contrast for dense data
172
+ const denseColors = {
173
+ background: 'bg-surface-deep', // Darkest background
174
+ card: 'bg-surface-base', // Slightly lighter
175
+ highlight: 'bg-accent/10', // Subtle highlight
176
+ border: 'border-border/50', // Subtle borders
177
+ text: 'text-white', // Maximum contrast
178
+ muted: 'text-text-secondary', // De-emphasized
179
+ };
180
+ ```
181
+
182
+ ## Condensing Information Patterns
183
+
184
+ ### Collapsible Sections
185
+ ```tsx
186
+ function CollapsibleDataSection({ title, defaultOpen = false, children }) {
187
+ const [isOpen, setIsOpen] = useState(defaultOpen);
188
+
189
+ return (
190
+ <div className="border border-border rounded-lg overflow-hidden">
191
+ <button
192
+ onClick={() => setIsOpen(!isOpen)}
193
+ className="w-full flex items-center justify-between px-4 py-3 bg-surface-raised hover:bg-surface-raised/80"
194
+ >
195
+ <span className="text-sm font-medium text-white">{title}</span>
196
+ <ChevronDownIcon className={`w-4 h-4 transition-transform ${isOpen ? 'rotate-180' : ''}`} />
197
+ </button>
198
+
199
+ {isOpen && (
200
+ <div className="px-4 py-3 bg-surface-base">
201
+ {children}
202
+ </div>
203
+ )}
204
+ </div>
205
+ );
206
+ }
207
+ ```
208
+
209
+ ### Truncation with Expansion
210
+ ```tsx
211
+ function TruncatedText({ text, maxLength = 100 }) {
212
+ const [isExpanded, setIsExpanded] = useState(false);
213
+ const shouldTruncate = text.length > maxLength;
214
+
215
+ return (
216
+ <div>
217
+ <p className="text-sm text-text-primary">
218
+ {isExpanded || !shouldTruncate ? text : `${text.slice(0, maxLength)}...`}
219
+ </p>
220
+ {shouldTruncate && (
221
+ <button
222
+ onClick={() => setIsExpanded(!isExpanded)}
223
+ className="text-xs text-accent hover:underline mt-1"
224
+ >
225
+ {isExpanded ? 'Show less' : 'Show more'}
226
+ </button>
227
+ )}
228
+ </div>
229
+ );
230
+ }
231
+ ```
232
+
233
+ ### Progressive Disclosure
234
+ ```tsx
235
+ // Show summary, expand for details
236
+ function DataCard({ summary, details }) {
237
+ const [showDetails, setShowDetails] = useState(false);
238
+
239
+ return (
240
+ <div className="p-4 bg-surface-raised rounded-lg">
241
+ {/* Always visible summary */}
242
+ <div className="flex items-center justify-between">
243
+ <div>
244
+ <h4 className="text-sm font-medium text-white">{summary.title}</h4>
245
+ <p className="text-xs text-text-muted">{summary.subtitle}</p>
246
+ </div>
247
+ <button
248
+ onClick={() => setShowDetails(!showDetails)}
249
+ className="text-xs text-accent"
250
+ >
251
+ {showDetails ? 'Less' : 'More'}
252
+ </button>
253
+ </div>
254
+
255
+ {/* Expandable details */}
256
+ {showDetails && (
257
+ <div className="mt-3 pt-3 border-t border-border text-xs space-y-2">
258
+ {details.map((d, i) => (
259
+ <div key={i} className="flex justify-between">
260
+ <span className="text-text-muted">{d.label}</span>
261
+ <span className="text-white">{d.value}</span>
262
+ </div>
263
+ ))}
264
+ </div>
265
+ )}
266
+ </div>
267
+ );
268
+ }
269
+ ```
270
+
271
+ ## Dense Grid Layouts
272
+
273
+ ### Responsive Dense Grid
274
+ ```tsx
275
+ // Auto-fit columns based on available space
276
+ <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-2">
277
+ {items.map(item => (
278
+ <DenseCard key={item.id} item={item} />
279
+ ))}
280
+ </div>
281
+
282
+ // Fixed minimum width columns
283
+ <div className="grid gap-2" style={{ gridTemplateColumns: 'repeat(auto-fit, minmax(150px, 1fr))' }}>
284
+ {items.map(item => (
285
+ <DenseCard key={item.id} item={item} />
286
+ ))}
287
+ </div>
288
+ ```
289
+
290
+ ### Dense Stats Grid
291
+ ```tsx
292
+ function StatsGrid({ stats }) {
293
+ return (
294
+ <div className="grid grid-cols-2 sm:grid-cols-4 lg:grid-cols-6 gap-1">
295
+ {stats.map((stat) => (
296
+ <div
297
+ key={stat.label}
298
+ className="p-2 bg-surface-raised/50 rounded text-center"
299
+ >
300
+ <div className="text-lg font-bold text-white font-mono">
301
+ {stat.value}
302
+ </div>
303
+ <div className="text-[10px] text-text-muted uppercase tracking-wide">
304
+ {stat.label}
305
+ </div>
306
+ </div>
307
+ ))}
308
+ </div>
309
+ );
310
+ }
311
+ ```
312
+
313
+ ## Dense Tables
314
+
315
+ ### Compact Table Pattern
316
+ ```tsx
317
+ function DenseTable({ columns, data }) {
318
+ return (
319
+ <div className="overflow-x-auto">
320
+ <table className="w-full text-xs">
321
+ <thead>
322
+ <tr className="bg-surface-raised">
323
+ {columns.map((col) => (
324
+ <th
325
+ key={col.key}
326
+ className="px-2 py-1.5 text-left font-medium text-text-muted uppercase tracking-wide whitespace-nowrap"
327
+ >
328
+ {col.label}
329
+ </th>
330
+ ))}
331
+ </tr>
332
+ </thead>
333
+ <tbody className="divide-y divide-border/30">
334
+ {data.map((row, i) => (
335
+ <tr key={i} className="hover:bg-surface-raised/30">
336
+ {columns.map((col) => (
337
+ <td
338
+ key={col.key}
339
+ className="px-2 py-1.5 text-text-primary whitespace-nowrap"
340
+ >
341
+ {row[col.key]}
342
+ </td>
343
+ ))}
344
+ </tr>
345
+ ))}
346
+ </tbody>
347
+ </table>
348
+ </div>
349
+ );
350
+ }
351
+ ```
352
+
353
+ ### Virtualized Long Lists
354
+ ```tsx
355
+ // For lists with 100+ items, use virtualization
356
+ import { useVirtualizer } from '@tanstack/react-virtual';
357
+
358
+ function VirtualizedList({ items, renderItem, itemHeight = 40 }) {
359
+ const parentRef = useRef<HTMLDivElement>(null);
360
+
361
+ const virtualizer = useVirtualizer({
362
+ count: items.length,
363
+ getScrollElement: () => parentRef.current,
364
+ estimateSize: () => itemHeight,
365
+ });
366
+
367
+ return (
368
+ <div
369
+ ref={parentRef}
370
+ className="h-[400px] overflow-auto"
371
+ >
372
+ <div
373
+ style={{ height: `${virtualizer.getTotalSize()}px`, position: 'relative' }}
374
+ >
375
+ {virtualizer.getVirtualItems().map((virtualRow) => (
376
+ <div
377
+ key={virtualRow.key}
378
+ style={{
379
+ position: 'absolute',
380
+ top: 0,
381
+ left: 0,
382
+ width: '100%',
383
+ height: `${virtualRow.size}px`,
384
+ transform: `translateY(${virtualRow.start}px)`,
385
+ }}
386
+ >
387
+ {renderItem(items[virtualRow.index])}
388
+ </div>
389
+ ))}
390
+ </div>
391
+ </div>
392
+ );
393
+ }
394
+ ```
395
+
396
+ ## Navigation in Dense UIs
397
+
398
+ ### Sticky Section Headers
399
+ ```tsx
400
+ function StickySection({ title, children }) {
401
+ return (
402
+ <div className="relative">
403
+ <div className="sticky top-0 z-10 bg-surface-deep/95 backdrop-blur-sm py-2 -mx-4 px-4 border-b border-border">
404
+ <h3 className="text-sm font-semibold text-white">{title}</h3>
405
+ </div>
406
+ <div className="pt-3">
407
+ {children}
408
+ </div>
409
+ </div>
410
+ );
411
+ }
412
+ ```
413
+
414
+ ### Jump Navigation
415
+ ```tsx
416
+ function JumpNav({ sections, activeSection, onJump }) {
417
+ return (
418
+ <nav className="sticky top-0 z-20 bg-surface-deep border-b border-border py-2 -mx-4 px-4 mb-4">
419
+ <div className="flex gap-1 overflow-x-auto scrollbar-none">
420
+ {sections.map((section) => (
421
+ <button
422
+ key={section.id}
423
+ onClick={() => onJump(section.id)}
424
+ className={`
425
+ px-2.5 py-1 text-xs font-medium rounded-md whitespace-nowrap
426
+ ${activeSection === section.id
427
+ ? 'bg-accent/20 text-accent'
428
+ : 'text-text-muted hover:text-white hover:bg-surface-raised'}
429
+ `}
430
+ >
431
+ {section.label}
432
+ </button>
433
+ ))}
434
+ </div>
435
+ </nav>
436
+ );
437
+ }
438
+ ```
439
+
440
+ ## Responsive Density Adjustments
441
+
442
+ ### Breakpoint-Based Density
443
+ ```tsx
444
+ // More dense on larger screens, less on mobile
445
+ const densityClasses = {
446
+ mobile: 'p-4 space-y-4 text-sm', // Looser spacing
447
+ desktop: 'p-2 space-y-2 text-xs', // Tighter spacing
448
+ };
449
+
450
+ <div className={`
451
+ ${densityClasses.mobile}
452
+ lg:${densityClasses.desktop}
453
+ `}>
454
+ {content}
455
+ </div>
456
+ ```
457
+
458
+ ### Hide Secondary Info on Mobile
459
+ ```tsx
460
+ <div className="flex items-center gap-4">
461
+ <span className="text-white">{primary}</span>
462
+ <span className="hidden sm:inline text-text-muted">{secondary}</span>
463
+ <span className="hidden lg:inline text-text-muted">{tertiary}</span>
464
+ </div>
465
+ ```
466
+
467
+ ## Audit Checklist for Dense UIs
468
+
469
+ ### Critical (Must Fix)
470
+ - [ ] Z-index values follow established scale - elements hidden/overlapping
471
+ - [ ] Modals/dialogs appear above all content - blocked interactions
472
+ - [ ] All content accessible via scroll - data inaccessible
473
+ - [ ] Text meets minimum size (12px body, 10px labels) - unreadable
474
+ - [ ] Sufficient contrast ratios maintained - accessibility violation
475
+
476
+ ### Major (Should Fix)
477
+ - [ ] Fixed elements don't overlap scrollable content - content hidden
478
+ - [ ] Dropdowns/popovers don't get clipped - unusable controls
479
+ - [ ] No horizontal scroll unless intentional (tables) - poor mobile UX
480
+ - [ ] Tooltips/popovers stay within viewport - information cut off
481
+ - [ ] Mobile safe areas respected - notch/home bar overlap
482
+ - [ ] Adequate spacing between elements - hard to tap/click
483
+ - [ ] Long lists are virtualized (100+ items) - performance issues
484
+ - [ ] No layout shift during loading - disorienting jumps
485
+
486
+ ### Minor (Nice to Have)
487
+ - [ ] Line height appropriate for text size - readability polish
488
+ - [ ] Jump navigation for long pages - convenience
489
+ - [ ] Section headers are sticky - navigation convenience
490
+ - [ ] Current section is highlighted - orientation
491
+ - [ ] Scroll position preserved on back navigation - continuity
492
+ - [ ] Images are lazy loaded - performance optimization
493
+ - [ ] Animations are reduced in dense areas - performance polish