- Full 8,703-key Hindi dictionary in src/i18n/hi (7 namespace batches),
placeholders verified, only 2% identical strings (brand/protocol names).
- Register hi in Language/LANGUAGE_LOADERS, detectLanguage (hi-IN),
LanguageToggle (🇮🇳, हिन्दी) and dateFnsI18n (hi-IN).
- Lazy-load Noto Sans Devanagari for hi via lib/localeFonts.ts (renamed from
cjkFonts.ts) and add it to the CSS font stack; other locales don't download it.
- check-i18n covers hi: 24 dictionaries / 25 codes at 100%; tsc/tests/build green.
Bundles leaflet CSS + MarkerCluster CSS (main.tsx) and the default marker PNGs (SpotMap) instead of loading them from unpkg.com, so boot makes no third-party request; unpkg.com removed from the CSP (index.html meta + _headers + netlify.toml). Adds dns-prefetch/preconnect for relay.skate-spots.org and blossom.skate-spots.org.
Kanit (th), Noto Sans JP (ja) and Noto Sans KR (ko) were imported statically in main.tsx, so every visitor downloaded ~16MB of CJK font files. They're now loaded on demand once per locale (lib/cjkFonts.ts, wired in LanguageContext), so non-CJK users never fetch them and CJK users get their font after the first paint.
Every provider lived at /coach/<pubkey>/<id> regardless of craft (a barber got
a "coach" URL). New src/lib/labRoutes.ts maps craft kind → segment and builds
the canonical path; the router adds /lab/:craft/:pubkey/:identifier (the craft
segment is cosmetic — the page still resolves by pubkey + identifier) and keeps
/coach/... working for old links. All generated links updated: offer-form
redirects, Lab cards + "Your Lab profiles", cross-links, spot/event/admin links,
the CVM client URL, the share path, and the SPA clean-link shim.
The offer → publish loop had two dead ends: a provider's own page only offered
Delete (no Edit), and there was no way to share a listing (the whole point of
announcing a service).
- Owner "Manage" card gains an "Edit profile" button deep-linking to
/become/<craft> (prefills the existing profile). Admins still get only
take-down, not a misleading self-edit link.
- A Share button on every provider page opens ShareProfileDialog (QR + copy +
native share) with the service URL /coach/<pubkey>/<identifier>.
- ShareProfileDialog accepts an optional `path` to override the default
/<npub> share URL.
- main.tsx clean-link shim now also rewrites /coach/<pubkey>/<d> to the hash
route, so shared /coach/... links resolve on the live site.
Follow-ups (not done): live preview before publishing, draft/autosave for the
long forms, a multi-step/progress layout, and a "your Lab profiles" manage
strip on /lab.
- U2: CardPreview is zoomable (click for a full-screen overlay); used in the
studio, 'My passes' and the public card.
- U4: the page title is translated (Rider Card / Carné de Rider) — was hardcoded
English.
- L4: removed the legacy style/skills from RiderCardConfig + CardData (the card
derives style/level and shows only witnessed badges).
- I2: cardVerifyUrl/cardPublicUrl are clean (/verify/<naddr>, /card/<npub>) and a
startup shim rewrites those paths to the hash (old /#/ links still work).
Deploys replace hashed chunk filenames; a tab that was already open can load a
chunk that no longer exists (404) and hit the error boundary ('THIS PAGE
SLAMMED'). Listen for Vite's vite:preloadError (and dynamic-import failures) and
reload once, guarded against loops.
Two changes targeting the post-update white screen on the Zapstore APK:
1. vite.config: set base './' when CAPACITOR_BUILD is set. In a native
WebView the bundle is served from the local filesystem, so absolute '/'
asset paths are the classic cause of a silent white screen. The web
deploy keeps '/'. This is the documented Capacitor requirement and is
zero-risk to the working web build.
2. index.html: add a dependency-free "boot crash guard" that runs before
the app bundle and paints any uncaught error / unhandled rejection —
plus a 12s "did not render" timeout — directly to the screen using
inline styles only. A boot failure that would otherwise be an
info-less white screen now shows the actual error ON DEVICE, with no
USB/remote-debugging needed. main.tsx signals a clean boot to cancel
the timeout guard.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Three compounding bugs fixed:
1. WRONG FORMAT: Was using nostrsigner: directly, then intent: with encoded
values. Amber README shows intent: with raw unencoded S.key=value params.
2. # IN CALLBACKURL: Our callbackUrl was https://.../#/amber-callback which
contains a # — but intent: uses # as its own delimiter (#Intent;...;end).
Having a # inside the callbackUrl value breaks the entire intent string.
Fixed: callbackUrl is now https://.../amber-callback?event= (no hash).
3. HASHROUTER MISMATCH: Amber opens /amber-callback (no hash) but HashRouter
only handles /#/route paths. Fixed in main.tsx: pre-React IIFE detects
/amber-callback path, saves ?event= to sessionStorage, then redirects to
/#/amber-callback so React Router matches AmberCallbackPage correctly.
Final correct intent URL format:
intent:#Intent;scheme=nostrsigner;S.compressionType=none;S.returnType=signature;S.type=get_public_key;S.callbackUrl=https://skate-spots.org/amber-callback?event=;end
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Remove debug red banner from index.html and main.tsx
- Add android:build:apk script that uses CAPACITOR_BUILD=1 for single
bundle output + strips Shakespeare build artifacts from dist/index.html
- Update all android:* scripts to use android:build:apk
Root cause of white screen: 100+ JS chunk files overwhelm Android
WebView local file serving. Single bundle with inlineDynamicImports
fixes this.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Red banner renders from pure HTML before any JS loads.
If visible → HTML loads but JS fails.
If not visible → WebView can't even load index.html.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
The primary cause of the white screen in the APK was BrowserRouter.
Capacitor serves files via https://localhost/ and the HTML5 History API
routing (BrowserRouter) fails to resolve routes in this context,
resulting in a blank white page.
Changes:
- Switch BrowserRouter → HashRouter in AppRouter.tsx
- Add DeepLinkHandler component (handles appUrlOpen for Amber callbacks
and other deep links in native context)
- Fix Amber callback URL builder to use org.skatespots.app:// custom
scheme when running in Capacitor (so Android fires an intent back into
the app instead of navigating a browser)
- Fix getSearchParams() in amber.ts to extract query params from hash
fragment (HashRouter URLs look like /#/amber-callback?event=XXX)
- Fix captureAmberCallback in main.tsx to check hash fragment too
- Remove debug error overlay (no longer needed)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Add SplashScreen.hide() call in main.tsx so splash dismisses when JS loads
- Set launchShowDuration: 0 + launchAutoHide: true in capacitor.config.ts
- Fix ErrorBoundary to use bg-black text-white instead of bg-background
(bg-background = white before dark class is applied = white screen on error)
- These three combined should eliminate the white screen in the APK
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Install @fontsource/bebas-neue and @fontsource/barlow-condensed
- Add .font-display (Bebas Neue) and .font-condensed (Barlow Condensed) CSS utilities
- Hero headline: split into two lines SKATE / SPOTS with clamp() fluid sizing,
Bebas Neue replaces Impact throughout
- Subtitle: Barlow Condensed 700 with wide letter-spacing
- Description: Barlow Condensed italic
- All section headings (Featured Spots, Events, The Lab, CTA, New Here?): Bebas Neue
- Section subheadings: Barlow Condensed with tracked uppercase
- Desktop + mobile header logo: Bebas Neue
- Footer logo: Bebas Neue
- Tagline badge: Barlow Condensed 600
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>