From d3122d64f88dd9b2fbe150af95ece94b00420191 Mon Sep 17 00:00:00 2001 From: Cesar Mendivil Date: Fri, 7 Nov 2025 17:34:24 -0700 Subject: [PATCH] =?UTF-8?q?feat:=20Mejorar=20el=20panel=20de=20participant?= =?UTF-8?q?es=20y=20agregar=20funcionalidad=20de=20pesta=C3=B1as=20en=20el?= =?UTF-8?q?=20panel=20derecho?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/ParticipantsPanel.tsx | 117 ++++++++++-------- .../studio-panel/src/components/Studio.tsx | 53 ++++++-- .../src/components/StudioRightPanel.tsx | 107 +++++++++------- 3 files changed, 170 insertions(+), 107 deletions(-) diff --git a/packages/studio-panel/src/components/ParticipantsPanel.tsx b/packages/studio-panel/src/components/ParticipantsPanel.tsx index f9c2c89..267aa08 100644 --- a/packages/studio-panel/src/components/ParticipantsPanel.tsx +++ b/packages/studio-panel/src/components/ParticipantsPanel.tsx @@ -57,62 +57,79 @@ const ParticipantsPanel: React.FC = ({ roomName }) => { const isConnected = (identity: string) => liveParticipants.some((p: any) => p.identity === identity) return ( -
-
-

Conectados

- {liveParticipants.length === 0 ? ( -

No hay participantes conectados.

- ) : ( -
- {liveParticipants.map((p: any) => ( -
-
-
- {p.identity?.charAt(0)?.toUpperCase()} -
-
-

{p.identity}

-

{p.isLocal ? 'Tú (presentador)' : 'Invitado'}

-
-
-
- - -
-
- ))} -
- )} +
+ {/* Header */} +
+

Participantes

+

+ Gestiona quién está en el stream +

-
-

Invitados

- {loading ? ( -

Cargando...

- ) : error ? ( -

Error: {error}

- ) : invited.length === 0 ? ( -

No hay invitados registrados.

- ) : ( -
- {invited.map((inv) => ( -
-
-
- {inv.identity?.charAt(0)?.toUpperCase()} + {/* Content */} +
+
+

Conectados

+ {liveParticipants.length === 0 ? ( +

No hay participantes conectados.

+ ) : ( +
+ {liveParticipants.map((p: any) => ( +
+
+
+ {p.identity?.charAt(0)?.toUpperCase()} +
+
+

{p.identity}

+

{p.isLocal ? 'Tú (presentador)' : 'Invitado'}

+
-
-

{inv.identity}

-

{isConnected(inv.identity) ? 'Conectado' : 'Esperando'}

+
+ +
-
- + ))} +
+ )} +
+ +
+

Invitados

+ {loading ? ( +

Cargando...

+ ) : error ? ( +

Error: {error}

+ ) : invited.length === 0 ? ( +

No hay invitados registrados.

+ ) : ( +
+ {invited.map((inv) => ( +
+
+
+ {inv.identity?.charAt(0)?.toUpperCase()} +
+
+

{inv.identity}

+

{isConnected(inv.identity) ? 'Conectado' : 'Esperando'}

+
+
+
+ +
-
- ))} -
- )} + ))} +
+ )} +
) diff --git a/packages/studio-panel/src/components/Studio.tsx b/packages/studio-panel/src/components/Studio.tsx index 5e49cf4..30ced5e 100644 --- a/packages/studio-panel/src/components/Studio.tsx +++ b/packages/studio-panel/src/components/Studio.tsx @@ -4,7 +4,7 @@ import '@livekit/components-styles' import StudioHeader from './StudioHeader' import StudioLeftSidebar from './StudioLeftSidebar' import StudioVideoArea from './StudioVideoArea' -import StudioRightPanel from './StudioRightPanel' +import StudioRightPanel, { TabsColumn, TabType } from './StudioRightPanel' import StudioControls from './StudioControls' import PresentationPanel from './PresentationPanel' import { DEMO_TOKEN } from '../config/demo' @@ -25,6 +25,7 @@ const Studio: React.FC = ({ userName, roomName }) => { const [mode, setMode] = useState<'video' | 'audio'>('video') const [showLeftPanel, setShowLeftPanel] = useState(true) const [showRightPanel, setShowRightPanel] = useState(true) + const [activeRightTab, setActiveRightTab] = useState('brand') // Utility: heurística ligera para validar token en cliente const isTokenLikelyValid = (t?: string) => { @@ -332,18 +333,34 @@ const Studio: React.FC = ({ userName, roomName }) => { {/* Panel derecho - Ajustes (posición absoluta derecha) */}
- + setActiveRightTab(t)} + /> +
+ + + {/* Tabs Column externo (modo demo): permanece visible incluso cuando el panel se oculta */} +
+
+ setActiveRightTab(t)} /> +
- {/* Botón toggle derecho (en el borde izquierdo del panel derecho) */} + {/* Botón toggle derecho (se mueve con el panel) */}
+ + {/* Panel derecho - Ajustes (posición absoluta derecha) */}
- + setActiveRightTab(t)} + /> + +
+ + {/* Tabs Column externo: permanece visible incluso cuando el panel se oculta */} +
+
+ setActiveRightTab(t)} /> +
- {/* Botón toggle derecho (en el borde izquierdo del panel derecho) */} + {/* Botón toggle derecho (se mueve con el panel) */} + ) + })} +
+ ) +} + +const StudioRightPanel = ({ roomName, activeTab: activeTabProp, onChangeTab }: { roomName?: string; activeTab?: TabType; onChangeTab?: (t: TabType) => void }) => { + const [internalActiveTab, setInternalActiveTab] = useState('brand') + const activeTab = activeTabProp ?? internalActiveTab + const setActiveTab = onChangeTab ?? setInternalActiveTab return (
@@ -52,41 +92,7 @@ const StudioRightPanel = ({ roomName }: { roomName?: string }) => { - {/* Tabs Column - Vertical tabs como en Streamyard */} -
- {tabs.map((tab) => { - const Icon = tab.icon - const isActive = activeTab === tab.id - - return ( - - ) - })} -
+
) } @@ -218,7 +224,12 @@ const NotesTab = () => {
{notes.length} caracteres - +