Segundo vistaso

This commit is contained in:
unknown
2026-05-26 23:08:21 -04:00
parent bd93fb3bf2
commit 3d063113d1
16 changed files with 1158 additions and 2087 deletions

View File

@@ -1,7 +1,6 @@
'use client';
import { useEffect, useRef } from 'react';
import styles from './Hero.module.css';
const stats = [
{ value: '10K+', label: 'Equipos activos' },
@@ -18,14 +17,15 @@ export default function Hero() {
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add(styles.visible);
entry.target.classList.add('opacity-100', 'translate-y-0');
entry.target.classList.remove('opacity-0', 'translate-y-6');
}
});
},
{ threshold: 0.1 }
);
const elements = heroRef.current?.querySelectorAll(`.${styles.reveal}`);
const elements = heroRef.current?.querySelectorAll('.reveal');
elements?.forEach((el) => observer.observe(el));
return () => observer.disconnect();
@@ -40,10 +40,15 @@ export default function Hero() {
};
return (
<section className={styles.hero} id="hero" ref={heroRef} aria-label="Sección principal">
<div className={`container ${styles.inner}`}>
<section
className="pt-[72px] bg-white overflow-hidden"
id="hero"
ref={heroRef}
aria-label="Sección principal"
>
<div className="container flex flex-col items-center text-center pt-20 pb-16 gap-6">
{/* Badge */}
<div className={`${styles.reveal} ${styles.badgeWrap}`}>
<div className="reveal opacity-0 translate-y-6 transition-all duration-700 ease-out delay-100 mb-2">
<span className="badge badge-dark">
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" aria-hidden="true">
<circle cx="4" cy="4" r="4" fill="#00c853" />
@@ -53,34 +58,40 @@ export default function Hero() {
</div>
{/* Heading */}
<h1 className={`${styles.reveal} ${styles.heading}`}>
<h1 className="reveal opacity-0 translate-y-6 transition-all duration-700 ease-out delay-200 text-[clamp(2.5rem,7vw,5rem)] font-black tracking-[-0.04em] leading-[1.05] text-black max-w-[800px]">
El flujo de trabajo
<br />
<em className={styles.emphasis}>que tu equipo</em>
<em className="italic font-black">que tu equipo</em>
<br />
siempre necesitó
</h1>
{/* Subheading */}
<p className={`${styles.reveal} ${styles.subheading}`}>
<p className="reveal opacity-0 translate-y-6 transition-all duration-700 ease-out delay-300 text-[clamp(1rem,2vw,1.25rem)] text-gray-600 max-w-[520px] leading-relaxed mt-2">
FlowSync conecta a tu equipo, automatiza tareas repetitivas y te da
visibilidad total de cada proyecto todo en un solo lugar.
</p>
{/* CTA Buttons */}
<div className={`${styles.reveal} ${styles.ctas}`}>
<div className="reveal opacity-0 translate-y-6 transition-all duration-700 ease-out delay-400 flex flex-wrap justify-center gap-3 mt-2 max-sm:flex-col max-sm:w-full max-sm:max-w-[320px]">
<button
className="btn btn-primary btn-lg"
className="btn btn-primary btn-lg max-sm:w-full"
id="hero-cta-primary"
onClick={handleScrollToContact}
>
Empieza gratis
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<path d="M3 8h10M9 4l4 4-4 4" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<path
d="M3 8h10M9 4l4 4-4 4"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</button>
<button
className="btn btn-secondary btn-lg"
className="btn btn-secondary btn-lg max-sm:w-full"
id="hero-cta-secondary"
onClick={handleScrollToFeatures}
>
@@ -89,71 +100,92 @@ export default function Hero() {
</div>
{/* Trust note */}
<p className={`${styles.reveal} ${styles.trustNote}`}>
<p className="reveal opacity-0 translate-y-6 transition-all duration-700 ease-out delay-500 text-sm text-gray-400 mt-1">
Sin tarjeta de crédito &nbsp;·&nbsp; 14 días gratis &nbsp;·&nbsp; Cancela cuando quieras
</p>
{/* Dashboard mockup */}
<div className={`${styles.reveal} ${styles.mockupWrap}`}>
<div className={styles.mockup} role="img" aria-label="Vista previa del dashboard de FlowSync">
<div className="reveal opacity-0 translate-y-6 transition-all duration-700 ease-out delay-600 w-full max-w-[900px] mt-8 [perspective:1200px]">
<div
className="bg-white border border-gray-200 rounded-2xl shadow-xl overflow-hidden transform rotate-x-4 transition-transform duration-400 ease-out hover:rotate-x-0"
role="img"
aria-label="Vista previa del dashboard de FlowSync"
style={{ transform: 'rotateX(4deg)' }}
>
{/* Window chrome */}
<div className={styles.mockupBar}>
<span className={styles.dot} style={{ background: '#ff5f57' }} />
<span className={styles.dot} style={{ background: '#febc2e' }} />
<span className={styles.dot} style={{ background: '#28c840' }} />
<span className={styles.mockupUrl}>app.flowsync.io/dashboard</span>
<div className="flex items-center gap-2 px-4 py-3 bg-gray-50 border-b border-gray-200">
<span className="w-3 h-3 rounded-full shrink-0 bg-[#ff5f57]" />
<span className="w-3 h-3 rounded-full shrink-0 bg-[#febc2e]" />
<span className="w-3 h-3 rounded-full shrink-0 bg-[#28c840]" />
<span className="flex-1 text-center text-xs text-gray-400 bg-white border border-gray-200 rounded-full py-[2px] px-3 max-w-[280px] mx-auto">
app.flowsync.io/dashboard
</span>
</div>
{/* Mock dashboard content */}
<div className={styles.mockupBody}>
<div className="flex h-[380px] max-md:h-[260px]">
{/* Sidebar */}
<nav className={styles.mockupSidebar} aria-hidden="true">
<div className={styles.sidebarLogo} />
<nav className="w-14 bg-gray-50 border-r border-gray-200 px-3 py-4 flex flex-col gap-3 shrink-0 max-md:hidden" aria-hidden="true">
<div className="w-8 h-8 bg-black rounded-md mb-4" />
{[...Array(5)].map((_, i) => (
<div key={i} className={`${styles.sidebarItem} ${i === 0 ? styles.sidebarActive : ''}`} />
<div
key={i}
className={`w-8 h-8 rounded-md ${
i === 0 ? 'bg-black' : 'bg-gray-200'
}`}
/>
))}
</nav>
{/* Main content */}
<main className={styles.mockupMain} aria-hidden="true">
<main className="flex-1 p-6 flex flex-col gap-4 overflow-hidden" aria-hidden="true">
{/* Header row */}
<div className={styles.mockupHeader}>
<div className={styles.mockupTitle} />
<div className={styles.mockupBtn} />
<div className="flex justify-between items-center">
<div className="h-5 w-40 bg-gray-200 rounded-sm" />
<div className="h-8 w-24 bg-black rounded-md" />
</div>
{/* Metric cards */}
<div className={styles.metricsRow}>
<div className="grid grid-cols-4 max-md:grid-cols-2 gap-3">
{['#0066ff', '#00c853', '#ff9500', '#6c5ce7'].map((color, i) => (
<div key={i} className={styles.metricCard}>
<div className={styles.metricIcon} style={{ background: `${color}18`, color }} />
<div className={styles.metricLines}>
<div className={styles.metricValue} />
<div className={styles.metricLabel} />
<div key={i} className="bg-gray-50 border border-gray-200 rounded-xl p-3 flex gap-2 items-center">
<div
className="w-8 h-8 rounded-md shrink-0"
style={{ background: `${color}18`, color }}
/>
<div className="flex flex-col gap-[6px] flex-1">
<div className="h-[14px] bg-gray-300 rounded-sm w-[70%]" />
<div className="h-[10px] bg-gray-200 rounded-sm w-[90%]" />
</div>
</div>
))}
</div>
{/* Chart area */}
<div className={styles.chartArea}>
<div className={styles.chartBars}>
<div className="flex-1 bg-gray-50 border border-gray-200 rounded-xl p-4 overflow-hidden">
<div className="flex items-end gap-2 h-100">
{[60, 80, 50, 90, 70, 85, 65, 95, 75, 88].map((h, i) => (
<div
key={i}
className={styles.bar}
style={{ height: `${h}%`, animationDelay: `${i * 0.05}s` }}
className={`flex-1 rounded-t-sm animate-fadeIn opacity-100 ${
i === 3 || i === 7 ? 'bg-black opacity-90' : 'bg-black opacity-10'
}`}
style={{
height: `${h}%`,
animationDelay: `${i * 0.05}s`,
opacity: i === 3 || i === 7 ? 0.9 : (i % 2 === 0 ? 0.12 : 0.08)
}}
/>
))}
</div>
</div>
{/* Task list */}
<div className={styles.taskList}>
<div className="flex flex-col gap-2">
{[85, 60, 95, 70].map((w, i) => (
<div key={i} className={styles.taskRow}>
<div className={styles.taskCheck} />
<div className={styles.taskLine} style={{ width: `${w}%` }} />
<div key={i} className="flex items-center gap-3">
<div className="w-4 h-4 border-2 border-gray-300 rounded-sm shrink-0" />
<div className="h-[10px] bg-gray-200 rounded-sm" style={{ width: `${w}%` }} />
</div>
))}
</div>
@@ -163,11 +195,15 @@ export default function Hero() {
</div>
{/* Stats */}
<div className={`${styles.reveal} ${styles.stats}`}>
<div className="reveal opacity-0 translate-y-6 transition-all duration-700 ease-out delay-700 flex flex-wrap justify-center gap-12 max-md:gap-8 mt-8">
{stats.map((stat) => (
<div key={stat.label} className={styles.statItem}>
<span className={styles.statValue}>{stat.value}</span>
<span className={styles.statLabel}>{stat.label}</span>
<div key={stat.label} className="flex flex-col items-center gap-1">
<span className="text-3xl font-black tracking-[-0.04em] text-black">
{stat.value}
</span>
<span className="text-sm text-gray-500">
{stat.label}
</span>
</div>
))}
</div>