@tpitre/story-ui 4.6.2 → 4.7.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/dist/story-generator/enhancedComponentDiscovery.d.ts +6 -1
- package/dist/story-generator/enhancedComponentDiscovery.d.ts.map +1 -1
- package/dist/story-generator/enhancedComponentDiscovery.js +62 -13
- package/dist/story-generator/framework-adapters/angular-adapter.d.ts +9 -0
- package/dist/story-generator/framework-adapters/angular-adapter.d.ts.map +1 -1
- package/dist/story-generator/framework-adapters/angular-adapter.js +54 -0
- package/dist/story-generator/framework-adapters/base-adapter.d.ts +11 -1
- package/dist/story-generator/framework-adapters/base-adapter.d.ts.map +1 -1
- package/dist/story-generator/framework-adapters/base-adapter.js +44 -5
- package/dist/story-generator/framework-adapters/index.d.ts.map +1 -1
- package/dist/story-generator/framework-adapters/index.js +5 -1
- package/dist/story-generator/framework-adapters/react-adapter.d.ts +9 -0
- package/dist/story-generator/framework-adapters/react-adapter.d.ts.map +1 -1
- package/dist/story-generator/framework-adapters/react-adapter.js +46 -0
- package/dist/story-generator/framework-adapters/svelte-adapter.d.ts +9 -0
- package/dist/story-generator/framework-adapters/svelte-adapter.d.ts.map +1 -1
- package/dist/story-generator/framework-adapters/svelte-adapter.js +58 -0
- package/dist/story-generator/framework-adapters/vue-adapter.d.ts +9 -0
- package/dist/story-generator/framework-adapters/vue-adapter.d.ts.map +1 -1
- package/dist/story-generator/framework-adapters/vue-adapter.js +74 -0
- package/dist/story-generator/framework-adapters/web-components-adapter.d.ts +13 -0
- package/dist/story-generator/framework-adapters/web-components-adapter.d.ts.map +1 -1
- package/dist/story-generator/framework-adapters/web-components-adapter.js +80 -0
- package/dist/story-generator/promptGenerator.d.ts +6 -0
- package/dist/story-generator/promptGenerator.d.ts.map +1 -1
- package/dist/story-generator/promptGenerator.js +41 -4
- package/dist/templates/StoryUI/StoryUIPanel.css +60 -12
- package/package.json +1 -1
- package/templates/StoryUI/StoryUIPanel.css +60 -12
|
@@ -16,7 +16,12 @@ export declare class EnhancedComponentDiscovery {
|
|
|
16
16
|
private config;
|
|
17
17
|
private discoveredComponents;
|
|
18
18
|
private validateAvailableComponents;
|
|
19
|
+
private frameworkAdapter;
|
|
19
20
|
constructor(config: StoryUIConfig);
|
|
21
|
+
/**
|
|
22
|
+
* Create the appropriate framework adapter based on config
|
|
23
|
+
*/
|
|
24
|
+
private createFrameworkAdapter;
|
|
20
25
|
/**
|
|
21
26
|
* Discover components from all available sources
|
|
22
27
|
* Priority: 1. Dynamic Discovery 2. Static Lists 3. Manual Config
|
|
@@ -76,7 +81,7 @@ export declare class EnhancedComponentDiscovery {
|
|
|
76
81
|
/**
|
|
77
82
|
* Extract component name from file
|
|
78
83
|
*/
|
|
79
|
-
private
|
|
84
|
+
private extractComponentNames;
|
|
80
85
|
/**
|
|
81
86
|
* Extract props from file content
|
|
82
87
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enhancedComponentDiscovery.d.ts","sourceRoot":"","sources":["../../story-generator/enhancedComponentDiscovery.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"enhancedComponentDiscovery.d.ts","sourceRoot":"","sources":["../../story-generator/enhancedComponentDiscovery.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAWtD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,KAAK,GAAG,OAAO,GAAG,iBAAiB,GAAG,YAAY,CAAC;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,iBAAkB,SAAQ,mBAAmB;IAC5D,MAAM,EAAE,eAAe,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,qBAAa,0BAA0B;IACrC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,oBAAoB,CAA6C;IACzE,OAAO,CAAC,2BAA2B,CAA0B;IAC7D,OAAO,CAAC,gBAAgB,CAAuB;gBAEnC,MAAM,EAAE,aAAa;IAKjC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAkB9B;;;OAGG;IACG,WAAW,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;IA2CjD;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAyCjC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAWvB;;GAED;IACH,OAAO,CAAC,cAAc;IAmBtB;;OAEG;IACH,OAAO,CAAC,eAAe;IA6GvB;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAI/B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA6B9B;;KAEC;YACW,sBAAsB;IAgGpC;;;OAGG;IACH,OAAO,CAAC,8BAA8B;IAoRtC;;OAEG;YACW,sBAAsB;IA+CpC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAe1B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAmB3B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA6B1B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAmC7B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA0B5B;;OAEG;IACH,OAAO,CAAC,YAAY;IAiBpB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAkC3B;;OAEG;YACW,0BAA0B;IAmCxC;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAcnC;;OAEG;YACW,sBAAsB;IAMpC;;OAEG;IACH,OAAO,CAAC,yBAAyB;IA4CjC;;OAEG;IACG,sBAAsB,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;QAC9D,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAClC,CAAC;IAwCF;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAwC5B;;OAEG;IACH,0BAA0B,IAAI,MAAM,EAAE;CAMvC"}
|
|
@@ -2,11 +2,36 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { DynamicPackageDiscovery } from './dynamicPackageDiscovery.js';
|
|
4
4
|
import { logger } from './logger.js';
|
|
5
|
+
import { ReactAdapter } from './framework-adapters/react-adapter.js';
|
|
6
|
+
import { VueAdapter } from './framework-adapters/vue-adapter.js';
|
|
7
|
+
import { AngularAdapter } from './framework-adapters/angular-adapter.js';
|
|
8
|
+
import { SvelteAdapter } from './framework-adapters/svelte-adapter.js';
|
|
9
|
+
import { WebComponentsAdapter } from './framework-adapters/web-components-adapter.js';
|
|
5
10
|
export class EnhancedComponentDiscovery {
|
|
6
11
|
constructor(config) {
|
|
7
12
|
this.discoveredComponents = new Map();
|
|
8
13
|
this.validateAvailableComponents = new Set();
|
|
9
14
|
this.config = config;
|
|
15
|
+
this.frameworkAdapter = this.createFrameworkAdapter();
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create the appropriate framework adapter based on config
|
|
19
|
+
*/
|
|
20
|
+
createFrameworkAdapter() {
|
|
21
|
+
const framework = (this.config.componentFramework || 'react');
|
|
22
|
+
switch (framework) {
|
|
23
|
+
case 'vue':
|
|
24
|
+
return new VueAdapter();
|
|
25
|
+
case 'angular':
|
|
26
|
+
return new AngularAdapter();
|
|
27
|
+
case 'svelte':
|
|
28
|
+
return new SvelteAdapter();
|
|
29
|
+
case 'web-components':
|
|
30
|
+
return new WebComponentsAdapter();
|
|
31
|
+
case 'react':
|
|
32
|
+
default:
|
|
33
|
+
return new ReactAdapter();
|
|
34
|
+
}
|
|
10
35
|
}
|
|
11
36
|
/**
|
|
12
37
|
* Discover components from all available sources
|
|
@@ -609,15 +634,22 @@ export class EnhancedComponentDiscovery {
|
|
|
609
634
|
if (!fs.existsSync(source.path)) {
|
|
610
635
|
return;
|
|
611
636
|
}
|
|
612
|
-
|
|
637
|
+
// Use adapter's file patterns if source doesn't specify patterns
|
|
638
|
+
const defaultPatterns = this.frameworkAdapter.getComponentFilePatterns()
|
|
639
|
+
.map(p => p.replace('**/', '')); // Convert glob to simpler patterns
|
|
640
|
+
const files = this.findComponentFiles(source.path, source.patterns || defaultPatterns);
|
|
613
641
|
for (const file of files) {
|
|
614
642
|
// Skip story files, test files, and other non-component files
|
|
615
643
|
if (this.isNonComponentFile(file)) {
|
|
616
644
|
continue;
|
|
617
645
|
}
|
|
618
646
|
const content = fs.readFileSync(file, 'utf-8');
|
|
619
|
-
|
|
620
|
-
|
|
647
|
+
// Use framework adapter for component extraction
|
|
648
|
+
const componentNames = this.frameworkAdapter.extractComponentNamesFromFile(file, content);
|
|
649
|
+
for (const componentName of componentNames) {
|
|
650
|
+
if (this.discoveredComponents.has(componentName)) {
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
621
653
|
// Skip Story UI components and other internal components
|
|
622
654
|
if (this.shouldSkipComponent(componentName, content)) {
|
|
623
655
|
continue;
|
|
@@ -701,18 +733,35 @@ export class EnhancedComponentDiscovery {
|
|
|
701
733
|
/**
|
|
702
734
|
* Extract component name from file
|
|
703
735
|
*/
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
736
|
+
extractComponentNames(filePath, content) {
|
|
737
|
+
const names = new Set();
|
|
738
|
+
// 1. Check for inline exports: export function/const/class Name
|
|
739
|
+
const inlineExportRegex = /export\s+(default\s+)?(function|const|class)\s+([A-Z][A-Za-z0-9]*)/g;
|
|
740
|
+
let match;
|
|
741
|
+
while ((match = inlineExportRegex.exec(content)) !== null) {
|
|
742
|
+
names.add(match[3]);
|
|
743
|
+
}
|
|
744
|
+
// 2. Check for grouped exports: export { Name1, Name2 }
|
|
745
|
+
const groupedExportRegex = /export\s*\{\s*([^}]+)\s*\}/g;
|
|
746
|
+
while ((match = groupedExportRegex.exec(content)) !== null) {
|
|
747
|
+
const exports = match[1].split(',');
|
|
748
|
+
for (const exp of exports) {
|
|
749
|
+
// Handle "Name" or "Name as Alias" - we want the original name
|
|
750
|
+
const namePart = exp.trim().split(/\s+as\s+/)[0].trim();
|
|
751
|
+
// Only include PascalCase names (components start with uppercase)
|
|
752
|
+
if (/^[A-Z][A-Za-z0-9]*$/.test(namePart)) {
|
|
753
|
+
names.add(namePart);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
709
756
|
}
|
|
710
|
-
//
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
757
|
+
// 3. Fallback to filename if no exports found
|
|
758
|
+
if (names.size === 0) {
|
|
759
|
+
const fileName = path.basename(filePath, path.extname(filePath));
|
|
760
|
+
if (fileName !== 'index' && /^[A-Z]/.test(fileName)) {
|
|
761
|
+
names.add(fileName);
|
|
762
|
+
}
|
|
714
763
|
}
|
|
715
|
-
return
|
|
764
|
+
return Array.from(names);
|
|
716
765
|
}
|
|
717
766
|
/**
|
|
718
767
|
* Extract props from file content
|
|
@@ -13,6 +13,15 @@ export declare class AngularAdapter extends BaseFrameworkAdapter {
|
|
|
13
13
|
readonly name = "Angular";
|
|
14
14
|
readonly supportedStoryFrameworks: StoryFramework[];
|
|
15
15
|
readonly defaultExtension = ".stories.ts";
|
|
16
|
+
/**
|
|
17
|
+
* Get glob patterns for Angular component files
|
|
18
|
+
*/
|
|
19
|
+
getComponentFilePatterns(): string[];
|
|
20
|
+
/**
|
|
21
|
+
* Extract component names from an Angular source file.
|
|
22
|
+
* Handles @Component decorators and NgModule exports.
|
|
23
|
+
*/
|
|
24
|
+
extractComponentNamesFromFile(filePath: string, content: string): string[];
|
|
16
25
|
generateSystemPrompt(config: StoryUIConfig, options?: StoryGenerationOptions): string;
|
|
17
26
|
generateExamples(config: StoryUIConfig): string;
|
|
18
27
|
generateSampleStory(config: StoryUIConfig, components: DiscoveredComponent[]): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"angular-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/angular-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"angular-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/angular-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,aAAa,EACb,cAAc,EACd,sBAAsB,EACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,qBAAa,cAAe,SAAQ,oBAAoB;IACtD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAa;IACzC,QAAQ,CAAC,IAAI,aAAa;IAC1B,QAAQ,CAAC,wBAAwB,EAAE,cAAc,EAAE,CAGjD;IACF,QAAQ,CAAC,gBAAgB,iBAAiB;IAE1C;;OAEG;IACH,wBAAwB,IAAI,MAAM,EAAE;IAIpC;;;OAGG;IACH,6BAA6B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAmD1E,oBAAoB,CAClB,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM;IAuJT,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IAsL/C,mBAAmB,CACjB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,GAChC,MAAM;IAqDT,gBAAgB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM;IA4B1D;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;OAEG;IACH,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAkBzC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;CA+CrE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,cAAc,CAErD"}
|
|
@@ -16,6 +16,60 @@ export class AngularAdapter extends BaseFrameworkAdapter {
|
|
|
16
16
|
];
|
|
17
17
|
this.defaultExtension = '.stories.ts';
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Get glob patterns for Angular component files
|
|
21
|
+
*/
|
|
22
|
+
getComponentFilePatterns() {
|
|
23
|
+
return ['**/*.component.ts', '**/*.ts'];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Extract component names from an Angular source file.
|
|
27
|
+
* Handles @Component decorators and NgModule exports.
|
|
28
|
+
*/
|
|
29
|
+
extractComponentNamesFromFile(filePath, content) {
|
|
30
|
+
const names = new Set();
|
|
31
|
+
// Pattern 1: @Component decorator with class
|
|
32
|
+
// @Component({ selector: 'app-name' }) export class NameComponent
|
|
33
|
+
const componentRegex = /@Component\s*\(\s*\{[\s\S]*?\}\s*\)\s*export\s+class\s+(\w+)/g;
|
|
34
|
+
let match;
|
|
35
|
+
while ((match = componentRegex.exec(content)) !== null) {
|
|
36
|
+
names.add(match[1]);
|
|
37
|
+
}
|
|
38
|
+
// Pattern 2: NgModule exports array - for barrel files
|
|
39
|
+
const exportsArrayRegex = /exports\s*:\s*\[([\s\S]*?)\]/g;
|
|
40
|
+
while ((match = exportsArrayRegex.exec(content)) !== null) {
|
|
41
|
+
const exportsContent = match[1];
|
|
42
|
+
const componentNames = exportsContent
|
|
43
|
+
.split(',')
|
|
44
|
+
.map(item => item.trim())
|
|
45
|
+
.filter(item => item && !item.startsWith('//') && /^[A-Z]/.test(item));
|
|
46
|
+
componentNames.forEach(name => names.add(name));
|
|
47
|
+
}
|
|
48
|
+
// Pattern 3: Named exports from barrel files
|
|
49
|
+
// export { NameComponent } from './name.component'
|
|
50
|
+
const namedExportRegex = /export\s*\{\s*([^}]+)\s*\}\s*from\s*['"`]([^'"`]+)['"`]/g;
|
|
51
|
+
while ((match = namedExportRegex.exec(content)) !== null) {
|
|
52
|
+
const exports = match[1].split(',');
|
|
53
|
+
for (const exp of exports) {
|
|
54
|
+
const namePart = exp.trim().split(/\s+as\s+/).pop()?.trim() || '';
|
|
55
|
+
if (/^[A-Z][A-Za-z0-9]*(?:Component)?$/.test(namePart)) {
|
|
56
|
+
names.add(namePart);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Pattern 4: export * from './path' - track for further resolution
|
|
61
|
+
// (handled at discovery level, not here)
|
|
62
|
+
// Filter out non-components (services, modules, etc.)
|
|
63
|
+
const filteredNames = Array.from(names).filter(name => {
|
|
64
|
+
// Keep if ends with Component or doesn't end with Service/Module/Directive/Pipe
|
|
65
|
+
return name.endsWith('Component') ||
|
|
66
|
+
(!name.endsWith('Service') &&
|
|
67
|
+
!name.endsWith('Module') &&
|
|
68
|
+
!name.endsWith('Directive') &&
|
|
69
|
+
!name.endsWith('Pipe'));
|
|
70
|
+
});
|
|
71
|
+
return filteredNames;
|
|
72
|
+
}
|
|
19
73
|
generateSystemPrompt(config, options) {
|
|
20
74
|
if (config.systemPrompt) {
|
|
21
75
|
return config.systemPrompt;
|
|
@@ -16,6 +16,16 @@ export declare abstract class BaseFrameworkAdapter implements FrameworkAdapter {
|
|
|
16
16
|
abstract readonly name: string;
|
|
17
17
|
abstract readonly supportedStoryFrameworks: StoryFramework[];
|
|
18
18
|
abstract readonly defaultExtension: string;
|
|
19
|
+
/**
|
|
20
|
+
* Get glob patterns for component files in this framework.
|
|
21
|
+
* Used by component discovery to find relevant files.
|
|
22
|
+
*/
|
|
23
|
+
abstract getComponentFilePatterns(): string[];
|
|
24
|
+
/**
|
|
25
|
+
* Extract component names from a source file.
|
|
26
|
+
* Framework-specific implementation to detect component exports.
|
|
27
|
+
*/
|
|
28
|
+
abstract extractComponentNamesFromFile(filePath: string, content: string): string[];
|
|
19
29
|
/**
|
|
20
30
|
* Generate the system prompt for this framework
|
|
21
31
|
*/
|
|
@@ -69,7 +79,7 @@ export declare abstract class BaseFrameworkAdapter implements FrameworkAdapter {
|
|
|
69
79
|
*/
|
|
70
80
|
protected log(message: string, data?: Record<string, unknown>): void;
|
|
71
81
|
/**
|
|
72
|
-
* Get common story structure rules
|
|
82
|
+
* Get common story structure rules including MANDATORY spacing
|
|
73
83
|
*/
|
|
74
84
|
protected getCommonRules(): string;
|
|
75
85
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/base-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAG/D;;GAEG;AACH,8BAAsB,oBAAqB,YAAW,gBAAgB;IACpE,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,wBAAwB,EAAE,cAAc,EAAE,CAAC;IAC7D,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAE3C;;OAEG;IACH,QAAQ,CAAC,oBAAoB,CAC3B,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM;IAET;;OAEG;IACH,0BAA0B,CACxB,UAAU,EAAE,mBAAmB,EAAE,EACjC,MAAM,EAAE,aAAa,GACpB,MAAM;IAmBT;;OAEG;IACH,SAAS,CAAC,oBAAoB,CAC5B,SAAS,EAAE,mBAAmB,EAC9B,MAAM,EAAE,aAAa,GACpB,MAAM;IAkBT;;OAEG;IACH,SAAS,CAAC,aAAa,CACrB,SAAS,EAAE,mBAAmB,EAC9B,MAAM,EAAE,aAAa,GACpB,MAAM;IAUT;;OAEG;IACH,SAAS,CAAC,wBAAwB,CAChC,UAAU,EAAE,mBAAmB,EAAE,GAChC,MAAM,CAAC,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAcxC;;OAEG;IACH,QAAQ,CAAC,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IAExD;;OAEG;IACH,QAAQ,CAAC,mBAAmB,CAC1B,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,GAChC,MAAM;IAET;;OAEG;IACH,eAAe,CACb,UAAU,EAAE,mBAAmB,EAAE,EACjC,MAAM,EAAE,aAAa,GACpB,MAAM;IAoBT;;;OAGG;IACH,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAmBzC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;IAkBpE;;OAEG;IACH,QAAQ,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM;IAEnE;;OAEG;IACH,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIpE;;OAEG;IACH,SAAS,CAAC,cAAc,IAAI,MAAM;
|
|
1
|
+
{"version":3,"file":"base-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/base-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAG/D;;GAEG;AACH,8BAAsB,oBAAqB,YAAW,gBAAgB;IACpE,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,wBAAwB,EAAE,cAAc,EAAE,CAAC;IAC7D,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAE3C;;;OAGG;IACH,QAAQ,CAAC,wBAAwB,IAAI,MAAM,EAAE;IAE7C;;;OAGG;IACH,QAAQ,CAAC,6BAA6B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAEnF;;OAEG;IACH,QAAQ,CAAC,oBAAoB,CAC3B,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM;IAET;;OAEG;IACH,0BAA0B,CACxB,UAAU,EAAE,mBAAmB,EAAE,EACjC,MAAM,EAAE,aAAa,GACpB,MAAM;IAmBT;;OAEG;IACH,SAAS,CAAC,oBAAoB,CAC5B,SAAS,EAAE,mBAAmB,EAC9B,MAAM,EAAE,aAAa,GACpB,MAAM;IAkBT;;OAEG;IACH,SAAS,CAAC,aAAa,CACrB,SAAS,EAAE,mBAAmB,EAC9B,MAAM,EAAE,aAAa,GACpB,MAAM;IAUT;;OAEG;IACH,SAAS,CAAC,wBAAwB,CAChC,UAAU,EAAE,mBAAmB,EAAE,GAChC,MAAM,CAAC,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAcxC;;OAEG;IACH,QAAQ,CAAC,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IAExD;;OAEG;IACH,QAAQ,CAAC,mBAAmB,CAC1B,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,GAChC,MAAM;IAET;;OAEG;IACH,eAAe,CACb,UAAU,EAAE,mBAAmB,EAAE,EACjC,MAAM,EAAE,aAAa,GACpB,MAAM;IAoBT;;;OAGG;IACH,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAmBzC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;IAkBpE;;OAEG;IACH,QAAQ,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM;IAEnE;;OAEG;IACH,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIpE;;OAEG;IACH,SAAS,CAAC,cAAc,IAAI,MAAM;CA2DnC"}
|
|
@@ -132,7 +132,7 @@ export class BaseFrameworkAdapter {
|
|
|
132
132
|
logger.debug(`[${this.name}Adapter] ${message}`, data);
|
|
133
133
|
}
|
|
134
134
|
/**
|
|
135
|
-
* Get common story structure rules
|
|
135
|
+
* Get common story structure rules including MANDATORY spacing
|
|
136
136
|
*/
|
|
137
137
|
getCommonRules() {
|
|
138
138
|
return `
|
|
@@ -148,10 +148,49 @@ IMAGE RULES:
|
|
|
148
148
|
- Always include alt text for images
|
|
149
149
|
- Example: https://picsum.photos/400/300?random=1
|
|
150
150
|
|
|
151
|
-
SPACING RULES:
|
|
152
|
-
-
|
|
153
|
-
|
|
154
|
-
|
|
151
|
+
MANDATORY SPACING & LAYOUT RULES (NON-NEGOTIABLE):
|
|
152
|
+
** CRITICAL: Every generated component MUST have professional-quality spacing. Components without proper spacing look broken and unprofessional. **
|
|
153
|
+
|
|
154
|
+
1. STORY WRAPPER (REQUIRED for every story):
|
|
155
|
+
- The render function MUST return a wrapper div with padding
|
|
156
|
+
- Pattern: render: () => <div style={{ padding: "24px" }}>...content...</div>
|
|
157
|
+
- This ensures content has breathing room within the Storybook canvas
|
|
158
|
+
|
|
159
|
+
2. FORM FIELD SPACING (CRITICAL):
|
|
160
|
+
- ALWAYS wrap form fields in a container with vertical spacing
|
|
161
|
+
- Use flexbox column with gap: <div style={{ display: "flex", flexDirection: "column", gap: "16px" }}>
|
|
162
|
+
- Or use design system spacing tokens if available
|
|
163
|
+
- MINIMUM 16px gap between form fields
|
|
164
|
+
|
|
165
|
+
3. BUTTON SPACING:
|
|
166
|
+
- Submit/action buttons: 24px margin-top from form fields above
|
|
167
|
+
- Pattern: <div style={{ marginTop: "24px" }}><Button>Submit</Button></div>
|
|
168
|
+
- Button groups should be wrapped with margin-top from content
|
|
169
|
+
|
|
170
|
+
4. SECTION SPACING:
|
|
171
|
+
- Between major sections: 32-48px
|
|
172
|
+
- Between related content groups: 24px
|
|
173
|
+
- Use dividers or significant whitespace between unrelated content
|
|
174
|
+
|
|
175
|
+
5. HEADING SPACING:
|
|
176
|
+
- More space ABOVE headings (24-32px) than below (8-16px)
|
|
177
|
+
- Pattern: <Heading style={{ marginTop: "32px", marginBottom: "12px" }}>
|
|
178
|
+
|
|
179
|
+
6. CARD/CONTAINER PADDING:
|
|
180
|
+
- Internal padding: minimum 16px, preferred 24px
|
|
181
|
+
- Pattern: <Card style={{ padding: "24px" }}>
|
|
182
|
+
|
|
183
|
+
7. SPECIFIC VALUES TO USE:
|
|
184
|
+
- Tight spacing (icons, inline): 4-8px
|
|
185
|
+
- Related items: 8-12px
|
|
186
|
+
- Form fields: 16px gap
|
|
187
|
+
- Buttons from content: 24px margin-top
|
|
188
|
+
- Sections: 32-48px
|
|
189
|
+
- Major divisions: 48-64px
|
|
190
|
+
|
|
191
|
+
SPACING VALIDATION (Self-check before generating):
|
|
192
|
+
Ask yourself: "Does every element have adequate breathing room from its neighbors?"
|
|
193
|
+
If any elements appear cramped or touching, add appropriate spacing.
|
|
155
194
|
`;
|
|
156
195
|
}
|
|
157
196
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,cAAc,YAAY,CAAC;AAG3B,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAGzD,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AAC/F,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAGzE,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAOpB,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,cAAc,YAAY,CAAC;AAG3B,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAGzD,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AAC/F,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAGzE,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAOpB,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAI/D;;;;;GAKG;AACH,cAAM,eAAe;IACnB,OAAO,CAAC,QAAQ,CAAmD;IACnE,OAAO,CAAC,cAAc,CAAmB;IACzC,OAAO,CAAC,iBAAiB,CAAkC;;IAU3D;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAY/B;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAIzC;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,aAAa,GAAG,gBAAgB,GAAG,SAAS;IAItD;;OAEG;IACH,MAAM,IAAI,gBAAgB,EAAE;IAI5B;;OAEG;IACH,iBAAiB,IAAI,aAAa,EAAE;IAIpC;;OAEG;IACH,sBAAsB,IAAI,aAAa,EAAE;IAIzC;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,gBAAgB;IAIjD;;OAEG;IACH,UAAU,IAAI,gBAAgB;IAI9B;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAQrC;;OAEG;IACG,UAAU,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAoBjE;;OAEG;IACH,oBAAoB,IAAI,iBAAiB,GAAG,IAAI;IAIhD;;OAEG;IACG,cAAc,CAClB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,EACjC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,eAAe,CAAC;CAkC5B;AAKD;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,eAAe,CAKpD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,gBAAgB,GAAG,SAAS,CAE5E;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,gBAAgB,CAEpD;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAEvF;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,EACjC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,eAAe,CAAC,CAE1B"}
|
|
@@ -22,6 +22,7 @@ import { AngularAdapter } from './angular-adapter.js';
|
|
|
22
22
|
import { SvelteAdapter } from './svelte-adapter.js';
|
|
23
23
|
import { detectFramework } from './framework-detector.js';
|
|
24
24
|
import { logger } from '../logger.js';
|
|
25
|
+
import { generateLayoutInstructions } from '../promptGenerator.js';
|
|
25
26
|
/**
|
|
26
27
|
* Framework Adapter Registry
|
|
27
28
|
*
|
|
@@ -147,10 +148,13 @@ class AdapterRegistry {
|
|
|
147
148
|
adapter = await this.autoDetect();
|
|
148
149
|
}
|
|
149
150
|
logger.debug('Generating prompt with adapter', { adapter: adapter.type });
|
|
151
|
+
// Generate layout instructions including mandatory spacing rules
|
|
152
|
+
const layoutInstructionsArray = generateLayoutInstructions(config);
|
|
153
|
+
const layoutInstructionsString = layoutInstructionsArray.join('\n');
|
|
150
154
|
return {
|
|
151
155
|
systemPrompt: adapter.generateSystemPrompt(config, options),
|
|
152
156
|
componentReference: adapter.generateComponentReference(components, config),
|
|
153
|
-
layoutInstructions:
|
|
157
|
+
layoutInstructions: layoutInstructionsString,
|
|
154
158
|
examples: adapter.generateExamples(config),
|
|
155
159
|
sampleStory: adapter.generateSampleStory(config, components),
|
|
156
160
|
framework: this.detectedFramework || {
|
|
@@ -13,6 +13,15 @@ export declare class ReactAdapter extends BaseFrameworkAdapter {
|
|
|
13
13
|
readonly name = "React";
|
|
14
14
|
readonly supportedStoryFrameworks: StoryFramework[];
|
|
15
15
|
readonly defaultExtension = ".stories.tsx";
|
|
16
|
+
/**
|
|
17
|
+
* Get glob patterns for React component files
|
|
18
|
+
*/
|
|
19
|
+
getComponentFilePatterns(): string[];
|
|
20
|
+
/**
|
|
21
|
+
* Extract component names from a React source file.
|
|
22
|
+
* Handles both inline exports and grouped exports.
|
|
23
|
+
*/
|
|
24
|
+
extractComponentNamesFromFile(filePath: string, content: string): string[];
|
|
16
25
|
generateSystemPrompt(config: StoryUIConfig, options?: StoryGenerationOptions): string;
|
|
17
26
|
/**
|
|
18
27
|
* FIX #2: Detect if the project uses Chakra UI v3
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/react-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"react-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/react-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,aAAa,EACb,cAAc,EACd,sBAAsB,EACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,qBAAa,YAAa,SAAQ,oBAAoB;IACpD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAW;IACvC,QAAQ,CAAC,IAAI,WAAW;IACxB,QAAQ,CAAC,wBAAwB,EAAE,cAAc,EAAE,CAIjD;IACF,QAAQ,CAAC,gBAAgB,kBAAkB;IAE3C;;OAEG;IACH,wBAAwB,IAAI,MAAM,EAAE;IAIpC;;;OAGG;IACH,6BAA6B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAyC1E,oBAAoB,CAClB,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM;IA+GT;;OAEG;IACH,OAAO,CAAC,iBAAiB;IASzB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IAkE/C,mBAAmB,CACjB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,GAChC,MAAM;IA4CT,gBAAgB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM;IA0B1D;;OAEG;IACH,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IA4BzC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;CA2BrE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,YAAY,CAEjD"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Generates Storybook stories for React components.
|
|
5
5
|
* Supports CSF 3.0 format with TypeScript.
|
|
6
6
|
*/
|
|
7
|
+
import * as path from 'path';
|
|
7
8
|
import { BaseFrameworkAdapter } from './base-adapter.js';
|
|
8
9
|
export class ReactAdapter extends BaseFrameworkAdapter {
|
|
9
10
|
constructor() {
|
|
@@ -17,6 +18,51 @@ export class ReactAdapter extends BaseFrameworkAdapter {
|
|
|
17
18
|
];
|
|
18
19
|
this.defaultExtension = '.stories.tsx';
|
|
19
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Get glob patterns for React component files
|
|
23
|
+
*/
|
|
24
|
+
getComponentFilePatterns() {
|
|
25
|
+
return ['**/*.tsx', '**/*.jsx', '**/*.ts', '**/*.js'];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Extract component names from a React source file.
|
|
29
|
+
* Handles both inline exports and grouped exports.
|
|
30
|
+
*/
|
|
31
|
+
extractComponentNamesFromFile(filePath, content) {
|
|
32
|
+
const names = new Set();
|
|
33
|
+
// 1. Check for inline exports: export function/const/class Name
|
|
34
|
+
const inlineExportRegex = /export\s+(default\s+)?(function|const|class)\s+([A-Z][A-Za-z0-9]*)/g;
|
|
35
|
+
let match;
|
|
36
|
+
while ((match = inlineExportRegex.exec(content)) !== null) {
|
|
37
|
+
names.add(match[3]);
|
|
38
|
+
}
|
|
39
|
+
// 2. Check for grouped exports: export { Name1, Name2 }
|
|
40
|
+
const groupedExportRegex = /export\s*\{\s*([^}]+)\s*\}/g;
|
|
41
|
+
while ((match = groupedExportRegex.exec(content)) !== null) {
|
|
42
|
+
const exports = match[1].split(',');
|
|
43
|
+
for (const exp of exports) {
|
|
44
|
+
// Handle "Name" or "Name as Alias" - we want the original name
|
|
45
|
+
const namePart = exp.trim().split(/\s+as\s+/)[0].trim();
|
|
46
|
+
// Only include PascalCase names (components start with uppercase)
|
|
47
|
+
if (/^[A-Z][A-Za-z0-9]*$/.test(namePart)) {
|
|
48
|
+
names.add(namePart);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// 3. Check for React.forwardRef patterns
|
|
53
|
+
const forwardRefRegex = /export\s+const\s+([A-Z][A-Za-z0-9]*)\s*=\s*(?:React\.)?forwardRef/g;
|
|
54
|
+
while ((match = forwardRefRegex.exec(content)) !== null) {
|
|
55
|
+
names.add(match[1]);
|
|
56
|
+
}
|
|
57
|
+
// 4. Fallback to filename if no exports found
|
|
58
|
+
if (names.size === 0) {
|
|
59
|
+
const fileName = path.basename(filePath, path.extname(filePath));
|
|
60
|
+
if (fileName !== 'index' && /^[A-Z]/.test(fileName)) {
|
|
61
|
+
names.add(fileName);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return Array.from(names);
|
|
65
|
+
}
|
|
20
66
|
generateSystemPrompt(config, options) {
|
|
21
67
|
if (config.systemPrompt) {
|
|
22
68
|
return config.systemPrompt;
|
|
@@ -13,6 +13,15 @@ export declare class SvelteAdapter extends BaseFrameworkAdapter {
|
|
|
13
13
|
readonly name = "Svelte";
|
|
14
14
|
readonly supportedStoryFrameworks: StoryFramework[];
|
|
15
15
|
readonly defaultExtension = ".stories.svelte";
|
|
16
|
+
/**
|
|
17
|
+
* Get glob patterns for Svelte component files
|
|
18
|
+
*/
|
|
19
|
+
getComponentFilePatterns(): string[];
|
|
20
|
+
/**
|
|
21
|
+
* Extract component names from a Svelte source file.
|
|
22
|
+
* Handles .svelte files and barrel exports.
|
|
23
|
+
*/
|
|
24
|
+
extractComponentNamesFromFile(filePath: string, content: string): string[];
|
|
16
25
|
generateSystemPrompt(config: StoryUIConfig, options?: StoryGenerationOptions): string;
|
|
17
26
|
generateExamples(config: StoryUIConfig): string;
|
|
18
27
|
generateSampleStory(config: StoryUIConfig, components: DiscoveredComponent[]): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"svelte-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/svelte-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"svelte-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/svelte-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,aAAa,EACb,cAAc,EACd,sBAAsB,EACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,qBAAa,aAAc,SAAQ,oBAAoB;IACrD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAY;IACxC,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,wBAAwB,EAAE,cAAc,EAAE,CAGjD;IACF,QAAQ,CAAC,gBAAgB,qBAAqB;IAE9C;;OAEG;IACH,wBAAwB,IAAI,MAAM,EAAE;IAIpC;;;OAGG;IACH,6BAA6B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAoD1E,oBAAoB,CAClB,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM;IAgJT,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IA2H/C,mBAAmB,CACjB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,GAChC,MAAM;IAqCT,gBAAgB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM;IAmB1D;;OAEG;IACH,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IA8HzC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;IA2CpE;;OAEG;IACH,eAAe,CACb,UAAU,EAAE,mBAAmB,EAAE,EACjC,MAAM,EAAE,aAAa,GACpB,MAAM;CAWV;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,aAAa,CAEnD"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Generates Storybook stories for Svelte components.
|
|
5
5
|
* Supports both Svelte 4 and Svelte 5 (runes).
|
|
6
6
|
*/
|
|
7
|
+
import * as path from 'path';
|
|
7
8
|
import { BaseFrameworkAdapter } from './base-adapter.js';
|
|
8
9
|
export class SvelteAdapter extends BaseFrameworkAdapter {
|
|
9
10
|
constructor() {
|
|
@@ -16,6 +17,63 @@ export class SvelteAdapter extends BaseFrameworkAdapter {
|
|
|
16
17
|
];
|
|
17
18
|
this.defaultExtension = '.stories.svelte';
|
|
18
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Get glob patterns for Svelte component files
|
|
22
|
+
*/
|
|
23
|
+
getComponentFilePatterns() {
|
|
24
|
+
return ['**/*.svelte', '**/*.ts', '**/*.js'];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Extract component names from a Svelte source file.
|
|
28
|
+
* Handles .svelte files and barrel exports.
|
|
29
|
+
*/
|
|
30
|
+
extractComponentNamesFromFile(filePath, content) {
|
|
31
|
+
const names = new Set();
|
|
32
|
+
// For .svelte files, derive name from filename
|
|
33
|
+
if (filePath.endsWith('.svelte')) {
|
|
34
|
+
const fileName = path.basename(filePath, '.svelte');
|
|
35
|
+
// Skip SvelteKit special files
|
|
36
|
+
if (fileName.startsWith('+')) {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
// If already PascalCase, use as-is; otherwise convert kebab-case/snake_case
|
|
40
|
+
if (/^[A-Z][a-zA-Z0-9]*$/.test(fileName)) {
|
|
41
|
+
names.add(fileName);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// Convert kebab-case or snake_case to PascalCase
|
|
45
|
+
const pascalName = fileName
|
|
46
|
+
.split(/[-_]/)
|
|
47
|
+
.map(part => part.charAt(0).toUpperCase() + part.slice(1))
|
|
48
|
+
.join('');
|
|
49
|
+
if (/^[A-Z]/.test(pascalName)) {
|
|
50
|
+
names.add(pascalName);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return Array.from(names);
|
|
54
|
+
}
|
|
55
|
+
// For .ts/.js barrel files
|
|
56
|
+
// Pattern: export { default as ComponentName } from './Component.svelte'
|
|
57
|
+
const barrelExportRegex = /export\s*\{\s*default\s+as\s+([A-Z][a-zA-Z0-9]*)\s*\}\s*from\s*['"`]([^'"`]+\.svelte)['"`]/g;
|
|
58
|
+
let match;
|
|
59
|
+
while ((match = barrelExportRegex.exec(content)) !== null) {
|
|
60
|
+
names.add(match[1]);
|
|
61
|
+
}
|
|
62
|
+
// Pattern: export { ComponentName } from './path'
|
|
63
|
+
const namedExportRegex = /export\s*\{\s*([^}]+)\s*\}\s*from\s*['"`]([^'"`]+)['"`]/g;
|
|
64
|
+
while ((match = namedExportRegex.exec(content)) !== null) {
|
|
65
|
+
const exports = match[1].split(',');
|
|
66
|
+
for (const exp of exports) {
|
|
67
|
+
const namePart = exp.trim().split(/\s+as\s+/).pop()?.trim() || '';
|
|
68
|
+
if (/^[A-Z][A-Za-z0-9]*$/.test(namePart)) {
|
|
69
|
+
names.add(namePart);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Pattern: export * from './Component.svelte'
|
|
74
|
+
// These need to be resolved at discovery level
|
|
75
|
+
return Array.from(names);
|
|
76
|
+
}
|
|
19
77
|
generateSystemPrompt(config, options) {
|
|
20
78
|
if (config.systemPrompt) {
|
|
21
79
|
return config.systemPrompt;
|
|
@@ -13,6 +13,15 @@ export declare class VueAdapter extends BaseFrameworkAdapter {
|
|
|
13
13
|
readonly name = "Vue";
|
|
14
14
|
readonly supportedStoryFrameworks: StoryFramework[];
|
|
15
15
|
readonly defaultExtension = ".stories.ts";
|
|
16
|
+
/**
|
|
17
|
+
* Get glob patterns for Vue component files
|
|
18
|
+
*/
|
|
19
|
+
getComponentFilePatterns(): string[];
|
|
20
|
+
/**
|
|
21
|
+
* Extract component names from a Vue source file.
|
|
22
|
+
* Handles .vue SFCs and barrel files.
|
|
23
|
+
*/
|
|
24
|
+
extractComponentNamesFromFile(filePath: string, content: string): string[];
|
|
16
25
|
generateSystemPrompt(config: StoryUIConfig, options?: StoryGenerationOptions): string;
|
|
17
26
|
generateExamples(config: StoryUIConfig): string;
|
|
18
27
|
generateSampleStory(config: StoryUIConfig, components: DiscoveredComponent[]): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vue-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/vue-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"vue-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/vue-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,aAAa,EACb,cAAc,EACd,sBAAsB,EACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,qBAAa,UAAW,SAAQ,oBAAoB;IAClD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAS;IACrC,QAAQ,CAAC,IAAI,SAAS;IACtB,QAAQ,CAAC,wBAAwB,EAAE,cAAc,EAAE,CAIjD;IACF,QAAQ,CAAC,gBAAgB,iBAAiB;IAE1C;;OAEG;IACH,wBAAwB,IAAI,MAAM,EAAE;IAIpC;;;OAGG;IACH,6BAA6B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAkE1E,oBAAoB,CAClB,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM;IA+FT,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IAuH/C,mBAAmB,CACjB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,GAChC,MAAM;IA4CT,gBAAgB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM;IAsB1D;;OAEG;IACH,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IA8CzC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;CAuBrE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,UAAU,CAE7C"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Generates Storybook stories for Vue 3 components.
|
|
5
5
|
* Supports Composition API and Options API.
|
|
6
6
|
*/
|
|
7
|
+
import * as path from 'path';
|
|
7
8
|
import { BaseFrameworkAdapter } from './base-adapter.js';
|
|
8
9
|
export class VueAdapter extends BaseFrameworkAdapter {
|
|
9
10
|
constructor() {
|
|
@@ -17,6 +18,79 @@ export class VueAdapter extends BaseFrameworkAdapter {
|
|
|
17
18
|
];
|
|
18
19
|
this.defaultExtension = '.stories.ts';
|
|
19
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Get glob patterns for Vue component files
|
|
23
|
+
*/
|
|
24
|
+
getComponentFilePatterns() {
|
|
25
|
+
return ['**/*.vue', '**/*.ts', '**/*.js'];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Extract component names from a Vue source file.
|
|
29
|
+
* Handles .vue SFCs and barrel files.
|
|
30
|
+
*/
|
|
31
|
+
extractComponentNamesFromFile(filePath, content) {
|
|
32
|
+
const names = new Set();
|
|
33
|
+
// For .vue files, derive name from filename or defineComponent name
|
|
34
|
+
if (filePath.endsWith('.vue')) {
|
|
35
|
+
// Try to extract name from defineComponent({ name: 'ComponentName' })
|
|
36
|
+
const defineComponentNameRegex = /defineComponent\s*\(\s*\{[^]*?name\s*:\s*['"`]([A-Z][a-zA-Z0-9]*)['"`]/;
|
|
37
|
+
const nameMatch = content.match(defineComponentNameRegex);
|
|
38
|
+
if (nameMatch) {
|
|
39
|
+
names.add(nameMatch[1]);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
// Try Options API name property
|
|
43
|
+
const optionsNameRegex = /name\s*:\s*['"`]([A-Z][a-zA-Z0-9]*)['"`]/;
|
|
44
|
+
const optionsMatch = content.match(optionsNameRegex);
|
|
45
|
+
if (optionsMatch) {
|
|
46
|
+
names.add(optionsMatch[1]);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// Fallback to filename
|
|
50
|
+
const fileName = path.basename(filePath, '.vue');
|
|
51
|
+
// If already PascalCase, use as-is; otherwise convert kebab-case/snake_case
|
|
52
|
+
if (/^[A-Z][a-zA-Z0-9]*$/.test(fileName)) {
|
|
53
|
+
names.add(fileName);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
// Convert kebab-case or snake_case to PascalCase
|
|
57
|
+
const pascalName = fileName
|
|
58
|
+
.split(/[-_]/)
|
|
59
|
+
.map(part => part.charAt(0).toUpperCase() + part.slice(1))
|
|
60
|
+
.join('');
|
|
61
|
+
if (/^[A-Z]/.test(pascalName)) {
|
|
62
|
+
names.add(pascalName);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return Array.from(names);
|
|
68
|
+
}
|
|
69
|
+
// For .ts/.js barrel files, look for re-exports
|
|
70
|
+
// Pattern: export { default as ComponentName } from './Component.vue'
|
|
71
|
+
const barrelExportRegex = /export\s*\{\s*default\s+as\s+([A-Z][a-zA-Z0-9]*)\s*\}\s*from\s*['"`]([^'"`]+\.vue)['"`]/g;
|
|
72
|
+
let match;
|
|
73
|
+
while ((match = barrelExportRegex.exec(content)) !== null) {
|
|
74
|
+
names.add(match[1]);
|
|
75
|
+
}
|
|
76
|
+
// Pattern: export { ComponentName } from './path'
|
|
77
|
+
const namedExportRegex = /export\s*\{\s*([^}]+)\s*\}\s*from\s*['"`]([^'"`]+)['"`]/g;
|
|
78
|
+
while ((match = namedExportRegex.exec(content)) !== null) {
|
|
79
|
+
const exports = match[1].split(',');
|
|
80
|
+
for (const exp of exports) {
|
|
81
|
+
const namePart = exp.trim().split(/\s+as\s+/).pop()?.trim() || '';
|
|
82
|
+
if (/^[A-Z][A-Za-z0-9]*$/.test(namePart)) {
|
|
83
|
+
names.add(namePart);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Pattern: export const ComponentName = ...
|
|
88
|
+
const constExportRegex = /export\s+const\s+([A-Z][A-Za-z0-9]*)\s*=/g;
|
|
89
|
+
while ((match = constExportRegex.exec(content)) !== null) {
|
|
90
|
+
names.add(match[1]);
|
|
91
|
+
}
|
|
92
|
+
return Array.from(names);
|
|
93
|
+
}
|
|
20
94
|
generateSystemPrompt(config, options) {
|
|
21
95
|
if (config.systemPrompt) {
|
|
22
96
|
return config.systemPrompt;
|
|
@@ -13,6 +13,19 @@ export declare class WebComponentsAdapter extends BaseFrameworkAdapter {
|
|
|
13
13
|
readonly name = "Web Components";
|
|
14
14
|
readonly supportedStoryFrameworks: StoryFramework[];
|
|
15
15
|
readonly defaultExtension = ".stories.ts";
|
|
16
|
+
/**
|
|
17
|
+
* Get glob patterns for Web Component files
|
|
18
|
+
*/
|
|
19
|
+
getComponentFilePatterns(): string[];
|
|
20
|
+
/**
|
|
21
|
+
* Extract component names from a Web Component source file.
|
|
22
|
+
* Handles vanilla customElements.define, Lit @customElement, and Stencil @Component.
|
|
23
|
+
*/
|
|
24
|
+
extractComponentNamesFromFile(filePath: string, content: string): string[];
|
|
25
|
+
/**
|
|
26
|
+
* Convert a kebab-case tag name to PascalCase
|
|
27
|
+
*/
|
|
28
|
+
private tagToPascalCase;
|
|
16
29
|
generateSystemPrompt(config: StoryUIConfig, options?: StoryGenerationOptions): string;
|
|
17
30
|
generateExamples(config: StoryUIConfig): string;
|
|
18
31
|
generateSampleStory(config: StoryUIConfig, components: DiscoveredComponent[]): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-components-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/web-components-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"web-components-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/web-components-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,aAAa,EACb,cAAc,EACd,sBAAsB,EACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,qBAAa,oBAAqB,SAAQ,oBAAoB;IAC5D,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAoB;IAChD,QAAQ,CAAC,IAAI,oBAAoB;IACjC,QAAQ,CAAC,wBAAwB,EAAE,cAAc,EAAE,CAGjD;IACF,QAAQ,CAAC,gBAAgB,iBAAiB;IAE1C;;OAEG;IACH,wBAAwB,IAAI,MAAM,EAAE;IAIpC;;;OAGG;IACH,6BAA6B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAoE1E;;OAEG;IACH,OAAO,CAAC,eAAe;IAOvB,oBAAoB,CAClB,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM;IA4FT,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IA0G/C,mBAAmB,CACjB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,GAChC,MAAM;IA8CT,gBAAgB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM;IAsB1D;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;OAEG;IACH,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAuCzC;;;;;;;;OAQG;IACH,OAAO,CAAC,yBAAyB;IAiCjC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;IAwBpE;;OAEG;IACH,eAAe,CACb,UAAU,EAAE,mBAAmB,EAAE,EACjC,MAAM,EAAE,aAAa,GACpB,MAAM;CAYV;AAED;;GAEG;AACH,wBAAgB,0BAA0B,IAAI,oBAAoB,CAEjE"}
|
|
@@ -16,6 +16,86 @@ export class WebComponentsAdapter extends BaseFrameworkAdapter {
|
|
|
16
16
|
];
|
|
17
17
|
this.defaultExtension = '.stories.ts';
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Get glob patterns for Web Component files
|
|
21
|
+
*/
|
|
22
|
+
getComponentFilePatterns() {
|
|
23
|
+
return ['**/*.ts', '**/*.js', '**/custom-elements.json'];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Extract component names from a Web Component source file.
|
|
27
|
+
* Handles vanilla customElements.define, Lit @customElement, and Stencil @Component.
|
|
28
|
+
*/
|
|
29
|
+
extractComponentNamesFromFile(filePath, content) {
|
|
30
|
+
const names = new Set();
|
|
31
|
+
// Check for Custom Elements Manifest (preferred)
|
|
32
|
+
if (filePath.endsWith('custom-elements.json')) {
|
|
33
|
+
try {
|
|
34
|
+
const manifest = JSON.parse(content);
|
|
35
|
+
if (manifest.modules) {
|
|
36
|
+
for (const module of manifest.modules) {
|
|
37
|
+
if (module.declarations) {
|
|
38
|
+
for (const declaration of module.declarations) {
|
|
39
|
+
if (declaration.customElement && declaration.tagName) {
|
|
40
|
+
// Convert tag-name to PascalCase
|
|
41
|
+
const pascalName = this.tagToPascalCase(declaration.tagName);
|
|
42
|
+
names.add(pascalName);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return Array.from(names);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Invalid JSON, continue with regex patterns
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Pattern 1: Vanilla customElements.define('tag-name', ClassName) with named class
|
|
55
|
+
const vanillaDefineNamedRegex = /customElements\.define\(\s*['"]([a-z][\w-]*)['"],\s*([A-Z][A-Za-z0-9]*)\s*[),]/g;
|
|
56
|
+
let match;
|
|
57
|
+
while ((match = vanillaDefineNamedRegex.exec(content)) !== null) {
|
|
58
|
+
names.add(match[2]); // Use the class name
|
|
59
|
+
}
|
|
60
|
+
// Pattern 1b: Vanilla customElements.define('tag-name', class extends...) - inline class
|
|
61
|
+
// For inline classes, convert tag name to PascalCase
|
|
62
|
+
const vanillaDefineInlineRegex = /customElements\.define\(\s*['"]([a-z][\w-]*)['"],\s*class\s+extends/gi;
|
|
63
|
+
while ((match = vanillaDefineInlineRegex.exec(content)) !== null) {
|
|
64
|
+
const pascalName = this.tagToPascalCase(match[1]);
|
|
65
|
+
names.add(pascalName);
|
|
66
|
+
}
|
|
67
|
+
// Pattern 2: Lit @customElement('tag-name') decorator (handles multiline)
|
|
68
|
+
const litDecoratorRegex = /@customElement\(\s*['"]([a-z][\w-]*)['"][^)]*\)[\s\S]*?(?:export\s+)?class\s+([A-Z][A-Za-z0-9]*)/g;
|
|
69
|
+
while ((match = litDecoratorRegex.exec(content)) !== null) {
|
|
70
|
+
names.add(match[2]); // Use the class name
|
|
71
|
+
}
|
|
72
|
+
// Pattern 3: Stencil @Component({ tag: 'tag-name' }) decorator
|
|
73
|
+
const stencilRegex = /@Component\(\s*\{[^}]*tag:\s*['"]([a-z][\w-]*)['"][^}]*\}\s*\)\s*(?:export\s+)?class\s+(\w+)/gi;
|
|
74
|
+
while ((match = stencilRegex.exec(content)) !== null) {
|
|
75
|
+
names.add(match[2]); // Use the class name
|
|
76
|
+
}
|
|
77
|
+
// Pattern 4: Named exports from barrel files
|
|
78
|
+
const namedExportRegex = /export\s*\{\s*([^}]+)\s*\}\s*from\s*['"`]([^'"`]+)['"`]/g;
|
|
79
|
+
while ((match = namedExportRegex.exec(content)) !== null) {
|
|
80
|
+
const exports = match[1].split(',');
|
|
81
|
+
for (const exp of exports) {
|
|
82
|
+
const namePart = exp.trim().split(/\s+as\s+/).pop()?.trim() || '';
|
|
83
|
+
if (/^[A-Z][A-Za-z0-9]*$/.test(namePart)) {
|
|
84
|
+
names.add(namePart);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return Array.from(names);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Convert a kebab-case tag name to PascalCase
|
|
92
|
+
*/
|
|
93
|
+
tagToPascalCase(tagName) {
|
|
94
|
+
return tagName
|
|
95
|
+
.split('-')
|
|
96
|
+
.map(part => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
|
|
97
|
+
.join('');
|
|
98
|
+
}
|
|
19
99
|
generateSystemPrompt(config, options) {
|
|
20
100
|
if (config.systemPrompt) {
|
|
21
101
|
return config.systemPrompt;
|
|
@@ -19,6 +19,12 @@ export interface GeneratedPrompt {
|
|
|
19
19
|
* Generates a comprehensive AI prompt based on the configuration and discovered components
|
|
20
20
|
*/
|
|
21
21
|
export declare function generatePrompt(config: StoryUIConfig, components: DiscoveredComponent[]): GeneratedPrompt;
|
|
22
|
+
/**
|
|
23
|
+
* Generates layout-specific instructions including MANDATORY vertical spacing rules
|
|
24
|
+
* @param config - The StoryUI configuration object
|
|
25
|
+
* @returns Array of layout instruction strings to be included in the prompt
|
|
26
|
+
*/
|
|
27
|
+
export declare function generateLayoutInstructions(config: StoryUIConfig): string[];
|
|
22
28
|
/**
|
|
23
29
|
* Builds the complete Claude prompt
|
|
24
30
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promptGenerator.d.ts","sourceRoot":"","sources":["../../story-generator/promptGenerator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAI9D,OAAO,EAEL,eAAe,EACf,sBAAsB,EACtB,aAAa,EACb,gBAAgB,EACjB,MAAM,+BAA+B,CAAC;AAyOvC;;;GAGG;AACH,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,eAAe,EAAE,oBAAoB,CAAC;IACvF,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,mBAAmB,EAAE,GAAG,eAAe,CAcxG;
|
|
1
|
+
{"version":3,"file":"promptGenerator.d.ts","sourceRoot":"","sources":["../../story-generator/promptGenerator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAI9D,OAAO,EAEL,eAAe,EACf,sBAAsB,EACtB,aAAa,EACb,gBAAgB,EACjB,MAAM,+BAA+B,CAAC;AAyOvC;;;GAGG;AACH,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,eAAe,EAAE,oBAAoB,CAAC;IACvF,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,mBAAmB,EAAE,GAAG,eAAe,CAcxG;AAqTD;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,EAAE,CA6D1E;AA0MD;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,GAChC,OAAO,CAAC,MAAM,CAAC,CA8JjB;AAED;;;GAGG;AACH,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,EACjC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,oBAAoB,CAAC,CAqB/B;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,EACjC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,MAAM,CAAC,CAiHjB;AA4ED;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAIzF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,aAAa,GAAG,gBAAgB,CAG9E;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,aAAa,EAAE,CAGxD"}
|
|
@@ -465,13 +465,47 @@ function formatComponentReference(component, config) {
|
|
|
465
465
|
return reference;
|
|
466
466
|
}
|
|
467
467
|
/**
|
|
468
|
-
* Generates layout-specific instructions
|
|
468
|
+
* Generates layout-specific instructions including MANDATORY vertical spacing rules
|
|
469
|
+
* @param config - The StoryUI configuration object
|
|
470
|
+
* @returns Array of layout instruction strings to be included in the prompt
|
|
469
471
|
*/
|
|
470
|
-
function generateLayoutInstructions(config) {
|
|
472
|
+
export function generateLayoutInstructions(config) {
|
|
471
473
|
const instructions = [];
|
|
472
474
|
const layoutRules = config.layoutRules;
|
|
475
|
+
// MANDATORY VERTICAL SPACING RULES - These are non-negotiable for professional UI quality
|
|
476
|
+
instructions.push('MANDATORY VERTICAL SPACING RULES (NON-NEGOTIABLE):');
|
|
477
|
+
instructions.push('');
|
|
478
|
+
instructions.push('** CRITICAL: Every component MUST have proper vertical spacing. Components without spacing look broken and unprofessional. **');
|
|
479
|
+
instructions.push('');
|
|
480
|
+
instructions.push('1. FORM FIELDS: Always wrap form fields in a container with vertical spacing:');
|
|
481
|
+
instructions.push(' - Use flexbox column with gap: <div style={{ display: "flex", flexDirection: "column", gap: "16px" }}>');
|
|
482
|
+
instructions.push(' - Or use your design system\'s spacing tokens if available');
|
|
483
|
+
instructions.push(' - MINIMUM 16px gap between form fields, 24px for complex forms');
|
|
484
|
+
instructions.push('');
|
|
485
|
+
instructions.push('2. BUTTON SPACING: Buttons MUST have margin-top from content above:');
|
|
486
|
+
instructions.push(' - Submit/action buttons: 24px margin-top from form fields');
|
|
487
|
+
instructions.push(' - Button groups: wrap in <div style={{ marginTop: "24px" }}>');
|
|
488
|
+
instructions.push('');
|
|
489
|
+
instructions.push('3. SECTION SPACING: Logical sections need clear visual separation:');
|
|
490
|
+
instructions.push(' - Between major sections: 32-48px');
|
|
491
|
+
instructions.push(' - Between related content groups: 24px');
|
|
492
|
+
instructions.push(' - Use dividers or significant whitespace between unrelated content');
|
|
493
|
+
instructions.push('');
|
|
494
|
+
instructions.push('4. HEADING SPACING: Headings need asymmetric spacing:');
|
|
495
|
+
instructions.push(' - More space ABOVE headings (24-32px) than below (8-16px)');
|
|
496
|
+
instructions.push(' - This creates visual hierarchy and groups content with its heading');
|
|
497
|
+
instructions.push('');
|
|
498
|
+
instructions.push('5. CARD/CONTAINER PADDING: Internal padding is mandatory:');
|
|
499
|
+
instructions.push(' - Minimum 16px padding on all sides');
|
|
500
|
+
instructions.push(' - Preferred 24px for cards with multiple elements');
|
|
501
|
+
instructions.push(' - Use design system spacing tokens when available');
|
|
502
|
+
instructions.push('');
|
|
503
|
+
instructions.push('6. WRAPPER PATTERN (REQUIRED): The story render function MUST return a wrapper div with padding:');
|
|
504
|
+
instructions.push(' - render: () => <div style={{ padding: "24px" }}>...content...</div>');
|
|
505
|
+
instructions.push(' - This ensures content has breathing room within the Storybook canvas');
|
|
506
|
+
instructions.push('');
|
|
473
507
|
if (layoutRules.multiColumnWrapper && layoutRules.columnComponent) {
|
|
474
|
-
instructions.push('
|
|
508
|
+
instructions.push('MULTI-COLUMN LAYOUT RULES:');
|
|
475
509
|
instructions.push(`- For ANY multi-column layout (2, 3, or more columns), use ${layoutRules.multiColumnWrapper} components`);
|
|
476
510
|
instructions.push(`- Each column must be wrapped in its own ${layoutRules.columnComponent} element`);
|
|
477
511
|
instructions.push(`- Structure: <${layoutRules.multiColumnWrapper}><${layoutRules.columnComponent}>column 1</${layoutRules.columnComponent}><${layoutRules.columnComponent}>column 2</${layoutRules.columnComponent}></${layoutRules.multiColumnWrapper}>`);
|
|
@@ -479,14 +513,17 @@ function generateLayoutInstructions(config) {
|
|
|
479
513
|
instructions.push(`- NEVER use CSS properties as props (like display="grid" or gridTemplateColumns) - these are not valid props`);
|
|
480
514
|
instructions.push(`- For grid-like layouts, use Flex with wrap prop and appropriate gap, NOT CSS Grid`);
|
|
481
515
|
instructions.push(`- The ${layoutRules.multiColumnWrapper} should be the main component in your story for multi-column layouts`);
|
|
516
|
+
instructions.push('');
|
|
482
517
|
}
|
|
483
518
|
if (layoutRules.prohibitedElements && layoutRules.prohibitedElements.length > 0) {
|
|
484
519
|
instructions.push(`- NEVER use plain HTML ${layoutRules.prohibitedElements.join(', ')} elements - ALWAYS use the provided design system components`);
|
|
485
520
|
}
|
|
486
521
|
// Generic layout instructions for all design systems
|
|
522
|
+
instructions.push('GENERAL LAYOUT BEST PRACTICES:');
|
|
487
523
|
instructions.push(`- Use semantic heading components from your design system instead of raw <h1>-<h6> tags`);
|
|
488
|
-
instructions.push(`- Use the design system's layout components and spacing tokens instead of inline styles`);
|
|
524
|
+
instructions.push(`- Use the design system's layout components and spacing tokens instead of inline styles when available`);
|
|
489
525
|
instructions.push(`- Prefer design system components over plain HTML elements for consistent styling`);
|
|
526
|
+
instructions.push(`- ALWAYS test mentally: "Does this component have enough visual breathing room?" If not, add spacing.`);
|
|
490
527
|
return instructions;
|
|
491
528
|
}
|
|
492
529
|
/**
|
|
@@ -1248,6 +1248,7 @@
|
|
|
1248
1248
|
|
|
1249
1249
|
/* ============================================
|
|
1250
1250
|
Completion Card - shares bubble styling with message bubbles
|
|
1251
|
+
Uses explicit colors with !important to prevent design system overrides
|
|
1251
1252
|
============================================ */
|
|
1252
1253
|
.sui-completion {
|
|
1253
1254
|
max-width: 85%;
|
|
@@ -1256,9 +1257,17 @@
|
|
|
1256
1257
|
border-bottom-left-radius: var(--radius-sm);
|
|
1257
1258
|
font-size: 0.9375rem;
|
|
1258
1259
|
line-height: 1.6;
|
|
1259
|
-
|
|
1260
|
-
background:
|
|
1261
|
-
color:
|
|
1260
|
+
/* Explicit light mode colors */
|
|
1261
|
+
background: #ffffff !important;
|
|
1262
|
+
color: #18181b !important;
|
|
1263
|
+
border: 1px solid #e4e4e7 !important;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
/* Completion card - dark mode */
|
|
1267
|
+
.sui-root.dark .sui-completion {
|
|
1268
|
+
background: #27272a !important;
|
|
1269
|
+
color: #fafafa !important;
|
|
1270
|
+
border: 1px solid #3f3f46 !important;
|
|
1262
1271
|
}
|
|
1263
1272
|
|
|
1264
1273
|
.sui-completion-header {
|
|
@@ -1266,7 +1275,13 @@
|
|
|
1266
1275
|
align-items: center;
|
|
1267
1276
|
gap: var(--space-2);
|
|
1268
1277
|
font-weight: 500;
|
|
1269
|
-
|
|
1278
|
+
/* Explicit green for success - readable on white */
|
|
1279
|
+
color: #16a34a !important;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
/* Completion header - dark mode */
|
|
1283
|
+
.sui-root.dark .sui-completion-header {
|
|
1284
|
+
color: #22c55e !important;
|
|
1270
1285
|
}
|
|
1271
1286
|
|
|
1272
1287
|
.sui-completion-components {
|
|
@@ -1278,48 +1293,81 @@
|
|
|
1278
1293
|
|
|
1279
1294
|
.sui-completion-tag {
|
|
1280
1295
|
padding: 0.125rem var(--space-2);
|
|
1281
|
-
|
|
1282
|
-
|
|
1296
|
+
/* Explicit blue colors - readable tag styling */
|
|
1297
|
+
background: #eff6ff !important;
|
|
1298
|
+
color: #2563eb !important;
|
|
1283
1299
|
border-radius: var(--radius-full);
|
|
1284
1300
|
font-size: 0.75rem;
|
|
1285
1301
|
font-family: var(--font-mono);
|
|
1286
1302
|
}
|
|
1287
1303
|
|
|
1304
|
+
/* Completion tag - dark mode */
|
|
1305
|
+
.sui-root.dark .sui-completion-tag {
|
|
1306
|
+
background: #1e3a5f !important;
|
|
1307
|
+
color: #60a5fa !important;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1288
1310
|
.sui-completion-metrics {
|
|
1289
1311
|
display: flex;
|
|
1290
1312
|
gap: var(--space-4);
|
|
1291
1313
|
margin-top: var(--space-3);
|
|
1292
1314
|
font-size: 0.8125rem;
|
|
1293
|
-
|
|
1315
|
+
/* Explicit muted gray */
|
|
1316
|
+
color: #71717a !important;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
/* Completion metrics - dark mode */
|
|
1320
|
+
.sui-root.dark .sui-completion-metrics {
|
|
1321
|
+
color: #a1a1aa !important;
|
|
1294
1322
|
}
|
|
1295
1323
|
|
|
1296
1324
|
/* Fallback story styling (error placeholder was created) */
|
|
1297
1325
|
.sui-completion-fallback .sui-completion-header {
|
|
1298
|
-
color:
|
|
1326
|
+
color: #ca8a04 !important; /* Amber/warning color */
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
.sui-root.dark .sui-completion-fallback .sui-completion-header {
|
|
1330
|
+
color: #facc15 !important; /* Lighter amber for dark mode */
|
|
1299
1331
|
}
|
|
1300
1332
|
|
|
1301
1333
|
.sui-completion-fallback-warning {
|
|
1302
1334
|
margin-top: var(--space-2);
|
|
1303
1335
|
padding: var(--space-2) var(--space-3);
|
|
1304
|
-
background:
|
|
1336
|
+
background: #fef9c3 !important; /* Light amber background */
|
|
1305
1337
|
border-radius: var(--radius-md);
|
|
1306
1338
|
font-size: 0.8125rem;
|
|
1307
1339
|
}
|
|
1308
1340
|
|
|
1341
|
+
.sui-root.dark .sui-completion-fallback-warning {
|
|
1342
|
+
background: #422006 !important; /* Dark amber background */
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1309
1345
|
.sui-completion-fallback-warning strong {
|
|
1310
1346
|
display: block;
|
|
1311
|
-
color:
|
|
1347
|
+
color: #ca8a04 !important; /* Amber text */
|
|
1312
1348
|
margin-bottom: var(--space-1);
|
|
1313
1349
|
}
|
|
1314
1350
|
|
|
1351
|
+
.sui-root.dark .sui-completion-fallback-warning strong {
|
|
1352
|
+
color: #facc15 !important;
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1315
1355
|
.sui-completion-fallback-warning p {
|
|
1316
1356
|
margin: 0;
|
|
1317
|
-
color:
|
|
1357
|
+
color: #71717a !important; /* Muted gray */
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
.sui-root.dark .sui-completion-fallback-warning p {
|
|
1361
|
+
color: #a1a1aa !important;
|
|
1318
1362
|
}
|
|
1319
1363
|
|
|
1320
1364
|
/* Error completion styling (generation failed completely) */
|
|
1321
1365
|
.sui-completion-error .sui-completion-header {
|
|
1322
|
-
color:
|
|
1366
|
+
color: #dc2626 !important; /* Red for errors */
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
.sui-root.dark .sui-completion-error .sui-completion-header {
|
|
1370
|
+
color: #f87171 !important; /* Lighter red for dark mode */
|
|
1323
1371
|
}
|
|
1324
1372
|
|
|
1325
1373
|
/* ============================================
|
package/package.json
CHANGED
|
@@ -1248,6 +1248,7 @@
|
|
|
1248
1248
|
|
|
1249
1249
|
/* ============================================
|
|
1250
1250
|
Completion Card - shares bubble styling with message bubbles
|
|
1251
|
+
Uses explicit colors with !important to prevent design system overrides
|
|
1251
1252
|
============================================ */
|
|
1252
1253
|
.sui-completion {
|
|
1253
1254
|
max-width: 85%;
|
|
@@ -1256,9 +1257,17 @@
|
|
|
1256
1257
|
border-bottom-left-radius: var(--radius-sm);
|
|
1257
1258
|
font-size: 0.9375rem;
|
|
1258
1259
|
line-height: 1.6;
|
|
1259
|
-
|
|
1260
|
-
background:
|
|
1261
|
-
color:
|
|
1260
|
+
/* Explicit light mode colors */
|
|
1261
|
+
background: #ffffff !important;
|
|
1262
|
+
color: #18181b !important;
|
|
1263
|
+
border: 1px solid #e4e4e7 !important;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
/* Completion card - dark mode */
|
|
1267
|
+
.sui-root.dark .sui-completion {
|
|
1268
|
+
background: #27272a !important;
|
|
1269
|
+
color: #fafafa !important;
|
|
1270
|
+
border: 1px solid #3f3f46 !important;
|
|
1262
1271
|
}
|
|
1263
1272
|
|
|
1264
1273
|
.sui-completion-header {
|
|
@@ -1266,7 +1275,13 @@
|
|
|
1266
1275
|
align-items: center;
|
|
1267
1276
|
gap: var(--space-2);
|
|
1268
1277
|
font-weight: 500;
|
|
1269
|
-
|
|
1278
|
+
/* Explicit green for success - readable on white */
|
|
1279
|
+
color: #16a34a !important;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
/* Completion header - dark mode */
|
|
1283
|
+
.sui-root.dark .sui-completion-header {
|
|
1284
|
+
color: #22c55e !important;
|
|
1270
1285
|
}
|
|
1271
1286
|
|
|
1272
1287
|
.sui-completion-components {
|
|
@@ -1278,48 +1293,81 @@
|
|
|
1278
1293
|
|
|
1279
1294
|
.sui-completion-tag {
|
|
1280
1295
|
padding: 0.125rem var(--space-2);
|
|
1281
|
-
|
|
1282
|
-
|
|
1296
|
+
/* Explicit blue colors - readable tag styling */
|
|
1297
|
+
background: #eff6ff !important;
|
|
1298
|
+
color: #2563eb !important;
|
|
1283
1299
|
border-radius: var(--radius-full);
|
|
1284
1300
|
font-size: 0.75rem;
|
|
1285
1301
|
font-family: var(--font-mono);
|
|
1286
1302
|
}
|
|
1287
1303
|
|
|
1304
|
+
/* Completion tag - dark mode */
|
|
1305
|
+
.sui-root.dark .sui-completion-tag {
|
|
1306
|
+
background: #1e3a5f !important;
|
|
1307
|
+
color: #60a5fa !important;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1288
1310
|
.sui-completion-metrics {
|
|
1289
1311
|
display: flex;
|
|
1290
1312
|
gap: var(--space-4);
|
|
1291
1313
|
margin-top: var(--space-3);
|
|
1292
1314
|
font-size: 0.8125rem;
|
|
1293
|
-
|
|
1315
|
+
/* Explicit muted gray */
|
|
1316
|
+
color: #71717a !important;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
/* Completion metrics - dark mode */
|
|
1320
|
+
.sui-root.dark .sui-completion-metrics {
|
|
1321
|
+
color: #a1a1aa !important;
|
|
1294
1322
|
}
|
|
1295
1323
|
|
|
1296
1324
|
/* Fallback story styling (error placeholder was created) */
|
|
1297
1325
|
.sui-completion-fallback .sui-completion-header {
|
|
1298
|
-
color:
|
|
1326
|
+
color: #ca8a04 !important; /* Amber/warning color */
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
.sui-root.dark .sui-completion-fallback .sui-completion-header {
|
|
1330
|
+
color: #facc15 !important; /* Lighter amber for dark mode */
|
|
1299
1331
|
}
|
|
1300
1332
|
|
|
1301
1333
|
.sui-completion-fallback-warning {
|
|
1302
1334
|
margin-top: var(--space-2);
|
|
1303
1335
|
padding: var(--space-2) var(--space-3);
|
|
1304
|
-
background:
|
|
1336
|
+
background: #fef9c3 !important; /* Light amber background */
|
|
1305
1337
|
border-radius: var(--radius-md);
|
|
1306
1338
|
font-size: 0.8125rem;
|
|
1307
1339
|
}
|
|
1308
1340
|
|
|
1341
|
+
.sui-root.dark .sui-completion-fallback-warning {
|
|
1342
|
+
background: #422006 !important; /* Dark amber background */
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1309
1345
|
.sui-completion-fallback-warning strong {
|
|
1310
1346
|
display: block;
|
|
1311
|
-
color:
|
|
1347
|
+
color: #ca8a04 !important; /* Amber text */
|
|
1312
1348
|
margin-bottom: var(--space-1);
|
|
1313
1349
|
}
|
|
1314
1350
|
|
|
1351
|
+
.sui-root.dark .sui-completion-fallback-warning strong {
|
|
1352
|
+
color: #facc15 !important;
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1315
1355
|
.sui-completion-fallback-warning p {
|
|
1316
1356
|
margin: 0;
|
|
1317
|
-
color:
|
|
1357
|
+
color: #71717a !important; /* Muted gray */
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
.sui-root.dark .sui-completion-fallback-warning p {
|
|
1361
|
+
color: #a1a1aa !important;
|
|
1318
1362
|
}
|
|
1319
1363
|
|
|
1320
1364
|
/* Error completion styling (generation failed completely) */
|
|
1321
1365
|
.sui-completion-error .sui-completion-header {
|
|
1322
|
-
color:
|
|
1366
|
+
color: #dc2626 !important; /* Red for errors */
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
.sui-root.dark .sui-completion-error .sui-completion-header {
|
|
1370
|
+
color: #f87171 !important; /* Lighter red for dark mode */
|
|
1323
1371
|
}
|
|
1324
1372
|
|
|
1325
1373
|
/* ============================================
|