@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.
Files changed (44) hide show
  1. package/README.md +36 -32
  2. package/dist/cli/index.js +0 -5
  3. package/dist/cli/setup.js +1 -1
  4. package/dist/mcp-server/routes/generateStory.d.ts.map +1 -1
  5. package/dist/mcp-server/routes/generateStory.js +142 -87
  6. package/dist/mcp-server/routes/generateStoryStream.d.ts.map +1 -1
  7. package/dist/mcp-server/routes/generateStoryStream.js +149 -31
  8. package/dist/story-generator/dynamicPackageDiscovery.d.ts +35 -2
  9. package/dist/story-generator/dynamicPackageDiscovery.d.ts.map +1 -1
  10. package/dist/story-generator/dynamicPackageDiscovery.js +332 -6
  11. package/dist/story-generator/enhancedComponentDiscovery.d.ts.map +1 -1
  12. package/dist/story-generator/enhancedComponentDiscovery.js +149 -2
  13. package/dist/story-generator/framework-adapters/base-adapter.d.ts +1 -0
  14. package/dist/story-generator/framework-adapters/base-adapter.d.ts.map +1 -1
  15. package/dist/story-generator/framework-adapters/base-adapter.js +12 -2
  16. package/dist/story-generator/framework-adapters/react-adapter.d.ts.map +1 -1
  17. package/dist/story-generator/framework-adapters/react-adapter.js +2 -0
  18. package/dist/story-generator/framework-adapters/svelte-adapter.d.ts.map +1 -1
  19. package/dist/story-generator/framework-adapters/svelte-adapter.js +53 -7
  20. package/dist/story-generator/framework-adapters/vue-adapter.d.ts.map +1 -1
  21. package/dist/story-generator/framework-adapters/vue-adapter.js +21 -1
  22. package/dist/story-generator/framework-adapters/web-components-adapter.d.ts.map +1 -1
  23. package/dist/story-generator/framework-adapters/web-components-adapter.js +4 -0
  24. package/dist/story-generator/llm-providers/openai-provider.js +2 -2
  25. package/dist/story-generator/promptGenerator.d.ts.map +1 -1
  26. package/dist/story-generator/promptGenerator.js +179 -26
  27. package/dist/story-generator/selfHealingLoop.d.ts +112 -0
  28. package/dist/story-generator/selfHealingLoop.d.ts.map +1 -0
  29. package/dist/story-generator/selfHealingLoop.js +202 -0
  30. package/dist/story-generator/validateStory.d.ts.map +1 -1
  31. package/dist/story-generator/validateStory.js +81 -12
  32. package/dist/story-ui.config.d.ts +2 -0
  33. package/dist/story-ui.config.d.ts.map +1 -1
  34. package/dist/templates/StoryUI/StoryUIPanel.d.ts +0 -5
  35. package/dist/templates/StoryUI/StoryUIPanel.d.ts.map +1 -1
  36. package/dist/templates/StoryUI/StoryUIPanel.js +411 -223
  37. package/package.json +4 -4
  38. package/templates/StoryUI/StoryUIPanel.mdx +84 -0
  39. package/templates/StoryUI/StoryUIPanel.tsx +493 -265
  40. package/dist/templates/StoryUI/StoryUIPanel.stories.d.ts +0 -18
  41. package/dist/templates/StoryUI/StoryUIPanel.stories.d.ts.map +0 -1
  42. package/dist/templates/StoryUI/StoryUIPanel.stories.js +0 -37
  43. package/templates/StoryUI/StoryUIPanel.stories.tsx +0 -44
  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 5px',
41
- borderRadius: '3px',
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 ? '12px' : 0 }, children: parseInline(paragraph.trim(), index) }, `p-${index}`))) }));
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, code, delayMs = 1500) => {
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: `✅ Created story: "${story.title}"\n\nThis story was recovered from memory. You can continue updating it or view it in Storybook.`
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", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif',
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: '8px 12px',
445
- background: '#3b82f6',
446
- color: 'white',
447
- border: 'none',
448
- borderRadius: '6px',
449
- fontSize: '13px',
450
- fontWeight: '500',
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: '6px',
497
+ marginBottom: '8px',
453
498
  transition: 'all 0.2s ease',
454
499
  boxShadow: 'none',
455
500
  display: 'flex',
456
501
  alignItems: 'center',
457
- justifyContent: 'center',
458
- gap: '6px',
502
+ justifyContent: 'flex-start',
503
+ gap: '10px',
459
504
  lineHeight: '1',
460
505
  },
461
506
  newChatButton: {
462
507
  width: '100%',
463
- padding: '8px 12px',
508
+ padding: '10px 14px',
464
509
  background: '#3b82f6',
465
510
  color: 'white',
466
511
  border: 'none',
467
- borderRadius: '6px',
468
- fontSize: '13px',
469
- fontWeight: '500',
512
+ borderRadius: '8px',
513
+ fontSize: '14px',
514
+ fontWeight: '600',
470
515
  cursor: 'pointer',
471
- marginBottom: '12px',
516
+ marginBottom: '16px',
472
517
  transition: 'all 0.2s ease',
473
- boxShadow: 'none',
518
+ boxShadow: '0 2px 8px rgba(59, 130, 246, 0.25)',
474
519
  display: 'flex',
475
520
  alignItems: 'center',
476
- justifyContent: 'center',
477
- gap: '6px',
521
+ justifyContent: 'flex-start',
522
+ gap: '10px',
478
523
  lineHeight: '1',
479
524
  },
480
525
  chatItem: {
481
- padding: '8px 10px',
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: '13px',
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: '11px',
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: '16px',
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: '10px',
603
+ marginBottom: '8px',
560
604
  },
561
605
  userMessage: {
562
- background: '#3b82f6',
563
- color: '#ffffff',
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.5',
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: '85%',
623
+ maxWidth: '90%',
580
624
  fontSize: '14px',
581
- lineHeight: '1.5',
582
- fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif',
583
- boxShadow: '0 1px 3px rgba(0, 0, 0, 0.08)',
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.9)',
589
- color: '#6b7280',
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
- fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif',
637
+ lineHeight: '1.45',
594
638
  display: 'flex',
595
639
  alignItems: 'center',
596
- gap: '6px',
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: '10px',
648
+ gap: '12px',
603
649
  margin: '0 16px 16px 16px',
604
- padding: '10px',
650
+ padding: '12px',
605
651
  background: 'rgba(255, 255, 255, 0.03)',
606
- borderRadius: '10px',
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
- fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif',
657
+ font: 'inherit',
612
658
  flex: 1,
613
- padding: '10px 14px',
614
- borderRadius: '6px',
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
- fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif',
670
+ font: 'inherit',
625
671
  padding: '10px 16px',
626
- borderRadius: '6px',
672
+ borderRadius: '10px',
627
673
  border: 'none',
628
- background: '#10b981',
629
- color: '#ffffff',
630
- fontSize: '13px',
631
- fontWeight: '500',
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: '5px',
636
- transition: 'all 0.15s ease',
637
- boxShadow: 'none',
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: '10px',
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: '10px 12px',
661
- borderRadius: '6px',
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: '6px',
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: '12px',
674
- maxWidth: '85%',
675
- boxShadow: '0 1px 3px rgba(0, 0, 0, 0.08)',
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.08)',
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.15)',
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: '6px',
738
+ marginBottom: '8px',
689
739
  display: 'flex',
690
740
  alignItems: 'center',
691
- gap: '5px',
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: '6px',
752
+ marginTop: '8px',
703
753
  },
704
754
  componentTag: {
705
755
  background: 'rgba(59, 130, 246, 0.12)',
706
756
  color: '#1d4ed8',
707
- fontSize: '10px',
708
- padding: '2px 6px',
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: '3px',
764
+ borderRadius: '4px',
715
765
  height: '4px',
716
- marginTop: '10px',
717
- marginBottom: '6px',
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: '11px',
728
- color: '#6b7280',
777
+ fontSize: '14px',
778
+ color: '#4b5563',
729
779
  display: 'flex',
730
780
  alignItems: 'center',
731
- gap: '5px',
781
+ gap: '6px',
782
+ fontWeight: '500',
783
+ lineHeight: '1.45',
732
784
  },
733
785
  phaseIcon: {
734
- fontSize: '12px',
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: '10px',
812
+ fontSize: '11px',
761
813
  padding: '2px 8px',
762
814
  borderRadius: '10px',
763
815
  display: 'inline-flex',
764
816
  alignItems: 'center',
765
- gap: '3px',
766
- marginTop: '6px',
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.08)',
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: '12px',
836
+ fontSize: '14px',
784
837
  color: '#4b5563',
785
- lineHeight: '1.5',
838
+ lineHeight: '1.45',
786
839
  },
787
840
  metricsRow: {
788
841
  display: 'flex',
789
- gap: '12px',
790
- marginTop: '8px',
791
- fontSize: '10px',
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: '3px',
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: '10px',
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 10px',
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: '6px',
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: '6px 6px 0 0',
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: '6px',
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: '6px',
940
- marginTop: '6px',
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
- const styleSheet = document.createElement('style');
981
- styleSheet.textContent = `
982
- @keyframes loadingDots {
983
- 0%, 20% { content: "."; }
984
- 40% { content: ".."; }
985
- 60%, 100% { content: "..."; }
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
- .loading-dots::after {
989
- content: ".";
990
- animation: loadingDots 1.4s infinite;
991
- }
992
- `;
993
- document.head.appendChild(styleSheet);
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 icon and text
1179
+ // Helper to get phase text (no icons - cleaner UI)
1013
1180
  const getPhaseInfo = (phase) => {
1014
1181
  const phases = {
1015
- config_loaded: { icon: '⚙️', text: 'Loading configuration' },
1016
- components_discovered: { icon: '🔍', text: 'Discovering components' },
1017
- prompt_built: { icon: '📝', text: 'Building prompt' },
1018
- llm_thinking: { icon: '🤔', text: 'AI is thinking' },
1019
- code_extracted: { icon: '📦', text: 'Extracting code' },
1020
- validating: { icon: '✅', text: 'Validating output' },
1021
- post_processing: { icon: '🔧', text: 'Processing' },
1022
- saving: { icon: '💾', text: 'Saving story' },
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] || { icon: '⏳', text: 'Working' };
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 ? '✅' : '❌', " ", completion.title] }), _jsx("div", { style: STYLES.summaryDescription, children: completion.summary.description }), completion.componentsUsed.length > 0 && (_jsxs("div", { style: { marginTop: '10px' }, children: [_jsx("div", { style: { fontSize: '12px', color: '#6b7280', marginBottom: '6px' }, 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: '10px' }, children: [_jsx("div", { style: { fontSize: '12px', color: '#6b7280', marginBottom: '6px' }, children: "Layout:" }), _jsx("div", { style: { fontSize: '12px', color: '#4b5563' }, children: completion.layoutChoices.map(l => l.pattern).join(', ') })] })), completion.validation && !completion.validation.isValid && (_jsxs("div", { style: { ...STYLES.validationBox, ...STYLES.validationWarning }, children: ["\u26A0\uFE0F ", completion.validation.autoFixApplied ? 'Auto-fixed issues' : 'Minor issues detected'] })), completion.suggestions && completion.suggestions.length > 0 && (_jsxs("div", { style: { marginTop: '10px', fontSize: '12px', color: '#6b7280' }, children: ["\uD83D\uDCA1 ", completion.suggestions[0]] })), completion.metrics && (_jsxs("div", { style: STYLES.metricsRow, children: [_jsxs("span", { style: STYLES.metric, children: ["\u23F1\uFE0F ", (completion.metrics.totalTimeMs / 1000).toFixed(1), "s"] }), _jsxs("span", { style: STYLES.metric, children: ["\uD83D\uDD04 ", 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: {
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' ? 'Copied!' : 'Copy Code' })] }), _jsx("pre", { style: STYLES.codeViewerPre, children: _jsx("code", { children: completion.code }) })] }))] }))] }) }));
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: ["\u274C ", error.message] }), error.details && _jsx("div", { style: { marginTop: '4px' }, children: error.details }), error.suggestion && _jsxs("div", { style: { marginTop: '8px' }, children: ["\uD83D\uDCA1 ", error.suggestion] })] }) }));
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", { style: STYLES.phaseIcon, children: "\uD83E\uDD16" }), _jsx("span", { children: "AI is generating your 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: {
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: ["\uD83D\uDD04 Retry ", retry.attempt, "/", retry.maxAttempts, ": ", retry.reason] })), !progress && !intent && (_jsx("div", { style: STYLES.progressPhase, children: _jsx("span", { className: "loading-dots", children: "Connecting" }) }))] }));
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 above._`);
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\n_Refresh Storybook (Cmd/Ctrl + R) to see new stories in the sidebar._`);
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 statusIcon = data.validation?.hasWarnings ? (data.validation.errors?.length > 0 ? '🔧' : '⚠️') : '';
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 = `${statusIcon} **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._`;
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 = `${statusIcon} **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💡 **Note**: If you don't see the story immediately, you may need to refresh your Storybook page (Cmd/Ctrl + R).`;
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 statusIcon = data.validation?.hasWarnings ? (data.validation.errors?.length > 0 ? '🔧' : '⚠️') : '';
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 = `${statusIcon} **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._`;
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 = `${statusIcon} **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💡 **Note**: If you don't see the story immediately, you may need to refresh your Storybook page (Cmd/Ctrl + R).`;
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.transform = 'translateY(-1px)';
1822
- e.currentTarget.style.boxShadow = '0 4px 16px rgba(59, 130, 246, 0.4)';
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.transform = 'translateY(0)';
1825
- e.currentTarget.style.boxShadow = '0 2px 8px rgba(59, 130, 246, 0.3)';
1826
- }, children: [_jsx("span", { style: { lineHeight: '0.5', display: 'inline-block', alignItems: 'center', width: '10px', height: '10px' }, children: "\u2630" }), _jsx("span", { children: "Chats" })] }), _jsxs("button", { onClick: handleNewChat, style: STYLES.newChatButton, onMouseEnter: (e) => {
1827
- e.currentTarget.style.transform = 'translateY(-1px)';
1828
- e.currentTarget.style.boxShadow = '0 4px 16px rgba(59, 130, 246, 0.4)';
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.transform = 'translateY(0)';
1831
- e.currentTarget.style.boxShadow = '0 2px 8px rgba(59, 130, 246, 0.2)';
1832
- }, children: [_jsx("span", { style: { lineHeight: '0.5', display: 'inline-block', alignItems: 'center', width: '10px', height: '10px' }, children: "+" }), _jsx("span", { children: "New Chat" })] }), recentChats.length > 0 && (_jsx("div", { style: {
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: "\u2715" })] }, chat.id)))] })), !sidebarOpen && (_jsx("div", { style: { padding: '8px', display: 'flex', justifyContent: 'center' }, children: _jsx("button", { onClick: () => setSidebarOpen(true), style: {
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("span", { style: { lineHeight: '0.4', display: 'inline-block', height: '10px' }, children: "\u2630" }) }) }))] }), _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: {
1870
- fontSize: '24px',
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: '600',
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
- }, children: "Story UI" }), _jsx("p", { style: { fontSize: '14px', margin: '4px 0 0 0', color: '#94a3b8' }, children: "Generate Storybook stories with AI" }), _jsxs("div", { style: {
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: '8px',
1881
- marginTop: '8px',
1882
- fontSize: '12px'
2066
+ gap: '6px',
2067
+ marginTop: '10px',
2068
+ fontSize: '11px'
1883
2069
  }, children: [_jsx("div", { style: {
1884
- width: '8px',
1885
- height: '8px',
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' : '#f87171' }, children: connectionStatus.connected
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: '6px' }, children: [_jsx("label", { style: { fontSize: '12px', color: '#94a3b8' }, children: "Provider:" }), _jsx("select", { value: selectedProvider, onChange: (e) => {
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: '6px' }, children: [_jsx("label", { style: { fontSize: '12px', color: '#94a3b8' }, children: "Model:" }), _jsx("select", { value: selectedModel, onChange: (e) => setSelectedModel(e.target.value), style: {
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: "\u00D7" })] }, img.id)))] })), _jsxs("form", { onSubmit: handleSend, style: {
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.5,
2144
+ opacity: 0.4,
1959
2145
  cursor: 'not-allowed',
1960
- background: '#6b7280',
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.transform = 'scale(1.05)';
1966
- e.currentTarget.style.boxShadow = '0 4px 16px rgba(16, 185, 129, 0.4)';
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
- e.currentTarget.style.transform = 'scale(1)';
1970
- e.currentTarget.style.boxShadow = '0 2px 8px rgba(16, 185, 129, 0.3)';
1971
- }, children: [_jsx("span", { children: "Send" }), _jsx("svg", { width: 16, height: 16, viewBox: "0 0 24 24", fill: "currentColor", children: _jsx("path", { d: "M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" }) })] })] })] })] }));
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 };