- AppRouter wraps every route (except /amber-callback and the 404) in ONE
<Route element={<Layout/>}> with an <Outlet/>; the chrome now persists across
navigation instead of being torn down and rebuilt on every page.
- Layout: children optional (falls back to <Outlet/>); the map is full-bleed via
a route check (isFullBleed) instead of a per-page noPadding prop.
- All 59 pages + CraftProfileForm/ErrorState/NewsletterIssueView now render
fragments instead of <Layout> (structure-preserving), imports dropped.
Removes the whole remount class: chrome no longer re-runs its hooks per
navigation, Sasquatch chat state survives navigation, and the header can't
re-open Amber on every page change.
- Preserve the geo 'g' tag and paid 'featured' tag when editing any Lab
profile (all 7 craft roles via CraftProfileForm + 5 bespoke pages).
- Render previously collected-but-hidden fields on the Lab profile page:
judge 'events_judged', organizer 'events_hosted', editor hardware/software,
and spot references.
- Include Event Organizer (35013) in Community Stats + counts.
- Cap Title inputs at 100 (was 120) so profiles no longer fail the parser
and silently vanish; MIN_TITLE_LEN 2 -> 1 for 1-char display names.
- Normalize bare-domain URLs (example.com) to https:// before storing instead
of dropping/hiding them (new normalizeUrlInput helper; fixes extra url fields).
- No crew strip for judging/organizing (was wrongly showing Photo & Film);
scrollable Offer Services FAB; live bio counters.
Audit of the Lab 'offer a service' flows found two cross-cutting gaps:
1. Every Lab card showed the name TWICE (the card renders a 'title' line, but
all forms wrote title = the kind-0 display name). The field is meant to be a
self-described headline.
2. Only the Skater flow could be edited; the 7 craft roles started blank and
silently overwrote the previous profile on submit.
Fixes (shared CraftProfileForm -> 7 roles: artist, graffiti, tattoo, trainer,
musician, judge, organizer):
- New useMyLabProfileEvent(kind, identifier) hook; the form prefills from your
existing profile and becomes an EDIT (button: Update Profile; toast: updated).
- New 'Name / headline' field -> the tag (defaults to your name).
- Lab ProfileCard only shows the title line when it differs from the name.
Gate: 101 tests, 0 errors/warnings, boot smoke green.
Extends LazyMount beyond the marketplace so these long card grids no longer
mount every card (and its hooks/DOM) up front. Cards keep equal height via
h-full wrappers.
Gate: 101 tests, 0 errors/warnings, boot smoke green.
- Bounty leaderboards no longer slice to top 50 before computing the current
user's rank (anyone outside the top 50 never saw their position), and each row
no longer prints the count twice
- Lab craft tabs: 4-up grid (11 tabs were laid out 5-across, leaving a lone
'Judges' orphan row); stale comment corrected
- Contacts search placeholder now says it filters by npub (it never matched the
displayed names)
The empty-state migration removed the `cn` import from both files on the
mistaken belief it was unused. In fact each file still uses cn() ~22 times
(ProfileCard, FilterDrawer, event cards, etc.), so /lab and /events crashed
at runtime with "cn is not defined" and hit the route error boundary.
Re-added `import { cn } from '@/lib/utils'` to both.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Empty states:
- LabPage and NotificationBell now use the shared <EmptyState> component.
- LabPage's logged-out "Log in to create a profile" prompt preserved via
the hint slot; removed now-unused cn import.
Page titles (U2):
- Audited all page routes for document titles. Only 3 were missing:
- EditTourPage: now sets "Edit <tour> - SkateSpots".
- AmberCallbackPage: now sets "Signing in with Amber - SkateSpots".
- NIP19Page ProfilePage: sets "<name> - SkateSpots" with about as
description; other NIP-19 branches already delegate to NotFound /
NewsletterIssueView which set their own titles.
ScrollToTop (U1): verified already correct — resets window scroll on every
pathname change, wired in AppRouter. No change needed.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Empty states (P4 follow-up):
- CrewsPage and EventsPage now render the shared <EmptyState> instead of
their own local copies, keeping spacing/actions/footer consistent.
Become-role routes (P1):
- Add src/lib/becomeRoles.tsx: single registry mapping each role slug to
either a CraftProfileForm config (artist/graffiti/musician/judge/tattoo/
trainer) or a lazy bespoke page (coach/filmer/editor/photographer/
builder/skater). The 6 craft roles were already thin config wrappers, so
their configs move into the registry and the wrapper files are deleted.
- Replace 12 hardcoded /become-* routes + 12 imports with one
/become/:role route (BecomeRolePage) that renders from the registry.
- Legacy /become-<slug> URLs now redirect to /become/<slug> so shared/
bookmarked links keep working.
- Update all internal links (LabPage, Index, SkatersPage, SpotDetailPage,
NIP19Page, SkaterDirectoryCard) to the canonical /become/<slug> paths.
Note: the 5 large bespoke forms were intentionally NOT merged into one
config — they carry distinct machinery (SpotPicker, wallet/Pro, geohashing)
and forcing them together would increase complexity, not reduce it.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
The PNG icon kept failing to render (corruption + browser caching of the
broken response) on both phone and desktop. Replaced it with the
PersonStanding Lucide vector icon in neon red with a red glow — it always
renders, never caches broken, is truly single-color and on-brand, and
works identically across phone and desktop. Removed dead image assets.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Swapped the busy multi-color icon for a clean, monochrome neon-red
skater glyph that reads clearly at small sizes. Refined the tile with a
subtle red border and clearer hover state for better visibility.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Replaced the large black-and-white photo panel with a compact,
app-styled skater icon (neon red #ff0040 + lime #ccff00) sitting in the
rounded icon tile used elsewhere in the app. Added a red drop-shadow
glow to match the brand aesthetic. Removed the unused photo asset.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Lab "Just a skater?" card now features the uploaded photo, framed and
faded into the card body with a neon-red edge consistent with the app's
look; adds a "The Crew" eyebrow label and a circular arrow affordance.
- Mobile bottom nav redesigned: glowing rounded pill behind the active
tab (replaces the tiny dot), gradient glass bar with a top hairline
glow, ring-2 wallet badge, and refined active/press micro-animations.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- New app-native Skater Profile kind 35000 with `skateskater` marker tag,
the anti-spam boundary that keeps generic kind-0 Nostr profiles out of the
directory (queried only from the community relay).
- Skater type, stance/style/level constants, and parser in types.ts.
- useSkaters + useUserSkaterProfile hooks.
- /skaters directory page: immersive hero, live count, search, style filter
chips, ranked skater grid with NIP-05 verification badges and lazy author
metadata.
- /become-skater opt-in flow (bio, photo, styles, stance, level, years, home
spot, location w/ geohash, socials).
- Wire "Skaters" into the mobile nav and a cross-link banner in The Lab so
plain skaters finally have a home.
- Document kind 35000 in NIP.md.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Flesh out SkateJudge as a full craft-based Lab profile (parseCraftBase),
with JUDGE_FORMAT / SPECIALTY / LEVEL label sets covering Game of S.K.A.T.E.,
best trick, jams, contests, am series, world tour stops, etc.
- Wire judge into useLabProfiles (union type, self-tag, parse case)
- Add "judging" ServiceType to LabPage: tab, accent, filter sections, empty
state, counts, profile card icon, and ?craft=judging deep link
- New BecomeJudgePage + /become-judge route + FAB entry
- CoachDetailPage renders judge profiles (accent, icon, labels, noun, title)
- Community Stats "Judges" card now links to /lab?craft=judging
- Document kind 35012 (skatejudge) in NIP.md
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
On mobile the 10 craft filters (Coaches, Filmers, Photo, Editors, Builders,
Artists, Graffiti, Tattoo, Trainers, Music) were in a sideways-scrolling
strip, hiding options off-screen. Switch to a 5-column grid on phones (two
tidy rows of five) while keeping the flex-wrap layout on desktop, so every
craft is visible at a glance with no horizontal scrolling.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- New addressable kinds 35007–35011 with types, label maps and parsers
- Shared parseCraftBase helper + parseLabProfile dispatcher in useLabProfiles
- Reusable, config-driven CraftProfileForm (polished shared shell, per-craft
skill sections + extra fields, entity/collective, CLINK, Pro upgrade)
- Five thin Become* pages wired into AppRouter and the Lab "Offer" menu
- LabPage: extended ServiceType, accents, scrollable tab strip, filter
sections, counts, empty states and ProfileCard to all 10 crafts
- CoachDetailPage renders all craft types (map-driven accents/icons/labels)
plus craft-specific fields (studio, books-open, credentials, remote,
graffiti crew, music links)
- NIP.md documents all five new craft schemas
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
The Lab category tabs (Coaches/Filmers/Photo/Editors/Builders) overflowed
the viewport and scrolled sideways on phones, hiding Builders. Replace the
overflow-x row with a 5-column grid of compact icon-over-label tabs so all
five are visible at once without lateral scrolling, with the count badge
floated to the corner so it never widens a tab.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Lab:
- useLabProfiles sorts featured (Pro) profiles first
- ProBadge shown on Lab cards (LabPage) + Lab detail page; featured cards
get a subtle amber highlight
Events (same no-paywall model as Lab):
- New FeaturedEventUpgrade: every event posts for free; optional fee adds a
featured badge + top placement (reuses existing featuredEvent fee)
- CreateEventPage: removed the paid-event fee gate; opt-in featured toggle,
writes a `featured` tag when active
- useSkateEvents sorts featured events first; EventCard shows ProBadge
(compact in list view, overlay on the image in full view)
Docs:
- NIP.md documents the `featured` tag (unix-seconds expiry, self-attested)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
New Photographers category (blue-indigo) — separate from Filmers:
- New addressable kind 35004 + SkatePhotographer type + parseSkatePhotographer.
- Rich photographer taxonomy as queryable `t` tags: services (action,
sequence, editorial, product, events…), camera bodies, lenses, lighting
(Profoto/Elinchrom/Godox/triggers…), support/rig, and shooting style,
plus a freeform "gear" tag and a portfolio link.
- BecomePhotographerPage form with chip-grid selectors for all gear
categories + "what's in the bag" textarea, wired to /become-photographer.
- The Lab: 4th "Photo" tab (indigo accent) with its own filters, cards,
empty state; OfferFAB gains "Offer Photography"; useLabProfiles fetches
35004; CoachDetailPage renders photographers (and editors) properly with
per-type accent, gear + portfolio display.
- NIP.md: documented the whole Lab (kinds 35001-35004) incl. photographer.
Filmer improvements (now video-focused, photography split out):
- Removed the token "Action Photography" service; added follow/line filming.
- Richer equipment list: cinema camera, HVX, action cam, gimbal, 4K/HFR.
- Filmers gain a freeform "what's in the bag" gear field + a reel/portfolio
link, both surfaced on the detail page.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Fix iOS directions: Apple Maps first on Apple platforms, removed broken geo: URI,
added Waze option, fixed popover z-index clipping behind Sheet component
- Fix 'Me' bottom nav: now deep-links to /settings?section=profile for logged-in users
so tapping 'Me' shows your profile, not a generic settings menu
- Add SettingsPage URL param support: ?section=X opens sub-screen directly
- Add onboarding welcome banner: dismissible strip at top of map for logged-out users
with 'Get Started' CTA pointing to /onboarding, stored in localStorage
- Fix Lab empty state: FAQ link + login prompt for logged-out users
- Fix Events empty state: FAQ link added to all empty state instances
- Fix GearSwap empty state: actionable 'Clear Filters' button + FAQ link
- Community stats: add 'this month' delta badges (+N this month) on all stat cards
- Newsletter pill: hide on map page to eliminate bottom sheet overlap conflict
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Add dedicated City location input field in toolbar alongside search (splits "Name/bio" and "City" search into two focused inputs)
- Fix Filter drawer responsiveness: bottom sheet on mobile, right side panel on desktop (md:)
- Replace TrustFilter compact dropdown in drawer with inline pill buttons (no nested dropdowns)
- Add active filter chips row in toolbar showing selected skills as dismissible pills, sort/trust badges, and "Clear all" button — only visible when filters are active
- Tab count badges now always show (including zero) to give clear feedback
- Fix results count row: remove empty min-h gap, now only renders when not loading
- Search now also matches against genUserName fallback for pubkey-derived names
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
1. AboutPage: add Credits section (Zapstore, ContextVM, Angor, Geyser, MKStack,
Shakespeare, Nostr), add Zapstore download button, fix powered-by text overflow
on mobile (wrap-friendly flex layout)
2. SasquatchGuide: make minimized bubble draggable on all devices
- pointer events for mouse, touch, and stylus
- saves position to localStorage, persists across sessions
- tap still opens, drag moves (5px threshold to distinguish)
3. Layout (burger menu): add overflow-y-auto + pb-8 to SheetContent so
mobile menu is scrollable when content exceeds screen height
4. CashuWalletCard (wallet): fix input+button rows overflowing on mobile
- flex-col on small screens, flex-row on xs+ (stacked on phones)
- whitespace-nowrap on buttons to prevent text wrapping
5. LabPage: compact action buttons on mobile (h-8, text-[10px], px-2)
so all 4 buttons fit in 2x2 grid without overflow/truncation
6. LoginDialog (Amber): improve visibility-change handler - use fresh
SimplePool subscription on each foreground return instead of querySync
(which doesn't exist in nostr-tools v2.13)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Amber login (critical):
- Replace window.location.href with window.open(_system) in Capacitor WebViews
- Capacitor's WebView throws "malformed nostrsigner request" on href navigation
- New openAmberUrl() helper detects Capacitor via window.Capacitor.isNativePlatform()
- Add openAmberForLoginNoCallback() for PWA/Capacitor clipboard flow
- Fix all 6 Amber URL opens in amber.ts + LoginDialog.tsx
Mobile nav:
- Newsletter and Sasquatch AI (/pyramid) added to hamburger menu
- Sasquatch floating guide now shows on mobile (removed hidden md:block)
Lab page mobile:
- Action buttons (Offer Coaching/Filming/Editing/Get Card) now 2-col grid on mobile
- Service type filter (Coaches/Filmers/Editors) now 3-col grid, full width
- Reduced top padding on mobile (py-6 → py-12 on md+)
- Text truncates cleanly, icons don't overflow
Wallet page mobile:
- Reduced padding (py-6 md:py-8)
- Tab triggers use h-auto + py-2.5 to avoid overflow
- Smaller header text on mobile
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>