diff --git a/packages/studio-panel/src/components/ui/RightSidePanel.tsx b/packages/studio-panel/src/components/ui/RightSidePanel.tsx new file mode 100644 index 0000000..4192231 --- /dev/null +++ b/packages/studio-panel/src/components/ui/RightSidePanel.tsx @@ -0,0 +1,68 @@ +import React from 'react' + +type Tab = { id: string; label: string } + +const TABS: Tab[] = [ + { id: 'assets', label: 'Activos multimedia' }, + { id: 'style', label: 'Estilo' }, + { id: 'people', label: 'Personas' }, + { id: 'notes', label: 'Notas' }, +] + +type Props = { + activeTab: string | null + onSelectTab: (id: string | null) => void +} + +const RightSidePanel: React.FC = ({ activeTab, onSelectTab }) => { + return ( + <> + {/* Tabs column */} +
+ {TABS.map((t) => ( + + ))} +
+ + {/* Panel area */} +
+ +
+ + ) +} + +export default RightSidePanel diff --git a/packages/studio-panel/src/components/ui/RightSidebar.tsx b/packages/studio-panel/src/components/ui/RightSidebar.tsx new file mode 100644 index 0000000..25d4ca0 --- /dev/null +++ b/packages/studio-panel/src/components/ui/RightSidebar.tsx @@ -0,0 +1,200 @@ +import React from 'react' +// Inline SVG icons (kept minimal for clarity) +const IconChat = ({ size = 20 }: { size?: number }) => ( + + + +) + +const IconInfo = ({ size = 20 }: { size?: number }) => ( + + + + +) + +const IconClock = ({ size = 20 }: { size?: number }) => ( + + + + +) + +const IconUsers = ({ size = 20 }: { size?: number }) => ( + + + + +) +import { useAssets } from '../../hooks/useAssets' +import { usePeople } from '../../hooks/usePeople' +import { useStyle } from '../../hooks/useStyle' +import { useChat } from '../../hooks/useChat' + +type SidebarItem = { + id: string + label: string + icon: React.ReactNode +} + +type Props = { + activeTab: string | null + onSelectTab: (id: string | null) => void +} + +const RightSidebar: React.FC = ({ activeTab, onSelectTab }) => { + const { assets } = useAssets() + const { people } = usePeople() + const { style, update } = useStyle() + const { messages, send } = useChat() + + const items: SidebarItem[] = [ + { id: 'comments', label: 'Comentarios', icon: }, + { id: 'style', label: 'Estilo', icon: }, + { id: 'banners', label: 'Banners', icon: }, + { id: 'media', label: 'Archivos multimedia', icon: }, + { id: 'people', label: 'Personas', icon: }, + { id: 'private-chat', label: 'Chat privado', icon: }, + { id: 'notes', label: 'Notas', icon: }, + ] + + return ( +
+
+ {/* Panel: positioned to the left of tabs and slides with transform */} +
+
+ {activeTab ? ( +
+ {activeTab === 'media' && ( +
+

Archivos multimedia

+
    + {assets.map((a) => ( +
  • {a.name}
  • + ))} +
+
+ )} + + {activeTab === 'people' && ( +
+

Personas

+
    + {people.map((p) => ( +
  • {p.name} {p.role}
  • + ))} +
+
+ )} + + {activeTab === 'style' && ( +
+

Estilo

+
Color primario: {style.themeColor}
+
+ +
+
+ )} + + {activeTab === 'private-chat' && ( +
+

Chat privado

+
+ {messages.map((m) => ( +
+
{m.user}
+
{m.text}
+
+ ))} +
+
+ { + if (e.key === 'Enter') { + const val = (e.currentTarget as HTMLInputElement).value.trim() + if (val) { + send('Host', val) + ;(e.currentTarget as HTMLInputElement).value = '' + } + } + }} /> +
+
+ )} + + {activeTab === 'comments' && ( +
+

Comentarios

+

Panel de comentarios en tiempo real.

+
+ )} + + {activeTab === 'banners' && ( +
+

Banners

+

Gestión de banners y overlays.

+
+ )} + + {activeTab === 'notes' && ( +
+

Notas

+

Notas y recordatorios del stream.

+
+ )} +
+ ) : ( +
Seleccione una pestaña para ver opciones
+ )} +
+
+ + {/* Tabs aside: always visible on the right */} + +
+
+ ) +} + +export default RightSidebar diff --git a/packages/studio-panel/src/hooks/useAssets.ts b/packages/studio-panel/src/hooks/useAssets.ts new file mode 100644 index 0000000..6b2bf3c --- /dev/null +++ b/packages/studio-panel/src/hooks/useAssets.ts @@ -0,0 +1,20 @@ +import { useState, useEffect } from 'react' + +export type Asset = { id: string; name: string; type: 'image' | 'video' } + +export function useAssets() { + const [assets, setAssets] = useState([]) + + useEffect(() => { + // load sample assets (could be replaced by API) + setAssets([ + { id: 'a1', name: 'Intro.mp4', type: 'video' }, + { id: 'a2', name: 'Logo.png', type: 'image' }, + ]) + }, []) + + const addAsset = (a: Asset) => setAssets((s) => [a, ...s]) + const removeAsset = (id: string) => setAssets((s) => s.filter((x) => x.id !== id)) + + return { assets, addAsset, removeAsset } +} diff --git a/packages/studio-panel/src/hooks/useChat.ts b/packages/studio-panel/src/hooks/useChat.ts new file mode 100644 index 0000000..46b4a3c --- /dev/null +++ b/packages/studio-panel/src/hooks/useChat.ts @@ -0,0 +1,15 @@ +import { useState, useEffect } from 'react' + +export type ChatMessage = { id: string; user: string; text: string } + +export function useChat() { + const [messages, setMessages] = useState([]) + + useEffect(() => { + setMessages([{ id: 'm1', user: 'Alice', text: 'Hola a todos' }]) + }, []) + + const send = (user: string, text: string) => setMessages((s) => [...s, { id: `${Date.now()}`, user, text }]) + + return { messages, send } +} diff --git a/packages/studio-panel/src/hooks/usePeople.ts b/packages/studio-panel/src/hooks/usePeople.ts new file mode 100644 index 0000000..f69af92 --- /dev/null +++ b/packages/studio-panel/src/hooks/usePeople.ts @@ -0,0 +1,19 @@ +import { useState, useEffect } from 'react' + +export type Person = { id: string; name: string; role?: string } + +export function usePeople() { + const [people, setPeople] = useState([]) + + useEffect(() => { + setPeople([ + { id: 'p1', name: 'Alice' }, + { id: 'p2', name: 'Bob' }, + ]) + }, []) + + const addPerson = (p: Person) => setPeople((s) => [p, ...s]) + const removePerson = (id: string) => setPeople((s) => s.filter((x) => x.id !== id)) + + return { people, addPerson, removePerson } +} diff --git a/packages/studio-panel/src/hooks/useStyle.ts b/packages/studio-panel/src/hooks/useStyle.ts new file mode 100644 index 0000000..aef8f9f --- /dev/null +++ b/packages/studio-panel/src/hooks/useStyle.ts @@ -0,0 +1,11 @@ +import { useState } from 'react' + +export type StyleConfig = { themeColor: string; showLogo: boolean } + +export function useStyle() { + const [style, setStyle] = useState({ themeColor: '#2563eb', showLogo: true }) + + const update = (patch: Partial) => setStyle((s) => ({ ...s, ...patch })) + + return { style, update } +} diff --git a/packages/studio-panel/src/layouts/StudioLayout.tsx b/packages/studio-panel/src/layouts/StudioLayout.tsx index 6167614..198c132 100644 --- a/packages/studio-panel/src/layouts/StudioLayout.tsx +++ b/packages/studio-panel/src/layouts/StudioLayout.tsx @@ -1,15 +1,23 @@ import React, { useState } from 'react' import Header from '../components/ui/Header' import LeftSidePanel from '../components/ui/LeftSidePanel' +import RightSidebar from '../components/ui/RightSidebar' const StudioLayout: React.FC<{ children?: React.ReactNode }> = ({ children }) => { const [leftOpen, setLeftOpen] = useState(true) + const [rightActiveTab, setRightActiveTab] = useState(null) return (
setLeftOpen((v) => !v)} /> -
{children}
+
+ {children} +
+ +
) }