diff --git a/parfum-shop/public/atmos-hero-wordmark.svg b/parfum-shop/public/atmos-hero-wordmark.svg new file mode 100644 index 0000000..feea2b3 --- /dev/null +++ b/parfum-shop/public/atmos-hero-wordmark.svg @@ -0,0 +1,3 @@ + + + diff --git a/parfum-shop/public/blasse-seide-hero-product.webp b/parfum-shop/public/blasse-seide-hero-product.webp new file mode 100644 index 0000000..9049780 Binary files /dev/null and b/parfum-shop/public/blasse-seide-hero-product.webp differ diff --git a/parfum-shop/public/hero-section-beton-background.png b/parfum-shop/public/hero-section-beton-background.png new file mode 100644 index 0000000..3dd5b27 Binary files /dev/null and b/parfum-shop/public/hero-section-beton-background.png differ diff --git a/parfum-shop/src/components/landing/HeroSection.jsx b/parfum-shop/src/components/landing/HeroSection.jsx index a555bc0..e2b677d 100644 --- a/parfum-shop/src/components/landing/HeroSection.jsx +++ b/parfum-shop/src/components/landing/HeroSection.jsx @@ -6,45 +6,60 @@ function HeroSection({ heroImageRef, setHeadlinePrimaryRef, setHeadlineSecondaryRef, + setWordmarkRef, setDescriptionRef, setActionsRef, + setScrollRef, overlayRef, overlayTextRef, }) { return ( -
-
- Atmos perfume bottle in a material-led campaign scene +
+
+ ); } diff --git a/parfum-shop/src/pages/LandingPage.css b/parfum-shop/src/pages/LandingPage.css index aebebe6..af9129b 100644 --- a/parfum-shop/src/pages/LandingPage.css +++ b/parfum-shop/src/pages/LandingPage.css @@ -1,9 +1,6 @@ .page { position: relative; min-height: 100vh; - background: - radial-gradient(circle at 82% 12%, rgba(var(--theme-accent-rgb) / 0.13), transparent 28rem), - linear-gradient(180deg, var(--theme-bg), color-mix(in srgb, var(--theme-bg) 88%, #000 12%)); color: var(--theme-text); } @@ -27,112 +24,139 @@ .hero { position: relative; width: 100%; - min-height: clamp(680px, 100svh, 980px); + min-height: 720px; + min-height: max(720px, 100vh); + min-height: max(720px, 100dvh); overflow: hidden; - display: grid; - align-items: center; isolation: isolate; - background: #111; + background: var(--theme-bg); + transition: background-color var(--duration-med) var(--ease-out); } -.hero::before { +.hero::after { content: ""; position: absolute; inset: 0; - z-index: 2; + z-index: 1; pointer-events: none; + background: none; } -.hero::before { - background: - radial-gradient(circle at 72% 42%, rgba(255, 255, 255, 0.1), transparent 24rem), - linear-gradient(90deg, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0.42) 44%, rgba(0, 0, 0, 0.08) 100%), - linear-gradient(0deg, rgba(0, 0, 0, 0.44), transparent 46%); +.hero-material { + position: absolute; + inset: 0; + z-index: 0; + overflow: hidden; + background: var(--theme-bg); + will-change: transform; } -.hero-media { +.hero-material__texture { position: absolute; inset: 0; z-index: 1; + background: var(--theme-bg); will-change: transform; } -.hero-media__image { +.hero-wordmark { + position: absolute; + top: clamp(3.4rem, 6vh, 5.5rem); + left: var(--page-x); + right: var(--page-x); + z-index: 2; + pointer-events: none; + user-select: none; +} + +.hero-wordmark__mask { + overflow: hidden; + padding-top: 0.08rem; +} + +.hero-wordmark__image { + display: block; + width: 100%; + height: auto; + opacity: 0.96; + will-change: transform, opacity, filter; +} + +body.theme-light .hero-wordmark__image { + filter: invert(1); + opacity: 0.86; +} + +.hero-product { + position: absolute; + top: clamp(22rem, 58vh, 44rem); + left: 50%; + z-index: 5; + width: clamp(19rem, 29vw, 38rem); + aspect-ratio: 1078 / 1284; + margin: 0; + display: grid; + place-items: center; + transform: translate(-50%, -50%); + will-change: transform; +} + +.hero-product__inner { + position: relative; width: 100%; height: 100%; - display: block; - object-fit: cover; - object-position: 60% center; - will-change: transform; -} - -.hero .navbar--hero { - position: fixed; - top: clamp(0.75rem, 2.1vw, 1.4rem); - right: 0; - left: 0; - z-index: 998; - padding-top: 0; -} - -.hero-content { - position: relative; - z-index: 6; - width: var(--container-wide); - margin: 0 auto; - padding: clamp(7rem, 14vh, 11rem) 0 clamp(3rem, 8vh, 6rem); display: grid; - grid-template-columns: repeat(12, minmax(0, 1fr)); - gap: var(--gap-md); - align-items: center; -} - -.hero-title { - grid-column: 1 / span 7; - max-width: 10.8ch; - margin: 0; - font-size: clamp(3.2rem, 8.4vw, 8.8rem); - line-height: 0.9; - font-weight: 300; - letter-spacing: 0; - text-transform: uppercase; - color: #fff; - text-wrap: balance; -} - -.hero-title-line { - display: block; - overflow: hidden; - padding-right: 0.12em; - padding-bottom: 0.08em; - margin-right: -0.12em; - margin-bottom: -0.08em; -} - -.hero-title-line .reveal-line { - will-change: transform; -} - -.hero-title-line + .hero-title-line { - margin-top: 0.02em; -} - -.hero-text { - grid-column: 1 / span 5; - max-width: 31rem; - margin: 0; - font-size: var(--text-base); - line-height: 1.62; - color: rgba(255, 255, 255, 0.84); + place-items: center; will-change: transform, opacity; } +.hero-product__image { + position: relative; + z-index: 1; + width: 100%; + height: 100%; + object-fit: contain; + display: block; +} + +.hero-content { + position: absolute; + left: var(--page-x); + bottom: clamp(7.5rem, 19vh, 17rem); + z-index: 6; + width: min(25rem, calc(50vw - var(--page-x) - 8rem)); + color: var(--theme-text); +} + +.hero-copy { + max-width: 25rem; + margin: 0; + font-size: clamp(1.65rem, 2.25vw, 2.25rem); + line-height: 1.08; + font-weight: 300; + letter-spacing: 0; + color: var(--theme-text); +} + +.hero-copy-line { + display: block; + overflow: hidden; + padding-right: 0.08em; + padding-bottom: 0.03em; + margin-right: -0.08em; + margin-bottom: -0.03em; +} + +.hero-copy-line .reveal-line { + display: inline-block; + will-change: transform; +} + .hero-actions { - grid-column: 1 / span 5; display: flex; flex-wrap: wrap; - gap: var(--gap-xs); - margin-top: clamp(0.2rem, 1vw, 0.7rem); + gap: clamp(0.75rem, 1.2vw, 1rem); + margin-top: clamp(1.25rem, 3.2vh, 1.75rem); will-change: transform, opacity; } @@ -173,10 +197,34 @@ } .btn-secondary { - background: rgba(255, 255, 255, 0.13); - color: #fff; - border: 1px solid rgba(255, 255, 255, 0.24); - backdrop-filter: blur(12px); + background: color-mix(in srgb, var(--theme-surface) 72%, transparent); + color: var(--theme-text); + border: 1px solid var(--theme-border-strong); + backdrop-filter: blur(10px); +} + +.hero-scroll { + position: absolute; + right: var(--page-x); + bottom: clamp(7.5rem, 19vh, 17rem); + z-index: 6; + width: min(28vw, 420px); + padding-top: 0.55rem; + border-top: 1px solid var(--theme-border-strong); + color: var(--theme-text-muted); +} + +.hero-scroll__line { + display: none; +} + +.hero-scroll__label { + display: block; + margin: 0; + font-size: var(--text-xs); + line-height: 1.4; + letter-spacing: 0.16em; + text-transform: uppercase; } .intro-overlay { @@ -579,17 +627,20 @@ /* RESPONSIVE */ @media (max-width: 1180px) { + .hero-copy { + font-size: clamp(1.45rem, 2.35vw, 1.9rem); + } + + .hero-product { + width: clamp(21rem, 45vw, 34rem); + } + .hero-content { - grid-template-columns: repeat(8, minmax(0, 1fr)); + width: min(23rem, calc(50vw - var(--page-x) - 5rem)); } - .hero-title { - grid-column: 1 / span 6; - } - - .hero-text, - .hero-actions { - grid-column: 1 / span 4; + .hero-scroll { + width: clamp(9rem, 16vw, 12rem); } .section-heading { @@ -621,45 +672,55 @@ @media (max-width: 760px) { .hero { - min-height: clamp(620px, 91svh, 760px); + min-height: 720px; + min-height: max(720px, 100vh); + min-height: max(720px, 100dvh); } - .hero::before { - background: - linear-gradient(90deg, rgba(0, 0, 0, 0.74), rgba(0, 0, 0, 0.28)), - linear-gradient(0deg, rgba(0, 0, 0, 0.62), transparent 48%); + .hero-material__texture { + inset: 0; } - .hero-media__image { - object-position: 64% center; + .hero-wordmark { + top: clamp(5.8rem, 14svh, 7.5rem); + left: var(--page-x); + right: var(--page-x); + } + + .hero-product { + top: clamp(20.75rem, 49svh, 25.5rem); + left: 44%; + width: min(72vw, 19rem); + transform: translate(-50%, -58%); } .hero-content { - display: flex; - flex-direction: column; - align-items: flex-start; - justify-content: flex-end; - gap: var(--gap-sm); - padding-top: clamp(6.5rem, 18svh, 8.5rem); - padding-bottom: clamp(2.4rem, 8svh, 4rem); + left: clamp(1rem, 5vw, 1.5rem); + right: clamp(1rem, 5vw, 1.5rem); + bottom: clamp(2rem, 7svh, 4rem); + transform: none; + width: auto; + max-width: 27rem; } - .hero-title { - max-width: 9.6ch; - font-size: clamp(3rem, 17.5vw, 5.1rem); - } - - .hero-text { - max-width: 25rem; - font-size: var(--text-sm); + .hero-copy { + font-size: clamp(1.55rem, 7vw, 2rem); + line-height: 1.08; } .hero-actions { - width: min(100%, 22rem); + gap: 0.65rem; + margin-top: 1.1rem; } .hero-actions .btn { - width: 100%; + min-height: 44px; + padding-inline: 0.95rem; + font-size: 0.78rem; + } + + .hero-scroll { + display: none; } .product-grid { @@ -693,8 +754,20 @@ } @media (max-width: 430px) { - .hero-title { - max-width: 9.2ch; + .hero { + min-height: 700px; + min-height: max(700px, 100vh); + min-height: max(700px, 100dvh); + } + + .hero-product { + top: clamp(20.25rem, 48svh, 24.5rem); + left: 43%; + width: min(74vw, 18.25rem); + } + + .hero-copy { + font-size: clamp(1.42rem, 7vw, 1.72rem); } .section-heading h2, @@ -723,11 +796,14 @@ } @media (prefers-reduced-motion: reduce) { - .hero-media, - .hero-title-line, - .hero-text, + .hero-material, + .hero-material__texture, + .hero-copy-line, + .hero-wordmark__image, + .hero-product, + .hero-product__inner, + .hero-product__image, .hero-actions, - .hero-brand, .intro-overlay, .product-card, .product-image, diff --git a/parfum-shop/src/pages/LandingPage.jsx b/parfum-shop/src/pages/LandingPage.jsx index 24a18d7..fa762f2 100644 --- a/parfum-shop/src/pages/LandingPage.jsx +++ b/parfum-shop/src/pages/LandingPage.jsx @@ -25,6 +25,7 @@ function LandingPage() { const overlayTextRef = useRef(null); const heroImageWrapRef = useRef(null); const heroImageRef = useRef(null); + const heroWordmarkRef = useRef(null); const discoveryImageRef = useRef(null); const headlineLineRefs = useRef([]); const heroMetaRefs = useRef([]); @@ -56,6 +57,10 @@ function LandingPage() { headlineLineRefs.current[1] = element; }, []); + const setWordmarkRef = useCallback((element) => { + heroWordmarkRef.current = element; + }, []); + const setDescriptionRef = useCallback((element) => { heroMetaRefs.current[0] = element; }, []); @@ -64,23 +69,31 @@ function LandingPage() { heroMetaRefs.current[1] = element; }, []); + const setScrollRef = useCallback((element) => { + heroMetaRefs.current[2] = element; + }, []); + useLayoutEffect(() => { const overlay = overlayRef.current; const overlayText = overlayTextRef.current; const heroImageWrap = heroImageWrapRef.current; + const heroWordmark = heroWordmarkRef.current; const headlineLines = headlineLineRefs.current.filter(Boolean); - const heroMeta = heroMetaRefs.current.filter(Boolean); + const heroProduct = heroMetaRefs.current[0]; + const heroMeta = heroMetaRefs.current.slice(1).filter(Boolean); - if (!overlay || !overlayText || !heroImageWrap || headlineLines.length === 0) { + if ( + !overlay || + !overlayText || + !heroImageWrap || + !heroWordmark || + !heroProduct || + headlineLines.length === 0 + ) { return undefined; } const ctx = gsap.context(() => { - gsap.set(heroImageWrap, { - scale: 1.22, - transformOrigin: "center center", - }); - gsap.set(headlineLines, { yPercent: 115, rotate: 2.2, @@ -88,13 +101,69 @@ function LandingPage() { force3D: true, }); + gsap.set(heroWordmark, { + yPercent: 118, + autoAlpha: 0, + force3D: true, + }); + + gsap.set(heroProduct, { + scale: 0.82, + y: 54, + autoAlpha: 0, + transformOrigin: "50% 50%", + force3D: true, + }); + gsap.set(heroMeta, { - y: 36, + y: 30, autoAlpha: 0, }); - if (!shouldPlayIntro) { - gsap.set(heroImageWrap, { scale: 1 }); + const revealHero = () => + gsap + .timeline({ defaults: { ease: "power4.out" } }) + .to(heroWordmark, { + yPercent: 0, + autoAlpha: 1, + duration: 1.18, + ease: "expo.out", + }) + .to( + heroProduct, + { + scale: 1, + y: 0, + autoAlpha: 1, + duration: 1.42, + ease: "expo.out", + }, + "<0.16" + ) + .to( + headlineLines, + { + yPercent: 0, + rotate: 0, + duration: 1.08, + stagger: 0.08, + }, + "<0.34" + ) + .to( + heroMeta, + { + y: 0, + autoAlpha: 1, + duration: 0.86, + stagger: 0.1, + }, + "<0.18" + ); + + if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) { + gsap.set(heroWordmark, { yPercent: 0, autoAlpha: 1 }); + gsap.set(heroProduct, { scale: 1, y: 0, autoAlpha: 1 }); gsap.set(headlineLines, { yPercent: 0, rotate: 0 }); gsap.set(heroMeta, { y: 0, autoAlpha: 1 }); gsap.set(overlay, { @@ -105,6 +174,16 @@ function LandingPage() { return; } + if (!shouldPlayIntro) { + gsap.set(overlay, { + yPercent: -100, + autoAlpha: 0, + display: "none", + }); + revealHero(); + return; + } + gsap.set(overlay, { yPercent: 0, autoAlpha: 1, display: "block" }); gsap.set(overlayText, { xPercent: 28, yPercent: 140, autoAlpha: 0 }); @@ -133,37 +212,7 @@ function LandingPage() { }, ">" ) - .to( - heroImageWrap, - { - scale: 1, - duration: 1.6, - ease: "power2.out", - }, - "<0.03" - ) - .to( - headlineLines, - { - yPercent: 0, - rotate: 0, - duration: 1.18, - stagger: 0.1, - ease: "power4.out", - }, - "<0.27" - ) - .to( - heroMeta, - { - y: 0, - autoAlpha: 1, - duration: 1.02, - stagger: 0.12, - ease: "power4.out", - }, - "<0.16" - ) + .add(revealHero(), "<0.1") .set(overlay, { display: "none" }); }, pageRef); @@ -385,8 +434,10 @@ function LandingPage() { heroImageRef={heroImageRef} setHeadlinePrimaryRef={setHeadlinePrimaryRef} setHeadlineSecondaryRef={setHeadlineSecondaryRef} + setWordmarkRef={setWordmarkRef} setDescriptionRef={setDescriptionRef} setActionsRef={setActionsRef} + setScrollRef={setScrollRef} overlayRef={overlayRef} overlayTextRef={overlayTextRef} /> diff --git a/parfum-shop/src/style/navbar.css b/parfum-shop/src/style/navbar.css index eb5b02d..93c1c04 100644 --- a/parfum-shop/src/style/navbar.css +++ b/parfum-shop/src/style/navbar.css @@ -218,6 +218,11 @@ .nav-theme-switch { padding-inline: 0.45rem; } + + .navbar--hero .nav-pill { + width: fit-content; + max-width: calc(100vw - 1.5rem); + } } @media (max-width: 390px) {