import React, { useState, useEffect, useRef } from "react"; import { useStreamCrafterContext } from "../context/StreamCrafterContext"; import { useStudioTranslate } from "../context/StudioI18nContext"; import type { QualityProfile, StudioTranslationStrings, } from "@livepeer-frameworks/streamcrafter-core"; const QUALITY_PROFILES: { id: QualityProfile; labelKey: keyof StudioTranslationStrings; descKey: keyof StudioTranslationStrings; }[] = [ { id: "professional", labelKey: "professional", descKey: "professionalDesc" }, { id: "broadcast", labelKey: "broadcast", descKey: "broadcastDesc" }, { id: "conference", labelKey: "conference", descKey: "conferenceDesc" }, ]; const SettingsIcon = ({ size = 16 }: { size?: number }) => ( ); export interface StudioSettingsProps { /** Override quality profile (falls back to context) */ qualityProfile?: QualityProfile; /** Override callback (falls back to context) */ onProfileChange?: (profile: QualityProfile) => void; /** Auto-close dropdown on selection */ autoClose?: boolean; } export const StudioSettings: React.FC = ({ qualityProfile: propProfile, onProfileChange, autoClose = true, }) => { const ctx = useStreamCrafterContext(); const t = useStudioTranslate(); const [isOpen, setIsOpen] = useState(false); const dropdownRef = useRef(null); const buttonRef = useRef(null); const profile = propProfile ?? ctx.qualityProfile; useEffect(() => { if (!isOpen) return; const handleClickOutside = (e: MouseEvent) => { const target = e.target as Node; if ( dropdownRef.current && !dropdownRef.current.contains(target) && buttonRef.current && !buttonRef.current.contains(target) ) { setIsOpen(false); } }; const handleEscape = (e: KeyboardEvent) => { if (e.key === "Escape") setIsOpen(false); }; document.addEventListener("mousedown", handleClickOutside); document.addEventListener("keydown", handleEscape); return () => { document.removeEventListener("mousedown", handleClickOutside); document.removeEventListener("keydown", handleEscape); }; }, [isOpen]); const handleSelect = (id: QualityProfile) => { if (ctx.isStreaming) return; if (onProfileChange) onProfileChange(id); else ctx.setQualityProfile(id); if (autoClose) setIsOpen(false); }; return ( setIsOpen(!isOpen)} title={t("settings")} style={{ display: "flex", alignItems: "center", justifyContent: "center" }} > {isOpen && ( {t("quality")} {QUALITY_PROFILES.map((p) => ( handleSelect(p.id)} disabled={ctx.isStreaming} style={{ width: "100%", padding: "6px 8px", textAlign: "left", fontSize: "12px", borderRadius: "4px", transition: "all 0.15s", border: "none", cursor: ctx.isStreaming ? "not-allowed" : "pointer", opacity: ctx.isStreaming ? 0.5 : 1, background: profile === p.id ? "rgba(122, 162, 247, 0.2)" : "transparent", color: profile === p.id ? "#7aa2f7" : "#a9b1d6", }} > {t(p.labelKey)} {t(p.descKey)} ))} )} ); };