diff --git a/src/components/launch/LaunchWindow.tsx b/src/components/launch/LaunchWindow.tsx
index 032ecb4..2210276 100644
--- a/src/components/launch/LaunchWindow.tsx
+++ b/src/components/launch/LaunchWindow.tsx
@@ -97,7 +97,12 @@ export function LaunchWindow() {
const showWebcamControls = webcamEnabled && !recording;
const [isMicHovered, setIsMicHovered] = useState(false);
+ const [isMicFocused, setIsMicFocused] = useState(false);
+ const micExpanded = isMicHovered || isMicFocused;
+
const [isWebcamHovered, setIsWebcamHovered] = useState(false);
+ const [isWebcamFocused, setIsWebcamFocused] = useState(false);
+ const webcamExpanded = isWebcamHovered || isWebcamFocused;
const {
devices: micDevices,
@@ -108,6 +113,8 @@ export function LaunchWindow() {
devices: cameraDevices,
selectedDeviceId: selectedCameraId,
setSelectedDeviceId: setSelectedCameraId,
+ isLoading: isCameraDevicesLoading,
+ error: cameraDevicesError,
} = useCameraDevices(webcamEnabled);
const selectedMicLabel =
@@ -257,46 +264,43 @@ export function LaunchWindow() {
{/* Mic selector */}
{showMicControls && (
setIsMicHovered(true)}
onMouseLeave={() => setIsMicHovered(false)}
- style={{ width: isMicHovered ? "240px" : "140px", transition: "width 300ms ease" }}
+ onFocus={() => setIsMicFocused(true)}
+ onBlur={() => setIsMicFocused(false)}
+ style={{ width: micExpanded ? "240px" : "140px", transition: "width 300ms ease" }}
>
- {!isMicHovered ? (
+ {!micExpanded && (
{selectedMicLabel}
- ) : (
- <>
-
-
- >
+ )}
+
+ {micExpanded && (
+
)}
)}
@@ -304,43 +308,73 @@ export function LaunchWindow() {
{/* Webcam selector */}
{showWebcamControls && (
setIsWebcamHovered(true)}
onMouseLeave={() => setIsWebcamHovered(false)}
- style={{ width: isWebcamHovered ? "240px" : "140px", transition: "width 300ms ease" }}
+ onFocus={() => setIsWebcamFocused(true)}
+ onBlur={() => setIsWebcamFocused(false)}
+ style={{ width: webcamExpanded ? "240px" : "140px", transition: "width 300ms ease" }}
>
- {!isWebcamHovered ? (
+ {!webcamExpanded && (
{selectedCameraLabel}
- ) : cameraDevices.length > 0 ? (
- <>
-
-
- >
- ) : (
-
{t("webcam.searching")}
+ )}
+ {webcamExpanded &&
+ (isCameraDevicesLoading ? (
+
+ {t("webcam.searching")}
+
+ ) : cameraDevicesError ? (
+
+ {t("webcam.unavailable")}
+
+ ) : cameraDevices.length === 0 ? (
+
+ {t("webcam.noneFound")}
+
+ ) : (
+ <>
+
+
+ >
+ ))}
+ {!webcamExpanded && (
+
)}
diff --git a/src/i18n/locales/en/launch.json b/src/i18n/locales/en/launch.json
index f01e295..6e4a4ed 100644
--- a/src/i18n/locales/en/launch.json
+++ b/src/i18n/locales/en/launch.json
@@ -17,7 +17,9 @@
"enableWebcam": "Enable webcam",
"disableWebcam": "Disable webcam",
"defaultCamera": "Default Camera",
- "searching": "Searching..."
+ "searching": "Searching...",
+ "noneFound": "No camera found",
+ "unavailable": "Camera unavailable"
},
"sourceSelector": {
"loading": "Loading sources...",
diff --git a/src/i18n/locales/es/launch.json b/src/i18n/locales/es/launch.json
index 4902404..b25ec3d 100644
--- a/src/i18n/locales/es/launch.json
+++ b/src/i18n/locales/es/launch.json
@@ -17,7 +17,9 @@
"enableWebcam": "Activar cámara web",
"disableWebcam": "Desactivar cámara web",
"defaultCamera": "Cámara predeterminada",
- "searching": "Buscando..."
+ "searching": "Buscando...",
+ "noneFound": "No se encontró cámara",
+ "unavailable": "Cámara no disponible"
},
"sourceSelector": {
"loading": "Cargando fuentes...",
diff --git a/src/i18n/locales/zh-CN/launch.json b/src/i18n/locales/zh-CN/launch.json
index 48846a0..84fdcef 100644
--- a/src/i18n/locales/zh-CN/launch.json
+++ b/src/i18n/locales/zh-CN/launch.json
@@ -17,7 +17,9 @@
"enableWebcam": "启用摄像头",
"disableWebcam": "禁用摄像头",
"defaultCamera": "默认摄像头",
- "searching": "正在搜索..."
+ "searching": "正在搜索...",
+ "noneFound": "未找到摄像头",
+ "unavailable": "摄像头不可用"
},
"sourceSelector": {
"loading": "正在加载源...",