SPB Git

spb/search-box Public

Agentic web research engine — hypotheses, verbatim evidence, contradictions, sourced answers streamed live. Claude Opus 5 + Firecrawl + PostgreSQL.

TypeScript 76.9% CSS 18.7% SQL 2.1% JavaScript 1.8% Shell 0.5%
4.3 KB · 174 lines tsx
Raw Blame History
1/**2 * Search-box.ai3 * Author: Simon-Pierre Boucher4 * Contact: contact@spboucher.ai5 * File: apps/web/components/Pastille.tsx6 * Description: Hand-made icon pastilles — one custom SVG glyph per tool/event type.7 */89import type { JSX } from "react";1011export type PastilleKind =12  | "plan"13  | "search"14  | "fetch"15  | "read"16  | "claim"17  | "belief"18  | "evidence"19  | "contradiction"20  | "thought"21  | "synthesis"22  | "done"23  | "failed"24  | "source"25  | "confidence";2627/** All glyphs are drawn on a 24×24 grid, stroke 1.8, round caps — one visual family. */28const GLYPHS: Record<PastilleKind, JSX.Element> = {29  // branching trunk — the plan grows outward30  plan: (31    <>32      <path d="M12 21v-8" />33      <path d="M12 13c0-4-3.5-4.5-6-7" />34      <path d="M12 13c0-4 3.5-4.5 6-7" />35      <circle cx="6" cy="5.5" r="1.6" />36      <circle cx="18" cy="5.5" r="1.6" />37      <circle cx="12" cy="21" r="1.2" fill="currentColor" stroke="none" />38    </>39  ),40  search: (41    <>42      <circle cx="10.5" cy="10.5" r="5.7" />43      <path d="M14.8 14.8L20 20" />44    </>45  ),46  // page pulled down into the tray47  fetch: (48    <>49      <path d="M12 3v11" />50      <path d="M8 10l4 4 4-4" />51      <path d="M4 17v1.6A2.4 2.4 0 0 0 6.4 21h11.2a2.4 2.4 0 0 0 2.4-2.4V17" />52    </>53  ),54  // open book55  read: (56    <>57      <path d="M12 6c-2-1.5-4.6-2.1-8-2.1v14.3c3.4 0 6 .6 8 2.1 2-1.5 4.6-2.1 8-2.1V3.9c-3.4 0-6 .6-8 2.1z" />58      <path d="M12 6v14" />59    </>60  ),61  // hypothesis flask62  claim: (63    <>64      <path d="M9.2 3h5.6" />65      <path d="M10 3v5.2L4.8 17a2.6 2.6 0 0 0 2.3 3.9h9.8a2.6 2.6 0 0 0 2.3-3.9L14 8.2V3" />66      <path d="M7.5 14.5h9" />67    </>68  ),69  // gauge — belief updated70  belief: (71    <>72      <path d="M4.5 16a7.5 7.5 0 0 1 15 0" />73      <path d="M12 16l3.6-4.4" />74      <circle cx="12" cy="16" r="1.5" fill="currentColor" stroke="none" />75    </>76  ),77  // double quote78  evidence: (79    <>80      <path81        d="M5.5 15.5c0-4 1.8-6.6 4.5-7.5l.6 1.5c-1.5.7-2.3 1.9-2.5 3.2H10v5H5.5v-2.2zM13.5 15.5c0-4 1.8-6.6 4.5-7.5l.6 1.5c-1.5.7-2.3 1.9-2.5 3.2H18v5h-4.5v-2.2z"82        fill="currentColor"83        stroke="none"84      />85    </>86  ),87  // bolt — evidence collides88  contradiction: (89    <>90      <path d="M13 2.5L4.5 13.5H11l-1.5 8L18 10.5h-6.5z" fill="currentColor" stroke="none" />91    </>92  ),93  // speech bubble94  thought: (95    <>96      <path d="M4 7a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H9.5L4.8 20z" />97      <circle cx="9" cy="10" r="0.9" fill="currentColor" stroke="none" />98      <circle cx="12.5" cy="10" r="0.9" fill="currentColor" stroke="none" />99      <circle cx="16" cy="10" r="0.9" fill="currentColor" stroke="none" />100    </>101  ),102  // pen nib — writing the answer103  synthesis: (104    <>105      <path d="M5 21l1.8-5.6L16 6.2l3.4 3.4-9.2 9.2z" />106      <path d="M16 6.2l1.4-1.4a2.4 2.4 0 0 1 3.4 3.4L19.4 9.6" />107      <path d="M6.8 15.4l3.4 3.4" />108    </>109  ),110  done: (111    <>112      <circle cx="12" cy="12" r="8.5" />113      <path d="M8 12.4l2.7 2.7L16.4 9" />114    </>115  ),116  failed: (117    <>118      <path d="M12 3.5L21.5 20h-19z" />119      <path d="M12 10v4.5" />120      <circle cx="12" cy="17.2" r="1" fill="currentColor" stroke="none" />121    </>122  ),123  // layered stack — a source124  source: (125    <>126      <path d="M12 3.5l8.5 4.5L12 12.5 3.5 8z" />127      <path d="M3.5 12.5L12 17l8.5-4.5" />128      <path d="M3.5 16.5L12 21l8.5-4.5" />129    </>130  ),131  confidence: (132    <>133      <path d="M4.5 16a7.5 7.5 0 0 1 15 0" />134      <path d="M12 16l3.6-4.4" />135      <circle cx="12" cy="16" r="1.5" fill="currentColor" stroke="none" />136    </>137  )138};139140export function Glyph({ kind, size = 15 }: { kind: PastilleKind; size?: number }) {141  return (142    <svg143      width={size}144      height={size}145      viewBox="0 0 24 24"146      fill="none"147      stroke="currentColor"148      strokeWidth="1.8"149      strokeLinecap="round"150      strokeLinejoin="round"151      aria-hidden152    >153      {GLYPHS[kind]}154    </svg>155  );156}157158/** Colored disc + glyph. `spin` adds the working shimmer ring. */159export function Pastille({160  kind,161  spinning = false,162  size = "md"163}: {164  kind: PastilleKind;165  spinning?: boolean;166  size?: "sm" | "md";167}) {168  return (169    <span className={`pastille pk-${kind} ps-${size} ${spinning ? "spinning" : ""}`}>170      <Glyph kind={kind} size={size === "sm" ? 12 : 15} />171    </span>172  );173}174