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%
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