sonance-brand-mcp 1.3.111 → 1.3.113

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 (79) hide show
  1. package/dist/assets/api/sonance-save-image/route.ts +625 -0
  2. package/dist/assets/api/sonance-vision-apply/image-styling-detection.ts +1360 -0
  3. package/dist/assets/api/sonance-vision-apply/route.ts +988 -57
  4. package/dist/assets/api/sonance-vision-apply/styling-detection.ts +730 -0
  5. package/dist/assets/api/sonance-vision-apply/theme-discovery.ts +1 -1
  6. package/dist/assets/brand-system.ts +13 -12
  7. package/dist/assets/components/accordion.tsx +15 -7
  8. package/dist/assets/components/alert-dialog.tsx +35 -10
  9. package/dist/assets/components/alert.tsx +11 -10
  10. package/dist/assets/components/avatar.tsx +4 -4
  11. package/dist/assets/components/badge.tsx +16 -12
  12. package/dist/assets/components/button.stories.tsx +3 -3
  13. package/dist/assets/components/button.tsx +50 -31
  14. package/dist/assets/components/calendar.tsx +12 -8
  15. package/dist/assets/components/card.tsx +35 -29
  16. package/dist/assets/components/checkbox.tsx +9 -8
  17. package/dist/assets/components/code.tsx +19 -11
  18. package/dist/assets/components/command.tsx +32 -13
  19. package/dist/assets/components/context-menu.tsx +37 -16
  20. package/dist/assets/components/dialog.tsx +8 -5
  21. package/dist/assets/components/divider.tsx +15 -5
  22. package/dist/assets/components/drawer.tsx +4 -3
  23. package/dist/assets/components/dropdown-menu.tsx +15 -13
  24. package/dist/assets/components/hover-card.tsx +4 -1
  25. package/dist/assets/components/image.tsx +1 -1
  26. package/dist/assets/components/input.tsx +29 -14
  27. package/dist/assets/components/kbd.stories.tsx +3 -3
  28. package/dist/assets/components/kbd.tsx +29 -13
  29. package/dist/assets/components/listbox.tsx +8 -8
  30. package/dist/assets/components/menubar.tsx +50 -23
  31. package/dist/assets/components/navbar.stories.tsx +140 -13
  32. package/dist/assets/components/navbar.tsx +22 -5
  33. package/dist/assets/components/navigation-menu.tsx +28 -6
  34. package/dist/assets/components/pagination.tsx +10 -10
  35. package/dist/assets/components/popover.tsx +10 -8
  36. package/dist/assets/components/progress.tsx +6 -4
  37. package/dist/assets/components/radio-group.tsx +5 -5
  38. package/dist/assets/components/select.tsx +49 -29
  39. package/dist/assets/components/separator.tsx +3 -3
  40. package/dist/assets/components/sheet.tsx +4 -4
  41. package/dist/assets/components/sidebar.tsx +10 -10
  42. package/dist/assets/components/skeleton.tsx +13 -5
  43. package/dist/assets/components/slider.tsx +12 -10
  44. package/dist/assets/components/switch.tsx +4 -4
  45. package/dist/assets/components/table.tsx +5 -5
  46. package/dist/assets/components/tabs.tsx +8 -8
  47. package/dist/assets/components/textarea.tsx +11 -9
  48. package/dist/assets/components/toast.tsx +7 -7
  49. package/dist/assets/components/toggle.tsx +27 -7
  50. package/dist/assets/components/tooltip.tsx +10 -8
  51. package/dist/assets/components/user.tsx +8 -6
  52. package/dist/assets/dev-tools/SonanceDevTools.tsx +429 -362
  53. package/dist/assets/dev-tools/components/ApplyFirstPreview.tsx +10 -10
  54. package/dist/assets/dev-tools/components/ChatHistory.tsx +11 -7
  55. package/dist/assets/dev-tools/components/ChatInterface.tsx +61 -20
  56. package/dist/assets/dev-tools/components/ChatTabBar.tsx +1 -1
  57. package/dist/assets/dev-tools/components/DiffPreview.tsx +1 -1
  58. package/dist/assets/dev-tools/components/InlineDiffPreview.tsx +360 -36
  59. package/dist/assets/dev-tools/components/InspectorOverlay.tsx +9 -9
  60. package/dist/assets/dev-tools/components/PropertiesPanel.tsx +743 -93
  61. package/dist/assets/dev-tools/components/ScreenshotAnnotator.tsx +1 -1
  62. package/dist/assets/dev-tools/components/SectionHighlight.tsx +1 -1
  63. package/dist/assets/dev-tools/components/VisionDiffPreview.tsx +7 -7
  64. package/dist/assets/dev-tools/components/VisionModeBorder.tsx +4 -64
  65. package/dist/assets/dev-tools/hooks/index.ts +69 -0
  66. package/dist/assets/dev-tools/hooks/useComponentDetection.ts +132 -0
  67. package/dist/assets/dev-tools/hooks/useComputedStyles.ts +171 -65
  68. package/dist/assets/dev-tools/hooks/useContentHash.ts +212 -0
  69. package/dist/assets/dev-tools/hooks/useElementScanner.ts +398 -0
  70. package/dist/assets/dev-tools/hooks/useImageDetection.ts +162 -0
  71. package/dist/assets/dev-tools/hooks/useTextDetection.ts +217 -0
  72. package/dist/assets/dev-tools/panels/ComponentsPanel.tsx +160 -57
  73. package/dist/assets/dev-tools/panels/TextPanel.tsx +10 -10
  74. package/dist/assets/dev-tools/types.ts +42 -0
  75. package/dist/assets/globals.css +225 -9
  76. package/dist/assets/styles/brand-overrides.css +3 -2
  77. package/dist/assets/utils.ts +2 -1
  78. package/dist/index.js +32 -1
  79. package/package.json +1 -1
@@ -0,0 +1,730 @@
1
+ /**
2
+ * Styling System Detection
3
+ *
4
+ * Analyzes a codebase to determine what styling approach is used,
5
+ * enabling the AI to generate appropriate code modifications.
6
+ */
7
+
8
+ import * as fs from "fs";
9
+ import * as path from "path";
10
+
11
+ export type StylingSystem =
12
+ | "tailwind"
13
+ | "css-modules"
14
+ | "styled-components"
15
+ | "emotion"
16
+ | "vanilla-css"
17
+ | "scss"
18
+ | "sass"
19
+ | "less"
20
+ | "inline-styles"
21
+ | "unknown";
22
+
23
+ export type ComponentLibrary =
24
+ | "cva" // class-variance-authority
25
+ | "shadcn"
26
+ | "radix"
27
+ | "chakra"
28
+ | "material-ui"
29
+ | "ant-design"
30
+ | "none";
31
+
32
+ export interface StylingAnalysis {
33
+ primarySystem: StylingSystem;
34
+ secondarySystems: StylingSystem[];
35
+ componentLibraries: ComponentLibrary[];
36
+ hasClassMerging: boolean; // e.g., tailwind-merge, clsx
37
+ hasCSSVariables: boolean;
38
+ hasDesignTokens: boolean;
39
+ confidence: number; // 0-1
40
+ evidence: {
41
+ files: string[];
42
+ patterns: string[];
43
+ };
44
+ }
45
+
46
+ interface DetectionRule {
47
+ system: StylingSystem | ComponentLibrary;
48
+ type: "styling" | "component";
49
+ // Package.json dependencies to check
50
+ dependencies?: string[];
51
+ // File patterns to look for
52
+ filePatterns?: RegExp[];
53
+ // Code patterns to detect in files
54
+ codePatterns?: RegExp[];
55
+ // Config files that indicate this system
56
+ configFiles?: string[];
57
+ weight: number; // Higher = more definitive
58
+ }
59
+
60
+ const DETECTION_RULES: DetectionRule[] = [
61
+ // Tailwind CSS
62
+ {
63
+ system: "tailwind",
64
+ type: "styling",
65
+ dependencies: ["tailwindcss"],
66
+ configFiles: ["tailwind.config.js", "tailwind.config.ts", "tailwind.config.mjs"],
67
+ codePatterns: [
68
+ /className\s*=\s*["'`][^"'`]*(?:flex|grid|p-\d|m-\d|text-|bg-|border-|rounded)/,
69
+ /\bclass(?:Name)?\s*[:=]\s*["'`](?:[a-z]+-)+[a-z]+/,
70
+ ],
71
+ weight: 10,
72
+ },
73
+
74
+ // CSS Modules
75
+ {
76
+ system: "css-modules",
77
+ type: "styling",
78
+ filePatterns: [/\.module\.css$/, /\.module\.scss$/, /\.module\.sass$/],
79
+ codePatterns: [
80
+ /import\s+(?:styles|css|s)\s+from\s+["'][^"']+\.module\.(css|scss|sass)["']/,
81
+ /className\s*=\s*\{?\s*styles\./,
82
+ ],
83
+ weight: 9,
84
+ },
85
+
86
+ // styled-components
87
+ {
88
+ system: "styled-components",
89
+ type: "styling",
90
+ dependencies: ["styled-components"],
91
+ codePatterns: [
92
+ /import\s+styled\s+from\s+["']styled-components["']/,
93
+ /styled\.[a-z]+`/,
94
+ /styled\([A-Z][a-zA-Z]*\)`/,
95
+ ],
96
+ weight: 10,
97
+ },
98
+
99
+ // Emotion
100
+ {
101
+ system: "emotion",
102
+ type: "styling",
103
+ dependencies: ["@emotion/react", "@emotion/styled", "@emotion/css"],
104
+ codePatterns: [
105
+ /import\s+.*from\s+["']@emotion\/(react|styled|css)["']/,
106
+ /css\s*`/,
107
+ /styled\.[a-z]+`/,
108
+ ],
109
+ weight: 10,
110
+ },
111
+
112
+ // SCSS/Sass
113
+ {
114
+ system: "scss",
115
+ type: "styling",
116
+ dependencies: ["sass", "node-sass"],
117
+ filePatterns: [/\.scss$/],
118
+ codePatterns: [/import\s+["'][^"']+\.scss["']/],
119
+ weight: 7,
120
+ },
121
+
122
+ // Less
123
+ {
124
+ system: "less",
125
+ type: "styling",
126
+ dependencies: ["less"],
127
+ filePatterns: [/\.less$/],
128
+ codePatterns: [/import\s+["'][^"']+\.less["']/],
129
+ weight: 7,
130
+ },
131
+
132
+ // CVA (class-variance-authority)
133
+ {
134
+ system: "cva",
135
+ type: "component",
136
+ dependencies: ["class-variance-authority"],
137
+ codePatterns: [
138
+ /import\s+.*\bcva\b.*from\s+["']class-variance-authority["']/,
139
+ /\bcva\s*\(/,
140
+ ],
141
+ weight: 8,
142
+ },
143
+
144
+ // shadcn/ui
145
+ {
146
+ system: "shadcn",
147
+ type: "component",
148
+ configFiles: ["components.json"],
149
+ filePatterns: [/components\/ui\//],
150
+ codePatterns: [
151
+ /@\/components\/ui\//,
152
+ /from\s+["']@\/components\/ui\//,
153
+ ],
154
+ weight: 8,
155
+ },
156
+
157
+ // Radix UI
158
+ {
159
+ system: "radix",
160
+ type: "component",
161
+ dependencies: ["@radix-ui/react-dialog", "@radix-ui/react-dropdown-menu", "@radix-ui/react-popover"],
162
+ codePatterns: [/import\s+.*from\s+["']@radix-ui\//],
163
+ weight: 7,
164
+ },
165
+
166
+ // Chakra UI
167
+ {
168
+ system: "chakra",
169
+ type: "component",
170
+ dependencies: ["@chakra-ui/react"],
171
+ codePatterns: [/import\s+.*from\s+["']@chakra-ui\//],
172
+ weight: 9,
173
+ },
174
+
175
+ // Material UI
176
+ {
177
+ system: "material-ui",
178
+ type: "component",
179
+ dependencies: ["@mui/material", "@material-ui/core"],
180
+ codePatterns: [
181
+ /import\s+.*from\s+["']@mui\//,
182
+ /import\s+.*from\s+["']@material-ui\//,
183
+ ],
184
+ weight: 9,
185
+ },
186
+
187
+ // Ant Design
188
+ {
189
+ system: "ant-design",
190
+ type: "component",
191
+ dependencies: ["antd"],
192
+ codePatterns: [/import\s+.*from\s+["']antd["']/],
193
+ weight: 9,
194
+ },
195
+ ];
196
+
197
+ // Patterns that indicate class merging utilities
198
+ const CLASS_MERGING_PATTERNS = [
199
+ /import\s+.*\btwMerge\b.*from\s+["']tailwind-merge["']/,
200
+ /import\s+.*\bclsx\b.*from\s+["']clsx["']/,
201
+ /import\s+.*\bclassnames\b.*from\s+["']classnames["']/,
202
+ /import\s+.*\bcn\b.*from/,
203
+ /export\s+function\s+cn\s*\(/,
204
+ ];
205
+
206
+ // Patterns that indicate CSS variables / design tokens
207
+ const CSS_VARIABLES_PATTERNS = [
208
+ /--[a-z][a-z0-9-]*\s*:/,
209
+ /var\s*\(\s*--[a-z]/,
210
+ ];
211
+
212
+ const DESIGN_TOKENS_PATTERNS = [
213
+ /tokens?\.(colors?|spacing|typography)/i,
214
+ /theme\.(colors?|spacing|typography)/i,
215
+ /"tokens"\s*:/,
216
+ ];
217
+
218
+ /**
219
+ * Analyze a codebase to detect the styling system(s) in use
220
+ */
221
+ export async function detectStylingSystem(projectRoot: string): Promise<StylingAnalysis> {
222
+ const result: StylingAnalysis = {
223
+ primarySystem: "unknown",
224
+ secondarySystems: [],
225
+ componentLibraries: [],
226
+ hasClassMerging: false,
227
+ hasCSSVariables: false,
228
+ hasDesignTokens: false,
229
+ confidence: 0,
230
+ evidence: {
231
+ files: [],
232
+ patterns: [],
233
+ },
234
+ };
235
+
236
+ // Track scores for each system
237
+ const systemScores: Record<string, number> = {};
238
+ const componentScores: Record<string, number> = {};
239
+
240
+ // 1. Check package.json
241
+ const packageJsonPath = path.join(projectRoot, "package.json");
242
+ let packageJson: { dependencies?: Record<string, string>; devDependencies?: Record<string, string> } = {};
243
+
244
+ if (fs.existsSync(packageJsonPath)) {
245
+ try {
246
+ packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
247
+ const allDeps = {
248
+ ...packageJson.dependencies,
249
+ ...packageJson.devDependencies,
250
+ };
251
+
252
+ for (const rule of DETECTION_RULES) {
253
+ if (rule.dependencies) {
254
+ for (const dep of rule.dependencies) {
255
+ if (allDeps[dep]) {
256
+ const scoreMap = rule.type === "styling" ? systemScores : componentScores;
257
+ scoreMap[rule.system] = (scoreMap[rule.system] || 0) + rule.weight;
258
+ result.evidence.patterns.push(`package.json: ${dep}`);
259
+ }
260
+ }
261
+ }
262
+ }
263
+
264
+ // Check for class merging utilities
265
+ if (allDeps["tailwind-merge"] || allDeps["clsx"] || allDeps["classnames"]) {
266
+ result.hasClassMerging = true;
267
+ result.evidence.patterns.push("Class merging utility detected");
268
+ }
269
+ } catch {
270
+ // Ignore JSON parse errors
271
+ }
272
+ }
273
+
274
+ // 2. Check for config files
275
+ for (const rule of DETECTION_RULES) {
276
+ if (rule.configFiles) {
277
+ for (const configFile of rule.configFiles) {
278
+ const configPath = path.join(projectRoot, configFile);
279
+ if (fs.existsSync(configPath)) {
280
+ const scoreMap = rule.type === "styling" ? systemScores : componentScores;
281
+ scoreMap[rule.system] = (scoreMap[rule.system] || 0) + rule.weight;
282
+ result.evidence.files.push(configFile);
283
+ }
284
+ }
285
+ }
286
+ }
287
+
288
+ // 3. Scan source files for patterns
289
+ const srcDir = path.join(projectRoot, "src");
290
+ if (fs.existsSync(srcDir)) {
291
+ const filesToScan = findFilesRecursive(srcDir, /\.(tsx?|jsx?|css|scss|sass|less)$/, 100);
292
+
293
+ for (const filePath of filesToScan) {
294
+ try {
295
+ const content = fs.readFileSync(filePath, "utf-8");
296
+ const relativePath = path.relative(projectRoot, filePath);
297
+
298
+ // Check code patterns
299
+ for (const rule of DETECTION_RULES) {
300
+ // Check file pattern matches
301
+ if (rule.filePatterns) {
302
+ for (const pattern of rule.filePatterns) {
303
+ if (pattern.test(filePath)) {
304
+ const scoreMap = rule.type === "styling" ? systemScores : componentScores;
305
+ scoreMap[rule.system] = (scoreMap[rule.system] || 0) + (rule.weight / 2);
306
+ if (!result.evidence.files.includes(relativePath)) {
307
+ result.evidence.files.push(relativePath);
308
+ }
309
+ }
310
+ }
311
+ }
312
+
313
+ // Check code patterns
314
+ if (rule.codePatterns) {
315
+ for (const pattern of rule.codePatterns) {
316
+ if (pattern.test(content)) {
317
+ const scoreMap = rule.type === "styling" ? systemScores : componentScores;
318
+ scoreMap[rule.system] = (scoreMap[rule.system] || 0) + (rule.weight / 3);
319
+ }
320
+ }
321
+ }
322
+ }
323
+
324
+ // Check for CSS variables
325
+ for (const pattern of CSS_VARIABLES_PATTERNS) {
326
+ if (pattern.test(content)) {
327
+ result.hasCSSVariables = true;
328
+ break;
329
+ }
330
+ }
331
+
332
+ // Check for design tokens
333
+ for (const pattern of DESIGN_TOKENS_PATTERNS) {
334
+ if (pattern.test(content)) {
335
+ result.hasDesignTokens = true;
336
+ break;
337
+ }
338
+ }
339
+
340
+ // Check for class merging
341
+ if (!result.hasClassMerging) {
342
+ for (const pattern of CLASS_MERGING_PATTERNS) {
343
+ if (pattern.test(content)) {
344
+ result.hasClassMerging = true;
345
+ result.evidence.patterns.push(`Class merging in ${relativePath}`);
346
+ break;
347
+ }
348
+ }
349
+ }
350
+ } catch {
351
+ // Ignore file read errors
352
+ }
353
+ }
354
+ }
355
+
356
+ // 4. Determine primary and secondary systems
357
+ const sortedSystems = Object.entries(systemScores)
358
+ .sort(([, a], [, b]) => b - a)
359
+ .map(([system]) => system as StylingSystem);
360
+
361
+ if (sortedSystems.length > 0) {
362
+ result.primarySystem = sortedSystems[0];
363
+ result.secondarySystems = sortedSystems.slice(1);
364
+
365
+ // Calculate confidence based on score difference
366
+ const topScore = systemScores[sortedSystems[0]] || 0;
367
+ const secondScore = sortedSystems[1] ? systemScores[sortedSystems[1]] || 0 : 0;
368
+ result.confidence = Math.min(1, topScore / 30 + (topScore - secondScore) / 20);
369
+ }
370
+
371
+ // Add component libraries
372
+ result.componentLibraries = Object.entries(componentScores)
373
+ .filter(([, score]) => score > 5)
374
+ .sort(([, a], [, b]) => b - a)
375
+ .map(([lib]) => lib as ComponentLibrary);
376
+
377
+ return result;
378
+ }
379
+
380
+ /**
381
+ * Generate styling-specific AI guidance based on detected system
382
+ */
383
+ export function generateStylingGuidance(analysis: StylingAnalysis): string {
384
+ const sections: string[] = [];
385
+
386
+ sections.push(`
387
+ ═══════════════════════════════════════════════════════════════════════════════
388
+ DETECTED STYLING SYSTEM: ${analysis.primarySystem.toUpperCase()}
389
+ Confidence: ${Math.round(analysis.confidence * 100)}%
390
+ ${analysis.secondarySystems.length > 0 ? `Also uses: ${analysis.secondarySystems.join(", ")}` : ""}
391
+ ${analysis.componentLibraries.length > 0 ? `Component libraries: ${analysis.componentLibraries.join(", ")}` : ""}
392
+ ═══════════════════════════════════════════════════════════════════════════════`);
393
+
394
+ // System-specific guidance
395
+ switch (analysis.primarySystem) {
396
+ case "tailwind":
397
+ sections.push(generateTailwindGuidance(analysis));
398
+ break;
399
+ case "css-modules":
400
+ sections.push(generateCSSModulesGuidance());
401
+ break;
402
+ case "styled-components":
403
+ case "emotion":
404
+ sections.push(generateCSSInJSGuidance(analysis.primarySystem));
405
+ break;
406
+ case "scss":
407
+ case "sass":
408
+ case "less":
409
+ sections.push(generatePreprocessorGuidance(analysis.primarySystem));
410
+ break;
411
+ case "vanilla-css":
412
+ sections.push(generateVanillaCSSGuidance());
413
+ break;
414
+ default:
415
+ sections.push(generateGenericGuidance());
416
+ }
417
+
418
+ // Component library specific guidance
419
+ for (const lib of analysis.componentLibraries) {
420
+ sections.push(generateComponentLibraryGuidance(lib, analysis));
421
+ }
422
+
423
+ return sections.join("\n\n");
424
+ }
425
+
426
+ function generateTailwindGuidance(analysis: StylingAnalysis): string {
427
+ let guidance = `
428
+ TAILWIND CSS MODIFICATION RULES:
429
+
430
+ 1. MODIFYING STYLES:
431
+ - Add/change utility classes in className prop
432
+ - Example: className="bg-blue-500" → className="bg-green-500"
433
+
434
+ 2. SPACING: Use Tailwind spacing scale
435
+ - Padding: p-{0-96}, px-{}, py-{}, pt-{}, etc.
436
+ - Margin: m-{0-96}, mx-{}, my-{}, mt-{}, etc.
437
+ - Gap: gap-{0-96}
438
+
439
+ 3. COLORS: Use theme colors or arbitrary values
440
+ - Theme: bg-primary, text-foreground, border-border
441
+ - Arbitrary: bg-[#FF5733], text-[rgb(255,87,51)]
442
+
443
+ 4. LAYOUT:
444
+ - Flexbox: flex, items-center, justify-between, flex-col
445
+ - Grid: grid, grid-cols-{1-12}, gap-{n}
446
+
447
+ 5. SIZING:
448
+ - Width: w-{size}, w-full, w-screen, w-[200px]
449
+ - Height: h-{size}, h-full, h-screen, h-[200px]
450
+ - Border radius: rounded-{none|sm|md|lg|xl|2xl|full}`;
451
+
452
+ if (analysis.hasClassMerging) {
453
+ guidance += `
454
+
455
+ 6. CLASS MERGING ENABLED:
456
+ - This codebase uses a class merging utility (cn/clsx/twMerge)
457
+ - Later classes WILL override earlier conflicting classes
458
+ - Safe to add override classes: className="rounded-none" will override component defaults`;
459
+ }
460
+
461
+ if (analysis.hasCSSVariables) {
462
+ guidance += `
463
+
464
+ 7. CSS VARIABLES AVAILABLE:
465
+ - Use semantic color variables when available
466
+ - Prefer var(--primary) over hardcoded colors
467
+ - Check globals.css or theme files for available variables`;
468
+ }
469
+
470
+ return guidance;
471
+ }
472
+
473
+ function generateCSSModulesGuidance(): string {
474
+ return `
475
+ CSS MODULES MODIFICATION RULES:
476
+
477
+ 1. STYLE CHANGES REQUIRE EDITING .module.css FILES:
478
+ - Find the imported CSS module (e.g., styles from './Component.module.css')
479
+ - Modify the CSS class definitions in that file
480
+
481
+ 2. TO ADD NEW STYLES:
482
+ - Add new class to the .module.css file
483
+ - Reference in component: className={styles.newClassName}
484
+
485
+ 3. TO MODIFY EXISTING STYLES:
486
+ - Locate the class in the .module.css file
487
+ - Update the CSS properties there
488
+
489
+ 4. COMPOSING STYLES:
490
+ - Use composes: existingClass; to extend styles
491
+ - Or combine: className={\`\${styles.base} \${styles.modifier}\`}
492
+
493
+ 5. STRUCTURAL VS DESIGN CHANGES:
494
+ - Design changes: Edit the .module.css file
495
+ - Structural changes: Edit the component JSX
496
+
497
+ EXAMPLE:
498
+ User asks: "make the card blue"
499
+ 1. Find: import styles from './Card.module.css'
500
+ 2. Edit Card.module.css: .card { background-color: blue; }
501
+ NOT: Add inline styles or className strings`;
502
+ }
503
+
504
+ function generateCSSInJSGuidance(system: "styled-components" | "emotion"): string {
505
+ const importPath = system === "styled-components" ? "styled-components" : "@emotion/styled";
506
+
507
+ return `
508
+ ${system.toUpperCase()} MODIFICATION RULES:
509
+
510
+ 1. MODIFYING STYLED COMPONENTS:
511
+ - Find the styled.div\` ... \` or styled(Component)\` ... \` definition
512
+ - Modify the CSS inside the template literal
513
+
514
+ 2. EXAMPLE:
515
+ const Card = styled.div\`
516
+ background: blue; // Change this value
517
+ padding: 16px;
518
+ \`;
519
+
520
+ 3. DYNAMIC STYLES (props-based):
521
+ const Button = styled.button\`
522
+ background: \${props => props.primary ? 'blue' : 'gray'};
523
+ \`;
524
+ // Pass props: <Button primary />
525
+
526
+ 4. EXTENDING STYLES:
527
+ const BlueCard = styled(Card)\`
528
+ background: blue;
529
+ \`;
530
+
531
+ 5. TO CHANGE COMPONENT INSTANCES:
532
+ - Prefer extending with styled() over inline overrides
533
+ - Or use the css prop: <Card css={{ background: 'blue' }} />
534
+
535
+ DESIGN CHANGES: Edit the styled\` \` template
536
+ STRUCTURAL CHANGES: Edit the JSX structure`;
537
+ }
538
+
539
+ function generatePreprocessorGuidance(system: "scss" | "sass" | "less"): string {
540
+ const extension = system === "less" ? "less" : system;
541
+
542
+ return `
543
+ ${system.toUpperCase()} MODIFICATION RULES:
544
+
545
+ 1. STYLE CHANGES GO IN .${extension} FILES:
546
+ - Find the imported stylesheet
547
+ - Modify CSS/SCSS rules there
548
+
549
+ 2. USING VARIABLES:
550
+ - SCSS/Sass: $variable-name
551
+ - Less: @variable-name
552
+ - Modify variable definitions for global changes
553
+
554
+ 3. NESTING:
555
+ - Styles are often nested under parent selectors
556
+ - Follow the nesting to find the right rule
557
+
558
+ 4. MIXINS:
559
+ - Look for @mixin/@include (SCSS) or .mixin() (Less)
560
+ - Modify mixin definitions for reusable style changes
561
+
562
+ 5. APPROACH:
563
+ - Design changes: Edit .${extension} files
564
+ - Structural changes: Edit component files
565
+ - Use variables for theme-wide changes`;
566
+ }
567
+
568
+ function generateVanillaCSSGuidance(): string {
569
+ return `
570
+ VANILLA CSS MODIFICATION RULES:
571
+
572
+ 1. FIND THE CSS FILE:
573
+ - Check for imported .css files
574
+ - Or look for <link> tags in HTML/layout files
575
+
576
+ 2. CSS SPECIFICITY MATTERS:
577
+ - More specific selectors override less specific ones
578
+ - ID > Class > Element
579
+ - Later rules override earlier ones (same specificity)
580
+
581
+ 3. TO CHANGE STYLES:
582
+ - Locate the selector in the CSS file
583
+ - Modify the properties
584
+ - Consider specificity when adding new rules
585
+
586
+ 4. FOR ONE-OFF CHANGES:
587
+ - Add inline styles: style={{ backgroundColor: 'blue' }}
588
+ - Or add a more specific class selector
589
+
590
+ 5. STRUCTURAL VS DESIGN:
591
+ - Design: Edit CSS files
592
+ - Structural: Edit JSX/HTML`;
593
+ }
594
+
595
+ function generateGenericGuidance(): string {
596
+ return `
597
+ STYLING APPROACH NOT DEFINITIVELY DETECTED
598
+
599
+ When modifying styles, consider:
600
+
601
+ 1. CHECK FOR:
602
+ - className props (utility classes or CSS class references)
603
+ - style={{ }} inline styles
604
+ - styled-components or CSS-in-JS
605
+ - External CSS file imports
606
+
607
+ 2. FOLLOW THE PATTERN:
608
+ - Look at how existing styles are applied
609
+ - Match the same approach for consistency
610
+
611
+ 3. COMMON PATTERNS:
612
+ - className="..." → Add/modify class names
613
+ - style={{...}} → Modify inline style object
614
+ - styled.div\`\` → Edit template literal CSS
615
+ - import './styles.css' → Edit the CSS file`;
616
+ }
617
+
618
+ function generateComponentLibraryGuidance(library: ComponentLibrary, analysis: StylingAnalysis): string {
619
+ switch (library) {
620
+ case "cva":
621
+ return `
622
+ CVA (class-variance-authority) DETECTED:
623
+
624
+ Components use variants for predefined styles:
625
+ - size="sm" | "md" | "lg"
626
+ - variant="default" | "destructive" | "outline"
627
+
628
+ TO MODIFY:
629
+ 1. Use variant props when available
630
+ 2. Override with className (${analysis.hasClassMerging ? "class merging is enabled" : "may need careful ordering"})
631
+ 3. Edit the cva() definition for permanent changes
632
+
633
+ Example:
634
+ <Button variant="destructive" size="lg"> // Use props
635
+ <Button className="rounded-full"> // Override`;
636
+
637
+ case "shadcn":
638
+ return `
639
+ SHADCN/UI DETECTED:
640
+
641
+ Components are in src/components/ui/ and can be modified directly.
642
+ They typically use:
643
+ - CVA for variants
644
+ - Tailwind for styling
645
+ - Radix primitives for behavior
646
+
647
+ TO MODIFY:
648
+ 1. Use component props (variant, size, etc.)
649
+ 2. Pass className for overrides
650
+ 3. Edit the component file for permanent changes`;
651
+
652
+ case "chakra":
653
+ return `
654
+ CHAKRA UI DETECTED:
655
+
656
+ Use Chakra's style props directly on components:
657
+ <Box bg="blue.500" p={4} borderRadius="lg">
658
+ <Button colorScheme="blue" size="lg">
659
+
660
+ TO MODIFY:
661
+ 1. Use style props: bg, color, p, m, w, h, etc.
662
+ 2. Use theme tokens: "blue.500", "gray.100"
663
+ 3. Use sx prop for custom CSS: sx={{ '&:hover': { bg: 'blue.600' } }}`;
664
+
665
+ case "material-ui":
666
+ return `
667
+ MATERIAL UI DETECTED:
668
+
669
+ Use MUI's sx prop or styled() API:
670
+ <Box sx={{ bgcolor: 'primary.main', p: 2 }}>
671
+ <Button variant="contained" color="primary">
672
+
673
+ TO MODIFY:
674
+ 1. Use sx prop for one-off styles
675
+ 2. Use theme tokens: 'primary.main', 'grey.100'
676
+ 3. Use styled() API for reusable styled components`;
677
+
678
+ case "ant-design":
679
+ return `
680
+ ANT DESIGN DETECTED:
681
+
682
+ Components use props for variants:
683
+ <Button type="primary" size="large">
684
+ <Card bordered={false}>
685
+
686
+ TO MODIFY:
687
+ 1. Use component props (type, size, etc.)
688
+ 2. Use style prop for custom inline styles
689
+ 3. Use className for CSS class overrides
690
+ 4. Modify theme variables for global changes`;
691
+
692
+ default:
693
+ return "";
694
+ }
695
+ }
696
+
697
+ /**
698
+ * Helper to recursively find files
699
+ */
700
+ function findFilesRecursive(dir: string, pattern: RegExp, maxFiles: number): string[] {
701
+ const files: string[] = [];
702
+
703
+ function walk(currentDir: string) {
704
+ if (files.length >= maxFiles) return;
705
+
706
+ try {
707
+ const entries = fs.readdirSync(currentDir, { withFileTypes: true });
708
+
709
+ for (const entry of entries) {
710
+ if (files.length >= maxFiles) break;
711
+
712
+ const fullPath = path.join(currentDir, entry.name);
713
+
714
+ // Skip node_modules, .git, dist, build, etc.
715
+ if (entry.isDirectory()) {
716
+ if (!["node_modules", ".git", "dist", "build", ".next", "coverage"].includes(entry.name)) {
717
+ walk(fullPath);
718
+ }
719
+ } else if (entry.isFile() && pattern.test(entry.name)) {
720
+ files.push(fullPath);
721
+ }
722
+ }
723
+ } catch {
724
+ // Ignore permission errors
725
+ }
726
+ }
727
+
728
+ walk(dir);
729
+ return files;
730
+ }