AvanzaCast/packages/ui-components/STUDIO_IMPLEMENTATION.md

8.0 KiB

Implementación de Avanza UI en Studio Panel

🚀 Pasos de Instalación

1. Instalar Avanza UI en studio-panel

cd packages/studio-panel
npm install ../ui-components

2. Actualizar package.json de studio-panel

{
  "dependencies": {
    "avanza-ui": "file:../ui-components",
    "react": "^18.3.1",
    "react-dom": "^18.3.1"
  }
}

3. Importar estilos globales en main.tsx

// packages/studio-panel/src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

// Importar estilos de Avanza UI
import 'avanza-ui/dist/index.css';

// Tus estilos personalizados
import './styles.css';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

4. Ejemplo de Uso en Componentes

Header.tsx con Avanza UI

// packages/studio-panel/src/components/Header.tsx
import React from 'react';
import {
  Avatar,
  Button,
  Dropdown,
  DropdownItem,
  DropdownDivider,
  Tooltip,
} from 'avanza-ui';

export const Header: React.FC = () => {
  return (
    <header style={{
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'space-between',
      padding: '1rem 2rem',
      backgroundColor: 'var(--au-surface)',
      borderBottom: '1px solid var(--au-border-light)',
    }}>
      <div>Logo</div>

      <div style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
        <Tooltip content="Invitar participantes">
          <Button variant="secondary" size="sm">
            Invitar
          </Button>
        </Tooltip>

        <Dropdown
          trigger={
            <Avatar
              src="/avatar.jpg"
              alt="Usuario"
              size="sm"
              status="online"
            />
          }
          align="right"
        >
          <DropdownItem icon={<span>👤</span>}>Mi Perfil</DropdownItem>
          <DropdownItem icon={<span>⚙️</span>}>Configuración</DropdownItem>
          <DropdownDivider />
          <DropdownItem danger icon={<span>🚪</span>}>
            Cerrar Sesión
          </DropdownItem>
        </Dropdown>
      </div>
    </header>
  );
};

Sidebar.tsx con Avanza UI

// packages/studio-panel/src/components/Sidebar.tsx
import React from 'react';
import { Card, CardHeader, CardBody, Badge, Tooltip } from 'avanza-ui';

export const Sidebar: React.FC = () => {
  return (
    <aside style={{
      width: '300px',
      backgroundColor: 'var(--au-surface)',
      borderRight: '1px solid var(--au-border-light)',
      padding: '1rem',
    }}>
      <Card>
        <CardHeader>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <h3>Participantes</h3>
            <Badge variant="primary">3</Badge>
          </div>
        </CardHeader>
        <CardBody>
          {/* Lista de participantes */}
        </CardBody>
      </Card>

      <Card style={{ marginTop: '1rem' }}>
        <CardHeader>
          <h3>Chat</h3>
        </CardHeader>
        <CardBody>
          {/* Mensajes de chat */}
        </CardBody>
      </Card>
    </aside>
  );
};

StudioLayout.tsx con Avanza UI

// packages/studio-panel/src/components/StudioLayout.tsx
import React, { useState } from 'react';
import {
  Button,
  Modal,
  ModalHeader,
  ModalBody,
  ModalFooter,
  Input,
  Alert,
  Spinner,
} from 'avanza-ui';
import { Header } from './Header';
import { Sidebar } from './Sidebar';

export const StudioLayout: React.FC = () => {
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [isLoading, setIsLoading] = useState(false);

  return (
    <div style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}>
      <Header />

      <div style={{ flex: 1, display: 'flex', overflow: 'hidden' }}>
        <Sidebar />

        <main style={{ flex: 1, padding: '2rem', overflowY: 'auto' }}>
          <Alert
            variant="info"
            title="Bienvenido al Studio"
            message="Configura tu transmisión en vivo"
            closable
          />

          <div style={{ marginTop: '2rem' }}>
            <Button
              variant="primary"
              onClick={() => setIsModalOpen(true)}
              leftIcon={<span></span>}
            >
              Iniciar Transmisión
            </Button>
          </div>

          {isLoading && (
            <div style={{ marginTop: '2rem', textAlign: 'center' }}>
              <Spinner size="lg" variant="primary" />
              <p>Conectando...</p>
            </div>
          )}
        </main>
      </div>

      {/* Modal de Configuración */}
      <Modal
        isOpen={isModalOpen}
        onClose={() => setIsModalOpen(false)}
        size="md"
      >
        <ModalHeader
          title="Configurar Transmisión"
          onClose={() => setIsModalOpen(false)}
        />
        <ModalBody>
          <Input
            label="Título de la transmisión"
            placeholder="Ingresa un título"
            fullWidth
          />
          <Input
            label="Descripción"
            placeholder="Descripción opcional"
            fullWidth
            style={{ marginTop: '1rem' }}
          />
        </ModalBody>
        <ModalFooter>
          <Button variant="secondary" onClick={() => setIsModalOpen(false)}>
            Cancelar
          </Button>
          <Button variant="primary">Comenzar</Button>
        </ModalFooter>
      </Modal>
    </div>
  );
};

🎨 Personalización del Tema

Archivo de estilos personalizado (styles.css)

/* packages/studio-panel/src/styles.css */

/* Personalizar colores primarios */
:root {
  --au-primary-600: #6366f1; /* Tu color primario */
  --au-primary-700: #4f46e5;
}

/* Dark theme personalizado */
[data-theme="dark"] {
  --au-bg-primary: #0a0e1a;
  --au-surface: #13192b;
}

/* Estilos adicionales específicos del studio */
.studio-video-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: var(--au-spacing-4);
  padding: var(--au-spacing-4);
}

Toggle de Tema

// packages/studio-panel/src/components/ThemeToggle.tsx
import React, { useState, useEffect } from 'react';
import { Button } from 'avanza-ui';

export const ThemeToggle: React.FC = () => {
  const [theme, setTheme] = useState<'light' | 'dark'>('light');

  useEffect(() => {
    // Leer tema del localStorage
    const savedTheme = localStorage.getItem('theme') as 'light' | 'dark' | null;
    if (savedTheme) {
      setTheme(savedTheme);
      document.documentElement.setAttribute('data-theme', savedTheme);
    }
  }, []);

  const toggleTheme = () => {
    const newTheme = theme === 'light' ? 'dark' : 'light';
    setTheme(newTheme);
    document.documentElement.setAttribute('data-theme', newTheme);
    localStorage.setItem('theme', newTheme);
  };

  return (
    <Button variant="ghost" onClick={toggleTheme}>
      {theme === 'light' ? '🌙' : '☀️'}
    </Button>
  );
};

📋 Checklist de Migración

  • Instalar avanza-ui en package.json
  • Importar estilos globales en main.tsx
  • Reemplazar componentes existentes con Avanza UI
  • Configurar tema dark/light
  • Personalizar variables CSS si es necesario
  • Probar en diferentes navegadores
  • Verificar accesibilidad

🔄 Comparación con Vristo

Vristo Avanza UI Beneficio
Depende de Tailwind CSS Modules Sin conflictos de clases
require('react-popper') Estado interno Menos dependencias
Configuración compleja Plug & Play Más rápido de implementar
Múltiples estilos Variables CSS Personalización fácil

🚀 Comandos Útiles

# Desarrollo
cd packages/ui-components && npm run dev
cd packages/studio-panel && npm run dev

# Build de producción
cd packages/ui-components && npm run build
cd packages/studio-panel && npm run build

# Actualizar biblioteca
cd packages/ui-components && npm run build
cd packages/studio-panel && npm install ../ui-components

¡Listo para usar Avanza UI en tu Studio Panel!