feat: implement solutions page, use cases, and update landing page sections including MagicBento, ScrollStack, and interactive components
This commit is contained in:
@@ -145,48 +145,49 @@ export default function WhatWeDo({ isLoaded = false }: WhatWeDoProps) {
|
||||
if (typeof window === 'undefined') return;
|
||||
|
||||
const ctx = gsap.context(() => {
|
||||
// Header: blur fade-up with stagger
|
||||
gsap.fromTo(
|
||||
'.wwd-header-el',
|
||||
{ opacity: 0, y: 40 },
|
||||
{ opacity: 0, y: 36, filter: 'blur(6px)' },
|
||||
{
|
||||
opacity: 1, y: 0, duration: DEFAULT_DURATION, stagger: 0.15, ease: DEFAULT_EASE,
|
||||
opacity: 1, y: 0, filter: 'blur(0px)',
|
||||
duration: 1, stagger: 0.18, ease: 'expo.out',
|
||||
scrollTrigger: { trigger: '.wwd-header', start: 'top 85%', toggleActions: 'play none none reset' },
|
||||
}
|
||||
);
|
||||
|
||||
// Per-card reveal: each card gets its own scrubbed-in timeline
|
||||
// (clip-path wipe + rise), staggered across the row, with the
|
||||
// icon and copy cascading in right after.
|
||||
gsap.utils.toArray<HTMLElement>('.wwd-card').forEach((card, i) => {
|
||||
const tl = gsap.timeline({
|
||||
scrollTrigger: { trigger: card, start: 'top 85%', toggleActions: 'play none none reset' },
|
||||
delay: i * 0.1,
|
||||
});
|
||||
// Cards: single staggered timeline triggered once the row enters view
|
||||
const cards = gsap.utils.toArray<HTMLElement>('.wwd-card');
|
||||
const grid = document.querySelector('.wwd-grid-container');
|
||||
|
||||
tl.fromTo(card,
|
||||
{ opacity: 0, y: 70, scale: 0.94, clipPath: 'inset(0% 0% 100% 0% round 22px)' },
|
||||
{ opacity: 1, y: 0, scale: 1, clipPath: 'inset(0% 0% 0% 0% round 22px)', duration: 0.75, ease: 'power3.out' },
|
||||
0
|
||||
)
|
||||
.fromTo(card.querySelector('.wwd-icon'),
|
||||
{ opacity: 0, scale: 0.4, rotate: -20 },
|
||||
{ opacity: 1, scale: 1, rotate: 0, duration: 0.55, ease: 'back.out(2.2)' },
|
||||
0.3
|
||||
gsap.fromTo(cards,
|
||||
{ opacity: 0, y: 56, scale: 0.93, filter: 'blur(4px)' },
|
||||
{
|
||||
opacity: 1, y: 0, scale: 1, filter: 'blur(0px)',
|
||||
duration: 0.8, stagger: 0.12, ease: 'expo.out',
|
||||
scrollTrigger: { trigger: grid, start: 'top 82%', toggleActions: 'play none none reset' },
|
||||
}
|
||||
);
|
||||
|
||||
// Cascade inner elements after cards land
|
||||
cards.forEach((card, i) => {
|
||||
const tl = gsap.timeline({ delay: i * 0.12 + 0.25 });
|
||||
|
||||
tl.fromTo(card.querySelector('.wwd-icon'),
|
||||
{ opacity: 0, scale: 0.5, rotate: -15, filter: 'blur(3px)' },
|
||||
{ opacity: 1, scale: 1, rotate: 0, filter: 'blur(0px)', duration: 0.55, ease: 'back.out(2)' }
|
||||
)
|
||||
.fromTo(card.querySelector('.wwd-title'),
|
||||
{ opacity: 0, y: 16 },
|
||||
{ opacity: 1, y: 0, duration: 0.45, ease: 'power2.out' },
|
||||
0.5
|
||||
{ opacity: 0, y: 14 },
|
||||
{ opacity: 1, y: 0, duration: 0.4, ease: 'power3.out' }, '-=0.2'
|
||||
)
|
||||
.fromTo(card.querySelector('.wwd-tagline'),
|
||||
{ opacity: 0, y: 12 },
|
||||
{ opacity: 1, y: 0, duration: 0.45, ease: 'power2.out' },
|
||||
0.58
|
||||
{ opacity: 0, y: 10 },
|
||||
{ opacity: 1, y: 0, duration: 0.38, ease: 'power3.out' }, '-=0.2'
|
||||
)
|
||||
.fromTo(card.querySelector('.wwd-detail'),
|
||||
{ opacity: 0, y: 10 },
|
||||
{ opacity: 1, y: 0, duration: 0.4, ease: 'power2.out' },
|
||||
0.66
|
||||
{ opacity: 0, y: 8 },
|
||||
{ opacity: 1, y: 0, duration: 0.35, ease: 'power3.out' }, '-=0.18'
|
||||
);
|
||||
});
|
||||
}, containerRef);
|
||||
|
||||
Reference in New Issue
Block a user