172 lines
5.2 KiB
TypeScript
172 lines
5.2 KiB
TypeScript
'use client';
|
|
|
|
import { usePathname } from 'next/navigation';
|
|
import { useParlay } from '@/contexts/ParlayContext';
|
|
|
|
const TABS = [
|
|
{ id: 'home', label: 'Home', href: '/dashboard', icon: HomeIcon },
|
|
{ id: 'scan', label: 'Read', href: '/scan', icon: ScanIcon },
|
|
{ id: 'parlay', label: 'Parlay', href: null, icon: ParlayIcon },
|
|
{ id: 'ledger', label: 'Ledger', href: '/ledger', icon: LedgerIcon },
|
|
{ id: 'profile', label: 'Profile', href: '/profile', icon: ProfileIcon },
|
|
] as const;
|
|
|
|
// Pages where the bottom tab bar should stay hidden (auth flows, landing).
|
|
const HIDE_ON = new Set(['/login', '/signup', '/auth/callback', '/']);
|
|
|
|
export default function BottomTabBar() {
|
|
const pathname = usePathname() || '/';
|
|
const { open, legCount } = useParlay();
|
|
|
|
if (HIDE_ON.has(pathname)) return null;
|
|
|
|
return (
|
|
<nav
|
|
role="navigation"
|
|
aria-label="Primary"
|
|
className="mobile-tab-bar"
|
|
style={{
|
|
position: 'fixed',
|
|
bottom: 0,
|
|
left: 0,
|
|
right: 0,
|
|
height: 64,
|
|
zIndex: 40,
|
|
display: 'flex',
|
|
borderTop: '1px solid var(--border)',
|
|
background: 'rgba(10,10,15,0.92)',
|
|
backdropFilter: 'blur(16px)',
|
|
WebkitBackdropFilter: 'blur(16px)',
|
|
paddingBottom: 'env(safe-area-inset-bottom)',
|
|
}}
|
|
>
|
|
{TABS.map((t) => {
|
|
const active = t.href ? (pathname === t.href || pathname.startsWith(`${t.href}/`)) : false;
|
|
const color = active ? 'var(--grade-a)' : 'var(--text-secondary)';
|
|
const Icon = t.icon;
|
|
const isParlay = t.id === 'parlay';
|
|
const onClick = () => {
|
|
if (isParlay) open();
|
|
};
|
|
|
|
const inner = (
|
|
<div
|
|
style={{
|
|
flex: 1,
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
gap: 4,
|
|
color,
|
|
fontSize: 10,
|
|
fontWeight: 600,
|
|
textDecoration: 'none',
|
|
fontFamily: 'inherit',
|
|
border: 'none',
|
|
background: 'transparent',
|
|
cursor: 'pointer',
|
|
position: 'relative',
|
|
}}
|
|
>
|
|
<Icon color={color} />
|
|
<span>{t.label}</span>
|
|
{isParlay && legCount > 0 && (
|
|
<span
|
|
className="mono"
|
|
style={{
|
|
position: 'absolute',
|
|
top: 6,
|
|
right: 'calc(50% - 22px)',
|
|
minWidth: 18,
|
|
height: 18,
|
|
padding: '0 5px',
|
|
borderRadius: 999,
|
|
background: 'var(--grade-a)',
|
|
color: 'var(--bg-primary)',
|
|
fontSize: 10,
|
|
fontWeight: 800,
|
|
display: 'inline-flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
}}
|
|
>
|
|
{legCount}
|
|
</span>
|
|
)}
|
|
</div>
|
|
);
|
|
|
|
if (isParlay || !t.href) {
|
|
return (
|
|
<button key={t.id} onClick={onClick} style={{ flex: 1, background: 'transparent', border: 'none', padding: 0 }}>
|
|
{inner}
|
|
</button>
|
|
);
|
|
}
|
|
return (
|
|
<a key={t.id} href={t.href} style={{ flex: 1, padding: 0, textDecoration: 'none' }}>
|
|
{inner}
|
|
</a>
|
|
);
|
|
})}
|
|
|
|
<style jsx>{`
|
|
@media (min-width: 768px) {
|
|
:global(.mobile-tab-bar) {
|
|
display: none !important;
|
|
}
|
|
}
|
|
`}</style>
|
|
</nav>
|
|
);
|
|
}
|
|
|
|
// Lightweight inline SVG icons — keeps the bundle slim and avoids icon-lib install
|
|
function HomeIcon({ color }: { color: string }) {
|
|
return (
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
<path d="M3 12 12 3l9 9" />
|
|
<path d="M5 10v10h14V10" />
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
function ScanIcon({ color }: { color: string }) {
|
|
return (
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
<circle cx="11" cy="11" r="7" />
|
|
<path d="M21 21l-4.3-4.3" />
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
function ParlayIcon({ color }: { color: string }) {
|
|
return (
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
<rect x="3" y="4" width="18" height="4" rx="1" />
|
|
<rect x="3" y="10" width="18" height="4" rx="1" />
|
|
<rect x="3" y="16" width="18" height="4" rx="1" />
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
function LedgerIcon({ color }: { color: string }) {
|
|
return (
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
<path d="M4 4h16v16H4z" />
|
|
<path d="M4 9h16" />
|
|
<path d="M9 4v16" />
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
function ProfileIcon({ color }: { color: string }) {
|
|
return (
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
<circle cx="12" cy="8" r="4" />
|
|
<path d="M4 21c1.5-4 5-6 8-6s6.5 2 8 6" />
|
|
</svg>
|
|
);
|
|
}
|