SPB Git forge
28commits 1branches 0releases
7.7 MBsize
maindefault branch
10 days agolast push
Python 66.3% TypeScript 22.7% JavaScript 8.6% HTML 1.4% CSS 0.7%
2.7 KB · 54 lines tsx
Raw Blame History
1'use client';2import { Activity, Bookmark, Home, Search, Trophy } from 'lucide-react';3import Link from 'next/link';4import { usePathname } from 'next/navigation';5import { cn } from '@/lib/cn';6import { useOpenSearch } from './search-context';78/** Bottom tab bar (< lg): Home · Live · Search · Rankings · Watchlist (spec §87). Safe-area aware. */9export function MobileTabBar() {10  const pathname = usePathname();11  const openSearch = useOpenSearch();12  const isActive = (href: string) => (href === '/' ? pathname === '/' : pathname === href || pathname.startsWith(href + '/'));13  const cls = (active: boolean) => cn('flex h-full w-full flex-col items-center justify-center gap-0.5 text-[10.5px]', active ? 'text-accent' : 'text-ink-2');14  return (15    <nav aria-label="Primary (mobile)" className="safe-bottom fixed inset-x-0 bottom-0 z-[46] border-t border-rule bg-canvas/95 backdrop-blur-md lg:hidden">16      <ul className="grid h-[var(--tabbar-h)] grid-cols-5">17        <li className="min-w-0">18          <Link href="/" aria-current={isActive('/') ? 'page' : undefined} className={cls(isActive('/'))}>19            <Home size={21} aria-hidden strokeWidth={isActive('/') ? 2.25 : 1.75} />20            <span className="truncate">Home</span>21          </Link>22        </li>23        <li className="min-w-0">24          <Link href="/live" aria-current={isActive('/live') ? 'page' : undefined} className={cls(isActive('/live'))}>25            <span className="relative">26              <Activity size={21} aria-hidden strokeWidth={isActive('/live') ? 2.25 : 1.75} />27              <span className="dot absolute -right-1 -top-0.5 size-[6px]" aria-hidden />28            </span>29            <span className="truncate">Live</span>30          </Link>31        </li>32        <li className="min-w-0">33          <button type="button" onClick={openSearch} className={cls(false)} aria-label="Search">34            <Search size={21} aria-hidden strokeWidth={1.75} />35            <span className="truncate">Search</span>36          </button>37        </li>38        <li className="min-w-0">39          <Link href="/rankings" aria-current={isActive('/rankings') ? 'page' : undefined} className={cls(isActive('/rankings'))}>40            <Trophy size={21} aria-hidden strokeWidth={isActive('/rankings') ? 2.25 : 1.75} />41            <span className="truncate">Rankings</span>42          </Link>43        </li>44        <li className="min-w-0">45          <Link href="/watchlist" aria-current={isActive('/watchlist') ? 'page' : undefined} className={cls(isActive('/watchlist'))}>46            <Bookmark size={21} aria-hidden strokeWidth={isActive('/watchlist') ? 2.25 : 1.75} />47            <span className="truncate">Watchlist</span>48          </Link>49        </li>50      </ul>51    </nav>52  );53}54