Cesar Mendivil f57ce90c11 feat: Enhance StudioControls with presentation and layout features
- Added props for handling presentation and screen sharing actions.
- Implemented buttons for opening presentation panel and changing layouts (grid/focus) and modes (video/audio).
- Updated UI to reflect active presentations and added functionality to clear presentations.

fix: Adjust StudioLeftSidebar and StudioRightPanel for full height

- Modified styles to ensure both sidebars occupy full height of the container.

feat: Introduce ParticipantsPanel for managing participants in the conference

- Created ParticipantsPanel component to display connected and invited participants.
- Integrated API calls to fetch invited participants and handle connection status.

feat: Implement PresentationPanel for sharing presentations

- Developed PresentationPanel component to handle file uploads and screen sharing.

refactor: Update StudioVideoArea to support layout and mode changes

- Refactored StudioVideoArea to accept layout and mode props, rendering appropriate conference views.

feat: Add AudioConference and VideoConference prefabs for audio and video handling

- Created AudioConference and VideoConference components to manage respective media streams.

feat: Introduce Chat component for real-time messaging

- Developed Chat component to facilitate messaging between participants.

feat: Implement ControlBar for user controls in the conference

- Created ControlBar component for managing participant actions like leaving the conference and toggling audio/video.

feat: Add PreJoin component for pre-conference setup

- Developed PreJoin component to allow users to preview video before joining the conference.

chore: Update Vite configuration for better module resolution

- Enhanced Vite config to include path aliases for easier imports across the project.

chore: Add TypeScript definitions for environment variables

- Created env.d.ts to define types for environment variables used in the project.
2025-11-07 14:29:14 -07:00

180 lines
7.0 KiB
TypeScript

import { useState } from 'react'
import { MdAdd, MdMoreVert, MdEdit, MdDelete, MdContentCopy } from 'react-icons/md'
import { DEMO_SCENES } from '../config/demo'
interface Scene {
id: string
name: string
thumbnail: string
active: boolean
}
const StudioLeftSidebar = () => {
const [scenes, setScenes] = useState<Scene[]>(DEMO_SCENES)
const [openMenuId, setOpenMenuId] = useState<string | null>(null)
const handleSceneClick = (sceneId: string) => {
setScenes(scenes.map(scene => ({
...scene,
active: scene.id === sceneId
})))
}
const handleAddScene = () => {
const newScene: Scene = {
id: Date.now().toString(),
name: `Nueva Escena ${scenes.length + 1}`,
thumbnail: '/placeholder-scene.jpg',
active: false
}
setScenes([...scenes, newScene])
}
const handleDeleteScene = (sceneId: string) => {
if (scenes.length > 1) {
setScenes(scenes.filter(scene => scene.id !== sceneId))
}
setOpenMenuId(null)
}
const handleDuplicateScene = (sceneId: string) => {
const sceneToDuplicate = scenes.find(scene => scene.id === sceneId)
if (sceneToDuplicate) {
const newScene: Scene = {
...sceneToDuplicate,
id: Date.now().toString(),
name: `${sceneToDuplicate.name} (copia)`,
active: false
}
setScenes([...scenes, newScene])
}
setOpenMenuId(null)
}
return (
<div className="w-64 h-full bg-gray-800 border-r border-gray-700 flex flex-col">
{/* Header de Escenas */}
<div className="p-4 border-b border-gray-700">
<h3 className="text-white font-semibold text-sm flex items-center gap-2">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 4v16M17 4v16M3 8h4m10 0h4M3 12h18M3 16h4m10 0h4M4 20h16a1 1 0 001-1V5a1 1 0 00-1-1H4a1 1 0 00-1 1v14a1 1 0 001 1z" />
</svg>
Escenas
</h3>
</div>
{/* Lista de Escenas */}
<div className="flex-1 overflow-y-auto p-2">
{scenes.map((scene) => (
<div
key={scene.id}
className={`group relative flex items-center gap-3 p-2 rounded-lg mb-2 cursor-pointer transition-all ${
scene.active
? 'bg-pink-500/20 border border-pink-500/50'
: 'bg-gray-700/50 hover:bg-gray-700 border border-transparent'
}`}
onClick={() => handleSceneClick(scene.id)}
>
{/* Thumbnail */}
<div className={`w-16 h-10 rounded overflow-hidden flex-shrink-0 ${
scene.active ? 'ring-2 ring-pink-500' : ''
}`}>
<div className="w-full h-full bg-gray-600 flex items-center justify-center">
<svg className="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" />
</svg>
</div>
</div>
{/* Nombre */}
<span className={`flex-1 text-sm truncate ${
scene.active ? 'text-white font-medium' : 'text-gray-300'
}`}>
{scene.name}
</span>
{/* Menú de opciones */}
<div className="relative">
<button
onClick={(e) => {
e.stopPropagation()
setOpenMenuId(openMenuId === scene.id ? null : scene.id)
}}
className="p-1 rounded hover:bg-gray-600 text-gray-400 hover:text-white opacity-0 group-hover:opacity-100 transition-opacity"
>
<MdMoreVert size={18} />
</button>
{/* Dropdown menu */}
{openMenuId === scene.id && (
<div className="absolute right-0 top-full mt-1 w-40 bg-gray-700 rounded-lg shadow-lg border border-gray-600 py-1 z-50">
<button
onClick={(e) => {
e.stopPropagation()
handleDuplicateScene(scene.id)
}}
className="w-full px-3 py-2 text-left text-sm text-gray-300 hover:bg-gray-600 flex items-center gap-2"
>
<MdContentCopy size={16} />
Duplicar
</button>
<button
onClick={(e) => {
e.stopPropagation()
// TODO: Implementar edición
setOpenMenuId(null)
}}
className="w-full px-3 py-2 text-left text-sm text-gray-300 hover:bg-gray-600 flex items-center gap-2"
>
<MdEdit size={16} />
Renombrar
</button>
<button
onClick={(e) => {
e.stopPropagation()
handleDeleteScene(scene.id)
}}
className="w-full px-3 py-2 text-left text-sm text-red-400 hover:bg-gray-600 flex items-center gap-2"
disabled={scenes.length === 1}
>
<MdDelete size={16} />
Eliminar
</button>
</div>
)}
</div>
</div>
))}
{/* Botón agregar escena */}
<button
onClick={handleAddScene}
className="w-full flex items-center justify-center gap-2 p-3 rounded-lg border-2 border-dashed border-gray-600 text-gray-400 hover:border-pink-500 hover:text-pink-500 transition-all mt-2"
>
<MdAdd size={20} />
<span className="text-sm font-medium">Nueva Escena</span>
</button>
</div>
{/* Acciones rápidas */}
<div className="p-3 border-t border-gray-700 space-y-2">
<button className="w-full flex items-center gap-3 px-3 py-2 text-sm text-gray-300 hover:text-white hover:bg-gray-700 rounded-lg transition-colors">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
</svg>
Agregar Elemento
</button>
<button className="w-full flex items-center gap-3 px-3 py-2 text-sm text-gray-300 hover:text-white hover:bg-gray-700 rounded-lg transition-colors">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
Añadir Multimedia
</button>
</div>
</div>
)
}
export default StudioLeftSidebar