Sessions 5-7a: 955 tests, deployment ready

This commit is contained in:
Kev
2026-06-08 18:35:13 -04:00
parent 06b82624a2
commit 1fa04dc776
371 changed files with 49366 additions and 955 deletions
+259
View File
@@ -0,0 +1,259 @@
'use client';
import { useState } from 'react';
import { useAuth } from '@/contexts/AuthContext';
import Wordmark from '@/components/Wordmark';
import NotificationBell from '@/components/NotificationBell';
const NAV_LINKS = [
{ label: 'Read', href: '/scan' },
{ label: 'Tracker', href: '/tracker' },
{ label: 'Ledger', href: '/ledger' },
{ label: 'Pricing', href: '/#pricing' },
{ label: 'Blog', href: '/blog' },
];
export default function Nav() {
const { user, tier, scansRemaining, signOut } = useAuth();
const [mobileOpen, setMobileOpen] = useState(false);
const [menuOpen, setMenuOpen] = useState(false);
return (
<nav
style={{
position: 'fixed',
top: 0,
left: 0,
right: 0,
zIndex: 50,
height: 64,
borderBottom: '1px solid var(--border)',
background: 'rgba(10, 10, 15, 0.85)',
backdropFilter: 'blur(12px)',
WebkitBackdropFilter: 'blur(12px)',
}}
>
<div
style={{
maxWidth: 1280,
margin: '0 auto',
padding: '0 24px',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
gap: 24,
}}
>
<a
href="/"
style={{ color: 'var(--text-0)', textDecoration: 'none', display: 'inline-flex', alignItems: 'center' }}
aria-label="VYNDR — home"
>
<Wordmark size={22} />
</a>
<div className="nav-desktop" style={{ display: 'none', gap: 28, alignItems: 'center' }}>
{NAV_LINKS.map((l) => (
<a
key={l.href}
href={l.href}
style={{
fontSize: 14,
color: 'var(--text-secondary)',
textDecoration: 'none',
transition: 'color 200ms ease',
}}
onMouseEnter={(e) => (e.currentTarget.style.color = 'var(--text-primary)')}
onMouseLeave={(e) => (e.currentTarget.style.color = 'var(--text-secondary)')}
>
{l.label}
</a>
))}
{user ? (
<div style={{ position: 'relative', display: 'inline-flex', alignItems: 'center', gap: 10 }}>
{scansRemaining != null && tier === 'free' && (
<span
className="mono"
style={{
fontSize: 12,
color: scansRemaining <= 1 ? 'var(--grade-c)' : 'var(--text-secondary)',
}}
>
{scansRemaining}/5 reads · MO
</span>
)}
<NotificationBell />
<button
onClick={() => setMenuOpen((o) => !o)}
aria-haspopup="menu"
aria-expanded={menuOpen}
style={{
width: 36,
height: 36,
borderRadius: 999,
background: 'var(--bg-elevated)',
border: '1px solid var(--border-focus)',
color: 'var(--text-primary)',
cursor: 'pointer',
fontFamily: 'inherit',
fontWeight: 600,
}}
>
{user.email?.charAt(0).toUpperCase()}
</button>
{menuOpen && (
<div
role="menu"
className="surface-elevated"
style={{
position: 'absolute',
right: 0,
top: 'calc(100% + 8px)',
minWidth: 220,
padding: 8,
}}
>
<div style={{ padding: '8px 12px', borderBottom: '1px solid var(--border)' }}>
<div style={{ fontSize: 12, color: 'var(--text-tertiary)' }}>Signed in as</div>
<div style={{ fontSize: 13, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis' }}>
{user.email}
</div>
<div className="mono" style={{ marginTop: 6, fontSize: 11, color: 'var(--grade-a)', textTransform: 'uppercase' }}>
{tier} tier
</div>
</div>
{tier === 'free' && (
<a
href="/#pricing"
role="menuitem"
style={{ display: 'block', padding: '10px 12px', fontSize: 13, color: 'var(--text-primary)', textDecoration: 'none' }}
>
Upgrade $14.99/mo
</a>
)}
<button
onClick={() => {
void signOut();
setMenuOpen(false);
}}
role="menuitem"
style={{
width: '100%',
textAlign: 'left',
padding: '10px 12px',
background: 'transparent',
border: 'none',
color: 'var(--text-secondary)',
fontSize: 13,
cursor: 'pointer',
fontFamily: 'inherit',
}}
>
Log out
</button>
</div>
)}
</div>
) : (
<a href="/login" className="btn-primary" style={{ padding: '8px 16px', fontSize: 13 }}>
Log In
</a>
)}
</div>
<button
className="nav-mobile-toggle"
aria-label="Toggle menu"
aria-expanded={mobileOpen}
onClick={() => setMobileOpen((o) => !o)}
style={{
display: 'flex',
background: 'transparent',
border: '1px solid var(--border)',
borderRadius: 8,
padding: 8,
color: 'var(--text-primary)',
cursor: 'pointer',
}}
>
{mobileOpen ? '×' : '≡'}
</button>
</div>
{mobileOpen && (
<div
className="nav-mobile-panel"
style={{
borderTop: '1px solid var(--border)',
background: 'var(--bg-primary)',
padding: 16,
}}
>
<div style={{ display: 'grid', gap: 4 }}>
{NAV_LINKS.map((l) => (
<a
key={l.href}
href={l.href}
onClick={() => setMobileOpen(false)}
style={{
padding: '12px 16px',
fontSize: 15,
color: 'var(--text-primary)',
textDecoration: 'none',
borderRadius: 8,
}}
>
{l.label}
</a>
))}
{user ? (
<button
onClick={() => {
void signOut();
setMobileOpen(false);
}}
style={{
textAlign: 'left',
padding: '12px 16px',
fontSize: 15,
color: 'var(--text-secondary)',
background: 'transparent',
border: 'none',
cursor: 'pointer',
fontFamily: 'inherit',
}}
>
Log out
</button>
) : (
<a
href="/login"
className="btn-primary"
style={{ marginTop: 8, padding: 12 }}
onClick={() => setMobileOpen(false)}
>
Log In
</a>
)}
</div>
</div>
)}
<style jsx>{`
@media (min-width: 768px) {
:global(.nav-desktop) {
display: flex !important;
}
:global(.nav-mobile-toggle) {
display: none !important;
}
:global(.nav-mobile-panel) {
display: none !important;
}
}
`}</style>
</nav>
);
}