@voice-ai-workforce/react
Version:
React components with 3-tier interface modes for voice-controlled workforce applications
208 lines (207 loc) • 26.1 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
// packages/react/src/components/VoiceSettingsPanel.tsx
import { useState } from 'react';
import { useVoiceAI } from '../hooks/useVoiceAI';
import { useVoiceVisibility } from '../hooks/useVoiceVisibility';
import { useComponentTheme, useVoiceContext } from './VoiceProvider';
import { AIProvider, } from '../../../types/src/types';
import { SIZE_CLASSES } from '../utils/theme';
// Icons
const SettingsIcon = ({ className }) => (_jsx("svg", { className: className, fill: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { d: "M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.82,11.69,4.82,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.43-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z" }) }));
const MicrophoneIcon = ({ className }) => (_jsxs("svg", { className: className, fill: "currentColor", viewBox: "0 0 24 24", children: [_jsx("path", { d: "M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3z" }), _jsx("path", { d: "M17 11c0 2.76-2.24 5-5 5s-5-2.24-5-5H5c0 3.53 2.61 6.43 6 6.92V21h2v-3.08c3.39-.49 6-3.39 6-6.92h-2z" })] }));
const PaletteIcon = ({ className }) => (_jsx("svg", { className: className, fill: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { d: "M12,3c-4.97,0-9,4.03-9,9c0,0.83,0.12,1.64,0.33,2.41C4.06,15.31,4.92,16,6,16c1.66,0,3-1.34,3-3c0-1.66-1.34-3-3-3 c-0.44,0-0.85,0.09-1.23,0.26C4.28,8.53,4,6.84,4,5c0-0.55,0.45-1,1-1s1,0.45,1,1c0,0.28,0.22,0.5,0.5,0.5S7,5.28,7,5 c0-1.1-0.9-2-2-2s-2,0.9-2,2c0,2.21,0.34,4.31,0.96,6.26C3.36,11.09,3,10.59,3,10c0-4.97,4.03-9,9-9s9,4.03,9,9 c0,2.12-0.74,4.07-1.97,5.61c-0.26,0.33-0.13,0.81,0.26,0.95C20.47,16.91,21.73,17,23,17c0.55,0,1-0.45,1-1 C24,7.03,19.97,3,12,3z" }) }));
const CloudIcon = ({ className }) => (_jsx("svg", { className: className, fill: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { d: "M19.35 10.04A7.49 7.49 0 0 0 12 4C9.11 4 6.6 5.64 5.35 8.04A5.994 5.994 0 0 0 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96z" }) }));
const CloseIcon = ({ className }) => (_jsx("svg", { className: className, fill: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }));
const ResetIcon = ({ className }) => (_jsx("svg", { className: className, fill: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { d: "M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z" }) }));
const ModeIcon = ({ className }) => (_jsx("svg", { className: className, fill: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { d: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" }) }));
export const VoiceSettingsPanel = ({ config, onConfigChange, onClose, theme: customTheme, size = 'md', className = '', style,
// Legacy props - now controlled by visibility
showAdvanced, showThemeSettings, showAudioSettings, showProviderSettings,
// NEW: Mode support props
mode, visibilityOverrides, customLabels: propCustomLabels, ...props }) => {
const theme = useComponentTheme(customTheme);
const { updateTheme, resetTheme, setMode: setContextMode, updateVisibility, updateLabels } = useVoiceContext();
// NEW: Resolve visibility and labels based on mode
const { visibility, labels } = useVoiceVisibility(config, mode, visibilityOverrides);
// Merge prop labels with resolved labels
const effectiveLabels = {
voiceButton: { ...labels.voiceButton, ...propCustomLabels?.voiceButton },
status: { ...labels.status, ...propCustomLabels?.status },
providers: { ...labels.providers, ...propCustomLabels?.providers },
errors: { ...labels.errors, ...propCustomLabels?.errors }
};
// Determine what tabs to show based on mode and legacy props
const shouldShowAdvanced = showAdvanced !== undefined ? showAdvanced : visibility.showAdvancedSettings;
const shouldShowTheme = showThemeSettings !== undefined ? showThemeSettings : visibility.showAdvancedSettings;
const shouldShowAudio = showAudioSettings !== undefined ? showAudioSettings : visibility.showAdvancedSettings;
const shouldShowProvider = showProviderSettings !== undefined ? showProviderSettings : visibility.showProviders;
// Available tabs based on visibility
const availableTabs = [
{ id: 'general', label: 'General', icon: SettingsIcon, visible: true },
{ id: 'audio', label: 'Audio', icon: MicrophoneIcon, visible: shouldShowAudio },
{ id: 'providers', label: 'Providers', icon: CloudIcon, visible: shouldShowProvider },
{ id: 'theme', label: 'Theme', icon: PaletteIcon, visible: shouldShowTheme },
{ id: 'mode', label: 'Mode', icon: ModeIcon, visible: visibility.showAdvancedSettings },
{ id: 'advanced', label: 'Advanced', icon: SettingsIcon, visible: shouldShowAdvanced }
].filter(tab => tab.visible);
const [activeTab, setActiveTab] = useState(availableTabs[0]?.id || 'general');
// Voice AI state
const { getState } = useVoiceAI({ config, autoStart: false });
const state = getState();
// Settings state
const [settings, setSettings] = useState({
preferredProvider: config.aiProviders?.primary?.provider || AIProvider.OPENAI,
fallbackProviders: config.aiProviders?.fallbacks?.map(f => f.provider) || [],
microphoneGain: 1.0,
noiseReduction: true,
echoCancellation: true,
autoGainControl: true,
confidenceThreshold: config.confidenceThreshold || 0.8,
speechTimeout: 5000,
silenceTimeout: 2000,
autoStart: config.autoListen || false,
showVisualFeedback: true,
playAudioFeedback: true,
logLevel: 'info',
retryAttempts: config.aiProviders?.retryAttempts || 3,
requestTimeout: config.aiProviders?.timeoutMs || 10000,
});
// Handle settings change
const handleSettingChange = (key, value) => {
setSettings(prev => ({ ...prev, [key]: value }));
// Apply changes to config
const configUpdate = {};
switch (key) {
case 'preferredProvider':
if (config.aiProviders) {
configUpdate.aiProviders = {
...config.aiProviders,
// @ts-ignore
primary: { ...config.aiProviders.primary, provider: value }
};
}
break;
case 'confidenceThreshold':
configUpdate.confidenceThreshold = value;
break;
case 'autoStart':
configUpdate.autoListen = value;
break;
case 'retryAttempts':
if (config.aiProviders) {
configUpdate.aiProviders = {
...config.aiProviders,
retryAttempts: value
};
}
break;
case 'requestTimeout':
if (config.aiProviders) {
configUpdate.aiProviders = {
...config.aiProviders,
timeoutMs: value
};
}
break;
}
if (Object.keys(configUpdate).length > 0) {
onConfigChange?.(configUpdate);
}
};
// Reset all settings
const handleResetSettings = () => {
setSettings({
preferredProvider: AIProvider.OPENAI,
fallbackProviders: [],
microphoneGain: 1.0,
noiseReduction: true,
echoCancellation: true,
autoGainControl: true,
confidenceThreshold: 0.8,
speechTimeout: 5000,
silenceTimeout: 2000,
autoStart: false,
showVisualFeedback: true,
playAudioFeedback: true,
logLevel: 'info',
retryAttempts: 3,
requestTimeout: 10000,
});
resetTheme();
};
const panelClasses = [
'bg-white rounded-lg border shadow-lg',
SIZE_CLASSES.panel?.[size] || 'w-96 max-h-96',
className
].filter(Boolean).join(' ');
return (_jsxs("div", { className: panelClasses, style: {
backgroundColor: theme.colors.surface,
borderColor: theme.colors.border,
boxShadow: theme.shadows.lg,
...style
}, ...props, children: [_jsxs("div", { className: "flex items-center justify-between p-4 border-b", style: { borderColor: theme.colors.border }, children: [_jsxs("div", { className: "flex items-center space-x-2", children: [_jsx(SettingsIcon, { className: "w-5 h-5", style: { color: theme.colors.text.primary } }), _jsx("h3", { className: "text-lg font-semibold", style: { color: theme.colors.text.primary }, children: "Voice Settings" })] }), _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx("button", { onClick: handleResetSettings, className: "p-2 rounded hover:bg-gray-100 transition-colors", style: { color: theme.colors.text.secondary }, title: "Reset to defaults", children: _jsx(ResetIcon, { className: "w-4 h-4" }) }), onClose && (_jsx("button", { onClick: onClose, className: "p-2 rounded hover:bg-gray-100 transition-colors", style: { color: theme.colors.text.secondary }, title: "Close settings", children: _jsx(CloseIcon, { className: "w-4 h-4" }) }))] })] }), availableTabs.length > 1 && (_jsx("div", { className: "flex border-b overflow-x-auto", style: { borderColor: theme.colors.border }, children: availableTabs.map(tab => (_jsxs("button", { onClick: () => setActiveTab(tab.id), className: `flex items-center space-x-2 px-4 py-3 text-sm font-medium whitespace-nowrap transition-colors ${activeTab === tab.id
? 'border-b-2'
: 'hover:bg-gray-50'}`, style: {
color: activeTab === tab.id ? theme.colors.primary : theme.colors.text.secondary,
borderBottomColor: activeTab === tab.id ? theme.colors.primary : 'transparent'
}, children: [_jsx(tab.icon, { className: "w-4 h-4" }), _jsx("span", { children: tab.label })] }, tab.id))) })), _jsxs("div", { className: "p-4 max-h-96 overflow-y-auto", children: [activeTab === 'general' && (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium mb-2", style: { color: theme.colors.text.primary }, children: "Auto Start" }), _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx("input", { type: "checkbox", checked: settings.autoStart, onChange: (e) => handleSettingChange('autoStart', e.target.checked), className: "rounded" }), _jsx("span", { className: "text-sm", style: { color: theme.colors.text.secondary }, children: "Automatically start voice recognition when component loads" })] })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium mb-2", style: { color: theme.colors.text.primary }, children: "Confidence Threshold" }), _jsx("input", { type: "range", min: "0.1", max: "1.0", step: "0.1", value: settings.confidenceThreshold, onChange: (e) => handleSettingChange('confidenceThreshold', parseFloat(e.target.value)), className: "w-full" }), _jsxs("div", { className: "flex justify-between text-xs mt-1", style: { color: theme.colors.text.muted }, children: [_jsx("span", { children: "Low (0.1)" }), _jsxs("span", { children: ["Current: ", settings.confidenceThreshold] }), _jsx("span", { children: "High (1.0)" })] })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium mb-2", style: { color: theme.colors.text.primary }, children: "Feedback Options" }), _jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center space-x-2", children: [_jsx("input", { type: "checkbox", checked: settings.showVisualFeedback, onChange: (e) => handleSettingChange('showVisualFeedback', e.target.checked), className: "rounded" }), _jsx("span", { className: "text-sm", style: { color: theme.colors.text.secondary }, children: "Show visual feedback" })] }), _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx("input", { type: "checkbox", checked: settings.playAudioFeedback, onChange: (e) => handleSettingChange('playAudioFeedback', e.target.checked), className: "rounded" }), _jsx("span", { className: "text-sm", style: { color: theme.colors.text.secondary }, children: "Play audio feedback" })] })] })] })] })), activeTab === 'audio' && shouldShowAudio && (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium mb-2", style: { color: theme.colors.text.primary }, children: "Microphone Gain" }), _jsx("input", { type: "range", min: "0.1", max: "2.0", step: "0.1", value: settings.microphoneGain, onChange: (e) => handleSettingChange('microphoneGain', parseFloat(e.target.value)), className: "w-full" }), _jsxs("div", { className: "flex justify-between text-xs mt-1", style: { color: theme.colors.text.muted }, children: [_jsx("span", { children: "Low (0.1)" }), _jsxs("span", { children: ["Current: ", settings.microphoneGain, "x"] }), _jsx("span", { children: "High (2.0)" })] })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium mb-2", style: { color: theme.colors.text.primary }, children: "Audio Processing" }), _jsx("div", { className: "space-y-2", children: [
{ key: 'noiseReduction', label: 'Noise Reduction' },
{ key: 'echoCancellation', label: 'Echo Cancellation' },
{ key: 'autoGainControl', label: 'Auto Gain Control' }
].map(({ key, label }) => (_jsxs("div", { className: "flex items-center space-x-2", children: [_jsx("input", { type: "checkbox", checked: settings[key], onChange: (e) => handleSettingChange(key, e.target.checked), className: "rounded" }), _jsx("span", { className: "text-sm", style: { color: theme.colors.text.secondary }, children: label })] }, key))) })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium mb-2", style: { color: theme.colors.text.primary }, children: "Speech Timeout (ms)" }), _jsx("input", { type: "number", min: "1000", max: "30000", step: "1000", value: settings.speechTimeout, onChange: (e) => handleSettingChange('speechTimeout', parseInt(e.target.value)), className: "w-full px-3 py-2 border rounded-md text-sm", style: {
backgroundColor: theme.colors.background,
borderColor: theme.colors.border
} })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium mb-2", style: { color: theme.colors.text.primary }, children: "Silence Timeout (ms)" }), _jsx("input", { type: "number", min: "500", max: "10000", step: "500", value: settings.silenceTimeout, onChange: (e) => handleSettingChange('silenceTimeout', parseInt(e.target.value)), className: "w-full px-3 py-2 border rounded-md text-sm", style: {
backgroundColor: theme.colors.background,
borderColor: theme.colors.border
} })] })] })] })), activeTab === 'providers' && shouldShowProvider && (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium mb-2", style: { color: theme.colors.text.primary }, children: "Preferred Provider" }), _jsxs("select", { value: settings.preferredProvider, onChange: (e) => handleSettingChange('preferredProvider', e.target.value), className: "w-full px-3 py-2 border rounded-md text-sm", style: {
backgroundColor: theme.colors.background,
borderColor: theme.colors.border
}, children: [_jsx("option", { value: AIProvider.OPENAI, children: "OpenAI" }), _jsx("option", { value: AIProvider.ANTHROPIC, children: "Anthropic" }), _jsx("option", { value: AIProvider.GOOGLE, children: "Google" }), _jsx("option", { value: AIProvider.KEYWORDS, children: "Keywords Only" })] })] }), visibility.showProviderStatus && (_jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium mb-2", style: { color: theme.colors.text.primary }, children: "Provider Status" }), _jsx("div", { className: "space-y-2", children: Object.entries(state.providerStatus || {}).map(([provider, status]) => (_jsxs("div", { className: "flex items-center justify-between py-2 px-3 rounded", style: { backgroundColor: theme.colors.background }, children: [_jsx("span", { className: "text-sm capitalize", style: { color: theme.colors.text.primary }, children: visibility.showProviders ? provider : effectiveLabels.providers.generic }), _jsx("span", { className: `px-2 py-1 text-xs rounded ${status === 'available' ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'}`, children: status })] }, provider))) })] }))] })), activeTab === 'theme' && shouldShowTheme && (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium mb-2", style: { color: theme.colors.text.primary }, children: "Color Scheme" }), _jsx("div", { className: "grid grid-cols-3 gap-2", children: [
{ name: 'Blue', primary: '#2563eb' },
{ name: 'Green', primary: '#059669' },
{ name: 'Purple', primary: '#7c3aed' },
{ name: 'Red', primary: '#dc2626' },
{ name: 'Orange', primary: '#d97706' },
{ name: 'Gray', primary: '#64748b' }
].map((color) => (_jsxs("button", { onClick: () => updateTheme({
colors: {
...theme.colors,
primary: color.primary
}
}), className: "flex items-center space-x-2 p-2 rounded border hover:bg-gray-50 transition-colors", style: { borderColor: theme.colors.border }, children: [_jsx("div", { className: "w-4 h-4 rounded-full", style: { backgroundColor: color.primary } }), _jsx("span", { className: "text-xs", style: { color: theme.colors.text.secondary }, children: color.name })] }, color.name))) })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium mb-2", style: { color: theme.colors.text.primary }, children: "Border Radius" }), _jsxs("select", { value: theme.borderRadius.md, onChange: (e) => updateTheme({
borderRadius: {
...theme.borderRadius,
md: e.target.value
}
}), className: "w-full px-3 py-2 border rounded-md text-sm", style: {
backgroundColor: theme.colors.background,
borderColor: theme.colors.border
}, children: [_jsx("option", { value: "0", children: "Square" }), _jsx("option", { value: "0.25rem", children: "Small" }), _jsx("option", { value: "0.375rem", children: "Medium" }), _jsx("option", { value: "0.5rem", children: "Large" }), _jsx("option", { value: "1rem", children: "Extra Large" })] })] })] })), activeTab === 'mode' && visibility.showAdvancedSettings && (_jsx("div", { className: "space-y-4", children: _jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium mb-2", style: { color: theme.colors.text.primary }, children: "Interface Mode" }), _jsx("div", { className: "space-y-2", children: [
{
id: 'developer',
label: 'Developer Mode',
description: 'Shows all technical details and options'
},
{
id: 'project',
label: 'Project Mode',
description: 'Balanced view for project configuration'
},
{
id: 'end-user',
label: 'End User Mode',
description: 'Simplified interface for end users'
}
].map((modeOption) => (_jsx("div", { className: "border rounded p-3", style: { borderColor: theme.colors.border }, children: _jsxs("div", { className: "flex items-start space-x-3", children: [_jsx("input", { type: "radio", name: "interfaceMode", value: modeOption.id, checked: mode === modeOption.id, onChange: () => setContextMode && setContextMode(modeOption.id), className: "mt-1" }), _jsxs("div", { children: [_jsx("div", { className: "font-medium text-sm", style: { color: theme.colors.text.primary }, children: modeOption.label }), _jsx("div", { className: "text-xs", style: { color: theme.colors.text.secondary }, children: modeOption.description })] })] }) }, modeOption.id))) })] }) })), activeTab === 'advanced' && shouldShowAdvanced && (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium mb-2", style: { color: theme.colors.text.primary }, children: "Log Level" }), _jsxs("select", { value: settings.logLevel, onChange: (e) => handleSettingChange('logLevel', e.target.value), className: "w-full px-3 py-2 border rounded-md text-sm", style: {
backgroundColor: theme.colors.background,
borderColor: theme.colors.border
}, children: [_jsx("option", { value: "error", children: "Error" }), _jsx("option", { value: "warn", children: "Warning" }), _jsx("option", { value: "info", children: "Info" }), _jsx("option", { value: "debug", children: "Debug" })] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium mb-2", style: { color: theme.colors.text.primary }, children: "Retry Attempts" }), _jsx("input", { type: "number", min: "0", max: "10", value: settings.retryAttempts, onChange: (e) => handleSettingChange('retryAttempts', parseInt(e.target.value)), className: "w-full px-3 py-2 border rounded-md text-sm", style: {
backgroundColor: theme.colors.background,
borderColor: theme.colors.border
} })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium mb-2", style: { color: theme.colors.text.primary }, children: "Request Timeout (ms)" }), _jsx("input", { type: "number", min: "1000", max: "30000", step: "1000", value: settings.requestTimeout, onChange: (e) => handleSettingChange('requestTimeout', parseInt(e.target.value)), className: "w-full px-3 py-2 border rounded-md text-sm", style: {
backgroundColor: theme.colors.background,
borderColor: theme.colors.border
} })] })] }), visibility.showDebugInfo && (_jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium mb-2", style: { color: theme.colors.text.primary }, children: "Debug Information" }), _jsxs("div", { className: "p-3 rounded bg-gray-50 text-xs font-mono", style: { backgroundColor: theme.colors.background }, children: [_jsxs("div", { children: ["Active Provider: ", state.activeProvider || 'None'] }), _jsxs("div", { children: ["Available Providers: ", Object.keys(state.providerStatus || {}).join(', ')] }), _jsxs("div", { children: ["Commands Available: ", config.commands?.registry?.commands?.length || 0] }), _jsxs("div", { children: ["Current Mode: ", mode || config.interfaceMode || 'project'] }), _jsxs("div", { children: ["Theme: ", theme.colors.primary] })] })] }))] }))] })] }));
};
export default VoiceSettingsPanel;