spb/company-atlas
Public
Python 66.3%
TypeScript 22.7%
JavaScript 8.6%
HTML 1.4%
CSS 0.7%
1'use client';2import { Plus, X } from 'lucide-react';3import { useRouter } from 'next/navigation';4import { useEffect, useState } from 'react';5import { clientApi } from '@/lib/client-api';6import { routes } from '@/lib/site';7import type { Suggestion } from '@/lib/types';89/** Add/remove companies on /company/compare via `/search/suggest` (2–6 slugs in the URL). */10export function ComparePicker({ slugs, names }: { slugs: string[]; names: Record<string, string> }) {11 const router = useRouter();12 const [q, setQ] = useState('');13 const [items, setItems] = useState<Suggestion[]>([]);14 useEffect(() => {15 if (q.trim().length < 1) {16 setItems([]);17 return;18 }19 const ctrl = new AbortController();20 const t = setTimeout(() => {21 clientApi22 .suggest(q.trim(), ctrl.signal)23 .then((r) => setItems(r.items.filter((s) => s.kind === 'company')))24 .catch(() => setItems([]));25 }, 120);26 return () => {27 clearTimeout(t);28 ctrl.abort();29 };30 }, [q]);31 const slugOf = (href: string) => href.replace(/^\/company\//, '').split('?')[0] ?? '';32 const add = (s: string) => {33 if (!s || slugs.includes(s) || slugs.length >= 6) return;34 router.push(routes.compare([...slugs, s]));35 setQ('');36 setItems([]);37 };38 const remove = (s: string) => router.push(routes.compare(slugs.filter((x) => x !== s)));39 return (40 <div className="flex flex-wrap items-center gap-2" data-compare-picker>41 {slugs.map((s) => (42 <span key={s} className="inline-flex h-10 items-center gap-1 border border-rule bg-surface pl-2.5 pr-0.5 text-sm">43 {names[s] ?? s}44 <button type="button" onClick={() => remove(s)} className="flex size-10 items-center justify-center text-ink-3 hover:text-danger" aria-label={`Remove ${names[s] ?? s}`}>45 <X className="size-3.5" aria-hidden />46 </button>47 </span>48 ))}49 {slugs.length < 6 && (50 <div className="relative">51 <label className="sr-only" htmlFor="compare-add">52 Add a company53 </label>54 <span className="flex min-h-10 items-center gap-1 border border-rule-strong bg-surface px-2">55 <Plus className="size-4 text-ink-3" aria-hidden />56 <input id="compare-add" value={q} onChange={(e) => setQ(e.target.value)} placeholder="Add company…" className="h-10 w-40 bg-transparent text-sm focus:outline-none" autoComplete="off" data-compare-input onKeyDown={(e) => e.key === 'Enter' && items[0] && add(slugOf(items[0].href))} />57 </span>58 {items.length > 0 && (59 <ul className="panel absolute left-0 top-full z-20 mt-1 w-64 py-1 shadow-lg" role="listbox">60 {items.slice(0, 8).map((s) => (61 <li key={s.href}>62 <button type="button" onClick={() => add(slugOf(s.href))} className="flex w-full items-center gap-2 px-3 py-2 text-left text-sm hover:bg-surface-2" role="option" aria-selected={false}>63 <span className="flex-1 truncate">{s.label}</span>64 <span className="truncate text-xs text-ink-3">{s.sublabel}</span>65 </button>66 </li>67 ))}68 </ul>69 )}70 </div>71 )}72 </div>73 );74}75