Files
hostingdelsur.net/src/components/ProcessSteps.astro
T
Mauricio López Coria 9aeaeafa3f feat: Awwwards transformation Phases 1-6
Phase 1 — Design System:
- Glassmorphism tokens (--glass-bg, --glass-border, --blur-glass)
- Gradient tokens (--hds-gradient-hero, --hds-gradient-section)
- Motion tokens (--ease-spring, --ease-out-expo)
- .glass-card component class with hover uplift + mouse-tracking glow
- .noise-overlay: SVG feTurbulence texture at 0.025 opacity
- Buttons with spring easing, prefers-reduced-motion support

Phase 2 — Preloader + Hero:
- Preloader.astro: vanilla JS logo fade-in + loading bar + slide-up
- Uses sessionStorage to skip on repeat visits
- Hero.astro: full-bleed 100dvh, GSAP timeline, glass ring decoration
- Parallax floating SVG shapes (sine yoyo animation)
- i18n: hero.scrollDown key

Phase 3 — 'Por qué elegirnos' Bento Grid:
- DifferenceCards.astro: asymmetric 3-column bento grid
- Glass cards with mouse-tracking glow (--mouse-x/--mouse-y)
- GSAP ScrollTrigger stagger reveal (opacity 0→1, y: 40→0)

Phase 4 — Pricing + Process:
- planes.astro: 5 visible + 4 in details accordion
- Empresarial as hero card, price annual only (no toggle)
- ProcessSteps.astro: timeline + ScrollTrigger progress bar

Phase 5 — Global Polish:
- LenisScroll.astro: smooth scroll (duration 1.2, cubic easing)
- GSAP ticker sync, noise overlay in BaseLayout

Phase 6 — Deploy:
- deploy.sh: auto-detects repo path, auto-builds if stale
- Relative paths instead of hardcoded /root/opencode/development
2026-07-01 23:16:36 -03:00

153 lines
4.6 KiB
Plaintext

---
// "Cómo trabajamos" — Timeline with GSAP ScrollTrigger progress bar
// Phase 4 — Organic Fluidity Premium
import SectionEyebrow from './SectionEyebrow.astro';
import type { TranslationKey } from '@/i18n/ui';
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
gsap.registerPlugin(ScrollTrigger);
interface Props {
t: (key: TranslationKey) => string;
}
const { t } = Astro.props;
const steps = [
{ num: '01', titleKey: 'process.step1.title' as TranslationKey, bodyKey: 'process.step1.body' as TranslationKey },
{ num: '02', titleKey: 'process.step2.title' as TranslationKey, bodyKey: 'process.step2.body' as TranslationKey },
{ num: '03', titleKey: 'process.step3.title' as TranslationKey, bodyKey: 'process.step3.body' as TranslationKey },
{ num: '04', titleKey: 'process.step4.title' as TranslationKey, bodyKey: 'process.step4.body' as TranslationKey },
];
---
<section class="py-24 md:py-32 relative overflow-hidden" style="background: var(--hds-bg-soft);" id="como-trabajamos">
<div class="absolute inset-0 pointer-events-none" style="background: var(--hds-gradient-section);" aria-hidden="true"></div>
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="max-w-3xl mb-16 md:mb-20 reveal">
<SectionEyebrow text={t('process.eyebrow')} />
<h2 class="font-display leading-tight mt-5" style="font-size: clamp(2rem, 5vw, 3.5rem); color: var(--hds-fg);">
{t('process.title')}
</h2>
</div>
<!-- Timeline with progress bar -->
<div class="process-timeline">
<!-- Vertical progress bar track -->
<div class="process-progress-track" aria-hidden="true">
<div id="process-progress-fill" class="process-progress-fill"></div>
</div>
<div class="process-steps">
{steps.map((step, i) => (
<div id={`process-step-${i}`} class="process-step-wrap">
<article class="glass-card process-step-card p-8 md:p-10">
<div class="flex items-start gap-6">
<div class="font-display leading-none flex-shrink-0" style="font-size: 3.5rem; color: var(--color-hds-naranja); font-weight: 500; opacity: 0.9;">
{step.num}
</div>
<div>
<h3 class="text-xl md:text-2xl font-semibold mb-3" style="color: var(--hds-fg);">
{t(step.titleKey)}
</h3>
<p class="text-[15px] md:text-base leading-relaxed" style="color: var(--hds-fg-soft);">
{t(step.bodyKey)}
</p>
</div>
</div>
</article>
</div>
))}
</div>
</div>
</div>
</section>
<script>
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
gsap.registerPlugin(ScrollTrigger);
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (!prefersReduced) {
const steps = document.querySelectorAll('.process-step-card');
const progressFill = document.getElementById('process-progress-fill');
if (steps.length && progressFill) {
// Animate progress bar as user scrolls through the section
ScrollTrigger.create({
trigger: '.process-steps',
start: 'top 70%',
end: 'bottom bottom',
onUpdate: (self) => {
progressFill.style.setProperty('--progress', `${self.progress * 100}%`);
},
});
// Stagger reveal each step card
gsap.from('.process-step-card', {
scrollTrigger: {
trigger: '.process-steps',
start: 'top 75%',
toggleActions: 'play none none none',
},
opacity: 0,
x: -30,
duration: 0.7,
stagger: 0.15,
ease: 'power3.out',
});
}
}
</script>
<style>
.process-timeline {
display: flex;
gap: 2rem;
max-width: 48rem;
margin: 0 auto;
}
.process-progress-track {
flex-shrink: 0;
width: 3px;
border-radius: 3px;
background: var(--hds-line);
position: relative;
margin-top: 0;
}
.process-progress-fill {
position: sticky;
top: 0;
width: 100%;
height: 40vh;
background: var(--color-hds-naranja);
border-radius: inherit;
clip-path: inset(0 0 calc(100% - var(--progress, 0%)) 0);
transition: clip-path 0.1s linear;
}
.process-steps {
display: flex;
flex-direction: column;
gap: 1.5rem;
flex-grow: 1;
}
.process-step-card {
width: 100%;
}
@media (max-width: 767px) {
.process-timeline {
gap: 1rem;
}
.process-progress-track {
width: 2px;
}
}
</style>