From 5d39e0f076bb34e3aa8f059c8b794516f6a10532 Mon Sep 17 00:00:00 2001 From: Max Ronzhin Date: Thu, 30 Jul 2026 00:25:19 +0300 Subject: [PATCH] =?UTF-8?q?feat(room):=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=BC=D0=B8=D0=BA=D1=80=D0=BE=D1=84=D0=BE=D0=BD=D0=B0?= =?UTF-8?q?=20=D0=B2=20=D0=BC=D0=B8=D0=BD=D0=B8-=D0=BE=D0=BA=D0=BD=D0=B5?= =?UTF-8?q?=20(PiP)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document PiP не показывает тулбар комнаты — во время звонка в мини-окне нельзя было замьютить себя, не разворачивая основное окно. Кнопка лежит поверх единственной плитки мини-плеера и использует тот же useTrackToggle, что и тулбар: React-контекст LiveKitRoom не разрывается порталом в pipWindow.document.body, поэтому состояние читается и меняется одинаково что в основном окне, что в мини-плеере. --- frontend/src/components/room/RoomStage.tsx | 27 +++++++++++++++++++++- frontend/src/styles/room.css | 25 +++++++++++++++++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/room/RoomStage.tsx b/frontend/src/components/room/RoomStage.tsx index 4f4939e..1f85321 100644 --- a/frontend/src/components/room/RoomStage.tsx +++ b/frontend/src/components/room/RoomStage.tsx @@ -1,5 +1,5 @@ import { useEffect, useState, type ReactNode } from 'react' -import { EyeOff, Users } from 'lucide-react' +import { EyeOff, Mic, MicOff, Users } from 'lucide-react' import { Track, type Participant } from 'livekit-client' import { CarouselLayout, @@ -8,6 +8,7 @@ import { isTrackReference, useRoomContext, useSpeakingParticipants, + useTrackToggle, useTracks, type TrackReferenceOrPlaceholder, } from '@livekit/components-react' @@ -93,6 +94,29 @@ function hasLiveVideo(track: TrackReferenceOrPlaceholder): boolean { return isTrackReference(track) && !track.publication.isMuted } +/** + * Кнопка микрофона поверх единственной плитки мини-плеера (задача A5): в + * Document PiP своего тулбара нет вовсе, а звонок продолжается — без неё + * замьютить себя можно, только развернув основное окно. `useTrackToggle` — + * тот же хук, что и в `RoomToolbar`, читает/меняет состояние ЧЕРЕЗ + * `RoomContext`, а не через DOM, поэтому работает одинаково что в основном + * окне, что в портале, рендерящем эту сцену внутрь `pipWindow.document.body` + * (React-контекст порталом не разрывается, в отличие от DOM-дерева). + */ +function PipMicToggle() { + const mic = useTrackToggle({ source: Track.Source.Microphone }) + return ( + + ) +} + /** * Основная сцена конференции: превью остальных участников + крупная плитка * активного спикера (FocusLayoutContainer + CarouselLayout при нескольких @@ -366,6 +390,7 @@ export function RoomStage({ return (
{focusTrack && } +
) diff --git a/frontend/src/styles/room.css b/frontend/src/styles/room.css index c4806a2..3e2778c 100644 --- a/frontend/src/styles/room.css +++ b/frontend/src/styles/room.css @@ -133,9 +133,32 @@ video[data-lk-source='screen_share'] { object-fit: contain; background: #000; } * `.stage-tiles` в основном окне) плюс подстраховочный `min-height`, чтобы * плитка не схлопывалась, если видео ещё не выдало реальные размеры. */ -.room-single-tile { flex: 1; min-height: 0; display: flex; } +.room-single-tile { position: relative; flex: 1; min-height: 0; display: flex; } .room-single-tile .lk-participant-tile { flex: 1; min-height: 220px; width: 100%; } +/* Кнопка микрофона мини-плеера (задача A5) — своего тулбара в PiP нет, + кнопка лежит поверх единственной плитки левым нижним углом (правый занят + штатным `.lk-focus-toggle-button`/нашей булавкой закрепления — тут её нет, + в PiP закреплять нечего, но геометрия зеркалит `.room-pin-toggle`). */ +.room-pip-mic-toggle { + position: absolute; + left: 0.5rem; + bottom: 0.5rem; + z-index: 5; + width: 36px; + height: 36px; + border-radius: 50%; + border: none; + display: flex; + align-items: center; + justify-content: center; + background: var(--color-room-mic-on); + color: #10331f; + cursor: pointer; +} +.room-pip-mic-toggle svg { width: 18px; height: 18px; } +.room-pip-mic-toggle.is-off { background: var(--color-room-danger-bg); color: #fff; } + /* * ---------- Колонка миниатюр (кнопка «Скрыть» + карусель) ---------- * Прямой ребёнок `.lk-focus-layout` — вместо самой карусели, потому что над