diff --git a/packages/landing-page/TECHWIND_MIGRATION.md b/packages/landing-page/TECHWIND_MIGRATION.md new file mode 100644 index 0000000..c55750d --- /dev/null +++ b/packages/landing-page/TECHWIND_MIGRATION.md @@ -0,0 +1,165 @@ +# Migración de Estilos y Comportamientos de Techwind + +## Archivos Creados + +### 1. `src/styles/techwind-animations.css` +Archivo CSS global con animaciones y helpers migrados desde Techwind SCSS. + +**Contenido incluido:** +- **Tipografía**: `::selection`, defaults de `

` y headings +- **Animaciones**: + - `mover`: Animación de flotación vertical (1.5s infinite alternate) + - `animate`: Círculos animados que suben y rotan (para efectos de fondo hero) + - `ppb_kenburns`: Efecto Ken Burns para imágenes (zoom + pan) + - `sk-bounce`: Animación de rebote para spinner/preloader + - `scroll`: Scroll infinito horizontal para sliders de logos +- **Utilidades**: + - `.scrollbar-hide`: Oculta scrollbars nativas + - `.carousel-smooth`: Scroll suave para carruseles + - `.background-effect .circles li`: Círculos animados de fondo + - `.image-wrap`: Wrapper para efecto Ken Burns + - `.spinner`: Spinner de carga con double-bounce +- **Navegación de testimonios**: + - `.tns-nav`: Estilos para dots de paginación + - `.slider .slide-track`: Track de slider infinito + +**Uso:** +```tsx +// Ya importado globalmente en main.tsx +import './styles/techwind-animations.css' +``` + +### 2. `src/components/BackToTop.tsx` +Botón "Volver arriba" que aparece al hacer scroll > 500px. + +**Características:** +- Aparece/desaparece automáticamente según scroll +- Scroll suave al hacer clic +- Diseño responsive con Tailwind +- Icono SVG de flecha arriba + +**Uso:** +```tsx +import BackToTop from '../components/BackToTop' + +function Layout() { + return ( + <> + {/* Tu contenido */} + + + ) +} +``` + +### 3. `src/hooks/useScrollSticky.ts` +Hook para detectar scroll y hacer navbar sticky. + +**Características:** +- Retorna `true` cuando scroll > 50px +- Event listener optimizado con `passive: true` +- Limpieza automática de listeners + +**Uso:** +```tsx +import { useScrollSticky } from '../hooks/useScrollSticky' + +function Navbar() { + const isSticky = useScrollSticky() + + return ( +

+ ) +} +``` + +## Clases CSS Disponibles + +### Animaciones + +#### `.mover` +Flotación vertical suave (usar en iconos, ilustraciones): +```tsx +
+ Floating icon +
+``` + +#### `.background-effect` +Círculos animados de fondo (para hero sections): +```tsx +
+ + {/* Contenido hero */} +
+``` + +#### `.image-wrap` +Efecto Ken Burns en imágenes (zoom + pan lento): +```tsx +
+ Business +
+``` + +### Utilidades + +#### `.scrollbar-hide` +Oculta scrollbars sin afectar funcionalidad: +```tsx +
+ {/* Contenido scrollable */} +
+``` + +#### `.carousel-smooth` +Scroll suave para carruseles (ya usado en TestimonialsSection): +```tsx +
+ {items.map(item => )} +
+``` + +## Estilos SCSS Migrados (Referencia Original) + +Los siguientes archivos de Techwind fueron analizados y migrados: + +1. **`custom/_general.scss`**: Tipografía, selección +2. **`custom/_fonts.scss`**: Imports de Google Fonts (Nunito, etc.) +3. **`custom/pages/_helper.scss`**: Animaciones (mover, kenburns, preloader, cookies) +4. **`custom/pages/_hero.scss`**: Background effects, círculos animados +5. **`custom/plugins/_testi.scss`**: Navegación de testimonios, slider infinito +6. **`custom/plugins/_swiper-slider.scss`**: Swiper pagination +7. **`custom/structure/_topnav.scss`**: Navbar sticky, menú responsive +8. **`assets/js/app.js`**: Back to top, scroll sticky, dark mode toggle + +## Funcionalidades NO Migradas (Manuales) + +Las siguientes funcionalidades del `app.js` de Techwind requieren implementación manual según necesidad: + +- **Toggle Menu**: Menú hamburguesa (implementar según diseño del navbar) +- **Active Menu**: Resaltado de item activo según URL (usar React Router `useLocation`) +- **Dark Mode Toggle**: Switch de modo oscuro (implementar con contexto/estado global) +- **RTL Mode**: Cambio LTR/RTL (agregar si se necesita soporte multiidioma RTL) +- **Contact Form**: Validación de formulario (implementar con React Hook Form o similar) +- **Preloader**: Pantalla de carga inicial (agregar si se desea) + +## Próximos Pasos Recomendados + +1. **Aplicar `.mover` a iconos/ilustraciones** en Features y Hero sections +2. **Agregar círculos animados** de fondo en StreamingHeroSection +3. **Implementar navbar sticky** con `useScrollSticky` en ModernSaasHeader +4. **Aplicar efecto Ken Burns** a imágenes hero si se usan +5. **Verificar paginación de testimonios** con estilos `.tns-nav` si se cambia diseño + +## Notas + +- Los errores de linter en `techwind-animations.css` sobre `@apply` son normales; Vite + Tailwind los procesan correctamente +- El archivo CSS se carga globalmente en `main.tsx`, no requiere importarlo en componentes +- Los componentes BackToTop y useScrollSticky son drop-in replacements listos para usar diff --git a/packages/landing-page/public/images/blog/01.jpg b/packages/landing-page/public/images/blog/01.jpg new file mode 100644 index 0000000..1d442a5 Binary files /dev/null and b/packages/landing-page/public/images/blog/01.jpg differ diff --git a/packages/landing-page/public/images/blog/02.jpg b/packages/landing-page/public/images/blog/02.jpg new file mode 100644 index 0000000..5114b6c Binary files /dev/null and b/packages/landing-page/public/images/blog/02.jpg differ diff --git a/packages/landing-page/public/images/blog/03.jpg b/packages/landing-page/public/images/blog/03.jpg new file mode 100644 index 0000000..0b9ad68 Binary files /dev/null and b/packages/landing-page/public/images/blog/03.jpg differ diff --git a/packages/landing-page/public/images/blog/04.jpg b/packages/landing-page/public/images/blog/04.jpg new file mode 100644 index 0000000..d13dae0 Binary files /dev/null and b/packages/landing-page/public/images/blog/04.jpg differ diff --git a/packages/landing-page/public/images/blog/05.jpg b/packages/landing-page/public/images/blog/05.jpg new file mode 100644 index 0000000..65ba2b0 Binary files /dev/null and b/packages/landing-page/public/images/blog/05.jpg differ diff --git a/packages/landing-page/public/images/blog/06.jpg b/packages/landing-page/public/images/blog/06.jpg new file mode 100644 index 0000000..61af384 Binary files /dev/null and b/packages/landing-page/public/images/blog/06.jpg differ diff --git a/packages/landing-page/public/images/blog/07.jpg b/packages/landing-page/public/images/blog/07.jpg new file mode 100644 index 0000000..e1e4a0a Binary files /dev/null and b/packages/landing-page/public/images/blog/07.jpg differ diff --git a/packages/landing-page/public/images/blog/08.jpg b/packages/landing-page/public/images/blog/08.jpg new file mode 100644 index 0000000..b169e87 Binary files /dev/null and b/packages/landing-page/public/images/blog/08.jpg differ diff --git a/packages/landing-page/public/images/blog/09.jpg b/packages/landing-page/public/images/blog/09.jpg new file mode 100644 index 0000000..9021255 Binary files /dev/null and b/packages/landing-page/public/images/blog/09.jpg differ diff --git a/packages/landing-page/public/images/blog/10.jpg b/packages/landing-page/public/images/blog/10.jpg new file mode 100644 index 0000000..935623b Binary files /dev/null and b/packages/landing-page/public/images/blog/10.jpg differ diff --git a/packages/landing-page/public/images/blog/11.jpg b/packages/landing-page/public/images/blog/11.jpg new file mode 100644 index 0000000..d1161e6 Binary files /dev/null and b/packages/landing-page/public/images/blog/11.jpg differ diff --git a/packages/landing-page/public/images/blog/12.jpg b/packages/landing-page/public/images/blog/12.jpg new file mode 100644 index 0000000..83aa5a3 Binary files /dev/null and b/packages/landing-page/public/images/blog/12.jpg differ diff --git a/packages/landing-page/public/images/blog/13.jpg b/packages/landing-page/public/images/blog/13.jpg new file mode 100644 index 0000000..277e61e Binary files /dev/null and b/packages/landing-page/public/images/blog/13.jpg differ diff --git a/packages/landing-page/public/images/blog/14.jpg b/packages/landing-page/public/images/blog/14.jpg new file mode 100644 index 0000000..b750754 Binary files /dev/null and b/packages/landing-page/public/images/blog/14.jpg differ diff --git a/packages/landing-page/public/images/blog/bg.jpg b/packages/landing-page/public/images/blog/bg.jpg new file mode 100644 index 0000000..9c17035 Binary files /dev/null and b/packages/landing-page/public/images/blog/bg.jpg differ diff --git a/packages/landing-page/public/images/blog/bg1.jpg b/packages/landing-page/public/images/blog/bg1.jpg new file mode 100644 index 0000000..5fafd55 Binary files /dev/null and b/packages/landing-page/public/images/blog/bg1.jpg differ diff --git a/packages/landing-page/public/images/blog/slide02.jpg b/packages/landing-page/public/images/blog/slide02.jpg new file mode 100644 index 0000000..38383a8 Binary files /dev/null and b/packages/landing-page/public/images/blog/slide02.jpg differ diff --git a/packages/landing-page/public/images/clients/01.jpg b/packages/landing-page/public/images/clients/01.jpg new file mode 100644 index 0000000..1ecd810 Binary files /dev/null and b/packages/landing-page/public/images/clients/01.jpg differ diff --git a/packages/landing-page/public/images/clients/02.jpg b/packages/landing-page/public/images/clients/02.jpg new file mode 100644 index 0000000..bf4afcb Binary files /dev/null and b/packages/landing-page/public/images/clients/02.jpg differ diff --git a/packages/landing-page/public/images/clients/03.jpg b/packages/landing-page/public/images/clients/03.jpg new file mode 100644 index 0000000..83c8311 Binary files /dev/null and b/packages/landing-page/public/images/clients/03.jpg differ diff --git a/packages/landing-page/public/images/clients/04.jpg b/packages/landing-page/public/images/clients/04.jpg new file mode 100644 index 0000000..a476e28 Binary files /dev/null and b/packages/landing-page/public/images/clients/04.jpg differ diff --git a/packages/landing-page/public/images/clients/05.jpg b/packages/landing-page/public/images/clients/05.jpg new file mode 100644 index 0000000..f515459 Binary files /dev/null and b/packages/landing-page/public/images/clients/05.jpg differ diff --git a/packages/landing-page/public/images/clients/06.jpg b/packages/landing-page/public/images/clients/06.jpg new file mode 100644 index 0000000..71420c9 Binary files /dev/null and b/packages/landing-page/public/images/clients/06.jpg differ diff --git a/packages/landing-page/public/images/clients/07.jpg b/packages/landing-page/public/images/clients/07.jpg new file mode 100644 index 0000000..7d6fb2d Binary files /dev/null and b/packages/landing-page/public/images/clients/07.jpg differ diff --git a/packages/landing-page/public/images/clients/08.jpg b/packages/landing-page/public/images/clients/08.jpg new file mode 100644 index 0000000..e6692d1 Binary files /dev/null and b/packages/landing-page/public/images/clients/08.jpg differ diff --git a/packages/landing-page/public/images/clients/10.png b/packages/landing-page/public/images/clients/10.png new file mode 100644 index 0000000..dbb2693 Binary files /dev/null and b/packages/landing-page/public/images/clients/10.png differ diff --git a/packages/landing-page/public/images/clients/11.png b/packages/landing-page/public/images/clients/11.png new file mode 100644 index 0000000..7920cd6 Binary files /dev/null and b/packages/landing-page/public/images/clients/11.png differ diff --git a/packages/landing-page/public/images/clients/12.png b/packages/landing-page/public/images/clients/12.png new file mode 100644 index 0000000..0d54d48 Binary files /dev/null and b/packages/landing-page/public/images/clients/12.png differ diff --git a/packages/landing-page/public/images/clients/13.png b/packages/landing-page/public/images/clients/13.png new file mode 100644 index 0000000..63ff869 Binary files /dev/null and b/packages/landing-page/public/images/clients/13.png differ diff --git a/packages/landing-page/public/images/clients/14.png b/packages/landing-page/public/images/clients/14.png new file mode 100644 index 0000000..0e99dc2 Binary files /dev/null and b/packages/landing-page/public/images/clients/14.png differ diff --git a/packages/landing-page/public/images/clients/9.png b/packages/landing-page/public/images/clients/9.png new file mode 100644 index 0000000..c735f43 Binary files /dev/null and b/packages/landing-page/public/images/clients/9.png differ diff --git a/packages/landing-page/public/images/clients/amazon.svg b/packages/landing-page/public/images/clients/amazon.svg new file mode 100644 index 0000000..256f970 --- /dev/null +++ b/packages/landing-page/public/images/clients/amazon.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + diff --git a/packages/landing-page/public/images/clients/android.png b/packages/landing-page/public/images/clients/android.png new file mode 100644 index 0000000..392a37f Binary files /dev/null and b/packages/landing-page/public/images/clients/android.png differ diff --git a/packages/landing-page/public/images/clients/circle-logo.png b/packages/landing-page/public/images/clients/circle-logo.png new file mode 100644 index 0000000..8e55a5c Binary files /dev/null and b/packages/landing-page/public/images/clients/circle-logo.png differ diff --git a/packages/landing-page/public/images/clients/facebook-logo-2019.png b/packages/landing-page/public/images/clients/facebook-logo-2019.png new file mode 100644 index 0000000..903aad0 Binary files /dev/null and b/packages/landing-page/public/images/clients/facebook-logo-2019.png differ diff --git a/packages/landing-page/public/images/clients/facebook.svg b/packages/landing-page/public/images/clients/facebook.svg new file mode 100644 index 0000000..2073d33 --- /dev/null +++ b/packages/landing-page/public/images/clients/facebook.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/packages/landing-page/public/images/clients/google-logo.png b/packages/landing-page/public/images/clients/google-logo.png new file mode 100644 index 0000000..d5eb773 Binary files /dev/null and b/packages/landing-page/public/images/clients/google-logo.png differ diff --git a/packages/landing-page/public/images/clients/google.svg b/packages/landing-page/public/images/clients/google.svg new file mode 100644 index 0000000..eb12171 --- /dev/null +++ b/packages/landing-page/public/images/clients/google.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + diff --git a/packages/landing-page/public/images/clients/lenovo-logo.png b/packages/landing-page/public/images/clients/lenovo-logo.png new file mode 100644 index 0000000..7ed0af4 Binary files /dev/null and b/packages/landing-page/public/images/clients/lenovo-logo.png differ diff --git a/packages/landing-page/public/images/clients/linkedin.png b/packages/landing-page/public/images/clients/linkedin.png new file mode 100644 index 0000000..5772192 Binary files /dev/null and b/packages/landing-page/public/images/clients/linkedin.png differ diff --git a/packages/landing-page/public/images/clients/linkedin.svg b/packages/landing-page/public/images/clients/linkedin.svg new file mode 100644 index 0000000..f97991d --- /dev/null +++ b/packages/landing-page/public/images/clients/linkedin.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/packages/landing-page/public/images/clients/microsoft.svg b/packages/landing-page/public/images/clients/microsoft.svg new file mode 100644 index 0000000..3e8a42f --- /dev/null +++ b/packages/landing-page/public/images/clients/microsoft.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/packages/landing-page/public/images/clients/shree-logo.png b/packages/landing-page/public/images/clients/shree-logo.png new file mode 100644 index 0000000..401eb5d Binary files /dev/null and b/packages/landing-page/public/images/clients/shree-logo.png differ diff --git a/packages/landing-page/public/images/clients/skype.png b/packages/landing-page/public/images/clients/skype.png new file mode 100644 index 0000000..3597af0 Binary files /dev/null and b/packages/landing-page/public/images/clients/skype.png differ diff --git a/packages/landing-page/public/images/clients/snapchat.png b/packages/landing-page/public/images/clients/snapchat.png new file mode 100644 index 0000000..7e7d565 Binary files /dev/null and b/packages/landing-page/public/images/clients/snapchat.png differ diff --git a/packages/landing-page/public/images/clients/spotify.png b/packages/landing-page/public/images/clients/spotify.png new file mode 100644 index 0000000..8f810e7 Binary files /dev/null and b/packages/landing-page/public/images/clients/spotify.png differ diff --git a/packages/landing-page/public/images/clients/telegram.png b/packages/landing-page/public/images/clients/telegram.png new file mode 100644 index 0000000..bb1fdfe Binary files /dev/null and b/packages/landing-page/public/images/clients/telegram.png differ diff --git a/packages/landing-page/public/images/clients/whatsapp.png b/packages/landing-page/public/images/clients/whatsapp.png new file mode 100644 index 0000000..e1f7203 Binary files /dev/null and b/packages/landing-page/public/images/clients/whatsapp.png differ diff --git a/packages/landing-page/public/images/payments/american-ex.png b/packages/landing-page/public/images/payments/american-ex.png new file mode 100644 index 0000000..4a321ce Binary files /dev/null and b/packages/landing-page/public/images/payments/american-ex.png differ diff --git a/packages/landing-page/public/images/payments/discover.png b/packages/landing-page/public/images/payments/discover.png new file mode 100644 index 0000000..6cf08a9 Binary files /dev/null and b/packages/landing-page/public/images/payments/discover.png differ diff --git a/packages/landing-page/public/images/payments/fund.png b/packages/landing-page/public/images/payments/fund.png new file mode 100644 index 0000000..ca5b8ab Binary files /dev/null and b/packages/landing-page/public/images/payments/fund.png differ diff --git a/packages/landing-page/public/images/payments/master-card.png b/packages/landing-page/public/images/payments/master-card.png new file mode 100644 index 0000000..22a1511 Binary files /dev/null and b/packages/landing-page/public/images/payments/master-card.png differ diff --git a/packages/landing-page/public/images/payments/paypal.png b/packages/landing-page/public/images/payments/paypal.png new file mode 100644 index 0000000..06c3629 Binary files /dev/null and b/packages/landing-page/public/images/payments/paypal.png differ diff --git a/packages/landing-page/public/images/payments/visa.png b/packages/landing-page/public/images/payments/visa.png new file mode 100644 index 0000000..07c0ff1 Binary files /dev/null and b/packages/landing-page/public/images/payments/visa.png differ diff --git a/packages/landing-page/public/images/testimonials/01.jpg b/packages/landing-page/public/images/testimonials/01.jpg new file mode 100644 index 0000000..1ecd810 Binary files /dev/null and b/packages/landing-page/public/images/testimonials/01.jpg differ diff --git a/packages/landing-page/public/images/testimonials/02.jpg b/packages/landing-page/public/images/testimonials/02.jpg new file mode 100644 index 0000000..bf4afcb Binary files /dev/null and b/packages/landing-page/public/images/testimonials/02.jpg differ diff --git a/packages/landing-page/public/images/testimonials/03.jpg b/packages/landing-page/public/images/testimonials/03.jpg new file mode 100644 index 0000000..83c8311 Binary files /dev/null and b/packages/landing-page/public/images/testimonials/03.jpg differ diff --git a/packages/landing-page/public/images/testimonials/04.jpg b/packages/landing-page/public/images/testimonials/04.jpg new file mode 100644 index 0000000..a476e28 Binary files /dev/null and b/packages/landing-page/public/images/testimonials/04.jpg differ diff --git a/packages/landing-page/public/images/testimonials/05.jpg b/packages/landing-page/public/images/testimonials/05.jpg new file mode 100644 index 0000000..f515459 Binary files /dev/null and b/packages/landing-page/public/images/testimonials/05.jpg differ diff --git a/packages/landing-page/public/images/testimonials/06.jpg b/packages/landing-page/public/images/testimonials/06.jpg new file mode 100644 index 0000000..71420c9 Binary files /dev/null and b/packages/landing-page/public/images/testimonials/06.jpg differ diff --git a/packages/landing-page/public/images/testimonials/07.jpg b/packages/landing-page/public/images/testimonials/07.jpg new file mode 100644 index 0000000..7d6fb2d Binary files /dev/null and b/packages/landing-page/public/images/testimonials/07.jpg differ diff --git a/packages/landing-page/public/images/testimonials/08.jpg b/packages/landing-page/public/images/testimonials/08.jpg new file mode 100644 index 0000000..e6692d1 Binary files /dev/null and b/packages/landing-page/public/images/testimonials/08.jpg differ diff --git a/packages/landing-page/public/images/testimonials/user1.svg b/packages/landing-page/public/images/testimonials/user1.svg new file mode 100644 index 0000000..191408c --- /dev/null +++ b/packages/landing-page/public/images/testimonials/user1.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/packages/landing-page/public/images/testimonials/user2.svg b/packages/landing-page/public/images/testimonials/user2.svg new file mode 100644 index 0000000..7b913f9 --- /dev/null +++ b/packages/landing-page/public/images/testimonials/user2.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/packages/landing-page/public/images/testimonials/user3.svg b/packages/landing-page/public/images/testimonials/user3.svg new file mode 100644 index 0000000..c59aeed --- /dev/null +++ b/packages/landing-page/public/images/testimonials/user3.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/packages/landing-page/public/images/testimonials/user4.svg b/packages/landing-page/public/images/testimonials/user4.svg new file mode 100644 index 0000000..8309d18 --- /dev/null +++ b/packages/landing-page/public/images/testimonials/user4.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/packages/landing-page/src/components/BackToTop.tsx b/packages/landing-page/src/components/BackToTop.tsx new file mode 100644 index 0000000..4f9e5bb --- /dev/null +++ b/packages/landing-page/src/components/BackToTop.tsx @@ -0,0 +1,51 @@ +import React, { useState, useEffect } from 'react' + +export default function BackToTop() { + const [isVisible, setIsVisible] = useState(false) + + useEffect(() => { + const handleScroll = () => { + if (window.scrollY > 500) { + setIsVisible(true) + } else { + setIsVisible(false) + } + } + + window.addEventListener('scroll', handleScroll, { passive: true }) + return () => window.removeEventListener('scroll', handleScroll) + }, []) + + const scrollToTop = () => { + window.scrollTo({ + top: 0, + behavior: 'smooth' + }) + } + + if (!isVisible) return null + + return ( + + ) +} diff --git a/packages/landing-page/src/components/BlogSection.tsx b/packages/landing-page/src/components/BlogSection.tsx new file mode 100644 index 0000000..5530f2e --- /dev/null +++ b/packages/landing-page/src/components/BlogSection.tsx @@ -0,0 +1,95 @@ +import React from 'react' +import Reveal from './Reveal' + +interface BlogPost { + id: number + title: string + excerpt: string + image: string + link: string +} + +const blogPosts: BlogPost[] = [ + { + id: 1, + title: 'Design your apps in your own way', + excerpt: 'The phrasal sequence of the is now so that many campaign and benefit', + image: '/images/blog/01.jpg', + link: '#' + }, + { + id: 2, + title: 'How apps is changing the IT world', + excerpt: 'The phrasal sequence of the is now so that many campaign and benefit', + image: '/images/blog/02.jpg', + link: '#' + }, + { + id: 3, + title: 'Smartest Applications for Business', + excerpt: 'The phrasal sequence of the is now so that many campaign and benefit', + image: '/images/blog/03.jpg', + link: '#' + } +] + +export default function BlogSection() { + return ( +
+
+ +
+
+
Blogs
+

+ Reads Our Latest
News & Blog +

+
+ +
+

+ Start working with Tailwind CSS that can provide everything you need to generate awareness, drive traffic, connect. +

+
+
+
+ +
+ {blogPosts.map((post, index) => ( + +
+ {post.title} { + e.currentTarget.src = '/images/blog/placeholder.jpg' + }} + className="w-full h-auto" + /> + +
+ + {post.title} + +

{post.excerpt}

+ + +
+
+
+ ))} +
+
+
+ ) +} diff --git a/packages/landing-page/src/components/ModernSaasFooter.tsx b/packages/landing-page/src/components/ModernSaasFooter.tsx index 9c1da10..a103e79 100644 --- a/packages/landing-page/src/components/ModernSaasFooter.tsx +++ b/packages/landing-page/src/components/ModernSaasFooter.tsx @@ -229,27 +229,27 @@ const ModernSaasFooter: React.FC = () => { diff --git a/packages/landing-page/src/components/ModernSaasHeader.tsx b/packages/landing-page/src/components/ModernSaasHeader.tsx index 6bdcf86..e0a11dd 100644 --- a/packages/landing-page/src/components/ModernSaasHeader.tsx +++ b/packages/landing-page/src/components/ModernSaasHeader.tsx @@ -4,9 +4,10 @@ */ import React, { useState, useEffect } from 'react' +import { useScrollSticky } from '../hooks/useScrollSticky' const ModernSaasHeader: React.FC = () => { - const [isScrolled, setIsScrolled] = useState(false) + const isScrolled = useScrollSticky() const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false) const [activeDropdown, setActiveDropdown] = useState(null) const [isDarkMode, setIsDarkMode] = useState(false) @@ -24,12 +25,7 @@ const ModernSaasHeader: React.FC = () => { document.documentElement.classList.remove('dark') } - const handleScroll = () => { - setIsScrolled(window.scrollY > 50) - } - - window.addEventListener('scroll', handleScroll) - return () => window.removeEventListener('scroll', handleScroll) + // Removed scroll listener - now handled by useScrollSticky hook }, []) const toggleTheme = () => { diff --git a/packages/landing-page/src/components/NewTestimonialsCarousel.tsx b/packages/landing-page/src/components/NewTestimonialsCarousel.tsx index c40936f..4b1590b 100644 --- a/packages/landing-page/src/components/NewTestimonialsCarousel.tsx +++ b/packages/landing-page/src/components/NewTestimonialsCarousel.tsx @@ -16,7 +16,7 @@ const testimonials: Testimonial[] = [ name: 'María García', role: 'CEO', company: 'TechStartup', - image: '/images/testimonials/user1.jpg', + 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 }, @@ -25,7 +25,7 @@ const testimonials: Testimonial[] = [ name: 'Carlos Rodríguez', role: 'Content Creator', company: 'YouTube', - image: '/images/testimonials/user2.jpg', + 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 }, @@ -34,7 +34,7 @@ const testimonials: Testimonial[] = [ name: 'Ana Martínez', role: 'Marketing Director', company: 'GlobalCorp', - image: '/images/testimonials/user3.jpg', + 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 }, @@ -43,7 +43,7 @@ const testimonials: Testimonial[] = [ name: 'Juan Pérez', role: 'Podcaster', company: 'El Podcast Diario', - image: '/images/testimonials/user4.jpg', + image: '/images/testimonials/user4.svg', quote: 'La calidad de audio es impresionante. Mis invitados siempre comentan lo profesional que se ve todo.', rating: 5 } diff --git a/packages/landing-page/src/components/StreamingFeatures.tsx b/packages/landing-page/src/components/StreamingFeatures.tsx index 5dbb497..7b55ca6 100644 --- a/packages/landing-page/src/components/StreamingFeatures.tsx +++ b/packages/landing-page/src/components/StreamingFeatures.tsx @@ -1,56 +1,83 @@ 'use client'; -import { useState } from 'react'; +import { useState, useEffect } from 'react'; +import feather from 'feather-icons'; import Reveal from './Reveal' const features = [ { id: 1, - icon: '📡', + icon: 'monitor', title: 'Multistreaming Avanzado', - description: 'Transmite simultáneamente a YouTube, Twitch, Facebook, LinkedIn y más de 15 plataformas con un solo click.', + description: 'Transmite simultáneamente a YouTube, Twitch, Facebook, LinkedIn y más plataformas.', benefits: ['Sin límites de plataformas', 'Configuración automática', 'Calidad HD/4K'], }, { id: 2, - icon: '☁️', - title: 'Grabación en la Nube', - description: 'Todas tus transmisiones se guardan automáticamente en la nube con almacenamiento ilimitado.', - benefits: ['Almacenamiento ilimitado', 'Respaldo automático', 'Descarga instantánea'], + icon: 'heart', + title: 'Estudio Virtual Profesional', + description: 'Estudio completo en la nube con escenas, overlays y transiciones profesionales.', + benefits: ['Escenas personalizadas', 'Transiciones suaves', 'Sin marca de agua'], }, { id: 3, - icon: '👥', - title: 'Invitados Remotos', - description: 'Invita hasta 10 participantes simultáneos con video HD y audio profesional de baja latencia.', - benefits: ['Hasta 10 invitados', 'Baja latencia', 'Sin instalación'], + icon: 'eye', + title: 'Chat Unificado en Vivo', + description: 'Gestiona todos los chats de tus plataformas en un solo lugar con moderación.', + benefits: ['Chat consolidado', 'Moderación IA', 'Respuestas rápidas'], }, { id: 4, - icon: '🎨', - title: 'Branding Personalizado', - description: 'Crea overlays, logos, banners y escenas personalizadas con nuestro editor de arrastrar y soltar.', - benefits: ['Editor visual', 'Plantillas profesionales', 'Sin marca de agua'], + icon: 'layout', + title: 'Invitados Remotos', + description: 'Invita hasta 10 participantes simultáneos con audio y video de alta calidad.', + benefits: ['Hasta 10 invitados', 'Baja latencia', 'Sin instalación'], }, { id: 5, - icon: '💬', - title: 'Chat Unificado', - description: 'Gestiona todos los chats de tus plataformas en un solo lugar con moderación automática.', - benefits: ['Chat unificado', 'Moderación IA', 'Respuestas rápidas'], + icon: 'feather', + title: 'Grabación Automática', + description: 'Todas tus transmisiones se graban automáticamente en la nube con calidad HD.', + benefits: ['Respaldo automático', 'Descarga ilimitada', 'Edición posterior'], }, { id: 6, - icon: '📊', + icon: 'code', + title: 'Branding Personalizado', + description: 'Diseña tu propio branding con logos, overlays y gráficos personalizados.', + benefits: ['Editor drag & drop', 'Plantillas pro', 'Logo permanente'], + }, + { + id: 7, + icon: 'user-check', title: 'Analytics en Tiempo Real', - description: 'Monitorea espectadores, engagement, comentarios y estadísticas detalladas durante el stream.', - benefits: ['Métricas en vivo', 'Reportes detallados', 'Exportación de datos'], + description: 'Monitorea audiencia, engagement y métricas detalladas durante tu stream.', + benefits: ['Métricas en vivo', 'Reportes detallados', 'Exportación datos'], + }, + { + id: 8, + icon: 'globe', + title: 'Compatible con RTMP', + description: 'Transmite desde cualquier software o hardware compatible con RTMP/RTMPS.', + benefits: ['OBS Studio', 'vMix', 'Hardware encoders'], + }, + { + id: 9, + icon: 'settings', + title: 'Scheduling Avanzado', + description: 'Programa tus transmisiones y automatiza anuncios en todas tus plataformas.', + benefits: ['Calendario integrado', 'Auto-notificaciones', 'Multi-plataforma'], }, ]; export default function StreamingFeatures() { const [activeFeature, setActiveFeature] = useState(1); + useEffect(() => { + // Inicializar iconos de Feather + feather.replace(); + }, []); + return (
@@ -69,7 +96,7 @@ export default function StreamingFeatures() {
- {feature.icon} +

diff --git a/packages/landing-page/src/components/StreamingHeroSection.tsx b/packages/landing-page/src/components/StreamingHeroSection.tsx index b950c35..8f72854 100644 --- a/packages/landing-page/src/components/StreamingHeroSection.tsx +++ b/packages/landing-page/src/components/StreamingHeroSection.tsx @@ -13,7 +13,14 @@ export default function StreamingHeroSection() { }; return ( -
+
+ {/* Animated background circles */} +
    + {Array.from({ length: 10 }).map((_, i) => ( +
  • + ))} +
+
{/* Content */} @@ -58,7 +65,7 @@ export default function StreamingHeroSection() { {/* Video Preview */}
-
+
diff --git a/packages/landing-page/src/components/TestimonialsSection.tsx b/packages/landing-page/src/components/TestimonialsSection.tsx index 383b855..5753bad 100644 --- a/packages/landing-page/src/components/TestimonialsSection.tsx +++ b/packages/landing-page/src/components/TestimonialsSection.tsx @@ -1,14 +1,12 @@ import React, { useEffect, useRef, useState } from 'react' import Reveal from './Reveal' -interface Testimonial { text: string; author: string } +interface Testimonial { id: number; text: string; name: string; role?: string; company?: string; image?: string; rating?: number } const testimonials: Testimonial[] = [ - { text: 'Esta probablemente sea la plataforma de transmisión más fácil de usar que conozco...', author: 'Bomeca Trotter' }, - { text: 'Uso AvanzaCast desde hace mucho tiempo y sigo eligiéndolo...', author: 'Krissy Buck' }, - { text: 'Hace dos años que uso este sistema y me encanta!', author: 'Joy Ann Lajeret' }, - { text: 'La integración con múltiples plataformas es perfecta...', author: 'Carlos Mendoza' }, - { text: 'Como creadora de contenido, necesitaba una herramienta confiable...', author: 'María González' } + { id: 1, name: 'Calvin Carlo', role: 'Manager', company: '', image: '/images/clients/01.jpg', rating: 5, text: 'It seems that only fragments of the original text remain in the Lorem Ipsum texts used today.' }, + { id: 2, name: 'Christa Smith', role: 'Manager', company: '', image: '/images/clients/02.jpg', rating: 5, text: "The most well-known dummy text is the 'Lorem Ipsum', which is said to have originated in the 16th century." }, + { id: 3, name: 'Jemina C LOne', role: 'Manager', company: '', image: '/images/clients/03.jpg', rating: 5, text: 'One disadvantage of Lorum Ipsum is that in Latin certain letters appear more frequently than others.' }, ] export default function TestimonialsSection() { @@ -16,16 +14,68 @@ export default function TestimonialsSection() { const [isAutoPlay, setIsAutoPlay] = useState(true) const multiplier = 12 const duplicatedTestimonials = Array.from({ length: multiplier }, () => testimonials).flat() + const [activeIndex, setActiveIndex] = useState(0) + const itemWidthRef = useRef(400) - const scrollLeft = () => { if (scrollRef.current) scrollRef.current.scrollBy({ left: -400, behavior: 'smooth' }) } - const scrollRight = () => { if (scrollRef.current) scrollRef.current.scrollBy({ left: 400, behavior: 'smooth' }) } + const scrollLeft = () => { if (scrollRef.current) scrollRef.current.scrollBy({ left: -itemWidthRef.current, behavior: 'smooth' }) } + const scrollRight = () => { if (scrollRef.current) scrollRef.current.scrollBy({ left: itemWidthRef.current, behavior: 'smooth' }) } + + // Scroll to a canonical item index (0..testimonials.length-1) within the middle set + const goToIndex = (itemIndex: number) => { + if (!scrollRef.current) return + const container = scrollRef.current + const itemW = itemWidthRef.current || 400 + const singleSetWidth = testimonials.length * itemW + const middleStart = singleSetWidth * Math.floor(multiplier / 2) + const target = middleStart + itemIndex * itemW + container.scrollTo({ left: target, behavior: 'smooth' }) + } useEffect(() => { if (scrollRef.current) { - const singleSetWidth = testimonials.length * 400 + // measure item width from DOM (first testimonial-item) + const container = scrollRef.current + const firstItem = container.querySelector('.testimonial-item') as HTMLElement | null + const ww = firstItem ? firstItem.clientWidth : 400 + itemWidthRef.current = ww + const singleSetWidth = testimonials.length * ww const middleStart = singleSetWidth * Math.floor(multiplier / 2) - scrollRef.current.scrollLeft = middleStart + + // Calculate visible items based on viewport + const containerWidth = container.clientWidth + let visibleItems = 3 // desktop default + if (containerWidth < 768) visibleItems = 1 // mobile + else if (containerWidth < 1024) visibleItems = 2 // tablet + + // Center the carousel by adding padding to show exact number of items + const totalVisibleWidth = ww * visibleItems + const sidePadding = Math.max(0, (containerWidth - totalVisibleWidth) / 2) + container.style.paddingLeft = `${sidePadding}px` + container.style.paddingRight = `${sidePadding}px` + + container.scrollLeft = middleStart } + // re-measure on resize + const onResize = () => { + if (!scrollRef.current) return + const container = scrollRef.current + const firstItem = container.querySelector('.testimonial-item') as HTMLElement | null + if (!firstItem) return + const ww = firstItem.clientWidth + itemWidthRef.current = ww + + const containerWidth = container.clientWidth + let visibleItems = 3 + if (containerWidth < 768) visibleItems = 1 + else if (containerWidth < 1024) visibleItems = 2 + + const totalVisibleWidth = ww * visibleItems + const sidePadding = Math.max(0, (containerWidth - totalVisibleWidth) / 2) + container.style.paddingLeft = `${sidePadding}px` + container.style.paddingRight = `${sidePadding}px` + } + window.addEventListener('resize', onResize) + return () => window.removeEventListener('resize', onResize) }, []) useEffect(() => { @@ -39,13 +89,18 @@ export default function TestimonialsSection() { const container = scrollRef.current const handleScroll = () => { if (!container) return - const singleSetWidth = testimonials.length * 400 + const itemW = itemWidthRef.current || 400 + const singleSetWidth = testimonials.length * itemW const totalWidth = singleSetWidth * multiplier const middleStart = singleSetWidth * Math.floor(multiplier / 2) - const tolerance = 100 + const tolerance = Math.max(50, itemW / 4) requestAnimationFrame(() => { if (container.scrollLeft <= tolerance) container.scrollLeft = middleStart else if (container.scrollLeft >= totalWidth - container.clientWidth - tolerance) container.scrollLeft = middleStart + // compute visible index relative to middle set + const relative = Math.round((container.scrollLeft - middleStart) / itemW) + const idx = ((relative % testimonials.length) + testimonials.length) % testimonials.length + setActiveIndex(idx) }) } @@ -57,32 +112,60 @@ export default function TestimonialsSection() { }, []) return ( -
+
-

+

Ya se crearon más de 60 millones de transmisiones y grabaciones en AvanzaCast -

+

+ +

Start working with Tailwind CSS that can provide everything you need to generate awareness, drive traffic, connect.

- + {/* Navigation arrows at extremes */} + {/* Arrows removed — navigation via pagination dots only */} - - -
setIsAutoPlay(false)} onMouseLeave={() => setIsAutoPlay(true)}> - {duplicatedTestimonials.map((testimonial, index) => { +
setIsAutoPlay(false)} onMouseLeave={() => setIsAutoPlay(true)}> + {duplicatedTestimonials.map((testimonial, index) => { const setNumber = Math.floor(index / testimonials.length) const itemIndex = index % testimonials.length + const base = testimonials[itemIndex] return ( -
+
-
-

“{testimonial.text}”

-

{testimonial.author}

-
+
+
+
+ + + + +
+ +

“{base.text}”

+ +
+ {Array.from({ length: base.rating || 5 }).map((_, i) => ( + + ))} +
+
+ +
+
+ {base.name}{ e.currentTarget.src = '/images/testimonials/user1.svg' }} className="mx-auto rounded-full w-20 h-20 sm:w-22 sm:h-22 md:w-24 md:h-24 object-cover shadow-2xl ring-4 ring-white" /> +
+
+

{base.name}

+

{base.role}

+
+
+ {/* small pointer triangle */} +
+ + + +
+
) @@ -90,20 +173,18 @@ export default function TestimonialsSection() {
-
- +
+
+ {testimonials.map((t, idx) => ( +
diff --git a/packages/landing-page/src/hooks/useScrollSticky.ts b/packages/landing-page/src/hooks/useScrollSticky.ts new file mode 100644 index 0000000..bfc9fa8 --- /dev/null +++ b/packages/landing-page/src/hooks/useScrollSticky.ts @@ -0,0 +1,23 @@ +import { useEffect, useState } from 'react' + +/** + * Hook para navbar sticky - migrado de Techwind + * Agrega clase 'nav-sticky' al navbar cuando el scroll > 50px + */ +export function useScrollSticky() { + const [isSticky, setIsSticky] = useState(false) + + useEffect(() => { + const handleScroll = () => { + const scrollTop = window.scrollY || document.documentElement.scrollTop + setIsSticky(scrollTop >= 50) + } + + window.addEventListener('scroll', handleScroll, { passive: true }) + handleScroll() // Check initial state + + return () => window.removeEventListener('scroll', handleScroll) + }, []) + + return isSticky +} diff --git a/packages/landing-page/src/main.tsx b/packages/landing-page/src/main.tsx index 0ddb0cb..bf9eef6 100644 --- a/packages/landing-page/src/main.tsx +++ b/packages/landing-page/src/main.tsx @@ -2,6 +2,7 @@ import React from 'react' import { createRoot } from 'react-dom/client' import App from './App' import './index.css' +import './styles/techwind-animations.css' createRoot(document.getElementById('root')!).render( diff --git a/packages/landing-page/src/pages/NextreamLanding.tsx b/packages/landing-page/src/pages/NextreamLanding.tsx index a13c906..f309afa 100644 --- a/packages/landing-page/src/pages/NextreamLanding.tsx +++ b/packages/landing-page/src/pages/NextreamLanding.tsx @@ -12,8 +12,9 @@ import StreamingFeatures from '../components/StreamingFeatures' import PlatformLogos from '../components/PlatformLogos' import TestimonialsSection from '../components/TestimonialsSection' import PricingSection from '../components/PricingSection' +import BlogSection from '../components/BlogSection' import ModernSaasFooter from '../components/ModernSaasFooter' -import ScrollToTop from '../components/ScrollToTop' +import BackToTop from '../components/BackToTop' const NextreamLanding: React.FC = () => { useEffect(() => { @@ -41,11 +42,14 @@ const NextreamLanding: React.FC = () => { {/* Pricing Section */} + {/* Blog Section */} + + {/* Modern SaaS Footer */} - {/* Scroll to Top Button */} - + {/* Back to Top Button - Migrated from Techwind */} + ) } diff --git a/packages/landing-page/src/styles/techwind-animations.css b/packages/landing-page/src/styles/techwind-animations.css new file mode 100644 index 0000000..9bba03a --- /dev/null +++ b/packages/landing-page/src/styles/techwind-animations.css @@ -0,0 +1,199 @@ +/* Techwind Migrated Styles - Animations & Helpers */ + +/* Selection */ +::selection { + @apply bg-indigo-600/90 text-white; +} + +/* Typography defaults */ +p { + @apply leading-relaxed; +} + +h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { + @apply leading-normal; +} + +/* Mover animation */ +.mover { + animation: mover 1.5s infinite alternate; +} + +@keyframes mover { + 0% { + transform: translateY(0); + } + 100% { + transform: translateY(10px); + } +} + +/* Smooth scrollbar hide */ +.scrollbar-hide { + -ms-overflow-style: none; + scrollbar-width: none; +} + +.scrollbar-hide::-webkit-scrollbar { + display: none; +} + +/* Carousel smooth scroll */ +.carousel-smooth { + scroll-behavior: smooth; + -webkit-overflow-scrolling: touch; +} + +/* Background animated circles (hero effects) */ +@keyframes animate { + 0% { + transform: translateY(0) rotate(0deg); + opacity: 1; + border-radius: 10px; + } + 100% { + transform: translateY(-1000px) rotate(720deg); + opacity: 0; + } +} + +.background-effect .circles li { + @apply absolute block -bottom-[150px] bg-indigo-600/30; + animation: animate 25s linear infinite; +} + +.background-effect .circles li:nth-child(1) { + @apply size-12 start-1/4; + animation-delay: 0s; +} + +.background-effect .circles li:nth-child(2) { + @apply size-12 start-[10%]; + animation-delay: 2s; + animation-duration: 12s; +} + +.background-effect .circles li:nth-child(3) { + @apply size-12 start-[70%]; + animation-delay: 4s; +} + +.background-effect .circles li:nth-child(4) { + @apply size-12 start-[40%]; + animation-delay: 0s; + animation-duration: 18s; +} + +.background-effect .circles li:nth-child(5) { + @apply size-12 start-[65%]; + animation-delay: 0s; +} + +.background-effect .circles li:nth-child(6) { + @apply size-12 start-3/4; + animation-delay: 3s; +} + +.background-effect .circles li:nth-child(7) { + @apply size-12 start-[35%]; + animation-delay: 7s; +} + +.background-effect .circles li:nth-child(8) { + @apply size-12 start-1/2; + animation-delay: 15s; + animation-duration: 45s; +} + +.background-effect .circles li:nth-child(9) { + @apply size-12 start-[20%]; + animation-delay: 2s; + animation-duration: 35s; +} + +.background-effect .circles li:nth-child(10) { + @apply size-12 start-[85%]; + animation-delay: 0s; + animation-duration: 11s; +} + +/* Kenburn effect for images */ +.image-wrap { + animation: 100s ppb_kenburns linear infinite alternate; +} + +@keyframes ppb_kenburns { + 0% { + transform: scale(1.3) translate(-10%, 10%); + } + 25% { + transform: scale(1) translate(0, 0); + } + 50% { + transform: scale(1.3) translate(10%, 10%); + } + 75% { + transform: scale(1) translate(0, 0); + } + 100% { + transform: scale(1.3) translate(-10%, 10%); + } +} + +/* Preloader spinner */ +@keyframes sk-bounce { + 0%, 100% { + transform: scale(0.0); + } + 50% { + transform: scale(1.0); + } +} + +.spinner .double-bounce1, +.spinner .double-bounce2 { + @apply w-full h-full rounded-full bg-indigo-600/60 absolute top-0 start-0; + animation: sk-bounce 2.0s infinite ease-in-out; +} + +.spinner .double-bounce2 { + animation-delay: -1.0s; +} + +/* Dark mode toggle switch */ +.label .ball { + transition: transform 0.2s linear; + @apply translate-x-0; +} + +.checkbox:checked + .label .ball { + @apply translate-x-6; +} + +/* Testimonial navigation dots (pagination) */ +.tns-nav { + @apply text-center mt-3; +} + +.tns-nav button { + @apply rounded-[3px] bg-indigo-600/30 duration-500 border-0 m-1 p-[5px]; +} + +.tns-nav button.tns-nav-active { + @apply bg-indigo-600 rotate-[45deg]; +} + +/* Smooth infinite scroll slider */ +@keyframes scroll { + 0% { + transform: translateX(0); + } + 100% { + transform: translateX(calc(-360px * 6)); + } +} + +.slider .slide-track { + animation: scroll 120s linear infinite; + width: calc(360px * 20); +}