aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
760 lines (757 loc) • 30.2 kB
JavaScript
'use client';
import { jsx, jsxs } from 'react/jsx-runtime';
import { useReducedMotion } from '../../hooks/useReducedMotion.js';
import { cn } from '../../lib/utilsComprehensive.js';
import { motion, AnimatePresence } from 'framer-motion';
import { AlertCircle, HelpCircle, Settings, X, CheckCircle, Pause, SkipBack, SkipForward, Volume1, MessageCircle, Mic, MicOff } from 'lucide-react';
import { useState, useEffect, useCallback } from 'react';
// Mock voice control hook - in real implementation this would use actual Web Speech API
const useVoiceGlassControl = () => {
const [isEnabled, setIsEnabled] = useState(false);
const [isListening, setIsListening] = useState(false);
const [isSupported, setIsSupported] = useState(false);
const [transcript, setTranscript] = useState("");
const [interimTranscript, setInterimTranscript] = useState("");
const [lastCommand, setLastCommand] = useState(null);
const [error, setError] = useState(null);
const [wakeWordDetected, setWakeWordDetected] = useState(false);
const [availableVoices, setAvailableVoices] = useState([]);
// Mock implementation
useEffect(() => {
setIsSupported(typeof window !== "undefined" && ("webkitSpeechRecognition" in window || "SpeechRecognition" in window) && "speechSynthesis" in window);
if (typeof window !== "undefined" && "speechSynthesis" in window) {
const loadVoices = () => {
const voices = speechSynthesis.getVoices();
setAvailableVoices(voices);
};
loadVoices();
speechSynthesis.onvoiceschanged = loadVoices;
}
}, []);
const enable = useCallback(() => {
if (!isSupported) {
setError("Voice control not supported in this browser");
return;
}
setIsEnabled(true);
setError(null);
}, [isSupported]);
const disable = useCallback(() => {
setIsEnabled(false);
setIsListening(false);
setWakeWordDetected(false);
}, []);
const toggle = useCallback(() => {
if (isEnabled) {
disable();
} else {
enable();
}
}, [isEnabled, enable, disable]);
const speak = useCallback((text, voice) => {
if (!isSupported) return;
const utterance = new SpeechSynthesisUtterance(text);
if (voice) {
utterance.voice = voice;
}
speechSynthesis.speak(utterance);
}, [isSupported]);
const clearError = useCallback(() => {
setError(null);
}, []);
const getAvailableVoices = useCallback(() => {
return availableVoices;
}, [availableVoices]);
return {
state: {
isEnabled,
isListening,
isSupported,
transcript,
interimTranscript,
lastCommand,
error,
wakeWordDetected,
lastFeedback: lastCommand?.feedback
},
actions: {
enable,
disable,
toggle,
speak,
clearError,
getAvailableVoices
}
};
};
// Mock voice commands helper
const GlassVoiceCommands = () => {
const commands = [`"Hey Genesis" - wake word to activate voice control`, `"Show navigation" - open main navigation menu`, `"Hide navigation" - close main navigation menu`, `"Go to home" - navigate to home page`, `"Go to settings" - navigate to settings page`, `"Scroll up" - scroll page up`, `"Scroll down" - scroll page down`, `"Play music" - start playing media`, `"Pause music" - pause current media`, `"Next track" - skip to next track`, `"Previous track" - go to previous track`, `"Increase volume" - turn up volume`, `"Decrease volume" - turn down volume`, `"Show help" - display voice commands help`, `"Hide help" - close help overlay`, `"Toggle theme" - switch between light and dark mode`, `"Show notifications" - open notifications panel`, `"Hide notifications" - close notifications panel`, `"Search for [term]" - search for specific content`, `"Open [app name]" - launch specific application`, `"Close [window]" - close specific window or panel`];
return commands;
};
function VoiceGlassControl({
className,
position = "top-left",
autoEnable = false,
showTranscript = true,
onVoiceCommand,
onToggleControls,
wakeWord = "Hey Genesis",
enableFeedback = true,
showHelp = true,
maxTranscriptLength = 100
}) {
const prefersReducedMotion = useReducedMotion();
const {
state,
actions
} = useVoiceGlassControl();
const [showSettings, setShowSettings] = useState(false);
const [showHelpPanel, setShowHelpPanel] = useState(false);
const [selectedVoice, setSelectedVoice] = useState(null);
const [feedbackEnabled, setFeedbackEnabled] = useState(enableFeedback);
const [currentVolume, setCurrentVolume] = useState(75);
const [isPlaying, setIsPlaying] = useState(false);
// Auto-enable on mount if requested
useEffect(() => {
if (autoEnable && state.isSupported && !state.isEnabled) {
actions.enable();
}
}, [autoEnable, state.isSupported, state.isEnabled, actions]);
// Load available voices when speech synthesis is ready
useEffect(() => {
const loadVoices = () => {
const voices = actions.getAvailableVoices();
if (voices.length > 0 && !selectedVoice) {
// Prefer English voices
const englishVoice = voices.find(voice => voice.lang.startsWith("en") && voice.localService) || voices.find(voice => voice.lang.startsWith("en")) || voices[0];
setSelectedVoice(englishVoice);
}
};
loadVoices();
if (typeof window !== "undefined" && window.speechSynthesis) {
window.speechSynthesis.onvoiceschanged = loadVoices;
}
return () => {
if (typeof window !== "undefined" && window.speechSynthesis) {
window.speechSynthesis.onvoiceschanged = null;
}
};
}, [actions, selectedVoice]);
// Handle voice command callback
useEffect(() => {
if (state.lastCommand && onVoiceCommand) {
onVoiceCommand(state.lastCommand.originalText, state.lastCommand);
}
}, [state.lastCommand, onVoiceCommand]);
// Handle controls visibility
useEffect(() => {
if (state.lastCommand?.type === "TOGGLE_CONTROLS" && onToggleControls) {
onToggleControls(state.lastCommand.parameters?.show || false);
}
}, [state.lastCommand, onToggleControls]);
// Mock voice command processing
const processVoiceCommand = useCallback(transcript => {
const command = transcript.toLowerCase().trim();
// Navigation commands
if (command.includes("show navigation") || command.includes("open menu")) {
setLastCommand({
type: "NAVIGATION",
action: "show",
feedback: "Navigation menu opened",
parameters: {
target: "navigation"
}
});
} else if (command.includes("hide navigation") || command.includes("close menu")) {
setLastCommand({
type: "NAVIGATION",
action: "hide",
feedback: "Navigation menu closed",
parameters: {
target: "navigation"
}
});
} else if (command.includes("go to home")) {
setLastCommand({
type: "NAVIGATION",
action: "navigate",
feedback: "Navigating to home",
parameters: {
target: "home"
}
});
} else if (command.includes("go to settings")) {
setLastCommand({
type: "NAVIGATION",
action: "navigate",
feedback: "Opening settings",
parameters: {
target: "settings"
}
});
}
// Media commands
else if (command.includes("play music") || command.includes("play")) {
setIsPlaying(true);
setLastCommand({
type: "MEDIA",
action: "play",
feedback: "Playing music",
parameters: {
target: "music"
}
});
} else if (command.includes("pause music") || command.includes("pause")) {
setIsPlaying(false);
setLastCommand({
type: "MEDIA",
action: "pause",
feedback: "Music paused",
parameters: {
target: "music"
}
});
} else if (command.includes("next track") || command.includes("next")) {
setLastCommand({
type: "MEDIA",
action: "next",
feedback: "Next track",
parameters: {
target: "music"
}
});
} else if (command.includes("previous track") || command.includes("previous")) {
setLastCommand({
type: "MEDIA",
action: "previous",
feedback: "Previous track",
parameters: {
target: "music"
}
});
}
// Volume commands
else if (command.includes("increase volume") || command.includes("volume up")) {
const newVolume = Math.min(100, currentVolume + 10);
setCurrentVolume(newVolume);
setLastCommand({
type: "VOLUME",
action: "increase",
feedback: `Volume set to ${newVolume}%`,
parameters: {
volume: newVolume
}
});
} else if (command.includes("decrease volume") || command.includes("volume down")) {
const newVolume = Math.max(0, currentVolume - 10);
setCurrentVolume(newVolume);
setLastCommand({
type: "VOLUME",
action: "decrease",
feedback: `Volume set to ${newVolume}%`,
parameters: {
volume: newVolume
}
});
}
// UI commands
else if (command.includes("toggle theme")) {
setLastCommand({
type: "UI",
action: "toggle_theme",
feedback: "Theme toggled",
parameters: {
target: "theme"
}
});
} else if (command.includes("show help")) {
setShowHelpPanel(true);
setLastCommand({
type: "UI",
action: "show_help",
feedback: "Help panel opened",
parameters: {
target: "help"
}
});
} else if (command.includes("hide help")) {
setShowHelpPanel(false);
setLastCommand({
type: "UI",
action: "hide_help",
feedback: "Help panel closed",
parameters: {
target: "help"
}
});
} else if (command.includes("show notifications")) {
setLastCommand({
type: "UI",
action: "show_notifications",
feedback: "Notifications panel opened",
parameters: {
target: "notifications"
}
});
} else if (command.includes("hide notifications")) {
setLastCommand({
type: "UI",
action: "hide_notifications",
feedback: "Notifications panel closed",
parameters: {
target: "notifications"
}
});
}
// Help command
else if (command.includes("what can i say") || command.includes("help")) {
setShowHelpPanel(true);
setLastCommand({
type: "HELP",
action: "show_commands",
feedback: "Showing available voice commands",
parameters: {
target: "commands"
}
});
}
// Unknown command
else {
setLastCommand({
type: "UNKNOWN",
action: "unknown",
feedback: `I didn't understand: "${transcript}"`,
parameters: {
originalText: transcript
}
});
}
}, [currentVolume]);
// Mock function to set last command (would be handled by the hook in real implementation)
const setLastCommand = command => {
// In real implementation, this would update the hook's state
console.log("Voice command processed:", command);
if (feedbackEnabled && command.feedback) {
actions.speak(command.feedback, selectedVoice || undefined);
}
};
const positionClasses = {
"bottom-left": "bottom-4 left-4",
"bottom-right": "bottom-4 right-4",
"top-left": "top-4 left-4",
"top-right": "top-4 right-4"
};
const getStateIcon = () => {
if (!state.isSupported) return jsx(AlertCircle, {
className: 'h-5 w-5 text-primary'
});
if (state.isListening) return jsx(Mic, {
className: 'h-5 w-5 text-primary'
});
if (state.wakeWordDetected) return jsx(Mic, {
className: 'h-5 w-5 text-primary animate-pulse'
});
if (state.error) return jsx(AlertCircle, {
className: 'h-5 w-5 text-primary'
});
if (state.isEnabled) return jsx(MicOff, {
className: 'h-5 w-5 glass-text-secondary'
});
return jsx(MicOff, {
className: 'h-5 w-5 glass-text-secondary'
});
};
const getStateColor = () => {
if (!state.isSupported) return "border-red-400 bg-red-400/10";
if (state.isListening) return "border-blue-400 bg-blue-400/10";
if (state.wakeWordDetected) return "border-green-400 bg-green-400/10";
if (state.error) return "border-red-400 bg-red-400/10";
return "border-gray-400 bg-gray-400/10";
};
const getStateDescription = () => {
if (!state.isSupported) return "Voice control not supported";
if (state.isListening) return `Listening for "${wakeWord}"...`;
if (state.wakeWordDetected) return "Wake word detected! Speak your command...";
if (state.error) return state.error;
if (state.isEnabled) return "Voice control active - say wake word to begin";
return "Voice control inactive";
};
const handleTestCommand = () => {
const testCommands = ["show navigation", "play music", "increase volume", "toggle theme", "show help"];
const randomCommand = testCommands[Math.floor(Math.random() * testCommands.length)];
processVoiceCommand(randomCommand);
};
if (!state.isSupported) {
return jsx("div", {
className: cn("fixed z-50", positionClasses[position], className),
children: jsx(motion.div, {
className: "glass-glass-glass-backdrop-blur-lg glass-border glass-border-red/20 glass-surface-red/10 glass-p-3 glass-radius-lg glass-contrast-guard",
whileHover: {
scale: 1.05
},
children: jsxs("div", {
className: 'glass-flex glass-items-center glass-gap-2 text-primary',
children: [jsx(AlertCircle, {
className: 'h-4 w-4'
}), jsx("span", {
className: "glass-text-sm",
children: "Voice control not supported"
})]
})
})
});
}
return jsx("div", {
className: cn("fixed z-50", positionClasses[position], className),
children: jsxs("div", {
className: "glass-flex glass-flex-col glass-gap-2",
children: [jsxs(motion.div, {
className: cn("glass-glass-backdrop-blur-lg border p-3 rounded-lg transition-all duration-300 glass-contrast-guard", getStateColor()),
whileHover: {
scale: 1.05
},
children: [jsxs("div", {
className: "glass-flex glass-items-center glass-gap-3",
children: [jsx("button", {
onClick: actions.toggle,
className: 'glass-flex glass-items-center glass-justify-center w-10 h-10 glass-radius-full glass-surface-subtle/10 hover:glass-surface-subtle/20 transition-colors glass-focus glass-touch-target glass-contrast-guard',
children: getStateIcon()
}), jsxs("div", {
className: 'glass-flex-1 min-glass-w-0',
children: [jsx("div", {
className: 'glass-text-sm font-medium text-primary',
children: "Voice Control"
}), jsx("div", {
className: 'glass-text-xs text-primary/70 truncate',
children: getStateDescription()
})]
}), jsxs("div", {
className: "glass-flex glass-items-center glass-gap-1",
children: [showHelp && jsx("button", {
onClick: () => setShowHelpPanel(true),
className: 'glass-p-1.5 hover:glass-surface-subtle/10 glass-radius transition-colors glass-focus glass-touch-target glass-contrast-guard',
title: "Help",
children: jsx(HelpCircle, {
className: 'h-4 w-4 text-primary/70'
})
}), jsx("button", {
onClick: () => setShowSettings(true),
className: 'glass-p-1.5 hover:glass-surface-subtle/10 glass-radius transition-colors glass-focus glass-touch-target glass-contrast-guard',
title: "Settings",
children: jsx(Settings, {
className: 'h-4 w-4 text-primary/70'
})
})]
})]
}), state.wakeWordDetected && jsx(motion.div, {
initial: {
opacity: 0,
y: -10
},
animate: prefersReducedMotion ? {} : {
opacity: 1,
y: 0
},
exit: {
opacity: 0,
y: -10
},
className: 'mt-2 glass-p-2 glass-surface-green/20 glass-radius glass-text-xs text-primary text-center',
children: "\uD83C\uDFA4 Wake word detected - speak your command now!"
}), state.error && jsx(motion.div, {
initial: {
opacity: 0,
y: -10
},
animate: prefersReducedMotion ? {} : {
opacity: 1,
y: 0
},
className: 'mt-2 glass-p-2 glass-surface-red/20 glass-radius glass-text-xs text-primary',
children: jsxs("div", {
className: "glass-flex glass-items-center glass-justify-between",
children: [jsx("span", {
children: state.error
}), jsx("button", {
onClick: actions.clearError,
className: 'glass-p-0.5 hover:glass-surface-red/20 glass-radius glass-focus glass-touch-target glass-contrast-guard',
children: jsx(X, {
className: 'h-3 w-3'
})
})]
})
}), showTranscript && (state.transcript || state.interimTranscript) && jsx(motion.div, {
initial: {
opacity: 0,
y: -10
},
animate: prefersReducedMotion ? {} : {
opacity: 1,
y: 0
},
className: 'mt-2 glass-p-2 glass-surface-subtle/10 glass-radius glass-text-xs',
children: jsxs("div", {
className: 'text-primary font-medium',
children: [state.transcript, jsx("span", {
className: 'text-primary/50 italic',
children: state.interimTranscript
})]
})
}), state.lastFeedback && jsx(motion.div, {
initial: {
opacity: 0,
y: -10
},
animate: prefersReducedMotion ? {} : {
opacity: 1,
y: 0
},
className: 'mt-2 glass-p-2 glass-surface-blue/20 glass-radius glass-text-xs text-primary',
children: jsxs("div", {
className: "glass-flex glass-items-start glass-gap-2",
children: [jsx(CheckCircle, {
className: 'h-3 w-3 glass-mt-0-5 glass-flex-shrink-0'
}), jsx("span", {
children: state.lastFeedback
})]
})
}), isPlaying && jsxs(motion.div, {
initial: {
opacity: 0,
y: -10
},
animate: prefersReducedMotion ? {} : {
opacity: 1,
y: 0
},
className: 'mt-2 glass-flex glass-items-center glass-gap-2 glass-p-2 glass-surface-subtle/10 glass-radius',
children: [jsx("button", {
onClick: () => setIsPlaying(false),
className: 'glass-p-1 hover:glass-surface-subtle/20 glass-radius glass-focus glass-touch-target glass-contrast-guard',
title: "Pause",
children: jsx(Pause, {
className: 'h-3 w-3 text-primary'
})
}), jsx("button", {
onClick: () => processVoiceCommand("previous track"),
className: 'glass-p-1 hover:glass-surface-subtle/20 glass-radius glass-focus glass-touch-target glass-contrast-guard',
title: "Previous",
children: jsx(SkipBack, {
className: 'h-3 w-3 text-primary'
})
}), jsx("button", {
onClick: () => processVoiceCommand("next track"),
className: 'glass-p-1 hover:glass-surface-subtle/20 glass-radius glass-focus glass-touch-target glass-contrast-guard',
title: "Next",
children: jsx(SkipForward, {
className: 'h-3 w-3 text-primary'
})
}), jsxs("div", {
className: "glass-flex-1 glass-flex glass-items-center glass-gap-2",
children: [jsx(Volume1, {
className: 'h-3 w-3 text-primary/70'
}), jsx("div", {
className: 'glass-flex-1 glass-surface-subtle/20 glass-radius-full h-1',
children: jsx("div", {
className: 'glass-surface-blue h-1 glass-radius-full transition-all',
style: {
width: `${currentVolume}%`
}
})
}), jsxs("span", {
className: 'glass-text-xs text-primary/70',
children: [currentVolume, "%"]
})]
})]
})]
}), jsx(AnimatePresence, {
children: showSettings && jsx(motion.div, {
initial: {
opacity: 0,
scale: 0.95,
y: 20
},
animate: prefersReducedMotion ? {} : {
opacity: 1,
scale: 1,
y: 0
},
exit: {
opacity: 0,
scale: 0.95,
y: 20
},
children: jsxs("div", {
className: 'glass-glass-glass-backdrop-blur-lg glass-border glass-border-white/20 glass-surface-subtle/10 glass-p-4 glass-radius-lg w-80 glass-contrast-guard',
children: [jsxs("div", {
className: 'glass-flex glass-items-center glass-justify-between mb-3',
children: [jsx("h3", {
className: 'font-medium text-primary',
children: "Voice Settings"
}), jsx("button", {
onClick: () => setShowSettings(false),
className: 'glass-p-1 hover:glass-surface-subtle/10 glass-radius transition-colors glass-focus glass-touch-target glass-contrast-guard',
children: jsx(X, {
className: 'h-4 w-4 text-primary/70'
})
})]
}), jsxs("div", {
className: 'space-y-4',
children: [jsxs("div", {
children: [jsx("label", {
className: 'block glass-text-sm font-medium text-primary mb-2',
children: "Wake Word"
}), jsx("input", {
type: "text",
value: wakeWord,
readOnly: true,
className: 'glass-w-full glass-p-2 glass-surface-subtle/10 glass-border glass-border-white/20 glass-radius text-primary glass-text-sm glass-focus glass-touch-target glass-contrast-guard'
}), jsx("div", {
className: 'glass-text-xs text-primary/60 mt-1',
children: "Say this to activate voice control"
})]
}), jsxs("div", {
children: [jsx("label", {
className: 'block glass-text-sm font-medium text-primary mb-2',
children: "Voice"
}), jsx("select", {
value: selectedVoice?.name || "",
onChange: e => {
const voice = actions.getAvailableVoices().find(v => v.name === e.target.value);
setSelectedVoice(voice || null);
},
className: 'glass-w-full glass-p-2 glass-surface-subtle/10 glass-border glass-border-white/20 glass-radius text-primary glass-text-sm glass-focus glass-touch-target glass-contrast-guard',
children: actions.getAvailableVoices().map(voice => jsxs("option", {
value: voice.name,
className: "glass-surface-primary",
children: [voice.name, " (", voice.lang, ")"]
}, voice.name))
})]
}), jsxs("div", {
className: "glass-flex glass-items-center glass-justify-between",
children: [jsxs("div", {
children: [jsx("div", {
className: 'glass-text-sm font-medium text-primary',
children: "Voice Feedback"
}), jsx("div", {
className: 'glass-text-xs text-primary/60',
children: "Speak command confirmations"
})]
}), jsx("button", {
onClick: () => setFeedbackEnabled(!feedbackEnabled),
className: cn("w-10 h-6 rounded-full transition-colors relative glass-focus glass-touch-target glass-contrast-guard", feedbackEnabled ? "bg-blue-500" : "bg-white/20"),
children: jsx("div", {
className: `absolute top-0.5 w-5 h-5 bg-white rounded-full transition-transform ${feedbackEnabled ? "transform translate-x-4" : "translate-x-0.5"}`
})
})]
}), jsxs("div", {
children: [jsx("label", {
className: 'block glass-text-sm font-medium text-primary mb-2',
children: "Test Commands"
}), jsx("button", {
onClick: handleTestCommand,
className: 'glass-w-full glass-p-2 glass-surface-blue/20 hover:glass-surface-blue/30 glass-border glass-border-blue/30 glass-radius text-primary glass-text-sm transition-colors glass-focus glass-touch-target glass-contrast-guard',
children: "Try Random Command"
}), jsx("button", {
onClick: () => actions.speak("Voice control is working correctly", selectedVoice || undefined),
className: 'glass-w-full glass-p-2 glass-surface-green/20 hover:glass-surface-green/30 glass-border glass-border-green/30 glass-radius text-primary glass-text-sm transition-colors mt-2 glass-focus glass-touch-target glass-contrast-guard',
children: "Test Voice Output"
})]
}), jsxs("div", {
className: 'pt-3 glass-border-t glass-border-white/10 space-y-1 glass-text-xs text-primary/60',
children: [jsxs("div", {
children: ["Status: ", state.isEnabled ? "Enabled" : "Disabled"]
}), jsxs("div", {
children: ["Listening: ", state.isListening ? "Active" : "Inactive"]
}), jsxs("div", {
children: ["Available voices: ", actions.getAvailableVoices().length]
}), jsxs("div", {
children: ["Volume: ", currentVolume, "%"]
})]
})]
})]
})
})
}), jsx(AnimatePresence, {
children: showHelpPanel && jsx(motion.div, {
initial: {
opacity: 0,
scale: 0.95,
y: 20
},
animate: prefersReducedMotion ? {} : {
opacity: 1,
scale: 1,
y: 0
},
exit: {
opacity: 0,
scale: 0.95,
y: 20
},
children: jsxs("div", {
className: 'glass-glass-glass-backdrop-blur-lg glass-border glass-border-white/20 glass-surface-subtle/10 glass-p-4 glass-radius-lg w-96 max-h-80 overflow-y-auto glass-contrast-guard',
children: [jsxs("div", {
className: 'glass-flex glass-items-center glass-justify-between mb-3',
children: [jsx("h3", {
className: 'font-medium text-primary',
children: "Voice Commands"
}), jsx("button", {
onClick: () => setShowHelpPanel(false),
className: 'glass-p-1 hover:glass-surface-subtle/10 glass-radius transition-colors glass-focus glass-touch-target glass-contrast-guard',
children: jsx(X, {
className: 'h-4 w-4 text-primary/70'
})
})]
}), jsxs("div", {
className: 'space-y-3',
children: [jsxs("div", {
className: 'glass-text-sm text-primary/80',
children: ["Start commands with", " ", jsxs("span", {
className: 'font-mono glass-surface-subtle/20 glass-px-1 glass-radius',
children: ["\"", wakeWord, "\""]
}), ":"]
}), jsx("div", {
className: 'space-y-2',
children: GlassVoiceCommands().slice(0, 10).map((command, index) => jsx("div", {
className: "glass-p-2 glass-surface-subtle/5 glass-radius glass-text-sm",
children: jsxs("div", {
className: 'text-primary font-mono',
children: ["\"", command, "\""]
})
}, index))
}), jsx("div", {
className: 'pt-3 glass-border-t glass-border-white/10',
children: jsxs("div", {
className: 'glass-text-xs text-primary/60',
children: [jsxs("div", {
className: 'glass-flex glass-items-center glass-gap-2 mb-1',
children: [jsx(MessageCircle, {
className: 'h-3 w-3'
}), jsx("span", {
children: "Tips:"
})]
}), jsxs("ul", {
className: 'list-disc list-inside space-y-1 ml-5',
children: [jsx("li", {
children: "Speak clearly and at normal volume"
}), jsx("li", {
children: "Wait for the wake word confirmation"
}), jsx("li", {
children: "Use natural language variations"
}), jsx("li", {
children: "Check your microphone permissions"
})]
})]
})
})]
})]
})
})
})]
})
});
}
export { GlassVoiceCommands, VoiceGlassControl as default };
//# sourceMappingURL=VoiceGlassControl.js.map