From 955316bb521408e0e8ebd14702fbe2249c5da050 Mon Sep 17 00:00:00 2001 From: Shan Usmani Date: Thu, 23 Jul 2026 03:10:59 +0530 Subject: [PATCH 1/2] feat(a11y): add scroll-progress bar + normalize typography letter-spacing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add scroll-progress bar at header bottom edge with cyan accent glow - Bar fills left-to-right proportional to scroll position (0%→100%) - Uses GPU-friendly transform:scaleX() for smooth animation - Respects prefers-reduced-motion (disables transition) - Normalize letter-spacing to 0.08em across nav links, badge, stat labels, widget labels, section headers - Optically align triangle logo mark with DEVTRACK wordmark via translate-y Closes #3222 --- src/app/globals.css | 29 ++++++++++++++++++++++++++ src/components/AppNavbar.tsx | 23 +++++++++++++++++--- src/components/landing/LandingPage.tsx | 12 +++++------ 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/app/globals.css b/src/app/globals.css index 3116f302f..bd7bc1656 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -761,6 +761,35 @@ body { .animate-shimmer { animation: shimmer-slide 1.5s infinite; } +/* ───────────────────────────────────────── + SCROLL PROGRESS BAR + ───────────────────────────────────────── */ +.scroll-progress-track { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 2px; + background: transparent; + z-index: 10; +} + +.scroll-progress-bar { + width: 100%; + height: 100%; + background: var(--accent); + transform-origin: left; + transform: scaleX(0); + transition: transform 0.1s linear; + box-shadow: 0 0 8px var(--accent), 0 0 16px var(--accent); +} + +@media (prefers-reduced-motion: reduce) { + .scroll-progress-bar { + transition: none !important; + } +} + /* Mouse spotlight enhancement for visibility on all backgrounds */ .lnd-root .mouse-spotlight { pointer-events: none; diff --git a/src/components/AppNavbar.tsx b/src/components/AppNavbar.tsx index 24d38a914..c04203c74 100644 --- a/src/components/AppNavbar.tsx +++ b/src/components/AppNavbar.tsx @@ -31,6 +31,7 @@ export default function AppNavbar() { const { data: session, status } = useSession(); const [mobileOpen, setMobileOpen] = useState(false); const [scrolled, setScrolled] = useState(false); + const [scrollProgress, setScrollProgress] = useState(0); const handleAnchorClick = (e: React.MouseEvent, href: string) => { const hashIndex = href.indexOf("#"); @@ -46,7 +47,12 @@ export default function AppNavbar() { useEffect(() => { setMobileOpen(false); }, [pathname]); useEffect(() => { - const fn = () => setScrolled(window.scrollY > 20); + const fn = () => { + setScrolled(window.scrollY > 20); + const scrollTop = window.scrollY; + const docHeight = document.documentElement.scrollHeight - window.innerHeight; + setScrollProgress(docHeight > 0 ? Math.min(scrollTop / docHeight, 1) : 0); + }; fn(); window.addEventListener("scroll", fn, { passive: true }); return () => window.removeEventListener("scroll", fn); @@ -98,7 +104,7 @@ export default function AppNavbar() { className="group inline-flex items-center gap-2.5 select-none transition-transform duration-300 hover:scale-[1.02]" style={{ fontFamily: MONO }} > - + @@ -115,7 +121,7 @@ export default function AppNavbar() { key={item.href} href={item.href} onClick={(e) => handleAnchorClick(e, item.href)} - className="relative px-3 py-2 text-[12px] font-medium transition-colors duration-150" + className="relative px-3 py-2 text-[12px] font-medium tracking-[0.08em] transition-colors duration-150" style={{ fontFamily: MONO, color: active ? "var(--accent)" : "var(--muted-foreground)", @@ -192,6 +198,17 @@ export default function AppNavbar() { + {/* Scroll progress bar */} +