diff --git a/app/globals.css b/app/globals.css index a05fb5f..1951a70 100644 --- a/app/globals.css +++ b/app/globals.css @@ -101,14 +101,10 @@ body { animation: marqueeScroll 30s linear infinite; } -/* Scroll-driven progress bar (Safari 18 / iOS 18+) */ -@keyframes growX { - from { transform: scaleX(0); } - to { transform: scaleX(1); } -} +/* Scroll progress bar — updated via JS in Navbar */ .scroll-progress { - animation: growX linear both; - animation-timeline: scroll(root); + transform: scaleX(0); + will-change: transform; } @keyframes shine { diff --git a/components/sections/more-about.tsx b/components/sections/more-about.tsx index 90c3aba..8293bcb 100644 --- a/components/sections/more-about.tsx +++ b/components/sections/more-about.tsx @@ -42,7 +42,7 @@ export async function MoreAboutSection() { {/* Image Column */} -
+
Andrés Sánchez(null) const [loadFailed, setLoadFailed] = useState(false) - // Fetch only when the dialog is opened, not on page load + const handleClose = useCallback(() => { + setClosing(true) + setTimeout(() => { + setOpen(false) + setClosing(false) + }, 150) + }, []) + useEffect(() => { if (!open || content !== null || loadFailed) return fetch('/cv.md') @@ -38,10 +46,10 @@ export function CvDialog() { useEffect(() => { if (!open) return - const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') setOpen(false) } + const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') handleClose() } document.addEventListener('keydown', onKey) return () => document.removeEventListener('keydown', onKey) - }, [open]) + }, [open, handleClose]) return ( <> @@ -54,7 +62,7 @@ export function CvDialog() { {open && createPortal(
setOpen(false)} + onClick={handleClose} /> {/* Dialog */} -
+
{/* Header */}
Curriculum Vitae
diff --git a/components/ui/navbar.tsx b/components/ui/navbar.tsx index 28a02ff..1b5abbd 100644 --- a/components/ui/navbar.tsx +++ b/components/ui/navbar.tsx @@ -14,6 +14,7 @@ export function Navbar() { const [activeSection, setActiveSection] = useState("") const [menuOpen, setMenuOpen] = useState(false) + const progressRef = useRef(null) const breadTopOpenRef = useRef(null) const breadTopCloseRef = useRef(null) const breadBotOpenRef = useRef(null) @@ -33,6 +34,17 @@ export function Navbar() { return () => observer.disconnect() }, []) + useEffect(() => { + const el = progressRef.current + if (!el) return + const onScroll = () => { + const scrolled = window.scrollY / (document.documentElement.scrollHeight - window.innerHeight) + el.style.transform = `scaleX(${Math.min(1, Math.max(0, scrolled))})` + } + window.addEventListener("scroll", onScroll, { passive: true }) + return () => window.removeEventListener("scroll", onScroll) + }, []) + useEffect(() => { const onResize = () => { if (window.innerWidth >= 768) setMenuOpen(false) } window.addEventListener("resize", onResize, { passive: true }) @@ -67,8 +79,7 @@ export function Navbar() { Skip to content - {/* Scroll Progress Bar — CSS scroll-driven, no JS */} -
+