SPB Git forge

spb/fetcha

Public
11commits 1branches 0releases
1.5 MBsize
maindefault branch
16 days agolast push
TypeScript 97.5% SQL 1.4% Python 0.8%
5.4 KB · 92 lines tsx
Raw Blame History
1import * as React from "react";2import { cn } from "@/lib/utils";34/** Dashed, animated connector. Vertical on small screens, horizontal from lg. Decorative only. */5function Flow({ className }: { className?: string }) {6  return (7    <div className={cn("flex shrink-0 items-center justify-center", className)} aria-hidden>8      {/* vertical (mobile) */}9      <svg className="h-9 w-4 lg:hidden" viewBox="0 0 16 36" fill="none">10        <line x1="8" y1="0" x2="8" y2="30" strokeWidth="1.5" strokeDasharray="4 4" className="stroke-accent animate-flow motion-reduce:animate-none" />11        <path d="M4 28l4 5 4-5" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" className="stroke-accent" />12      </svg>13      {/* horizontal (desktop) */}14      <svg className="hidden h-4 w-12 lg:block" viewBox="0 0 48 16" fill="none">15        <line x1="0" y1="8" x2="42" y2="8" strokeWidth="1.5" strokeDasharray="4 4" className="stroke-accent animate-flow motion-reduce:animate-none" />16        <path d="M40 4l5 4-5 4" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" className="stroke-accent" />17      </svg>18    </div>19  );20}2122function Node({ step, title, subtitle, children, className, highlight }: { step: string; title: string; subtitle: string; children?: React.ReactNode; className?: string; highlight?: boolean }) {23  return (24    <div className={cn("relative flex w-full flex-col rounded-lg border bg-bg-elevated p-4 shadow-xs", highlight ? "border-accent/50 ring-1 ring-accent/20" : "border-border", className)}>25      <div className="flex items-center justify-between gap-2">26        <span className="font-mono text-[11px] font-medium uppercase tracking-wide text-fg-subtle">{step}</span>27        {highlight ? <span className="size-1.5 rounded-full bg-accent" aria-hidden /> : null}28      </div>29      <div className="mt-1.5 text-[15px] font-semibold tracking-tight text-fg">{title}</div>30      <div className="mt-0.5 text-[12.5px] leading-snug text-fg-muted">{subtitle}</div>31      {children ? <div className="mt-3">{children}</div> : null}32    </div>33  );34}3536const NETWORKS: Array<{ label: string; live: boolean }> = [37  { label: "Datacenter", live: false },38  { label: "Residential", live: true },39  { label: "ISP", live: false },40  { label: "Mobile", live: false },41  { label: "Browser", live: true },42];4344export function ArchitectureDiagram() {45  return (46    <figure className="relative">47      <div className="absolute inset-0 -z-10 grid-bg opacity-70" aria-hidden />48      <div className="flex flex-col items-stretch lg:flex-row lg:items-center">49        <Node step="01 · Client" title="Your app" subtitle="Any language, any runtime. One HTTPS call.">50          <div className="rounded-md border border-border bg-bg-subtle px-2.5 py-1.5 font-mono text-[11.5px] text-fg-muted">51            <span className="text-accent">POST</span> /v1/fetch52            <br />53            <span className="text-fg-subtle">{"{"}</span> url, country <span className="text-fg-subtle">{"}"}</span>54          </div>55        </Node>56        <Flow />57        <Node step="02 · Edge" title="Fetcha API" subtitle="Auth, validation, rate limits, SSRF protection.">58          <ul className="space-y-1 text-[12px] text-fg-muted">59            <li className="flex items-center gap-2"><span className="size-1 rounded-full bg-fg-subtle" aria-hidden />Bearer key · scopes</li>60            <li className="flex items-center gap-2"><span className="size-1 rounded-full bg-fg-subtle" aria-hidden />Request ID on every call</li>61            <li className="flex items-center gap-2"><span className="size-1 rounded-full bg-fg-subtle" aria-hidden />Redacted logging</li>62          </ul>63        </Node>64        <Flow />65        <Node step="03 · Core" title="Smart routing" subtitle="Scores every route per domain, escalates on blocks, retries with a fresh IP." highlight className="lg:flex-[1.35]">66          <ul className="flex flex-wrap gap-1.5" aria-label="Network classes">67            {NETWORKS.map((n) => (68              <li key={n.label} className={cn("inline-flex items-center gap-1.5 rounded-md border px-2 py-0.5 text-[11.5px] font-medium", n.live ? "border-accent/40 bg-accent-soft text-accent" : "border-border bg-bg-subtle text-fg-subtle")}>69                <span className={cn("size-1.5 rounded-full", n.live ? "bg-accent" : "bg-border-strong")} aria-hidden />70                {n.label}71                {!n.live ? <span className="sr-only"> (coming soon)</span> : null}72              </li>73            ))}74          </ul>75          <p className="mt-2 text-[11px] text-fg-subtle">Residential and the managed browser are live today. Other classes are coming soon; <span className="font-mono">auto</span> resolves to the best available and escalates to the browser on JavaScript challenges.</p>76        </Node>77        <Flow />78        <Node step="04 · Target" title="Global web" subtitle="The page you asked for, from the geography you asked for.">79          <div className="rounded-md border border-border bg-bg-subtle px-2.5 py-1.5 font-mono text-[11.5px] text-fg-muted">80            <span className="text-success">200</span> example.com81            <br />82            <span className="text-fg-subtle">residential · CA · 842 ms</span>83          </div>84        </Node>85      </div>86      <figcaption className="mt-4 text-center text-[12.5px] text-fg-subtle">87        Your app → Fetcha API → Smart routing → Global web. You never manage proxies, IP pools or retries yourself.88      </figcaption>89    </figure>90  );91}92