// The test page every run loads: http://localhost:5190/ is the page alone, /?w= the same page plus one widget's // snippet at the end of , where the vendors say to put it. &bar=1 adds a sticky "add to cart" bar (the phone test). // ws://127.0.0.1:5190/w/ws is the mock for Spookat's socket: it answers the first frame the way api.spookat.com does // for a site with no look, so the panel can open. Only a click reaches it. // bun run --cwd tools/widget-lab serve import { WIDGETS } from "./widgets"; export const PORT = Number(process.env.LAB_PORT ?? 5190); // another port lets two tests run side by side export const ORIGIN = `http://localhost:${PORT}`; const API = `http://127.0.0.1:${PORT}`; // another site than the page, like api.spookat.com is for a customer export const url = (id?: string, extra = "") => `${ORIGIN}/${id ? `?w=${id}${extra}` : extra ? `?${extra.slice(1)}` : ""}`; const PARAS = [ "We make small-batch ceramic mugs in a garage in Gdańsk. Every mug is thrown by hand, glazed twice and fired at 1,240 °C, so no two look the same.", "Orders ship within three working days. We pack in recycled paper and send tracking the moment the courier scans the box.", "Not sure about a size? The 300 ml mug fits a flat white, the 450 ml one a proper tea. Both go in the dishwasher and the microwave.", "Wholesale for cafés starts at 24 pieces. Custom glazes take four weeks, because the kiln is small and we are two people.", ]; export function page(id?: string, bar = false) { const w = WIDGETS.find((w) => w.id === id); if (id && !w) throw new Error(`no widget ${id}`); return ` mugs from a garage
garage mugs

hand-thrown mugs, fired twice, shipped in three days

${PARAS.map((p) => `

${p}

`).join("\n")}

shop mugs

${["300 ml, sand", "300 ml, ink", "450 ml, moss", "450 ml, rust"].map((n, i) => `
${29 + i * 4} zł${n}
`).join("")}

about

${PARAS.slice(0, 2).map((p) => `

${p}

`).join("\n")}

contact

Questions about an order? Write to us and we answer the same day.

${bar ? `
450 ml, moss · 37 zł
` : ""} ${w ? w.snippet.replace("{API}", API) : ""} `; } // what api.spookat.com sends first for a site with no look and no chat yet (ServerFrame "config", packages/shared) const CONFIG = { t: "config", cfg: {}, name: "localhost", branding: true, days: 30, mail: false }; export function serve() { return Bun.serve({ port: PORT, websocket: { open: (ws) => void ws.send(JSON.stringify(CONFIG)), message() {}, // the lab never sends a message }, fetch(req, server) { const u = new URL(req.url); if (u.pathname === "/w/ws") return server.upgrade(req) ? undefined : new Response("websocket only", { status: 426 }); if (u.pathname !== "/") return new Response("not found", { status: 404 }); return new Response(page(u.searchParams.get("w") ?? undefined, u.searchParams.has("bar")), { headers: { "content-type": "text/html; charset=utf-8", "cache-control": "no-store" }, }); }, }); } if (import.meta.main) { serve(); console.log(`test page on ${url()}, with a widget: ${url("spookat")}`); }