start-vibing-stacks 2.0.3 → 2.0.4

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/dist/ui.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * Start Vibing Stacks — Terminal UI
3
3
  */
4
4
  import chalk from 'chalk';
5
- const VERSION = '2.0.3';
5
+ const VERSION = '2.0.4';
6
6
  const gradient = (text) => {
7
7
  const colors = [chalk.hex('#FF6B6B'), chalk.hex('#FF8E53'), chalk.hex('#FFBD2E'), chalk.hex('#48BB78'), chalk.hex('#4299E1'), chalk.hex('#9F7AEA')];
8
8
  return text.split('').map((c, i) => colors[i % colors.length](c)).join('');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "start-vibing-stacks",
3
- "version": "2.0.3",
3
+ "version": "2.0.4",
4
4
  "description": "AI-powered multi-stack dev workflow for Claude Code. Supports PHP, Node.js, Python and more.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -49,27 +49,139 @@ export default function Dashboard() {
49
49
 
50
50
  **Rule:** Never leave raw `console.log`. Always use controlled debug pattern.
51
51
 
52
- ## TailwindCSS Class Organization
52
+ ## TailwindCSS Class Organization (CONST Pattern)
53
+
54
+ **MANDATORY:** Define all CSS classes as constants at the TOP of the file, before the component.
55
+
56
+ ### Why
57
+
58
+ 1. **No re-renders** — string constants have stable references (no new object per render)
59
+ 2. **Single source of truth** — change style once, updates everywhere
60
+ 3. **Clean JSX** — readable templates, no class soup
61
+ 4. **Prevents React state warnings** — no inline objects/strings changing reference
62
+ 5. **Easy theming** — swap tokens in one place
63
+
64
+ ### Pattern
53
65
 
54
66
  ```tsx
55
- // ✅ Classes as CONST — clean JSX
56
- const STYLES = {
57
- container: 'flex flex-col gap-4 p-6 bg-white rounded-lg shadow-sm',
58
- title: 'text-2xl font-bold text-gray-900',
59
- button: 'px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition',
60
- grid: 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6',
61
- };
67
+ // ═══════════════════════════════════════════
68
+ // 1. TRANSLATIONS (before hooks)
69
+ // ═══════════════════════════════════════════
70
+ const LABELS = {
71
+ title: __('dashboard.title'),
72
+ save: __('common.save'),
73
+ } as const;
62
74
 
75
+ // ═══════════════════════════════════════════
76
+ // 2. STYLES (semantic tokens, not raw colors)
77
+ // ═══════════════════════════════════════════
78
+ const STYLES = {
79
+ // Layout
80
+ page: 'max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8',
81
+ section: 'space-y-6',
82
+ grid: 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4',
83
+
84
+ // Cards
85
+ card: 'bg-card border border-card-line rounded-xl p-6 hover:shadow-md transition-shadow',
86
+ cardHeader: 'flex items-center justify-between border-b border-card-divider pb-4 mb-4',
87
+ cardTitle: 'text-lg font-semibold text-foreground',
88
+ cardDescription: 'text-sm text-muted-foreground mt-1',
89
+
90
+ // Table
91
+ table: 'w-full text-sm',
92
+ tableHeader: 'text-left text-muted-foreground font-medium border-b border-border',
93
+ tableRow: 'border-b border-border hover:bg-muted/50 transition-colors',
94
+ tableCell: 'px-4 py-3 text-foreground',
95
+
96
+ // Buttons
97
+ btnPrimary: 'px-4 py-2 bg-primary text-primary-foreground rounded-lg hover:bg-primary-hover font-medium disabled:opacity-50 disabled:cursor-not-allowed transition-colors',
98
+ btnSecondary: 'px-4 py-2 bg-layer border border-layer-line text-layer-foreground rounded-lg hover:bg-layer-hover font-medium transition-colors',
99
+ btnDestructive: 'px-4 py-2 bg-destructive text-destructive-foreground rounded-lg hover:bg-destructive-hover font-medium transition-colors',
100
+ btnGhost: 'px-4 py-2 text-muted-foreground hover:bg-muted rounded-lg transition-colors',
101
+
102
+ // Forms
103
+ input: 'w-full h-10 px-3 rounded-md border border-border bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:border-transparent transition-colors',
104
+ label: 'block text-sm font-medium text-foreground mb-1',
105
+ fieldError: 'mt-1 text-sm text-destructive',
106
+
107
+ // Status badges
108
+ badgeSuccess: 'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400',
109
+ badgeWarning: 'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-400',
110
+ badgeDanger: 'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400',
111
+
112
+ // Typography
113
+ heading: 'text-2xl font-bold text-foreground',
114
+ subheading: 'text-lg font-semibold text-foreground',
115
+ body: 'text-sm text-foreground',
116
+ muted: 'text-sm text-muted-foreground',
117
+ } as const;
118
+
119
+ // ═══════════════════════════════════════════
120
+ // 3. COMPONENT
121
+ // ═══════════════════════════════════════════
63
122
  export default function Dashboard() {
123
+ const [data, setData] = useState(null);
124
+
64
125
  return (
65
- <div className={STYLES.container}>
66
- <h1 className={STYLES.title}>{LABELS.title}</h1>
126
+ <div className={STYLES.page}>
127
+ <h1 className={STYLES.heading}>{LABELS.title}</h1>
128
+ <div className={STYLES.grid}>
129
+ <div className={STYLES.card}>
130
+ <h2 className={STYLES.cardTitle}>Stats</h2>
131
+ <p className={STYLES.cardDescription}>Overview</p>
132
+ </div>
133
+ </div>
67
134
  </div>
68
135
  );
69
136
  }
137
+ ```
138
+
139
+ ### Composing Styles
70
140
 
71
- // ❌ Inline class soup
72
- <div className="flex flex-col gap-4 p-6 bg-white rounded-lg shadow-sm"> // ❌
141
+ ```tsx
142
+ // Combine with template literal when conditional
143
+ <tr className={`${STYLES.tableRow} ${isSelected ? 'bg-primary/5' : ''}`}>
144
+
145
+ // ✅ clsx/cn for complex conditions
146
+ import { cn } from '@/lib/utils';
147
+ <button className={cn(STYLES.btnPrimary, isFullWidth && 'w-full', className)}>
148
+ ```
149
+
150
+ ### Rules
151
+
152
+ 1. **CONST at top** — before hooks, before component
153
+ 2. **`as const`** — TypeScript ensures immutability
154
+ 3. **Semantic tokens** — `bg-card` not `bg-white`, `text-foreground` not `text-gray-900`
155
+ 4. **No inline class strings > 3 utilities** — extract to STYLES
156
+ 5. **Shared styles** — create a `styles.ts` file for cross-component constants
157
+
158
+ ```tsx
159
+ // resources/js/styles.ts — shared across components
160
+ export const SHARED_STYLES = {
161
+ page: 'max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8',
162
+ btnPrimary: 'px-4 py-2 bg-primary text-primary-foreground rounded-lg hover:bg-primary-hover ...',
163
+ input: 'w-full h-10 px-3 rounded-md border border-border bg-background ...',
164
+ } as const;
165
+ ```
166
+
167
+ ### ❌ FORBIDDEN
168
+
169
+ ```tsx
170
+ // ❌ Inline class soup — unreadable, unstable reference
171
+ <div className="flex flex-col gap-4 p-6 bg-white rounded-lg shadow-sm">
172
+
173
+ // ❌ Raw colors instead of tokens
174
+ const STYLES = { card: 'bg-white text-gray-900' }; // ❌ Breaks dark mode
175
+
176
+ // ❌ Dynamic class construction (breaks Tailwind purge)
177
+ const color = 'blue';
178
+ <div className={`bg-${color}-500`}> // ❌ Purged!
179
+
180
+ // ❌ Styles inside component (new object every render)
181
+ export default function Bad() {
182
+ const styles = { card: 'bg-card p-4' }; // ❌ Inside = new ref every render
183
+ return <div className={styles.card} />;
184
+ }
73
185
  ```
74
186
 
75
187
  ## SVG Icons