Canvas renderer overhaul:
- New 3-zone layout: left sidebar (avatar + stats + since) | right zone
(name/identity/shop/sponsors/skills) | top-right QR block
- Left sidebar has a subtle tinted background with accent-colored separator
- Stats shown as balanced column grid under the avatar
- Shop: "RIDES FOR" label + bold italic Georgia serif in theme shopColor (distinct from accent)
- Sponsors: "SPONSORS" label + regular weight in theme sponsorColor (warm gold/orange)
- Each theme now has shopColor + sponsorColor + sidebarBg + chipBorder fields
- Skills row appears only when skills/badges exist, with accent border on chips
- Full npub (44+remainder chars) shown at bottom of right zone in monospace
- Bottom bar: subtle fill + "SKATE-SPOTS.ORG" left, year right
- Park Access card: same sidebar layout, access level chip in solid accent fill
Share button:
- Uses Web Share API (navigator.share) if device supports it — opens native
share sheet (WhatsApp, iMessage, Telegram, AirDrop, etc.) with PNG file
- Falls back to copying profile URL to clipboard
- Lime green color to visually stand out from Print button
UI cleanup:
- Remove Badges tab entirely — was cluttering the nav
- Award Badge moved inline to secondary button row (yellow, subtle)
- Primary actions: Print | Share | Save PNG (all same size, flex-wrap)
- Secondary actions: Copy npub | Award Badge | Publish to Nostr
- Fixed stray closing divs from tab removal
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
QR fix (critical):
- loadImage() was routing ALL urls through proxy.shakespeare.diy including
data: URIs from QRCode.toDataURL() — proxy rejected them, QR never loaded
- Fix: only proxy http/https URLs; data: and blob: URIs load directly
- QR now renders reliably; scanning opens skate-spots.org/<npub> profile
npub display:
- Split full npub across two lines (32 chars each) instead of truncating
- Both lines shown in monospace below the brand header
- npub is now fully readable on the card
Explicit labeled sections:
- "SKATE SHOP" label in muted above shop name in accent color
- "SPONSORS" label in muted above sponsors text
- Sections only appear if data is entered — no empty space when blank
- Stats (Spots/Zaps/Events) shown as 3-column grid with label+value
Layout improvements:
- QR moved to top-right, rendered before other content (ensures it draws)
- Avatar sized 180px with "SINCE YYYY" underneath
- Identity column flows: name → nip05 → style chip → shop → sponsors → stats → skills
- Bottom divider line + year issued in footer
- fillTextFit() helper for clean text truncation with ellipsis
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
html2canvas was capturing the full browser viewport instead of just the
340×214px card element — causing the giant oversized/wrong layout in the PNG.
New approach: drawCardToCanvas() draws the card entirely via Canvas 2D API:
- Creates an 856×540px canvas (10× credit-card mm dimensions, print-ready)
- Draws gradient background, top stripe, avatar (with CORS proxy), text,
skill chips, stats, and QR code using direct canvas drawing commands
- QR code generated via qrcode lib toDataURL(), then drawn as image on canvas
- Avatar loaded via proxy.shakespeare.diy for CORS, with 4s timeout fallback
- Theme colors from THEME_PALETTE map — same 6 themes as the screen card
- No DOM capture, no scaling issues, no CSS stripping — output is pixel-perfect
QR code explanation:
- Encodes https://skate-spots.org/<npub>
- Scanning opens the rider's SkateSpots profile (NIP19Page handles /npub1...)
- White background patch behind QR for reliable scanning on dark card themes
Other changes:
- "Rider License" → "Skater License" everywhere
- Remove html2canvas dependency usage (kept package but unused for now)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Problems fixed:
- Card was rendering too tall: replaced flex-1/justify-between layout with
strict pixel-height rows (row1: 26px header, row2: 118px body, fixed bottom bar)
— content no longer floats or overflows
- No QR code: added QRCodeCanvas (existing component) in bottom-right of card
body, encoding https://skate-spots.org/<npub> — scanning takes you to the
rider's profile for verification
- License ID removed: replaced SS-XXXXXXX with shortNpub (npub1xxx...yyyy)
in top-right. The npub IS the identity — no made-up number needed
- Added crossOrigin="anonymous" on avatar img for html2canvas CORS handling
- Updated html2canvas onclone to lock card to 340×214px during capture
- Download filename uses npub prefix instead of licenseId
- verifyUrl() helper generates skate-spots.org/<npub> for QR content
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
The root cause of white/blank print: browsers strip CSS background gradients
and colors by default even with print-color-adjust: exact, especially inside
nested components wrapped by Layout.
Solution: use html2canvas to render the live card DOM to a canvas at 4x scale,
convert to PNG, then open a dedicated print window containing ONLY that image.
Images always print in full color — no CSS override needed.
Changes:
- Add html2canvas dependency
- renderCardToImage(): captures card DOM element at 4x scale with useCORS for
cross-origin avatars, temporarily strips holo animation for clean capture
- handlePrint(): calls renderCardToImage, opens popup window with CSS @page
set to 85.6×54mm, injects the PNG, auto-triggers print dialog
- handleDownload(): same render pipeline, saves as PNG file (for sharing
digitally, WhatsApp, iMessage, or taking to a print shop)
- Added Download / Save PNG button alongside Print Card button
- Added Loader2 spinner on buttons while rendering
- Removed print-only-card div and broken @media print CSS (no longer needed)
- Clean up CSS print block to minimal fallback only
- Fix "on-chain proof" → "Signed proof" in badge dialog
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Print fixes:
- Add -webkit-print-color-adjust: exact + print-color-adjust: exact to ALL
card theme classes so dark backgrounds/gradients actually print (browsers
strip them by default unless forced)
- Increase chip/muted opacity values slightly for print legibility
- Fix multiple-card issue: hide body > * on print, show only .print-only-card
- Remove complex repeating-linear-gradient from wood theme (simplify for print)
Language fixes:
- Remove "on-chain" terminology (Nostr is not a blockchain)
- Replace with plain explanation: "signed message on the Nostr network"
- Park access note now explains exactly what gets verified and how
- Park card info box now lists exactly what shows on a scan:
who issued it, who it was issued to, access level, expiry, timestamp
- Clarifies why a rider can't forge the card (would need your private key)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Remove "Shop Rider Card" type — shop affiliation is now a "Rides For" field
on the Rider License, separate from sponsors (brands/companies)
- Fix print: use visibility:hidden approach with .print-only-card overlay,
properly isolated from Layout wrapper (fixes blank print output)
- Replace "No." top-right with "LICENSE ID" showing SS-XXXXXXX derived from
pubkey + truncated npub underneath — meaningful, not random-looking
- Add Skill Badge system (kind 1293): witnessed badges are signed Nostr events
- "Award Badge" dialog: paste rider npub, pick skills, optional spot name
- Witnessed badges shown in gold ⭐ on card, distinct from self-claimed
- Badges tab shows full history with witness avatar, name, and location
- Park Access Card: only 2 types now (Rider License / Park Access),
added blue info note explaining owner-only issuing constraint
- Rename "Member npub" to "Rider's Nostr Address (npub)" with explanation
- Update NIP.md: document kind 1293 skill badges, remove kind 37097
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
@noble/curves v2 dropped the ./secp256k1 subpath export. The manual
getEventHash + schnorr.sign + bytesToHex pattern is replaced with
nostr-tools' finalizeEvent() which handles id computation and signing
internally, with no external subpath dependencies. Also removes the
now-unused getEventHash import and bytesToHex helper.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
@noble/hashes v2 dropped the ./utils subpath export, breaking the import
in useDirectMessages.ts. Replaced with a simple inline implementation
that has zero new dependencies and works correctly with any build tool.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
The entire skate-spots codebase was accidentally copied into src/src/ and
public/public/ instead of src/ and public/ directly. This left the real
src/ directory as blank MKStack template stubs, explaining why the landing
page showed the default template instead of SkateSpots.
Changes made:
- Copied all files from src/src/ up to src/ (App.tsx, AppRouter.tsx, main.tsx,
all pages, components, hooks, contexts, lib, i18n, test)
- Copied all files from public/public/ up to public/ (images, manifest, etc.)
- Deleted src/src/ and public/public/ nested directories
- Removed HelloWorld.tsx template stub from pages/
- Retained the previously fixed index.css (Tailwind v3 directives)
Full skate-spots feature set is now active:
- All 30+ routes (map, events, spots, coaches, marketplace, wallet, etc.)
- NWCProvider, LanguageProvider, PWAInstallPrompt, AmberCallbackHandler
- Skate community relays (goskatespots.nostr1.com, wotr.relatr.xyz, etc.)
- Outfit Variable font, Amber pre-check in main.tsx
- All hooks (useSkateSpots, useCoaches, useZaps, etc.)
- i18n support (en/es)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
The shadcn/ui components were using the new "radix-ui" umbrella package
import style (e.g. `import { Tooltip as TooltipPrimitive } from "radix-ui"`).
However, radix-ui@1.5.0 re-exports ALL radix primitives including ones not
installed (@radix-ui/react-accessible-icon, @radix-ui/react-form,
@radix-ui/react-one-time-password-field, @radix-ui/react-password-toggle-field,
@radix-ui/react-toolbar), causing esbuild to fail with 5 unresolved import
errors outside Shakespeare.
Fix: rewrite all 32 imports across the ui/ components to import directly
from their individual @radix-ui/react-* packages (which are all already
installed). Remove the radix-ui umbrella package entirely from package.json
and package-lock.json.
Affected files (32 import changes):
accordion, alert-dialog, aspect-ratio, avatar, badge, breadcrumb, button,
checkbox, collapsible, context-menu, dialog, dropdown-menu, form, hover-card,
label, menubar, navigation-menu, popover, progress, radio-group, scroll-area,
select, separator, sheet, sidebar, slider, switch, tabs, toggle-group, toggle,
tooltip
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Change z.url() to z.string().url() in AppProvider.tsx for Zod compatibility
- Update Zod version from ^3.25.71 to ^3.23.8 (valid published version)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Update Zod version from ^3.25.71 to ^3.23.8 (valid published version)
- Replace z.url() with z.string().url() in AppProvider.tsx for compatibility
- Remove unused npubcash-sdk dependency
- Remove duplicate nested src/src directory that was incorrectly created
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>