From 9246400da4a304f6513c14010b2f540e401a1972 Mon Sep 17 00:00:00 2001 From: Mustafa Date: Thu, 30 Jul 2026 13:02:11 +0300 Subject: [PATCH] feat: multi-phase hero texts + navbar after hero scroll --- components/Navigation.tsx | 29 ++-- components/sections/CloudRevealSection.tsx | 156 +++++++++++++-------- 2 files changed, 116 insertions(+), 69 deletions(-) diff --git a/components/Navigation.tsx b/components/Navigation.tsx index 5aaa647..3fb3b09 100644 --- a/components/Navigation.tsx +++ b/components/Navigation.tsx @@ -6,6 +6,7 @@ import Link from 'next/link' import Image from 'next/image' import { Menu, X, Phone } from 'lucide-react' import { cn } from '@/lib/utils' +import { SITE } from '@/lib/constants' interface NavigationProps { locale: string @@ -15,10 +16,16 @@ export default function Navigation({ locale }: NavigationProps) { const t = useTranslations('nav') const [menuOpen, setMenuOpen] = useState(false) const [scrolled, setScrolled] = useState(false) + const [visible, setVisible] = useState(false) useEffect(() => { - const handleScroll = () => setScrolled(window.scrollY > 80) - window.addEventListener('scroll', handleScroll) + const handleScroll = () => { + // Hero section 500vh — navbar scroll bittikten sonra görünür + const heroEnd = window.innerHeight * 4.5 + setVisible(window.scrollY > heroEnd) + setScrolled(window.scrollY > heroEnd + 80) + } + window.addEventListener('scroll', handleScroll, { passive: true }) return () => window.removeEventListener('scroll', handleScroll) }, []) @@ -36,6 +43,7 @@ export default function Navigation({ locale }: NavigationProps) {
Vesta Muğla @@ -71,6 +80,7 @@ export default function Navigation({ locale }: NavigationProps) { {/* Dil seçici */} {otherLocale} @@ -78,8 +88,8 @@ export default function Navigation({ locale }: NavigationProps) { {/* Telefon */} {t('phone')} @@ -90,6 +100,9 @@ export default function Navigation({ locale }: NavigationProps) { @@ -97,7 +110,7 @@ export default function Navigation({ locale }: NavigationProps) { {/* Mobile menu */} {menuOpen && ( -
+
{links.map((link) => ( ))}
- + {t('phone')} diff --git a/components/sections/CloudRevealSection.tsx b/components/sections/CloudRevealSection.tsx index 2ab0abe..27ad702 100644 --- a/components/sections/CloudRevealSection.tsx +++ b/components/sections/CloudRevealSection.tsx @@ -14,6 +14,21 @@ const TOTAL_FRAMES = 298 const FRAME_PATH = (n: number) => `/frames/ezgif-frame-${String(n).padStart(3, '0')}.jpg` +// Scroll aralığına göre opacity döndüren helper +function usePhaseOpacity( + scrollYProgress: ReturnType['scrollYProgress'], + inStart: number, + inEnd: number, + outStart: number, + outEnd: number +) { + return useTransform( + scrollYProgress, + [inStart, inEnd, outStart, outEnd], + [0, 1, 1, 0] + ) +} + export default function CloudRevealSection() { const t = useTranslations('hero') const prefersReducedMotion = useReducedMotion() @@ -29,17 +44,29 @@ export default function CloudRevealSection() { offset: ['start start', 'end end'], }) - // Tagline: ilk %15'te solar, aşağı kayar - const taglineOpacity = useTransform(scrollYProgress, [0, 0.15], [1, 0]) - const taglineY = useTransform(scrollYProgress, [0, 0.15], [0, 40]) - - // Progress bar: scroll'a göre genişler (0 → 100%) + // Progress bar const progressScaleX = useTransform(scrollYProgress, [0, 1], [0, 1]) + // --- Text phase opacities --- + // Phase 1: 0–15% → tagline (sol alt) + const phase1Opacity = useTransform(scrollYProgress, [0, 0.05, 0.12, 0.18], [0, 1, 1, 0]) + const phase1Y = useTransform(scrollYProgress, [0, 0.05], [20, 0]) + + // Phase 2: 20–45% → orta metin (merkez) + const phase2Opacity = useTransform(scrollYProgress, [0.20, 0.28, 0.40, 0.48], [0, 1, 1, 0]) + const phase2Y = useTransform(scrollYProgress, [0.20, 0.28], [30, 0]) + + // Phase 3: 50–72% → stat kartları (sağ) + const phase3Opacity = useTransform(scrollYProgress, [0.50, 0.57, 0.68, 0.75], [0, 1, 1, 0]) + const phase3Y = useTransform(scrollYProgress, [0.50, 0.57], [30, 0]) + + // Phase 4: 78–100% → CTA (merkez alt) + const phase4Opacity = useTransform(scrollYProgress, [0.78, 0.85, 0.95, 1], [0, 1, 1, 0]) + const phase4Y = useTransform(scrollYProgress, [0.78, 0.85], [30, 0]) + // Frame preload useEffect(() => { if (prefersReducedMotion) return - const images: HTMLImageElement[] = new Array(TOTAL_FRAMES) let loadedCount = 0 let cancelled = false @@ -59,7 +86,6 @@ export default function CloudRevealSection() { } images[i] = img } - return () => { cancelled = true } }, [prefersReducedMotion]) @@ -76,10 +102,7 @@ export default function CloudRevealSection() { useMotionValueEvent(scrollYProgress, 'change', (progress) => { if (!loaded) return - const frameIndex = Math.min( - Math.floor(progress * (TOTAL_FRAMES - 1)), - TOTAL_FRAMES - 1 - ) + const frameIndex = Math.min(Math.floor(progress * (TOTAL_FRAMES - 1)), TOTAL_FRAMES - 1) if (frameIndex !== currentFrameRef.current) { currentFrameRef.current = frameIndex drawFrame(frameIndex) @@ -102,17 +125,11 @@ export default function CloudRevealSection() { if (prefersReducedMotion) { return (
-
-
-

- Vesta Muğla -

-

- {t('tagline')} -

-

- {t('subtitle')} -

+
+
+

Vesta Muğla

+

{t('tagline')}

+

{t('subtitle')}

) @@ -123,63 +140,80 @@ export default function CloudRevealSection() {
{/* Canvas */} - + - {/* Gradient — alt kısım okunabilir olsun */} -
+ {/* Alt gradient */} +
{/* Loading */} {!loaded && (
-
+
-

- {loadProgress}% -

+

{loadProgress}%

)} - {/* Sol alt — tagline metni */} + {/* PHASE 1 — Sol alt: Ana tagline */} -

- Vesta Muğla -

-

+

Vesta Muğla

+

{t('tagline')}

-

- {t('subtitle')} -

+

{t('subtitle')}

- {/* Sağ alt — scroll göstergesi */} - {loaded && ( - - - {t('scroll')} - - - )} + {/* PHASE 2 — Merkez: Konum & kimlik */} + +
+

Muğla · Türkiye

+

+ Bulutların altında,
+ ormanın içinde +

+
+
+ - {/* Alt progress bar */} + {/* PHASE 3 — Sağ: Stat rakamları */} + + {[ + { value: '120', label: 'Konut' }, + { value: '15.000', label: 'm² Alan' }, + { value: '%60', label: 'Yeşil Alan' }, + ].map((stat) => ( +
+

{stat.value}

+

{stat.label}

+
+ ))} +
+ + {/* PHASE 4 — Merkez alt: CTA */} + +

Projeyi Keşfet

+

+ Hayalinizdeki yaşam
bir adım uzağınızda +

+
+ + + {/* Progress bar */}
- +