Compare commits

...

2 Commits

Author SHA1 Message Date
Adam Shiervani d0e6bb1ac6 feat: enhance audio settings UI and localization
Added new audio-related UI components and improved localization for multiple languages. The SettingsItem component now supports badge links and variants, enhancing the user experience. Updated the AudioPopover to include quick audio controls for speakers and microphone, with descriptions and HTTPS-only warnings where applicable.
2025-11-03 13:55:57 +01:00
Adam Shiervani 645b178d0d feat: add audio dependencies to Docker build context
Included the installation script for audio dependencies in the Docker build context preparation. This ensures that the necessary audio components are available during the build process.
2025-11-03 13:54:11 +01:00
12 changed files with 112 additions and 34 deletions

View File

@ -41,6 +41,7 @@ BUILD_IN_DOCKER=${BUILD_IN_DOCKER:-false}
function prepare_docker_build_context() {
msg_info "▶ Preparing docker build context ..."
cp .devcontainer/install-deps.sh \
.devcontainer/install_audio_deps.sh \
go.mod \
go.sum \
Dockerfile.build \

View File

@ -64,6 +64,12 @@
"audio_output_failed_enable": "Kunne ikke aktivere lydudgang: {error}",
"audio_output_title": "Lydudgang",
"audio_popover_title": "Lyd",
"audio_popover_description": "Hurtige lydkontroller til højttalere og mikrofon",
"audio_speakers_title": "Højttalere",
"audio_speakers_description": "Lyd fra mål til højttalere",
"audio_microphone_title": "Mikrofon",
"audio_microphone_description": "Mikrofonindgang til mål",
"audio_https_only": "Kun HTTPS",
"audio_settings_description": "Konfigurer lydindgangs- og lydudgangsindstillinger for din JetKVM-enhed",
"audio_settings_hdmi_label": "HDMI",
"audio_settings_input_description": "Aktiver eller deaktiver mikrofon lyd til fjerncomputeren",

View File

@ -64,6 +64,12 @@
"audio_output_failed_enable": "Fehler beim Aktivieren des Audioausgangs: {error}",
"audio_output_title": "Audioausgang",
"audio_popover_title": "Audio",
"audio_popover_description": "Schnelle Audiosteuerung für Lautsprecher und Mikrofon",
"audio_speakers_title": "Lautsprecher",
"audio_speakers_description": "Audio vom Ziel zu Lautsprechern",
"audio_microphone_title": "Mikrofon",
"audio_microphone_description": "Mikrofoneingang zum Ziel",
"audio_https_only": "Nur HTTPS",
"audio_settings_description": "Konfigurieren Sie Audio-Eingangs- und Ausgangseinstellungen für Ihr JetKVM-Gerät",
"audio_settings_hdmi_label": "HDMI",
"audio_settings_input_description": "Mikrofonaudio zum entfernten Computer aktivieren oder deaktivieren",

View File

@ -64,6 +64,12 @@
"audio_output_failed_enable": "Failed to enable audio output: {error}",
"audio_output_title": "Audio Output",
"audio_popover_title": "Audio",
"audio_popover_description": "Quick audio controls for speakers and microphone",
"audio_speakers_title": "Speakers",
"audio_speakers_description": "Audio from target to speakers",
"audio_microphone_title": "Microphone",
"audio_microphone_description": "Microphone input to target",
"audio_https_only": "HTTPS only",
"audio_settings_description": "Configure audio input and output settings for your JetKVM device",
"audio_settings_hdmi_label": "HDMI",
"audio_settings_input_description": "Enable or disable microphone audio to the remote computer",

View File

@ -64,6 +64,12 @@
"audio_output_failed_enable": "Error al activar la salida de audio: {error}",
"audio_output_title": "Salida de audio",
"audio_popover_title": "Audio",
"audio_popover_description": "Controles de audio rápidos para altavoces y micrófono",
"audio_speakers_title": "Altavoces",
"audio_speakers_description": "Audio del objetivo a los altavoces",
"audio_microphone_title": "Micrófono",
"audio_microphone_description": "Entrada de micrófono al objetivo",
"audio_https_only": "Solo HTTPS",
"audio_settings_description": "Configure los ajustes de entrada y salida de audio para su dispositivo JetKVM",
"audio_settings_hdmi_label": "HDMI",
"audio_settings_input_description": "Habilitar o deshabilitar el audio del micrófono a la computadora remota",

View File

@ -64,6 +64,12 @@
"audio_output_failed_enable": "Échec de l'activation de la sortie audio : {error}",
"audio_output_title": "Sortie audio",
"audio_popover_title": "Audio",
"audio_popover_description": "Contrôles audio rapides pour haut-parleurs et microphone",
"audio_speakers_title": "Haut-parleurs",
"audio_speakers_description": "Audio de la cible vers les haut-parleurs",
"audio_microphone_title": "Microphone",
"audio_microphone_description": "Entrée microphone vers la cible",
"audio_https_only": "HTTPS uniquement",
"audio_settings_description": "Configurez les paramètres d'entrée et de sortie audio pour votre appareil JetKVM",
"audio_settings_hdmi_label": "HDMI",
"audio_settings_input_description": "Activer ou désactiver l'audio du microphone vers l'ordinateur distant",

View File

@ -64,6 +64,12 @@
"audio_output_failed_enable": "Impossibile abilitare l'uscita audio: {error}",
"audio_output_title": "Uscita audio",
"audio_popover_title": "Audio",
"audio_popover_description": "Controlli audio rapidi per altoparlanti e microfono",
"audio_speakers_title": "Altoparlanti",
"audio_speakers_description": "Audio dal target agli altoparlanti",
"audio_microphone_title": "Microfono",
"audio_microphone_description": "Ingresso microfono al target",
"audio_https_only": "Solo HTTPS",
"audio_settings_description": "Configura le impostazioni di ingresso e uscita audio per il tuo dispositivo JetKVM",
"audio_settings_hdmi_label": "HDMI",
"audio_settings_input_description": "Abilita o disabilita l'audio del microfono al computer remoto",

View File

@ -64,6 +64,12 @@
"audio_output_failed_enable": "Kunne ikke aktivere lydutgang: {error}",
"audio_output_title": "Lydutgang",
"audio_popover_title": "Lyd",
"audio_popover_description": "Raske lydkontroller for høyttalere og mikrofon",
"audio_speakers_title": "Høyttalere",
"audio_speakers_description": "Lyd fra mål til høyttalere",
"audio_microphone_title": "Mikrofon",
"audio_microphone_description": "Mikrofoninngang til mål",
"audio_https_only": "Kun HTTPS",
"audio_settings_description": "Konfigurer lydinngangs- og lydutgangsinnstillinger for JetKVM-enheten din",
"audio_settings_hdmi_label": "HDMI",
"audio_settings_input_description": "Aktiver eller deaktiver mikrofonlyd til den eksterne datamaskinen",

View File

@ -64,6 +64,12 @@
"audio_output_failed_enable": "Det gick inte att aktivera ljudutgången: {error}",
"audio_output_title": "Ljudutgång",
"audio_popover_title": "Ljud",
"audio_popover_description": "Snabba ljudkontroller för högtalare och mikrofon",
"audio_speakers_title": "Högtalare",
"audio_speakers_description": "Ljud från mål till högtalare",
"audio_microphone_title": "Mikrofon",
"audio_microphone_description": "Mikrofoningång till mål",
"audio_https_only": "Endast HTTPS",
"audio_settings_description": "Konfigurera ljudinmatnings- och ljudutgångsinställningar för din JetKVM-enhet",
"audio_settings_hdmi_label": "HDMI",
"audio_settings_input_description": "Aktivera eller inaktivera mikrofonljud till fjärrdatorn",

View File

@ -64,6 +64,12 @@
"audio_output_failed_enable": "启用音频输出失败:{error}",
"audio_output_title": "音频输出",
"audio_popover_title": "音频",
"audio_popover_description": "扬声器和麦克风的快速音频控制",
"audio_speakers_title": "扬声器",
"audio_speakers_description": "从目标设备到扬声器的音频",
"audio_microphone_title": "麦克风",
"audio_microphone_description": "麦克风输入到目标设备",
"audio_https_only": "仅限 HTTPS",
"audio_settings_description": "配置 JetKVM 设备的音频输入和输出设置",
"audio_settings_hdmi_label": "HDMI",
"audio_settings_input_description": "启用或禁用到远程计算机的麦克风音频",

View File

@ -1,17 +1,45 @@
import { cx } from "@/cva.config";
import { Link } from "react-router";
import { cva, cx } from "@/cva.config";
import LoadingSpinner from "@components/LoadingSpinner";
const badgeVariants = cva({
base: "ml-2 rounded-full px-2 py-1 text-[10px] font-medium leading-none text-white dark:border",
variants: {
variant: {
error: "bg-red-500 dark:border-red-700 dark:bg-red-800 dark:text-red-50",
info: "bg-blue-500 dark:border-blue-600 dark:bg-blue-700 dark:text-blue-50",
},
},
});
interface SettingsItemProps {
readonly title: string;
readonly description: string | React.ReactNode;
readonly badge?: string;
readonly badgeVariant?: "error" | "info";
readonly badgeLink?: string;
readonly className?: string;
readonly loading?: boolean;
readonly children?: React.ReactNode;
}
export function SettingsItem(props: SettingsItemProps) {
const { title, description, badge, children, className, loading } = props;
const { title, description, badge, badgeVariant = "error", badgeLink, children, className, loading } = props;
const badgeClasses = badgeVariants({ variant: badgeVariant });
const badgeContent = badge && (
badgeLink ? (
<Link to={badgeLink} className={cx(badgeClasses, "hover:opacity-80 transition-opacity cursor-pointer")}>
{badge}
</Link>
) : (
<span className={badgeClasses}>
{badge}
</span>
)
);
return (
<label
@ -24,11 +52,7 @@ export function SettingsItem(props: SettingsItemProps) {
<div className="flex items-center gap-x-2">
<div className="flex items-center text-base font-semibold text-black dark:text-white">
{title}
{badge && (
<span className="ml-2 rounded-full bg-red-500 px-2 py-1 text-[10px] font-medium leading-none text-white dark:border dark:border-red-700 dark:bg-red-800 dark:text-red-50">
{badge}
</span>
)}
{badgeContent}
</div>
{loading && <LoadingSpinner className="h-4 w-4 text-blue-500" />}
</div>

View File

@ -1,10 +1,10 @@
import { useCallback, useEffect, useState } from "react";
import { LuVolume2 } from "react-icons/lu";
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
import { GridCard } from "@components/Card";
import { SettingsItem } from "@components/SettingsItem";
import { Button } from "@components/Button";
import { SettingsPageHeader } from "@components/SettingsPageheader";
import Checkbox from "@components/Checkbox";
import notifications from "@/notifications";
import { m } from "@localizations/messages.js";
@ -14,6 +14,7 @@ export default function AudioPopover() {
const [audioInputEnabled, setAudioInputEnabled] = useState<boolean>(true);
const [usbAudioEnabled, setUsbAudioEnabled] = useState<boolean>(false);
const [loading, setLoading] = useState(false);
const isHttps = window.location.protocol === "https:" || window.location.hostname === "localhost";
useEffect(() => {
send("getAudioOutputEnabled", {}, (resp: JsonRpcResponse) => {
@ -42,8 +43,7 @@ export default function AudioPopover() {
});
}, [send]);
const handleAudioOutputEnabledToggle = useCallback(() => {
const enabled = !audioOutputEnabled;
const handleAudioOutputEnabledToggle = useCallback((enabled: boolean) => {
setLoading(true);
send("setAudioOutputEnabled", { enabled }, (resp: JsonRpcResponse) => {
setLoading(false);
@ -58,10 +58,9 @@ export default function AudioPopover() {
notifications.success(successMsg);
}
});
}, [send, audioOutputEnabled]);
}, [send]);
const handleAudioInputEnabledToggle = useCallback(() => {
const enabled = !audioInputEnabled;
const handleAudioInputEnabledToggle = useCallback((enabled: boolean) => {
setLoading(true);
send("setAudioInputEnabled", { enabled }, (resp: JsonRpcResponse) => {
setLoading(false);
@ -76,28 +75,26 @@ export default function AudioPopover() {
notifications.success(successMsg);
}
});
}, [send, audioInputEnabled]);
}, [send]);
return (
<GridCard>
<div className="space-y-4 p-4 py-3">
<div className="space-y-4">
<div className="flex items-center gap-2 text-slate-900 dark:text-slate-100">
<LuVolume2 className="h-5 w-5" />
<h3 className="font-semibold">{m.audio_popover_title()}</h3>
</div>
<SettingsPageHeader
title={m.audio_popover_title()}
description={m.audio_popover_description()}
/>
<div className="space-y-3">
<SettingsItem
loading={loading}
title={m.audio_output_title()}
description={m.audio_output_description()}
title={m.audio_speakers_title()}
description={m.audio_speakers_description()}
>
<Button
size="SM"
theme={audioOutputEnabled ? "light" : "primary"}
text={audioOutputEnabled ? m.audio_disable() : m.audio_enable()}
onClick={handleAudioOutputEnabledToggle}
<Checkbox
checked={audioOutputEnabled}
onChange={(e) => handleAudioOutputEnabledToggle(e.target.checked)}
/>
</SettingsItem>
@ -107,14 +104,16 @@ export default function AudioPopover() {
<SettingsItem
loading={loading}
title={m.audio_input_title()}
description={m.audio_input_description()}
title={m.audio_microphone_title()}
description={m.audio_microphone_description()}
badge={!isHttps ? m.audio_https_only() : undefined}
badgeVariant="info"
badgeLink={!isHttps ? "settings/access" : undefined}
>
<Button
size="SM"
theme={audioInputEnabled ? "light" : "primary"}
text={audioInputEnabled ? m.audio_disable() : m.audio_enable()}
onClick={handleAudioInputEnabledToggle}
<Checkbox
checked={audioInputEnabled}
disabled={!isHttps}
onChange={(e) => handleAudioInputEnabledToggle(e.target.checked)}
/>
</SettingsItem>
</>