import { useSeoMeta } from '@unhead/react'; import { Link } from 'react-router-dom'; import { nip19 } from 'nostr-tools'; import { ShoppingBag, Zap, Coins, Shirt, Sticker, Package, Hammer, Sparkles, MapPin, MessageCircle, Printer, Download, Scissors, } from 'lucide-react'; import { PageHeader } from '@/components/PageHeader'; import { Button } from '@/components/ui/button'; import { PLATFORM_OWNER_PUBKEYS } from '@/hooks/useListingRestrictions'; /** Where "request an item" goes: an encrypted DM straight to the shop owner. */ const SHOP_OWNER_NPUB = nip19.npubEncode(PLATFORM_OWNER_PUBKEYS[0]); const REQUEST_HREF = `/messages/${SHOP_OWNER_NPUB}`; /** * App Shop — SkateSpots merch. * * Deliberately a STOREFRONT WITH NOTHING IN IT: there is no stock, no * pre-order, no price and nothing to buy. It exists so the section, the design * language and the payment story (sats only — Lightning or Cashu) are in place * before the first drop. When items land we can model them as listings and take * Lightning/Cashu payment; until then this page must never imply a sale. */ /** * Free, printable artwork. Physical size is baked into the files (mm units), so * "Actual size" printing gives an exact 55 × 86 mm sticker / A3 poster, and the * QR in each one resolves to https://skate-spots.org. */ const FREE_PRINT = [ { title: 'Sticker', size: '55 × 86 mm', tip: 'Black die-cut. Print on sticker paper, cut along the black edge.', file: '/images/print/skatespots-sticker.svg', }, { title: 'Poster', size: 'A3 · 297 × 420 mm', tip: 'Prints on A3; shrink to A4 (50%) and it still scans fine.', file: '/images/print/skatespots-poster.svg', }, ]; /** What we're working on. Not products, not prices — just intent. */ const PLANNED = [ { icon: Shirt, label: 'Tees & hoodies' }, { icon: Package, label: 'Decks' }, // 'Sticker packs' is rendered separately in the grid, because it is the one // entry that already contains something real: the free printables. { icon: Hammer, label: 'Shop tools' }, ]; const PAY_CHIPS = [ { icon: Zap, label: 'Lightning' }, { icon: Coins, label: 'Cashu' }, { icon: MapPin, label: 'Local handover' }, ]; export default function AppShopPage() { useSeoMeta({ title: 'App Shop — SkateSpots', description: 'SkateSpots merch, paid in sats over Lightning or Cashu. Nothing in stock yet — here is what is coming.', }); return (
{/* ── Hero ─────────────────────────────────────────────────────────── */}
Coming soon

Wear the
Scene

Merch for the people who keep this thing rolling — sold{' '} locally, on request. You message me, we sort the details, and you pay in{' '} sats — Lightning or Cashu — when you collect it. No cards, no accounts, no checkout robot, no middleman skimming the drop.

Opens a private, encrypted DM with me.
{PAY_CHIPS.map(({ icon: Icon, label }) => ( {label} ))}
{/* ── What's in the works ──────────────────────────────────────────── */}

In the works

not for sale yet
{PLANNED.slice(0, 2).map(({ icon: Icon, label }) => (

{label}

soon
))} {/* Sticker packs — the only thing you can actually GET today: the free printables. Kept inside its category (not a separate section) so the shop reads as one list of merch, free stuff included. */}

Sticker packs

The packs are coming. The designs are not — print these two right now, free.

Free
{FREE_PRINT.map((item) => (
{`SkateSpots

{item.title}

{item.size}

{item.tip}

))}

Print at 100% / “Actual size” so the size is exact and the QR stays sharp — it points at skate-spots.org. Vector files, so they scale without going fuzzy.

{PLANNED.slice(2).map(({ icon: Icon, label }) => (

{label}

soon
))}
{/* ── How it'll work ───────────────────────────────────────────────── */}

How buying works

it's a DM, not a cart
    {[ { n: '1', t: 'Message me', d: 'Send a DM with what you want — item, size, colour, whatever you are after.', }, { n: '2', t: 'We sort it out', d: 'Price in sats, and where and when to meet. It is a conversation, not a checkout.', }, { n: '3', t: 'Pay in sats', d: 'Lightning or Cashu at handover, then it is yours. No shipping, no waiting rooms.', }, ].map((s) => (
  1. {s.n}

    {s.t}

    {s.d}

  2. ))}
); }