rai-bench / src /components /Nav.tsx
rohanjaggi
fix: mobile responsiveness
fa3f2ca
Raw
History Blame Contribute Delete
3.94 kB
'use client'
import Image from 'next/image'
import { useEffect, useState, useCallback } from 'react'
const NAV_SECTIONS = ['criteria', 'leaderboard', 'about', 'insights'] as const
const NAV_LABELS: Record<string, string> = {
criteria: 'Overview',
leaderboard: 'Results',
about: 'Methodology',
insights: 'Insights',
}
export default function Nav({ modelCount, lastUpdated }: { modelCount: number; lastUpdated: string }) {
const [scrolled, setScrolled] = useState(false)
const [showTitle, setShowTitle] = useState(false)
const [activeSection, setActiveSection] = useState<string | null>(null)
const [menuOpen, setMenuOpen] = useState(false)
useEffect(() => {
const update = () => {
setScrolled(window.scrollY > 20)
const heroTitle = document.getElementById('hero-title')
if (heroTitle) {
const rect = heroTitle.getBoundingClientRect()
setShowTitle(rect.bottom < 0)
}
const scrollMid = window.scrollY + window.innerHeight * 0.35
let current: string | null = null
for (const id of NAV_SECTIONS) {
const el = document.getElementById(id)
if (el && el.offsetTop <= scrollMid) current = id
}
setActiveSection(current)
}
update()
window.addEventListener('scroll', update, { passive: true })
return () => window.removeEventListener('scroll', update)
}, [])
const closeMenu = useCallback(() => setMenuOpen(false), [])
return (
<>
<nav
className="nav-bar"
style={{ boxShadow: scrolled ? '0 1px 8px rgba(0,0,0,0.08)' : 'none' }}
>
<div className="nav-logo">
<Image
src="/govtech-logo.jpg"
alt="GovTech Singapore"
height={26}
width={104}
style={{ objectFit: 'contain', objectPosition: 'left center', width: 'auto', height: 26 }}
priority
/>
<span
className="nav-logo-sep"
style={{
opacity: showTitle ? 1 : 0,
transition: 'opacity 0.35s cubic-bezier(0.16, 1, 0.3, 1)',
}}
/>
<span
className="nav-logo-bench"
style={{
opacity: showTitle ? 1 : 0,
transform: showTitle ? 'translateY(0)' : 'translateY(4px)',
transition: 'opacity 0.35s cubic-bezier(0.16, 1, 0.3, 1), transform 0.35s cubic-bezier(0.16, 1, 0.3, 1)',
}}
>
Responsible AI Bench
</span>
</div>
<ul className="nav-links">
{NAV_SECTIONS.map(id => (
<li key={id}>
<a href={`#${id}`} className={activeSection === id ? 'nav-active' : ''}>
{NAV_LABELS[id]}
</a>
</li>
))}
</ul>
<button
className="nav-hamburger"
onClick={() => setMenuOpen(v => !v)}
aria-label="Toggle navigation menu"
aria-expanded={menuOpen}
>
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
{menuOpen ? (
<>
<line x1="6" y1="6" x2="18" y2="18" />
<line x1="6" y1="18" x2="18" y2="6" />
</>
) : (
<>
<line x1="4" y1="7" x2="20" y2="7" />
<line x1="4" y1="12" x2="20" y2="12" />
<line x1="4" y1="17" x2="20" y2="17" />
</>
)}
</svg>
</button>
</nav>
<div className={`nav-mobile-menu ${menuOpen ? 'open' : ''}`}>
{NAV_SECTIONS.map(id => (
<a
key={id}
href={`#${id}`}
className={activeSection === id ? 'nav-active' : ''}
onClick={closeMenu}
>
{NAV_LABELS[id]}
</a>
))}
</div>
</>
)
}