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
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
---
|
||||
// "Por qué elegirnos" — Bento grid with glass cards + magnetic hover glow
|
||||
// Phase 3 — Organic Fluidity Premium
|
||||
import SectionEyebrow from './SectionEyebrow.astro';
|
||||
import type { TranslationKey } from '@/i18n/ui';
|
||||
import MateIcon from './icons/MateIcon.astro';
|
||||
@@ -10,15 +12,23 @@ interface Props {
|
||||
}
|
||||
const { t } = Astro.props;
|
||||
|
||||
const items = [
|
||||
{ Icon: MateIcon, titleKey: 'diff.support.title' as TranslationKey, bodyKey: 'diff.support.body' as TranslationKey },
|
||||
interface DiffItem {
|
||||
Icon?: typeof MateIcon;
|
||||
titleKey: TranslationKey;
|
||||
bodyKey: TranslationKey;
|
||||
hero?: boolean;
|
||||
area?: string;
|
||||
}
|
||||
|
||||
const items: DiffItem[] = [
|
||||
{ Icon: MateIcon, titleKey: 'diff.support.title' as TranslationKey, bodyKey: 'diff.support.body' as TranslationKey, hero: true },
|
||||
{ Icon: SovereigntyIcon, titleKey: 'diff.sovereignty.title' as TranslationKey, bodyKey: 'diff.sovereignty.body' as TranslationKey },
|
||||
{ Icon: GlobeIcon, titleKey: 'diff.infra.title' as TranslationKey, bodyKey: 'diff.infra.body' as TranslationKey },
|
||||
];
|
||||
---
|
||||
<section class="py-20 md:py-28" style="background: var(--hds-bg-soft);">
|
||||
<section class="py-24 md:py-32" style="background: var(--hds-bg-soft);" id="por-que-elegirnos">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="max-w-3xl mb-14 md:mb-20 reveal">
|
||||
<div class="max-w-3xl mb-16 md:mb-20 reveal">
|
||||
<SectionEyebrow text={t('diff.eyebrow')} />
|
||||
<h2 class="font-display leading-tight mt-5" style="font-size: clamp(2rem, 5vw, 3.5rem); color: var(--hds-fg);">
|
||||
{t('diff.title')}
|
||||
@@ -28,20 +38,116 @@ const items = [
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 stagger">
|
||||
{items.map((item) => (
|
||||
<article class="service-card">
|
||||
<!-- Bento Grid: asymmetric 3-column layout -->
|
||||
<div class="bento-grid">
|
||||
{items.map((item, i) => (
|
||||
<article
|
||||
class:list={[
|
||||
'glass-card bento-item p-8 md:p-10 flex flex-col',
|
||||
{ 'bento-hero md:col-span-2 md:row-span-2': item.hero },
|
||||
]}
|
||||
data-bento-index={i}
|
||||
>
|
||||
<div class="icon-circle mb-6">
|
||||
<item.Icon class="w-7 h-7" />
|
||||
{item.Icon && <item.Icon class="w-7 h-7" />}
|
||||
</div>
|
||||
<h3 class="text-xl md:text-2xl font-semibold mb-3" style="color: var(--hds-fg);">
|
||||
<h3
|
||||
class:list={[
|
||||
'mb-4',
|
||||
{ 'text-2xl md:text-3xl': item.hero, 'text-xl md:text-2xl': !item.hero },
|
||||
]}
|
||||
style="color: var(--hds-fg); font-weight: 600;"
|
||||
>
|
||||
{t(item.titleKey)}
|
||||
</h3>
|
||||
<p class="text-[15px] leading-relaxed" style="color: var(--hds-fg-soft);">
|
||||
<p
|
||||
class:list={[
|
||||
'leading-relaxed',
|
||||
{ 'text-base md:text-lg': item.hero, 'text-[15px]': !item.hero },
|
||||
]}
|
||||
style="color: var(--hds-fg-soft);"
|
||||
>
|
||||
{t(item.bodyKey)}
|
||||
</p>
|
||||
|
||||
{item.hero && (
|
||||
<div class="mt-6 pt-6 border-t flex items-center gap-4" style="border-color: var(--glass-border);">
|
||||
<div class="flex -space-x-2">
|
||||
<div class="w-8 h-8 rounded-full flex items-center justify-center text-[10px] font-bold text-white" style="background: var(--color-hds-naranja);">M</div>
|
||||
<div class="w-8 h-8 rounded-full flex items-center justify-center text-[10px] font-bold" style="background: var(--color-hds-coral); color: var(--hds-tinta);">+2</div>
|
||||
</div>
|
||||
<span class="text-sm" style="color: var(--hds-fg-soft);">
|
||||
{t('diff.eyebrow') === 'La diferencia' ? 'Equipo de 3 ingenieros SRE' : 'Team of 3 SRE engineers'}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
import gsap from 'gsap';
|
||||
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
||||
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
|
||||
// Mouse-tracking glow on glass cards
|
||||
document.querySelectorAll('.bento-item').forEach((card) => {
|
||||
card.addEventListener('mousemove', (e) => {
|
||||
const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
|
||||
const x = ((e.clientX - rect.left) / rect.width) * 100;
|
||||
const y = ((e.clientY - rect.top) / rect.height) * 100;
|
||||
(e.currentTarget as HTMLElement).style.setProperty('--mouse-x', `${x}%`);
|
||||
(e.currentTarget as HTMLElement).style.setProperty('--mouse-y', `${y}%`);
|
||||
});
|
||||
});
|
||||
|
||||
// ScrollTrigger stagger reveal
|
||||
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
if (!prefersReduced) {
|
||||
gsap.from('.bento-item', {
|
||||
scrollTrigger: {
|
||||
trigger: '.bento-grid',
|
||||
start: 'top 80%',
|
||||
toggleActions: 'play none none none',
|
||||
},
|
||||
opacity: 0,
|
||||
y: 40,
|
||||
duration: 0.7,
|
||||
stagger: 0.12,
|
||||
ease: 'power3.out',
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.bento-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.bento-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-auto-rows: auto;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.bento-item {
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.bento-hero {
|
||||
min-height: 320px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.bento-hero {
|
||||
min-height: 380px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user