HTML 77.2%
TypeScript 10.5%
Python 9.6%
JavaScript 2.5%
1'use client';2import { X } from 'lucide-react';3import Link from 'next/link';4import { usePathname } from 'next/navigation';5import { typeLabel } from '@/lib/site';6import { COMPARE_MAX, COMPARE_MIN, compareHref, useCompareTray } from './compare-store';78/**9 * Floating tray summary shown on listings while the visitor collects entities: "n selected · Compare →".10 * Fixed above the mobile tab bar (< md) and bottom-right on desktop. Hidden on /compare itself and when empty.11 */12export function CompareTrayBar() {13 const tray = useCompareTray();14 const pathname = usePathname();15 if (!tray.ready || tray.items.length === 0 || pathname === '/compare') return null;16 const can = tray.items.length >= COMPARE_MIN;17 return (18 <div role="status" aria-live="polite" className="fixed inset-x-2 bottom-[calc(var(--tabbar-h)+env(safe-area-inset-bottom,0px)+8px)] z-[44] md:inset-x-auto md:bottom-6 md:right-6">19 <div className="panel flex items-center gap-2 p-1.5 pl-3 shadow-lg">20 <p className="min-w-0 flex-1 text-sm text-ink-2">21 <span className="tnum font-medium text-ink">{tray.items.length}</span> / {COMPARE_MAX} {tray.type ? typeLabel(tray.type, true).toLowerCase() : 'selected'}22 <span className="hidden text-ink-3 sm:inline"> · {tray.items.map((i) => i.name).slice(0, 3).join(', ')}{tray.items.length > 3 ? ` +${tray.items.length - 3}` : ''}</span>23 </p>24 {can ? (25 <Link href={compareHref(tray.items)} className="inline-flex h-10 items-center bg-ink px-3 text-sm font-medium text-canvas hover:opacity-90">26 Compare →27 </Link>28 ) : (29 <span className="inline-flex h-10 items-center px-2 text-xs text-ink-3">Pick {COMPARE_MIN - tray.items.length} more</span>30 )}31 <button type="button" onClick={tray.clear} className="flex size-10 items-center justify-center text-ink-3 hover:text-ink" aria-label="Clear comparison tray">32 <X className="size-4" aria-hidden />33 </button>34 </div>35 </div>36 );37}38