@tpitre/story-ui 4.5.2 → 4.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +5 -0
- package/dist/mcp-server/routes/generateStory.d.ts.map +1 -1
- package/dist/mcp-server/routes/generateStory.js +19 -5
- package/dist/mcp-server/routes/generateStoryStream.d.ts.map +1 -1
- package/dist/mcp-server/routes/generateStoryStream.js +19 -5
- package/dist/story-generator/promptGenerator.d.ts.map +1 -1
- package/dist/story-generator/promptGenerator.js +182 -24
- package/dist/story-generator/selfHealingLoop.d.ts.map +1 -1
- package/dist/story-generator/selfHealingLoop.js +48 -17
- package/dist/story-generator/storyTracker.d.ts +12 -0
- package/dist/story-generator/storyTracker.d.ts.map +1 -1
- package/dist/story-generator/storyTracker.js +42 -0
- package/dist/story-generator/storyValidator.d.ts.map +1 -1
- package/dist/story-generator/storyValidator.js +0 -4
- package/dist/story-generator/validateStory.d.ts.map +1 -1
- package/dist/story-generator/validateStory.js +128 -0
- package/dist/templates/StoryUI/StoryUIPanel.css +1623 -0
- package/dist/templates/StoryUI/StoryUIPanel.d.ts.map +1 -1
- package/dist/templates/StoryUI/StoryUIPanel.js +46 -69
- package/dist/templates/StoryUI/StoryUIPanel.mdx +84 -0
- package/package.json +3 -2
- package/templates/StoryUI/StoryUIPanel.css +152 -54
- package/templates/StoryUI/StoryUIPanel.tsx +51 -75
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StoryUIPanel.d.ts","sourceRoot":"","sources":["../../../templates/StoryUI/StoryUIPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,oBAAoB,CAAC;AAwwB5B,UAAU,iBAAiB;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC3B;AAED,iBAAS,YAAY,CAAC,EAAE,OAAO,EAAE,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"StoryUIPanel.d.ts","sourceRoot":"","sources":["../../../templates/StoryUI/StoryUIPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,oBAAoB,CAAC;AAwwB5B,UAAU,iBAAiB;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC3B;AAED,iBAAS,YAAY,CAAC,EAAE,OAAO,EAAE,EAAE,iBAAiB,2CAkrCnD;AAED,eAAe,YAAY,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -525,92 +525,69 @@ function StoryUIPanel({ mcpPort }) {
|
|
|
525
525
|
pollForExternalStories();
|
|
526
526
|
return () => clearInterval(intervalId);
|
|
527
527
|
}, []);
|
|
528
|
-
// Detect Storybook theme
|
|
528
|
+
// Detect Storybook MANAGER theme (not preview background)
|
|
529
|
+
// This ensures Story UI follows Storybook's overall theme, not the story preview background toggle
|
|
529
530
|
useEffect(() => {
|
|
530
|
-
const
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
//
|
|
534
|
-
const urlParams = new URLSearchParams(window.location.search);
|
|
535
|
-
const globals = urlParams.get('globals') || '';
|
|
536
|
-
const hasStorybookLightBg = globals.includes('backgrounds.value:light');
|
|
537
|
-
const hasStorybookDarkBg = globals.includes('backgrounds.value:dark') ||
|
|
538
|
-
globals.includes('backgrounds.value:%23') || // Hex colors starting with #
|
|
539
|
-
globals.includes('backgrounds.value:!hex');
|
|
540
|
-
// Check parent frame URL if we're in an iframe (Storybook 8+)
|
|
541
|
-
let parentHasDarkBg = false;
|
|
542
|
-
let parentHasLightBg = false;
|
|
543
|
-
let parentHasDarkClass = false;
|
|
531
|
+
const detectManagerTheme = () => {
|
|
532
|
+
let managerIsDark = false;
|
|
533
|
+
// Strategy 1: Check parent frame for Storybook manager theme (Storybook 8+)
|
|
534
|
+
// The manager theme is set in .storybook/manager.tsx via addons.setConfig({ theme: themes.dark })
|
|
544
535
|
try {
|
|
545
536
|
if (window.parent !== window) {
|
|
546
|
-
const parentUrl = new URL(window.parent.location.href);
|
|
547
|
-
const parentGlobals = parentUrl.searchParams.get('globals') || '';
|
|
548
|
-
parentHasLightBg = parentGlobals.includes('backgrounds.value:light');
|
|
549
|
-
parentHasDarkBg = parentGlobals.includes('backgrounds.value:dark') ||
|
|
550
|
-
parentGlobals.includes('backgrounds.value:%23');
|
|
551
|
-
// Check parent document for Storybook dark theme classes
|
|
552
537
|
const parentBody = window.parent.document.body;
|
|
553
538
|
const parentHtml = window.parent.document.documentElement;
|
|
554
|
-
|
|
555
|
-
|
|
539
|
+
// Check for Storybook's dark theme class (most reliable)
|
|
540
|
+
if (parentBody.classList.contains('sb-dark') ||
|
|
541
|
+
parentHtml.classList.contains('sb-dark') ||
|
|
556
542
|
parentHtml.getAttribute('data-theme') === 'dark' ||
|
|
557
|
-
parentBody.getAttribute('data-theme') === 'dark'
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
543
|
+
parentBody.getAttribute('data-theme') === 'dark') {
|
|
544
|
+
managerIsDark = true;
|
|
545
|
+
}
|
|
546
|
+
// Check Storybook manager sidebar/header background color as fallback
|
|
547
|
+
// The manager UI elements use the theme colors, not the preview background
|
|
548
|
+
const managerEl = window.parent.document.querySelector('.sb-sidebar, [class*="sidebar"], .sb-bar');
|
|
549
|
+
if (managerEl && !managerIsDark) {
|
|
550
|
+
const bgColor = window.getComputedStyle(managerEl).backgroundColor;
|
|
551
|
+
const rgb = bgColor.match(/\d+/g);
|
|
552
|
+
if (rgb && rgb.length >= 3) {
|
|
553
|
+
const luminance = (0.299 * parseInt(rgb[0]) + 0.587 * parseInt(rgb[1]) + 0.114 * parseInt(rgb[2])) / 255;
|
|
554
|
+
managerIsDark = luminance < 0.5;
|
|
567
555
|
}
|
|
568
556
|
}
|
|
569
557
|
}
|
|
570
558
|
}
|
|
571
559
|
catch {
|
|
572
|
-
// Cross-origin access not allowed,
|
|
560
|
+
// Cross-origin access not allowed, fall back to system preference
|
|
573
561
|
}
|
|
574
|
-
//
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
if (rgb && rgb.length >= 3) {
|
|
579
|
-
const luminance = (0.299 * parseInt(rgb[0]) + 0.587 * parseInt(rgb[1]) + 0.114 * parseInt(rgb[2])) / 255;
|
|
580
|
-
isBackgroundDark = luminance < 0.5;
|
|
562
|
+
// Strategy 2: If not in iframe or can't detect, use system preference
|
|
563
|
+
if (!managerIsDark) {
|
|
564
|
+
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
565
|
+
managerIsDark = systemPrefersDark;
|
|
581
566
|
}
|
|
582
|
-
|
|
583
|
-
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
584
|
-
// Explicit light mode takes precedence - if user selected "light" in Storybook, respect that
|
|
585
|
-
const hasExplicitLightMode = hasStorybookLightBg || parentHasLightBg;
|
|
586
|
-
// Explicit dark mode indicators
|
|
587
|
-
const hasExplicitDarkMode = body.classList.contains('sb-dark') ||
|
|
588
|
-
html.classList.contains('dark') ||
|
|
589
|
-
html.getAttribute('data-theme') === 'dark' ||
|
|
590
|
-
body.getAttribute('data-theme') === 'dark' ||
|
|
591
|
-
hasStorybookDarkBg ||
|
|
592
|
-
parentHasDarkBg;
|
|
593
|
-
// Determine dark mode: explicit light mode forces light, otherwise check dark indicators
|
|
594
|
-
const isDark = hasExplicitLightMode
|
|
595
|
-
? false
|
|
596
|
-
: (hasExplicitDarkMode || parentHasDarkClass || isBackgroundDark || systemPrefersDark);
|
|
597
|
-
dispatch({ type: 'SET_DARK_MODE', payload: isDark });
|
|
567
|
+
dispatch({ type: 'SET_DARK_MODE', payload: managerIsDark });
|
|
598
568
|
};
|
|
599
|
-
|
|
600
|
-
//
|
|
601
|
-
|
|
602
|
-
//
|
|
603
|
-
const intervalId = setInterval(detectTheme, 500);
|
|
604
|
-
const observer = new MutationObserver(detectTheme);
|
|
605
|
-
observer.observe(document.body, { attributes: true, attributeFilter: ['class', 'data-theme', 'style'] });
|
|
606
|
-
observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class', 'data-theme', 'style'] });
|
|
569
|
+
detectManagerTheme();
|
|
570
|
+
// Poll for changes (manager theme changes are rare but possible)
|
|
571
|
+
const intervalId = setInterval(detectManagerTheme, 1000);
|
|
572
|
+
// Listen for system preference changes
|
|
607
573
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
608
|
-
mediaQuery.addEventListener('change',
|
|
574
|
+
mediaQuery.addEventListener('change', detectManagerTheme);
|
|
575
|
+
// Observe parent document for theme changes if accessible
|
|
576
|
+
let parentObserver = null;
|
|
577
|
+
try {
|
|
578
|
+
if (window.parent !== window) {
|
|
579
|
+
parentObserver = new MutationObserver(detectManagerTheme);
|
|
580
|
+
parentObserver.observe(window.parent.document.body, { attributes: true, attributeFilter: ['class', 'data-theme'] });
|
|
581
|
+
parentObserver.observe(window.parent.document.documentElement, { attributes: true, attributeFilter: ['class', 'data-theme'] });
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
catch {
|
|
585
|
+
// Cross-origin, ignore
|
|
586
|
+
}
|
|
609
587
|
return () => {
|
|
610
|
-
window.removeEventListener('popstate', detectTheme);
|
|
611
588
|
clearInterval(intervalId);
|
|
612
|
-
|
|
613
|
-
|
|
589
|
+
mediaQuery.removeEventListener('change', detectManagerTheme);
|
|
590
|
+
parentObserver?.disconnect();
|
|
614
591
|
};
|
|
615
592
|
}, []);
|
|
616
593
|
// Close context menu when clicking outside
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{/*
|
|
2
|
+
Story UI Panel - MDX Documentation Page
|
|
3
|
+
|
|
4
|
+
This MDX file renders the Story UI Panel as a standalone documentation page.
|
|
5
|
+
Using MDX instead of a .stories.tsx file ensures the React component renders
|
|
6
|
+
correctly across ALL framework Storybooks (React, Vue, Svelte, Angular, Web Components).
|
|
7
|
+
|
|
8
|
+
Why this works:
|
|
9
|
+
- MDX is processed by @storybook/addon-docs which always uses React
|
|
10
|
+
- Regular .stories.tsx files render in the Preview iframe using the project's framework
|
|
11
|
+
- Non-React frameworks cannot render React components in their Preview
|
|
12
|
+
- MDX pages bypass this limitation by being compiled with React directly
|
|
13
|
+
|
|
14
|
+
Port Configuration:
|
|
15
|
+
- The port is automatically read from VITE_STORY_UI_PORT environment variable
|
|
16
|
+
- This is set during `npx story-ui init` and stored in .env
|
|
17
|
+
- URL parameter override: ?mcp-port=XXXX
|
|
18
|
+
|
|
19
|
+
Reference: Steve Dodier-Lazaro (Storybook team) recommendation
|
|
20
|
+
*/}
|
|
21
|
+
|
|
22
|
+
import { Meta } from '@storybook/addon-docs/blocks';
|
|
23
|
+
import { StoryUIPanel } from './StoryUIPanel';
|
|
24
|
+
import { useEffect, useState, useRef } from 'react';
|
|
25
|
+
|
|
26
|
+
<Meta title="Story UI/Story Generator" />
|
|
27
|
+
|
|
28
|
+
export const StoryUIPanelWrapper = () => {
|
|
29
|
+
const [isReady, setIsReady] = useState(false);
|
|
30
|
+
const hasInitialized = useRef(false);
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
// Only run once on mount
|
|
34
|
+
if (hasInitialized.current) return;
|
|
35
|
+
hasInitialized.current = true;
|
|
36
|
+
|
|
37
|
+
if (typeof window !== 'undefined') {
|
|
38
|
+
// Check for URL parameter override for MCP port
|
|
39
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
40
|
+
const mcpPortParam = urlParams.get('mcp-port');
|
|
41
|
+
|
|
42
|
+
if (mcpPortParam) {
|
|
43
|
+
// URL parameter takes highest priority
|
|
44
|
+
window.STORY_UI_MCP_PORT = mcpPortParam;
|
|
45
|
+
}
|
|
46
|
+
// Otherwise, let StoryUIPanel.tsx's getApiBaseUrl() handle port detection
|
|
47
|
+
// from VITE_STORY_UI_PORT environment variable (set during story-ui init)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
setIsReady(true);
|
|
51
|
+
}, []);
|
|
52
|
+
|
|
53
|
+
// Don't render until initialized to prevent hydration issues
|
|
54
|
+
if (!isReady) {
|
|
55
|
+
return (
|
|
56
|
+
<div style={{
|
|
57
|
+
display: 'flex',
|
|
58
|
+
alignItems: 'center',
|
|
59
|
+
justifyContent: 'center',
|
|
60
|
+
height: '100vh',
|
|
61
|
+
color: '#666'
|
|
62
|
+
}}>
|
|
63
|
+
Loading Story UI...
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return <StoryUIPanel />;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
{/*
|
|
72
|
+
Full-screen container to match the original story layout.
|
|
73
|
+
The StoryUIPanel component handles its own internal styling.
|
|
74
|
+
*/}
|
|
75
|
+
<div style={{
|
|
76
|
+
position: 'fixed',
|
|
77
|
+
top: 0,
|
|
78
|
+
left: 0,
|
|
79
|
+
right: 0,
|
|
80
|
+
bottom: 0,
|
|
81
|
+
overflow: 'hidden'
|
|
82
|
+
}}>
|
|
83
|
+
<StoryUIPanelWrapper />
|
|
84
|
+
</div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tpitre/story-ui",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.6.0",
|
|
4
4
|
"description": "AI-powered Storybook story generator with dynamic component discovery",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"LICENSE"
|
|
27
27
|
],
|
|
28
28
|
"scripts": {
|
|
29
|
-
"build": "tsc",
|
|
29
|
+
"build": "tsc && npm run copy-templates",
|
|
30
|
+
"copy-templates": "node -e \"const fs=require('fs');const path=require('path');const src='templates/StoryUI';const dst='dist/templates/StoryUI';['.css','.mdx'].forEach(ext=>{fs.readdirSync(src).filter(f=>f.endsWith(ext)).forEach(f=>fs.copyFileSync(path.join(src,f),path.join(dst,f)))});console.log('Static template files copied to dist/')\"",
|
|
30
31
|
"start": "yarn build && node dist/mcp-server/index.js",
|
|
31
32
|
"mcp": "yarn build && node dist/mcp-server/mcp-stdio-server.js",
|
|
32
33
|
"dev": "tsc --watch",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
--secondary: 240 4.8% 95.9%;
|
|
27
27
|
--secondary-foreground: 240 5.9% 10%;
|
|
28
28
|
--muted: 240 4.8% 95.9%;
|
|
29
|
-
--muted-foreground: 240
|
|
29
|
+
--muted-foreground: 240 5% 35%; /* Darker for WCAG AA compliance - was 46.1% */
|
|
30
30
|
--accent: 240 4.8% 95.9%;
|
|
31
31
|
--accent-foreground: 240 5.9% 10%;
|
|
32
32
|
--destructive: 0 84.2% 60.2%;
|
|
@@ -113,15 +113,15 @@
|
|
|
113
113
|
--input: 217 33% 22%;
|
|
114
114
|
--ring: 213 94% 68%;
|
|
115
115
|
|
|
116
|
-
/* User Bubble -
|
|
117
|
-
--user-bubble-bg:
|
|
118
|
-
--user-bubble-fg:
|
|
119
|
-
--user-bubble-border:
|
|
116
|
+
/* User Bubble - Dark bluish tint in dark mode */
|
|
117
|
+
--user-bubble-bg: 217 33% 22%;
|
|
118
|
+
--user-bubble-fg: 210 40% 98%;
|
|
119
|
+
--user-bubble-border: 217 33% 28%;
|
|
120
120
|
|
|
121
|
-
/* AI Bubble -
|
|
122
|
-
--ai-bubble-bg:
|
|
123
|
-
--ai-bubble-fg:
|
|
124
|
-
--ai-bubble-border:
|
|
121
|
+
/* AI Bubble - Dark zinc in dark mode */
|
|
122
|
+
--ai-bubble-bg: 240 4% 16%;
|
|
123
|
+
--ai-bubble-fg: 0 0% 98%;
|
|
124
|
+
--ai-bubble-border: 240 4% 26%;
|
|
125
125
|
|
|
126
126
|
--success: 142 69% 58%;
|
|
127
127
|
--warning: 48 96% 53%;
|
|
@@ -151,15 +151,15 @@
|
|
|
151
151
|
--input: 217 33% 22%;
|
|
152
152
|
--ring: 213 94% 68%;
|
|
153
153
|
|
|
154
|
-
/* User Bubble -
|
|
155
|
-
--user-bubble-bg:
|
|
156
|
-
--user-bubble-fg:
|
|
157
|
-
--user-bubble-border:
|
|
154
|
+
/* User Bubble - Dark bluish tint in dark mode */
|
|
155
|
+
--user-bubble-bg: 217 33% 22%;
|
|
156
|
+
--user-bubble-fg: 210 40% 98%;
|
|
157
|
+
--user-bubble-border: 217 33% 28%;
|
|
158
158
|
|
|
159
|
-
/* AI Bubble -
|
|
160
|
-
--ai-bubble-bg:
|
|
161
|
-
--ai-bubble-fg:
|
|
162
|
-
--ai-bubble-border:
|
|
159
|
+
/* AI Bubble - Dark zinc in dark mode */
|
|
160
|
+
--ai-bubble-bg: 240 4% 16%;
|
|
161
|
+
--ai-bubble-fg: 0 0% 98%;
|
|
162
|
+
--ai-bubble-border: 240 4% 26%;
|
|
163
163
|
|
|
164
164
|
--success: 142 69% 58%;
|
|
165
165
|
--warning: 48 96% 53%;
|
|
@@ -168,18 +168,20 @@
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
/* ============================================
|
|
171
|
-
Base Reset
|
|
171
|
+
Base Reset & CSS Isolation
|
|
172
172
|
============================================ */
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
.sui-root
|
|
176
|
-
|
|
173
|
+
|
|
174
|
+
/* Isolate StoryUI from Storybook's theme CSS variables */
|
|
175
|
+
.sui-root {
|
|
176
|
+
/* Reset inherited properties to prevent Storybook theme bleeding */
|
|
177
|
+
all: revert;
|
|
178
|
+
|
|
179
|
+
/* Re-apply necessary layout */
|
|
177
180
|
box-sizing: border-box;
|
|
178
181
|
margin: 0;
|
|
179
182
|
padding: 0;
|
|
180
|
-
}
|
|
181
183
|
|
|
182
|
-
|
|
184
|
+
/* Typography */
|
|
183
185
|
font-family: var(--font-sans);
|
|
184
186
|
font-size: 14px;
|
|
185
187
|
line-height: 1.5;
|
|
@@ -187,9 +189,28 @@
|
|
|
187
189
|
background-color: hsl(var(--background));
|
|
188
190
|
-webkit-font-smoothing: antialiased;
|
|
189
191
|
-moz-osx-font-smoothing: grayscale;
|
|
192
|
+
|
|
193
|
+
/* Layout */
|
|
190
194
|
height: 100%;
|
|
191
195
|
width: 100%;
|
|
192
196
|
display: flex;
|
|
197
|
+
|
|
198
|
+
/* Prevent inheriting Storybook's color scheme */
|
|
199
|
+
color-scheme: light;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.sui-root.dark {
|
|
203
|
+
color-scheme: dark;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.sui-root *,
|
|
207
|
+
.sui-root *::before,
|
|
208
|
+
.sui-root *::after {
|
|
209
|
+
box-sizing: border-box;
|
|
210
|
+
margin: 0;
|
|
211
|
+
padding: 0;
|
|
212
|
+
/* Prevent Storybook CSS variable inheritance */
|
|
213
|
+
color: inherit;
|
|
193
214
|
}
|
|
194
215
|
|
|
195
216
|
/* ============================================
|
|
@@ -405,58 +426,100 @@
|
|
|
405
426
|
opacity: 0.5;
|
|
406
427
|
}
|
|
407
428
|
|
|
408
|
-
/* Button Variants - Storybook-style */
|
|
429
|
+
/* Button Variants - Storybook-style with explicit fallback colors */
|
|
409
430
|
.sui-button-default {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
431
|
+
/* Explicit fallback colors to prevent Storybook bleeding */
|
|
432
|
+
background: #f4f4f5; /* hsl(240 4.8% 95.9%) */
|
|
433
|
+
color: #18181b; /* hsl(240 5.9% 10%) */
|
|
434
|
+
border: 1px solid #e4e4e7; /* hsl(240 5.9% 90%) */
|
|
413
435
|
border-radius: var(--radius-md);
|
|
414
436
|
height: 2rem;
|
|
415
437
|
padding: 0 var(--space-3);
|
|
416
438
|
}
|
|
417
439
|
|
|
418
440
|
.sui-button-default:hover {
|
|
419
|
-
background:
|
|
420
|
-
border-color:
|
|
441
|
+
background: #e4e4e7;
|
|
442
|
+
border-color: #a1a1aa;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/* Dark mode button defaults */
|
|
446
|
+
.sui-root.dark .sui-button-default {
|
|
447
|
+
background: #1e293b; /* hsl(217 33% 17%) */
|
|
448
|
+
color: #f8fafc; /* hsl(210 40% 98%) */
|
|
449
|
+
border-color: #334155; /* hsl(217 33% 22%) */
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
.sui-root.dark .sui-button-default:hover {
|
|
453
|
+
background: #334155;
|
|
454
|
+
border-color: #94a3b8;
|
|
421
455
|
}
|
|
422
456
|
|
|
423
457
|
.sui-button-secondary {
|
|
424
|
-
background:
|
|
425
|
-
color:
|
|
426
|
-
border: 1px solid
|
|
458
|
+
background: #f4f4f5;
|
|
459
|
+
color: #18181b;
|
|
460
|
+
border: 1px solid #e4e4e7;
|
|
427
461
|
border-radius: var(--radius-md);
|
|
428
462
|
height: 2rem;
|
|
429
463
|
padding: 0 var(--space-3);
|
|
430
464
|
}
|
|
431
465
|
|
|
432
466
|
.sui-button-secondary:hover {
|
|
433
|
-
background:
|
|
467
|
+
background: #e4e4e7;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.sui-root.dark .sui-button-secondary {
|
|
471
|
+
background: #1e293b;
|
|
472
|
+
color: #f8fafc;
|
|
473
|
+
border-color: #334155;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
.sui-root.dark .sui-button-secondary:hover {
|
|
477
|
+
background: #334155;
|
|
434
478
|
}
|
|
435
479
|
|
|
436
480
|
.sui-button-ghost {
|
|
437
|
-
color:
|
|
481
|
+
color: #0a0a0b;
|
|
438
482
|
border-radius: var(--radius-md);
|
|
439
483
|
height: 2rem;
|
|
440
484
|
padding: 0 var(--space-3);
|
|
441
485
|
}
|
|
442
486
|
|
|
443
487
|
.sui-button-ghost:hover {
|
|
444
|
-
background:
|
|
445
|
-
color:
|
|
488
|
+
background: #f4f4f5;
|
|
489
|
+
color: #18181b;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
.sui-root.dark .sui-button-ghost {
|
|
493
|
+
color: #f8fafc;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.sui-root.dark .sui-button-ghost:hover {
|
|
497
|
+
background: #1e293b;
|
|
498
|
+
color: #f8fafc;
|
|
446
499
|
}
|
|
447
500
|
|
|
448
501
|
.sui-button-outline {
|
|
449
|
-
border: 1px solid
|
|
502
|
+
border: 1px solid #e4e4e7;
|
|
450
503
|
background: transparent;
|
|
451
|
-
color:
|
|
504
|
+
color: #0a0a0b;
|
|
452
505
|
border-radius: var(--radius-md);
|
|
453
506
|
height: 2rem;
|
|
454
507
|
padding: 0 var(--space-3);
|
|
455
508
|
}
|
|
456
509
|
|
|
457
510
|
.sui-button-outline:hover {
|
|
458
|
-
background:
|
|
459
|
-
color:
|
|
511
|
+
background: #f4f4f5;
|
|
512
|
+
color: #18181b;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.sui-root.dark .sui-button-outline {
|
|
516
|
+
border-color: #334155;
|
|
517
|
+
color: #f8fafc;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
.sui-root.dark .sui-button-outline:hover {
|
|
521
|
+
background: #1e293b;
|
|
522
|
+
color: #f8fafc;
|
|
460
523
|
}
|
|
461
524
|
|
|
462
525
|
.sui-button-destructive {
|
|
@@ -747,27 +810,29 @@
|
|
|
747
810
|
.sui-welcome-greeting {
|
|
748
811
|
font-size: 1.75rem;
|
|
749
812
|
font-weight: 600;
|
|
750
|
-
color
|
|
813
|
+
/* Explicit high-contrast color - forces override of any inherited styles */
|
|
814
|
+
color: #18181b !important; /* hsl(240 6% 10%) - near black for maximum contrast */
|
|
751
815
|
margin-bottom: var(--space-3);
|
|
752
816
|
line-height: 1.3;
|
|
753
817
|
}
|
|
754
818
|
|
|
755
819
|
/* Dark mode: ensure greeting is clearly visible - WCAG AA compliant */
|
|
756
820
|
.sui-root.dark .sui-welcome-greeting {
|
|
757
|
-
color: #ffffff;
|
|
821
|
+
color: #ffffff !important;
|
|
758
822
|
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
|
|
759
823
|
}
|
|
760
824
|
|
|
761
825
|
.sui-welcome-subtitle {
|
|
762
826
|
font-size: 1rem;
|
|
763
|
-
color
|
|
827
|
+
/* Explicit high-contrast color - WCAG AA compliant */
|
|
828
|
+
color: #52525b !important; /* hsl(240 5% 35%) - ~8:1 contrast on white */
|
|
764
829
|
margin-bottom: var(--space-8);
|
|
765
830
|
max-width: 400px;
|
|
766
831
|
}
|
|
767
832
|
|
|
768
833
|
/* Dark mode: make subtitle more visible */
|
|
769
834
|
.sui-root.dark .sui-welcome-subtitle {
|
|
770
|
-
color: hsl(
|
|
835
|
+
color: #cbd5e1 !important; /* hsl(213 27% 84%) - high contrast on dark bg */
|
|
771
836
|
}
|
|
772
837
|
|
|
773
838
|
.sui-welcome-chips {
|
|
@@ -786,26 +851,39 @@
|
|
|
786
851
|
align-items: center;
|
|
787
852
|
justify-content: center;
|
|
788
853
|
padding: 0.5rem 1rem;
|
|
789
|
-
|
|
790
|
-
|
|
854
|
+
/* Explicit high-contrast colors - forces override of inherited styles */
|
|
855
|
+
background: #f4f4f5 !important; /* hsl(240 4.8% 95.9%) */
|
|
856
|
+
border: 1px solid #d4d4d8 !important; /* hsl(240 5% 84%) - slightly darker border */
|
|
791
857
|
border-radius: var(--radius-full);
|
|
792
858
|
font-size: 0.875rem;
|
|
793
859
|
font-weight: 500;
|
|
794
860
|
line-height: 1;
|
|
795
|
-
color: hsl(
|
|
861
|
+
color: #18181b !important; /* hsl(240 6% 10%) - near black for high contrast */
|
|
796
862
|
cursor: pointer;
|
|
797
863
|
transition: all var(--transition-fast);
|
|
798
864
|
}
|
|
799
865
|
|
|
800
866
|
.sui-chip:hover {
|
|
801
|
-
background: hsl(
|
|
802
|
-
border-color: hsl(
|
|
867
|
+
background: #e4e4e7; /* hsl(240 4.8% 95.9%) */
|
|
868
|
+
border-color: #a1a1aa; /* hsl(240 3.8% 46.1% / 0.3) */
|
|
803
869
|
}
|
|
804
870
|
|
|
805
871
|
.sui-chip:active {
|
|
806
872
|
transform: scale(0.98);
|
|
807
873
|
}
|
|
808
874
|
|
|
875
|
+
/* Dark mode chips */
|
|
876
|
+
.sui-root.dark .sui-chip {
|
|
877
|
+
background: #1e293b !important; /* hsl(217 33% 17%) */
|
|
878
|
+
border-color: #475569 !important; /* hsl(215 19% 35%) - more visible border */
|
|
879
|
+
color: #f8fafc !important; /* hsl(210 40% 98%) - near white */
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
.sui-root.dark .sui-chip:hover {
|
|
883
|
+
background: #334155;
|
|
884
|
+
border-color: #94a3b8;
|
|
885
|
+
}
|
|
886
|
+
|
|
809
887
|
/* ============================================
|
|
810
888
|
Messages
|
|
811
889
|
============================================ */
|
|
@@ -852,14 +930,34 @@
|
|
|
852
930
|
border-bottom-right-radius: var(--radius-sm);
|
|
853
931
|
}
|
|
854
932
|
|
|
855
|
-
/*
|
|
933
|
+
/* User bubble - dark mode: dark bluish tint with light text */
|
|
934
|
+
.sui-root.dark .sui-message-user .sui-message-bubble {
|
|
935
|
+
background: #2d3748 !important; /* Dark bluish - hsl(217 33% 22%) */
|
|
936
|
+
color: #f7fafc !important; /* Near white - hsl(210 40% 98%) */
|
|
937
|
+
border: 1px solid #4a5568 !important; /* Dark border - hsl(217 33% 28%) */
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
/* AI bubble - pure white with explicit high-contrast colors */
|
|
856
941
|
.sui-message-ai .sui-message-bubble {
|
|
857
|
-
background:
|
|
858
|
-
color:
|
|
859
|
-
border
|
|
942
|
+
background: #ffffff !important; /* Pure white */
|
|
943
|
+
color: #18181b !important; /* Near black - high contrast */
|
|
944
|
+
border: 1px solid #e4e4e7 !important; /* Light gray border */
|
|
860
945
|
border-bottom-left-radius: var(--radius-sm);
|
|
861
946
|
}
|
|
862
947
|
|
|
948
|
+
/* AI bubble - dark mode: dark background with light text */
|
|
949
|
+
.sui-root.dark .sui-message-ai .sui-message-bubble {
|
|
950
|
+
background: #27272a !important; /* Dark zinc - hsl(240 4% 16%) */
|
|
951
|
+
color: #fafafa !important; /* Near white - hsl(0 0% 98%) */
|
|
952
|
+
border: 1px solid #3f3f46 !important; /* Dark border - hsl(240 4% 26%) */
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
/* AI bubble code in dark mode */
|
|
956
|
+
.sui-root.dark .sui-message-ai .sui-message-bubble code {
|
|
957
|
+
background: rgba(63, 63, 70, 0.5) !important; /* Semi-transparent dark */
|
|
958
|
+
color: #e4e4e7 !important; /* Light gray text */
|
|
959
|
+
}
|
|
960
|
+
|
|
863
961
|
/*
|
|
864
962
|
* Markdown content styling
|
|
865
963
|
* Using .sui-message-bubble prefix for higher specificity (0,2,x)
|