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) => (
+
+ ))}
+
+
+
+
+
+

{ 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);
+}