type Tone = "positive" | "negative" | "neutral"; type Cell = { text: string; tone?: Tone; code?: boolean; }; type Column = { name: string; highlight?: boolean; }; const COLUMNS: Column[] = [ { name: "OpenSEO", highlight: true }, { name: "DIY open-source repos" }, { name: "Data-pipeline tools" }, ]; const ROWS: { label: string; cells: Cell[] }[] = [ { label: "Setup", cells: [ { text: "Simple, guided onboarding", tone: "positive" }, { text: "~30 min in the Google Cloud console" }, { text: "Account + connector setup" }, ], }, { label: "Google Cloud project", cells: [ { text: "Not needed", tone: "positive" }, { text: "Required", tone: "negative" }, { text: "Usually not needed", tone: "positive" }, ], }, { label: "Price", cells: [ { text: "Free, no credits", tone: "positive" }, { text: "Free (your time + your own quota)" }, { text: "Paid or limited free tier", tone: "negative" }, ], }, { label: "Read-only and safe", cells: [ { text: "webmasters.readonly", tone: "positive", code: true }, { text: "Depends on the scopes you grant" }, { text: "Varies" }, ], }, { label: "Built for SEO", cells: [ { text: "Also does keyword, rank, and backlink research", tone: "positive", }, { text: "Search Console only", tone: "negative" }, { text: "Reporting and analytics focus" }, ], }, { label: "Self-host option", cells: [ { text: "Yes", tone: "positive" }, { text: "Yes", tone: "positive" }, { text: "No", tone: "negative" }, ], }, ]; export function ComparisonTable() { return (
))} {ROWS.map((row) => ( {row.cells.map((cell, i) => { const highlight = COLUMNS[i]?.highlight; return ( ); })} ))}
{COLUMNS.map((col) => ( {col.name}
{row.label}
); } function CellContent({ cell, highlight }: { cell: Cell; highlight?: boolean }) { const tone = cell.tone ?? "neutral"; const textClass = tone === "negative" ? "text-neutral-400" : highlight && tone === "positive" ? "font-medium text-neutral-900" : "text-neutral-700"; return (
{cell.code ? ( {cell.text} ) : ( cell.text )}
); } function ToneIcon({ tone }: { tone: Tone }) { if (tone === "positive") { return ( ); } if (tone === "negative") { return ( ); } return null; }