1555 lines
48 KiB
Markdown
1555 lines
48 KiB
Markdown
I. Estructura y Componentes Lógicos:
|
|
|
|
La página web se puede descomponer en los siguientes 5 componentes lógicos modulares de React, envueltos por un `PageContainer` principal que gestiona el ancho máximo y el centrado:
|
|
|
|
1. **Header:**
|
|
* **Descripción:** Contiene el logo de la marca, la navegación principal con enlaces y dropdowns, y un botón de "Get started".
|
|
* **Jerarquía DOM Clave:** `<header>` que contiene un `<div>` para el logo y un `<nav>` para los enlaces de navegación (`<ul>`, `<li>` con `<a>`). Incluye un `<a>` con estilo de botón para "Get started".
|
|
* **Medidas Clave:**
|
|
* Altura: Aproximadamente `80px` (fijo).
|
|
* Layout: `display: flex` para alinear el logo y la navegación.
|
|
* Ancho máximo: Contenido limitado por el `max-width` global del `PageContainer`.
|
|
|
|
2. **HeroSection:**
|
|
* **Descripción:** La sección inicial de la página con un título principal impactante, una descripción y un formulario de registro/inicio de sesión.
|
|
* **Jerarquía DOM Clave:** `<section>` que contiene dos `<div>` principales: uno para el contenido de texto (`<h1>`, `<p>`) y otro para el formulario de suscripción (`<div>` con botones, input de email y texto de enlaces). Posiblemente un elemento gráfico de fondo.
|
|
* **Medidas Clave:**
|
|
* Layout: `display: flex` para una disposición en dos columnas (texto a la izquierda, formulario a la derecha) en escritorio.
|
|
* Ancho máximo: Contenido limitado por el `max-width` global del `PageContainer`.
|
|
* Formulario: Ancho fijo en escritorio, adaptativo en móvil. `border-radius: 16px`.
|
|
|
|
3. **FeaturesGrid (Sección de Características Destacadas):**
|
|
* **Descripción:** Presenta las características clave del producto mediante tarjetas interactivas con iconos y títulos.
|
|
* **Jerarquía DOM Clave:** `<section>` que contiene un `<div>` o `<ul>` para los elementos individuales. Cada elemento (`<div>` o `<li>`) contiene un `<img>` (icono/imagen) y un `<h3>` (título).
|
|
* **Medidas Clave:**
|
|
* Layout: `display: flex` con `gap` para la separación entre tarjetas. En móviles, implica `overflow-x: scroll` o una implementación de carrusel con flechas de navegación.
|
|
* Tarjetas: `border-radius: 16px`, `box-shadow` sutil. Dimensiones uniformes para cada tarjeta (ej. `200px` x `200px`).
|
|
|
|
4. **ContentDetailsSection (Sección de Contenido Detallado):**
|
|
* **Descripción:** Agrupa múltiples bloques de contenido que detallan aspectos específicos del producto, a menudo con un layout de texto e imagen/video lado a lado.
|
|
* **Jerarquía DOM Clave:** Múltiples `<section>` anidadas o `<div>`s, cada una con un `div` para el texto (H2, P) y un `div` para el contenido multimedia (imagen/video). El orden texto/imagen varía.
|
|
* **Medidas Clave:**
|
|
* Layout: `display: flex` para los bloques de texto y multimedia. `gap` entre ellos.
|
|
* Ancho máximo: Contenido limitado por el `max-width` global del `PageContainer`.
|
|
* Espaciado vertical: `padding-block: 80px` o `100px` para separar cada sub-sección.
|
|
|
|
5. **CallToActionSection:**
|
|
* **Descripción:** Una sección destacada al final de la página que incita al usuario a comenzar a usar el producto.
|
|
* **Jerarquía DOM Clave:** `<section>` con un `<h2>` para el mensaje principal, un `<button>` para la acción y un `<p>` con texto complementario, todo centrado.
|
|
* **Medidas Clave:**
|
|
* Layout: `display: flex`, `flex-direction: column`, `align-items: center`, `justify-content: center`.
|
|
* Ancho: `100%` del contenedor principal.
|
|
* Color de fondo: Azul primario (`#0066FF`) con un patrón gráfico sutil.
|
|
* Botón: `border-radius: 8px`, `padding: 16px 32px`.
|
|
|
|
---
|
|
|
|
II. Métricas Pixel-Perfect:
|
|
|
|
**A. Tipografía:**
|
|
* **Familia de Fuentes:** `sans-serif` (posiblemente una fuente personalizada como Inter, o 'system-ui', 'Helvetica Neue', 'Arial'). Para la implementación, se utilizará una fuente genérica sans-serif con `Inter` como principal si se importara.
|
|
* **H1 (`The easiest way to live stream and record`):**
|
|
* Tamaño: `64px`
|
|
* Peso: `800` (Extra Bold)
|
|
* Altura de línea: `1.2`
|
|
* Color: `#1A1A1A`
|
|
* **H2 (Títulos de Sección, ej. `Go live or record podcasts`):**
|
|
* Tamaño: `44px`
|
|
* Peso: `700` (Bold)
|
|
* Altura de línea: `1.3`
|
|
* Color: `#1A1A1A`
|
|
* **P (Párrafos de Contenido):**
|
|
* Tamaño: `18px`
|
|
* Peso: `400` (Regular)
|
|
* Altura de línea: `1.6`
|
|
* Color: `#333333`
|
|
* **Texto Pequeño (Footer, captions):**
|
|
* Tamaño: `14px`
|
|
* Peso: `400`
|
|
* Altura de línea: `1.5`
|
|
* Color: `#666666`
|
|
|
|
**B. Paleta de Colores:**
|
|
* **Fondo Principal (General):** `#FFFFFF` (Blanco puro) o `#F9FAFC` (Blanco muy ligero).
|
|
* **Texto Principal:** `#1A1A1A` (Negro muy oscuro).
|
|
* **Texto Secundario/Párrafos:** `#333333` o `#666666`.
|
|
* **Color de Acento (Azul Primario):** `#0066FF` (Botones, enlaces primarios).
|
|
* **Color de Acento (Rosa):** `#FFDCE6` (Fondos de sección específicos).
|
|
* **Color de Acento (Morado):** `#6432C8` (Fondos de sección específicos).
|
|
* **Color de Acento (Amarillo):** `#FFE664` (Fondos de sección específicos).
|
|
* **Bordes/Líneas sutiles:** `#E0E0E0`.
|
|
* **Sombras (Box-shadow):** `0 4px 12px rgba(0, 0, 0, 0.08)` para tarjetas y formularios.
|
|
* **Gradientes (ej. Hero Section):** `linear-gradient(to bottom, #EBF5FF, #FFFFFF)`.
|
|
|
|
**C. Espaciado y Bordeado:**
|
|
* **Separación Vertical entre Secciones:** `padding-top: 100px`, `padding-bottom: 100px`.
|
|
* **Separación Interna (Padding):**
|
|
* Botones: `padding: 16px 32px`.
|
|
* Tarjetas: `padding: 24px`.
|
|
* Contenedores de contenido: `padding-inline: 20px` (para márgenes laterales en pantallas más pequeñas).
|
|
* **Radio de Borde (`border-radius`):**
|
|
* Botones: `8px`.
|
|
* Tarjetas (Características, Blog, Testimonios): `16px`.
|
|
* Inputs de formulario: `6px`.
|
|
* Contenedor del formulario Hero: `16px`.
|
|
|
|
---
|
|
|
|
III. Funcionalidad y Scripts Internos:
|
|
|
|
**A. Funcionalidad del Aplicativo Web (Interactividad a Replicar):**
|
|
|
|
1. **Menú de Navegación Colapsable (Móvil):**
|
|
* En dispositivos móviles, el menú de navegación principal (`Header`) se contraerá en un icono de hamburguesa.
|
|
* Al hacer clic en el icono de hamburguesa, el menú se deslizará para mostrar los enlaces de navegación.
|
|
* Al hacer clic nuevamente o fuera del menú, este se ocultará.
|
|
2. **Dropdowns de Navegación (Header):**
|
|
* Los elementos "Product" y "For Business" en el `Header` deben mostrar un menú desplegable con sub-enlaces al pasar el ratón por encima (en escritorio).
|
|
* En dispositivos móviles, estos dropdowns deben expandirse/colapsar al hacer clic.
|
|
3. **Carrusel de Características (`FeaturesGrid`):**
|
|
* La sección con las tarjetas de características (Recording, Multistream, Guests, etc.) debe ser un carrusel o un contenedor con `overflow-x: scroll` en pantallas donde las tarjetas no quepan en una sola fila.
|
|
* Debe tener flechas de navegación izquierda/derecha para desplazarse entre las características (o auto-scroll si es `overflow`).
|
|
4. **Carrusel de Testimonios:**
|
|
* La sección "60,000,000+ streams..." presentará testimonios en un carrusel.
|
|
* Los usuarios podrán navegar entre los testimonios utilizando flechas de navegación a izquierda y derecha, y/o indicadores de paginación (puntos) en la parte inferior.
|
|
5. **Reproducción de Audio Interactivo:**
|
|
* En la sección "Studio quality recordings...", hay un elemento visual con un botón de "Play" y un texto "Click to hear the difference".
|
|
* Al hacer clic en este botón, debe simular la reproducción de audio (cambiando el icono a "Pause" y mostrando una barra de progreso visual). Un segundo clic pausaría.
|
|
|
|
**B. Scripts Internos (Lógica JavaScript Clave):**
|
|
|
|
1. **Manejo de Estado del Menú Móvil:**
|
|
* Se utilizará el hook `useState` de React en el componente `Header` para gestionar un booleano `isMobileMenuOpen`.
|
|
* Un evento `onClick` en el icono de hamburguesa alternará este estado.
|
|
* Las clases CSS se aplicarán condicionalmente basándose en `isMobileMenuOpen` para controlar la visibilidad y animación del menú.
|
|
2. **Lógica de Dropdowns:**
|
|
* Para los dropdowns de "Product" y "For Business", se usarán hooks `useState` individuales o un estado combinado para controlar su visibilidad (`isProductDropdownOpen`, `isBusinessDropdownOpen`).
|
|
* Eventos `onMouseEnter`/`onMouseLeave` (desktop) o `onClick` (mobile) manejarán el cambio de estado.
|
|
3. **Gestión de Carruseles:**
|
|
* Se implementará un estado `currentIndex` o `scrollPosition` en los componentes `FeaturesGrid` y en la sección de Testimonios.
|
|
* Las funciones `handlePrev` y `handleNext` actualizarán este estado, y las transiciones CSS (transform: translateX) se usarán para animar el movimiento de los elementos.
|
|
* Los puntos de paginación también actualizarán directamente `currentIndex`.
|
|
4. **Control de Audio Simulado:**
|
|
* Un hook `useState` para `isPlaying` y `progress` en el componente relevante (dentro de `ContentDetailsSection`).
|
|
* Una función `handlePlayPause` alternará el estado `isPlaying` y simulará la actualización de `progress` usando `setTimeout` o `setInterval` para una animación básica.
|
|
|
|
---
|
|
|
|
**Generación de Código**
|
|
|
|
A continuación, se presenta el código de los componentes React/TypeScript y sus archivos CSS Modules, siguiendo el informe técnico.
|
|
|
|
**`src/components/PageContainer.tsx`**
|
|
|
|
```tsx
|
|
import React, { ReactNode } from 'react';
|
|
import styles from './PageContainer.module.css';
|
|
|
|
interface PageContainerProps {
|
|
children: ReactNode;
|
|
}
|
|
|
|
const PageContainer: React.FC<PageContainerProps> = ({ children }) => {
|
|
return (
|
|
<div className={styles.pageContainer}>
|
|
{children}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default PageContainer;
|
|
```
|
|
|
|
**`src/components/PageContainer.module.css`**
|
|
|
|
```css
|
|
/* src/components/PageContainer.module.css */
|
|
|
|
.pageContainer {
|
|
max-width: 1280px; /* Ancho máximo del contenido */
|
|
margin: 0 auto; /* Centrar el contenedor en la página */
|
|
padding: 0 20px; /* Padding horizontal para evitar que el contenido toque los bordes en pantallas pequeñas */
|
|
overflow-x: hidden; /* Evita el scroll horizontal no deseado */
|
|
}
|
|
|
|
/* Base styles for the page */
|
|
:root {
|
|
--primary-blue: #0066FF;
|
|
--light-blue-gradient-start: #EBF5FF;
|
|
--text-dark: #1A1A1A;
|
|
--text-medium: #333333;
|
|
--text-light: #666666;
|
|
--bg-white: #FFFFFF;
|
|
--bg-light-grey: #F9FAFC;
|
|
--accent-pink: #FFDCE6;
|
|
--accent-purple: #6432C8;
|
|
--accent-yellow: #FFE664;
|
|
--border-light: #E0E0E0;
|
|
--shadow-sm: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
|
|
--font-size-h1: 64px;
|
|
--font-weight-h1: 800;
|
|
--line-height-h1: 1.2;
|
|
|
|
--font-size-h2: 44px;
|
|
--font-weight-h2: 700;
|
|
--line-height-h2: 1.3;
|
|
|
|
--font-size-p: 18px;
|
|
--font-weight-p: 400;
|
|
--line-height-p: 1.6;
|
|
|
|
--font-size-sm: 14px;
|
|
--font-weight-sm: 400;
|
|
--line-height-sm: 1.5;
|
|
|
|
--border-radius-button: 8px;
|
|
--border-radius-card: 16px;
|
|
--border-radius-input: 6px;
|
|
}
|
|
|
|
body {
|
|
font-family: 'Inter', 'Helvetica Neue', Arial, sans-serif; /* Usar Inter si está disponible, sino fallbacks */
|
|
margin: 0;
|
|
padding: 0;
|
|
background-color: var(--bg-white);
|
|
color: var(--text-medium);
|
|
-webkit-font-smoothing: antialiased;
|
|
-moz-osx-font-smoothing: grayscale;
|
|
}
|
|
|
|
h1 {
|
|
font-size: var(--font-size-h1);
|
|
font-weight: var(--font-weight-h1);
|
|
line-height: var(--line-height-h1);
|
|
color: var(--text-dark);
|
|
margin-top: 0;
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
h2 {
|
|
font-size: var(--font-size-h2);
|
|
font-weight: var(--font-weight-h2);
|
|
line-height: var(--line-height-h2);
|
|
color: var(--text-dark);
|
|
margin-top: 0;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
p {
|
|
font-size: var(--font-size-p);
|
|
font-weight: var(--font-weight-p);
|
|
line-height: var(--line-height-p);
|
|
color: var(--text-medium);
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
/* Responsive adjustments */
|
|
@media (max-width: 768px) {
|
|
.pageContainer {
|
|
padding: 0 16px;
|
|
}
|
|
|
|
h1 {
|
|
font-size: 40px; /* Ajuste para móviles */
|
|
line-height: 1.1;
|
|
}
|
|
|
|
h2 {
|
|
font-size: 32px; /* Ajuste para móviles */
|
|
line-height: 1.2;
|
|
}
|
|
|
|
p {
|
|
font-size: 16px; /* Ajuste para móviles */
|
|
line-height: 1.5;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 480px) {
|
|
h1 {
|
|
font-size: 32px;
|
|
}
|
|
|
|
h2 {
|
|
font-size: 28px;
|
|
}
|
|
}
|
|
```
|
|
|
|
**`src/components/Header/Header.tsx`**
|
|
|
|
```tsx
|
|
import React, { useState } from 'react';
|
|
import styles from './Header.module.css';
|
|
|
|
// Mock icons for demonstration
|
|
const MenuIcon = () => <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>;
|
|
const CloseIcon = () => <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>;
|
|
const ChevronDown = () => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg>;
|
|
|
|
const Header: React.FC = () => {
|
|
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
|
const [isProductDropdownOpen, setIsProductDropdownOpen] = useState(false);
|
|
const [isBusinessDropdownOpen, setIsBusinessDropdownOpen] = useState(false);
|
|
|
|
// Función para alternar el menú móvil
|
|
const toggleMobileMenu = () => {
|
|
setIsMobileMenuOpen(!isMobileMenuOpen);
|
|
};
|
|
|
|
// Funciones para manejar los dropdowns en desktop (hover)
|
|
const handleProductMouseEnter = () => setIsProductDropdownOpen(true);
|
|
const handleProductMouseLeave = () => setIsProductDropdownOpen(false);
|
|
const handleBusinessMouseEnter = () => setIsBusinessDropdownOpen(true);
|
|
const handleBusinessMouseLeave = () => setIsBusinessDropdownOpen(false);
|
|
|
|
// Funciones para manejar los dropdowns en mobile (click)
|
|
const toggleProductDropdown = () => setIsProductDropdownOpen(!isProductDropdownOpen);
|
|
const toggleBusinessDropdown = () => setIsBusinessDropdownOpen(!isBusinessDropdownOpen);
|
|
|
|
return (
|
|
<header className={styles.header}>
|
|
<div className={styles.logo}>
|
|
<img src="https://via.placeholder.com/150x40?text=StreamYard+Logo" alt="StreamYard Logo" />
|
|
</div>
|
|
|
|
{/* Botón de menú de hamburguesa para móvil */}
|
|
<button className={styles.menuToggle} onClick={toggleMobileMenu} aria-label="Toggle menu">
|
|
{isMobileMenuOpen ? <CloseIcon /> : <MenuIcon />}
|
|
</button>
|
|
|
|
{/* Menú de navegación */}
|
|
<nav className={`${styles.nav} ${isMobileMenuOpen ? styles.navOpen : ''}`}>
|
|
<ul className={styles.navList}>
|
|
{/* Dropdown 'Product' */}
|
|
<li
|
|
className={styles.navItemDropdown}
|
|
onMouseEnter={handleProductMouseEnter}
|
|
onMouseLeave={handleProductMouseLeave}
|
|
>
|
|
<a href="#" className={styles.navLink} onClick={toggleProductDropdown}>
|
|
Product <ChevronDown />
|
|
</a>
|
|
{isProductDropdownOpen && (
|
|
<ul className={styles.dropdownMenu}>
|
|
<li><a href="#">Features</a></li>
|
|
<li><a href="#">Pricing</a></li>
|
|
<li><a href="#">Integrations</a></li>
|
|
</ul>
|
|
)}
|
|
</li>
|
|
|
|
<li><a href="#" className={styles.navLink}>Contact</a></li>
|
|
<li><a href="#" className={styles.navLink}>Pricing</a></li>
|
|
<li><a href="#" className={styles.navLink}>What's New</a></li>
|
|
|
|
{/* Dropdown 'For Business' */}
|
|
<li
|
|
className={styles.navItemDropdown}
|
|
onMouseEnter={handleBusinessMouseEnter}
|
|
onMouseLeave={handleBusinessMouseLeave}
|
|
>
|
|
<a href="#" className={styles.navLink} onClick={toggleBusinessDropdown}>
|
|
For Business <ChevronDown />
|
|
</a>
|
|
{isBusinessDropdownOpen && (
|
|
<ul className={styles.dropdownMenu}>
|
|
<li><a href="#">Enterprise</a></li>
|
|
<li><a href="#">Agencies</a></li>
|
|
</ul>
|
|
)}
|
|
</li>
|
|
|
|
<li><a href="#" className={styles.navLink}>Log In</a></li>
|
|
<li>
|
|
<button className={styles.getStartedButton}>Get started</button>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</header>
|
|
);
|
|
};
|
|
|
|
export default Header;
|
|
```
|
|
|
|
**`src/components/Header/Header.module.css`**
|
|
|
|
```css
|
|
/* src/components/Header/Header.module.css */
|
|
|
|
.header {
|
|
display: flex;
|
|
justify-content: space-between; /* Espacia el logo y la navegación */
|
|
align-items: center;
|
|
padding: 16px 20px; /* Padding interno */
|
|
height: 80px; /* Altura fija */
|
|
background-color: var(--bg-white);
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); /* Sombra sutil */
|
|
position: sticky; /* Sticky header */
|
|
top: 0;
|
|
z-index: 1000; /* Asegura que el header esté por encima de otros elementos */
|
|
}
|
|
|
|
.logo img {
|
|
height: 40px; /* Altura del logo */
|
|
width: auto;
|
|
}
|
|
|
|
.nav {
|
|
display: flex; /* Por defecto, flex para escritorio */
|
|
}
|
|
|
|
.navList {
|
|
list-style: none;
|
|
margin: 0;
|
|
padding: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 30px; /* Espacio entre elementos de navegación */
|
|
}
|
|
|
|
.navLink {
|
|
text-decoration: none;
|
|
color: var(--text-medium);
|
|
font-weight: 500;
|
|
font-size: 16px;
|
|
padding: 8px 0;
|
|
transition: color 0.3s ease;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 4px; /* Espacio para el icono de chevron */
|
|
}
|
|
|
|
.navLink:hover {
|
|
color: var(--primary-blue); /* Color al pasar el ratón */
|
|
}
|
|
|
|
.getStartedButton {
|
|
background-color: var(--primary-blue);
|
|
color: var(--bg-white);
|
|
border: none;
|
|
border-radius: var(--border-radius-button);
|
|
padding: 12px 24px;
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: background-color 0.3s ease;
|
|
}
|
|
|
|
.getStartedButton:hover {
|
|
background-color: #0056e6; /* Azul más oscuro al pasar el ratón */
|
|
}
|
|
|
|
/* Estilos para el menú dropdown */
|
|
.navItemDropdown {
|
|
position: relative;
|
|
}
|
|
|
|
.dropdownMenu {
|
|
position: absolute;
|
|
top: 100%; /* Debajo del elemento padre */
|
|
left: 0;
|
|
background-color: var(--bg-white);
|
|
box-shadow: var(--shadow-sm);
|
|
border-radius: var(--border-radius-input);
|
|
list-style: none;
|
|
padding: 10px 0;
|
|
margin-top: 5px; /* Pequeño espacio entre el link y el dropdown */
|
|
min-width: 160px;
|
|
display: none; /* Oculto por defecto, se muestra con JS */
|
|
flex-direction: column;
|
|
z-index: 1010;
|
|
}
|
|
|
|
.navItemDropdown:hover .dropdownMenu {
|
|
display: flex; /* Mostrar en hover para desktop */
|
|
}
|
|
|
|
.dropdownMenu li a {
|
|
display: block;
|
|
padding: 8px 15px;
|
|
color: var(--text-medium);
|
|
text-decoration: none;
|
|
font-size: 15px;
|
|
}
|
|
|
|
.dropdownMenu li a:hover {
|
|
background-color: var(--bg-light-grey);
|
|
color: var(--primary-blue);
|
|
}
|
|
|
|
/* Menú de hamburguesa (visible solo en móvil) */
|
|
.menuToggle {
|
|
display: none; /* Oculto por defecto */
|
|
background: none;
|
|
border: none;
|
|
cursor: pointer;
|
|
padding: 0;
|
|
}
|
|
|
|
/* Responsive: Mobile styles */
|
|
@media (max-width: 1024px) {
|
|
.navList {
|
|
gap: 20px; /* Reduce el espacio entre elementos */
|
|
}
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.header {
|
|
padding: 16px;
|
|
height: 60px; /* Reduce la altura del header en móvil */
|
|
}
|
|
|
|
.nav {
|
|
display: none; /* Oculta la navegación por defecto en móvil */
|
|
flex-direction: column;
|
|
position: absolute;
|
|
top: 60px; /* Debajo del header */
|
|
left: 0;
|
|
width: 100%;
|
|
background-color: var(--bg-white);
|
|
box-shadow: var(--shadow-sm);
|
|
padding: 20px 0;
|
|
z-index: 999;
|
|
/* Animación de deslizamiento */
|
|
transform: translateY(-100%);
|
|
transition: transform 0.3s ease-out;
|
|
}
|
|
|
|
.nav.navOpen {
|
|
display: flex; /* Muestra el menú cuando está abierto */
|
|
transform: translateY(0);
|
|
}
|
|
|
|
.navList {
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
gap: 10px;
|
|
}
|
|
|
|
.navList li {
|
|
width: 100%;
|
|
padding: 8px 20px; /* Padding para los ítems del menú móvil */
|
|
}
|
|
|
|
.navLink {
|
|
width: 100%;
|
|
}
|
|
|
|
.navItemDropdown {
|
|
width: 100%;
|
|
}
|
|
|
|
.navItemDropdown:hover .dropdownMenu {
|
|
display: none; /* Deshabilita el hover en mobile, se activa con click */
|
|
}
|
|
|
|
.navItemDropdown .dropdownMenu {
|
|
position: static; /* Cambia a posición estática para que fluya en el menú móvil */
|
|
box-shadow: none;
|
|
border-radius: 0;
|
|
padding-left: 20px; /* Indentación para sub-items */
|
|
margin-top: 0;
|
|
display: none; /* Oculto por defecto en móvil */
|
|
}
|
|
|
|
/* Mostrar dropdowns en móvil al hacer click */
|
|
.navItemDropdown:has(> a.navLink[aria-expanded="true"]) .dropdownMenu {
|
|
display: flex;
|
|
}
|
|
|
|
.menuToggle {
|
|
display: block; /* Muestra el botón de hamburguesa */
|
|
}
|
|
|
|
.getStartedButton {
|
|
width: calc(100% - 40px); /* Ajuste de ancho para botón en móvil */
|
|
margin: 10px 20px;
|
|
text-align: center;
|
|
}
|
|
}
|
|
```
|
|
|
|
**`src/components/HeroSection/HeroSection.tsx`**
|
|
|
|
```tsx
|
|
import React from 'react';
|
|
import styles from './HeroSection.module.css';
|
|
|
|
const HeroSection: React.FC = () => {
|
|
return (
|
|
<section className={styles.heroSection}>
|
|
<div className={styles.heroContent}>
|
|
<h1>The easiest way to live stream and record</h1>
|
|
<p>
|
|
StreamYard is a professional live streaming and recording studio in your
|
|
browser. Record your content, or stream live to Facebook, YouTube, and
|
|
other platforms.
|
|
</p>
|
|
</div>
|
|
<div className={styles.heroFormContainer}>
|
|
<div className={styles.heroForm}>
|
|
<button className={styles.googleButton}>
|
|
<img src="https://upload.wikimedia.org/wikipedia/commons/4/4a/Logo_2013_Google.png" alt="Google Logo" className={styles.googleLogo} />
|
|
Continue with Google
|
|
</button>
|
|
<div className={styles.separator}>Or continue with email</div>
|
|
<input
|
|
type="email"
|
|
placeholder="Enter email address"
|
|
className={styles.emailInput}
|
|
/>
|
|
<button className={styles.getStartedButton}>
|
|
Get started - It's free!
|
|
</button>
|
|
<p className={styles.formFooterText}>
|
|
Trusted by 12,000,000+ creators!
|
|
<br />
|
|
By continuing, you accept our <a href="#">User Terms of Service</a> and{' '}
|
|
<a href="#">Plan Usage Policy</a> and acknowledge receipt of our{' '}
|
|
<a href="#">Privacy Policy</a>
|
|
</p>
|
|
<p className={styles.loginText}>Already using StreamYard? <a href="#">Log in.</a></p>
|
|
</div>
|
|
<img
|
|
src="https://via.placeholder.com/400x300?text=Hero+Graphic" // Placeholder image for the graphic
|
|
alt="StreamYard Interface Graphic"
|
|
className={styles.heroGraphic}
|
|
/>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export default HeroSection;
|
|
```
|
|
|
|
**`src/components/HeroSection/HeroSection.module.css`**
|
|
|
|
```css
|
|
/* src/components/HeroSection/HeroSection.module.css */
|
|
|
|
.heroSection {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
padding: 100px 0; /* Espaciado vertical */
|
|
background: linear-gradient(to bottom, var(--light-blue-gradient-start), var(--bg-white)); /* Gradiente de fondo */
|
|
gap: 80px; /* Espacio entre el contenido de texto y el formulario */
|
|
flex-wrap: wrap; /* Permite que los elementos se envuelvan en pantallas más pequeñas */
|
|
}
|
|
|
|
.heroContent {
|
|
flex: 1; /* Ocupa el espacio disponible */
|
|
min-width: 300px; /* Ancho mínimo para el texto */
|
|
max-width: 600px; /* Ancho máximo para el texto */
|
|
}
|
|
|
|
.heroContent h1 {
|
|
font-size: var(--font-size-h1);
|
|
font-weight: var(--font-weight-h1);
|
|
line-height: var(--line-height-h1);
|
|
color: var(--text-dark);
|
|
}
|
|
|
|
.heroContent p {
|
|
font-size: var(--font-size-p);
|
|
line-height: var(--line-height-p);
|
|
color: var(--text-medium);
|
|
max-width: 500px; /* Limita el ancho del párrafo */
|
|
}
|
|
|
|
.heroFormContainer {
|
|
position: relative;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: flex-end; /* Alinea el formulario y el gráfico a la derecha */
|
|
min-width: 350px;
|
|
}
|
|
|
|
.heroForm {
|
|
background-color: var(--bg-white);
|
|
border-radius: var(--border-radius-card); /* Radio de borde para el formulario */
|
|
box-shadow: var(--shadow-sm); /* Sombra para el formulario */
|
|
padding: 30px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 15px; /* Espacio entre elementos del formulario */
|
|
width: 380px; /* Ancho fijo para el formulario */
|
|
z-index: 1; /* Asegura que el formulario esté sobre el gráfico */
|
|
}
|
|
|
|
.googleButton {
|
|
background-color: var(--bg-white);
|
|
border: 1px solid var(--border-light);
|
|
border-radius: var(--border-radius-button);
|
|
padding: 12px 20px;
|
|
font-size: 16px;
|
|
font-weight: 500;
|
|
color: var(--text-medium);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 10px;
|
|
cursor: pointer;
|
|
transition: background-color 0.3s ease;
|
|
}
|
|
|
|
.googleButton:hover {
|
|
background-color: var(--bg-light-grey);
|
|
}
|
|
|
|
.googleLogo {
|
|
height: 20px;
|
|
width: 20px;
|
|
}
|
|
|
|
.separator {
|
|
text-align: center;
|
|
font-size: var(--font-size-sm);
|
|
color: var(--text-light);
|
|
position: relative;
|
|
margin: 10px 0;
|
|
}
|
|
|
|
.separator::before,
|
|
.separator::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 50%;
|
|
width: 40%;
|
|
height: 1px;
|
|
background-color: var(--border-light);
|
|
}
|
|
|
|
.separator::before {
|
|
left: 0;
|
|
}
|
|
|
|
.separator::after {
|
|
right: 0;
|
|
}
|
|
|
|
.emailInput {
|
|
border: 1px solid var(--border-light);
|
|
border-radius: var(--border-radius-input);
|
|
padding: 14px 15px;
|
|
font-size: 16px;
|
|
width: calc(100% - 30px); /* Ajusta el ancho por el padding */
|
|
}
|
|
|
|
.emailInput:focus {
|
|
outline: none;
|
|
border-color: var(--primary-blue);
|
|
box-shadow: 0 0 0 2px rgba(0, 102, 255, 0.2);
|
|
}
|
|
|
|
.getStartedButton {
|
|
background-color: var(--primary-blue);
|
|
color: var(--bg-white);
|
|
border: none;
|
|
border-radius: var(--border-radius-button);
|
|
padding: 16px 20px;
|
|
font-size: 18px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: background-color 0.3s ease;
|
|
}
|
|
|
|
.getStartedButton:hover {
|
|
background-color: #0056e6;
|
|
}
|
|
|
|
.formFooterText {
|
|
font-size: 13px;
|
|
color: var(--text-light);
|
|
text-align: center;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.formFooterText a,
|
|
.loginText a {
|
|
color: var(--primary-blue);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.loginText {
|
|
font-size: var(--font-size-sm);
|
|
color: var(--text-medium);
|
|
text-align: center;
|
|
margin-top: 15px;
|
|
}
|
|
|
|
.heroGraphic {
|
|
position: absolute;
|
|
top: -80px; /* Posiciona el gráfico flotando por encima del formulario */
|
|
right: -100px; /* Ajusta la posición del gráfico */
|
|
width: 450px; /* Tamaño del gráfico */
|
|
height: auto;
|
|
opacity: 0.8; /* Transparencia para que parezca de fondo */
|
|
z-index: 0; /* Detrás del formulario */
|
|
filter: blur(1px); /* Ligero desenfoque */
|
|
}
|
|
|
|
|
|
/* Responsive adjustments */
|
|
@media (max-width: 1024px) {
|
|
.heroSection {
|
|
flex-direction: column; /* Apila el contenido y el formulario */
|
|
padding: 80px 0;
|
|
gap: 50px;
|
|
}
|
|
|
|
.heroContent {
|
|
text-align: center;
|
|
max-width: 90%;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.heroContent h1 {
|
|
font-size: 52px;
|
|
}
|
|
|
|
.heroContent p {
|
|
font-size: 17px;
|
|
}
|
|
|
|
.heroFormContainer {
|
|
align-items: center; /* Centra el formulario */
|
|
min-width: unset;
|
|
width: 100%;
|
|
}
|
|
|
|
.heroForm {
|
|
width: 85%; /* El formulario ocupa más ancho en móviles */
|
|
max-width: 450px; /* Limita el ancho del formulario */
|
|
}
|
|
|
|
.heroGraphic {
|
|
position: static; /* Quita el posicionamiento absoluto en móvil */
|
|
margin-top: 30px;
|
|
width: 80%;
|
|
max-width: 400px;
|
|
opacity: 1;
|
|
filter: none;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.heroSection {
|
|
padding: 60px 0;
|
|
}
|
|
|
|
.heroContent h1 {
|
|
font-size: 40px;
|
|
}
|
|
|
|
.heroForm {
|
|
width: 95%; /* Aún más ancho en pantallas más pequeñas */
|
|
padding: 20px;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 480px) {
|
|
.heroContent h1 {
|
|
font-size: 32px;
|
|
}
|
|
.heroContent p {
|
|
font-size: 16px;
|
|
}
|
|
}
|
|
```
|
|
|
|
**`src/components/FeaturesGrid/FeaturesGrid.tsx`**
|
|
|
|
```tsx
|
|
import React, { useState, useRef } from 'react';
|
|
import styles from './FeaturesGrid.module.css';
|
|
|
|
// Mock data for features
|
|
const features = [
|
|
{ id: 1, name: 'Recording', icon: 'https://via.placeholder.com/64?text=Rec' },
|
|
{ id: 2, name: 'Multistream', icon: 'https://via.placeholder.com/64?text=Multi' },
|
|
{ id: 3, name: 'Guests', icon: 'https://via.placeholder.com/64?text=Guests' },
|
|
{ id: 4, name: 'Branding', icon: 'https://via.placeholder.com/64?text=Brand' },
|
|
{ id: 5, name: 'Podcasts', icon: 'https://via.placeholder.com/64?text=Pod' },
|
|
{ id: 6, name: 'Webinars', icon: 'https://via.placeholder.com/64?text=Web' },
|
|
{ id: 7, name: 'Analytics', icon: 'https://via.placeholder.com/64?text=Anal' },
|
|
];
|
|
|
|
const FeaturesGrid: React.FC = () => {
|
|
const scrollRef = useRef<HTMLDivElement>(null);
|
|
|
|
const scroll = (direction: 'left' | 'right') => {
|
|
if (scrollRef.current) {
|
|
const scrollAmount = 300; // Cantidad de desplazamiento
|
|
if (direction === 'left') {
|
|
scrollRef.current.scrollBy({ left: -scrollAmount, behavior: 'smooth' });
|
|
} else {
|
|
scrollRef.current.scrollBy({ left: scrollAmount, behavior: 'smooth' });
|
|
}
|
|
}
|
|
};
|
|
|
|
return (
|
|
<section className={styles.featuresSection}>
|
|
<div className={styles.featuresHeader}>
|
|
<h2>Explore powerful features</h2>
|
|
<p>Discover how StreamYard can elevate your live streams and recordings.</p>
|
|
</div>
|
|
<div className={styles.carouselContainer}>
|
|
{/* Flecha de navegación izquierda */}
|
|
<button className={`${styles.navArrow} ${styles.leftArrow}`} onClick={() => scroll('left')} aria-label="Scroll left">
|
|
‹ {/* Carácter de flecha izquierda */}
|
|
</button>
|
|
<div className={styles.featuresGrid} ref={scrollRef}>
|
|
{features.map((feature) => (
|
|
<div key={feature.id} className={styles.featureCard}>
|
|
<img src={feature.icon} alt={feature.name} className={styles.featureIcon} />
|
|
<h3>{feature.name}</h3>
|
|
</div>
|
|
))}
|
|
</div>
|
|
{/* Flecha de navegación derecha */}
|
|
<button className={`${styles.navArrow} ${styles.rightArrow}`} onClick={() => scroll('right')} aria-label="Scroll right">
|
|
› {/* Carácter de flecha derecha */}
|
|
</button>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export default FeaturesGrid;
|
|
```
|
|
|
|
**`src/components/FeaturesGrid/FeaturesGrid.module.css`**
|
|
|
|
```css
|
|
/* src/components/FeaturesGrid/FeaturesGrid.module.css */
|
|
|
|
.featuresSection {
|
|
padding: 100px 0; /* Espaciado vertical */
|
|
background-color: var(--bg-light-grey); /* Fondo sutil */
|
|
text-align: center; /* Centra el texto */
|
|
}
|
|
|
|
.featuresHeader {
|
|
margin-bottom: 50px;
|
|
}
|
|
|
|
.featuresHeader h2 {
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.featuresHeader p {
|
|
font-size: var(--font-size-p);
|
|
color: var(--text-medium);
|
|
}
|
|
|
|
.carouselContainer {
|
|
position: relative;
|
|
max-width: 1200px; /* Ancho máximo para el carrusel */
|
|
margin: 0 auto;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.featuresGrid {
|
|
display: flex;
|
|
overflow-x: auto; /* Permite el desplazamiento horizontal */
|
|
-webkit-overflow-scrolling: touch; /* Suaviza el scroll en iOS */
|
|
scroll-snap-type: x mandatory; /* Ajuste para el scroll-snap */
|
|
gap: 30px; /* Espacio entre las tarjetas */
|
|
padding: 20px; /* Padding para evitar que las tarjetas toquen los bordes */
|
|
margin: 0 -20px; /* Compensa el padding para que el contenido fluya */
|
|
scrollbar-width: none; /* Oculta la barra de desplazamiento en Firefox */
|
|
}
|
|
|
|
/* Oculta la barra de desplazamiento en Chrome/Safari */
|
|
.featuresGrid::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
|
|
.featureCard {
|
|
flex: 0 0 auto; /* No permite que las tarjetas se encojan */
|
|
width: 220px; /* Ancho fijo de la tarjeta */
|
|
height: 220px; /* Altura fija para que sean cuadradas */
|
|
background-color: var(--bg-white);
|
|
border-radius: var(--border-radius-card);
|
|
box-shadow: var(--shadow-sm);
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
padding: 20px;
|
|
text-align: center;
|
|
scroll-snap-align: start; /* Alineación para el scroll-snap */
|
|
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.featureCard:hover {
|
|
transform: translateY(-5px); /* Pequeño efecto de elevación */
|
|
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.featureIcon {
|
|
width: 64px; /* Tamaño del icono */
|
|
height: 64px;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.featureCard h3 {
|
|
font-size: 20px;
|
|
font-weight: 600;
|
|
color: var(--text-dark);
|
|
margin: 0;
|
|
}
|
|
|
|
.navArrow {
|
|
position: absolute;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
background-color: var(--bg-white);
|
|
border: 1px solid var(--border-light);
|
|
border-radius: 50%; /* Botones circulares */
|
|
width: 50px;
|
|
height: 50px;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
font-size: 24px;
|
|
cursor: pointer;
|
|
z-index: 10;
|
|
box-shadow: var(--shadow-sm);
|
|
transition: background-color 0.3s ease, transform 0.3s ease;
|
|
}
|
|
|
|
.navArrow:hover {
|
|
background-color: var(--bg-light-grey);
|
|
transform: translateY(-50%) scale(1.05);
|
|
}
|
|
|
|
.leftArrow {
|
|
left: -25px; /* Posicionar fuera del grid */
|
|
}
|
|
|
|
.rightArrow {
|
|
right: -25px; /* Posicionar fuera del grid */
|
|
}
|
|
|
|
/* Responsive adjustments */
|
|
@media (max-width: 1280px) {
|
|
.leftArrow {
|
|
left: 0px; /* Mueve las flechas dentro del padding del contenedor principal */
|
|
}
|
|
|
|
.rightArrow {
|
|
right: 0px;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.featuresSection {
|
|
padding: 60px 0;
|
|
}
|
|
|
|
.featuresGrid {
|
|
gap: 20px; /* Reduce el espacio entre tarjetas */
|
|
padding: 15px;
|
|
margin: 0 -15px;
|
|
}
|
|
|
|
.featureCard {
|
|
width: 180px; /* Reduce el tamaño de las tarjetas */
|
|
height: 180px;
|
|
padding: 15px;
|
|
}
|
|
|
|
.featureIcon {
|
|
width: 50px;
|
|
height: 50px;
|
|
}
|
|
|
|
.featureCard h3 {
|
|
font-size: 18px;
|
|
}
|
|
|
|
.navArrow {
|
|
width: 40px;
|
|
height: 40px;
|
|
font-size: 20px;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 480px) {
|
|
.featuresHeader h2 {
|
|
font-size: 32px;
|
|
}
|
|
|
|
.featuresHeader p {
|
|
font-size: 16px;
|
|
}
|
|
|
|
.featuresGrid {
|
|
padding: 10px;
|
|
margin: 0 -10px;
|
|
}
|
|
|
|
.featureCard {
|
|
width: 150px; /* Aún más pequeñas */
|
|
height: 150px;
|
|
}
|
|
|
|
.navArrow {
|
|
display: none; /* Oculta las flechas si el scroll es el método principal */
|
|
}
|
|
}
|
|
```
|
|
|
|
**`src/components/ContentDetailsSection/ContentDetailsSection.tsx`**
|
|
|
|
```tsx
|
|
import React, { useState } from 'react';
|
|
import styles from './ContentDetailsSection.module.css';
|
|
|
|
// Mock component for Play/Pause icon
|
|
const PlayIcon = () => (
|
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
<polygon points="5 3 19 12 5 21 5 3"></polygon>
|
|
</svg>
|
|
);
|
|
const PauseIcon = () => (
|
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
<rect x="6" y="4" width="4" height="16"></rect>
|
|
<rect x="14" y="4" width="4" height="16"></rect>
|
|
</svg>
|
|
);
|
|
|
|
const ContentDetailsSection: React.FC = () => {
|
|
const [isPlayingAudio, setIsPlayingAudio] = useState(false);
|
|
const [audioProgress, setAudioProgress] = useState(0);
|
|
|
|
// Simula la reproducción de audio
|
|
const handlePlayPauseAudio = () => {
|
|
setIsPlayingAudio(!isPlayingAudio);
|
|
if (!isPlayingAudio) {
|
|
// Simular progreso
|
|
let currentProgress = 0;
|
|
const interval = setInterval(() => {
|
|
currentProgress += 10; // Incrementa el progreso
|
|
if (currentProgress > 100) {
|
|
currentProgress = 0;
|
|
setIsPlayingAudio(false);
|
|
clearInterval(interval);
|
|
}
|
|
setAudioProgress(currentProgress);
|
|
}, 500); // Actualiza cada 0.5 segundos
|
|
} else {
|
|
setAudioProgress(0); // Reinicia si se pausa
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className={styles.contentDetailsSection}>
|
|
{/* Sección 1: Go live or record podcasts with remote guests */}
|
|
<section className={`${styles.contentBlock} ${styles.bgPink}`}>
|
|
<div className={styles.textColumn}>
|
|
<h2>Go live or record podcasts with remote guests</h2>
|
|
<p>
|
|
It's easy for guests to join from their browser or phone in a few
|
|
clicks. No software downloads.
|
|
</p>
|
|
<a href="#" className={styles.learnMoreLink}>Learn more →</a>
|
|
</div>
|
|
<div className={styles.imageColumn}>
|
|
<img src="https://via.placeholder.com/500x350?text=Remote+Guests" alt="Remote Guests" className={styles.contentImage} />
|
|
</div>
|
|
</section>
|
|
|
|
{/* Sección 2: Studio quality recordings on any connection */}
|
|
<section className={`${styles.contentBlock} ${styles.bgPurple} ${styles.reverseLayout}`}>
|
|
<div className={styles.imageColumn}>
|
|
<div className={styles.audioPlayer}>
|
|
<img src="https://via.placeholder.com/500x350?text=Studio+Quality" alt="Studio Quality" className={styles.contentImage} />
|
|
<div className={styles.audioControls}>
|
|
<button onClick={handlePlayPauseAudio} className={styles.playPauseButton}>
|
|
{isPlayingAudio ? <PauseIcon /> : <PlayIcon />}
|
|
</button>
|
|
<div className={styles.progressBarContainer}>
|
|
<div
|
|
className={styles.progressBar}
|
|
style={{ width: `${audioProgress}%` }}
|
|
></div>
|
|
</div>
|
|
<span className={styles.audioLabel}>Click to hear the difference</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className={styles.textColumn}>
|
|
<h2>Studio quality recordings on any connection</h2>
|
|
<p>
|
|
Sick of Zoom and Skype ruining your podcast? With local recordings,
|
|
a separate audio and video file is recorded on each user's device.
|
|
Even if someone has weak internet, the recordings won't be blurry or choppy.
|
|
</p>
|
|
<a href="#" className={styles.learnMoreLink}>Discover more →</a>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Sección 3: Multistream to all platforms at once */}
|
|
<section className={`${styles.contentBlock} ${styles.bgWhite}`}>
|
|
<div className={styles.textColumn}>
|
|
<h2>Multistream to all platforms at once</h2>
|
|
<p>
|
|
Stream to Facebook, YouTube, Instagram, LinkedIn, X (Twitter),
|
|
Twitch, and more. Make your audience feel special by featuring
|
|
their comments on screen.
|
|
</p>
|
|
<a href="#" className={styles.learnMoreLink}>See all integrations →</a>
|
|
</div>
|
|
<div className={styles.imageColumn}>
|
|
<img src="https://via.placeholder.com/500x350?text=Multistream" alt="Multistream" className={styles.contentImage} />
|
|
</div>
|
|
</section>
|
|
|
|
{/* Sección 4: Move your webinars to StreamYard On-Air */}
|
|
<section className={`${styles.contentBlock} ${styles.bgBlueish} ${styles.reverseLayout}`}>
|
|
<div className={styles.imageColumn}>
|
|
<img src="https://via.placeholder.com/500x350?text=Webinars" alt="Webinars" className={styles.contentImage} />
|
|
</div>
|
|
<div className={styles.textColumn}>
|
|
<h2>Move your webinars to StreamYard On-Air</h2>
|
|
<p>
|
|
StreamYard On-Air is a live webinar platform. We're redefining
|
|
webinar stability, simplicity, and production quality. You can
|
|
even embed it on your website for a fully white-label experience.
|
|
</p>
|
|
<a href="#" className={styles.learnMoreLink}>See why everyone is switching →</a>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ContentDetailsSection;
|
|
```
|
|
|
|
**`src/components/ContentDetailsSection/ContentDetailsSection.module.css`**
|
|
|
|
```css
|
|
/* src/components/ContentDetailsSection/ContentDetailsSection.module.css */
|
|
|
|
.contentDetailsSection {
|
|
padding: 0; /* Las secciones internas manejan su propio padding */
|
|
}
|
|
|
|
.contentBlock {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 80px; /* Espacio entre columnas */
|
|
padding: 100px 0; /* Espaciado vertical entre bloques */
|
|
margin-bottom: 0; /* Cada bloque es una sección, no necesita margen inferior extra */
|
|
flex-wrap: wrap; /* Permite envolver columnas en pantallas pequeñas */
|
|
}
|
|
|
|
/* Fondos de sección */
|
|
.bgPink {
|
|
background-color: var(--accent-pink);
|
|
}
|
|
|
|
.bgPurple {
|
|
background-color: var(--accent-purple);
|
|
color: var(--bg-white); /* Texto blanco para fondo oscuro */
|
|
}
|
|
.bgPurple h2, .bgPurple p, .bgPurple .learnMoreLink {
|
|
color: var(--bg-white);
|
|
}
|
|
|
|
.bgYellow {
|
|
background-color: var(--accent-yellow);
|
|
}
|
|
|
|
.bgBlueish {
|
|
background-color: #EBF7FF; /* Un azul muy claro */
|
|
}
|
|
|
|
|
|
.textColumn {
|
|
flex: 1; /* Ocupa el espacio disponible */
|
|
min-width: 300px;
|
|
max-width: 600px; /* Limita el ancho del texto */
|
|
}
|
|
|
|
.imageColumn {
|
|
flex: 1; /* Ocupa el espacio disponible */
|
|
min-width: 300px;
|
|
display: flex;
|
|
justify-content: center; /* Centra la imagen dentro de su columna */
|
|
align-items: center;
|
|
}
|
|
|
|
.contentImage {
|
|
max-width: 100%; /* Asegura que la imagen no se desborde */
|
|
height: auto;
|
|
border-radius: var(--border-radius-card);
|
|
box-shadow: var(--shadow-sm);
|
|
}
|
|
|
|
.reverseLayout {
|
|
flex-direction: row-reverse; /* Invierte el orden de las columnas */
|
|
}
|
|
|
|
.learnMoreLink {
|
|
color: var(--primary-blue);
|
|
text-decoration: none;
|
|
font-weight: 600;
|
|
transition: color 0.3s ease;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
margin-top: 15px;
|
|
}
|
|
.bgPurple .learnMoreLink {
|
|
color: var(--bg-white);
|
|
}
|
|
|
|
.learnMoreLink:hover {
|
|
color: #0047b3; /* Azul más oscuro al pasar el ratón */
|
|
}
|
|
|
|
/* Estilos para el reproductor de audio simulado */
|
|
.audioPlayer {
|
|
position: relative;
|
|
width: 100%;
|
|
max-width: 500px; /* Ancho máximo para el reproductor */
|
|
border-radius: var(--border-radius-card);
|
|
box-shadow: var(--shadow-sm);
|
|
overflow: hidden; /* Asegura que la imagen y los controles respeten el borde */
|
|
}
|
|
|
|
.audioPlayer .contentImage {
|
|
border-radius: 0; /* La imagen no necesita borde-radius si el contenedor ya lo tiene */
|
|
display: block; /* Elimina espacios extra debajo de la imagen */
|
|
}
|
|
|
|
.audioControls {
|
|
position: absolute;
|
|
bottom: 20px;
|
|
left: 20px;
|
|
right: 20px;
|
|
background-color: rgba(255, 255, 255, 0.9); /* Fondo semitransparente para los controles */
|
|
border-radius: var(--border-radius-button);
|
|
padding: 10px 15px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 15px;
|
|
box-shadow: var(--shadow-sm);
|
|
}
|
|
|
|
.playPauseButton {
|
|
background: none;
|
|
border: none;
|
|
color: var(--primary-blue);
|
|
cursor: pointer;
|
|
padding: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.playPauseButton svg {
|
|
width: 30px;
|
|
height: 30px;
|
|
}
|
|
|
|
.progressBarContainer {
|
|
flex-grow: 1;
|
|
height: 8px;
|
|
background-color: var(--border-light);
|
|
border-radius: 4px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.progressBar {
|
|
height: 100%;
|
|
background-color: var(--primary-blue);
|
|
width: 0%; /* Controlado por el estado de React */
|
|
transition: width 0.1s linear; /* Animación suave para el progreso */
|
|
}
|
|
|
|
.audioLabel {
|
|
font-size: var(--font-size-sm);
|
|
color: var(--text-medium);
|
|
white-space: nowrap; /* Evita que el texto se rompa */
|
|
}
|
|
|
|
/* Responsive adjustments */
|
|
@media (max-width: 1024px) {
|
|
.contentBlock {
|
|
flex-direction: column; /* Apila las columnas */
|
|
text-align: center;
|
|
padding: 80px 0;
|
|
gap: 40px;
|
|
}
|
|
|
|
.reverseLayout {
|
|
flex-direction: column; /* También apila en layout invertido */
|
|
}
|
|
|
|
.textColumn, .imageColumn {
|
|
max-width: 90%; /* Ajusta el ancho para móvil */
|
|
margin: 0 auto; /* Centra las columnas */
|
|
}
|
|
|
|
.audioControls {
|
|
bottom: 15px;
|
|
left: 15px;
|
|
right: 15px;
|
|
padding: 8px 10px;
|
|
gap: 10px;
|
|
}
|
|
|
|
.playPauseButton svg {
|
|
width: 25px;
|
|
height: 25px;
|
|
}
|
|
|
|
.audioLabel {
|
|
font-size: 12px;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.contentBlock {
|
|
padding: 60px 0;
|
|
gap: 30px;
|
|
}
|
|
|
|
.textColumn h2 {
|
|
font-size: 32px;
|
|
}
|
|
|
|
.textColumn p {
|
|
font-size: 16px;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 480px) {
|
|
.textColumn h2 {
|
|
font-size: 28px;
|
|
}
|
|
}
|
|
```
|
|
|
|
**`src/components/CallToActionSection/CallToActionSection.tsx`**
|
|
|
|
```tsx
|
|
import React from 'react';
|
|
import styles from './CallToActionSection.module.css';
|
|
|
|
const CallToActionSection: React.FC = () => {
|
|
return (
|
|
<section className={styles.ctaSection}>
|
|
<div className={styles.ctaContent}>
|
|
<h2>Get creating.</h2>
|
|
<button className={styles.ctaButton}>Get started - It's free!</button>
|
|
<p>Join millions of StreamYard users and start streaming or podcasting today.</p>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export default CallToActionSection;
|
|
```
|
|
|
|
**`src/components/CallToActionSection/CallToActionSection.module.css`**
|
|
|
|
```css
|
|
/* src/components/CallToActionSection/CallToActionSection.module.css */
|
|
|
|
.ctaSection {
|
|
background-color: var(--primary-blue); /* Fondo azul */
|
|
/* Imagen de fondo sutil con patrón geométrico */
|
|
background-image: url('data:image/svg+xml;utf8,<svg width="100%" height="100%" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h100v100H0z" fill="none"/><path d="M0 50h50L25 75zM50 0h50L75 25z" fill="rgba(255,255,255,0.05)"/></svg>');
|
|
background-size: 200px 200px; /* Tamaño del patrón */
|
|
color: var(--bg-white); /* Texto blanco */
|
|
text-align: center;
|
|
padding: 120px 20px; /* Espaciado interno */
|
|
margin-top: 100px; /* Espacio superior para separar de la sección anterior */
|
|
}
|
|
|
|
.ctaContent {
|
|
max-width: 700px; /* Ancho máximo para el contenido del CTA */
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.ctaContent h2 {
|
|
font-size: var(--font-size-h2);
|
|
color: var(--bg-white);
|
|
margin-bottom: 25px;
|
|
}
|
|
|
|
.ctaButton {
|
|
background-color: var(--bg-white); /* Botón blanco sobre fondo azul */
|
|
color: var(--primary-blue);
|
|
border: none;
|
|
border-radius: var(--border-radius-button);
|
|
padding: 18px 36px;
|
|
font-size: 20px;
|
|
font-weight: 700;
|
|
cursor: pointer;
|
|
transition: background-color 0.3s ease, transform 0.3s ease;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.ctaButton:hover {
|
|
background-color: #f0f0f0; /* Ligero cambio de color al pasar el ratón */
|
|
transform: translateY(-2px); /* Pequeño efecto de elevación */
|
|
}
|
|
|
|
.ctaContent p {
|
|
font-size: var(--font-size-p);
|
|
color: rgba(255, 255, 255, 0.8); /* Texto más claro */
|
|
margin: 0;
|
|
}
|
|
|
|
/* Responsive adjustments */
|
|
@media (max-width: 768px) {
|
|
.ctaSection {
|
|
padding: 80px 16px;
|
|
margin-top: 80px;
|
|
}
|
|
|
|
.ctaContent h2 {
|
|
font-size: 36px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.ctaButton {
|
|
padding: 16px 30px;
|
|
font-size: 18px;
|
|
}
|
|
|
|
.ctaContent p {
|
|
font-size: 16px;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 480px) {
|
|
.ctaSection {
|
|
padding: 60px 16px;
|
|
margin-top: 60px;
|
|
}
|
|
|
|
.ctaContent h2 {
|
|
font-size: 30px;
|
|
}
|
|
|
|
.ctaButton {
|
|
padding: 14px 24px;
|
|
font-size: 16px;
|
|
}
|
|
}
|
|
``` |