diff --git a/README.md b/README.md index afb7a49..6fe0554 100644 --- a/README.md +++ b/README.md @@ -168,7 +168,12 @@ whisk/ │ ├── core/ # @usewhisk/core — framework-agnostic engine │ └── react/ # @usewhisk/react — components, hooks, provider ├── examples/ -│ └── playground/ # Drop-in showcase + playground +│ ├── playground/ # Drop-in showcase + every-prop playground +│ ├── ecommerce-checkout/ # Atelier Hibiscus — Next.js storefront +│ ├── donate-button/ # OpenForest — Vite donation page +│ ├── themed-saas/ # Steelpath Cloud — Next.js dark dashboard +│ ├── payroll-batch/ # Studio Fortune — Vite batch payouts +│ └── invoice-link/ # Studio Hibiscus — Next.js invoice links └── apps/ └── docs/ # Documentation site (Fumadocs) ``` @@ -180,6 +185,24 @@ Deeper design docs — engine boundary, state machine, fee model, resolvers, err --- +## Recipes + +Five reference integrations, each a themed mini-app. All run on testnet — +grab test USDC from the [Circle faucet](https://faucet.circle.com). + +| Recipe | What it shows | Live demo | +| ----------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------- | +| **E-commerce checkout** | Cart total + merchant address locked; the widget is confirm-and-pay | [demo](https://whisk-ecommerce-checkout.vercel.app/) | +| **Donate button** | Pinned treasury + preset amounts that seed `defaultAmount` | [demo](https://whisk-donate-button.vercel.app/) | +| **Themed SaaS** | `--whisk-*` overrides repaint the widget into a dark dashboard | [demo](https://whisk-themed-saas.vercel.app/) | +| **Payroll batch** | Widget remounts per payee, bridging treasury USDC to each one's chain | [demo](https://whisk-payroll-batch.vercel.app/) | +| **Invoice link** | A shareable URL opens a pre-filled, locked checkout | [demo](https://whisk-invoice-link.vercel.app/) | + +Source for each lives under `examples/`. They're starting points to clone and +adapt, not finished apps. + +--- + ## Supported chains | Network | Chain ID | Send | Bridge | Account types | diff --git a/apps/docs/src/components/marketing/recipes-showcase.tsx b/apps/docs/src/components/marketing/recipes-showcase.tsx index 0349523..f7e0af0 100644 --- a/apps/docs/src/components/marketing/recipes-showcase.tsx +++ b/apps/docs/src/components/marketing/recipes-showcase.tsx @@ -50,7 +50,7 @@ const RECIPES: Recipe[] = [ title: "E-commerce checkout", blurb: "Recipient + total + both chains are locked from the cart. The widget collapses to a confirm-and-pay surface so the buyer can't fat-finger it.", - href: "https://github.com/Signor1/whisk/tree/main/examples/ecommerce-checkout", + href: "https://whisk-ecommerce-checkout.vercel.app/", Shell: EcommerceShell, snippet: [ [b("<"), c("WhiskSend"), txt("")], @@ -68,7 +68,7 @@ const RECIPES: Recipe[] = [ title: "Donate button", blurb: "Treasury wallet and both chains are pinned. Donors pick from preset amounts the host renders above the widget; the selection seeds defaultAmount.", - href: "https://github.com/Signor1/whisk/tree/main/examples/donate-button", + href: "https://whisk-donate-button.vercel.app/", Shell: DonateShell, snippet: [ [ @@ -98,7 +98,7 @@ const RECIPES: Recipe[] = [ title: "Themed SaaS dashboard", blurb: "Override --whisk-* CSS variables once and the widget repaints to the dashboard's palette. The customer can pay from any chain; Whisk bridges to the treasury chain automatically.", - href: "https://github.com/Signor1/whisk/tree/main/examples/themed-saas", + href: "https://whisk-themed-saas.vercel.app/", Shell: SaasShell, snippet: [ [cm("// customer pays from their L2, treasury collects on Base")], @@ -117,7 +117,7 @@ const RECIPES: Recipe[] = [ title: "Payroll batch", blurb: "An admin tool that walks a list of payees. The widget remounts per row with the payee's address + amount locked, and bridges treasury USDC to whatever chain the payee prefers.", - href: "https://github.com/Signor1/whisk/tree/main/examples/payroll-batch", + href: "https://whisk-payroll-batch.vercel.app/", Shell: PayrollShell, snippet: [ [cm("// treasury on Base, payees collect on Polygon")], @@ -139,7 +139,7 @@ const RECIPES: Recipe[] = [ title: "Invoice payment link", blurb: "A shareable URL that opens a pre-filled checkout. Everything comes from the invoice record, including the source chain the client is paying from. Whisk bridges to the studio's home chain in one click.", - href: "https://github.com/Signor1/whisk/tree/main/examples/invoice-link", + href: "https://whisk-invoice-link.vercel.app/", Shell: InvoiceShell, snippet: [ [cm("// app/i/[id]/page.tsx")], diff --git a/apps/docs/src/content/docs/recipes/donate-button.mdx b/apps/docs/src/content/docs/recipes/donate-button.mdx index 9f81e1b..4eb6d18 100644 --- a/apps/docs/src/content/docs/recipes/donate-button.mdx +++ b/apps/docs/src/content/docs/recipes/donate-button.mdx @@ -74,6 +74,10 @@ onSuccess={async ({ quote, finalTxHash }) => { }} ``` +## Live demo + +[whisk-donate-button.vercel.app](https://whisk-donate-button.vercel.app/) — running on testnet. + ## Full source [`examples/donate-button`](https://github.com/Signor1/whisk/tree/main/examples/donate-button) diff --git a/apps/docs/src/content/docs/recipes/ecommerce-checkout.mdx b/apps/docs/src/content/docs/recipes/ecommerce-checkout.mdx index 2ae4d2f..ce8d499 100644 --- a/apps/docs/src/content/docs/recipes/ecommerce-checkout.mdx +++ b/apps/docs/src/content/docs/recipes/ecommerce-checkout.mdx @@ -92,6 +92,10 @@ export async function POST(req, { params }) { This step matters. Skipping it is how stores get drained. +## Live demo + +[whisk-ecommerce-checkout.vercel.app](https://whisk-ecommerce-checkout.vercel.app/) — running on testnet. + ## Full source [`examples/ecommerce-checkout`](https://github.com/Signor1/whisk/tree/main/examples/ecommerce-checkout) diff --git a/apps/docs/src/content/docs/recipes/invoice-link.mdx b/apps/docs/src/content/docs/recipes/invoice-link.mdx index 2d7d7cc..23cbd0f 100644 --- a/apps/docs/src/content/docs/recipes/invoice-link.mdx +++ b/apps/docs/src/content/docs/recipes/invoice-link.mdx @@ -108,6 +108,10 @@ export async function POST(req: Request) { Then the page verifies the signature before mounting the widget. If the sig doesn't match, show the invalid-link page. +## Live demo + +[whisk-invoice-link.vercel.app](https://whisk-invoice-link.vercel.app/) — running on testnet. + ## Full source [`examples/invoice-link`](https://github.com/Signor1/whisk/tree/main/examples/invoice-link) diff --git a/apps/docs/src/content/docs/recipes/payroll-batch.mdx b/apps/docs/src/content/docs/recipes/payroll-batch.mdx index 269b96d..4974a7f 100644 --- a/apps/docs/src/content/docs/recipes/payroll-batch.mdx +++ b/apps/docs/src/content/docs/recipes/payroll-batch.mdx @@ -75,6 +75,10 @@ from one payee to the next, the widget would keep the previous payee's state around. The `key` forces a fresh mount per row, so each payment starts from a clean form. +## Live demo + +[whisk-payroll-batch.vercel.app](https://whisk-payroll-batch.vercel.app/) — running on testnet. + ## Full source [`examples/payroll-batch`](https://github.com/Signor1/whisk/tree/main/examples/payroll-batch) diff --git a/apps/docs/src/content/docs/recipes/themed-saas.mdx b/apps/docs/src/content/docs/recipes/themed-saas.mdx index cf3f9f9..79a3d54 100644 --- a/apps/docs/src/content/docs/recipes/themed-saas.mdx +++ b/apps/docs/src/content/docs/recipes/themed-saas.mdx @@ -69,6 +69,10 @@ export default function PayoutsPage() { That's it. Every Whisk component (card, input, button, chips, step rail, banner, badge) picks up the new palette automatically. +## Live demo + +[whisk-themed-saas.vercel.app](https://whisk-themed-saas.vercel.app/) — running on testnet. + ## Full source [`examples/themed-saas`](https://github.com/Signor1/whisk/tree/main/examples/themed-saas) diff --git a/examples/donate-button/README.md b/examples/donate-button/README.md index e0248e6..5d0e3df 100644 --- a/examples/donate-button/README.md +++ b/examples/donate-button/README.md @@ -1,5 +1,7 @@ # whisk-example-donate-button +> **Live demo:** https://whisk-donate-button.vercel.app/ (testnet) + **OpenForest** — a reforestation NGO landing page with a public donor wall, annual-goal progress bar, three donation tiers (Seedling, Grove, Canopy), custom-amount fallback, and an active-projects showcase. diff --git a/examples/ecommerce-checkout/README.md b/examples/ecommerce-checkout/README.md index fb3dcb4..244b1bc 100644 --- a/examples/ecommerce-checkout/README.md +++ b/examples/ecommerce-checkout/README.md @@ -1,5 +1,7 @@ # whisk-example-ecommerce-checkout +> **Live demo:** https://whisk-ecommerce-checkout.vercel.app/ (testnet) + **Atelier Hibiscus** — an editorial DTC storefront with a 5-product catalog, multi-item cart, two-step checkout, and order confirmation. Pay-with-USDC at checkout via Whisk. diff --git a/examples/invoice-link/README.md b/examples/invoice-link/README.md index d7d5bfb..fdc2548 100644 --- a/examples/invoice-link/README.md +++ b/examples/invoice-link/README.md @@ -1,5 +1,7 @@ # whisk-example-invoice-link +> **Live demo:** https://whisk-invoice-link.vercel.app/ (testnet) + **Studio Hibiscus** — an invoice-link flow with two views: - `/` (customer view) — reads `?to=…&amount=…&chain=…&memo=…` from the diff --git a/examples/payroll-batch/README.md b/examples/payroll-batch/README.md index 5804433..926ccb3 100644 --- a/examples/payroll-batch/README.md +++ b/examples/payroll-batch/README.md @@ -1,5 +1,7 @@ # whisk-example-payroll-batch +> **Live demo:** https://whisk-payroll-batch.vercel.app/ (testnet) + **Studio Fortune** — a creative agency payroll tool. Three-step flow (review → dispatch → confirm), 6 payees on a claret/ivory editorial palette, progress bar that animates as each transfer settles. diff --git a/examples/playground/src/app/circle-cors-shim.ts b/examples/playground/src/app/circle-cors-shim.ts index dc00174..25cc08a 100644 --- a/examples/playground/src/app/circle-cors-shim.ts +++ b/examples/playground/src/app/circle-cors-shim.ts @@ -17,6 +17,23 @@ * other fetch — wagmi RPC calls, our own routes, analytics — passes * through untouched. */ + +/** + * True only when the URL's host is Circle's API (`api.circle.com` or any + * `*.circle.com` host). Parses the URL and checks the host rather than + * substring-matching, so the name can't be smuggled into a path or query + * string (e.g. `https://evil.com/?x=api.circle.com`). + */ +function isCircleApiUrl(url: string): boolean { + let host: string; + try { + host = new URL(url, window.location.href).hostname.toLowerCase(); + } catch { + return false; + } + return host === "circle.com" || host.endsWith(".circle.com"); +} + let installed = false; export function installCircleCorsShim() { @@ -37,7 +54,7 @@ export function installCircleCorsShim() { ? input.href : input.url; - if (!url.includes("api.circle.com")) { + if (!isCircleApiUrl(url)) { return originalFetch(input, init); } diff --git a/examples/themed-saas/README.md b/examples/themed-saas/README.md index d466276..798b1c5 100644 --- a/examples/themed-saas/README.md +++ b/examples/themed-saas/README.md @@ -1,5 +1,7 @@ # whisk-example-themed-saas +> **Live demo:** https://whisk-themed-saas.vercel.app/ (testnet) + **Steelpath Cloud** — a B2B treasury dashboard with sidebar nav, KPI cards, a scheduled-vendors table, recent settlements feed, and an activity log. Click any vendor row to fund their next payout via Whisk.