From f978442a2945bf1c6077aea6cb7b9077d87be590 Mon Sep 17 00:00:00 2001 From: Ferran Buireu Date: Sat, 16 Dec 2023 19:01:57 +0100 Subject: [PATCH] feat: improved GSAP performance --- src/content/blog/using-mdx.mdx | 2 +- src/pages/index.astro | 8 +- .../components/atoms/ReactScriptProvider.tsx | 2 + .../headerLink/HeaderLink.astro | 0 src/ui/components/atoms/logo/Logo.astro | 8 ++ .../header/components => atoms}/logo/logo.css | 2 +- .../components => atoms}/menu/Menu.astro | 2 +- .../header/components => atoms}/menu/menu.css | 0 .../menuButton/MenuButton.astro | 2 +- .../menuButton/menuButton.css | 0 .../menuOverlay/MenuOverlay.astro | 2 +- .../menuOverlay/menuOverlay.css | 3 +- .../molecules/testimonials/Testimonials.astro | 8 +- .../molecules/testimonials/testimonials.css | 64 ++-------- .../molecules/welcome/Welcome.astro | 12 +- .../welcome/utils/initializeParallax/index.ts | 1 + .../initializeParallax/initializeParallax.ts | 31 +++++ .../components/molecules/welcome/welcome.css | 6 +- .../components/organisms/header/Header.astro | 8 +- .../header/components/logo/Logo.astro | 8 -- .../header/utils/toggleMenu/toggleMenu.ts | 112 +++++++++++------- src/ui/styles/base/base.css | 7 +- src/ui/styles/global/animations.css | 6 +- 23 files changed, 162 insertions(+), 132 deletions(-) rename src/ui/components/{organisms/header/components => atoms}/headerLink/HeaderLink.astro (100%) create mode 100644 src/ui/components/atoms/logo/Logo.astro rename src/ui/components/{organisms/header/components => atoms}/logo/logo.css (91%) rename src/ui/components/{organisms/header/components => atoms}/menu/Menu.astro (93%) rename src/ui/components/{organisms/header/components => atoms}/menu/menu.css (100%) rename src/ui/components/{organisms/header/components => atoms}/menuButton/MenuButton.astro (79%) rename src/ui/components/{organisms/header/components => atoms}/menuButton/menuButton.css (100%) rename src/ui/components/{organisms/header/components => atoms}/menuOverlay/MenuOverlay.astro (77%) rename src/ui/components/{organisms/header/components => atoms}/menuOverlay/menuOverlay.css (80%) create mode 100644 src/ui/components/molecules/welcome/utils/initializeParallax/index.ts create mode 100644 src/ui/components/molecules/welcome/utils/initializeParallax/initializeParallax.ts delete mode 100644 src/ui/components/organisms/header/components/logo/Logo.astro diff --git a/src/content/blog/using-mdx.mdx b/src/content/blog/using-mdx.mdx index 55630eb0..7f474aa9 100644 --- a/src/content/blog/using-mdx.mdx +++ b/src/content/blog/using-mdx.mdx @@ -20,7 +20,7 @@ When you open this page in the browser, you should see the clickable button belo -import HeaderLink from '../../ui/components/organisms/header/components/headerLink/HeaderLink.astro'; +import HeaderLink from '../../ui/components/atoms/headerLink/HeaderLink.astro'; Embedded component in MDX diff --git a/src/pages/index.astro b/src/pages/index.astro index 8b2a0d14..73a86db5 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -3,7 +3,7 @@ import BaseLayout from '@components/templates/baseLayout/BaseLayout.astro'; import Welcome from '@components/molecules/welcome/Welcome.astro'; import Testimonials from '@components/molecules/testimonials/Testimonials.astro'; -// todo: acabar welcome (tilt) +// todo: add testimonial // todo: reveal on enter viewport // todo: view transitions // todo: add vitest @@ -12,10 +12,4 @@ import Testimonials from '@components/molecules/testimonials/Testimonials.astro' -

- This template comes with a few integrations already configured in your - astro.config.mjs file. You can customize your setup with - Astro Integrations to add tools like - Tailwind, React, or Vue to your project. -

diff --git a/src/ui/components/atoms/ReactScriptProvider.tsx b/src/ui/components/atoms/ReactScriptProvider.tsx index d191a801..b6159252 100644 --- a/src/ui/components/atoms/ReactScriptProvider.tsx +++ b/src/ui/components/atoms/ReactScriptProvider.tsx @@ -1,11 +1,13 @@ import { useEffect } from 'react'; import { toggleMenu } from '@components/organisms/header/utils/toggleMenu'; import { scrollDirection } from '@components/organisms/header/utils/scrollDirection'; +import { initializeParallax } from '@components/molecules/welcome/utils/initializeParallax'; const ReactScriptProvider = () => { useEffect(() => { toggleMenu(); scrollDirection(); + initializeParallax(); }, []); return null; diff --git a/src/ui/components/organisms/header/components/headerLink/HeaderLink.astro b/src/ui/components/atoms/headerLink/HeaderLink.astro similarity index 100% rename from src/ui/components/organisms/header/components/headerLink/HeaderLink.astro rename to src/ui/components/atoms/headerLink/HeaderLink.astro diff --git a/src/ui/components/atoms/logo/Logo.astro b/src/ui/components/atoms/logo/Logo.astro new file mode 100644 index 00000000..723f47c5 --- /dev/null +++ b/src/ui/components/atoms/logo/Logo.astro @@ -0,0 +1,8 @@ +--- +import logo from 'src/ui/assets/images/svg/logo.svg?raw'; +import './logo.css'; +--- + + diff --git a/src/ui/components/organisms/header/components/logo/logo.css b/src/ui/components/atoms/logo/logo.css similarity index 91% rename from src/ui/components/organisms/header/components/logo/logo.css rename to src/ui/components/atoms/logo/logo.css index 16494a76..cfcd5573 100644 --- a/src/ui/components/organisms/header/components/logo/logo.css +++ b/src/ui/components/atoms/logo/logo.css @@ -10,7 +10,7 @@ z-index: 20; svg { - transition: scale .2s; + transition: scale 0.2s; } &.--is-scrolling:not(.--is-menu-open) svg{ diff --git a/src/ui/components/organisms/header/components/menu/Menu.astro b/src/ui/components/atoms/menu/Menu.astro similarity index 93% rename from src/ui/components/organisms/header/components/menu/Menu.astro rename to src/ui/components/atoms/menu/Menu.astro index 94091e1a..7527c312 100644 --- a/src/ui/components/organisms/header/components/menu/Menu.astro +++ b/src/ui/components/atoms/menu/Menu.astro @@ -1,6 +1,6 @@ --- import './menu.css'; -import HeaderLink from '@components/organisms/header/components/headerLink/HeaderLink.astro'; +import HeaderLink from 'src/ui/components/atoms/headerLink/HeaderLink.astro'; --- diff --git a/src/ui/components/molecules/testimonials/testimonials.css b/src/ui/components/molecules/testimonials/testimonials.css index 909e696a..f2d75fd5 100644 --- a/src/ui/components/molecules/testimonials/testimonials.css +++ b/src/ui/components/molecules/testimonials/testimonials.css @@ -1,56 +1,18 @@ -@layer welcome { - .welcome { - display: grid; - grid-template-areas: 'LeftGreeting WelcomeImage RightGreeting'; - grid-template-columns: 1fr 1fr 1fr; +@layer testimonials { + .testimonials__wrapper{ + margin-top: 9rem; } - .welcome__image{ - grid-area: WelcomeImage; - align-self: center; - justify-self: center; - width: 100%; - max-width: 400px; - height: auto; - } - - .welcome__text__body { - align-self: center; + .testimonials__title, + .testimonials__body { text-align: center; - color: var(--neutral-main); - - &.--right { - grid-area: RightGreeting; - justify-self: start; - margin-left: -3rem; - z-index: 10; - } - &.--left { - grid-area: LeftGreeting; - justify-self: end; - margin-right: -1.5rem; - z-index: 10; - translate: 0 -100px; - } - @supports (animation-timeline: scroll(root block)) { - &.--right { - animation: float-up-far 200ms linear; - animation-timeline: scroll(root block); - } - &.--left { - animation: float-up-close linear; - animation-timeline: scroll(root block); - } - } + margin: 0 auto; } - .welcome__text__description{ - grid-area: RightGreeting; - padding-inline-start: 1rem; - align-self: center; - margin-top: 8rem; - - @supports (animation-timeline: scroll(root block)) { - animation: float-up-close linear; - animation-timeline: scroll(root block); - } + .testimonials__title{ + text-transform: uppercase; + letter-spacing: .5rem; + } + .testimonials__body { + max-width: var(--grid-small); + width: 100%; } } diff --git a/src/ui/components/molecules/welcome/Welcome.astro b/src/ui/components/molecules/welcome/Welcome.astro index 6d7bdedf..1713c502 100644 --- a/src/ui/components/molecules/welcome/Welcome.astro +++ b/src/ui/components/molecules/welcome/Welcome.astro @@ -3,8 +3,12 @@ import { Picture } from "astro-imagetools/components"; import './welcome.css'; ---
-

Hi! I'm

- -

Bianca

-

Lorem ipsum dolor sit amet ipsum dolor sit amet ipsum dolor sit amet ipsum dolor sit amet

+

Hi! I'm

+ +

Bianca Fiore

+

Lorem ipsum dolor sit amet ipsum dolor sit amet ipsum dolor sit amet ipsum dolor sit amet

+ + diff --git a/src/ui/components/molecules/welcome/utils/initializeParallax/index.ts b/src/ui/components/molecules/welcome/utils/initializeParallax/index.ts new file mode 100644 index 00000000..2daf6dc2 --- /dev/null +++ b/src/ui/components/molecules/welcome/utils/initializeParallax/index.ts @@ -0,0 +1 @@ +export * from './initializeParallax'; diff --git a/src/ui/components/molecules/welcome/utils/initializeParallax/initializeParallax.ts b/src/ui/components/molecules/welcome/utils/initializeParallax/initializeParallax.ts new file mode 100644 index 00000000..b760f858 --- /dev/null +++ b/src/ui/components/molecules/welcome/utils/initializeParallax/initializeParallax.ts @@ -0,0 +1,31 @@ +import { gsap } from 'gsap'; +import type { MouseEvent } from 'react'; + +interface ParallaxParams { + event: globalThis.MouseEvent | MouseEvent; + target: string; + movement: number; +} + +export function initializeParallax() { + const WELCOME = document.querySelector('.welcome') as HTMLElement; + + if (WELCOME instanceof HTMLElement) { + WELCOME.addEventListener('mousemove', (event) => { + attachParallax({ event, target: '.welcome__image', movement: -30 }); + }); + } + function attachParallax({ event, target, movement }: ParallaxParams) { + if (WELCOME instanceof HTMLElement) { + const { offsetLeft, offsetTop, offsetWidth, offsetHeight } = WELCOME; + const relativeX = event.pageX - offsetLeft; + const relativeY = event.pageY - offsetTop; + + gsap.to(target, { + duration: 1, + x: ((relativeX - offsetWidth / 2) / offsetWidth) * movement, + y: ((relativeY - offsetHeight / 2) / offsetHeight) * movement, + }); + } + } +} diff --git a/src/ui/components/molecules/welcome/welcome.css b/src/ui/components/molecules/welcome/welcome.css index 909e696a..60cd903b 100644 --- a/src/ui/components/molecules/welcome/welcome.css +++ b/src/ui/components/molecules/welcome/welcome.css @@ -4,7 +4,7 @@ grid-template-areas: 'LeftGreeting WelcomeImage RightGreeting'; grid-template-columns: 1fr 1fr 1fr; } - .welcome__image{ + .welcome__image { grid-area: WelcomeImage; align-self: center; justify-self: center; @@ -13,7 +13,7 @@ height: auto; } - .welcome__text__body { + .welcome__text__title { align-self: center; text-align: center; color: var(--neutral-main); @@ -42,7 +42,7 @@ } } } - .welcome__text__description{ + .welcome__text__body { grid-area: RightGreeting; padding-inline-start: 1rem; align-self: center; diff --git a/src/ui/components/organisms/header/Header.astro b/src/ui/components/organisms/header/Header.astro index 841d34d4..631cde3a 100644 --- a/src/ui/components/organisms/header/Header.astro +++ b/src/ui/components/organisms/header/Header.astro @@ -1,9 +1,9 @@ --- import './header.css'; -import MenuButton from '@components/organisms/header/components/menuButton/MenuButton.astro'; -import MenuOverlay from '@components/organisms/header/components/menuOverlay/MenuOverlay.astro'; -import Logo from '@components/organisms/header/components/logo/Logo.astro'; -import Menu from '@components/organisms/header/components/menu/Menu.astro'; +import MenuButton from 'src/ui/components/atoms/menuButton/MenuButton.astro'; +import MenuOverlay from 'src/ui/components/atoms/menuOverlay/MenuOverlay.astro'; +import Logo from 'src/ui/components/atoms/logo/Logo.astro'; +import Menu from 'src/ui/components/atoms/menu/Menu.astro'; ---
diff --git a/src/ui/components/organisms/header/components/logo/Logo.astro b/src/ui/components/organisms/header/components/logo/Logo.astro deleted file mode 100644 index d1781c7e..00000000 --- a/src/ui/components/organisms/header/components/logo/Logo.astro +++ /dev/null @@ -1,8 +0,0 @@ ---- -import logo from '@assets/images/svg/logo.svg?raw'; -import '@components/organisms/header/components/logo/logo.css'; ---- - - diff --git a/src/ui/components/organisms/header/utils/toggleMenu/toggleMenu.ts b/src/ui/components/organisms/header/utils/toggleMenu/toggleMenu.ts index 6e8e7f97..b8fb4e85 100644 --- a/src/ui/components/organisms/header/utils/toggleMenu/toggleMenu.ts +++ b/src/ui/components/organisms/header/utils/toggleMenu/toggleMenu.ts @@ -1,45 +1,74 @@ -import { gsap } from 'gsap'; +import { gsap, Power2, Power3, Power4 } from 'gsap'; const ANIMATION_CONFIG = { - POWER4_IN_OUT: 'power4.inOut', - POWER2_EASE_OUT: 'power2.easeOut', - POWER2_EASE_IN: 'power2.easeIn', - POWER3_OUT: 'power3.out', + POWER4_IN_OUT: Power4.easeInOut, + POWER2_EASE_OUT: Power2.easeOut, + POWER3_OUT: Power3.easeOut, WHITE: getComputedStyle(document.documentElement).getPropertyValue('--white') ?? 'var(--white)', PATH_START: 'M0 502S175 272 500 272s500 230 500 230V0H0Z', PATH_END: 'M0,1005S175,995,500,995s500,5,500,5V0H0Z', }; +const SELECTORS = { + BODY: 'body', + HTML: 'html', + TOGGLE_MENU_BUTTON: '.header__menu-button', + MENU_OVERLAY: '.header__menu-overlay__wrapper', + OVERLAY_PATH: '.header__menu-overlay__wrapper path', + HEADER_MENU_TEXT: '.header__menu-text', + BUTTON_OUTLINE: '.header__menu-button__outline', + SITE_LOGO: '.site__logo', + SITE_LOGO_SVG: '.site__logo svg', + HEADER_MENU: '.header__menu', + NAVIGATION_DIVIDER: '.navigation__menu__divider', + NAVIGATION_ITEMS: '.navigation__menu__item > *', + QUOTE: '.navigation__menu__quote > *', +}; + export function toggleMenu() { let isMenuOpen = false; let toggleMenuText = 'Menu'; + const timeline = gsap.timeline({ paused: true }); - const BODY = document.querySelector('body')!; - const HTML = document.querySelector('html')!; - const MENU_OVERLAY = document.querySelector('.header__menu-overlay__wrapper')!; - const MENU_DIVIDER = document.querySelector('.navigation__menu__divider')!; - const TOGGLE_MENU_BUTTON = document.querySelector('.header__menu-button')!; - const LOGO = document.querySelector('.site__logo')!; - const MENU_TEXT = document.querySelector('.header__menu-text')!; - const OVERLAY_PATH = MENU_OVERLAY.querySelector('path'); + const { + BODY: BODY_SELECTOR, + HTML: HTML_SELECTOR, + TOGGLE_MENU_BUTTON: TOGGLE_MENU_BUTTON_SELECTOR, + MENU_OVERLAY, + OVERLAY_PATH, + BUTTON_OUTLINE, + SITE_LOGO, + SITE_LOGO_SVG, + NAVIGATION_DIVIDER, + HEADER_MENU, + NAVIGATION_ITEMS, + QUOTE, + HEADER_MENU_TEXT, + } = SELECTORS; - const ELEMENTS_TO_TOGGLE = [BODY, HTML, LOGO, MENU_OVERLAY, MENU_DIVIDER]; + const BODY = document.querySelector(BODY_SELECTOR)!; + const HTML = document.querySelector(HTML_SELECTOR)!; + const LOGO = document.querySelector(SITE_LOGO)!; + const TOGGLE_MENU_BUTTON = document.querySelector(TOGGLE_MENU_BUTTON_SELECTOR)!; + const MENU_DIVIDER = document.querySelector(NAVIGATION_DIVIDER)!; + const MENU_TEXT = document.querySelector(HEADER_MENU_TEXT)!; + + const ELEMENTS_TO_TOGGLE = [BODY, HTML, LOGO, MENU_DIVIDER]; - const timeline = gsap.timeline({ paused: true }); toggleMenuItems(); function updateButtonContent() { if (!MENU_TEXT) return; toggleMenuText = isMenuOpen ? 'Close' : 'Menu'; - const timeout = isMenuOpen ? 500 : 0; + const timeout = isMenuOpen ? 300 : 0; setTimeout(() => (MENU_TEXT.textContent = toggleMenuText), timeout); } function toggleMenuItems() { - const { POWER4_IN_OUT, POWER2_EASE_IN, POWER3_OUT, WHITE, PATH_START, PATH_END } = ANIMATION_CONFIG; + const { POWER4_IN_OUT, POWER2_EASE_OUT, POWER3_OUT, WHITE, PATH_START, PATH_END } = ANIMATION_CONFIG; - timeline.to('.header__menu-overlay__wrapper', { zIndex: '0', display: 'block' }, '<'); - timeline.to('.header__menu-text', { + timeline.to(MENU_OVERLAY, { display: 'block' }); + timeline.to(MENU_TEXT, { top: '1.5rem', left: '1rem', fontSize: '1.5rem', @@ -47,11 +76,11 @@ export function toggleMenu() { x: 0, y: 0, ease: POWER4_IN_OUT, - duration: 1.25, + duration: 1, }); timeline.add(() => updateButtonContent(), '<'); timeline.to( - '.header__menu-button__outline', + BUTTON_OUTLINE, { width: '90px', height: '90px', @@ -59,48 +88,43 @@ export function toggleMenu() { x: 0, y: 0, ease: POWER4_IN_OUT, - duration: 1.25, + duration: 1, }, '<' ); - timeline.to('.site__logo', { y: '3rem', duration: 0.25 }, '-=0.5'); - timeline.to('.site__logo svg', { fill: WHITE, duration: 0.25 }, '<'); - timeline.to('.site__logo .--is-scrolling:not(.--is-menu-open) svg', { scale: 1 }, '<'); - timeline - .to(OVERLAY_PATH, { attr: { d: PATH_START }, ease: POWER2_EASE_IN, duration: 0.8 }, '<') - .to(OVERLAY_PATH, { attr: { d: PATH_END }, ease: POWER2_EASE_IN, duration: 0.8 }, '-=0.5'); - timeline.to('.header__menu', { visibility: 'visible', duration: 1 }, '-=0.5'); + timeline.to(SITE_LOGO, { y: '3rem', duration: 0.25 }, '<'); + timeline.to(SITE_LOGO_SVG, { fill: WHITE, duration: 0.25 }, '<'); timeline - .to( - '.navigation__menu__item > *', - { - top: 0, - ease: POWER3_OUT, - stagger: { amount: 0.5 }, - duration: 1, - }, - '-=1' - ) - .reverse(); + .to(OVERLAY_PATH, { attr: { d: PATH_START }, ease: POWER2_EASE_OUT, duration: 1 }, '<') + .to(OVERLAY_PATH, { attr: { d: PATH_END }, ease: POWER2_EASE_OUT, duration: 1 }, '-=0.5'); + timeline.to(HEADER_MENU, { visibility: 'visible', duration: 1 }, '-=0.5'); timeline .to( - '.navigation__menu__quote > *', + NAVIGATION_ITEMS, { top: 0, ease: POWER3_OUT, stagger: { amount: 0.5 }, - duration: 1, + duration: 0.75, }, '-=1' ) .reverse(); + timeline.to( + QUOTE, + { + top: 0, + ease: POWER3_OUT, + duration: 0.75, + }, + '-=1' + ); } TOGGLE_MENU_BUTTON.addEventListener('click', () => { isMenuOpen = !isMenuOpen; + timeline.reversed(!timeline.reversed()); ELEMENTS_TO_TOGGLE.forEach((element) => element.classList.toggle('--is-menu-open')); - - timeline.reversed(!timeline.reversed()); }); } diff --git a/src/ui/styles/base/base.css b/src/ui/styles/base/base.css index 8b797561..3b932bda 100644 --- a/src/ui/styles/base/base.css +++ b/src/ui/styles/base/base.css @@ -82,7 +82,12 @@ fill: var(--neutral-main); } - h1, h2{ + h1, h2 { font-size: clamp(2rem, 5rem, 5rem); } + + h3{ + font-size: clamp(2rem, 3.5rem, 3.5rem); + letter-spacing: 0.35rem; + } } diff --git a/src/ui/styles/global/animations.css b/src/ui/styles/global/animations.css index e00f4eee..c7b56b48 100644 --- a/src/ui/styles/global/animations.css +++ b/src/ui/styles/global/animations.css @@ -10,20 +10,22 @@ border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%; } } + @keyframes float-up-close { 0% { transform: translateY(0); } 100% { - transform: translateY(-100px); + transform: translateY(-50px); } } + @keyframes float-up-far { 0% { translate: 0 0; } 100% { - translate: 0 -400px; + translate: 0 -200px; } } }