feat: docs and ui tweaks

This commit is contained in:
DESKTOP-RTLN3BA\$punk 2026-07-06 19:26:35 -07:00
parent 64f2b4a6eb
commit 271a21aee6
103 changed files with 2161 additions and 2625 deletions

View file

@ -1,11 +1,11 @@
import {
IconBrandGoogle,
IconBrandGoogleMaps,
IconBrandReddit,
IconBrandYoutube,
IconWorldWww,
} from "@tabler/icons-react";
import type { ComponentType } from "react";
import {
GoogleMapsIcon,
GoogleSearchIcon,
RedditIcon,
WebIcon,
YouTubeIcon,
} from "./platform-icons";
/** Icon component that accepts a ``className`` (Tabler + Lucide both satisfy this). */
export type PlatformIcon = ComponentType<{ className?: string }>;
@ -36,13 +36,13 @@ export const PLAYGROUND_PLATFORMS: PlaygroundPlatform[] = [
{
id: "reddit",
label: "Reddit",
icon: IconBrandReddit,
icon: RedditIcon,
verbs: [{ name: "reddit.scrape", verb: "scrape", label: "Scrape" }],
},
{
id: "youtube",
label: "YouTube",
icon: IconBrandYoutube,
icon: YouTubeIcon,
verbs: [
{ name: "youtube.scrape", verb: "scrape", label: "Scrape" },
{ name: "youtube.comments", verb: "comments", label: "Comments" },
@ -51,7 +51,7 @@ export const PLAYGROUND_PLATFORMS: PlaygroundPlatform[] = [
{
id: "google_maps",
label: "Google Maps",
icon: IconBrandGoogleMaps,
icon: GoogleMapsIcon,
verbs: [
{ name: "google_maps.scrape", verb: "scrape", label: "Scrape" },
{ name: "google_maps.reviews", verb: "reviews", label: "Reviews" },
@ -60,13 +60,13 @@ export const PLAYGROUND_PLATFORMS: PlaygroundPlatform[] = [
{
id: "google_search",
label: "Google Search",
icon: IconBrandGoogle,
icon: GoogleSearchIcon,
verbs: [{ name: "google_search.scrape", verb: "scrape", label: "Scrape" }],
},
{
id: "web",
label: "Web",
icon: IconWorldWww,
icon: WebIcon,
verbs: [{ name: "web.crawl", verb: "crawl", label: "Crawl" }],
},
];

View file

@ -1,11 +1,28 @@
/** Formatting helpers shared by the playground runs table and runner output. */
import type { ScraperPricingMeter } from "@/contracts/types/scraper.types";
export function formatCost(costMicros: number | null | undefined): string {
if (costMicros == null) return "—";
if (costMicros === 0) return "Free";
return `$${(costMicros / 1_000_000).toFixed(4)}`;
}
/** One meter as a per-1k rate, e.g. 3500 micros/place -> "$3.50 / 1k places". */
export function formatRate(meter: ScraperPricingMeter): string {
const perThousand = (meter.micros_per_unit * 1000) / 1_000_000;
const dollars = Number.isInteger(perThousand)
? perThousand.toString()
: perThousand.toFixed(2);
return `$${dollars} / 1k ${meter.unit}s`;
}
/** A capability's full price line: "Free", one rate, or "rate + rate". */
export function formatPricing(pricing: ScraperPricingMeter[] | undefined): string {
if (!pricing || pricing.length === 0) return "Free";
return pricing.map(formatRate).join(" + ");
}
export function formatDuration(ms: number | null | undefined): string {
if (ms == null) return "—";
if (ms < 1000) return `${ms}ms`;

View file

@ -0,0 +1,29 @@
import Image from "next/image";
import { cn } from "@/lib/utils";
/**
* Full-color brand marks for the platform-native scraper verbs, served from
* `/public/connectors/*.svg` (same asset library the connector UI uses). Each
* is a `ComponentType<{ className?: string }>` so it drops into the playground
* catalog and the composer badge exactly like a Lucide/Tabler icon.
*/
function brandIcon(src: string, alt: string) {
return function BrandIcon({ className }: { className?: string }) {
return (
<Image
src={src}
alt={alt}
width={20}
height={20}
className={cn("select-none object-contain pointer-events-none", className)}
draggable={false}
/>
);
};
}
export const RedditIcon = brandIcon("/connectors/reddit.svg", "Reddit");
export const YouTubeIcon = brandIcon("/connectors/youtube.svg", "YouTube");
export const GoogleMapsIcon = brandIcon("/connectors/google-maps.svg", "Google Maps");
export const GoogleSearchIcon = brandIcon("/connectors/google-search.svg", "Google Search");
export const WebIcon = brandIcon("/connectors/web.svg", "Web");