SPB Git forge

spb/ai-atlas

Public
41commits 1branches 0releases
4.6 MBsize
maindefault branch
12 days agolast push
HTML 77.2% TypeScript 10.5% Python 9.6% JavaScript 2.5%
2.2 KB · 40 lines tsx
Raw Blame History
1'use client';2import { Check, Plus } from 'lucide-react';3import { cn } from '@/lib/cn';4import { COMPARE_MAX, type TrayItem, trayType, useCompareTray } from './compare-store';56/**7 * Small toggle that adds/removes an entity from the compare tray (localStorage-backed, mirrored into `/compare?ids=`).8 * `size="sm"` for table rows (still a ≥ 44 px hit area through padding on touch), default for entity headers.9 * Renders a neutral placeholder before hydration so server and client markup match.10 */11export function CompareButton({ e, size = 'md', className, label = 'Compare' }: { e: TrayItem | { slug: string; name: string; entity_type: string; organization?: { name: string } | null }; size?: 'sm' | 'md'; className?: string; label?: string }) {12  const tray = useCompareTray();13  const item: TrayItem = { slug: e.slug, name: e.name, entity_type: e.entity_type, organization: typeof e.organization === 'string' || e.organization === null || e.organization === undefined ? (e.organization as string | null | undefined) : e.organization.name };14  const on = tray.ready && tray.has(item.slug);15  const otherType = tray.ready && tray.type !== null && tray.type !== trayType(item.entity_type) && !on;16  const full = tray.ready && tray.full && !on;17  const title = on ? 'Remove from comparison' : otherType ? `Start a new ${item.entity_type} comparison (replaces the current tray)` : full ? `The tray holds at most ${COMPARE_MAX} items` : 'Add to comparison';18  return (19    <button20      type="button"21      onClick={() => {22        if (full) return;23        tray.toggle(item);24      }}25      aria-pressed={on}26      title={title}27      disabled={full}28      className={cn(29        'inline-flex shrink-0 items-center gap-1 border text-xs font-medium whitespace-nowrap transition-colors disabled:cursor-not-allowed disabled:opacity-40',30        size === 'sm' ? 'h-7 px-1.5' : 'h-9 px-2.5 text-sm',31        on ? 'border-accent bg-accent-soft text-accent' : 'border-rule text-ink-2 hover:border-rule-strong hover:text-ink',32        className,33      )}34    >35      {on ? <Check className={size === 'sm' ? 'size-3' : 'size-3.5'} aria-hidden /> : <Plus className={size === 'sm' ? 'size-3' : 'size-3.5'} aria-hidden />}36      <span>{on ? 'Comparing' : label}</span>37    </button>38  );39}40