spb/company-atlas
Public
Python 66.3%
TypeScript 22.7%
JavaScript 8.6%
HTML 1.4%
CSS 0.7%
1'use client';2import Link from 'next/link';3import { ConfidenceBadge, CountryChip, EventTypeBadge, ImportanceMeter } from '@/components/ui/badges';4import { LiveAgo } from '@/components/ui/live';5import { cn } from '@/lib/cn';6import { eventStyle } from '@/lib/event-styles';7import { fmtTime, truncate } from '@/lib/format';8import { routes } from '@/lib/site';9import type { Event } from '@/lib/types';10import { useEventDrawer } from './event-drawer-context';1112/**13 * Dense feed row: hue bar · type chip · title (opens the evidence drawer) · company · importance · confidence · time.14 * `variant="feed"` is the live feed (fresh rows animate); `"table"` is the events list; `"timeline"` hides the company.15 */16export function EventRow({ event, fresh = false, selected = false, variant = 'feed', showCompany = true, className, id }: { event: Event; fresh?: boolean; selected?: boolean; variant?: 'feed' | 'table' | 'timeline'; showCompany?: boolean; className?: string; id?: string }) {17 const { open } = useEventDrawer();18 const s = eventStyle(event.event_type);19 const retracted = event.status === 'retracted';20 return (21 <li id={id} data-event-id={event.id} data-selected={selected || undefined} className={cn('group relative grid grid-cols-[3px_minmax(0,1fr)] gap-x-3 border-b border-rule', fresh && 'feed-new', selected && 'bg-surface-2', className)}>22 <span className="my-2 rounded-full" style={{ background: s.color }} aria-hidden />23 <div className={cn('min-w-0 py-2.5', variant === 'timeline' ? 'pr-1' : 'pr-0')}>24 <div className="flex flex-wrap items-center gap-x-2 gap-y-1">25 <EventTypeBadge type={event.event_type} subtype={variant !== 'feed' ? event.event_subtype : undefined} small />26 {showCompany && (27 <Link href={routes.company(event.company.slug)} className="max-w-[55%] truncate text-[13px] font-medium text-ink hover:text-accent">28 {event.company.display_name}29 </Link>30 )}31 {showCompany && <CountryChip code={event.company.country} />}32 <span className="ml-auto inline-flex items-center gap-2 text-[11px] text-ink-3">33 <ImportanceMeter importance={event.importance} />34 {variant === 'timeline' ? <span className="tnum">{fmtTime(event.detected_at)} UTC</span> : <LiveAgo at={event.detected_at} tick={variant === 'feed' ? 1000 : 30000} />}35 </span>36 </div>37 <button type="button" onClick={() => open(event)} className={cn('mt-1 block w-full text-left text-[14px] leading-snug text-ink hover:text-accent', retracted && 'line-through decoration-danger/60')} data-open-event>38 {event.title}39 </button>40 {event.summary && variant !== 'feed' && <p className="mt-0.5 text-[13px] leading-snug text-ink-2">{truncate(event.summary, 200)}</p>}41 <div className="mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-[11px] text-ink-3">42 <ConfidenceBadge label={event.confidence_label} />43 {event.old_value && event.new_value && (44 <span className="min-w-0 truncate">45 <span className="text-ink-3 line-through">{truncate(event.old_value, 28)}</span> → <span className="text-ink-2">{truncate(event.new_value, 28)}</span>46 </span>47 )}48 {event.origin !== 'deterministic' && <span className="uppercase tracking-wider">{event.origin}</span>}49 {retracted && <span className="text-danger">retracted</span>}50 <Link href={routes.event(event.id)} className="ml-auto opacity-0 transition-opacity group-hover:opacity-100 focus:opacity-100 hover:text-accent">51 Details →52 </Link>53 </div>54 </div>55 </li>56 );57}5859export function EventList({ events, className, variant = 'table', showCompany = true, emptyLabel = 'No monitored evidence available yet.' }: { events: Event[]; className?: string; variant?: 'feed' | 'table' | 'timeline'; showCompany?: boolean; emptyLabel?: string }) {60 if (!events.length) return <p className={cn('border border-dashed border-rule-strong px-4 py-8 text-center text-sm text-ink-3', className)}>{emptyLabel}</p>;61 return (62 <ul className={cn('border-t border-rule', className)}>63 {events.map((e) => (64 <EventRow key={e.id} event={e} variant={variant} showCompany={showCompany} />65 ))}66 </ul>67 );68}69