Skip to content

Shop elements: cart, product-list, product-page - #35

Merged
ecropolis merged 2 commits into
mainfrom
claude/cart-element
Oct 8, 2026
Merged

ecropolis merged 2 commits into
mainfrom
claude/cart-element

Conversation

@ecropolis

Copy link
Copy Markdown
Owner

Three elements for the Superhero Shop add-on ("Pieces to build" item 2 in the shop design note). They are built to the Worker's public contract in ecropolis/SuperheroShop PR #1 (claude/worker-stub, not yet merged or deployed).

  • cart: a cart button with its count and a drawer (a native <dialog>, copied from off-canvas's pattern).
    • It is kept in localStorage per shop: at most 20 lines, 1 to 20 of each.
    • It re-checks stock on open and before checkout, and asks ship or pickup.
    • It POSTs ids and quantities with a fresh crypto.randomUUID() key, then redirects to Square.
    • A 409 short clamps the line and says so. A 503 reads "This shop is closed for the moment." A network failure is one sentence.
  • product-list: a card grid built at deploy, with a from-price and sized lazy images. Sold out shows from a build-time map or one optional browser stock check.
  • product-page: images, a plain-text description, a variation radio group whose price follows the choice, quantity, and add to cart through the cart's attribute contract. It emits Product JSON-LD with one Offer per variation.
  • fetchCatalog(site): in src/library/product-list/fetchCatalog.ts. It validates the catalogue and throws one sentence, so a bad catalogue fails the build.
  • CSP: the site needs connect-src https://shop.superherotech.ai, plus img-src for Square's image host.

All three are in "Offers & conversion". Their aka lists name WooCommerce, the Shopify Buy Button, Ecwid and Square Online.

Checks

scripts/check-shop.mjs is added to npm run check. It covers:

  • the cart's rules, run from the source against a fake Worker: caps, cleaning stored data, money, no price in any request, a fresh key per attempt, the 409 clamp, and the 503 and network sentences;
  • the built drawer's accessibility rules on three pages;
  • the product-list cards;
  • the Product JSON-LD shape and escaping;
  • fetchCatalog.

It catches 38 of 38 planted faults. The full chain passes:

check ok: 46 elements, 46 pages built, 30 with asks.
check-shop ok: … 38/38 mutants caught.

I also walked it in a browser at desktop and phone width. That pass found three bugs, all fixed in the second commit:

  • the cart's script-built lines got no styles;
  • the "Added" flash wiped the button's markup;
  • radio labels ran together in the accessible name.

The website builds against this branch (ELEMENTS_SOURCE, exit 0) and has the three new /elements/ pages. Demos show the JSON-LD as text instead of emitting it, so superherotech.ai publishes no Product markup for a fake product.

Contract fields relied on

Route Fields
GET /v1/shops/:site/catalog currency, products[].id, slug, name, description, images[], variations[].id, name, price_cents, tracked
GET /v1/shops/:site/stock?ids= { [variationId]: number | null }, where null means untracked
POST /v1/shops/:site/checkout the body { items: [{ variationId, quantity }], fulfillment, pickupPoint?, idempotencyKey }; then 200 { url }, 409 { error: "short", short: [{ variationId, available }] }, 400 { error: "unknown_variation", ids }, 400 bad_pickup_point and shipping_unavailable, 403, 429, 503 shop_closed

Not defined by the Worker's README

I read these from the Worker's source instead. Worth adding to its README before it merges:

  • description format. The README doesn't say. The code passes Square's description field through as plain text and never returns HTML, so the product page renders it as text.
  • Stock ids left out. An id outside the visible category is left out of the /stock answer. Only a code comment says so. The cart treats a missing id as "no longer sold" and removes the line.
  • Stock limits and errors. /stock takes at most 100 ids, and its error bodies are validation_failed, the openShop reasons, and 502 stock_unavailable. None of that is in the README.
  • Stock and site builds. /stock answers only the shop's own origins, so a site build cannot fetch it. That is why product-list's build-time stock prop is mainly for fixtures.
  • Shipping and pickup settings. There is no public route for flat shipping, the free-shipping threshold or pickup points. The site copies them into props by hand, so the drawer's estimate can drift from the Worker's real fee when a seller changes them. A public read of those three fields would fix that.
  • Pickup point shape. { id, name, details? } is in types.ts, not the README.
  • Error body shape. It is { ok: false, error, detail? }; the README shows only { error }. Also, 413 too_large is missing from the README's table.
  • Image size. The catalogue gives none, so cards and product pages reserve a fixed box with object-fit: cover.
  • open. It is a build-time snapshot, so the cart ignores it and trusts the 503.

For Warren

  • _headers budget. The site's _headers goes from 92 to 95 of Cloudflare Pages' 100 rules. Its build warns at 95. Three more element pages will hit the cap.
  • Square image host. The CSP img-src line names items-images-production.s3.us-west-2.amazonaws.com, the host in the Worker's README example. Confirm it against a real Sandbox catalogue.
  • Merge order. The skill sections are in ecropolis/agent-skills, branch claude/shop-elements-skill (house-stack 0.47.0). Merge that with this PR.

🤖 Generated with Claude Code

ecropolis and others added 2 commits October 7, 2026 22:51
…, demos or checks yet)

Built to the Superhero Shop Worker contract (PR #1, claude/worker-stub).
Not finished: catalog entries, demos, GOLDEN categories, check-shop.mjs
with mutation tests, skill sections.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cart, product-list and product-page join the catalogue under Offers &
conversion, with SE Ranking queries, asks and demos run against a fake
Worker origin. scripts/check-shop.mjs runs the cart's rules from the
source (caps, no price in any request, a fresh key per attempt, the 409
clamp, 503 and network sentences), pins the built drawer's a11y, the
product-list cards and the Product JSON-LD, tests fetchCatalog, and
catches 38 planted faults.

Fixes found in a browser pass: cart styles are global (script-built lines
never carry Astro's scope attribute), the Added flash restores the
button's own markup, and radio labels keep their spaces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ecropolis
ecropolis merged commit 6e1cc72 into main Oct 8, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant