fix(ui): dark-theme colors in discussion session — replace light-mode Tailwind classes

ChatMessage, DiscussionPanel, ReasoningPanel, ModeSwitchMarker: swap all
hard-coded light-mode colors (bg-slate-*, text-slate-7xx, bg-amber-50,
bg-gray-*, border-gray-200, bg-white) for dark-theme tokens
(text-foreground, text-muted-foreground, border-border, bg-card, bg-white/5,
bg-amber-500/10) that match the existing dark glass-panel design system.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Vadym Samoilenko 2026-05-25 12:13:48 +01:00
parent e156ef897e
commit f626d2534b
4 changed files with 76 additions and 80 deletions

View file

@ -79,7 +79,7 @@ const ChatMessage = ({ message, persona, toggleHighlight, participants = [], foc
id={`message-${message.id}`}
className={cn(
"flex items-start p-3 rounded-lg transition-colors",
message.highlighted ? "bg-amber-50 border border-amber-200" : "hover:bg-slate-50",
message.highlighted ? "bg-amber-500/10 border border-amber-500/30" : "hover:bg-white/5",
isModerator ? "border-l-4 border-l-primary pl-4" : "",
isFacilitator ? "border-l-4 border-l-green-500 pl-4" : ""
)}
@ -93,20 +93,20 @@ const ChatMessage = ({ message, persona, toggleHighlight, participants = [], foc
<Bot className="h-6 w-6 text-primary" />
</div>
) : isFacilitator ? (
<div className="bg-green-100 p-2 rounded-full">
<User className="h-6 w-6 text-green-600" />
<div className="bg-green-500/15 p-2 rounded-full">
<User className="h-6 w-6 text-green-400" />
</div>
) : persona ? (
<div className="bg-slate-100 p-2 rounded-full">
<img
src={getPersonaAvatarSrc(persona)}
alt={`${persona.name} avatar`}
className="h-6 w-6 rounded-full object-cover"
<div className="bg-white/10 p-2 rounded-full">
<img
src={getPersonaAvatarSrc(persona)}
alt={`${persona.name} avatar`}
className="h-6 w-6 rounded-full object-cover"
/>
</div>
) : (
<div className="bg-slate-100 p-2 rounded-full">
<UserCircle className="h-6 w-6 text-slate-600" />
<div className="bg-white/10 p-2 rounded-full">
<UserCircle className="h-6 w-6 text-muted-foreground" />
</div>
)}
</div>
@ -123,12 +123,12 @@ const ChatMessage = ({ message, persona, toggleHighlight, participants = [], foc
</Badge>
)}
<span className="text-xs text-slate-500 ml-auto">
<span className="text-xs text-muted-foreground ml-auto">
{message.timestamp.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
</span>
</div>
<p className="text-slate-700">
<p className="text-foreground">
{!message.text || message.text.trim() === '' || message.text === '...' ? (
<span className="text-red-500 italic">
[No response content - AI generation may have failed]
@ -140,12 +140,12 @@ const ChatMessage = ({ message, persona, toggleHighlight, participants = [], foc
{/* Display creative asset if this is a moderator/facilitator message with an asset */}
{hasCreativeAsset && assetInfo && (
<div className="mt-3 p-3 border rounded-lg bg-slate-50">
<div className="mt-3 p-3 border border-border rounded-lg bg-white/5">
<div className="flex items-center gap-2 mb-2">
<ImageIcon className="h-4 w-4 text-slate-600" />
<span className="text-sm font-medium text-slate-700">Creative Asset</span>
<ImageIcon className="h-4 w-4 text-muted-foreground" />
<span className="text-sm font-medium text-foreground">Creative Asset</span>
{assetInfo.displayReference !== assetInfo.filename && (
<span className="text-xs text-slate-500">({assetInfo.displayReference})</span>
<span className="text-xs text-muted-foreground">({assetInfo.displayReference})</span>
)}
</div>
<img

View file

@ -1185,7 +1185,7 @@ const DiscussionPanel = ({
)
))}
{(isTyping || effectiveAiModeActive) && (
<div className="flex items-center space-x-2 text-sm text-slate-500 animate-pulse">
<div className="flex items-center space-x-2 text-sm text-muted-foreground animate-pulse">
<div className="bg-primary/10 p-2 rounded-full">
{effectiveAiModeActive ? (
<Bot className="h-4 w-4 text-primary animate-spin" />
@ -1229,21 +1229,21 @@ const DiscussionPanel = ({
/>
{/* Control panel - pinned to bottom */}
<div className="pt-4 border-t border-slate-200 w-full">
<div className="pt-4 border-t border-border w-full">
{/* Show selected file indicator */}
{selectedFile && (
<div className="mb-2 p-2 bg-blue-50 border border-blue-200 rounded-md flex items-center justify-between">
<div className="mb-2 p-2 bg-blue-500/10 border border-blue-500/30 rounded-md flex items-center justify-between">
<div className="flex items-center gap-2">
<Paperclip className="h-4 w-4 text-blue-600" />
<span className="text-sm text-blue-700">{selectedFile.name}</span>
<span className="text-xs text-blue-500">({(selectedFile.size / 1024 / 1024).toFixed(1)} MB)</span>
<Paperclip className="h-4 w-4 text-blue-400" />
<span className="text-sm text-blue-300">{selectedFile.name}</span>
<span className="text-xs text-blue-400/70">({(selectedFile.size / 1024 / 1024).toFixed(1)} MB)</span>
</div>
<Button
type="button"
variant="ghost"
size="sm"
onClick={clearSelectedFile}
className="h-6 w-6 p-0 text-blue-600 hover:text-blue-800"
className="h-6 w-6 p-0 text-blue-400 hover:text-blue-200"
>
×
</Button>
@ -1298,7 +1298,7 @@ const DiscussionPanel = ({
<div className="flex justify-between items-center mt-3">
<div className="flex items-center space-x-2">
<p className="text-sm text-slate-500">
<p className="text-sm text-muted-foreground">
{isSpeaking ? 'Speaking...' :
effectiveAiModeActive ? 'AI mode active' :
'Manual moderation mode'}
@ -1313,7 +1313,7 @@ const DiscussionPanel = ({
className={`hover-transition ${
effectiveAiModeActive
? 'bg-red-50 text-red-600 hover:bg-red-100'
: 'bg-blue-50 text-blue-600 hover:bg-blue-100'
: 'bg-blue-500/10 text-blue-400 hover:bg-blue-500/20'
}`}
title={effectiveAiModeActive ? "Stop AI mode and return to manual" : "Start autonomous AI conversation"}
>
@ -1346,7 +1346,7 @@ const DiscussionPanel = ({
scrollToBottom();
}
}}
className={`hover-transition ${autoScroll ? 'bg-blue-50 text-blue-600 hover:bg-blue-100' : ''}`}
className={`hover-transition ${autoScroll ? 'bg-blue-500/10 text-blue-400 hover:bg-blue-500/20' : ''}`}
title={autoScroll ? 'Disable auto-scroll' : 'Enable auto-scroll'}
>
<ArrowDown className="h-3 w-3 mr-1" />
@ -1386,7 +1386,7 @@ const DiscussionPanel = ({
{/* Show AI mode status and controls */}
{effectiveAiModeActive && (
<div className="flex items-center gap-2">
<div className="flex items-center gap-1 text-sm text-slate-600">
<div className="flex items-center gap-1 text-sm text-muted-foreground">
<div className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div>
<span>AI Active</span>
</div>

View file

@ -25,29 +25,29 @@ const ModeSwitchMarker = ({ modeEvent }: ModeSwitchMarkerProps) => {
const getEventColor = (eventType: string) => {
switch (eventType) {
case 'ai_mode_started':
return 'text-blue-600';
return 'text-blue-400';
case 'manual_mode_started':
return 'text-slate-600';
return 'text-muted-foreground';
case 'ai_session_concluded':
return 'text-green-600';
return 'text-green-400';
default:
return 'text-gray-600';
return 'text-muted-foreground';
}
};
return (
<div className="flex items-center my-6 px-4">
<div className="flex-1 border-t border-gray-200"></div>
<div className={`mx-4 px-3 py-1 bg-white border border-gray-200 rounded-full ${getEventColor(modeEvent.event_type)}`}>
<div className="flex-1 border-t border-border"></div>
<div className={`mx-4 px-3 py-1 bg-card border border-border rounded-full ${getEventColor(modeEvent.event_type)}`}>
<div className="flex items-center space-x-2 text-xs font-medium">
<span>{getEventText(modeEvent.event_type)}</span>
<span className="text-gray-400">at</span>
<span className="text-muted-foreground">at</span>
<span>{formatTime(modeEvent.timestamp)}</span>
</div>
</div>
<div className="flex-1 border-t border-gray-200"></div>
<div className="flex-1 border-t border-border"></div>
</div>
);
};
export default ModeSwitchMarker;
export default ModeSwitchMarker;

View file

@ -18,34 +18,34 @@ interface ReasoningPanelProps {
reasoningHistory: ReasoningEntry[];
isVisible: boolean;
onToggle: () => void;
isAiMode?: boolean; // Whether the focus group is in AI mode
isAiMode?: boolean;
}
const ActionIcon = ({ action }: { action: string }) => {
switch (action) {
case 'moderator_speak':
return <MessageSquare className="h-4 w-4 text-blue-500" />;
return <MessageSquare className="h-4 w-4 text-blue-400" />;
case 'participant_respond':
return <Users className="h-4 w-4 text-green-500" />;
return <Users className="h-4 w-4 text-green-400" />;
case 'participant_interaction':
return <Users className="h-4 w-4 text-primary" />;
case 'probe_trigger':
return <Zap className="h-4 w-4 text-orange-500" />;
return <Zap className="h-4 w-4 text-orange-400" />;
case 'end_session':
return <AlertTriangle className="h-4 w-4 text-red-500" />;
return <AlertTriangle className="h-4 w-4 text-red-400" />;
default:
return <Brain className="h-4 w-4 text-gray-500" />;
return <Brain className="h-4 w-4 text-muted-foreground" />;
}
};
const StatusIcon = ({ status }: { status: string }) => {
switch (status) {
case 'success':
return <CheckCircle className="h-3 w-3 text-green-500" />;
return <CheckCircle className="h-3 w-3 text-green-400" />;
case 'error':
return <XCircle className="h-3 w-3 text-red-500" />;
return <XCircle className="h-3 w-3 text-red-400" />;
case 'pending':
return <Clock className="h-3 w-3 text-yellow-500 animate-pulse" />;
return <Clock className="h-3 w-3 text-yellow-400 animate-pulse" />;
default:
return null;
}
@ -75,10 +75,10 @@ const ReasoningEntry = ({ entry, isLatest }: { entry: ReasoningEntry; isLatest:
const [isExpanded, setIsExpanded] = useState(isLatest);
return (
<Card className={`mb-2 ${isLatest ? 'ring-2 ring-blue-200 bg-blue-50/50' : ''}`}>
<Card className={`mb-2 ${isLatest ? 'ring-2 ring-blue-500/30 bg-blue-500/10' : ''}`}>
<Collapsible open={isExpanded} onOpenChange={setIsExpanded}>
<CollapsibleTrigger asChild>
<CardHeader className="pb-2 cursor-pointer hover:bg-gray-50/50 transition-colors">
<CardHeader className="pb-2 cursor-pointer hover:bg-white/5 transition-colors">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<ActionIcon action={entry.action} />
@ -89,7 +89,7 @@ const ReasoningEntry = ({ entry, isLatest }: { entry: ReasoningEntry; isLatest:
</span>
<StatusIcon status={entry.execution_status} />
</div>
<span className="text-xs text-gray-500">
<span className="text-xs text-muted-foreground">
{formatTimestamp(entry.timestamp)}
</span>
</div>
@ -101,9 +101,9 @@ const ReasoningEntry = ({ entry, isLatest }: { entry: ReasoningEntry; isLatest:
</Badge>
)}
{isExpanded ? (
<ChevronUp className="h-4 w-4 text-gray-400" />
<ChevronUp className="h-4 w-4 text-muted-foreground" />
) : (
<ChevronDown className="h-4 w-4 text-gray-400" />
<ChevronDown className="h-4 w-4 text-muted-foreground" />
)}
</div>
</div>
@ -113,31 +113,31 @@ const ReasoningEntry = ({ entry, isLatest }: { entry: ReasoningEntry; isLatest:
<CardContent className="pt-0">
<div className="space-y-2">
<div>
<h4 className="text-sm font-medium text-gray-700 mb-1">AI Reasoning:</h4>
<p className="text-sm text-gray-600 bg-gray-50 p-2 rounded italic">
<h4 className="text-sm font-medium text-foreground mb-1">AI Reasoning:</h4>
<p className="text-sm text-muted-foreground bg-white/5 p-2 rounded italic">
"{entry.reasoning}"
</p>
</div>
{entry.details && Object.keys(entry.details).length > 0 && (
<div>
<h4 className="text-sm font-medium text-gray-700 mb-1">Details:</h4>
<div className="text-xs text-gray-600 bg-gray-50 p-2 rounded font-mono">
<h4 className="text-sm font-medium text-foreground mb-1">Details:</h4>
<div className="text-xs text-muted-foreground bg-white/5 p-2 rounded font-mono">
{JSON.stringify(entry.details, null, 2)}
</div>
</div>
)}
{entry.execution_result && (
<div>
<h4 className="text-sm font-medium text-gray-700 mb-1">
<h4 className="text-sm font-medium text-foreground mb-1">
Execution Result:
</h4>
<div className="text-xs text-gray-600 bg-gray-50 p-2 rounded">
<div className="text-xs text-muted-foreground bg-white/5 p-2 rounded">
{entry.execution_result.error ? (
<span className="text-red-600">Error: {entry.execution_result.error}</span>
<span className="text-red-400">Error: {entry.execution_result.error}</span>
) : (
<span className="text-green-600">
<span className="text-green-400">
{entry.execution_result.message || 'Success'}
</span>
)}
@ -155,10 +155,8 @@ const ReasoningEntry = ({ entry, isLatest }: { entry: ReasoningEntry; isLatest:
const ReasoningPanel = ({ reasoningHistory, isVisible, onToggle, isAiMode = false }: ReasoningPanelProps) => {
const [autoScroll, setAutoScroll] = useState(true);
// Auto-expand latest entry when new reasoning arrives
useEffect(() => {
if (autoScroll && reasoningHistory.length > 0) {
// Scroll to top of reasoning panel when new entry arrives
const reasoningPanel = document.getElementById('reasoning-panel-content');
if (reasoningPanel) {
reasoningPanel.scrollTop = 0;
@ -167,10 +165,10 @@ const ReasoningPanel = ({ reasoningHistory, isVisible, onToggle, isAiMode = fals
}, [reasoningHistory.length, autoScroll]);
return (
<div className="border-t border-gray-200 bg-white">
<div className="border-t border-border bg-card">
<Collapsible open={isVisible} onOpenChange={onToggle}>
<CollapsibleTrigger asChild>
<div className="flex items-center justify-between p-3 cursor-pointer hover:bg-gray-50 transition-colors">
<div className="flex items-center justify-between p-3 cursor-pointer hover:bg-white/5 transition-colors">
<div className="flex items-center gap-2">
<Brain className="h-4 w-4 text-primary" />
<span className="font-medium text-sm">
@ -188,27 +186,26 @@ const ReasoningPanel = ({ reasoningHistory, isVisible, onToggle, isAiMode = fals
)}
</div>
{isVisible ? (
<ChevronUp className="h-4 w-4 text-gray-400" />
<ChevronUp className="h-4 w-4 text-muted-foreground" />
) : (
<ChevronDown className="h-4 w-4 text-gray-400" />
<ChevronDown className="h-4 w-4 text-muted-foreground" />
)}
</div>
</CollapsibleTrigger>
<CollapsibleContent>
<div className="border-t border-gray-100">
<div className="border-t border-border">
{isAiMode ? (
// AI Mode: Show reasoning history
reasoningHistory.length === 0 ? (
<div className="p-4 text-center text-gray-500">
<Brain className="h-8 w-8 mx-auto mb-2 text-gray-300" />
<div className="p-4 text-center text-muted-foreground">
<Brain className="h-8 w-8 mx-auto mb-2 text-muted-foreground/40" />
<p className="text-sm">No AI decisions yet</p>
<p className="text-xs text-gray-400">
<p className="text-xs text-muted-foreground/70">
Reasoning will appear here when the AI makes decisions
</p>
</div>
) : (
<ScrollArea
id="reasoning-panel-content"
<ScrollArea
id="reasoning-panel-content"
className="h-[25vh] p-3"
>
<div className="space-y-2">
@ -223,14 +220,13 @@ const ReasoningPanel = ({ reasoningHistory, isVisible, onToggle, isAiMode = fals
</ScrollArea>
)
) : (
// Manual Mode: Show status and guidance
<div className="p-4 text-center text-gray-500">
<Settings className="h-8 w-8 mx-auto mb-2 text-gray-400" />
<p className="text-sm font-medium text-gray-700">Manual Moderation Mode</p>
<p className="text-xs text-gray-500 mt-1">
<div className="p-4 text-center text-muted-foreground">
<Settings className="h-8 w-8 mx-auto mb-2 text-muted-foreground/60" />
<p className="text-sm font-medium text-foreground">Manual Moderation Mode</p>
<p className="text-xs text-muted-foreground mt-1">
You are currently moderating the discussion manually.
</p>
<p className="text-xs text-gray-500 mt-2">
<p className="text-xs text-muted-foreground mt-2">
Switch to AI Mode to see automated reasoning and decisions.
</p>
</div>
@ -242,4 +238,4 @@ const ReasoningPanel = ({ reasoningHistory, isVisible, onToggle, isAiMode = fals
);
};
export default ReasoningPanel;
export default ReasoningPanel;