Add new logo SVG file for Avanzacast application
This commit is contained in:
parent
a3a436e6d9
commit
6594ce2ade
@ -132,7 +132,7 @@ Planes y precios SaaS:
|
||||
- Soporte 24/7 + Account Manager
|
||||
- Multi-usuario (5 cuentas)
|
||||
- **Visual Destacado**: Plan Pro con badge "MÁS POPULAR", scale aumentado, gradiente
|
||||
- **CTA por Plan**: "Comenzar Gratis" / "Iniciar Prueba de 14 Días"
|
||||
- **CTA por Plan**: "Empecemos" / "Iniciar Prueba de 14 Días"
|
||||
- **Features con Iconos**: ✓ para incluido, ✗ para no incluido
|
||||
- **Trust Badges**:
|
||||
- Sin tarjeta de crédito
|
||||
@ -143,7 +143,7 @@ Planes y precios SaaS:
|
||||
- **CTA Section**:
|
||||
- Gradiente purple-to-blue de fondo
|
||||
- Headline impactante: "¿Listo para Revolucionar tus Transmisiones?"
|
||||
- Botón grande: "Comenzar Gratis - 14 Días de Prueba"
|
||||
- Botón grande: "Empecemos - 14 Días de Prueba"
|
||||
- **Footer Completo**:
|
||||
- Logo AvanzaCast con gradiente
|
||||
- 4 Columnas:
|
||||
|
||||
288
packages/landing-page/LIMPIEZA_ARCHIVOS.md
Normal file
288
packages/landing-page/LIMPIEZA_ARCHIVOS.md
Normal file
@ -0,0 +1,288 @@
|
||||
# 🧹 Análisis de Limpieza - Landing Page AvanzaCast
|
||||
|
||||
## ✅ LIMPIEZA COMPLETADA - 4 Nov 2025
|
||||
|
||||
### <20> ARCHIVOS ELIMINADOS
|
||||
|
||||
**TOTAL: 22 archivos .tsx eliminados (~60KB)**
|
||||
|
||||
#### Páginas obsoletas (3)
|
||||
- ✅ `src/pages/Dashboard.tsx`
|
||||
- ✅ `src/pages/Landing.tsx`
|
||||
- ✅ `src/pages/NewLanding.tsx`
|
||||
|
||||
#### Componentes Landing antigua (5)
|
||||
- ✅ `src/components/HeroSection.tsx`
|
||||
- ✅ `src/components/FeatureHighlights.tsx`
|
||||
- ✅ `src/components/FeaturesCarousel.tsx`
|
||||
- ✅ `src/components/ContentSection.tsx`
|
||||
- ✅ `src/components/CTAAndFooter.tsx`
|
||||
|
||||
#### Componentes NewLanding (7)
|
||||
- ✅ `src/components/NewHeroSection.tsx`
|
||||
- ✅ `src/components/NewFeaturesGrid.tsx`
|
||||
- ✅ `src/components/NewContentDetailsSection.tsx`
|
||||
- ✅ `src/components/NewTestimonialsCarousel.tsx`
|
||||
- ✅ `src/components/NewCallToAction.tsx`
|
||||
- ✅ `src/components/NewFooter.tsx`
|
||||
- ✅ `src/components/PageContainer.tsx`
|
||||
|
||||
#### Headers/Footers duplicados (2)
|
||||
- ✅ `src/components/NewHeader.tsx`
|
||||
- ✅ `src/components/NextreamHeader.tsx`
|
||||
|
||||
#### Componentes huérfanos (5)
|
||||
- ✅ `src/components/Navigation.tsx`
|
||||
- ✅ `src/components/Header.tsx`
|
||||
- ✅ `src/components/StudioPreview.tsx`
|
||||
- ✅ `src/components/StreamingStats.tsx`
|
||||
- ✅ `src/components/ScrollToTop.tsx`
|
||||
|
||||
#### App.tsx actualizado
|
||||
- ✅ Eliminados imports de Landing y NewLanding
|
||||
- ✅ Eliminadas rutas `/landing` y `/new-landing`
|
||||
- ✅ Ruta principal: `/` → NextreamLanding
|
||||
|
||||
---
|
||||
|
||||
## 📂 ESTRUCTURA ACTUAL
|
||||
|
||||
### Páginas (6)
|
||||
- ✅ `Broadcasts.tsx` - Panel de transmisiones
|
||||
- ✅ `Studio.tsx` - Estudio de streaming
|
||||
- ✅ `Login.tsx` - Inicio de sesión
|
||||
- ✅ `Register.tsx` - Registro
|
||||
- ✅ `NextreamLanding.tsx` - **Landing principal**
|
||||
- ✅ `index.tsx`
|
||||
|
||||
### Componentes Activos (14)
|
||||
- ✅ `ModernSaasHeader.tsx` - Header principal
|
||||
- ✅ `ModernSaasFooter.tsx` - Footer principal
|
||||
- ✅ `StreamingHeroSection.tsx` - Hero landing
|
||||
- ✅ `NextreamHeroSection.tsx` - Hero alternativo
|
||||
- ✅ `StreamingFeatures.tsx` - Características
|
||||
- ✅ `PlatformLogos.tsx` - Logos plataformas
|
||||
- ✅ `TestimonialsSection.tsx` - Testimonios
|
||||
- ✅ `PricingSection.tsx` - Precios
|
||||
- ✅ `BlogSection.tsx` - Blog
|
||||
- ✅ `BackToTop.tsx` - Botón scroll
|
||||
- ✅ `Reveal.tsx` - Animaciones
|
||||
- ✅ `MainLayout.tsx` - Layout autenticado
|
||||
- ✅ `Layouts/Header.tsx` - Header app
|
||||
- ✅ `Layouts/Sidebar.tsx` - Sidebar app
|
||||
|
||||
---
|
||||
|
||||
## 🎯 BENEFICIOS
|
||||
|
||||
✅ Código más limpio y mantenible
|
||||
✅ Estructura clara y sin duplicados
|
||||
✅ Menor confusión sobre qué componentes usar
|
||||
✅ ~60KB de código eliminado
|
||||
✅ Un solo landing principal: NextreamLanding
|
||||
|
||||
---
|
||||
|
||||
## 🔄 PRÓXIMOS PASOS
|
||||
|
||||
1. ✅ Verificar que la app funcione correctamente
|
||||
2. ✅ Hacer commit de los cambios
|
||||
3. ✅ Probar todas las rutas
|
||||
4. ⏳ Documentar componentes restantes (opcional)
|
||||
|
||||
---
|
||||
|
||||
**Limpieza realizada:** 4 de noviembre de 2025
|
||||
**Archivos eliminados:** 22 TSX
|
||||
**Estado:** ✅ Completado sin errores
|
||||
|
||||
---
|
||||
|
||||
## ❌ PÁGINAS OBSOLETAS (3 archivos)
|
||||
|
||||
### Páginas a eliminar:
|
||||
1. **`src/pages/Dashboard.tsx`** - No se usa en ninguna ruta del router
|
||||
2. **`src/pages/Landing.tsx`** - Versión antigua, reemplazada por NextreamLanding
|
||||
3. **`src/pages/NewLanding.tsx`** - Versión intermedia, no es la ruta principal
|
||||
|
||||
**✅ Página principal actual:** `NextreamLanding.tsx` (ruta "/" en App.tsx)
|
||||
|
||||
---
|
||||
|
||||
## ❌ HEADERS DUPLICADOS (3 archivos)
|
||||
|
||||
### Headers sin uso activo en landing:
|
||||
1. **`src/components/Header.tsx`** - Header genérico básico (solo en MainLayout para área autenticada)
|
||||
2. **`src/components/NewHeader.tsx`** - Solo usado en NewLanding (obsoleta)
|
||||
3. **`src/components/NextreamHeader.tsx`** - Parece duplicado de ModernSaasHeader
|
||||
|
||||
**✅ Header actual:** `ModernSaasHeader.tsx` (usado en NextreamLanding)
|
||||
|
||||
---
|
||||
|
||||
## ❌ FOOTERS DUPLICADOS (2 archivos)
|
||||
|
||||
### Footers obsoletos:
|
||||
1. **`src/components/NewFooter.tsx`** - Solo en NewLanding (obsoleta)
|
||||
2. **`src/components/CTAAndFooter.tsx`** - Solo en Landing (obsoleta)
|
||||
|
||||
**✅ Footer actual:** `ModernSaasFooter.tsx` (usado en NextreamLanding)
|
||||
|
||||
---
|
||||
|
||||
## ❌ COMPONENTES DE LANDING ANTIGUA (4 archivos)
|
||||
|
||||
### Componentes solo usados en Landing.tsx (obsoleta):
|
||||
1. **`src/components/HeroSection.tsx`**
|
||||
2. **`src/components/FeatureHighlights.tsx`**
|
||||
3. **`src/components/FeaturesCarousel.tsx`**
|
||||
4. **`src/components/ContentSection.tsx`**
|
||||
|
||||
---
|
||||
|
||||
## ❌ COMPONENTES DE NEW LANDING (5 archivos)
|
||||
|
||||
### Componentes solo usados en NewLanding.tsx (obsoleta):
|
||||
1. **`src/components/NewHeroSection.tsx`**
|
||||
2. **`src/components/NewFeaturesGrid.tsx`**
|
||||
3. **`src/components/NewContentDetailsSection.tsx`**
|
||||
4. **`src/components/NewTestimonialsCarousel.tsx`**
|
||||
5. **`src/components/NewCallToAction.tsx`**
|
||||
|
||||
---
|
||||
|
||||
## ❌ COMPONENTES HUÉRFANOS (4 archivos)
|
||||
|
||||
### Sin referencias activas:
|
||||
1. **`src/components/Navigation.tsx`** - No usado en landing principal
|
||||
2. **`src/components/PageContainer.tsx`** - Solo en NewLanding (obsoleta)
|
||||
3. **`src/components/StudioPreview.tsx`** - No referenciado
|
||||
4. **`src/components/StreamingStats.tsx`** - No referenciado
|
||||
5. **`src/components/ScrollToTop.tsx`** - No referenciado
|
||||
|
||||
---
|
||||
|
||||
## ✅ COMPONENTES ACTIVOS (Mantener)
|
||||
|
||||
### Landing Principal (NextreamLanding):
|
||||
- ✅ `ModernSaasHeader.tsx`
|
||||
- ✅ `StreamingHeroSection.tsx`
|
||||
- ✅ `StreamingFeatures.tsx`
|
||||
- ✅ `PlatformLogos.tsx`
|
||||
- ✅ `TestimonialsSection.tsx`
|
||||
- ✅ `PricingSection.tsx`
|
||||
- ✅ `BlogSection.tsx`
|
||||
- ✅ `ModernSaasFooter.tsx`
|
||||
- ✅ `BackToTop.tsx`
|
||||
- ✅ `Reveal.tsx` (utilidad de animación)
|
||||
|
||||
### Área Autenticada:
|
||||
- ✅ `MainLayout.tsx`
|
||||
- ✅ `Layouts/Sidebar.tsx`
|
||||
- ✅ `Layouts/Header.tsx`
|
||||
|
||||
### Páginas Funcionales:
|
||||
- ✅ `Login.tsx`
|
||||
- ✅ `Register.tsx`
|
||||
- ✅ `Broadcasts.tsx`
|
||||
- ✅ `Studio.tsx`
|
||||
- ✅ `NextreamLanding.tsx`
|
||||
|
||||
---
|
||||
|
||||
## 🗑️ PLAN DE LIMPIEZA
|
||||
|
||||
### Fase 1 - Páginas obsoletas (3 archivos)
|
||||
```bash
|
||||
rm src/pages/Dashboard.tsx
|
||||
rm src/pages/Landing.tsx
|
||||
rm src/pages/NewLanding.tsx
|
||||
```
|
||||
|
||||
### Fase 2 - Componentes Landing antigua (4 archivos)
|
||||
```bash
|
||||
rm src/components/HeroSection.tsx
|
||||
rm src/components/FeatureHighlights.tsx
|
||||
rm src/components/FeaturesCarousel.tsx
|
||||
rm src/components/ContentSection.tsx
|
||||
rm src/components/CTAAndFooter.tsx
|
||||
```
|
||||
|
||||
### Fase 3 - Componentes NewLanding (6 archivos)
|
||||
```bash
|
||||
rm src/components/NewHeroSection.tsx
|
||||
rm src/components/NewFeaturesGrid.tsx
|
||||
rm src/components/NewContentDetailsSection.tsx
|
||||
rm src/components/NewTestimonialsCarousel.tsx
|
||||
rm src/components/NewCallToAction.tsx
|
||||
rm src/components/NewFooter.tsx
|
||||
rm src/components/PageContainer.tsx
|
||||
```
|
||||
|
||||
### Fase 4 - Headers/Footers duplicados (2 archivos)
|
||||
```bash
|
||||
rm src/components/NewHeader.tsx
|
||||
rm src/components/NextreamHeader.tsx
|
||||
```
|
||||
|
||||
### Fase 5 - Componentes huérfanos (5 archivos)
|
||||
```bash
|
||||
rm src/components/Navigation.tsx
|
||||
rm src/components/Header.tsx
|
||||
rm src/components/StudioPreview.tsx
|
||||
rm src/components/StreamingStats.tsx
|
||||
rm src/components/ScrollToTop.tsx
|
||||
```
|
||||
|
||||
### Fase 6 - Actualizar App.tsx
|
||||
Eliminar imports obsoletos:
|
||||
```tsx
|
||||
// Eliminar estas líneas:
|
||||
import Landing from './pages/Landing'
|
||||
import NewLanding from './pages/NewLanding'
|
||||
|
||||
// Y sus rutas:
|
||||
<Route path="/landing" element={<Landing />} />
|
||||
<Route path="/new-landing" element={<NewLanding />} />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 IMPACTO DE LA LIMPIEZA
|
||||
|
||||
| Categoría | Archivos | Estimado |
|
||||
|-----------|----------|----------|
|
||||
| Páginas | 3 | ~5KB |
|
||||
| Headers/Footers | 5 | ~15KB |
|
||||
| Componentes Landing | 4 | ~12KB |
|
||||
| Componentes NewLanding | 6 | ~18KB |
|
||||
| Huérfanos | 5 | ~10KB |
|
||||
| **TOTAL** | **23** | **~60KB** |
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ RECOMENDACIONES
|
||||
|
||||
1. ✅ **Hacer commit** antes de eliminar archivos
|
||||
2. ✅ **Verificar imports** con grep antes de eliminar
|
||||
3. ✅ **Probar la app** después de cada fase
|
||||
4. ✅ **Mantener backup** temporal
|
||||
5. ✅ **Actualizar documentación** después de limpiar
|
||||
|
||||
---
|
||||
|
||||
## 🚀 SIGUIENTE PASO
|
||||
|
||||
Ejecutar el siguiente comando para eliminar todos los archivos de una vez:
|
||||
|
||||
```bash
|
||||
cd /home/xesar/Documentos/Nextream/AvanzaCast/packages/landing-page
|
||||
|
||||
# Eliminar todo de una vez (¡CUIDADO!)
|
||||
rm src/pages/{Dashboard,Landing,NewLanding}.tsx \
|
||||
src/components/{HeroSection,FeatureHighlights,FeaturesCarousel,ContentSection,CTAAndFooter}.tsx \
|
||||
src/components/{NewHeroSection,NewFeaturesGrid,NewContentDetailsSection,NewTestimonialsCarousel,NewCallToAction,NewFooter,PageContainer}.tsx \
|
||||
src/components/{NewHeader,NextreamHeader,Navigation,Header,StudioPreview,StreamingStats,ScrollToTop}.tsx
|
||||
```
|
||||
|
||||
O hacerlo fase por fase para mayor seguridad.
|
||||
File diff suppressed because one or more lines are too long
45
packages/landing-page/public/logo-avanzacast.svg
Normal file
45
packages/landing-page/public/logo-avanzacast.svg
Normal file
@ -0,0 +1,45 @@
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Fondo morado principal con forma redondeada -->
|
||||
<path d="M100 0C44.772 0 0 44.772 0 100V412C0 467.228 44.772 512 100 512H412C467.228 512 512 467.228 512 412V100C512 44.772 467.228 0 412 0H100Z" fill="url(#gradient1)"/>
|
||||
|
||||
<!-- Forma morada oscura superior derecha -->
|
||||
<path d="M200 130C200 119.507 208.507 111 219 111H430C440.493 111 449 102.493 449 92C449 81.507 440.493 73 430 73H330C330 62.507 338.507 54 349 54C349 43.507 340.493 35 330 35H219C208.507 35 200 43.507 200 54V130Z" fill="url(#gradient2)"/>
|
||||
|
||||
<!-- Botón de play amarillo/crema con sombra -->
|
||||
<g filter="url(#shadow)">
|
||||
<path d="M145 195C145 184.507 153.507 176 164 176H348C358.493 176 367 184.507 367 195V429C367 439.493 358.493 448 348 448H164C153.507 448 145 439.493 145 429V195Z" fill="white"/>
|
||||
<path d="M200 230L320 312L200 394V230Z" fill="url(#gradient3)"/>
|
||||
</g>
|
||||
|
||||
<defs>
|
||||
<!-- Degradado morado principal -->
|
||||
<linearGradient id="gradient1" x1="0" y1="0" x2="512" y2="512" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#6B3FF2"/>
|
||||
<stop offset="1" stop-color="#4B1FD2"/>
|
||||
</linearGradient>
|
||||
|
||||
<!-- Degradado morado oscuro superior -->
|
||||
<linearGradient id="gradient2" x1="200" y1="35" x2="449" y2="130" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#8B6FF9"/>
|
||||
<stop offset="1" stop-color="#6B3FF2"/>
|
||||
</linearGradient>
|
||||
|
||||
<!-- Degradado amarillo/crema del play -->
|
||||
<linearGradient id="gradient3" x1="200" y1="230" x2="320" y2="394" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FFE9A0"/>
|
||||
<stop offset="1" stop-color="#FFD770"/>
|
||||
</linearGradient>
|
||||
|
||||
<!-- Sombra del botón de play -->
|
||||
<filter id="shadow" x="135" y="170" width="242" height="292" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="4"/>
|
||||
<feGaussianBlur stdDeviation="5"/>
|
||||
<feComposite in2="hardAlpha" operator="out"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
1641
packages/landing-page/public/logo_avanzacast.svg
Normal file
1641
packages/landing-page/public/logo_avanzacast.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 231 KiB |
@ -3,8 +3,6 @@ import { BrowserRouter, Routes as RRDRoutes, Route, useLocation } from 'react-ro
|
||||
const AnyRoutes: any = RRDRoutes
|
||||
import Broadcasts from './pages/Broadcasts'
|
||||
import Studio from './pages/Studio'
|
||||
import Landing from './pages/Landing'
|
||||
import NewLanding from './pages/NewLanding'
|
||||
import NextreamLanding from './pages/NextreamLanding'
|
||||
import Login from './pages/Login'
|
||||
import Register from './pages/Register'
|
||||
@ -31,9 +29,6 @@ export default function App() {
|
||||
<AnyRoutes>
|
||||
{/* Public landing and auth routes */}
|
||||
<Route path="/" element={<NextreamLanding />} />
|
||||
<Route path="/landing" element={<Landing />} />
|
||||
<Route path="/new-landing" element={<NewLanding />} />
|
||||
<Route path="/nextream" element={<NextreamLanding />} />
|
||||
<Route path="/auth/login" element={<Login />} />
|
||||
<Route path="/auth/register" element={<Register />} />
|
||||
|
||||
|
||||
@ -1,157 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
const platforms = ['YouTube', 'Twitch', 'Facebook', 'LinkedIn', 'TikTok']
|
||||
|
||||
const companies = [
|
||||
{ name: 'Microsoft', logo: '🏢' },
|
||||
{ name: 'Adobe', logo: '🎨' },
|
||||
{ name: 'Netflix', logo: '🎬' },
|
||||
{ name: 'Spotify', logo: '🎵' },
|
||||
{ name: 'Google', logo: '🔍' },
|
||||
{ name: 'Meta', logo: '📘' }
|
||||
]
|
||||
|
||||
export default function CTAAndFooter() {
|
||||
return (
|
||||
<>
|
||||
{/* Final CTA Section */}
|
||||
<section className="bg-white py-20">
|
||||
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
||||
<h2 className="text-3xl lg:text-5xl font-bold text-gray-900 mb-8">
|
||||
Transmite profesionalmente desde el primer día
|
||||
</h2>
|
||||
<p className="text-xl text-gray-600 mb-10 leading-relaxed">
|
||||
Con AvanzaCast, no necesitas ser un experto en tecnología para crear transmisiones de alta calidad.
|
||||
Comienza en minutos y crece con nosotros.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-6 justify-center items-center mb-8">
|
||||
<a href="/auth/register">
|
||||
<button className="bg-gradient-to-r from-teal-600 to-teal-700 hover:from-teal-700 hover:to-teal-800 text-white px-10 py-5 text-xl font-bold rounded-xl transition-all duration-200 transform hover:scale-105 hover:shadow-xl active:scale-95 shadow-lg">
|
||||
Comenzar prueba gratuita
|
||||
</button>
|
||||
</a>
|
||||
<button className="text-gray-600 hover:text-gray-800 font-semibold underline transition-colors text-lg hover:bg-white px-4 py-3 rounded-lg hover:shadow-sm">
|
||||
Ver demos en vivo
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p className="text-sm text-gray-500">
|
||||
✓ Sin tarjeta de crédito requerida • ✓ Configuración en 2 minutos • ✓ Soporte 24/7
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Trusted By Section */}
|
||||
<section className="bg-gray-50 py-16">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
||||
<p className="text-gray-500 text-lg mb-8">Confiado por más de 4 millones de creadores</p>
|
||||
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-8 items-center opacity-60">
|
||||
{companies.map((company, index) => (
|
||||
<div key={index} className="flex flex-col items-center space-y-2 hover:opacity-100 transition-opacity">
|
||||
<div className="text-3xl">{company.logo}</div>
|
||||
<span className="text-sm font-medium text-gray-400">{company.name}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Additional CTA Section */}
|
||||
<section className="py-20 bg-gradient-to-r from-blue-50 to-indigo-50">
|
||||
<div className="max-w-4xl mx-auto text-center px-4 sm:px-6 lg:px-8">
|
||||
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-4">
|
||||
¿Listo para elevar tu contenido?
|
||||
</h2>
|
||||
<p className="text-xl text-gray-600 mb-8">
|
||||
Únete a miles de creadores que ya confían en AvanzaCast para sus transmisiones profesionales
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-6 justify-center mb-8">
|
||||
<a href="/auth/register">
|
||||
<button className="w-full sm:w-auto bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 text-white px-10 py-5 text-xl font-bold rounded-xl transition-all duration-200 transform hover:scale-105 hover:shadow-xl active:scale-95 shadow-lg">
|
||||
🚀 Crear Cuenta Gratis
|
||||
</button>
|
||||
</a>
|
||||
<button className="w-full sm:w-auto border-2 border-gray-300 hover:border-gray-400 bg-white hover:bg-gray-50 text-gray-700 px-10 py-5 text-xl font-bold rounded-xl transition-all duration-200 transform hover:scale-105 hover:shadow-lg active:scale-95">
|
||||
📞 Contactar Ventas
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Trust indicators */}
|
||||
<div className="pt-8 border-t border-gray-200">
|
||||
<p className="text-sm text-gray-500 mb-4">Confiado por creadores en todo el mundo</p>
|
||||
<div className="flex justify-center items-center space-x-8 opacity-60">
|
||||
{platforms.map((platform, index) => (
|
||||
<div
|
||||
key={platform}
|
||||
className="text-gray-400 font-medium hover:text-gray-600 hover:-translate-y-0.5 transition-all duration-200 cursor-pointer"
|
||||
>
|
||||
{platform}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="bg-gray-900 text-white py-12">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="grid md:grid-cols-4 gap-8">
|
||||
{/* Logo and description */}
|
||||
<div>
|
||||
<div className="mb-4">
|
||||
<img src="/images/logoavanzacast_white.png" alt="AvanzaCast" className="h-12 w-auto" />
|
||||
</div>
|
||||
<p className="text-gray-400 mb-6">
|
||||
La plataforma profesional de streaming que necesitas para crear contenido de calidad.
|
||||
</p>
|
||||
<div className="flex space-x-4">
|
||||
{/* Social links */}
|
||||
<a href="#" className="text-gray-400 hover:text-white transition-colors">
|
||||
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="#" className="text-gray-400 hover:text-white transition-colors">
|
||||
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M22.46 6c-.77.35-1.6.58-2.46.69.88-.53 1.56-1.37 1.88-2.38-.83.5-1.75.85-2.72 1.05C18.37 4.5 17.26 4 16 4c-2.35 0-4.27 1.92-4.27 4.29 0 .34.04.67.11.98C8.28 9.09 5.11 7.38 3 4.79c-.37.63-.58 1.37-.58 2.15 0 1.49.75 2.81 1.91 3.56-.71 0-1.37-.2-1.95-.5v.03c0 2.08 1.48 3.82 3.44 4.21a4.22 4.22 0 0 1-1.93.07 4.28 4.28 0 0 0 4 2.98 8.521 8.521 0 0 1-5.33 1.84c-.34 0-.68-.02-1.02-.06C3.44 20.29 5.7 21 8.12 21 16 21 20.33 14.46 20.33 8.79c0-.19 0-.37-.01-.56.84-.6 1.56-1.36 2.14-2.23z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="#" className="text-gray-400 hover:text-white transition-colors">
|
||||
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer sections */}
|
||||
{['Producto','Soporte','Empresa'].map((section, idx) => (
|
||||
<div key={idx}>
|
||||
<h4 className="font-semibold mb-4">{section}</h4>
|
||||
<ul className="space-y-2 text-gray-400">
|
||||
<li><a href="#" className="hover:text-white transition-colors">Enlace 1</a></li>
|
||||
<li><a href="#" className="hover:text-white transition-colors">Enlace 2</a></li>
|
||||
<li><a href="#" className="hover:text-white transition-colors">Enlace 3</a></li>
|
||||
<li><a href="#" className="hover:text-white transition-colors">Enlace 4</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="border-t border-gray-700 mt-8 pt-8 flex flex-col md:flex-row justify-between items-center text-gray-400">
|
||||
<p>© 2024 AvanzaCast. Todos los derechos reservados.</p>
|
||||
<div className="flex space-x-6 mt-4 md:mt-0">
|
||||
<a href="/privacy" className="hover:text-white transition-colors">Política de Privacidad</a>
|
||||
<a href="/terms" className="hover:text-white transition-colors">Términos de Servicio</a>
|
||||
<a href="/cookies" className="hover:text-white transition-colors">Cookies</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -1,100 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
interface BlogPost {
|
||||
image: string
|
||||
color: string
|
||||
title: string
|
||||
author: string
|
||||
tag: string
|
||||
}
|
||||
|
||||
const blogPosts: BlogPost[] = [
|
||||
{
|
||||
image: '📅',
|
||||
color: 'bg-red-500',
|
||||
title: 'Cómo programar una transmisión en vivo en YouTube',
|
||||
author: 'Kelsey Bentz',
|
||||
tag: 'YouTube'
|
||||
},
|
||||
{
|
||||
image: '🎙️',
|
||||
color: 'bg-blue-600',
|
||||
title: '7 formas de mejorar el audio de la transmisión en vivo',
|
||||
author: 'AvanzaCast',
|
||||
tag: 'Audio'
|
||||
},
|
||||
{
|
||||
image: '⏱️',
|
||||
color: 'bg-yellow-500',
|
||||
title: '¿Cuánto tiempo debe durar un podcast? Elegir la duración adecuada del episodio',
|
||||
author: 'AvanzaCast',
|
||||
tag: 'Podcast'
|
||||
},
|
||||
{
|
||||
image: '📺',
|
||||
color: 'bg-blue-700',
|
||||
title: 'Cómo realizar una transmisión en vivo de prueba sin ir en vivo | 3 formas fáciles',
|
||||
author: 'AvanzaCast',
|
||||
tag: 'Tutorial'
|
||||
}
|
||||
]
|
||||
|
||||
export default function ContentSection() {
|
||||
return (
|
||||
<>
|
||||
{/* Content Header Section */}
|
||||
<section className="bg-gradient-to-r from-blue-600 via-purple-600 to-green-500 py-20">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
||||
<h2 className="text-3xl lg:text-4xl font-bold text-white mb-8">
|
||||
Transmite mejor, crece más rápido
|
||||
</h2>
|
||||
<p className="text-xl text-white/90 mb-8 max-w-4xl mx-auto">
|
||||
Descubre consejos de expertos, guías prácticas y acciones reales diseñadas para ayudarte a
|
||||
crear contenido de alta calidad, involucrar a tu audiencia y aumentar tu presencia—una
|
||||
transmisión a la vez.
|
||||
</p>
|
||||
<button className="text-blue-600 bg-white hover:bg-gray-50 px-6 py-3 rounded-lg font-medium transition-colors">
|
||||
Ver todas las publicaciones
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Blog Posts Grid */}
|
||||
<section className="bg-white py-20">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-8">
|
||||
{blogPosts.map((post, index) => (
|
||||
<article key={index} className="group cursor-pointer">
|
||||
<div className={`${post.color} rounded-2xl p-6 mb-4 text-center text-white relative overflow-hidden hover:scale-105 transition-transform`}>
|
||||
<div className="text-6xl mb-4">{post.image}</div>
|
||||
<div className="absolute bottom-4 left-4 right-4">
|
||||
<p className="text-sm opacity-90">avanzacast.com/blog</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
<span className="text-xs bg-gray-100 text-gray-600 px-2 py-1 rounded-full">
|
||||
{post.tag}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-gray-500">
|
||||
Escrito por <span className="text-blue-600 font-medium">{post.author}</span>
|
||||
</p>
|
||||
<h3 className="font-bold text-gray-900 group-hover:text-blue-600 transition-colors line-clamp-3">
|
||||
{post.title}
|
||||
</h3>
|
||||
<button className="text-blue-600 text-sm font-medium flex items-center hover:text-blue-800 transition-colors">
|
||||
Leer más
|
||||
<svg className="w-4 h-4 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -1,105 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
export default function FeatureHighlights() {
|
||||
return (
|
||||
<section className="bg-gray-50 py-20">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
{/* First Feature */}
|
||||
<div className="grid lg:grid-cols-2 gap-16 items-center mb-20">
|
||||
<div>
|
||||
<h2 className="text-3xl lg:text-4xl font-bold text-gray-900 mb-6">
|
||||
Transmite en vivo o graba podcasts con invitados remotos
|
||||
</h2>
|
||||
<p className="text-xl text-gray-600 leading-relaxed">
|
||||
Los invitados pueden unirse fácilmente desde su navegador o teléfono en unos pocos clics.
|
||||
No hace falta descargar ningún software.
|
||||
</p>
|
||||
<div className="mt-8">
|
||||
<button className="bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 text-white px-8 py-4 rounded-xl font-bold text-lg transition-all duration-200 transform hover:scale-105 hover:shadow-xl active:scale-95 shadow-lg">
|
||||
Invitar colaboradores
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-pink-100 rounded-3xl p-8">
|
||||
<div className="bg-white rounded-2xl p-6 shadow-lg">
|
||||
<div className="flex items-center space-x-4 mb-4">
|
||||
<div className="w-20 h-16 bg-gray-300 rounded flex items-center justify-center">
|
||||
<span className="text-xs font-medium">James</span>
|
||||
</div>
|
||||
<div className="w-20 h-16 bg-gray-300 rounded flex items-center justify-center">
|
||||
<span className="text-xs font-medium">Helena</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-purple-600 rounded-lg p-4 text-center">
|
||||
<div className="text-white text-lg font-semibold">Melanie Dyann Howe</div>
|
||||
<div className="text-purple-200 text-sm">Anfitriona</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Second Feature */}
|
||||
<div className="grid lg:grid-cols-2 gap-16 items-center">
|
||||
<div className="order-2 lg:order-1">
|
||||
<div className="bg-gradient-to-r from-purple-600 to-blue-600 rounded-3xl p-8 text-white">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<span className="text-sm opacity-80">Zoom</span>
|
||||
<span className="text-sm font-semibold">AvanzaCast</span>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="bg-black/20 rounded-lg aspect-video flex items-center justify-center">
|
||||
<span className="text-xs">📹 Video Feed 1</span>
|
||||
</div>
|
||||
<div className="bg-black/20 rounded-lg aspect-video flex items-center justify-center">
|
||||
<span className="text-xs">📹 Video Feed 2</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 text-center">
|
||||
<div className="inline-flex items-center bg-green-500 text-white px-3 py-1 rounded-full text-xs">
|
||||
<div className="w-2 h-2 bg-white rounded-full mr-2"></div>
|
||||
Grabando en HD
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="order-1 lg:order-2">
|
||||
<h2 className="text-3xl lg:text-4xl font-bold text-gray-900 mb-6">
|
||||
Grabaciones con calidad de estudio, independientemente de tu conexión
|
||||
</h2>
|
||||
<p className="text-xl text-gray-600 leading-relaxed mb-8">
|
||||
¿Te cansaste de que tus podcasts queden arruinados con Zoom y Skype? Con las grabaciones locales,
|
||||
se graba un archivo de video separado de cada invitado directamente en su computadora, sin importar
|
||||
qué tan mala sea su conexión a internet.
|
||||
</p>
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="w-5 h-5 bg-green-500 rounded-full flex items-center justify-center">
|
||||
<svg className="w-3 h-3 text-white" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-gray-600">Grabación local en cada dispositivo</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="w-5 h-5 bg-green-500 rounded-full flex items-center justify-center">
|
||||
<svg className="w-3 h-3 text-white" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-gray-600">Calidad 4K independiente de la conexión</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="w-5 h-5 bg-green-500 rounded-full flex items-center justify-center">
|
||||
<svg className="w-3 h-3 text-white" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-gray-600">Sincronización automática</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@ -1,109 +0,0 @@
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
interface Feature {
|
||||
icon: string
|
||||
title: string
|
||||
description: string
|
||||
}
|
||||
|
||||
const features: Feature[] = [
|
||||
{ icon: '/images/carousel_recording.svg', title: 'Recording', description: 'Graba contenido de alta calidad' },
|
||||
{ icon: '/images/carousel_streaming.svg', title: 'Streaming', description: 'Transmite en vivo a múltiples plataformas' },
|
||||
{ icon: '/images/carousel_guests.svg', title: 'Guests', description: 'Invita colaboradores fácilmente' },
|
||||
{ icon: '/images/carousel_branding.svg', title: 'Branding', description: 'Personaliza tu transmisión' },
|
||||
{ icon: '/images/carousel_engagement.svg', title: 'Engagement', description: 'Interactúa con tu audiencia' },
|
||||
{ icon: '/images/carousel_podcasts.svg', title: 'Podcasts', description: 'Crea podcasts profesionales' },
|
||||
{ icon: '/images/carousel_repurpose.svg', title: 'Repurpose', description: 'Reutiliza tu contenido' }
|
||||
]
|
||||
|
||||
export default function FeaturesCarousel() {
|
||||
const scrollRef = useRef<HTMLDivElement | null>(null)
|
||||
const multiplier = 12
|
||||
const duplicatedFeatures = Array.from({ length: multiplier }, () => features).flat()
|
||||
|
||||
const scrollLeft = () => {
|
||||
if (scrollRef.current) scrollRef.current.scrollBy({ left: -320, behavior: 'smooth' })
|
||||
}
|
||||
const scrollRight = () => {
|
||||
if (scrollRef.current) scrollRef.current.scrollBy({ left: 320, behavior: 'smooth' })
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (scrollRef.current) {
|
||||
const singleSetWidth = features.length * (288 + 24)
|
||||
const middleStart = singleSetWidth * Math.floor(multiplier / 2)
|
||||
scrollRef.current.scrollLeft = middleStart
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
let scrollTimeout: any
|
||||
const container = scrollRef.current
|
||||
const handleScroll = () => {
|
||||
if (!container) return
|
||||
const singleSetWidth = features.length * (288 + 24)
|
||||
const totalWidth = singleSetWidth * multiplier
|
||||
const middleStart = singleSetWidth * Math.floor(multiplier / 2)
|
||||
const tolerance = 50
|
||||
requestAnimationFrame(() => {
|
||||
if (container.scrollLeft <= tolerance) container.scrollLeft = middleStart
|
||||
else if (container.scrollLeft >= totalWidth - container.clientWidth - tolerance) container.scrollLeft = middleStart
|
||||
})
|
||||
}
|
||||
|
||||
if (container) {
|
||||
const debounced = () => {
|
||||
clearTimeout(scrollTimeout)
|
||||
scrollTimeout = setTimeout(handleScroll, 150)
|
||||
}
|
||||
container.addEventListener('scroll', debounced, { passive: true })
|
||||
return () => {
|
||||
container.removeEventListener('scroll', debounced as any)
|
||||
clearTimeout(scrollTimeout)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<section className="bg-gray-50 py-16 w-full">
|
||||
<div className="w-full">
|
||||
<div className="text-center mb-12 px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto">
|
||||
<p className="text-gray-600 mb-8">
|
||||
AvanzaCast es un estudio profesional para grabar y hacer transmisiones en vivo desde tu
|
||||
navegador. Graba contenido o transmite en vivo a Facebook, YouTube y otras plataformas.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="relative w-full">
|
||||
<button onClick={scrollLeft} className="absolute left-4 top-1/2 -translate-y-1/2 z-10 w-12 h-12 rounded-full bg-white shadow-lg border border-gray-200 flex items-center justify-center hover:bg-gray-50 cursor-pointer transition-all">
|
||||
<svg className="w-6 h-6 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7"/></svg>
|
||||
</button>
|
||||
|
||||
<button onClick={scrollRight} className="absolute right-4 top-1/2 -translate-y-1/2 z-10 w-12 h-12 rounded-full bg-white shadow-lg border border-gray-200 flex items-center justify-center hover:bg-gray-50 cursor-pointer transition-all">
|
||||
<svg className="w-6 h-6 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7"/></svg>
|
||||
</button>
|
||||
|
||||
<div ref={scrollRef} className="flex space-x-6 overflow-x-auto scrollbar-hide carousel-smooth pb-4 px-16">
|
||||
{duplicatedFeatures.map((feature, index) => {
|
||||
const setNumber = Math.floor(index / features.length)
|
||||
const itemIndex = index % features.length
|
||||
return (
|
||||
<div key={`set-${setNumber}-item-${itemIndex}-${feature.title}`} className="flex-shrink-0 w-72">
|
||||
<Link to="/auth/register" className="block group hover:scale-105 transition-transform duration-200">
|
||||
<div className="bg-white rounded-2xl p-6 text-center shadow-sm hover:shadow-lg transition-all duration-200 border border-gray-100 hover:border-blue-200">
|
||||
<div className="mb-6 overflow-hidden rounded-xl">
|
||||
<img src={feature.icon} alt={feature.title} className="w-full h-40 object-cover group-hover:scale-110 transition-transform duration-300" />
|
||||
</div>
|
||||
<h5 className="font-bold text-gray-900 text-lg mb-2 group-hover:text-blue-600 transition-colors">{feature.title}</h5>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
export default function Header(){
|
||||
return (
|
||||
<header className="sticky top-0 z-20 bg-white border-b border-slate-200 px-6 py-3">
|
||||
<div className="max-w-7xl mx-auto flex items-center justify-between">
|
||||
<div className="flex items-center gap-4">
|
||||
<button className="btn btn-ghost">☰</button>
|
||||
<div className="text-lg font-semibold">AvanzaCast</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<input className="input" placeholder="Buscar..." />
|
||||
<div className="w-9 h-9 rounded-full bg-slate-200 flex items-center justify-center font-medium">X</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
@ -1,158 +0,0 @@
|
||||
import React, { useState } from 'react'
|
||||
import { Link, useNavigate } from 'react-router-dom'
|
||||
|
||||
export default function HeroSection() {
|
||||
const [email, setEmail] = useState('')
|
||||
const [isGoogleAuthenticated, setIsGoogleAuthenticated] = useState(false)
|
||||
const [googleUser] = useState({ name: 'Nextv', email: 'nextv.stream@gmail.com', initial: 'N' })
|
||||
const navigate = useNavigate()
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
navigate(`/auth/register?email=${encodeURIComponent(email)}`)
|
||||
}
|
||||
|
||||
const handleGoogleLogin = () => {
|
||||
// Demo stub for OAuth flow
|
||||
setTimeout(() => setIsGoogleAuthenticated(true), 600)
|
||||
}
|
||||
|
||||
const handleGoogleContinue = () => {
|
||||
navigate('/broadcasts')
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="relative bg-white py-20 lg:py-32">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="grid lg:grid-cols-2 gap-16 items-center">
|
||||
{/* Left Content */}
|
||||
<div className="space-y-8">
|
||||
<div className="space-y-6">
|
||||
<h1 className="text-4xl lg:text-6xl font-black text-gray-900 leading-tight">
|
||||
La manera más sencilla de
|
||||
<br />
|
||||
<span className="text-gray-900">grabar y transmitir</span>
|
||||
<br />
|
||||
<span className="text-gray-900">en vivo</span>
|
||||
</h1>
|
||||
|
||||
<p className="text-xl text-gray-600 leading-relaxed max-w-lg">
|
||||
AvanzaCast es un estudio profesional para grabar y hacer transmisiones en vivo desde tu
|
||||
navegador. Graba contenido o transmite en vivo a Facebook, YouTube y otras plataformas.
|
||||
</p>
|
||||
|
||||
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4">
|
||||
<div className="flex items-start">
|
||||
<div className="text-blue-600 mr-3 mt-0.5">ℹ️</div>
|
||||
<div>
|
||||
<p className="text-blue-900 font-medium">¡Te refieres a AvanzaCast!</p>
|
||||
<p className="text-blue-700 text-sm">Recibirás una prueba gratuita de 14 días. No se requiere tarjeta.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Content - Registration Form */}
|
||||
<div className="bg-white rounded-2xl shadow-xl border border-gray-200 p-6 max-w-md mx-auto">
|
||||
<div className="mb-4">
|
||||
{!isGoogleAuthenticated ? (
|
||||
<button
|
||||
onClick={handleGoogleLogin}
|
||||
className="w-full flex items-center justify-center px-4 py-2.5 border border-gray-300 rounded-md shadow-sm bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors"
|
||||
>
|
||||
<div className="flex items-center space-x-3">
|
||||
<svg className="w-5 h-5" viewBox="0 0 24 24">
|
||||
<path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
|
||||
<path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
|
||||
<path fill="#FBBC04" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
|
||||
<path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
|
||||
</svg>
|
||||
<span className="text-sm font-medium text-gray-700">Continuar con Google</span>
|
||||
</div>
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={handleGoogleContinue}
|
||||
className="w-full flex items-center px-4 py-2.5 border border-gray-300 rounded-lg shadow-sm bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors"
|
||||
>
|
||||
<div className="w-7 h-7 bg-purple-600 rounded-full flex items-center justify-center">
|
||||
<span className="text-white text-sm font-bold">{googleUser.initial}</span>
|
||||
</div>
|
||||
<div className="flex-1 ml-3">
|
||||
<p className="text-sm font-medium text-gray-900">Continuar como {googleUser.name}</p>
|
||||
<p className="text-xs text-gray-500">{googleUser.email}</p>
|
||||
</div>
|
||||
<svg className="w-4 h-4 text-gray-400" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
|
||||
</svg>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="relative mb-4">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<div className="w-full border-t border-gray-200"></div>
|
||||
</div>
|
||||
<div className="relative flex justify-center text-sm">
|
||||
<span className="px-3 bg-white text-gray-500">O continúa con tu correo</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div>
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
placeholder="Ingresa tu dirección de correo electrónico"
|
||||
className="w-full px-6 py-4 text-base border-2 border-gray-300 rounded-xl focus:ring-4 focus:ring-blue-500/20 focus:border-blue-500 transition-all duration-200 placeholder:text-gray-500 hover:border-gray-400 shadow-sm hover:shadow-md"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 text-white py-4 px-6 rounded-xl font-bold text-base transition-all duration-200 transform hover:scale-105 hover:shadow-lg active:scale-95 shadow-md"
|
||||
>
|
||||
¡Empiezo gratis ahora!
|
||||
</button>
|
||||
|
||||
<div className="text-center py-2">
|
||||
<p className="text-green-600 font-medium text-xs">¡Confiado por más de 12,000,000 creadores!</p>
|
||||
</div>
|
||||
|
||||
<div className="text-xs text-gray-500 text-center leading-tight">
|
||||
<p>
|
||||
Al continuar, aceptas nuestros{' '}
|
||||
<Link to="/terms" className="text-blue-600 hover:underline">
|
||||
Términos de Servicio
|
||||
</Link>
|
||||
, {' '}
|
||||
<Link to="/privacy-policy" className="text-blue-600 hover:underline">
|
||||
Política de Uso
|
||||
</Link>
|
||||
, y reconoces nuestra{' '}
|
||||
<Link to="/privacy" className="text-blue-600 hover:underline">
|
||||
Política de Privacidad
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="text-center pt-2">
|
||||
<p className="text-sm text-gray-600">
|
||||
¿Ya usas AvanzaCast?{' '}
|
||||
<Link to="/auth/login" className="text-blue-600 hover:underline font-medium">
|
||||
Inicia sesión
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@ -68,13 +68,12 @@ const ModernSaasFooter: React.FC = () => {
|
||||
<div className="grid md:grid-cols-12 grid-cols-1 gap-[30px]">
|
||||
{/* Company Info */}
|
||||
<div className="lg:col-span-4 md:col-span-12">
|
||||
<a href="/" className="flex items-center space-x-2 mb-4">
|
||||
<div className="w-10 h-10 bg-indigo-600 rounded-lg flex items-center justify-center">
|
||||
<svg className="w-6 h-6 text-white" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 2L2 7v10c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V7l-10-5z"/>
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
</svg>
|
||||
</div>
|
||||
<a href="/" className="flex items-center space-x-3 mb-4">
|
||||
<img
|
||||
src="/logo_avanzacast.svg"
|
||||
alt="AvanzaCast"
|
||||
className="w-12 h-12"
|
||||
/>
|
||||
<span className="text-2xl font-bold text-white">AvanzaCast</span>
|
||||
</a>
|
||||
<p className="text-slate-300 mb-6">
|
||||
|
||||
@ -53,17 +53,21 @@ const ModernSaasHeader: React.FC = () => {
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="flex items-center justify-between h-20">
|
||||
{/* Logo */}
|
||||
<a href="/" className="flex items-center space-x-2 group">
|
||||
<div className="w-10 h-10 bg-gradient-to-br from-indigo-600 to-indigo-700 rounded-lg flex items-center justify-center shadow-lg group-hover:shadow-xl transition-shadow duration-300">
|
||||
<svg className="w-6 h-6 text-white" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 2L2 7v10c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V7l-10-5z"/>
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
</svg>
|
||||
</div>
|
||||
<span className={`text-2xl font-bold transition-colors duration-300 ${
|
||||
<a href="/" className="flex items-center space-x-3 group">
|
||||
<img
|
||||
src="/logo_avanzacast.svg"
|
||||
alt="AvanzaCast"
|
||||
className="w-14 h-14 transition-transform duration-300 group-hover:scale-110"
|
||||
/>
|
||||
<span className={`text-2xl transition-colors duration-300 ${
|
||||
isScrolled ? 'text-slate-900 dark:text-white' : 'text-slate-900 dark:text-white'
|
||||
}`}>
|
||||
AvanzaCast
|
||||
Avanza
|
||||
</span>
|
||||
<span className={`text-2xl font-bold transition-colors duration-300 ${
|
||||
isScrolled ? 'text-slate-900 dark:text-white' : 'text-slate-900 dark:text-white'
|
||||
}`}>
|
||||
Cast
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@ -217,7 +221,7 @@ const ModernSaasHeader: React.FC = () => {
|
||||
Iniciar Sesión
|
||||
</a>
|
||||
<a href="/auth/register" className="px-5 py-2.5 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg transition-all duration-300 inline-flex items-center shadow-lg hover:shadow-xl font-medium">
|
||||
Comenzar Gratis
|
||||
Empecemos
|
||||
<i className="uil uil-arrow-right ml-2"></i>
|
||||
</a>
|
||||
</div>
|
||||
@ -385,7 +389,7 @@ const ModernSaasHeader: React.FC = () => {
|
||||
Iniciar Sesión
|
||||
</a>
|
||||
<a href="/auth/register" className="block text-center px-5 py-3 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg transition-colors font-medium shadow-lg">
|
||||
Comenzar Gratis
|
||||
Empecemos
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,95 +0,0 @@
|
||||
import React, { useState } from 'react'
|
||||
|
||||
interface NavigationItem {
|
||||
name: string
|
||||
dropdown: boolean
|
||||
href?: string
|
||||
}
|
||||
|
||||
const navigationItems: NavigationItem[] = [
|
||||
{ name: 'Producto', dropdown: true },
|
||||
{ name: 'Comunidad', dropdown: false, href: '/community' },
|
||||
{ name: 'AvanzaCast para', dropdown: false, href: '/for' },
|
||||
{ name: 'Únete a nosotros', dropdown: false, href: '/join' }
|
||||
]
|
||||
|
||||
export default function Navigation() {
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
||||
|
||||
return (
|
||||
<nav className="bg-white shadow-sm border-b border-gray-100 sticky top-0 z-50">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex justify-between items-center h-20">
|
||||
{/* Logo */}
|
||||
<div className="flex-shrink-0 flex items-center">
|
||||
<a href="/" className="flex items-center space-x-3">
|
||||
<img src="/images/logoavanzacast_black.png" alt="AvanzaCast" className="h-12 w-auto" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* Desktop Navigation */}
|
||||
<nav className="hidden md:flex space-x-8">
|
||||
{navigationItems.map((item) => (
|
||||
<div key={item.name} className="relative">
|
||||
<a
|
||||
href={item.href || '#'}
|
||||
className="text-gray-700 hover:text-gray-900 px-3 py-2 text-sm font-medium flex items-center transition-colors"
|
||||
>
|
||||
{item.name}
|
||||
{item.dropdown && (
|
||||
<svg className="ml-1 w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
)}
|
||||
</a>
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
{/* CTA Buttons */}
|
||||
<div className="flex items-center space-x-4">
|
||||
<a href="/auth/login">
|
||||
<button className="text-gray-700 hover:text-gray-900 px-5 py-3 text-base font-semibold transition-all duration-200 hover:bg-gray-50 rounded-xl">
|
||||
Accede
|
||||
</button>
|
||||
</a>
|
||||
<a href="/auth/register">
|
||||
<button className="bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 text-white px-7 py-3 rounded-xl text-base font-bold transition-all duration-200 transform hover:scale-105 hover:shadow-lg active:scale-95 shadow-md">
|
||||
Empezamos
|
||||
</button>
|
||||
</a>
|
||||
|
||||
{/* Mobile menu button */}
|
||||
<button
|
||||
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
||||
className="md:hidden text-gray-700 hover:text-gray-900 p-2"
|
||||
>
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
|
||||
d={mobileMenuOpen ? 'M6 18L18 6M6 6l12 12' : 'M4 6h16M4 12h16M4 18h16'} />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile menu */}
|
||||
{mobileMenuOpen && (
|
||||
<div className="md:hidden py-4 border-t border-gray-100">
|
||||
<div className="flex flex-col space-y-2">
|
||||
{navigationItems.map((item) => (
|
||||
<a
|
||||
key={item.name}
|
||||
href={item.href || '#'}
|
||||
className="text-gray-700 hover:text-gray-900 px-3 py-2 text-sm font-medium"
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
>
|
||||
{item.name}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
const NewCallToAction: React.FC = () => {
|
||||
return (
|
||||
<section className="py-24 bg-gradient-to-r from-blue-600 to-purple-600 relative overflow-hidden">
|
||||
{/* Decorative circles */}
|
||||
<div className="absolute top-0 left-0 w-96 h-96 bg-white opacity-5 rounded-full -translate-x-1/2 -translate-y-1/2"></div>
|
||||
<div className="absolute bottom-0 right-0 w-96 h-96 bg-white opacity-5 rounded-full translate-x-1/2 translate-y-1/2"></div>
|
||||
|
||||
<div className="max-w-[1280px] mx-auto px-5 relative z-10">
|
||||
<div className="text-center max-w-3xl mx-auto">
|
||||
<h2 className="text-4xl lg:text-5xl font-bold text-white mb-6">
|
||||
¿Listo para comenzar tu próxima transmisión?
|
||||
</h2>
|
||||
<p className="text-xl text-blue-100 mb-10">
|
||||
Únete a miles de creadores que ya están transmitiendo con AvanzaCast. Es gratis para comenzar.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center items-center">
|
||||
<a
|
||||
href="/auth/register"
|
||||
className="bg-white text-blue-600 px-10 py-5 rounded-lg hover:bg-gray-100 transition-all font-bold text-lg shadow-xl hover:shadow-2xl hover:-translate-y-1 no-underline"
|
||||
>
|
||||
Comienza gratis
|
||||
</a>
|
||||
<a
|
||||
href="#features"
|
||||
className="bg-transparent border-2 border-white text-white px-10 py-5 rounded-lg hover:bg-white hover:text-blue-600 transition-all font-bold text-lg no-underline"
|
||||
>
|
||||
Ver características
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p className="text-sm text-blue-100 mt-8">
|
||||
No se requiere tarjeta de crédito • Configura en menos de 2 minutos
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewCallToAction;
|
||||
@ -1,107 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
interface ContentBlock {
|
||||
title: string;
|
||||
description: string;
|
||||
image: string;
|
||||
link?: string;
|
||||
background?: string;
|
||||
reverse?: boolean;
|
||||
}
|
||||
|
||||
const contentBlocks: ContentBlock[] = [
|
||||
{
|
||||
title: 'Transmite en vivo o graba podcasts con invitados remotos',
|
||||
description: 'Los invitados pueden unirse fácilmente desde su navegador o teléfono en unos pocos clics. No necesitan crear una cuenta ni descargar nada.',
|
||||
image: '/images/features/guests.svg',
|
||||
link: '/features/guests',
|
||||
reverse: false
|
||||
},
|
||||
{
|
||||
title: 'Grabaciones con calidad de estudio, independientemente de tu conexión',
|
||||
description: '¿Te cansaste de que tus podcasts queden arruinados con Zoom y Skype? AvanzaCast graba localmente en la computadora de cada invitado para obtener pistas de audio y video perfectas.',
|
||||
image: '/images/features/recording.svg',
|
||||
link: '/features/recording',
|
||||
background: 'bg-pink-50',
|
||||
reverse: true
|
||||
},
|
||||
{
|
||||
title: 'Transmite a YouTube, Facebook, LinkedIn y más',
|
||||
description: 'Transmite simultáneamente a múltiples destinos. Alcanza a tu audiencia dondequiera que estén, todo desde un solo lugar.',
|
||||
image: '/images/features/multistream.svg',
|
||||
link: '/features/multistream',
|
||||
reverse: false
|
||||
},
|
||||
{
|
||||
title: 'Personaliza con tu marca',
|
||||
description: 'Añade tu logo, fondos personalizados y overlays para crear transmisiones profesionales que reflejen tu marca.',
|
||||
image: '/images/features/branding.svg',
|
||||
link: '/features/branding',
|
||||
background: 'bg-purple-50',
|
||||
reverse: true
|
||||
}
|
||||
];
|
||||
|
||||
const NewContentDetailsSection: React.FC = () => {
|
||||
return (
|
||||
<section className="py-12">
|
||||
{contentBlocks.map((block, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`py-20 ${block.background || ''}`}
|
||||
>
|
||||
<div className="max-w-[1280px] mx-auto px-5">
|
||||
<div className={`grid lg:grid-cols-2 gap-12 items-center ${block.reverse ? 'lg:grid-flow-dense' : ''}`}>
|
||||
{/* Contenido de texto */}
|
||||
<div className={block.reverse ? 'lg:col-start-2' : ''}>
|
||||
<h2 className="text-4xl lg:text-5xl font-bold text-gray-900 mb-6">
|
||||
{block.title}
|
||||
</h2>
|
||||
<p className="text-lg text-gray-600 mb-8 leading-relaxed">
|
||||
{block.description}
|
||||
</p>
|
||||
{block.link && (
|
||||
<a
|
||||
href={block.link}
|
||||
className="inline-flex items-center gap-2 text-blue-600 hover:text-blue-700 font-medium text-lg group"
|
||||
>
|
||||
Saber más
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
className="group-hover:translate-x-1 transition-transform"
|
||||
>
|
||||
<polyline points="9 18 15 12 9 6"></polyline>
|
||||
</svg>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Imagen */}
|
||||
<div className={block.reverse ? 'lg:col-start-1 lg:row-start-1' : ''}>
|
||||
<div className="relative rounded-2xl overflow-hidden shadow-2xl bg-gradient-to-br from-indigo-500 to-purple-600">
|
||||
<img
|
||||
src={block.image}
|
||||
alt={block.title}
|
||||
className="w-full h-auto"
|
||||
onError={(e) => {
|
||||
// Crear un placeholder SVG inline
|
||||
const svg = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='400'%3E%3Crect width='600' height='400' fill='%234F46E5'/%3E%3Ctext x='50%25' y='50%25' dominant-baseline='middle' text-anchor='middle' font-family='system-ui' font-size='18' fill='white'%3E${encodeURIComponent(block.title.substring(0, 50))}%3C/text%3E%3C/svg%3E`;
|
||||
e.currentTarget.src = svg;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewContentDetailsSection;
|
||||
@ -1,132 +0,0 @@
|
||||
import React, { useState, useRef } from 'react';
|
||||
|
||||
const features = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Grabación',
|
||||
icon: '🎙️',
|
||||
description: 'Graba con calidad de estudio'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Multistream',
|
||||
icon: '📡',
|
||||
description: 'Transmite a múltiples plataformas'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Invitados',
|
||||
icon: '👥',
|
||||
description: 'Invita fácilmente a colaboradores'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Marca',
|
||||
icon: '🎨',
|
||||
description: 'Personaliza con tu branding'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Chat en Vivo',
|
||||
icon: '💬',
|
||||
description: 'Interactúa con tu audiencia'
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'Pantalla Compartida',
|
||||
icon: '🖥️',
|
||||
description: 'Comparte tu pantalla fácilmente'
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: 'Analytics',
|
||||
icon: '📊',
|
||||
description: 'Analiza tu rendimiento'
|
||||
},
|
||||
];
|
||||
|
||||
const NewFeaturesGrid: React.FC = () => {
|
||||
const scrollRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const scroll = (direction: 'left' | 'right') => {
|
||||
if (scrollRef.current) {
|
||||
const scrollAmount = 300;
|
||||
scrollRef.current.scrollBy({
|
||||
left: direction === 'left' ? -scrollAmount : scrollAmount,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleFeatureClick = (featureName: string) => {
|
||||
window.location.href = `/auth/register?feature=${encodeURIComponent(featureName)}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="py-24 bg-white">
|
||||
<div className="max-w-[1280px] mx-auto px-5">
|
||||
{/* Header */}
|
||||
<div className="text-center mb-16">
|
||||
<h2 className="text-4xl lg:text-5xl font-bold text-gray-900 mb-4">
|
||||
Todo lo que necesitas para transmitir
|
||||
</h2>
|
||||
<p className="text-lg text-gray-600 max-w-2xl mx-auto">
|
||||
Herramientas profesionales al alcance de un clic
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Carrusel de características */}
|
||||
<div className="relative">
|
||||
{/* Flecha izquierda */}
|
||||
<button
|
||||
onClick={() => scroll('left')}
|
||||
className="absolute left-0 top-1/2 -translate-y-1/2 z-10 bg-white border-2 border-gray-200 rounded-full p-3 hover:bg-gray-50 hover:scale-105 transition-all shadow-lg hidden md:block"
|
||||
aria-label="Anterior"
|
||||
>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<polyline points="15 18 9 12 15 6"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{/* Grid de características */}
|
||||
<div
|
||||
ref={scrollRef}
|
||||
className="flex gap-6 overflow-x-auto scrollbar-hide scroll-smooth pb-4"
|
||||
style={{ scrollbarWidth: 'none', msOverflowStyle: 'none' }}
|
||||
>
|
||||
{features.map((feature) => (
|
||||
<div
|
||||
key={feature.id}
|
||||
onClick={() => handleFeatureClick(feature.name)}
|
||||
className="flex-none w-64 bg-white border-2 border-gray-200 rounded-2xl p-8 hover:-translate-y-2 hover:shadow-2xl transition-all cursor-pointer group"
|
||||
>
|
||||
<div className="text-5xl mb-4 group-hover:scale-110 transition-transform">
|
||||
{feature.icon}
|
||||
</div>
|
||||
<h3 className="text-xl font-bold text-gray-900 mb-2">
|
||||
{feature.name}
|
||||
</h3>
|
||||
<p className="text-sm text-gray-600">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Flecha derecha */}
|
||||
<button
|
||||
onClick={() => scroll('right')}
|
||||
className="absolute right-0 top-1/2 -translate-y-1/2 z-10 bg-white border-2 border-gray-200 rounded-full p-3 hover:bg-gray-50 hover:scale-105 transition-all shadow-lg hidden md:block"
|
||||
aria-label="Siguiente"
|
||||
>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<polyline points="9 18 15 12 9 6"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewFeaturesGrid;
|
||||
@ -1,125 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const NewFooter: React.FC = () => {
|
||||
const [selectedLanguage, setSelectedLanguage] = useState('es');
|
||||
|
||||
return (
|
||||
<footer className="bg-gray-900 text-gray-300 py-16">
|
||||
<div className="max-w-[1280px] mx-auto px-5">
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-8 mb-12">
|
||||
{/* Logo y descripción */}
|
||||
<div className="col-span-2 md:col-span-4 lg:col-span-1">
|
||||
<img src="/images/logo-white.svg" alt="AvanzaCast" className="h-10 mb-4" />
|
||||
<p className="text-sm text-gray-400">
|
||||
La plataforma de streaming profesional para creadores y empresas.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Producto */}
|
||||
<div>
|
||||
<h3 className="text-white font-bold mb-4">Producto</h3>
|
||||
<ul className="space-y-3 text-sm">
|
||||
<li><a href="/features" className="hover:text-white transition-colors no-underline">Características</a></li>
|
||||
<li><a href="/pricing" className="hover:text-white transition-colors no-underline">Precios</a></li>
|
||||
<li><a href="/integrations" className="hover:text-white transition-colors no-underline">Integraciones</a></li>
|
||||
<li><a href="/updates" className="hover:text-white transition-colors no-underline">Novedades</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Comunidad */}
|
||||
<div>
|
||||
<h3 className="text-white font-bold mb-4">Comunidad</h3>
|
||||
<ul className="space-y-3 text-sm">
|
||||
<li><a href="/blog" className="hover:text-white transition-colors no-underline">Blog</a></li>
|
||||
<li><a href="/tutorials" className="hover:text-white transition-colors no-underline">Tutoriales</a></li>
|
||||
<li><a href="/forum" className="hover:text-white transition-colors no-underline">Foro</a></li>
|
||||
<li><a href="/events" className="hover:text-white transition-colors no-underline">Eventos</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Empresa */}
|
||||
<div>
|
||||
<h3 className="text-white font-bold mb-4">Empresa</h3>
|
||||
<ul className="space-y-3 text-sm">
|
||||
<li><a href="/about" className="hover:text-white transition-colors no-underline">Acerca de</a></li>
|
||||
<li><a href="/careers" className="hover:text-white transition-colors no-underline">Carreras</a></li>
|
||||
<li><a href="/contact" className="hover:text-white transition-colors no-underline">Contacto</a></li>
|
||||
<li><a href="/partners" className="hover:text-white transition-colors no-underline">Partners</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Legal */}
|
||||
<div>
|
||||
<h3 className="text-white font-bold mb-4">Legal</h3>
|
||||
<ul className="space-y-3 text-sm">
|
||||
<li><a href="/terms" className="hover:text-white transition-colors no-underline">Términos de Servicio</a></li>
|
||||
<li><a href="/privacy" className="hover:text-white transition-colors no-underline">Política de Privacidad</a></li>
|
||||
<li><a href="/cookies" className="hover:text-white transition-colors no-underline">Cookies</a></li>
|
||||
<li><a href="/dmca" className="hover:text-white transition-colors no-underline">DMCA</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom bar */}
|
||||
<div className="border-t border-gray-800 pt-8 flex flex-col md:flex-row justify-between items-center gap-4">
|
||||
<p className="text-sm text-gray-400">
|
||||
© 2025 AvanzaCast. Todos los derechos reservados.
|
||||
</p>
|
||||
|
||||
{/* Social links */}
|
||||
<div className="flex gap-6">
|
||||
<a href="https://twitter.com/avanzacast" className="text-gray-400 hover:text-white transition-colors" aria-label="Twitter">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M23 3a10.9 10.9 0 01-3.14 1.53 4.48 4.48 0 00-7.86 3v1A10.66 10.66 0 013 4s-4 9 5 13a11.64 11.64 0 01-7 2c9 5 20 0 20-11.5a4.5 4.5 0 00-.08-.83A7.72 7.72 0 0023 3z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="https://facebook.com/avanzacast" className="text-gray-400 hover:text-white transition-colors" aria-label="Facebook">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M18 2h-3a5 5 0 00-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 011-1h3z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="https://youtube.com/avanzacast" className="text-gray-400 hover:text-white transition-colors" aria-label="YouTube">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M22.54 6.42a2.78 2.78 0 00-1.94-2C18.88 4 12 4 12 4s-6.88 0-8.6.46a2.78 2.78 0 00-1.94 2A29 29 0 001 11.75a29 29 0 00.46 5.33A2.78 2.78 0 003.4 19c1.72.46 8.6.46 8.6.46s6.88 0 8.6-.46a2.78 2.78 0 001.94-2 29 29 0 00.46-5.25 29 29 0 00-.46-5.33z"/>
|
||||
<polygon points="9.75 15.02 15.5 11.75 9.75 8.48 9.75 15.02" fill="#fff"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="https://linkedin.com/company/avanzacast" className="text-gray-400 hover:text-white transition-colors" aria-label="LinkedIn">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M16 8a6 6 0 016 6v7h-4v-7a2 2 0 00-2-2 2 2 0 00-2 2v7h-4v-7a6 6 0 016-6zM2 9h4v12H2z"/>
|
||||
<circle cx="4" cy="4" r="2"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* Language selector */}
|
||||
<div className="relative">
|
||||
<select
|
||||
value={selectedLanguage}
|
||||
onChange={(e) => setSelectedLanguage(e.target.value)}
|
||||
className="bg-gray-800 border border-gray-700 text-gray-300 px-4 py-2 rounded-lg appearance-none cursor-pointer hover:bg-gray-700 transition-colors pr-10"
|
||||
>
|
||||
<option value="es">🇪🇸 Español</option>
|
||||
<option value="en">🇺🇸 English</option>
|
||||
<option value="pt">🇧🇷 Português</option>
|
||||
<option value="fr">🇫🇷 Français</option>
|
||||
</select>
|
||||
<svg
|
||||
className="absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none text-gray-400"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewFooter;
|
||||
@ -1,179 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
// Iconos SVG
|
||||
const MenuIcon = () => (
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<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">
|
||||
<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">
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
);
|
||||
|
||||
const IconMic = () => (
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"></path>
|
||||
<path d="M19 10v2a7 7 0 0 1-14 0v-2"></path>
|
||||
<line x1="12" y1="19" x2="12" y2="23"></line>
|
||||
<line x1="8" y1="23" x2="16" y2="23"></line>
|
||||
</svg>
|
||||
);
|
||||
|
||||
const IconUsers = () => (
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
|
||||
<circle cx="9" cy="7" r="4"></circle>
|
||||
<path d="M23 21v-2a4 4 0 0 0-3-3.87m-3-12a4 4 0 0 1 0 7.75"></path>
|
||||
</svg>
|
||||
);
|
||||
|
||||
const IconVideo = () => (
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<path d="M23 7l-7 5 7 5V7z"></path>
|
||||
<rect x="1" y="5" width="15" height="14" rx="2" ry="2"></rect>
|
||||
</svg>
|
||||
);
|
||||
|
||||
const NewHeader: React.FC = () => {
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||
const [isProductDropdownOpen, setIsProductDropdownOpen] = useState(false);
|
||||
const [isBusinessDropdownOpen, setIsBusinessDropdownOpen] = useState(false);
|
||||
|
||||
const toggleMobileMenu = () => setIsMobileMenuOpen(!isMobileMenuOpen);
|
||||
|
||||
return (
|
||||
<header className="sticky top-0 bg-white border-b border-gray-200 z-50 shadow-sm">
|
||||
<div className="max-w-[1280px] mx-auto px-5">
|
||||
<div className="flex items-center justify-between h-20">
|
||||
{/* Logo */}
|
||||
<a href="/" className="flex items-center">
|
||||
<img src="/images/logo.svg" alt="AvanzaCast" className="h-10 w-auto" />
|
||||
</a>
|
||||
|
||||
{/* Desktop Navigation */}
|
||||
<nav className="hidden lg:flex items-center gap-8">
|
||||
<ul className="flex items-center gap-8 list-none m-0 p-0">
|
||||
{/* Producto Dropdown */}
|
||||
<li
|
||||
className="relative"
|
||||
onMouseEnter={() => setIsProductDropdownOpen(true)}
|
||||
onMouseLeave={() => setIsProductDropdownOpen(false)}
|
||||
>
|
||||
<a href="#" className="flex items-center gap-1 text-gray-700 hover:text-blue-600 transition-colors no-underline">
|
||||
Producto
|
||||
<ChevronDown />
|
||||
</a>
|
||||
{isProductDropdownOpen && (
|
||||
<ul className="absolute top-full left-0 mt-2 bg-white border border-gray-200 rounded-lg shadow-lg min-w-[220px] p-2">
|
||||
<li>
|
||||
<a href="#" className="flex items-center gap-3 px-4 py-3 hover:bg-gray-50 rounded text-gray-700 no-underline">
|
||||
<IconMic />
|
||||
<span>Grabación</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" className="flex items-center gap-3 px-4 py-3 hover:bg-gray-50 rounded text-gray-700 no-underline">
|
||||
<IconVideo />
|
||||
<span>Multistream</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" className="flex items-center gap-3 px-4 py-3 hover:bg-gray-50 rounded text-gray-700 no-underline">
|
||||
<IconUsers />
|
||||
<span>Invitados</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
)}
|
||||
</li>
|
||||
|
||||
<li><a href="#" className="text-gray-700 hover:text-blue-600 transition-colors no-underline">Contacto</a></li>
|
||||
<li><a href="#" className="text-gray-700 hover:text-blue-600 transition-colors no-underline">Precios</a></li>
|
||||
<li><a href="#" className="text-gray-700 hover:text-blue-600 transition-colors no-underline">Novedades</a></li>
|
||||
|
||||
{/* Para Empresas Dropdown */}
|
||||
<li
|
||||
className="relative"
|
||||
onMouseEnter={() => setIsBusinessDropdownOpen(true)}
|
||||
onMouseLeave={() => setIsBusinessDropdownOpen(false)}
|
||||
>
|
||||
<a href="#" className="flex items-center gap-1 text-gray-700 hover:text-blue-600 transition-colors no-underline">
|
||||
Para empresas
|
||||
<ChevronDown />
|
||||
</a>
|
||||
{isBusinessDropdownOpen && (
|
||||
<ul className="absolute top-full left-0 mt-2 bg-white border border-gray-200 rounded-lg shadow-lg min-w-[220px] p-2">
|
||||
<li>
|
||||
<a href="#" className="flex items-center gap-3 px-4 py-3 hover:bg-gray-50 rounded text-gray-700 no-underline">
|
||||
Soluciones empresariales
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" className="flex items-center gap-3 px-4 py-3 hover:bg-gray-50 rounded text-gray-700 no-underline">
|
||||
Casos de uso
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
)}
|
||||
</li>
|
||||
|
||||
<li><a href="/auth/login" className="text-gray-700 hover:text-blue-600 transition-colors no-underline">Accede</a></li>
|
||||
</ul>
|
||||
|
||||
<a
|
||||
href="/auth/register"
|
||||
className="bg-blue-600 text-white px-8 py-4 rounded-lg hover:bg-blue-700 transition-colors no-underline font-medium"
|
||||
>
|
||||
Empecemos
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
{/* Mobile Menu Toggle */}
|
||||
<button
|
||||
className="lg:hidden p-2 text-gray-700 hover:text-blue-600"
|
||||
onClick={toggleMobileMenu}
|
||||
aria-label="Toggle menu"
|
||||
>
|
||||
{isMobileMenuOpen ? <CloseIcon /> : <MenuIcon />}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu */}
|
||||
{isMobileMenuOpen && (
|
||||
<nav className="lg:hidden py-4 border-t border-gray-200">
|
||||
<ul className="flex flex-col gap-4 list-none m-0 p-0">
|
||||
<li><a href="#" className="block py-2 text-gray-700 hover:text-blue-600 no-underline">Producto</a></li>
|
||||
<li><a href="#" className="block py-2 text-gray-700 hover:text-blue-600 no-underline">Contacto</a></li>
|
||||
<li><a href="#" className="block py-2 text-gray-700 hover:text-blue-600 no-underline">Precios</a></li>
|
||||
<li><a href="#" className="block py-2 text-gray-700 hover:text-blue-600 no-underline">Novedades</a></li>
|
||||
<li><a href="#" className="block py-2 text-gray-700 hover:text-blue-600 no-underline">Para empresas</a></li>
|
||||
<li><a href="/auth/login" className="block py-2 text-gray-700 hover:text-blue-600 no-underline">Accede</a></li>
|
||||
<li>
|
||||
<a
|
||||
href="/auth/register"
|
||||
className="block bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700 transition-colors no-underline text-center font-medium"
|
||||
>
|
||||
Empecemos
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
)}
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewHeader;
|
||||
@ -1,106 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const NewHeroSection: React.FC = () => {
|
||||
const [email, setEmail] = useState('');
|
||||
|
||||
const handleGoogleSignup = () => {
|
||||
window.location.href = '/auth/register?provider=google';
|
||||
};
|
||||
|
||||
const handleEmailSignup = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
window.location.href = `/auth/register?email=${encodeURIComponent(email)}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="relative py-24 lg:py-32 bg-gradient-to-b from-blue-50 to-white overflow-hidden">
|
||||
<div className="max-w-[1280px] mx-auto px-5">
|
||||
<div className="grid lg:grid-cols-2 gap-12 items-center">
|
||||
{/* Contenido del Hero */}
|
||||
<div className="max-w-[600px]">
|
||||
<h1 className="text-5xl lg:text-6xl font-bold text-gray-900 leading-tight mb-6">
|
||||
La manera más sencilla de transmitir en vivo y grabar
|
||||
</h1>
|
||||
<p className="text-lg lg:text-xl text-gray-600 mb-8 max-w-[500px]">
|
||||
AvanzaCast es un estudio profesional para grabar y hacer transmisiones en vivo desde tu navegador. Invita a tus invitados, comparte tu pantalla y transmite en varias plataformas a la vez.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Formulario de Registro */}
|
||||
<div className="relative min-w-[350px]">
|
||||
<div className="bg-white p-8 rounded-2xl shadow-xl relative z-10">
|
||||
<h3 className="text-2xl font-bold text-gray-900 mb-6">Comienza gratis</h3>
|
||||
|
||||
{/* Botón de Google */}
|
||||
<button
|
||||
onClick={handleGoogleSignup}
|
||||
className="w-full bg-white border-2 border-gray-300 text-gray-700 px-6 py-4 rounded-lg hover:bg-gray-50 transition-colors flex items-center justify-center gap-3 mb-4 font-medium"
|
||||
>
|
||||
<svg width="20" height="20" viewBox="0 0 24 24">
|
||||
<path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
|
||||
<path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
|
||||
<path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
|
||||
<path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
|
||||
</svg>
|
||||
Continuar con Google
|
||||
</button>
|
||||
|
||||
{/* Separador */}
|
||||
<div className="relative text-center my-6">
|
||||
<span className="relative bg-white px-4 text-sm text-gray-500 z-10">o</span>
|
||||
<div className="absolute top-1/2 left-0 right-0 h-px bg-gray-200 -z-10"></div>
|
||||
</div>
|
||||
|
||||
{/* Formulario de Email */}
|
||||
<form onSubmit={handleEmailSignup}>
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
placeholder="Ingresa tu correo electrónico"
|
||||
className="w-full border border-gray-300 px-4 py-4 rounded-lg mb-4 focus:outline-none focus:border-blue-600 focus:ring-2 focus:ring-blue-100"
|
||||
required
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full bg-blue-600 text-white px-6 py-4 rounded-lg hover:bg-blue-700 transition-colors font-medium text-lg"
|
||||
>
|
||||
Empecemos
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<p className="text-xs text-gray-500 mt-4 text-center">
|
||||
Al continuar, aceptas nuestros{' '}
|
||||
<a href="/terms" className="text-blue-600 hover:underline">Términos de Servicio</a>
|
||||
{' '}y{' '}
|
||||
<a href="/privacy" className="text-blue-600 hover:underline">Política de Privacidad</a>.
|
||||
</p>
|
||||
|
||||
<p className="text-sm text-gray-600 mt-6 text-center">
|
||||
¿Ya tienes cuenta?{' '}
|
||||
<a href="/auth/login" className="text-blue-600 hover:underline font-medium">Inicia sesión</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Gráfico decorativo de fondo */}
|
||||
<div className="absolute -right-8 -bottom-8 w-64 h-64 bg-gradient-to-br from-blue-100 to-purple-100 rounded-full blur-3xl opacity-30 -z-10"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Logos de clientes */}
|
||||
<div className="mt-20 pt-12 border-t border-gray-200">
|
||||
<p className="text-center text-sm text-gray-500 mb-8">Confiado por miles de creadores y empresas</p>
|
||||
<div className="flex flex-wrap justify-center items-center gap-12 opacity-60 grayscale">
|
||||
<img src="/images/clients/microsoft.svg" alt="Microsoft" className="h-8" />
|
||||
<img src="/images/clients/google.svg" alt="Google" className="h-8" />
|
||||
<img src="/images/clients/amazon.svg" alt="Amazon" className="h-8" />
|
||||
<img src="/images/clients/facebook.svg" alt="Facebook" className="h-8" />
|
||||
<img src="/images/clients/linkedin.svg" alt="LinkedIn" className="h-8" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewHeroSection;
|
||||
@ -1,182 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
interface Testimonial {
|
||||
id: number;
|
||||
name: string;
|
||||
role: string;
|
||||
company: string;
|
||||
image: string;
|
||||
quote: string;
|
||||
rating: number;
|
||||
}
|
||||
|
||||
const testimonials: Testimonial[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'María García',
|
||||
role: 'CEO',
|
||||
company: 'TechStartup',
|
||||
image: '/images/testimonials/user1.svg',
|
||||
quote: 'AvanzaCast transformó completamente la forma en que hacemos webinars. La calidad es excepcional y es súper fácil de usar.',
|
||||
rating: 5
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Carlos Rodríguez',
|
||||
role: 'Content Creator',
|
||||
company: 'YouTube',
|
||||
image: '/images/testimonials/user2.svg',
|
||||
quote: 'Llevo más de 2 años usando AvanzaCast para mis streams. No cambiaría a otra plataforma por nada del mundo.',
|
||||
rating: 5
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Ana Martínez',
|
||||
role: 'Marketing Director',
|
||||
company: 'GlobalCorp',
|
||||
image: '/images/testimonials/user3.svg',
|
||||
quote: 'La capacidad de transmitir simultáneamente a múltiples plataformas nos ha ayudado a triplicar nuestro alcance.',
|
||||
rating: 5
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Juan Pérez',
|
||||
role: 'Podcaster',
|
||||
company: 'El Podcast Diario',
|
||||
image: '/images/testimonials/user4.svg',
|
||||
quote: 'La calidad de audio es impresionante. Mis invitados siempre comentan lo profesional que se ve todo.',
|
||||
rating: 5
|
||||
}
|
||||
];
|
||||
|
||||
const NewTestimonialsCarousel: React.FC = () => {
|
||||
const [currentIndex, setCurrentIndex] = useState(0);
|
||||
|
||||
const nextSlide = () => {
|
||||
setCurrentIndex((prev) => (prev + 1) % testimonials.length);
|
||||
};
|
||||
|
||||
const prevSlide = () => {
|
||||
setCurrentIndex((prev) => (prev - 1 + testimonials.length) % testimonials.length);
|
||||
};
|
||||
|
||||
const goToSlide = (index: number) => {
|
||||
setCurrentIndex(index);
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="py-24 bg-gradient-to-b from-blue-50 to-white">
|
||||
<div className="max-w-[1280px] mx-auto px-5">
|
||||
{/* Header */}
|
||||
<div className="text-center mb-16">
|
||||
<p className="text-sm font-semibold text-blue-600 uppercase tracking-wider mb-4">
|
||||
Testimonios
|
||||
</p>
|
||||
<h2 className="text-4xl lg:text-5xl font-bold text-gray-900 mb-4">
|
||||
60,000,000+ transmisiones realizadas
|
||||
</h2>
|
||||
<p className="text-lg text-gray-600 max-w-2xl mx-auto">
|
||||
Miles de creadores confían en AvanzaCast para sus transmisiones
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Carrusel */}
|
||||
<div className="relative max-w-4xl mx-auto">
|
||||
{/* Flecha izquierda */}
|
||||
<button
|
||||
onClick={prevSlide}
|
||||
className="absolute left-0 top-1/2 -translate-y-1/2 -translate-x-12 z-10 bg-white border-2 border-gray-200 rounded-full p-3 hover:bg-gray-50 hover:scale-105 transition-all shadow-lg hidden lg:block"
|
||||
aria-label="Anterior testimonio"
|
||||
>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<polyline points="15 18 9 12 15 6"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{/* Testimonial Card */}
|
||||
<div className="bg-white rounded-2xl shadow-xl p-12 min-h-[400px] flex flex-col justify-between">
|
||||
{/* Rating Stars */}
|
||||
<div className="flex gap-1 mb-6">
|
||||
{[...Array(testimonials[currentIndex].rating)].map((_, i) => (
|
||||
<svg key={i} width="24" height="24" viewBox="0 0 24 24" fill="#FFD700" stroke="#FFD700">
|
||||
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
|
||||
</svg>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Quote */}
|
||||
<blockquote className="text-2xl text-gray-700 leading-relaxed mb-8 flex-grow">
|
||||
"{testimonials[currentIndex].quote}"
|
||||
</blockquote>
|
||||
|
||||
{/* Author Info */}
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-16 h-16 rounded-full bg-gradient-to-br from-blue-400 to-purple-600 flex items-center justify-center text-white text-2xl font-bold">
|
||||
{testimonials[currentIndex].name.charAt(0)}
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-bold text-gray-900 text-lg">
|
||||
{testimonials[currentIndex].name}
|
||||
</p>
|
||||
<p className="text-gray-600">
|
||||
{testimonials[currentIndex].role} at {testimonials[currentIndex].company}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Flecha derecha */}
|
||||
<button
|
||||
onClick={nextSlide}
|
||||
className="absolute right-0 top-1/2 -translate-y-1/2 translate-x-12 z-10 bg-white border-2 border-gray-200 rounded-full p-3 hover:bg-gray-50 hover:scale-105 transition-all shadow-lg hidden lg:block"
|
||||
aria-label="Siguiente testimonio"
|
||||
>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<polyline points="9 18 15 12 9 6"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{/* Pagination Dots */}
|
||||
<div className="flex justify-center gap-3 mt-8">
|
||||
{testimonials.map((_, index) => (
|
||||
<button
|
||||
key={index}
|
||||
onClick={() => goToSlide(index)}
|
||||
className={`w-3 h-3 rounded-full transition-all ${
|
||||
index === currentIndex
|
||||
? 'bg-blue-600 w-8'
|
||||
: 'bg-gray-300 hover:bg-gray-400'
|
||||
}`}
|
||||
aria-label={`Ir al testimonio ${index + 1}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile Navigation */}
|
||||
<div className="flex justify-center gap-4 mt-8 lg:hidden">
|
||||
<button
|
||||
onClick={prevSlide}
|
||||
className="bg-white border-2 border-gray-200 rounded-full p-3 hover:bg-gray-50 transition-all shadow"
|
||||
aria-label="Anterior"
|
||||
>
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<polyline points="15 18 9 12 15 6"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
onClick={nextSlide}
|
||||
className="bg-white border-2 border-gray-200 rounded-full p-3 hover:bg-gray-50 transition-all shadow"
|
||||
aria-label="Siguiente"
|
||||
>
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<polyline points="9 18 15 12 9 6"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewTestimonialsCarousel;
|
||||
@ -1,393 +0,0 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
// Iconos SVG
|
||||
const MenuIcon = () => (
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<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">
|
||||
<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="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
);
|
||||
|
||||
const PhoneIcon = () => (
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"></path>
|
||||
</svg>
|
||||
);
|
||||
|
||||
const EmailIcon = () => (
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
|
||||
<polyline points="22,6 12,13 2,6"></polyline>
|
||||
</svg>
|
||||
);
|
||||
|
||||
const SearchIcon = () => (
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<circle cx="11" cy="11" r="8"></circle>
|
||||
<path d="m21 21-4.35-4.35"></path>
|
||||
</svg>
|
||||
);
|
||||
|
||||
const NextreamHeader: React.FC = () => {
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||
const [isScrolled, setIsScrolled] = useState(false);
|
||||
const [activeDropdown, setActiveDropdown] = useState<string | null>(null);
|
||||
|
||||
// Detectar scroll para cambiar el header
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
setIsScrolled(window.scrollY > 50);
|
||||
};
|
||||
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
return () => window.removeEventListener('scroll', handleScroll);
|
||||
}, []);
|
||||
|
||||
const handleDropdownToggle = (dropdown: string) => {
|
||||
setActiveDropdown(activeDropdown === dropdown ? null : dropdown);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Top Bar - Info superior */}
|
||||
<div className="bg-[#0A0E27] text-white py-2.5 hidden lg:block">
|
||||
<div className="max-w-[1280px] mx-auto px-5">
|
||||
<div className="flex justify-between items-center text-sm">
|
||||
{/* Información de contacto */}
|
||||
<div className="flex items-center gap-6">
|
||||
<div className="flex items-center gap-2 hover:text-blue-400 transition-colors cursor-pointer">
|
||||
<PhoneIcon />
|
||||
<span>+1 (555) 123-4567</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 hover:text-blue-400 transition-colors cursor-pointer">
|
||||
<EmailIcon />
|
||||
<span>contact@avanzacast.com</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Social icons y Language */}
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-3">
|
||||
{/* Facebook */}
|
||||
<a href="#" className="w-8 h-8 flex items-center justify-center rounded-full bg-white/10 hover:bg-blue-600 transition-all duration-300">
|
||||
<svg width="14" height="14" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/>
|
||||
</svg>
|
||||
</a>
|
||||
{/* Twitter */}
|
||||
<a href="#" className="w-8 h-8 flex items-center justify-center rounded-full bg-white/10 hover:bg-blue-400 transition-all duration-300">
|
||||
<svg width="14" height="14" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/>
|
||||
</svg>
|
||||
</a>
|
||||
{/* LinkedIn */}
|
||||
<a href="#" className="w-8 h-8 flex items-center justify-center rounded-full bg-white/10 hover:bg-blue-700 transition-all duration-300">
|
||||
<svg width="14" height="14" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* Language Selector */}
|
||||
<div className="flex items-center gap-2 text-sm border-l border-white/20 pl-4">
|
||||
<span className="text-white/70">🇪🇸</span>
|
||||
<select className="bg-transparent text-white text-sm cursor-pointer outline-none">
|
||||
<option value="es" className="bg-[#0A0E27]">ES</option>
|
||||
<option value="en" className="bg-[#0A0E27]">EN</option>
|
||||
<option value="pt" className="bg-[#0A0E27]">PT</option>
|
||||
<option value="fr" className="bg-[#0A0E27]">FR</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main Header - Navegación principal */}
|
||||
<header
|
||||
className={`sticky top-0 z-50 transition-all duration-300 ${
|
||||
isScrolled
|
||||
? 'bg-white shadow-lg'
|
||||
: 'bg-white'
|
||||
}`}
|
||||
>
|
||||
<div className="max-w-[1280px] mx-auto px-5">
|
||||
<div className="flex items-center justify-between h-20">
|
||||
{/* Logo */}
|
||||
<a href="/" className="flex items-center gap-3 group">
|
||||
<div className="relative">
|
||||
<div className="w-12 h-12 bg-gradient-to-br from-blue-600 via-blue-500 to-purple-600 rounded-lg flex items-center justify-center transform group-hover:scale-110 transition-transform duration-300 shadow-lg">
|
||||
<svg width="28" height="28" viewBox="0 0 24 24" fill="white">
|
||||
<path d="M23 7l-7 5 7 5V7z"></path>
|
||||
<rect x="1" y="5" width="15" height="14" rx="2" ry="2" fill="white"></rect>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="absolute -top-1 -right-1 w-3 h-3 bg-red-500 rounded-full animate-pulse"></div>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-2xl font-bold bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
|
||||
AvanzaCast
|
||||
</span>
|
||||
<span className="text-[10px] text-gray-500 -mt-1">Professional Streaming</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{/* Desktop Navigation */}
|
||||
<nav className="hidden lg:flex items-center gap-8">
|
||||
<a href="/" className="text-gray-700 hover:text-blue-600 font-medium transition-colors duration-200 relative group">
|
||||
Inicio
|
||||
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-blue-600 group-hover:w-full transition-all duration-300"></span>
|
||||
</a>
|
||||
|
||||
{/* Producto Dropdown */}
|
||||
<div
|
||||
className="relative"
|
||||
onMouseEnter={() => setActiveDropdown('producto')}
|
||||
onMouseLeave={() => setActiveDropdown(null)}
|
||||
>
|
||||
<button className="flex items-center gap-1 text-gray-700 hover:text-blue-600 font-medium transition-colors duration-200">
|
||||
Producto
|
||||
<ChevronDown />
|
||||
</button>
|
||||
|
||||
{activeDropdown === 'producto' && (
|
||||
<div className="absolute top-full left-0 mt-4 w-64 bg-white rounded-xl shadow-2xl border border-gray-100 py-3 animate-fadeIn">
|
||||
<div className="absolute -top-2 left-8 w-4 h-4 bg-white border-l border-t border-gray-100 transform rotate-45"></div>
|
||||
<a href="#" className="flex items-center gap-3 px-5 py-3 hover:bg-blue-50 transition-colors group">
|
||||
<div className="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center group-hover:bg-blue-600 transition-colors">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className="group-hover:stroke-white">
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<polygon points="10 8 16 12 10 16 10 8"></polygon>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<div className="font-medium text-gray-900">Streaming en Vivo</div>
|
||||
<div className="text-xs text-gray-500">Transmite a múltiples plataformas</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="#" className="flex items-center gap-3 px-5 py-3 hover:bg-blue-50 transition-colors group">
|
||||
<div className="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center group-hover:bg-purple-600 transition-colors">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className="group-hover:stroke-white">
|
||||
<rect x="2" y="2" width="20" height="20" rx="2.18" ry="2.18"></rect>
|
||||
<line x1="7" y1="2" x2="7" y2="22"></line>
|
||||
<line x1="17" y1="2" x2="17" y2="22"></line>
|
||||
<line x1="2" y1="12" x2="22" y2="12"></line>
|
||||
<line x1="2" y1="7" x2="7" y2="7"></line>
|
||||
<line x1="2" y1="17" x2="7" y2="17"></line>
|
||||
<line x1="17" y1="17" x2="22" y2="17"></line>
|
||||
<line x1="17" y1="7" x2="22" y2="7"></line>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<div className="font-medium text-gray-900">Estudio Virtual</div>
|
||||
<div className="text-xs text-gray-500">Editor profesional en vivo</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="#" className="flex items-center gap-3 px-5 py-3 hover:bg-blue-50 transition-colors group">
|
||||
<div className="w-10 h-10 bg-green-100 rounded-lg flex items-center justify-center group-hover:bg-green-600 transition-colors">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className="group-hover:stroke-white">
|
||||
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
||||
<polyline points="7 10 12 15 17 10"></polyline>
|
||||
<line x1="12" y1="15" x2="12" y2="3"></line>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<div className="font-medium text-gray-900">Grabación</div>
|
||||
<div className="text-xs text-gray-500">Graba y almacena en HD</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Soluciones Dropdown */}
|
||||
<div
|
||||
className="relative"
|
||||
onMouseEnter={() => setActiveDropdown('soluciones')}
|
||||
onMouseLeave={() => setActiveDropdown(null)}
|
||||
>
|
||||
<button className="flex items-center gap-1 text-gray-700 hover:text-blue-600 font-medium transition-colors duration-200">
|
||||
Soluciones
|
||||
<ChevronDown />
|
||||
</button>
|
||||
|
||||
{activeDropdown === 'soluciones' && (
|
||||
<div className="absolute top-full left-0 mt-4 w-64 bg-white rounded-xl shadow-2xl border border-gray-100 py-3 animate-fadeIn">
|
||||
<div className="absolute -top-2 left-8 w-4 h-4 bg-white border-l border-t border-gray-100 transform rotate-45"></div>
|
||||
<a href="#" className="flex items-center gap-3 px-5 py-3 hover:bg-blue-50 transition-colors">
|
||||
<span className="text-2xl">🎓</span>
|
||||
<div>
|
||||
<div className="font-medium text-gray-900">Educación</div>
|
||||
<div className="text-xs text-gray-500">Clases en vivo interactivas</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="#" className="flex items-center gap-3 px-5 py-3 hover:bg-blue-50 transition-colors">
|
||||
<span className="text-2xl">🏢</span>
|
||||
<div>
|
||||
<div className="font-medium text-gray-900">Empresas</div>
|
||||
<div className="text-xs text-gray-500">Webinars corporativos</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="#" className="flex items-center gap-3 px-5 py-3 hover:bg-blue-50 transition-colors">
|
||||
<span className="text-2xl">🎮</span>
|
||||
<div>
|
||||
<div className="font-medium text-gray-900">Gaming</div>
|
||||
<div className="text-xs text-gray-500">Streaming para gamers</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="#" className="flex items-center gap-3 px-5 py-3 hover:bg-blue-50 transition-colors">
|
||||
<span className="text-2xl">📺</span>
|
||||
<div>
|
||||
<div className="font-medium text-gray-900">Eventos</div>
|
||||
<div className="text-xs text-gray-500">Conferencias y eventos</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<a href="/pricing" className="text-gray-700 hover:text-blue-600 font-medium transition-colors duration-200 relative group">
|
||||
Precios
|
||||
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-blue-600 group-hover:w-full transition-all duration-300"></span>
|
||||
</a>
|
||||
|
||||
<a href="/about" className="text-gray-700 hover:text-blue-600 font-medium transition-colors duration-200 relative group">
|
||||
Nosotros
|
||||
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-blue-600 group-hover:w-full transition-all duration-300"></span>
|
||||
</a>
|
||||
|
||||
<a href="/contact" className="text-gray-700 hover:text-blue-600 font-medium transition-colors duration-200 relative group">
|
||||
Contacto
|
||||
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-blue-600 group-hover:w-full transition-all duration-300"></span>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
{/* CTA Buttons */}
|
||||
<div className="hidden lg:flex items-center gap-4">
|
||||
{/* Search Button */}
|
||||
<button className="w-10 h-10 flex items-center justify-center rounded-lg hover:bg-gray-100 transition-colors">
|
||||
<SearchIcon />
|
||||
</button>
|
||||
|
||||
{/* Login */}
|
||||
<a
|
||||
href="/auth/login"
|
||||
className="px-5 py-2.5 text-gray-700 font-medium hover:text-blue-600 transition-colors"
|
||||
>
|
||||
Iniciar sesión
|
||||
</a>
|
||||
|
||||
{/* Get Started Button */}
|
||||
<a
|
||||
href="/auth/register"
|
||||
className="px-6 py-2.5 bg-gradient-to-r from-blue-600 to-purple-600 text-white font-medium rounded-lg hover:shadow-lg hover:scale-105 transition-all duration-300 flex items-center gap-2"
|
||||
>
|
||||
Empezar Gratis
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<line x1="5" y1="12" x2="19" y2="12"></line>
|
||||
<polyline points="12 5 19 12 12 19"></polyline>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu Button */}
|
||||
<button
|
||||
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
||||
className="lg:hidden p-2 text-gray-700 hover:bg-gray-100 rounded-lg transition-colors"
|
||||
aria-label="Toggle menu"
|
||||
>
|
||||
{isMobileMenuOpen ? <CloseIcon /> : <MenuIcon />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu */}
|
||||
{isMobileMenuOpen && (
|
||||
<div className="lg:hidden bg-white border-t border-gray-200 animate-slideDown">
|
||||
<div className="max-w-[1280px] mx-auto px-5 py-6 space-y-4">
|
||||
<a href="/" className="block py-3 text-gray-700 hover:text-blue-600 font-medium border-b border-gray-100">
|
||||
Inicio
|
||||
</a>
|
||||
|
||||
<div className="border-b border-gray-100">
|
||||
<button
|
||||
onClick={() => handleDropdownToggle('producto-mobile')}
|
||||
className="w-full flex items-center justify-between py-3 text-gray-700 hover:text-blue-600 font-medium"
|
||||
>
|
||||
Producto
|
||||
<ChevronDown />
|
||||
</button>
|
||||
{activeDropdown === 'producto-mobile' && (
|
||||
<div className="pl-4 pb-3 space-y-2">
|
||||
<a href="#" className="block py-2 text-gray-600 hover:text-blue-600">Streaming en Vivo</a>
|
||||
<a href="#" className="block py-2 text-gray-600 hover:text-blue-600">Estudio Virtual</a>
|
||||
<a href="#" className="block py-2 text-gray-600 hover:text-blue-600">Grabación</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="border-b border-gray-100">
|
||||
<button
|
||||
onClick={() => handleDropdownToggle('soluciones-mobile')}
|
||||
className="w-full flex items-center justify-between py-3 text-gray-700 hover:text-blue-600 font-medium"
|
||||
>
|
||||
Soluciones
|
||||
<ChevronDown />
|
||||
</button>
|
||||
{activeDropdown === 'soluciones-mobile' && (
|
||||
<div className="pl-4 pb-3 space-y-2">
|
||||
<a href="#" className="block py-2 text-gray-600 hover:text-blue-600">Educación</a>
|
||||
<a href="#" className="block py-2 text-gray-600 hover:text-blue-600">Empresas</a>
|
||||
<a href="#" className="block py-2 text-gray-600 hover:text-blue-600">Gaming</a>
|
||||
<a href="#" className="block py-2 text-gray-600 hover:text-blue-600">Eventos</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<a href="/pricing" className="block py-3 text-gray-700 hover:text-blue-600 font-medium border-b border-gray-100">
|
||||
Precios
|
||||
</a>
|
||||
<a href="/about" className="block py-3 text-gray-700 hover:text-blue-600 font-medium border-b border-gray-100">
|
||||
Nosotros
|
||||
</a>
|
||||
<a href="/contact" className="block py-3 text-gray-700 hover:text-blue-600 font-medium border-b border-gray-100">
|
||||
Contacto
|
||||
</a>
|
||||
|
||||
<div className="pt-4 space-y-3">
|
||||
<a
|
||||
href="/auth/login"
|
||||
className="block w-full px-6 py-3 text-center text-gray-700 font-medium border-2 border-gray-300 rounded-lg hover:border-blue-600 hover:text-blue-600 transition-colors"
|
||||
>
|
||||
Iniciar sesión
|
||||
</a>
|
||||
<a
|
||||
href="/auth/register"
|
||||
className="block w-full px-6 py-3 text-center bg-gradient-to-r from-blue-600 to-purple-600 text-white font-medium rounded-lg hover:shadow-lg transition-all"
|
||||
>
|
||||
Empezar Gratis
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</header>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NextreamHeader;
|
||||
@ -1,15 +0,0 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
|
||||
interface PageContainerProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
const PageContainer: React.FC<PageContainerProps> = ({ children }) => {
|
||||
return (
|
||||
<div className="max-w-[1280px] mx-auto px-5 overflow-x-hidden">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PageContainer;
|
||||
@ -111,7 +111,7 @@ export default function PricingSection() {
|
||||
: 'bg-gradient-to-r from-purple-600 to-blue-600 text-white hover:from-purple-700 hover:to-blue-700 shadow-md hover:shadow-xl'
|
||||
}`}
|
||||
>
|
||||
{plan.name === 'Free' ? 'Comenzar Gratis' : 'Iniciar Prueba de 14 Días'}
|
||||
{plan.name === 'Free' ? 'Empecemos' : 'Iniciar Prueba de 14 Días'}
|
||||
</button>
|
||||
|
||||
<div className="mt-8 space-y-4">
|
||||
|
||||
@ -1,47 +0,0 @@
|
||||
/**
|
||||
* Scroll to Top Button - Estilo Techwind
|
||||
* Botón flotante que aparece al hacer scroll
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect } from 'react'
|
||||
|
||||
const ScrollToTop: React.FC = () => {
|
||||
const [isVisible, setIsVisible] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const toggleVisibility = () => {
|
||||
if (window.pageYOffset > 300) {
|
||||
setIsVisible(true)
|
||||
} else {
|
||||
setIsVisible(false)
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', toggleVisibility)
|
||||
|
||||
return () => window.removeEventListener('scroll', toggleVisibility)
|
||||
}, [])
|
||||
|
||||
const scrollToTop = () => {
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{isVisible && (
|
||||
<button
|
||||
onClick={scrollToTop}
|
||||
className="fixed bottom-5 end-5 z-50 size-12 inline-flex items-center justify-center tracking-wide align-middle duration-500 text-base text-center bg-indigo-600 hover:bg-indigo-700 border border-indigo-600 hover:border-indigo-700 text-white rounded-full shadow-lg hover:shadow-xl transition-all animate-bounce"
|
||||
aria-label="Volver arriba"
|
||||
>
|
||||
<i className="uil uil-arrow-up text-xl"></i>
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default ScrollToTop
|
||||
@ -72,11 +72,23 @@ const features = [
|
||||
|
||||
export default function StreamingFeatures() {
|
||||
const [activeFeature, setActiveFeature] = useState(1);
|
||||
const [selectedFeature, setSelectedFeature] = useState<typeof features[0] | null>(null);
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
// Inicializar iconos de Feather
|
||||
feather.replace();
|
||||
}, []);
|
||||
}, [isModalOpen]);
|
||||
|
||||
const openModal = (feature: typeof features[0]) => {
|
||||
setSelectedFeature(feature);
|
||||
setIsModalOpen(true);
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
setIsModalOpen(false);
|
||||
setTimeout(() => setSelectedFeature(null), 300);
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="py-20 bg-white dark:bg-slate-900 transition-colors duration-500">
|
||||
@ -94,7 +106,10 @@ export default function StreamingFeatures() {
|
||||
{features.map((feature, index) => (
|
||||
<div key={feature.id} className="lg:col-span-4 md:col-span-6">
|
||||
<Reveal durationMs={600} distance={16} threshold={0.08} delayMs={index * 80}>
|
||||
<div className="flex duration-500 hover:scale-105 shadow dark:shadow-gray-800 hover:shadow-md dark:hover:shadow-gray-700 ease-in-out items-center p-3 rounded-md bg-white dark:bg-slate-900 transition-all">
|
||||
<div
|
||||
onClick={() => openModal(feature)}
|
||||
className="flex duration-500 hover:scale-105 shadow dark:shadow-gray-800 hover:shadow-md dark:hover:shadow-gray-700 ease-in-out items-center p-3 rounded-md bg-white dark:bg-slate-900 transition-all cursor-pointer"
|
||||
>
|
||||
<div className="flex items-center justify-center h-[45px] min-w-[45px] -rotate-45 bg-gradient-to-r from-transparent to-indigo-600/10 text-indigo-600 dark:text-indigo-400 text-center rounded-full me-3 transition-colors duration-500">
|
||||
<i data-feather={feature.icon} className="size-5 rotate-45"></i>
|
||||
</div>
|
||||
@ -120,6 +135,85 @@ export default function StreamingFeatures() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Modal */}
|
||||
{isModalOpen && selectedFeature && (
|
||||
<div
|
||||
className={`fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-sm transition-opacity duration-300 ${isModalOpen ? 'opacity-100' : 'opacity-0'}`}
|
||||
onClick={closeModal}
|
||||
>
|
||||
<div
|
||||
className={`relative bg-white dark:bg-slate-900 rounded-lg shadow-2xl max-w-2xl w-full max-h-[90vh] overflow-y-auto transform transition-all duration-500 mirror-shine ${
|
||||
isModalOpen
|
||||
? 'scale-100 opacity-100 rotate-0'
|
||||
: 'scale-0 opacity-0 rotate-180'
|
||||
}`}
|
||||
style={{
|
||||
transformStyle: 'preserve-3d',
|
||||
animation: isModalOpen ? 'modalFlipIn 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55)' : 'none'
|
||||
}}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{/* Modal Header */}
|
||||
<div className="sticky top-0 bg-gradient-to-r from-indigo-600 to-indigo-700 text-white p-6 rounded-t-lg">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center justify-center h-12 w-12 -rotate-45 bg-white/20 text-white rounded-full">
|
||||
<i data-feather={selectedFeature.icon} className="size-6 rotate-45"></i>
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold">{selectedFeature.title}</h3>
|
||||
</div>
|
||||
<button
|
||||
onClick={closeModal}
|
||||
className="text-white hover:text-gray-200 transition-colors"
|
||||
aria-label="Cerrar modal"
|
||||
>
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Modal Body */}
|
||||
<div className="p-6 space-y-6">
|
||||
<div>
|
||||
<h4 className="text-lg font-semibold text-slate-900 dark:text-white mb-3">
|
||||
Descripción
|
||||
</h4>
|
||||
<p className="text-slate-600 dark:text-slate-400 leading-relaxed">
|
||||
{selectedFeature.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 className="text-lg font-semibold text-slate-900 dark:text-white mb-3">
|
||||
Beneficios Principales
|
||||
</h4>
|
||||
<ul className="space-y-2">
|
||||
{selectedFeature.benefits.map((benefit, idx) => (
|
||||
<li key={idx} className="flex items-center gap-2 text-slate-600 dark:text-slate-400">
|
||||
<svg className="w-5 h-5 text-indigo-600 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
|
||||
</svg>
|
||||
<span>{benefit}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="pt-4 border-t border-slate-200 dark:border-slate-700">
|
||||
<button
|
||||
onClick={closeModal}
|
||||
className="w-full py-3 px-6 bg-indigo-600 hover:bg-indigo-700 text-white font-semibold rounded-md transition-colors duration-300"
|
||||
>
|
||||
Entendido
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ export default function StreamingHeroSection() {
|
||||
<Reveal durationMs={800} distance={16} threshold={0.06}>
|
||||
<div className="mt-6">
|
||||
<a href="/auth/register" className="py-2 px-5 inline-block font-semibold tracking-wide border align-middle duration-500 text-base text-center bg-indigo-600 hover:bg-indigo-700 border-indigo-600 hover:border-indigo-700 text-white rounded-md transition-all">
|
||||
Comenzar Gratis
|
||||
Empecemos
|
||||
</a>
|
||||
<p className="text-slate-400 dark:text-slate-500 text-sm mt-3 transition-colors duration-500">Sin tarjeta de crédito. Prueba gratis por 14 días</p>
|
||||
</div>
|
||||
|
||||
@ -1,164 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
interface Stat {
|
||||
id: number;
|
||||
value: number;
|
||||
suffix: string;
|
||||
label: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
const stats: Stat[] = [
|
||||
{
|
||||
id: 1,
|
||||
value: 50000,
|
||||
suffix: '+',
|
||||
label: 'Transmisiones Activas',
|
||||
description: 'Streams en vivo simultáneos cada mes',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
value: 2500000,
|
||||
suffix: '+',
|
||||
label: 'Horas Transmitidas',
|
||||
description: 'Contenido de calidad profesional',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
value: 98,
|
||||
suffix: '%',
|
||||
label: 'Tasa de Éxito',
|
||||
description: 'Transmisiones sin interrupciones',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
value: 15,
|
||||
suffix: '+',
|
||||
label: 'Plataformas Soportadas',
|
||||
description: 'YouTube, Twitch, Facebook y más',
|
||||
},
|
||||
];
|
||||
|
||||
export default function StreamingStats() {
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
const sectionRef = useRef<HTMLElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const observer = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
if (entry.isIntersecting) {
|
||||
setIsVisible(true);
|
||||
}
|
||||
},
|
||||
{ threshold: 0.1 }
|
||||
);
|
||||
|
||||
if (sectionRef.current) {
|
||||
observer.observe(sectionRef.current);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (sectionRef.current) {
|
||||
observer.unobserve(sectionRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<section
|
||||
ref={sectionRef}
|
||||
className="py-20 bg-gradient-to-br from-purple-900 via-indigo-900 to-blue-900 relative overflow-hidden"
|
||||
>
|
||||
{/* Background Effects */}
|
||||
<div className="absolute inset-0 opacity-20">
|
||||
<div className="absolute top-0 left-0 w-96 h-96 bg-purple-500 rounded-full filter blur-3xl animate-float"></div>
|
||||
<div className="absolute bottom-0 right-0 w-96 h-96 bg-blue-500 rounded-full filter blur-3xl animate-float-delayed"></div>
|
||||
</div>
|
||||
|
||||
<div className="container mx-auto px-4 relative z-10">
|
||||
<div className="text-center mb-16">
|
||||
<span className="inline-flex items-center gap-2 text-purple-300 font-semibold mb-4">
|
||||
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
|
||||
</svg>
|
||||
Estadísticas de la Plataforma
|
||||
</span>
|
||||
<h2 className="text-4xl md:text-5xl font-bold text-white mb-4">
|
||||
Potenciando Creadores de Contenido
|
||||
</h2>
|
||||
<p className="text-xl text-gray-300 max-w-2xl mx-auto">
|
||||
Únete a miles de streamers profesionales que confían en AvanzaCast
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
|
||||
{stats.map((stat, index) => (
|
||||
<StatCard
|
||||
key={stat.id}
|
||||
stat={stat}
|
||||
isVisible={isVisible}
|
||||
delay={index * 0.2}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
interface StatCardProps {
|
||||
stat: Stat;
|
||||
isVisible: boolean;
|
||||
delay: number;
|
||||
}
|
||||
|
||||
function StatCard({ stat, isVisible, delay }: StatCardProps) {
|
||||
const [count, setCount] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (isVisible) {
|
||||
let start = 0;
|
||||
const end = stat.value;
|
||||
const duration = 2000;
|
||||
const increment = end / (duration / 16);
|
||||
|
||||
const timer = setInterval(() => {
|
||||
start += increment;
|
||||
if (start >= end) {
|
||||
setCount(end);
|
||||
clearInterval(timer);
|
||||
} else {
|
||||
setCount(Math.floor(start));
|
||||
}
|
||||
}, 16);
|
||||
|
||||
return () => clearInterval(timer);
|
||||
}
|
||||
}, [isVisible, stat.value]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="bg-white/10 backdrop-blur-lg rounded-2xl p-8 border border-white/20 hover:border-purple-400 transition-all duration-300 hover:transform hover:scale-105 hover:shadow-2xl hover:shadow-purple-500/50"
|
||||
style={{
|
||||
animation: isVisible ? `fadeInUp 0.6s ease-out ${delay}s both` : 'none',
|
||||
}}
|
||||
>
|
||||
<div className="text-center">
|
||||
<h2 className="text-5xl font-bold text-white mb-2">
|
||||
{isVisible && (
|
||||
<>
|
||||
{count.toLocaleString()}
|
||||
<span className="text-purple-400">{stat.suffix}</span>
|
||||
</>
|
||||
)}
|
||||
</h2>
|
||||
<h6 className="text-lg font-semibold text-purple-300 mb-3">
|
||||
{stat.label}
|
||||
</h6>
|
||||
<p className="text-gray-400 text-sm">{stat.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -1,190 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function StudioPreview() {
|
||||
const [activeScene, setActiveScene] = useState('main');
|
||||
|
||||
return (
|
||||
<section className="py-20 bg-gradient-to-br from-gray-900 via-purple-900 to-gray-900 relative overflow-hidden">
|
||||
{/* Animated Background */}
|
||||
<div className="absolute inset-0 opacity-30">
|
||||
<div className="absolute top-1/4 left-1/4 w-64 h-64 bg-purple-500 rounded-full filter blur-3xl animate-pulse"></div>
|
||||
<div className="absolute bottom-1/4 right-1/4 w-80 h-80 bg-blue-500 rounded-full filter blur-3xl animate-pulse" style={{ animationDelay: '1s' }}></div>
|
||||
</div>
|
||||
|
||||
<div className="container mx-auto px-4 relative z-10">
|
||||
<div className="text-center mb-12">
|
||||
<span className="inline-flex items-center gap-2 text-purple-300 font-semibold mb-4">
|
||||
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M2 6a2 2 0 012-2h6a2 2 0 012 2v8a2 2 0 01-2 2H4a2 2 0 01-2-2V6zM14.553 7.106A1 1 0 0014 8v4a1 1 0 00.553.894l2 1A1 1 0 0018 13V7a1 1 0 00-1.447-.894l-2 1z" />
|
||||
</svg>
|
||||
Estudio Virtual Profesional
|
||||
</span>
|
||||
<h2 className="text-4xl md:text-5xl font-bold text-white mb-4">
|
||||
Tu Estudio de Broadcasting Completo
|
||||
</h2>
|
||||
<p className="text-xl text-gray-300 max-w-2xl mx-auto">
|
||||
Control total de tu transmisión desde el navegador, sin software adicional
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Studio Interface Preview */}
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<div className="bg-gray-800/50 backdrop-blur-xl rounded-3xl border border-gray-700 shadow-2xl overflow-hidden">
|
||||
{/* Studio Header */}
|
||||
<div className="bg-gradient-to-r from-gray-800 to-gray-900 px-6 py-4 border-b border-gray-700">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex gap-2">
|
||||
<div className="w-3 h-3 rounded-full bg-red-500"></div>
|
||||
<div className="w-3 h-3 rounded-full bg-yellow-500"></div>
|
||||
<div className="w-3 h-3 rounded-full bg-green-500"></div>
|
||||
</div>
|
||||
<span className="text-white font-semibold">AvanzaCast Studio</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-2 bg-red-500 px-4 py-2 rounded-full animate-pulse">
|
||||
<div className="w-2 h-2 rounded-full bg-white"></div>
|
||||
<span className="text-white text-sm font-bold">EN VIVO</span>
|
||||
</div>
|
||||
<span className="text-gray-400 text-sm">1,234 espectadores</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main Preview Area */}
|
||||
<div className="relative bg-black aspect-video">
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<div className="w-32 h-32 mx-auto mb-4 bg-gradient-to-br from-purple-500 to-blue-500 rounded-full flex items-center justify-center animate-float">
|
||||
<svg className="w-16 h-16 text-white" 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>
|
||||
<p className="text-gray-400 text-lg">Vista previa de tu cámara</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Overlays */}
|
||||
<div className="absolute top-6 left-6 bg-black/80 backdrop-blur-sm px-4 py-2 rounded-lg border border-purple-500">
|
||||
<p className="text-white font-bold">Mi Transmisión Profesional</p>
|
||||
</div>
|
||||
<div className="absolute bottom-6 left-6 bg-black/80 backdrop-blur-sm px-6 py-3 rounded-xl border border-blue-500">
|
||||
<p className="text-blue-400 text-sm mb-1">Nombre del Invitado</p>
|
||||
<p className="text-white font-semibold">CEO, Empresa Tech</p>
|
||||
</div>
|
||||
|
||||
{/* Scene Indicators */}
|
||||
<div className="absolute bottom-6 right-6 flex gap-2">
|
||||
<div className="w-20 h-12 bg-purple-500/30 border-2 border-purple-500 rounded-lg"></div>
|
||||
<div className="w-20 h-12 bg-gray-700/50 border border-gray-600 rounded-lg"></div>
|
||||
<div className="w-20 h-12 bg-gray-700/50 border border-gray-600 rounded-lg"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Controls Panel */}
|
||||
<div className="bg-gradient-to-r from-gray-800 to-gray-900 px-6 py-6 border-t border-gray-700">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
{/* Scene Selector */}
|
||||
<div>
|
||||
<h4 className="text-white font-semibold mb-3 flex items-center gap-2">
|
||||
<svg className="w-5 h-5 text-purple-400" 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>
|
||||
Escenas
|
||||
</h4>
|
||||
<div className="space-y-2">
|
||||
{['Cámara Principal', 'Pantalla Compartida', 'Multi-invitados'].map((scene, i) => (
|
||||
<button
|
||||
key={i}
|
||||
className={`w-full text-left px-3 py-2 rounded-lg transition-all ${
|
||||
i === 0
|
||||
? 'bg-purple-500 text-white'
|
||||
: 'bg-gray-700 text-gray-300 hover:bg-gray-600'
|
||||
}`}
|
||||
>
|
||||
{scene}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Streaming Destinations */}
|
||||
<div>
|
||||
<h4 className="text-white font-semibold mb-3 flex items-center gap-2">
|
||||
<svg className="w-5 h-5 text-blue-400" 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>
|
||||
Destinos Activos
|
||||
</h4>
|
||||
<div className="space-y-2">
|
||||
{[
|
||||
{ name: 'YouTube', status: 'live', viewers: 856 },
|
||||
{ name: 'Twitch', status: 'live', viewers: 234 },
|
||||
{ name: 'Facebook', status: 'live', viewers: 144 },
|
||||
].map((dest, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="flex items-center justify-between bg-gray-700 px-3 py-2 rounded-lg"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-2 h-2 rounded-full bg-green-500 animate-pulse"></div>
|
||||
<span className="text-white text-sm">{dest.name}</span>
|
||||
</div>
|
||||
<span className="text-gray-400 text-xs">{dest.viewers} 👁️</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Quick Actions */}
|
||||
<div>
|
||||
<h4 className="text-white font-semibold mb-3 flex items-center gap-2">
|
||||
<svg className="w-5 h-5 text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
Acciones Rápidas
|
||||
</h4>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
{[
|
||||
{ icon: '🎤', label: 'Audio' },
|
||||
{ icon: '📹', label: 'Video' },
|
||||
{ icon: '🖥️', label: 'Pantalla' },
|
||||
{ icon: '💬', label: 'Chat' },
|
||||
].map((action, i) => (
|
||||
<button
|
||||
key={i}
|
||||
className="bg-gray-700 hover:bg-gray-600 px-3 py-2 rounded-lg transition-all text-white text-sm flex items-center justify-center gap-2"
|
||||
>
|
||||
<span>{action.icon}</span>
|
||||
<span>{action.label}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Feature Badges */}
|
||||
<div className="mt-8 flex flex-wrap justify-center gap-4">
|
||||
{[
|
||||
'✨ Sin software adicional',
|
||||
'🔒 Conexión segura',
|
||||
'⚡ Latencia ultra baja',
|
||||
'📊 Analytics en vivo',
|
||||
].map((badge, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="bg-white/10 backdrop-blur-lg px-4 py-2 rounded-full border border-white/20 text-white text-sm"
|
||||
>
|
||||
{badge}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
import React, {useState} from 'react'
|
||||
import { ComputerDesktopIcon } from '@heroicons/react/24/outline'
|
||||
|
||||
function CreateCard({title, subtitle}:{title:string; subtitle?:string}){
|
||||
return (
|
||||
<button className="create-card rounded-md hover:shadow-sm p-4 text-left">
|
||||
<div className="icon bg-sky-50 text-sky-600 flex items-center justify-center"><ComputerDesktopIcon className="w-6 h-6" /></div>
|
||||
<div className="ml-3">
|
||||
<div className="font-medium">{title}</div>
|
||||
{subtitle && <div className="text-sm text-slate-500">{subtitle}</div>}
|
||||
</div>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
export default function Broadcasts(){
|
||||
const [tab, setTab] = useState<'upcoming'|'previous'>('upcoming')
|
||||
|
||||
return (
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<h1 className="text-2xl font-semibold mb-6">Transmisiones</h1>
|
||||
|
||||
<section className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 mb-8">
|
||||
<CreateCard title="Transmisión en vivo" subtitle="Inicia una transmisión" />
|
||||
<CreateCard title="Grabación" subtitle="Inicia una grabación" />
|
||||
<CreateCard title="Seminario web On-Air" subtitle="Programar evento" />
|
||||
</section>
|
||||
|
||||
<section className="panel p-6">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h2 className="text-lg font-medium">Transmisiones y grabaciones</h2>
|
||||
<div className="flex items-center gap-2">
|
||||
<button className={`tab-btn ${tab==='upcoming'?'active':''}`} onClick={()=>setTab('upcoming')}>Próximamente</button>
|
||||
<button className={`tab-btn ${tab==='previous'?'active':''}`} onClick={()=>setTab('previous')}>Anteriores</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="min-h-[260px] flex items-center justify-center text-slate-500">
|
||||
No tienes próximas transmisiones ni grabaciones
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import ContentSection from '../components/ContentSection'
|
||||
import CTAAndFooter from '../components/CTAAndFooter'
|
||||
import HeroSection from '../components/HeroSection'
|
||||
import FeatureHighlights from '../components/FeatureHighlights'
|
||||
import FeaturesCarousel from '../components/FeaturesCarousel'
|
||||
import TestimonialsSection from '../components/TestimonialsSection'
|
||||
import '../../public/next-assets/css/main.css'
|
||||
|
||||
export default function Landing() {
|
||||
useEffect(() => {
|
||||
const s = document.createElement('script')
|
||||
s.src = '/next-assets/js/main.js'
|
||||
s.async = true
|
||||
document.body.appendChild(s)
|
||||
return () => { document.body.removeChild(s) }
|
||||
}, [])
|
||||
return (
|
||||
<div className="bg-white">
|
||||
<header className="bg-white py-6">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex items-center justify-between">
|
||||
<a href="/" className="text-2xl font-bold">AvanzaCast</a>
|
||||
<div className="space-x-4">
|
||||
<a href="/auth/login" className="text-gray-700">Accede</a>
|
||||
<a href="/auth/register" className="bg-blue-600 text-white px-4 py-2 rounded-lg">Empezamos</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<HeroSection />
|
||||
<FeaturesCarousel />
|
||||
<FeatureHighlights />
|
||||
<ContentSection />
|
||||
<TestimonialsSection />
|
||||
<CTAAndFooter />
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -5,6 +5,7 @@ import { useAuth } from '../hooks/useApi'
|
||||
export default function Login(){
|
||||
const [email, setEmail] = useState('cesar@avanzacast.com')
|
||||
const [password, setPassword] = useState('')
|
||||
const [rememberMe, setRememberMe] = useState(false)
|
||||
const [error, setError] = useState('')
|
||||
const { login, isLoading } = useAuth()
|
||||
const navigate = useNavigate()
|
||||
@ -17,20 +18,126 @@ export default function Login(){
|
||||
else setError(result.error || 'Error al iniciar sesión')
|
||||
}
|
||||
|
||||
const handleGoogleLogin = () => {
|
||||
// TODO: Implementar autenticación con Google OAuth
|
||||
console.log('Google login clicked')
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center p-6 bg-gray-50">
|
||||
<div className="w-full max-w-md">
|
||||
<div className="bg-white rounded-2xl shadow p-8">
|
||||
<h2 className="text-2xl font-bold mb-4">Iniciar sesión</h2>
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
{error && <div className="text-red-600">{error}</div>}
|
||||
<input className="w-full p-3 border rounded" value={email} onChange={e=>setEmail(e.target.value)} placeholder="Email" required />
|
||||
<input className="w-full p-3 border rounded" type="password" value={password} onChange={e=>setPassword(e.target.value)} placeholder="Password" required />
|
||||
<button className="w-full bg-blue-600 text-white p-3 rounded" disabled={isLoading}>{isLoading? 'Cargando...' : 'Entrar'}</button>
|
||||
</form>
|
||||
<p className="mt-4 text-sm">¿No tienes cuenta? <Link to="/auth/register" className="text-blue-600">Regístrate</Link></p>
|
||||
<section className="md:h-screen py-36 flex items-center bg-gradient-to-br from-indigo-600 via-purple-600 to-pink-500 bg-no-repeat bg-center bg-cover">
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-transparent to-black opacity-60"></div>
|
||||
<div className="container relative mx-auto px-4">
|
||||
<div className="flex justify-center">
|
||||
<div className="max-w-[400px] w-full m-auto p-6 bg-white dark:bg-slate-900 shadow-md dark:shadow-gray-800 rounded-md">
|
||||
{/* Logo */}
|
||||
<Link to="/" className="flex items-center justify-center mb-6">
|
||||
<img
|
||||
src="/logo_avanzacast.svg"
|
||||
alt="AvanzaCast"
|
||||
className="w-20 h-20"
|
||||
/>
|
||||
</Link>
|
||||
|
||||
<h5 className="my-6 text-xl font-semibold text-center">Iniciar Sesión</h5>
|
||||
|
||||
{error && (
|
||||
<div className="mb-4 p-3 bg-red-100 dark:bg-red-900/30 border border-red-400 dark:border-red-700 text-red-700 dark:text-red-400 rounded">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<form className="text-start" onSubmit={handleSubmit}>
|
||||
<div className="grid grid-cols-1">
|
||||
<div className="mb-4">
|
||||
<label className="font-semibold" htmlFor="LoginEmail">Email:</label>
|
||||
<input
|
||||
id="LoginEmail"
|
||||
type="email"
|
||||
className="form-input mt-3 w-full py-2 px-3 h-10 bg-transparent dark:bg-slate-900 dark:text-slate-200 rounded outline-none border border-gray-200 focus:border-indigo-600 dark:border-gray-800 dark:focus:border-indigo-600 focus:ring-0"
|
||||
placeholder="nombre@ejemplo.com"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
<label className="font-semibold" htmlFor="LoginPassword">Contraseña:</label>
|
||||
<input
|
||||
id="LoginPassword"
|
||||
type="password"
|
||||
className="form-input mt-3 w-full py-2 px-3 h-10 bg-transparent dark:bg-slate-900 dark:text-slate-200 rounded outline-none border border-gray-200 focus:border-indigo-600 dark:border-gray-800 dark:focus:border-indigo-600 focus:ring-0"
|
||||
placeholder="Contraseña"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between mb-4">
|
||||
<div className="flex items-center mb-0">
|
||||
<input
|
||||
className="form-checkbox rounded border-gray-200 dark:border-gray-800 text-indigo-600 focus:border-indigo-300 focus:ring focus:ring-offset-0 focus:ring-indigo-200 focus:ring-opacity-50 me-2"
|
||||
type="checkbox"
|
||||
id="RememberMe"
|
||||
checked={rememberMe}
|
||||
onChange={(e) => setRememberMe(e.target.checked)}
|
||||
/>
|
||||
<label className="form-checkbox-label text-slate-400" htmlFor="RememberMe">Recordarme</label>
|
||||
</div>
|
||||
<p className="text-slate-400 mb-0">
|
||||
<Link to="/auth/forgot-password" className="text-slate-400 hover:text-indigo-600">¿Olvidaste tu contraseña?</Link>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
<button
|
||||
type="submit"
|
||||
className="py-2 px-5 inline-block tracking-wide border align-middle duration-500 text-base text-center bg-indigo-600 hover:bg-indigo-700 border-indigo-600 hover:border-indigo-700 text-white rounded-md w-full"
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? 'Cargando...' : 'Iniciar Sesión'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Divider */}
|
||||
<div className="relative mb-4">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<div className="w-full border-t border-gray-300 dark:border-gray-700"></div>
|
||||
</div>
|
||||
<div className="relative flex justify-center text-sm">
|
||||
<span className="px-2 bg-white dark:bg-slate-900 text-slate-400">O continúa con</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Google Sign In Button */}
|
||||
<div className="mb-4">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleGoogleLogin}
|
||||
className="py-2 px-5 inline-flex items-center justify-center tracking-wide border align-middle duration-500 text-base text-center bg-white hover:bg-gray-50 border-gray-300 hover:border-gray-400 text-gray-700 rounded-md w-full"
|
||||
>
|
||||
<svg className="w-5 h-5 mr-2" viewBox="0 0 24 24">
|
||||
<path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
|
||||
<path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
|
||||
<path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
|
||||
<path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
|
||||
</svg>
|
||||
Continuar con Google
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="text-center">
|
||||
<span className="text-slate-400 me-2">¿No tienes cuenta?</span>
|
||||
<Link to="/auth/register" className="text-black dark:text-white font-bold inline-block hover:text-indigo-600">
|
||||
Regístrate
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
import React from 'react';
|
||||
import PageContainer from '../components/PageContainer';
|
||||
import NewHeader from '../components/NewHeader';
|
||||
import NewHeroSection from '../components/NewHeroSection';
|
||||
import NewFeaturesGrid from '../components/NewFeaturesGrid';
|
||||
import NewContentDetailsSection from '../components/NewContentDetailsSection';
|
||||
import NewTestimonialsCarousel from '../components/NewTestimonialsCarousel';
|
||||
import NewCallToAction from '../components/NewCallToAction';
|
||||
import NewFooter from '../components/NewFooter';
|
||||
|
||||
const NewLanding: React.FC = () => {
|
||||
return (
|
||||
<div className="min-h-screen bg-white">
|
||||
<NewHeader />
|
||||
<main>
|
||||
<NewHeroSection />
|
||||
<NewFeaturesGrid />
|
||||
<NewContentDetailsSection />
|
||||
<NewTestimonialsCarousel />
|
||||
<NewCallToAction />
|
||||
</main>
|
||||
<NewFooter />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewLanding;
|
||||
@ -1,11 +1,12 @@
|
||||
import React, { useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { useNavigate, Link } from 'react-router-dom'
|
||||
import { useAuth } from '../hooks/useApi'
|
||||
|
||||
export default function Register(){
|
||||
const [name, setName] = useState('')
|
||||
const [email, setEmail] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const [acceptTerms, setAcceptTerms] = useState(false)
|
||||
const [error, setError] = useState('')
|
||||
const { register, isLoading } = useAuth()
|
||||
const navigate = useNavigate()
|
||||
@ -13,25 +14,149 @@ export default function Register(){
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
setError('')
|
||||
|
||||
if (!acceptTerms) {
|
||||
setError('Debes aceptar los términos y condiciones')
|
||||
return
|
||||
}
|
||||
|
||||
const result = await register({ name, email })
|
||||
if (result.success) navigate('/broadcasts')
|
||||
else setError(result.error || 'Error al registrar')
|
||||
}
|
||||
|
||||
const handleGoogleSignup = () => {
|
||||
// TODO: Implementar registro con Google OAuth
|
||||
console.log('Google signup clicked')
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center p-6 bg-gray-50">
|
||||
<div className="w-full max-w-md">
|
||||
<div className="bg-white rounded-2xl shadow p-8">
|
||||
<h2 className="text-2xl font-bold mb-4">Crear cuenta</h2>
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
{error && <div className="text-red-600">{error}</div>}
|
||||
<input className="w-full p-3 border rounded" value={name} onChange={e=>setName(e.target.value)} placeholder="Nombre" required />
|
||||
<input className="w-full p-3 border rounded" value={email} onChange={e=>setEmail(e.target.value)} placeholder="Email" required />
|
||||
<input className="w-full p-3 border rounded" type="password" value={password} onChange={e=>setPassword(e.target.value)} placeholder="Password" required />
|
||||
<button className="w-full bg-blue-600 text-white p-3 rounded" disabled={isLoading}>{isLoading? 'Creando...' : 'Crear cuenta'}</button>
|
||||
</form>
|
||||
<section className="md:h-screen py-36 flex items-center bg-gradient-to-br from-indigo-600 via-purple-600 to-pink-500 bg-no-repeat bg-center bg-cover">
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-transparent to-black opacity-60"></div>
|
||||
<div className="container relative mx-auto px-4">
|
||||
<div className="flex justify-center">
|
||||
<div className="max-w-[400px] w-full m-auto p-6 bg-white dark:bg-slate-900 shadow-md dark:shadow-gray-800 rounded-md">
|
||||
{/* Logo */}
|
||||
<Link to="/" className="flex items-center justify-center mb-6">
|
||||
<img
|
||||
src="/logo_avanzacast.svg"
|
||||
alt="AvanzaCast"
|
||||
className="w-20 h-20"
|
||||
/>
|
||||
</Link>
|
||||
|
||||
<h5 className="my-6 text-xl font-semibold text-center">Crear Cuenta</h5>
|
||||
|
||||
{error && (
|
||||
<div className="mb-4 p-3 bg-red-100 dark:bg-red-900/30 border border-red-400 dark:border-red-700 text-red-700 dark:text-red-400 rounded">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<form className="text-start" onSubmit={handleSubmit}>
|
||||
<div className="grid grid-cols-1">
|
||||
<div className="mb-4">
|
||||
<label className="font-semibold" htmlFor="RegisterName">Nombre completo:</label>
|
||||
<input
|
||||
id="RegisterName"
|
||||
type="text"
|
||||
className="form-input mt-3 w-full py-2 px-3 h-10 bg-transparent dark:bg-slate-900 dark:text-slate-200 rounded outline-none border border-gray-200 focus:border-indigo-600 dark:border-gray-800 dark:focus:border-indigo-600 focus:ring-0"
|
||||
placeholder="Juan Pérez"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
<label className="font-semibold" htmlFor="RegisterEmail">Email:</label>
|
||||
<input
|
||||
id="RegisterEmail"
|
||||
type="email"
|
||||
className="form-input mt-3 w-full py-2 px-3 h-10 bg-transparent dark:bg-slate-900 dark:text-slate-200 rounded outline-none border border-gray-200 focus:border-indigo-600 dark:border-gray-800 dark:focus:border-indigo-600 focus:ring-0"
|
||||
placeholder="nombre@ejemplo.com"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
<label className="font-semibold" htmlFor="RegisterPassword">Contraseña:</label>
|
||||
<input
|
||||
id="RegisterPassword"
|
||||
type="password"
|
||||
className="form-input mt-3 w-full py-2 px-3 h-10 bg-transparent dark:bg-slate-900 dark:text-slate-200 rounded outline-none border border-gray-200 focus:border-indigo-600 dark:border-gray-800 dark:focus:border-indigo-600 focus:ring-0"
|
||||
placeholder="Contraseña"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
<div className="flex items-center w-full mb-0">
|
||||
<input
|
||||
className="form-checkbox rounded border-gray-200 dark:border-gray-800 text-indigo-600 focus:border-indigo-300 focus:ring focus:ring-offset-0 focus:ring-indigo-200 focus:ring-opacity-50 me-2"
|
||||
type="checkbox"
|
||||
id="AcceptTerms"
|
||||
checked={acceptTerms}
|
||||
onChange={(e) => setAcceptTerms(e.target.checked)}
|
||||
/>
|
||||
<label className="form-check-label text-slate-400" htmlFor="AcceptTerms">
|
||||
Acepto los <Link to="/terms" className="text-indigo-600 hover:text-indigo-700">Términos y Condiciones</Link>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
<button
|
||||
type="submit"
|
||||
className="py-2 px-5 inline-block tracking-wide border align-middle duration-500 text-base text-center bg-indigo-600 hover:bg-indigo-700 border-indigo-600 hover:border-indigo-700 text-white rounded-md w-full"
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? 'Creando...' : 'Registrarse'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Divider */}
|
||||
<div className="relative mb-4">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<div className="w-full border-t border-gray-300 dark:border-gray-700"></div>
|
||||
</div>
|
||||
<div className="relative flex justify-center text-sm">
|
||||
<span className="px-2 bg-white dark:bg-slate-900 text-slate-400">O regístrate con</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Google Sign Up Button */}
|
||||
<div className="mb-4">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleGoogleSignup}
|
||||
className="py-2 px-5 inline-flex items-center justify-center tracking-wide border align-middle duration-500 text-base text-center bg-white hover:bg-gray-50 border-gray-300 hover:border-gray-400 text-gray-700 rounded-md w-full"
|
||||
>
|
||||
<svg className="w-5 h-5 mr-2" viewBox="0 0 24 24">
|
||||
<path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
|
||||
<path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
|
||||
<path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
|
||||
<path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
|
||||
</svg>
|
||||
Continuar con Google
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="text-center">
|
||||
<span className="text-slate-400 me-2">¿Ya tienes cuenta?</span>
|
||||
<Link to="/auth/login" className="text-black dark:text-white font-bold inline-block hover:text-indigo-600">
|
||||
Inicia sesión
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@ -28,6 +28,64 @@ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
|
||||
}
|
||||
}
|
||||
|
||||
/* Modal flip animation - espejo */
|
||||
@keyframes modalFlipIn {
|
||||
0% {
|
||||
transform: perspective(1000px) rotateY(90deg) scale(0.5);
|
||||
opacity: 0;
|
||||
}
|
||||
50% {
|
||||
transform: perspective(1000px) rotateY(-10deg) scale(1.05);
|
||||
opacity: 0.8;
|
||||
}
|
||||
100% {
|
||||
transform: perspective(1000px) rotateY(0deg) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes modalFlipOut {
|
||||
0% {
|
||||
transform: perspective(1000px) rotateY(0deg) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: perspective(1000px) rotateY(90deg) scale(0.5);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Efecto de brillo tipo espejo */
|
||||
@keyframes mirrorShine {
|
||||
0% {
|
||||
background-position: -200% center;
|
||||
}
|
||||
100% {
|
||||
background-position: 200% center;
|
||||
}
|
||||
}
|
||||
|
||||
.mirror-shine::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent 0%,
|
||||
rgba(255, 255, 255, 0.1) 45%,
|
||||
rgba(255, 255, 255, 0.3) 50%,
|
||||
rgba(255, 255, 255, 0.1) 55%,
|
||||
transparent 100%
|
||||
);
|
||||
background-size: 200% 100%;
|
||||
animation: mirrorShine 1.5s ease-in-out;
|
||||
pointer-events: none;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
/* Smooth scrollbar hide */
|
||||
.scrollbar-hide {
|
||||
-ms-overflow-style: none;
|
||||
|
||||
BIN
public/assets/images/app/logo_avanzacast.png
Normal file
BIN
public/assets/images/app/logo_avanzacast.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
1641
public/assets/images/app/logo_avanzacast.svg
Normal file
1641
public/assets/images/app/logo_avanzacast.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 231 KiB |
60
public/assets/images/app/logo_avanzacast_2.svg
Normal file
60
public/assets/images/app/logo_avanzacast_2.svg
Normal file
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="500"
|
||||
zoomAndPan="magnify"
|
||||
viewBox="0 0 375 374.999991"
|
||||
height="500"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
version="1.0"
|
||||
id="svg5"
|
||||
sodipodi:docname="logo_avanzacast.svg"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs5" />
|
||||
<sodipodi:namedview
|
||||
id="namedview5"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="1.598"
|
||||
inkscape:cx="249.68711"
|
||||
inkscape:cy="250"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1007"
|
||||
inkscape:window-x="2560"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg5" />
|
||||
<path
|
||||
fill="#5e17eb"
|
||||
d="M 316.738281 152.15625 L 98.78125 21.066406 C 70.617188 2.410156 33.015625 22.601562 33.015625 56.382812 L 33.015625 318.570312 C 33.015625 352.347656 70.617188 372.542969 98.78125 353.886719 L 125.273438 337.957031 C 112.703125 332.902344 103.800781 320.601562 103.800781 306.253906 L 103.800781 177.839844 C 103.800781 159 119.136719 143.679688 137.984375 143.679688 C 144.527344 143.679688 150.921875 145.585938 156.5 149.207031 L 263.285156 213.433594 L 263.527344 213.59375 C 273.09375 219.933594 278.804688 230.570312 278.804688 242.046875 C 278.804688 243.289062 278.726562 244.515625 278.597656 245.738281 L 316.738281 222.796875 C 342.027344 206.042969 342.027344 168.910156 316.738281 152.15625 "
|
||||
fill-opacity="1"
|
||||
fill-rule="nonzero"
|
||||
id="path2" />
|
||||
<path
|
||||
fill="#ffeb99"
|
||||
d="M 153.699219 260.164062 C 142.910156 260.164062 132.890625 251.585938 132.890625 239.378906 L 132.890625 157.699219 C 134.546875 157.277344 136.261719 157.054688 137.996094 157.054688 C 141.832031 157.054688 145.769531 158.140625 149.386719 160.535156 L 237.167969 213.332031 L 165.101562 256.679688 C 161.480469 259.078125 157.542969 260.164062 153.699219 260.164062 "
|
||||
fill-opacity="1"
|
||||
fill-rule="nonzero"
|
||||
id="path3" />
|
||||
<path
|
||||
fill="#ffeb99"
|
||||
d="M 132.890625 144.058594 L 132.890625 144.054688 C 134.507812 143.8125 136.164062 143.683594 137.847656 143.679688 C 136.164062 143.683594 134.507812 143.816406 132.890625 144.058594 M 137.867188 143.679688 C 137.875 143.679688 137.878906 143.679688 137.886719 143.679688 C 137.878906 143.679688 137.875 143.679688 137.867188 143.679688 M 137.917969 143.679688 C 137.925781 143.679688 137.929688 143.679688 137.9375 143.679688 C 137.929688 143.679688 137.925781 143.679688 137.917969 143.679688 "
|
||||
fill-opacity="1"
|
||||
fill-rule="nonzero"
|
||||
id="path4" />
|
||||
<path
|
||||
fill="#8c52ff"
|
||||
d="M 250.144531 205.527344 L 156.5 149.207031 C 150.921875 145.585938 144.527344 143.679688 137.984375 143.679688 C 137.96875 143.679688 137.953125 143.679688 137.9375 143.679688 C 137.929688 143.679688 137.925781 143.679688 137.917969 143.679688 C 137.910156 143.679688 137.898438 143.679688 137.886719 143.679688 C 137.878906 143.679688 137.875 143.679688 137.867188 143.679688 C 137.859375 143.679688 137.855469 143.679688 137.847656 143.679688 C 136.164062 143.683594 134.507812 143.8125 132.890625 144.054688 L 132.890625 110.964844 C 132.890625 98.757812 142.90625 90.179688 153.699219 90.179688 C 157.542969 90.179688 161.480469 91.265625 165.101562 93.664062 L 271.859375 157.871094 C 284.246094 166.078125 284.246094 184.261719 271.859375 192.472656 L 250.144531 205.527344 "
|
||||
fill-opacity="1"
|
||||
fill-rule="nonzero"
|
||||
id="path5" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
@ -33,7 +33,7 @@ export default function LandingPage() {
|
||||
Únete a miles de creadores que ya confían en AvanzaCast para sus streams profesionales
|
||||
</p>
|
||||
<button className="bg-white text-purple-600 hover:bg-gray-100 font-bold py-4 px-12 rounded-full text-lg shadow-xl hover:shadow-2xl transform hover:scale-105 transition-all duration-300">
|
||||
Comenzar Gratis - 14 Días de Prueba
|
||||
Empecemos - 14 Días de Prueba
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user