@tpitre/story-ui 3.6.2 → 3.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/README.md +36 -32
- package/dist/cli/index.js +0 -5
- package/dist/cli/setup.js +1 -1
- package/dist/mcp-server/routes/generateStory.d.ts.map +1 -1
- package/dist/mcp-server/routes/generateStory.js +142 -87
- package/dist/mcp-server/routes/generateStoryStream.d.ts.map +1 -1
- package/dist/mcp-server/routes/generateStoryStream.js +149 -31
- package/dist/story-generator/dynamicPackageDiscovery.d.ts +35 -2
- package/dist/story-generator/dynamicPackageDiscovery.d.ts.map +1 -1
- package/dist/story-generator/dynamicPackageDiscovery.js +332 -6
- package/dist/story-generator/enhancedComponentDiscovery.d.ts.map +1 -1
- package/dist/story-generator/enhancedComponentDiscovery.js +149 -2
- package/dist/story-generator/framework-adapters/base-adapter.d.ts +1 -0
- package/dist/story-generator/framework-adapters/base-adapter.d.ts.map +1 -1
- package/dist/story-generator/framework-adapters/base-adapter.js +12 -2
- package/dist/story-generator/framework-adapters/react-adapter.d.ts.map +1 -1
- package/dist/story-generator/framework-adapters/react-adapter.js +2 -0
- package/dist/story-generator/framework-adapters/svelte-adapter.d.ts.map +1 -1
- package/dist/story-generator/framework-adapters/svelte-adapter.js +53 -7
- package/dist/story-generator/framework-adapters/vue-adapter.d.ts.map +1 -1
- package/dist/story-generator/framework-adapters/vue-adapter.js +21 -1
- package/dist/story-generator/framework-adapters/web-components-adapter.d.ts.map +1 -1
- package/dist/story-generator/framework-adapters/web-components-adapter.js +4 -0
- package/dist/story-generator/llm-providers/openai-provider.js +2 -2
- package/dist/story-generator/promptGenerator.d.ts.map +1 -1
- package/dist/story-generator/promptGenerator.js +179 -26
- package/dist/story-generator/selfHealingLoop.d.ts +112 -0
- package/dist/story-generator/selfHealingLoop.d.ts.map +1 -0
- package/dist/story-generator/selfHealingLoop.js +202 -0
- package/dist/story-generator/validateStory.d.ts.map +1 -1
- package/dist/story-generator/validateStory.js +81 -12
- package/dist/story-ui.config.d.ts +2 -0
- package/dist/story-ui.config.d.ts.map +1 -1
- package/dist/templates/StoryUI/StoryUIPanel.d.ts +0 -5
- package/dist/templates/StoryUI/StoryUIPanel.d.ts.map +1 -1
- package/dist/templates/StoryUI/StoryUIPanel.js +411 -223
- package/package.json +4 -4
- package/templates/StoryUI/StoryUIPanel.mdx +84 -0
- package/templates/StoryUI/StoryUIPanel.tsx +493 -265
- package/dist/templates/StoryUI/StoryUIPanel.stories.d.ts +0 -18
- package/dist/templates/StoryUI/StoryUIPanel.stories.d.ts.map +0 -1
- package/dist/templates/StoryUI/StoryUIPanel.stories.js +0 -37
- package/templates/StoryUI/StoryUIPanel.stories.tsx +0 -44
- package/templates/StoryUI/manager.tsx +0 -859
|
@@ -37,8 +37,8 @@ const renderMarkdown = (text) => {
|
|
|
37
37
|
if (codeMatch) {
|
|
38
38
|
parts.push(_jsx("code", { style: {
|
|
39
39
|
background: 'rgba(0,0,0,0.08)',
|
|
40
|
-
padding: '1px
|
|
41
|
-
borderRadius: '
|
|
40
|
+
padding: '1px 4px',
|
|
41
|
+
borderRadius: '4px',
|
|
42
42
|
fontFamily: 'ui-monospace, monospace',
|
|
43
43
|
fontSize: '0.88em'
|
|
44
44
|
}, children: codeMatch[1] }, `c-${paragraphIndex}-${keyIndex++}`));
|
|
@@ -69,7 +69,7 @@ const renderMarkdown = (text) => {
|
|
|
69
69
|
}
|
|
70
70
|
return parts;
|
|
71
71
|
};
|
|
72
|
-
return (_jsx(_Fragment, { children: paragraphs.map((paragraph, index) => (_jsx("div", { style: { marginBottom: index < paragraphs.length - 1 ? '
|
|
72
|
+
return (_jsx(_Fragment, { children: paragraphs.map((paragraph, index) => (_jsx("div", { style: { marginBottom: index < paragraphs.length - 1 ? '8px' : 0 }, children: parseInline(paragraph.trim(), index) }, `p-${index}`))) }));
|
|
73
73
|
};
|
|
74
74
|
// Inline SVG icons for status indicators (avoiding emojis)
|
|
75
75
|
const StatusIcons = {
|
|
@@ -78,6 +78,38 @@ const StatusIcons = {
|
|
|
78
78
|
tip: (_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { color: '#f59e0b', verticalAlign: 'middle', marginRight: '4px' }, children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("line", { x1: "12", y1: "16", x2: "12", y2: "12" }), _jsx("line", { x1: "12", y1: "8", x2: "12.01", y2: "8" })] })),
|
|
79
79
|
wrench: (_jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { color: '#6366f1', verticalAlign: 'middle', marginRight: '4px' }, children: _jsx("path", { d: "M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z" }) }))
|
|
80
80
|
};
|
|
81
|
+
// Model display names for friendly UI presentation
|
|
82
|
+
// Maps API model IDs to human-readable names
|
|
83
|
+
const MODEL_DISPLAY_NAMES = {
|
|
84
|
+
// Claude models
|
|
85
|
+
'claude-opus-4-5-20251101': 'Claude Opus 4.5',
|
|
86
|
+
'claude-sonnet-4-5-20250929': 'Claude Sonnet 4.5',
|
|
87
|
+
'claude-haiku-4-5-20251001': 'Claude Haiku 4.5',
|
|
88
|
+
'claude-sonnet-4-20250514': 'Claude Sonnet 4',
|
|
89
|
+
'claude-opus-4-20250514': 'Claude Opus 4',
|
|
90
|
+
'claude-3-7-sonnet-20250219': 'Claude 3.7 Sonnet',
|
|
91
|
+
'claude-3-5-sonnet-20241022': 'Claude 3.5 Sonnet',
|
|
92
|
+
'claude-3-5-haiku-20241022': 'Claude 3.5 Haiku',
|
|
93
|
+
// OpenAI models
|
|
94
|
+
'gpt-5.1': 'GPT-5.1',
|
|
95
|
+
'gpt-5.1-thinking': 'GPT-5.1 Thinking',
|
|
96
|
+
'gpt-5': 'GPT-5',
|
|
97
|
+
'gpt-4o': 'GPT-4o',
|
|
98
|
+
'gpt-4o-mini': 'GPT-4o Mini',
|
|
99
|
+
'o1': 'o1',
|
|
100
|
+
'o1-mini': 'o1 Mini',
|
|
101
|
+
// Gemini models
|
|
102
|
+
'gemini-3-pro': 'Gemini 3 Pro',
|
|
103
|
+
'gemini-3-pro-preview': 'Gemini 3 Pro Preview',
|
|
104
|
+
'gemini-2.0-flash-exp': 'Gemini 2.0 Flash Exp',
|
|
105
|
+
'gemini-2.0-flash': 'Gemini 2.0 Flash',
|
|
106
|
+
'gemini-1.5-pro': 'Gemini 1.5 Pro',
|
|
107
|
+
'gemini-1.5-flash': 'Gemini 1.5 Flash',
|
|
108
|
+
};
|
|
109
|
+
// Get friendly display name for a model, falling back to the API name if not found
|
|
110
|
+
const getModelDisplayName = (modelId) => {
|
|
111
|
+
return MODEL_DISPLAY_NAMES[modelId] || modelId;
|
|
112
|
+
};
|
|
81
113
|
// Determine the MCP API base URL.
|
|
82
114
|
// Priority order:
|
|
83
115
|
// 1. VITE_STORY_UI_EDGE_URL - Edge Worker URL for cloud deployments
|
|
@@ -131,44 +163,12 @@ const titleToStoryPath = (title) => {
|
|
|
131
163
|
const kebabTitle = title.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
|
|
132
164
|
return `generated-${kebabTitle}--default`;
|
|
133
165
|
};
|
|
134
|
-
// Helper to store generated code for the Source Code panel to display
|
|
135
|
-
const storeGeneratedCode = (storyId, code, title) => {
|
|
136
|
-
const topWindow = window.top || window;
|
|
137
|
-
// Store code in the top window so it's accessible from manager frame
|
|
138
|
-
if (!topWindow.__STORY_UI_GENERATED_CODE__) {
|
|
139
|
-
topWindow.__STORY_UI_GENERATED_CODE__ = {};
|
|
140
|
-
}
|
|
141
|
-
// Store with story ID
|
|
142
|
-
topWindow.__STORY_UI_GENERATED_CODE__[storyId] = code;
|
|
143
|
-
// Also store in localStorage for persistence across page reloads
|
|
144
|
-
try {
|
|
145
|
-
const stored = JSON.parse(localStorage.getItem('storyui_generated_code') || '{}');
|
|
146
|
-
stored[storyId] = code;
|
|
147
|
-
// Also store with the title as key for easier lookup
|
|
148
|
-
if (title) {
|
|
149
|
-
const storyPath = titleToStoryPath(title);
|
|
150
|
-
stored[storyPath] = code;
|
|
151
|
-
stored[title] = code;
|
|
152
|
-
stored[title.replace(/\s+/g, '')] = code;
|
|
153
|
-
topWindow.__STORY_UI_GENERATED_CODE__[storyPath] = code;
|
|
154
|
-
}
|
|
155
|
-
localStorage.setItem('storyui_generated_code', JSON.stringify(stored));
|
|
156
|
-
console.log(`[Story UI] Stored code for story "${storyId}" in window cache and localStorage`);
|
|
157
|
-
}
|
|
158
|
-
catch (e) {
|
|
159
|
-
console.warn('[Story UI] Failed to store code in localStorage:', e);
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
166
|
// Helper to navigate to a newly created story after generation completes
|
|
163
167
|
// In dev mode with HMR, this prevents the "Couldn't find story after HMR" error
|
|
164
168
|
// In all modes, this provides a better UX by auto-navigating to the new story
|
|
165
|
-
const navigateToNewStory = (title,
|
|
169
|
+
const navigateToNewStory = (title, _code, delayMs = 1500) => {
|
|
166
170
|
const storyPath = titleToStoryPath(title);
|
|
167
171
|
console.log(`[Story UI] Will navigate to story "${storyPath}" in ${delayMs}ms...`);
|
|
168
|
-
// Store the code for the Source Code panel if provided
|
|
169
|
-
if (code) {
|
|
170
|
-
storeGeneratedCode(title, code, title);
|
|
171
|
-
}
|
|
172
172
|
setTimeout(() => {
|
|
173
173
|
// Navigate the TOP window (parent Storybook UI), not the iframe
|
|
174
174
|
// The Story UI panel runs inside an iframe, so we need window.top to escape it
|
|
@@ -305,7 +305,7 @@ const syncWithActualStories = async () => {
|
|
|
305
305
|
content: story.prompt || `Generate ${story.title}`
|
|
306
306
|
}, {
|
|
307
307
|
role: 'ai',
|
|
308
|
-
content:
|
|
308
|
+
content: `[SUCCESS] Created story: "${story.title}"\n\nThis story was recovered from memory. You can continue updating it or view it in Storybook.`
|
|
309
309
|
}],
|
|
310
310
|
lastUpdated: new Date(story.updatedAt || story.createdAt).getTime()
|
|
311
311
|
};
|
|
@@ -414,16 +414,61 @@ const testMCPConnection = async () => {
|
|
|
414
414
|
return { connected: false, error: error instanceof Error ? error.message : 'Unknown error' };
|
|
415
415
|
}
|
|
416
416
|
};
|
|
417
|
+
// Fetch orphan stories (stories on disk without corresponding chat history)
|
|
418
|
+
const fetchOrphanStories = async () => {
|
|
419
|
+
try {
|
|
420
|
+
const response = await fetch(STORIES_API);
|
|
421
|
+
if (!response.ok) {
|
|
422
|
+
console.error('Failed to fetch stories from backend for orphan detection');
|
|
423
|
+
return [];
|
|
424
|
+
}
|
|
425
|
+
const contentType = response.headers.get('content-type');
|
|
426
|
+
if (!contentType || !contentType.includes('application/json')) {
|
|
427
|
+
console.error('Server returned non-JSON response for orphan detection');
|
|
428
|
+
return [];
|
|
429
|
+
}
|
|
430
|
+
const data = await response.json();
|
|
431
|
+
const serverStories = data.stories || [];
|
|
432
|
+
// Load current chats from localStorage
|
|
433
|
+
const existingChats = loadChats();
|
|
434
|
+
const chatIds = new Set(existingChats.map(chat => chat.id));
|
|
435
|
+
const chatFileNames = new Set(existingChats.map(chat => chat.fileName).filter(Boolean));
|
|
436
|
+
// Find stories that don't have a matching chat
|
|
437
|
+
const orphans = [];
|
|
438
|
+
serverStories.forEach((story) => {
|
|
439
|
+
const storyId = story.id || story.storyId || story.fileName;
|
|
440
|
+
const fileName = story.fileName || '';
|
|
441
|
+
// Check if this story has a corresponding chat
|
|
442
|
+
const hasMatchingChat = chatIds.has(storyId) || chatFileNames.has(fileName);
|
|
443
|
+
if (!hasMatchingChat && fileName) {
|
|
444
|
+
orphans.push({
|
|
445
|
+
id: storyId,
|
|
446
|
+
fileName: fileName,
|
|
447
|
+
title: story.title || fileName.replace(/\.stories\.(tsx|ts|jsx|js)$/, ''),
|
|
448
|
+
createdAt: new Date(story.createdAt || Date.now()).getTime(),
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
// Sort by creation date, newest first
|
|
453
|
+
return orphans.sort((a, b) => b.createdAt - a.createdAt);
|
|
454
|
+
}
|
|
455
|
+
catch (error) {
|
|
456
|
+
console.error('Error fetching orphan stories:', error);
|
|
457
|
+
return [];
|
|
458
|
+
}
|
|
459
|
+
};
|
|
417
460
|
// Component styles
|
|
418
461
|
const STYLES = {
|
|
419
462
|
container: {
|
|
420
463
|
display: 'flex',
|
|
421
464
|
flexDirection: 'row',
|
|
422
|
-
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell",
|
|
465
|
+
fontFamily: '"IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", sans-serif',
|
|
423
466
|
height: '100vh',
|
|
424
467
|
overflow: 'hidden',
|
|
425
468
|
background: 'linear-gradient(135deg, #1e293b 0%, #334155 100%)',
|
|
426
469
|
color: '#e2e8f0',
|
|
470
|
+
fontSize: '14px',
|
|
471
|
+
lineHeight: '1.5',
|
|
427
472
|
},
|
|
428
473
|
// Sidebar
|
|
429
474
|
sidebar: {
|
|
@@ -441,44 +486,44 @@ const STYLES = {
|
|
|
441
486
|
},
|
|
442
487
|
sidebarToggle: {
|
|
443
488
|
width: '100%',
|
|
444
|
-
padding: '
|
|
445
|
-
background: '
|
|
446
|
-
color: '
|
|
447
|
-
border: '
|
|
448
|
-
borderRadius: '
|
|
449
|
-
fontSize: '
|
|
450
|
-
fontWeight: '
|
|
489
|
+
padding: '10px 14px',
|
|
490
|
+
background: 'rgba(59, 130, 246, 0.15)',
|
|
491
|
+
color: '#e2e8f0',
|
|
492
|
+
border: '1px solid rgba(59, 130, 246, 0.3)',
|
|
493
|
+
borderRadius: '8px',
|
|
494
|
+
fontSize: '14px',
|
|
495
|
+
fontWeight: '600',
|
|
451
496
|
cursor: 'pointer',
|
|
452
|
-
marginBottom: '
|
|
497
|
+
marginBottom: '8px',
|
|
453
498
|
transition: 'all 0.2s ease',
|
|
454
499
|
boxShadow: 'none',
|
|
455
500
|
display: 'flex',
|
|
456
501
|
alignItems: 'center',
|
|
457
|
-
justifyContent: '
|
|
458
|
-
gap: '
|
|
502
|
+
justifyContent: 'flex-start',
|
|
503
|
+
gap: '10px',
|
|
459
504
|
lineHeight: '1',
|
|
460
505
|
},
|
|
461
506
|
newChatButton: {
|
|
462
507
|
width: '100%',
|
|
463
|
-
padding: '
|
|
508
|
+
padding: '10px 14px',
|
|
464
509
|
background: '#3b82f6',
|
|
465
510
|
color: 'white',
|
|
466
511
|
border: 'none',
|
|
467
|
-
borderRadius: '
|
|
468
|
-
fontSize: '
|
|
469
|
-
fontWeight: '
|
|
512
|
+
borderRadius: '8px',
|
|
513
|
+
fontSize: '14px',
|
|
514
|
+
fontWeight: '600',
|
|
470
515
|
cursor: 'pointer',
|
|
471
|
-
marginBottom: '
|
|
516
|
+
marginBottom: '16px',
|
|
472
517
|
transition: 'all 0.2s ease',
|
|
473
|
-
boxShadow: '
|
|
518
|
+
boxShadow: '0 2px 8px rgba(59, 130, 246, 0.25)',
|
|
474
519
|
display: 'flex',
|
|
475
520
|
alignItems: 'center',
|
|
476
|
-
justifyContent: '
|
|
477
|
-
gap: '
|
|
521
|
+
justifyContent: 'flex-start',
|
|
522
|
+
gap: '10px',
|
|
478
523
|
lineHeight: '1',
|
|
479
524
|
},
|
|
480
525
|
chatItem: {
|
|
481
|
-
padding: '8px
|
|
526
|
+
padding: '8px 12px',
|
|
482
527
|
marginBottom: '4px',
|
|
483
528
|
background: 'rgba(255, 255, 255, 0.05)',
|
|
484
529
|
borderRadius: '6px',
|
|
@@ -492,7 +537,7 @@ const STYLES = {
|
|
|
492
537
|
borderLeft: '2px solid #3b82f6',
|
|
493
538
|
},
|
|
494
539
|
chatItemTitle: {
|
|
495
|
-
fontSize: '
|
|
540
|
+
fontSize: '14px',
|
|
496
541
|
fontWeight: '500',
|
|
497
542
|
marginBottom: '2px',
|
|
498
543
|
whiteSpace: 'nowrap',
|
|
@@ -500,7 +545,7 @@ const STYLES = {
|
|
|
500
545
|
textOverflow: 'ellipsis',
|
|
501
546
|
},
|
|
502
547
|
chatItemTime: {
|
|
503
|
-
fontSize: '
|
|
548
|
+
fontSize: '12px',
|
|
504
549
|
color: '#94a3b8',
|
|
505
550
|
},
|
|
506
551
|
deleteButton: {
|
|
@@ -541,10 +586,9 @@ const STYLES = {
|
|
|
541
586
|
color: '#94a3b8',
|
|
542
587
|
textAlign: 'center',
|
|
543
588
|
marginTop: '60px',
|
|
544
|
-
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif',
|
|
545
589
|
},
|
|
546
590
|
emptyStateTitle: {
|
|
547
|
-
fontSize: '
|
|
591
|
+
fontSize: '15px',
|
|
548
592
|
fontWeight: '500',
|
|
549
593
|
marginBottom: '8px',
|
|
550
594
|
color: '#cbd5e1',
|
|
@@ -556,62 +600,64 @@ const STYLES = {
|
|
|
556
600
|
// Message bubbles
|
|
557
601
|
messageContainer: {
|
|
558
602
|
display: 'flex',
|
|
559
|
-
marginBottom: '
|
|
603
|
+
marginBottom: '8px',
|
|
560
604
|
},
|
|
561
605
|
userMessage: {
|
|
562
|
-
background: '
|
|
563
|
-
color: '#
|
|
606
|
+
background: 'rgba(59, 130, 246, 0.12)',
|
|
607
|
+
color: '#e2e8f0',
|
|
564
608
|
borderRadius: '16px 16px 4px 16px',
|
|
565
609
|
padding: '10px 14px',
|
|
566
610
|
maxWidth: '85%',
|
|
567
611
|
marginLeft: 'auto',
|
|
568
612
|
fontSize: '14px',
|
|
569
|
-
lineHeight: '1.
|
|
570
|
-
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif',
|
|
613
|
+
lineHeight: '1.45',
|
|
571
614
|
boxShadow: 'none',
|
|
572
615
|
wordWrap: 'break-word',
|
|
616
|
+
border: '1px solid rgba(59, 130, 246, 0.2)',
|
|
573
617
|
},
|
|
574
618
|
aiMessage: {
|
|
575
619
|
background: 'rgba(255, 255, 255, 0.95)',
|
|
576
620
|
color: '#1f2937',
|
|
577
621
|
borderRadius: '16px 16px 16px 4px',
|
|
578
622
|
padding: '10px 14px',
|
|
579
|
-
maxWidth: '
|
|
623
|
+
maxWidth: '90%',
|
|
580
624
|
fontSize: '14px',
|
|
581
|
-
lineHeight: '1.
|
|
582
|
-
|
|
583
|
-
|
|
625
|
+
lineHeight: '1.45',
|
|
626
|
+
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.06)',
|
|
627
|
+
border: '1px solid rgba(0, 0, 0, 0.08)',
|
|
584
628
|
wordWrap: 'break-word',
|
|
585
629
|
whiteSpace: 'pre-wrap',
|
|
586
630
|
},
|
|
587
631
|
loadingMessage: {
|
|
588
|
-
background: 'rgba(255, 255, 255, 0.
|
|
589
|
-
color: '#
|
|
632
|
+
background: 'rgba(255, 255, 255, 0.95)',
|
|
633
|
+
color: '#4b5563',
|
|
590
634
|
borderRadius: '16px 16px 16px 4px',
|
|
591
635
|
padding: '10px 14px',
|
|
592
636
|
fontSize: '14px',
|
|
593
|
-
|
|
637
|
+
lineHeight: '1.45',
|
|
594
638
|
display: 'flex',
|
|
595
639
|
alignItems: 'center',
|
|
596
|
-
gap: '
|
|
640
|
+
gap: '8px',
|
|
641
|
+
border: '1px solid rgba(0, 0, 0, 0.08)',
|
|
642
|
+
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.06)',
|
|
597
643
|
},
|
|
598
644
|
// Input form
|
|
599
645
|
inputForm: {
|
|
600
646
|
display: 'flex',
|
|
601
647
|
alignItems: 'center',
|
|
602
|
-
gap: '
|
|
648
|
+
gap: '12px',
|
|
603
649
|
margin: '0 16px 16px 16px',
|
|
604
|
-
padding: '
|
|
650
|
+
padding: '12px',
|
|
605
651
|
background: 'rgba(255, 255, 255, 0.03)',
|
|
606
|
-
borderRadius: '
|
|
652
|
+
borderRadius: '12px',
|
|
607
653
|
border: '1px solid rgba(255, 255, 255, 0.08)',
|
|
608
654
|
backdropFilter: 'blur(10px)',
|
|
609
655
|
},
|
|
610
656
|
textInput: {
|
|
611
|
-
|
|
657
|
+
font: 'inherit',
|
|
612
658
|
flex: 1,
|
|
613
|
-
padding: '
|
|
614
|
-
borderRadius: '
|
|
659
|
+
padding: '12px 16px',
|
|
660
|
+
borderRadius: '8px',
|
|
615
661
|
border: '1px solid rgba(255, 255, 255, 0.15)',
|
|
616
662
|
fontSize: '13px',
|
|
617
663
|
color: '#1f2937',
|
|
@@ -621,20 +667,21 @@ const STYLES = {
|
|
|
621
667
|
boxSizing: 'border-box',
|
|
622
668
|
},
|
|
623
669
|
sendButton: {
|
|
624
|
-
|
|
670
|
+
font: 'inherit',
|
|
625
671
|
padding: '10px 16px',
|
|
626
|
-
borderRadius: '
|
|
672
|
+
borderRadius: '10px',
|
|
627
673
|
border: 'none',
|
|
628
|
-
background: '#
|
|
629
|
-
color: '
|
|
630
|
-
fontSize: '
|
|
631
|
-
fontWeight: '
|
|
674
|
+
background: '#3b82f6',
|
|
675
|
+
color: 'white',
|
|
676
|
+
fontSize: '14px',
|
|
677
|
+
fontWeight: '600',
|
|
632
678
|
cursor: 'pointer',
|
|
633
679
|
display: 'flex',
|
|
634
680
|
alignItems: 'center',
|
|
635
|
-
gap: '
|
|
636
|
-
transition: 'all 0.
|
|
637
|
-
boxShadow: '
|
|
681
|
+
gap: '6px',
|
|
682
|
+
transition: 'all 0.2s ease',
|
|
683
|
+
boxShadow: '0 2px 8px rgba(59, 130, 246, 0.35)',
|
|
684
|
+
flexShrink: 0,
|
|
638
685
|
},
|
|
639
686
|
errorMessage: {
|
|
640
687
|
background: 'rgba(248, 113, 113, 0.1)',
|
|
@@ -642,7 +689,7 @@ const STYLES = {
|
|
|
642
689
|
padding: '8px 12px',
|
|
643
690
|
borderRadius: '6px',
|
|
644
691
|
fontSize: '13px',
|
|
645
|
-
marginBottom: '
|
|
692
|
+
marginBottom: '8px',
|
|
646
693
|
border: '1px solid rgba(248, 113, 113, 0.2)',
|
|
647
694
|
},
|
|
648
695
|
loadingDots: {
|
|
@@ -657,38 +704,41 @@ const STYLES = {
|
|
|
657
704
|
},
|
|
658
705
|
codeBlock: {
|
|
659
706
|
background: '#1e293b',
|
|
660
|
-
padding: '
|
|
661
|
-
borderRadius: '
|
|
707
|
+
padding: '12px',
|
|
708
|
+
borderRadius: '8px',
|
|
662
709
|
fontFamily: 'Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace',
|
|
663
710
|
fontSize: '12px',
|
|
664
711
|
lineHeight: '1.5',
|
|
665
712
|
overflowX: 'auto',
|
|
666
|
-
marginTop: '
|
|
713
|
+
marginTop: '8px',
|
|
667
714
|
border: '1px solid rgba(255, 255, 255, 0.08)',
|
|
668
715
|
},
|
|
669
716
|
// Streaming progress styles
|
|
670
717
|
streamingContainer: {
|
|
671
718
|
background: 'rgba(255, 255, 255, 0.95)',
|
|
672
719
|
borderRadius: '16px 16px 16px 4px',
|
|
673
|
-
padding: '
|
|
674
|
-
maxWidth: '
|
|
675
|
-
boxShadow: '0 1px
|
|
720
|
+
padding: '10px 14px',
|
|
721
|
+
maxWidth: '90%',
|
|
722
|
+
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.06)',
|
|
723
|
+
border: '1px solid rgba(0, 0, 0, 0.08)',
|
|
724
|
+
fontSize: '14px',
|
|
725
|
+
lineHeight: '1.45',
|
|
676
726
|
},
|
|
677
727
|
intentPreview: {
|
|
678
|
-
background: 'rgba(59, 130, 246, 0.
|
|
728
|
+
background: 'rgba(59, 130, 246, 0.06)',
|
|
679
729
|
borderRadius: '8px',
|
|
680
|
-
padding: '10px',
|
|
730
|
+
padding: '10px 12px',
|
|
681
731
|
marginBottom: '10px',
|
|
682
|
-
border: '1px solid rgba(59, 130, 246, 0.
|
|
732
|
+
border: '1px solid rgba(59, 130, 246, 0.12)',
|
|
683
733
|
},
|
|
684
734
|
intentTitle: {
|
|
685
735
|
fontSize: '13px',
|
|
686
736
|
fontWeight: '600',
|
|
687
737
|
color: '#1e40af',
|
|
688
|
-
marginBottom: '
|
|
738
|
+
marginBottom: '8px',
|
|
689
739
|
display: 'flex',
|
|
690
740
|
alignItems: 'center',
|
|
691
|
-
gap: '
|
|
741
|
+
gap: '4px',
|
|
692
742
|
},
|
|
693
743
|
intentStrategy: {
|
|
694
744
|
fontSize: '12px',
|
|
@@ -699,22 +749,22 @@ const STYLES = {
|
|
|
699
749
|
display: 'flex',
|
|
700
750
|
flexWrap: 'wrap',
|
|
701
751
|
gap: '4px',
|
|
702
|
-
marginTop: '
|
|
752
|
+
marginTop: '8px',
|
|
703
753
|
},
|
|
704
754
|
componentTag: {
|
|
705
755
|
background: 'rgba(59, 130, 246, 0.12)',
|
|
706
756
|
color: '#1d4ed8',
|
|
707
|
-
fontSize: '
|
|
708
|
-
padding: '2px
|
|
757
|
+
fontSize: '11px',
|
|
758
|
+
padding: '2px 8px',
|
|
709
759
|
borderRadius: '10px',
|
|
710
760
|
fontWeight: '500',
|
|
711
761
|
},
|
|
712
762
|
progressBar: {
|
|
713
763
|
background: 'rgba(0, 0, 0, 0.08)',
|
|
714
|
-
borderRadius: '
|
|
764
|
+
borderRadius: '4px',
|
|
715
765
|
height: '4px',
|
|
716
|
-
marginTop: '
|
|
717
|
-
marginBottom: '
|
|
766
|
+
marginTop: '12px',
|
|
767
|
+
marginBottom: '8px',
|
|
718
768
|
overflow: 'hidden',
|
|
719
769
|
},
|
|
720
770
|
progressFill: {
|
|
@@ -724,14 +774,16 @@ const STYLES = {
|
|
|
724
774
|
transition: 'width 0.3s ease',
|
|
725
775
|
},
|
|
726
776
|
progressPhase: {
|
|
727
|
-
fontSize: '
|
|
728
|
-
color: '#
|
|
777
|
+
fontSize: '14px',
|
|
778
|
+
color: '#4b5563',
|
|
729
779
|
display: 'flex',
|
|
730
780
|
alignItems: 'center',
|
|
731
|
-
gap: '
|
|
781
|
+
gap: '6px',
|
|
782
|
+
fontWeight: '500',
|
|
783
|
+
lineHeight: '1.45',
|
|
732
784
|
},
|
|
733
785
|
phaseIcon: {
|
|
734
|
-
fontSize: '
|
|
786
|
+
fontSize: '14px',
|
|
735
787
|
},
|
|
736
788
|
validationBox: {
|
|
737
789
|
marginTop: '8px',
|
|
@@ -757,18 +809,18 @@ const STYLES = {
|
|
|
757
809
|
retryBadge: {
|
|
758
810
|
background: 'rgba(245, 158, 11, 0.12)',
|
|
759
811
|
color: '#b45309',
|
|
760
|
-
fontSize: '
|
|
812
|
+
fontSize: '11px',
|
|
761
813
|
padding: '2px 8px',
|
|
762
814
|
borderRadius: '10px',
|
|
763
815
|
display: 'inline-flex',
|
|
764
816
|
alignItems: 'center',
|
|
765
|
-
gap: '
|
|
766
|
-
marginTop: '
|
|
817
|
+
gap: '4px',
|
|
818
|
+
marginTop: '8px',
|
|
767
819
|
},
|
|
768
820
|
completionSummary: {
|
|
769
821
|
marginTop: '10px',
|
|
770
822
|
paddingTop: '10px',
|
|
771
|
-
borderTop: '1px solid rgba(0, 0, 0, 0.
|
|
823
|
+
borderTop: '1px solid rgba(0, 0, 0, 0.06)',
|
|
772
824
|
},
|
|
773
825
|
summaryTitle: {
|
|
774
826
|
fontSize: '14px',
|
|
@@ -778,23 +830,24 @@ const STYLES = {
|
|
|
778
830
|
display: 'flex',
|
|
779
831
|
alignItems: 'center',
|
|
780
832
|
gap: '6px',
|
|
833
|
+
lineHeight: '1.45',
|
|
781
834
|
},
|
|
782
835
|
summaryDescription: {
|
|
783
|
-
fontSize: '
|
|
836
|
+
fontSize: '14px',
|
|
784
837
|
color: '#4b5563',
|
|
785
|
-
lineHeight: '1.
|
|
838
|
+
lineHeight: '1.45',
|
|
786
839
|
},
|
|
787
840
|
metricsRow: {
|
|
788
841
|
display: 'flex',
|
|
789
|
-
gap: '
|
|
790
|
-
marginTop: '
|
|
791
|
-
fontSize: '
|
|
842
|
+
gap: '10px',
|
|
843
|
+
marginTop: '6px',
|
|
844
|
+
fontSize: '13px',
|
|
792
845
|
color: '#6b7280',
|
|
793
846
|
},
|
|
794
847
|
metric: {
|
|
795
848
|
display: 'flex',
|
|
796
849
|
alignItems: 'center',
|
|
797
|
-
gap: '
|
|
850
|
+
gap: '4px',
|
|
798
851
|
},
|
|
799
852
|
// Code viewer styles for generated stories
|
|
800
853
|
codeViewerContainer: {
|
|
@@ -820,7 +873,7 @@ const STYLES = {
|
|
|
820
873
|
background: 'rgba(59, 130, 246, 0.15)',
|
|
821
874
|
},
|
|
822
875
|
codeViewerContent: {
|
|
823
|
-
marginTop: '
|
|
876
|
+
marginTop: '12px',
|
|
824
877
|
background: '#1e293b',
|
|
825
878
|
borderRadius: '8px',
|
|
826
879
|
overflow: 'hidden',
|
|
@@ -840,7 +893,7 @@ const STYLES = {
|
|
|
840
893
|
fontFamily: 'ui-monospace, monospace',
|
|
841
894
|
},
|
|
842
895
|
copyButton: {
|
|
843
|
-
padding: '4px
|
|
896
|
+
padding: '4px 12px',
|
|
844
897
|
fontSize: '11px',
|
|
845
898
|
fontWeight: '500',
|
|
846
899
|
color: '#e2e8f0',
|
|
@@ -888,12 +941,12 @@ const STYLES = {
|
|
|
888
941
|
imagePreviewContainer: {
|
|
889
942
|
display: 'flex',
|
|
890
943
|
flexWrap: 'wrap',
|
|
891
|
-
gap: '
|
|
944
|
+
gap: '8px',
|
|
892
945
|
padding: '8px 12px',
|
|
893
946
|
background: 'rgba(255, 255, 255, 0.03)',
|
|
894
947
|
borderBottom: '1px solid rgba(255, 255, 255, 0.08)',
|
|
895
948
|
margin: '0 16px',
|
|
896
|
-
borderRadius: '
|
|
949
|
+
borderRadius: '8px 8px 0 0',
|
|
897
950
|
},
|
|
898
951
|
imagePreviewItem: {
|
|
899
952
|
position: 'relative',
|
|
@@ -929,15 +982,15 @@ const STYLES = {
|
|
|
929
982
|
imagePreviewLabel: {
|
|
930
983
|
display: 'flex',
|
|
931
984
|
alignItems: 'center',
|
|
932
|
-
gap: '
|
|
985
|
+
gap: '8px',
|
|
933
986
|
fontSize: '12px',
|
|
934
987
|
color: '#94a3b8',
|
|
935
988
|
marginRight: 'auto',
|
|
936
989
|
},
|
|
937
990
|
userMessageImages: {
|
|
938
991
|
display: 'flex',
|
|
939
|
-
gap: '
|
|
940
|
-
marginTop: '
|
|
992
|
+
gap: '8px',
|
|
993
|
+
marginTop: '8px',
|
|
941
994
|
flexWrap: 'wrap',
|
|
942
995
|
},
|
|
943
996
|
userMessageImage: {
|
|
@@ -976,24 +1029,138 @@ const STYLES = {
|
|
|
976
1029
|
boxShadow: '0 2px 8px rgba(59, 130, 246, 0.3)',
|
|
977
1030
|
},
|
|
978
1031
|
};
|
|
979
|
-
// Add custom style for loading animation
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
1032
|
+
// Add custom style for loading animation and IBM Plex Sans font
|
|
1033
|
+
// Use a unique ID to prevent duplicate stylesheets during HMR
|
|
1034
|
+
const STYLESHEET_ID = 'story-ui-panel-styles';
|
|
1035
|
+
if (!document.getElementById(STYLESHEET_ID)) {
|
|
1036
|
+
// Load IBM Plex Sans font
|
|
1037
|
+
const fontLink = document.createElement('link');
|
|
1038
|
+
fontLink.rel = 'stylesheet';
|
|
1039
|
+
fontLink.href = 'https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&display=swap';
|
|
1040
|
+
document.head.appendChild(fontLink);
|
|
1041
|
+
const styleSheet = document.createElement('style');
|
|
1042
|
+
styleSheet.id = STYLESHEET_ID;
|
|
1043
|
+
styleSheet.textContent = `
|
|
1044
|
+
@keyframes loadingDots {
|
|
1045
|
+
0%, 20% { content: "."; }
|
|
1046
|
+
40% { content: ".."; }
|
|
1047
|
+
60%, 100% { content: "..."; }
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
.loading-dots::after {
|
|
1051
|
+
content: ".";
|
|
1052
|
+
animation: loadingDots 1.4s infinite;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
/* Override Storybook's default styles with !important */
|
|
1056
|
+
.story-ui-panel,
|
|
1057
|
+
.story-ui-panel * {
|
|
1058
|
+
font-family: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
.story-ui-panel {
|
|
1062
|
+
font-size: 14px !important;
|
|
1063
|
+
line-height: 1.5 !important;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
/* Message bubbles - consistent styling */
|
|
1067
|
+
.story-ui-message {
|
|
1068
|
+
font-size: 16px !important;
|
|
1069
|
+
line-height: 1.45 !important;
|
|
1070
|
+
padding: 12px 16px !important;
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
.story-ui-user-message {
|
|
1074
|
+
background: rgba(59, 130, 246, 0.12) !important;
|
|
1075
|
+
color: #e2e8f0 !important;
|
|
1076
|
+
border-radius: 18px 18px 4px 18px !important;
|
|
1077
|
+
border: 1px solid rgba(59, 130, 246, 0.2) !important;
|
|
1078
|
+
}
|
|
987
1079
|
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1080
|
+
.story-ui-ai-message {
|
|
1081
|
+
background: rgba(255, 255, 255, 0.97) !important;
|
|
1082
|
+
color: #1f2937 !important;
|
|
1083
|
+
border-radius: 18px 18px 18px 4px !important;
|
|
1084
|
+
border: 1px solid rgba(0, 0, 0, 0.08) !important;
|
|
1085
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08) !important;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
/* Override nested elements in AI messages (from renderMarkdown)
|
|
1089
|
+
.story-ui-ai-message p,
|
|
1090
|
+
.story-ui-ai-message span,
|
|
1091
|
+
.story-ui-ai-message strong,
|
|
1092
|
+
.story-ui-ai-message em,
|
|
1093
|
+
.story-ui-ai-message li,
|
|
1094
|
+
.story-ui-ai-message ul,
|
|
1095
|
+
.story-ui-ai-message ol {
|
|
1096
|
+
font-size: 14px !important;
|
|
1097
|
+
line-height: 1.45 !important;
|
|
1098
|
+
margin: 0 !important;
|
|
1099
|
+
} */
|
|
1100
|
+
|
|
1101
|
+
.story-ui-ai-message p + p {
|
|
1102
|
+
margin-top: 8px !important;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
/* Status text */
|
|
1106
|
+
.story-ui-status {
|
|
1107
|
+
font-size: 13px !important;
|
|
1108
|
+
font-weight: 400 !important;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
.story-ui-status-connected {
|
|
1112
|
+
color: #10b981 !important;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
.story-ui-status-disconnected {
|
|
1116
|
+
color: #ef4444 !important;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
/* Sidebar buttons */
|
|
1120
|
+
.story-ui-sidebar button {
|
|
1121
|
+
font-size: 14px !important;
|
|
1122
|
+
font-weight: 600 !important;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
/* Header text */
|
|
1126
|
+
.story-ui-header h1 {
|
|
1127
|
+
font-size: 24px !important;
|
|
1128
|
+
font-weight: 700 !important;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
.story-ui-header p {
|
|
1132
|
+
font-size: 14px !important;
|
|
1133
|
+
color: #94a3b8 !important;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
/* Input field */
|
|
1137
|
+
.story-ui-input {
|
|
1138
|
+
font-size: 14px !important;
|
|
1139
|
+
font-family: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
/* Code blocks in messages */
|
|
1143
|
+
.story-ui-ai-message code {
|
|
1144
|
+
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace !important;
|
|
1145
|
+
font-size: 13px !important;
|
|
1146
|
+
background: rgba(0, 0, 0, 0.06) !important;
|
|
1147
|
+
padding: 2px 6px !important;
|
|
1148
|
+
border-radius: 4px !important;
|
|
1149
|
+
}
|
|
1150
|
+
`;
|
|
1151
|
+
document.head.appendChild(styleSheet);
|
|
1152
|
+
}
|
|
994
1153
|
// Helper function to format timestamp
|
|
995
1154
|
const formatTime = (timestamp) => {
|
|
1155
|
+
// Handle invalid timestamps
|
|
1156
|
+
if (!timestamp || isNaN(timestamp) || timestamp <= 0) {
|
|
1157
|
+
return '';
|
|
1158
|
+
}
|
|
996
1159
|
const date = new Date(timestamp);
|
|
1160
|
+
// Check if the date is valid
|
|
1161
|
+
if (isNaN(date.getTime())) {
|
|
1162
|
+
return '';
|
|
1163
|
+
}
|
|
997
1164
|
const now = new Date();
|
|
998
1165
|
const diffMs = now.getTime() - date.getTime();
|
|
999
1166
|
const diffMins = Math.floor(diffMs / 60000);
|
|
@@ -1009,19 +1176,19 @@ const formatTime = (timestamp) => {
|
|
|
1009
1176
|
return `${diffDays}d ago`;
|
|
1010
1177
|
return date.toLocaleDateString();
|
|
1011
1178
|
};
|
|
1012
|
-
// Helper to get phase
|
|
1179
|
+
// Helper to get phase text (no icons - cleaner UI)
|
|
1013
1180
|
const getPhaseInfo = (phase) => {
|
|
1014
1181
|
const phases = {
|
|
1015
|
-
config_loaded: {
|
|
1016
|
-
components_discovered: {
|
|
1017
|
-
prompt_built: {
|
|
1018
|
-
llm_thinking: {
|
|
1019
|
-
code_extracted: {
|
|
1020
|
-
validating: {
|
|
1021
|
-
post_processing: {
|
|
1022
|
-
saving: {
|
|
1182
|
+
config_loaded: { text: 'Loading configuration' },
|
|
1183
|
+
components_discovered: { text: 'Discovering components' },
|
|
1184
|
+
prompt_built: { text: 'Building prompt' },
|
|
1185
|
+
llm_thinking: { text: 'AI is thinking' },
|
|
1186
|
+
code_extracted: { text: 'Extracting code' },
|
|
1187
|
+
validating: { text: 'Validating output' },
|
|
1188
|
+
post_processing: { text: 'Processing' },
|
|
1189
|
+
saving: { text: 'Saving story' },
|
|
1023
1190
|
};
|
|
1024
|
-
return phases[phase] || {
|
|
1191
|
+
return phases[phase] || { text: 'Working' };
|
|
1025
1192
|
};
|
|
1026
1193
|
// Streaming Progress Message Component
|
|
1027
1194
|
const StreamingProgressMessage = ({ streamingData }) => {
|
|
@@ -1041,20 +1208,20 @@ const StreamingProgressMessage = ({ streamingData }) => {
|
|
|
1041
1208
|
};
|
|
1042
1209
|
// If completed, show completion summary
|
|
1043
1210
|
if (completion) {
|
|
1044
|
-
return (_jsx("div", { style: STYLES.streamingContainer, children: _jsxs("div", { style: STYLES.completionSummary, children: [_jsxs("div", { style: STYLES.summaryTitle, children: [completion.success ?
|
|
1211
|
+
return (_jsx("div", { style: STYLES.streamingContainer, children: _jsxs("div", { style: STYLES.completionSummary, children: [_jsxs("div", { style: STYLES.summaryTitle, children: [completion.success ? StatusIcons.success : StatusIcons.error, " ", completion.title] }), _jsx("div", { style: STYLES.summaryDescription, children: completion.summary.description }), completion.componentsUsed.length > 0 && (_jsxs("div", { style: { marginTop: '12px' }, children: [_jsx("div", { style: { fontSize: '12px', color: '#6b7280', marginBottom: '8px' }, children: "Components used:" }), _jsx("div", { style: STYLES.intentComponents, children: completion.componentsUsed.map((comp, i) => (_jsx("span", { style: STYLES.componentTag, children: comp.name }, i))) })] })), completion.layoutChoices.length > 0 && (_jsxs("div", { style: { marginTop: '12px' }, children: [_jsx("div", { style: { fontSize: '12px', color: '#6b7280', marginBottom: '8px' }, children: "Layout:" }), _jsx("div", { style: { fontSize: '12px', color: '#4b5563' }, children: completion.layoutChoices.map(l => l.pattern).join(', ') })] })), completion.validation && !completion.validation.isValid && (_jsx("div", { style: { ...STYLES.validationBox, ...STYLES.validationWarning }, children: completion.validation.autoFixApplied ? 'Auto-fixed issues' : 'Minor issues detected' })), completion.suggestions && completion.suggestions.length > 0 && (_jsxs("div", { style: { marginTop: '12px', fontSize: '12px', color: '#6b7280', display: 'flex', alignItems: 'flex-start', gap: '6px' }, children: [StatusIcons.tip, " ", _jsx("span", { children: completion.suggestions[0] })] })), completion.metrics && (_jsxs("div", { style: STYLES.metricsRow, children: [_jsxs("span", { style: STYLES.metric, children: [(completion.metrics.totalTimeMs / 1000).toFixed(1), "s"] }), _jsxs("span", { style: STYLES.metric, children: [completion.metrics.llmCallsCount, " LLM calls"] })] })), completion.code && (_jsxs("div", { style: STYLES.codeViewerContainer, children: [_jsxs("div", { style: STYLES.codeViewerToggle, onClick: () => setShowCode(!showCode), role: "button", tabIndex: 0, onKeyDown: (e) => e.key === 'Enter' && setShowCode(!showCode), children: [_jsxs("span", { children: [showCode ? '▼' : '▶', " View Generated Code"] }), _jsx("span", { style: { fontSize: '11px', color: '#6366f1' }, children: completion.fileName })] }), showCode && (_jsxs("div", { style: STYLES.codeViewerContent, children: [_jsxs("div", { style: STYLES.codeViewerHeader, children: [_jsx("span", { style: STYLES.codeViewerFileName, children: completion.fileName }), _jsx("button", { style: {
|
|
1045
1212
|
...STYLES.copyButton,
|
|
1046
1213
|
...(copyStatus === 'copied' ? STYLES.copyButtonSuccess : {})
|
|
1047
|
-
}, onClick: () => handleCopyCode(completion.code), children: copyStatus === 'copied' ? '
|
|
1214
|
+
}, onClick: () => handleCopyCode(completion.code), children: copyStatus === 'copied' ? 'Copied' : 'Copy' })] }), _jsx("pre", { style: STYLES.codeViewerPre, children: _jsx("code", { children: completion.code }) })] }))] }))] }) }));
|
|
1048
1215
|
}
|
|
1049
1216
|
// If error, show error
|
|
1050
1217
|
if (error) {
|
|
1051
|
-
return (_jsx("div", { style: STYLES.streamingContainer, children: _jsxs("div", { style: { ...STYLES.validationBox, ...STYLES.validationError }, children: [_jsxs("strong", { children: ["
|
|
1218
|
+
return (_jsx("div", { style: STYLES.streamingContainer, children: _jsxs("div", { style: { ...STYLES.validationBox, ...STYLES.validationError }, children: [_jsxs("strong", { style: { display: 'flex', alignItems: 'center', gap: '6px' }, children: [StatusIcons.error, " ", error.message] }), error.details && _jsx("div", { style: { marginTop: '4px' }, children: error.details }), error.suggestion && _jsxs("div", { style: { marginTop: '8px', display: 'flex', alignItems: 'flex-start', gap: '6px' }, children: [StatusIcons.tip, " ", _jsx("span", { children: error.suggestion })] })] }) }));
|
|
1052
1219
|
}
|
|
1053
1220
|
// Show progress - simplified to just show status without verbose details
|
|
1054
|
-
return (_jsxs("div", { style: STYLES.streamingContainer, children: [_jsxs("div", { style: STYLES.intentPreview, children: [_jsxs("div", { style: STYLES.progressPhase, children: [_jsx("span", {
|
|
1221
|
+
return (_jsxs("div", { style: STYLES.streamingContainer, children: [_jsxs("div", { style: STYLES.intentPreview, children: [_jsxs("div", { style: STYLES.progressPhase, children: [_jsx("span", { children: "Generating story..." }), progress && (_jsxs("span", { style: { marginLeft: 'auto', color: '#9ca3af' }, children: [progress.step, "/", progress.totalSteps] }))] }), progress && (_jsx("div", { style: { ...STYLES.progressBar, marginTop: '8px' }, children: _jsx("div", { style: {
|
|
1055
1222
|
...STYLES.progressFill,
|
|
1056
1223
|
width: `${(progress.step / progress.totalSteps) * 100}%`
|
|
1057
|
-
} }) }))] }), retry && (_jsxs("div", { style: STYLES.retryBadge, children: ["
|
|
1224
|
+
} }) }))] }), retry && (_jsxs("div", { style: STYLES.retryBadge, children: ["Retry ", retry.attempt, "/", retry.maxAttempts, ": ", retry.reason] })), !progress && !intent && (_jsx("div", { style: STYLES.progressPhase, children: _jsx("span", { className: "loading-dots", children: "Connecting" }) }))] }));
|
|
1058
1225
|
};
|
|
1059
1226
|
// Main component
|
|
1060
1227
|
function StoryUIPanel() {
|
|
@@ -1073,6 +1240,7 @@ function StoryUIPanel() {
|
|
|
1073
1240
|
const [streamingState, setStreamingState] = useState(null);
|
|
1074
1241
|
const [attachedImages, setAttachedImages] = useState([]);
|
|
1075
1242
|
const [considerations, setConsiderations] = useState('');
|
|
1243
|
+
const [orphanStories, setOrphanStories] = useState([]);
|
|
1076
1244
|
const chatEndRef = useRef(null);
|
|
1077
1245
|
const inputRef = useRef(null);
|
|
1078
1246
|
const fileInputRef = useRef(null);
|
|
@@ -1319,6 +1487,9 @@ function StoryUIPanel() {
|
|
|
1319
1487
|
setActiveChatId(sortedChats[0].id);
|
|
1320
1488
|
setActiveTitle(sortedChats[0].title);
|
|
1321
1489
|
}
|
|
1490
|
+
// Fetch orphan stories (stories on disk without chat history)
|
|
1491
|
+
const orphans = await fetchOrphanStories();
|
|
1492
|
+
setOrphanStories(orphans);
|
|
1322
1493
|
}
|
|
1323
1494
|
else {
|
|
1324
1495
|
// Load from local storage if server is not available
|
|
@@ -1421,10 +1592,10 @@ function StoryUIPanel() {
|
|
|
1421
1592
|
// In Edge mode, stories are stored in Durable Objects, not on filesystem
|
|
1422
1593
|
if (!isUpdate && !hasShownRefreshHint.current) {
|
|
1423
1594
|
if (isEdgeMode()) {
|
|
1424
|
-
parts.push(`\n\n_Story saved to cloud. View code in chat history
|
|
1595
|
+
parts.push(`\n\n_Story saved to cloud. View code in chat history recent chats navigation._`);
|
|
1425
1596
|
}
|
|
1426
1597
|
else {
|
|
1427
|
-
parts.push(`\n\
|
|
1598
|
+
parts.push(`\n\n_Might need toefresh Storybook (Cmd/Ctrl + R) to see new stories in the sidebar._`);
|
|
1428
1599
|
}
|
|
1429
1600
|
hasShownRefreshHint.current = true;
|
|
1430
1601
|
}
|
|
@@ -1460,10 +1631,6 @@ function StoryUIPanel() {
|
|
|
1460
1631
|
}
|
|
1461
1632
|
saveChats(chats);
|
|
1462
1633
|
setRecentChats(chats);
|
|
1463
|
-
// Store code for Source Code panel
|
|
1464
|
-
if (completion.code) {
|
|
1465
|
-
storeGeneratedCode(activeChatId, completion.code, activeTitle || completion.title);
|
|
1466
|
-
}
|
|
1467
1634
|
}
|
|
1468
1635
|
else {
|
|
1469
1636
|
const chatId = completion.storyId || completion.fileName || Date.now().toString();
|
|
@@ -1488,10 +1655,6 @@ function StoryUIPanel() {
|
|
|
1488
1655
|
// This prevents the "Couldn't find story after HMR" error by refreshing
|
|
1489
1656
|
// after the file system has been updated and HMR has processed the change
|
|
1490
1657
|
navigateToNewStory(chatTitle, completion.code);
|
|
1491
|
-
// Store code for Source Code panel
|
|
1492
|
-
if (completion.code) {
|
|
1493
|
-
storeGeneratedCode(chatId, completion.code, chatTitle);
|
|
1494
|
-
}
|
|
1495
1658
|
}
|
|
1496
1659
|
}, [activeChatId, activeTitle, conversation.length]);
|
|
1497
1660
|
const handleSend = async (e) => {
|
|
@@ -1637,13 +1800,13 @@ function StoryUIPanel() {
|
|
|
1637
1800
|
const data = await handleSendNonStreaming(userInput, newConversation);
|
|
1638
1801
|
// Process non-streaming response (same as before)
|
|
1639
1802
|
let responseMessage;
|
|
1640
|
-
const
|
|
1803
|
+
const statusMarker = data.validation?.hasWarnings ? (data.validation.errors?.length > 0 ? '[WRENCH]' : '[TIP]') : '[SUCCESS]';
|
|
1641
1804
|
// Build conversational response for fallback
|
|
1642
1805
|
if (data.isUpdate) {
|
|
1643
|
-
responseMessage = `${
|
|
1806
|
+
responseMessage = `${statusMarker} **Updated: "${data.title}"**\n\nI've made the requested changes to your component. You can view the updated version in Storybook.\n\n_Check the Docs tab to see both the rendered component and its code._`;
|
|
1644
1807
|
}
|
|
1645
1808
|
else {
|
|
1646
|
-
responseMessage = `${
|
|
1809
|
+
responseMessage = `${statusMarker} **Created: "${data.title}"**\n\nI've generated the component with the requested features. You can view it in Storybook where you'll see both the rendered component and its markup.\n\n[TIP] **Note**: If you don't see the story immediately, you may need to refresh your Storybook page (Cmd/Ctrl + R).`;
|
|
1647
1810
|
}
|
|
1648
1811
|
const aiMsg = { role: 'ai', content: responseMessage };
|
|
1649
1812
|
const updatedConversation = [...newConversation, aiMsg];
|
|
@@ -1664,10 +1827,6 @@ function StoryUIPanel() {
|
|
|
1664
1827
|
chats[chatIndex] = updatedSession;
|
|
1665
1828
|
saveChats(chats);
|
|
1666
1829
|
setRecentChats(chats);
|
|
1667
|
-
// Store code for Source Code panel
|
|
1668
|
-
if (data.code) {
|
|
1669
|
-
storeGeneratedCode(activeChatId, data.code, activeTitle || data.title);
|
|
1670
|
-
}
|
|
1671
1830
|
}
|
|
1672
1831
|
else {
|
|
1673
1832
|
const chatId = data.storyId || data.fileName || Date.now().toString();
|
|
@@ -1689,10 +1848,6 @@ function StoryUIPanel() {
|
|
|
1689
1848
|
setRecentChats(chats);
|
|
1690
1849
|
// Auto-navigate to the newly created story
|
|
1691
1850
|
navigateToNewStory(chatTitle, data.code);
|
|
1692
|
-
// Store code for Source Code panel
|
|
1693
|
-
if (data.code) {
|
|
1694
|
-
storeGeneratedCode(chatId, data.code, chatTitle);
|
|
1695
|
-
}
|
|
1696
1851
|
}
|
|
1697
1852
|
}
|
|
1698
1853
|
catch (fallbackErr) {
|
|
@@ -1713,13 +1868,13 @@ function StoryUIPanel() {
|
|
|
1713
1868
|
try {
|
|
1714
1869
|
const data = await handleSendNonStreaming(userInput, newConversation);
|
|
1715
1870
|
let responseMessage;
|
|
1716
|
-
const
|
|
1871
|
+
const statusMarker = data.validation?.hasWarnings ? (data.validation.errors?.length > 0 ? '[WRENCH]' : '[TIP]') : '[SUCCESS]';
|
|
1717
1872
|
// Build conversational response for non-streaming mode
|
|
1718
1873
|
if (data.isUpdate) {
|
|
1719
|
-
responseMessage = `${
|
|
1874
|
+
responseMessage = `${statusMarker} **Updated: "${data.title}"**\n\nI've made the requested changes to your component. You can view the updated version in Storybook.\n\n_Check the Docs tab to see both the rendered component and its code._`;
|
|
1720
1875
|
}
|
|
1721
1876
|
else {
|
|
1722
|
-
responseMessage = `${
|
|
1877
|
+
responseMessage = `${statusMarker} **Created: "${data.title}"**\n\nI've generated the component with the requested features. You can view it in Storybook where you'll see both the rendered component and its markup.\n\n[TIP] **Note**: If you don't see the story immediately, you may need to refresh your Storybook page (Cmd/Ctrl + R).`;
|
|
1723
1878
|
}
|
|
1724
1879
|
const aiMsg = { role: 'ai', content: responseMessage };
|
|
1725
1880
|
const updatedConversation = [...newConversation, aiMsg];
|
|
@@ -1739,10 +1894,6 @@ function StoryUIPanel() {
|
|
|
1739
1894
|
chats[chatIndex] = updatedSession;
|
|
1740
1895
|
saveChats(chats);
|
|
1741
1896
|
setRecentChats(chats);
|
|
1742
|
-
// Store code for Source Code panel
|
|
1743
|
-
if (data.code) {
|
|
1744
|
-
storeGeneratedCode(activeChatId, data.code, activeTitle || data.title);
|
|
1745
|
-
}
|
|
1746
1897
|
}
|
|
1747
1898
|
else {
|
|
1748
1899
|
const chatId = data.storyId || data.fileName || Date.now().toString();
|
|
@@ -1762,10 +1913,6 @@ function StoryUIPanel() {
|
|
|
1762
1913
|
chats.splice(MAX_RECENT_CHATS);
|
|
1763
1914
|
saveChats(chats);
|
|
1764
1915
|
setRecentChats(chats);
|
|
1765
|
-
// Store code for Source Code panel
|
|
1766
|
-
if (data.code) {
|
|
1767
|
-
storeGeneratedCode(chatId, data.code, chatTitle);
|
|
1768
|
-
}
|
|
1769
1916
|
}
|
|
1770
1917
|
}
|
|
1771
1918
|
catch (err) {
|
|
@@ -1814,22 +1961,22 @@ function StoryUIPanel() {
|
|
|
1814
1961
|
}
|
|
1815
1962
|
}
|
|
1816
1963
|
};
|
|
1817
|
-
return (_jsxs("div", { style: STYLES.container, children: [_jsxs("div", { style: {
|
|
1964
|
+
return (_jsxs("div", { className: "story-ui-panel", style: STYLES.container, children: [_jsxs("div", { style: {
|
|
1818
1965
|
...STYLES.sidebar,
|
|
1819
1966
|
...(sidebarOpen ? {} : STYLES.sidebarCollapsed),
|
|
1820
1967
|
}, children: [sidebarOpen && (_jsxs("div", { style: { flex: 1, overflowY: 'auto', padding: '16px' }, children: [_jsxs("button", { onClick: () => setSidebarOpen(false), style: STYLES.sidebarToggle, title: "Collapse sidebar", onMouseEnter: (e) => {
|
|
1821
|
-
e.currentTarget.style.
|
|
1822
|
-
e.currentTarget.style.
|
|
1968
|
+
e.currentTarget.style.background = 'rgba(59, 130, 246, 0.25)';
|
|
1969
|
+
e.currentTarget.style.borderColor = 'rgba(59, 130, 246, 0.5)';
|
|
1823
1970
|
}, onMouseLeave: (e) => {
|
|
1824
|
-
e.currentTarget.style.
|
|
1825
|
-
e.currentTarget.style.
|
|
1826
|
-
}, children: [_jsx("
|
|
1827
|
-
e.currentTarget.style.
|
|
1828
|
-
e.currentTarget.style.boxShadow = '0 4px
|
|
1971
|
+
e.currentTarget.style.background = 'rgba(59, 130, 246, 0.15)';
|
|
1972
|
+
e.currentTarget.style.borderColor = 'rgba(59, 130, 246, 0.3)';
|
|
1973
|
+
}, children: [_jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) }), _jsx("span", { children: "Chats" })] }), _jsxs("button", { onClick: handleNewChat, style: STYLES.newChatButton, onMouseEnter: (e) => {
|
|
1974
|
+
e.currentTarget.style.background = '#2563eb';
|
|
1975
|
+
e.currentTarget.style.boxShadow = '0 4px 12px rgba(59, 130, 246, 0.4)';
|
|
1829
1976
|
}, onMouseLeave: (e) => {
|
|
1830
|
-
e.currentTarget.style.
|
|
1831
|
-
e.currentTarget.style.boxShadow = '0 2px 8px rgba(59, 130, 246, 0.
|
|
1832
|
-
}, children: [
|
|
1977
|
+
e.currentTarget.style.background = '#3b82f6';
|
|
1978
|
+
e.currentTarget.style.boxShadow = '0 2px 8px rgba(59, 130, 246, 0.25)';
|
|
1979
|
+
}, children: [_jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }), _jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })] }), _jsx("span", { children: "New Chat" })] }), recentChats.length > 0 && (_jsx("div", { style: {
|
|
1833
1980
|
color: '#64748b',
|
|
1834
1981
|
fontSize: '12px',
|
|
1835
1982
|
marginBottom: '8px',
|
|
@@ -1853,7 +2000,45 @@ function StoryUIPanel() {
|
|
|
1853
2000
|
const deleteBtn = e.currentTarget.querySelector('.delete-btn');
|
|
1854
2001
|
if (deleteBtn)
|
|
1855
2002
|
deleteBtn.style.opacity = '0';
|
|
1856
|
-
}, children: [_jsx("div", { style: STYLES.chatItemTitle, children: chat.title }), _jsx("div", { style: STYLES.chatItemTime, children: formatTime(chat.lastUpdated) }), _jsx("button", { className: "delete-btn", onClick: (e) => handleDeleteChat(chat.id, e), style: STYLES.deleteButton, title: "Delete chat", children: "
|
|
2003
|
+
}, children: [_jsx("div", { style: STYLES.chatItemTitle, children: chat.title }), _jsx("div", { style: STYLES.chatItemTime, children: formatTime(chat.lastUpdated) }), _jsx("button", { className: "delete-btn", onClick: (e) => handleDeleteChat(chat.id, e), style: STYLES.deleteButton, title: "Delete chat", children: _jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), _jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) })] }, chat.id))), orphanStories.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { style: {
|
|
2004
|
+
color: '#64748b',
|
|
2005
|
+
fontSize: '12px',
|
|
2006
|
+
marginTop: '16px',
|
|
2007
|
+
marginBottom: '8px',
|
|
2008
|
+
fontWeight: '500',
|
|
2009
|
+
textTransform: 'uppercase',
|
|
2010
|
+
letterSpacing: '0.05em',
|
|
2011
|
+
}, children: "Generated Files" }), orphanStories.map(story => (_jsxs("div", { style: {
|
|
2012
|
+
...STYLES.chatItem,
|
|
2013
|
+
background: 'rgba(251, 191, 36, 0.1)',
|
|
2014
|
+
borderLeft: '3px solid rgba(251, 191, 36, 0.5)',
|
|
2015
|
+
}, onMouseEnter: (e) => {
|
|
2016
|
+
e.currentTarget.style.background = 'rgba(251, 191, 36, 0.15)';
|
|
2017
|
+
const deleteBtn = e.currentTarget.querySelector('.delete-orphan-btn');
|
|
2018
|
+
if (deleteBtn)
|
|
2019
|
+
deleteBtn.style.opacity = '1';
|
|
2020
|
+
}, onMouseLeave: (e) => {
|
|
2021
|
+
e.currentTarget.style.background = 'rgba(251, 191, 36, 0.1)';
|
|
2022
|
+
const deleteBtn = e.currentTarget.querySelector('.delete-orphan-btn');
|
|
2023
|
+
if (deleteBtn)
|
|
2024
|
+
deleteBtn.style.opacity = '0';
|
|
2025
|
+
}, children: [_jsx("div", { style: STYLES.chatItemTitle, children: story.title }), _jsx("div", { style: { ...STYLES.chatItemTime, fontSize: '11px' }, children: story.fileName }), _jsx("button", { className: "delete-orphan-btn", onClick: async (e) => {
|
|
2026
|
+
e.stopPropagation();
|
|
2027
|
+
try {
|
|
2028
|
+
const response = await fetch(`${STORIES_API}/${story.id}`, {
|
|
2029
|
+
method: 'DELETE',
|
|
2030
|
+
});
|
|
2031
|
+
if (response.ok) {
|
|
2032
|
+
setOrphanStories(prev => prev.filter(s => s.id !== story.id));
|
|
2033
|
+
}
|
|
2034
|
+
else {
|
|
2035
|
+
console.error('Failed to delete orphan story');
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
catch (err) {
|
|
2039
|
+
console.error('Error deleting orphan story:', err);
|
|
2040
|
+
}
|
|
2041
|
+
}, style: STYLES.deleteButton, title: "Delete generated file", children: _jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), _jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) })] }, story.id)))] }))] })), !sidebarOpen && (_jsx("div", { style: { padding: '8px', display: 'flex', justifyContent: 'center' }, children: _jsx("button", { onClick: () => setSidebarOpen(true), style: {
|
|
1857
2042
|
...STYLES.sidebarToggle,
|
|
1858
2043
|
width: '38px',
|
|
1859
2044
|
height: '38px',
|
|
@@ -1866,33 +2051,34 @@ function StoryUIPanel() {
|
|
|
1866
2051
|
}, onMouseLeave: (e) => {
|
|
1867
2052
|
e.currentTarget.style.transform = 'scale(1)';
|
|
1868
2053
|
e.currentTarget.style.background = '#3b82f6';
|
|
1869
|
-
}, children: _jsx("
|
|
1870
|
-
fontSize: '
|
|
2054
|
+
}, children: _jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("line", { x1: "3", y1: "6", x2: "21", y2: "6" }), _jsx("line", { x1: "3", y1: "12", x2: "21", y2: "12" }), _jsx("line", { x1: "3", y1: "18", x2: "21", y2: "18" })] }) }) }))] }), _jsxs("div", { style: { ...STYLES.mainContent, position: 'relative' }, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, children: [isDragging && (_jsx("div", { style: STYLES.dropOverlay, children: _jsxs("div", { style: STYLES.dropOverlayText, children: [_jsx("svg", { width: 24, height: 24, viewBox: "0 0 24 24", fill: "currentColor", children: _jsx("path", { d: "M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z" }) }), "Drop images here"] }) })), _jsxs("div", { style: STYLES.chatHeader, children: [_jsx("h1", { style: {
|
|
2055
|
+
fontSize: '22px',
|
|
1871
2056
|
margin: 0,
|
|
1872
|
-
fontWeight: '
|
|
2057
|
+
fontWeight: '700',
|
|
1873
2058
|
background: 'linear-gradient(135deg, #60a5fa 0%, #3b82f6 100%)',
|
|
1874
2059
|
WebkitBackgroundClip: 'text',
|
|
1875
2060
|
WebkitTextFillColor: 'transparent',
|
|
1876
|
-
display: 'inline-block'
|
|
1877
|
-
|
|
2061
|
+
display: 'inline-block',
|
|
2062
|
+
letterSpacing: '-0.02em'
|
|
2063
|
+
}, children: "Story UI" }), _jsx("p", { style: { fontSize: '14px', margin: '6px 0 0 0', color: '#94a3b8', fontWeight: '500' }, children: "Generate Storybook stories with AI" }), _jsxs("div", { style: {
|
|
1878
2064
|
display: 'flex',
|
|
1879
2065
|
alignItems: 'center',
|
|
1880
|
-
gap: '
|
|
1881
|
-
marginTop: '
|
|
1882
|
-
fontSize: '
|
|
2066
|
+
gap: '6px',
|
|
2067
|
+
marginTop: '10px',
|
|
2068
|
+
fontSize: '11px'
|
|
1883
2069
|
}, children: [_jsx("div", { style: {
|
|
1884
|
-
width: '
|
|
1885
|
-
height: '
|
|
2070
|
+
width: '6px',
|
|
2071
|
+
height: '6px',
|
|
1886
2072
|
borderRadius: '50%',
|
|
1887
2073
|
backgroundColor: connectionStatus.connected ? '#10b981' : '#f87171'
|
|
1888
|
-
} }), _jsx("span", { style: { color: connectionStatus.connected ? '#10b981' : '#
|
|
2074
|
+
} }), _jsx("span", { className: `story-ui-status ${connectionStatus.connected ? 'story-ui-status-connected' : 'story-ui-status-disconnected'}`, style: { color: connectionStatus.connected ? '#10b981' : '#ef4444', fontWeight: '400' }, children: connectionStatus.connected
|
|
1889
2075
|
? `Connected to ${getConnectionDisplayText()}`
|
|
1890
2076
|
: `Disconnected: ${connectionStatus.error || 'Server not running'}` })] }), connectionStatus.connected && availableProviders.length > 0 && (_jsxs("div", { style: {
|
|
1891
2077
|
display: 'flex',
|
|
1892
2078
|
gap: '12px',
|
|
1893
2079
|
marginTop: '12px',
|
|
1894
2080
|
flexWrap: 'wrap'
|
|
1895
|
-
}, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '
|
|
2081
|
+
}, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '8px' }, children: [_jsx("label", { style: { fontSize: '12px', color: '#94a3b8', fontWeight: '500' }, children: "Provider:" }), _jsx("select", { value: selectedProvider, onChange: (e) => {
|
|
1896
2082
|
const newProvider = e.target.value;
|
|
1897
2083
|
setSelectedProvider(newProvider);
|
|
1898
2084
|
// Reset model to first available for new provider
|
|
@@ -1908,7 +2094,7 @@ function StoryUIPanel() {
|
|
|
1908
2094
|
padding: '4px 8px',
|
|
1909
2095
|
fontSize: '12px',
|
|
1910
2096
|
cursor: 'pointer'
|
|
1911
|
-
}, children: availableProviders.map(p => (_jsx("option", { value: p.type, children: p.name }, p.type))) })] }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '
|
|
2097
|
+
}, children: availableProviders.map(p => (_jsx("option", { value: p.type, children: p.name }, p.type))) })] }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '8px' }, children: [_jsx("label", { style: { fontSize: '12px', color: '#94a3b8', fontWeight: '500' }, children: "Model:" }), _jsx("select", { value: selectedModel, onChange: (e) => setSelectedModel(e.target.value), style: {
|
|
1912
2098
|
background: '#1e293b',
|
|
1913
2099
|
border: '1px solid #334155',
|
|
1914
2100
|
borderRadius: '6px',
|
|
@@ -1919,9 +2105,9 @@ function StoryUIPanel() {
|
|
|
1919
2105
|
maxWidth: '200px'
|
|
1920
2106
|
}, children: availableProviders
|
|
1921
2107
|
.find(p => p.type === selectedProvider)
|
|
1922
|
-
?.models.map(model => (_jsx("option", { value: model, children: model }, model))) })] })] }))] }), _jsxs("div", { style: STYLES.chatContainer, children: [error && (_jsx("div", { style: STYLES.errorMessage, children: error })), conversation.length === 0 && !loading && (_jsxs("div", { style: STYLES.emptyState, children: [_jsx("div", { style: STYLES.emptyStateTitle, children: "Start a new conversation" }), _jsx("div", { style: STYLES.emptyStateSubtitle, children: "Describe the UI component you'd like to create" })] })), conversation.map((msg, i) => (_jsx("div", { style: STYLES.messageContainer, children: _jsxs("div", { style: msg.role === 'user' ? STYLES.userMessage : STYLES.aiMessage, children: [msg.role === 'ai' ? renderMarkdown(msg.content) : msg.content, msg.role === 'user' && msg.attachedImages && msg.attachedImages.length > 0 && (_jsx("div", { style: STYLES.userMessageImages, children: msg.attachedImages.map((img) => (_jsx("img", { src: img.base64
|
|
2108
|
+
?.models.map(model => (_jsx("option", { value: model, children: getModelDisplayName(model) }, model))) })] })] }))] }), _jsxs("div", { style: STYLES.chatContainer, children: [error && (_jsx("div", { style: STYLES.errorMessage, children: error })), conversation.length === 0 && !loading && (_jsxs("div", { style: STYLES.emptyState, children: [_jsx("div", { style: STYLES.emptyStateTitle, children: "Start a new conversation" }), _jsx("div", { style: STYLES.emptyStateSubtitle, children: "Describe the UI component you'd like to create" })] })), conversation.map((msg, i) => (_jsx("div", { style: STYLES.messageContainer, children: _jsxs("div", { className: `story-ui-message ${msg.role === 'user' ? 'story-ui-user-message' : 'story-ui-ai-message'}`, style: msg.role === 'user' ? STYLES.userMessage : STYLES.aiMessage, children: [msg.role === 'ai' ? renderMarkdown(msg.content) : msg.content, msg.role === 'user' && msg.attachedImages && msg.attachedImages.length > 0 && (_jsx("div", { style: STYLES.userMessageImages, children: msg.attachedImages.map((img) => (_jsx("img", { src: img.base64
|
|
1923
2109
|
? `data:${img.mediaType || 'image/png'};base64,${img.base64}`
|
|
1924
|
-
: img.preview, alt: "attached", style: STYLES.userMessageImage }, img.id))) }))] }) }, i))), loading && (_jsx("div", { style: STYLES.messageContainer, children: streamingState ? (_jsx(StreamingProgressMessage, { streamingData: streamingState })) : (_jsxs("div", { style: STYLES.loadingMessage, children: [_jsx("span", { children: "Generating story" }), _jsx("span", { className: "loading-dots" })] })) })), _jsx("div", { ref: chatEndRef })] }), _jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", multiple: true, style: { display: 'none' }, onChange: handleFileSelect }), attachedImages.length > 0 && (_jsxs("div", { style: STYLES.imagePreviewContainer, children: [_jsxs("span", { style: STYLES.imagePreviewLabel, children: [_jsx("svg", { width: 14, height: 14, viewBox: "0 0 24 24", fill: "currentColor", children: _jsx("path", { d: "M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z" }) }), attachedImages.length, " image", attachedImages.length > 1 ? 's' : '', " attached"] }), attachedImages.map((img) => (_jsxs("div", { style: STYLES.imagePreviewItem, children: [_jsx("img", { src: img.preview, alt: "preview", style: STYLES.imagePreviewImg }), _jsx("button", { type: "button", style: STYLES.imageRemoveButton, onClick: () => removeAttachedImage(img.id), title: "Remove image", children: "
|
|
2110
|
+
: img.preview, alt: "attached", style: STYLES.userMessageImage }, img.id))) }))] }) }, i))), loading && (_jsx("div", { style: STYLES.messageContainer, children: streamingState ? (_jsx(StreamingProgressMessage, { streamingData: streamingState })) : (_jsxs("div", { style: STYLES.loadingMessage, children: [_jsx("span", { children: "Generating story" }), _jsx("span", { className: "loading-dots" })] })) })), _jsx("div", { ref: chatEndRef })] }), _jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", multiple: true, style: { display: 'none' }, onChange: handleFileSelect }), attachedImages.length > 0 && (_jsxs("div", { style: STYLES.imagePreviewContainer, children: [_jsxs("span", { style: STYLES.imagePreviewLabel, children: [_jsx("svg", { width: 14, height: 14, viewBox: "0 0 24 24", fill: "currentColor", children: _jsx("path", { d: "M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z" }) }), attachedImages.length, " image", attachedImages.length > 1 ? 's' : '', " attached"] }), attachedImages.map((img) => (_jsxs("div", { style: STYLES.imagePreviewItem, children: [_jsx("img", { src: img.preview, alt: "preview", style: STYLES.imagePreviewImg }), _jsx("button", { type: "button", style: STYLES.imageRemoveButton, onClick: () => removeAttachedImage(img.id), title: "Remove image", children: _jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), _jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) })] }, img.id)))] })), _jsxs("form", { onSubmit: handleSend, style: {
|
|
1925
2111
|
...STYLES.inputForm,
|
|
1926
2112
|
...(attachedImages.length > 0 ? {
|
|
1927
2113
|
marginTop: 0,
|
|
@@ -1955,20 +2141,22 @@ function StoryUIPanel() {
|
|
|
1955
2141
|
} }), _jsxs("button", { type: "submit", disabled: loading || (!input.trim() && attachedImages.length === 0), style: {
|
|
1956
2142
|
...STYLES.sendButton,
|
|
1957
2143
|
...(loading || (!input.trim() && attachedImages.length === 0) ? {
|
|
1958
|
-
opacity: 0.
|
|
2144
|
+
opacity: 0.4,
|
|
1959
2145
|
cursor: 'not-allowed',
|
|
1960
|
-
background: '#
|
|
2146
|
+
background: '#64748b',
|
|
1961
2147
|
boxShadow: 'none'
|
|
1962
2148
|
} : {})
|
|
1963
2149
|
}, onMouseEnter: (e) => {
|
|
1964
2150
|
if (!loading && (input.trim() || attachedImages.length > 0)) {
|
|
1965
|
-
e.currentTarget.style.
|
|
1966
|
-
e.currentTarget.style.boxShadow = '0 4px 16px rgba(
|
|
2151
|
+
e.currentTarget.style.background = '#2563eb';
|
|
2152
|
+
e.currentTarget.style.boxShadow = '0 4px 16px rgba(59, 130, 246, 0.5)';
|
|
1967
2153
|
}
|
|
1968
2154
|
}, onMouseLeave: (e) => {
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
2155
|
+
if (!loading && (input.trim() || attachedImages.length > 0)) {
|
|
2156
|
+
e.currentTarget.style.background = '#3b82f6';
|
|
2157
|
+
e.currentTarget.style.boxShadow = '0 2px 8px rgba(59, 130, 246, 0.35)';
|
|
2158
|
+
}
|
|
2159
|
+
}, children: [_jsx("svg", { width: 18, height: 18, viewBox: "0 0 24 24", fill: "currentColor", children: _jsx("path", { d: "M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" }) }), _jsx("span", { children: "Send" })] })] })] })] }));
|
|
1972
2160
|
}
|
|
1973
2161
|
export default StoryUIPanel;
|
|
1974
2162
|
export { StoryUIPanel };
|