spb/worthdoing Public
Autonomous investigation agent that discovers, challenges, and ranks things genuinely worth doing — Claude + Firecrawl, Next.js 16, PostgreSQL
TypeScript 91.5%
SQL 5.8%
CSS 2.2%
1/**2 * WorthDoing.ai3 * Author: Simon-Pierre Boucher4 * Contact: contact@spboucher.ai5 * File: src/components/wd/OpportunityCard.tsx6 * Description: Opportunity card — Worth Score and evidence confidence shown as distinct figures, never blended.7 */8import Link from "next/link";9import { cn } from "@/lib/utils";1011export function WorthScore({12 score,13 confidence,14 size = "md",15}: {16 score: number | null;17 confidence: number | null;18 size?: "md" | "lg";19}) {20 const conf = confidence ?? 0;21 const confTone = conf >= 0.7 ? "text-verdict" : conf >= 0.45 ? "text-signal" : "text-rust";22 return (23 <div className="flex flex-col items-end">24 <span25 className={cn(26 "font-heading font-semibold leading-none text-ink tabular-nums",27 size === "lg" ? "text-5xl" : "text-3xl",28 )}29 >30 {score != null ? Math.round(score) : "—"}31 </span>32 <span className={cn("mt-1 font-mono text-[10px] uppercase tracking-wider", confTone)}>33 {confidence != null ? `${Math.round(conf * 100)}% evidence` : "unscored"}34 </span>35 </div>36 );37}3839export function OpportunityCard({40 id,41 title,42 summary,43 worthScore,44 evidenceConfidence,45 objective,46 hasReport = true,47}: {48 id: string;49 title: string;50 summary: string;51 worthScore: number | null;52 evidenceConfidence: number | null;53 objective?: string;54 hasReport?: boolean;55}) {56 return (57 <Link58 href={`/opportunity/${id}`}59 className="wd-enter group block rounded-xl border border-line bg-card p-5 transition-all hover:-translate-y-0.5 hover:border-verdict/40 hover:shadow-[0_8px_30px_-12px_rgba(22,107,73,0.25)]"60 >61 <div className="flex items-start justify-between gap-4">62 <div className="min-w-0">63 {objective && (64 <p className="mb-1 truncate font-mono text-[10px] uppercase tracking-wider text-ink-soft">65 {objective}66 </p>67 )}68 <h3 className="font-heading text-lg font-semibold leading-tight text-ink group-hover:text-verdict">69 {title}70 </h3>71 </div>72 <WorthScore score={worthScore} confidence={evidenceConfidence} />73 </div>74 <p className="mt-3 line-clamp-3 text-sm leading-relaxed text-ink-soft">{summary}</p>75 <p className="mt-3 font-mono text-[10px] uppercase tracking-wider text-ink-soft/70">76 {hasReport ? "read the full report →" : "report pending…"}77 </p>78 </Link>79 );80}81