import { LogOut, Maximize, MessageSquare, Mic, MicOff, Minimize, PictureInPicture2, ScreenShare, ScreenShareOff, Settings, Video, VideoOff, } from 'lucide-react' import { Track, type ScreenShareCaptureOptions } from 'livekit-client' import { DisconnectButton, useTrackToggle } from '@livekit/components-react' import { useToast } from '@/components/ui/ToastProvider' /** * Опции захвата демонстрации экрана: `audio: true` — звук * вкладки/экрана там, где браузер его отдаёт (Chrome/Edge — вкладка почти * всегда, целый экран — только Windows); `selfBrowserSurface: 'exclude'` * — не предлагать в списке * источников собственную вкладку (зеркальный туннель самой конференции); * `surfaceSwitching: 'include'` — разрешить переключать источник прямо во * время демонстрации, не останавливая её; `systemAudio: 'include'` — не * запрещать захват системного звука при выборе «весь экран». Вынесено в * модульную константу — `useTrackToggle` держит `JSON.stringify(captureOptions)` * в зависимостях внутреннего `useMemo`, инлайновый литерал был бы безвреден, * но константа явнее фиксирует неизменность опций. */ const SCREEN_SHARE_CAPTURE_OPTIONS: ScreenShareCaptureOptions = { audio: true, selfBrowserSurface: 'exclude', surfaceSwitching: 'include', systemAudio: 'include', } interface RoomToolbarProps { /** Показывать ли кнопку чата — `JoinOut.chat_enabled` И чат не помечен недоступным (close-код 4404). */ chatVisible: boolean chatOpen: boolean /** Число непрочитанных сообщений, накопленных со времени последнего открытия панели. */ chatUnreadCount: number onToggleChat: () => void /** Открыть диалог настроек устройств. */ onToggleSettings: () => void /** `document.fullscreenEnabled` — false скрывает кнопку. */ fullscreenSupported: boolean fullscreenActive: boolean onToggleFullscreen: () => void /** Доступен ли мини-плеер хоть в каком-то виде (Document PiP либо video-фолбэк) — false в Firefox скрывает кнопку. */ pipSupported: boolean pipActive: boolean onTogglePiP: () => void } /** * Нижний тулбар комнаты: микрофон/камера/демонстрация экрана/ * настройки устройств/полноэкранный режим/мини-плеер/чат/выход — собственные * кнопки на хуках LiveKit (useTrackToggle/DisconnectButton) и панели чата, * стилизованные по design/mockups/room.html. */ export function RoomToolbar({ chatVisible, chatOpen, chatUnreadCount, onToggleChat, onToggleSettings, fullscreenSupported, fullscreenActive, onToggleFullscreen, pipSupported, pipActive, onTogglePiP, }: RoomToolbarProps) { const toast = useToast() const mic = useTrackToggle({ source: Track.Source.Microphone }) const camera = useTrackToggle({ source: Track.Source.Camera }) const screenShare = useTrackToggle({ source: Track.Source.ScreenShare, captureOptions: SCREEN_SHARE_CAPTURE_OPTIONS, // Отмена браузерного диалога выбора экрана/окна (пользователь нажал // «Отмена») приходит сюда как NotAllowedError — молча игнорируем, это не // ошибка приложения. Прочие сбои (например, `NotReadableError` при // занятом источнике) показываем тостом. onDeviceError: (error) => { if (error.name === 'NotAllowedError') return toast.show('Не удалось начать демонстрацию экрана', 'error') }, }) return ( ) }