Commit graph

1,087 commits

Author SHA1 Message Date
613a925e45 fix(pwa): disable service worker in dev across all 8 vite configs
Was: every standalone (and the hub) registered a service worker
during \`npm run dev\` via VitePWA's devOptions.enabled = true.

Problem: the dev SW caches index.html and the JS bundle on first
load and survives across vite restarts. Any code change that
required a server restart (e.g. fixing a vite.config.ts merge
conflict) resulted in browsers continuing to serve the cached
pre-restart bundle until the user manually unregistered the SW.
This caused the hub at localhost:5173 to redirect to /market on
refresh — the cached bundle was from the broken-config period
which still had the old monolithic main app's market route.

PWA features (offline, install prompts, manifest) are still tested
by running:
  npm run preview            # for the hub
  npm run preview:<name>     # for any standalone

against a real production build, which is the more accurate
environment for PWA verification anyway.

Recovery for anyone with a stale SW lingering in their browser
(needed once after pulling, then never again):
  1. DevTools → Application → Service Workers → Unregister
  2. DevTools → Application → Storage → Clear site data
  3. Hard reload (Ctrl-Shift-R)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 10:58:34 +02:00
d37f37a36d fix(vite): resolve stranded merge conflict markers in vite.config.ts
Merge commit 13ad692 ("merge: forum standalone") committed
vite.config.ts with unresolved <<<<<<< / ||||||| / >>>>>>> markers
in the navigateFallbackDenylist regex array. Vite couldn't parse
the file, so the hub dev server failed to restart on config changes
and kept serving stale code from before the merge — including the
old monolithic main app's /market route, which manifested as a
mysterious redirect from / → /market for users testing the hub.

Resolution: keep the union of all three sides
  (sortir, castle, wallet, chat, market, cart, checkout, tasks,
   forum, submit, submission).

Recovery for anyone seeing the stale /market redirect after pulling:
  - hard-reload the browser (Cmd/Ctrl-Shift-R)
  - DevTools → Application → Service Workers → Unregister
  - Re-run npm run dev (or dev:all) — the hub now restarts cleanly

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 10:55:40 +02:00
4605703e20 feat(auth): require login on wallet, chat, and castle
These three standalone apps have no meaningful public view — wallet
needs the LNbits token to do anything, chat needs Nostr keys to
decrypt DMs, castle's accounting only makes sense for an account
holder. Their previous router guards only redirected when a route
explicitly opted in via meta.requiresAuth: an unauth user could land
on the home page and see broken / empty content with no signal.

Replaces each app's per-route guard with a strict policy: any
navigation to a path other than /login requires auth, otherwise
bounce to /login. /login itself bounces an authenticated user back
to /.

Affected guards:
  - src/wallet-app/app.ts
  - src/chat-app/app.ts
  - src/accounting-app/app.ts

Forum / market / tasks / activities keep the existing per-route
guard so they remain browseable without an account by default.
That browsing-vs-auth choice will become operator-configurable per
deployment (tracked separately).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 10:48:35 +02:00
86386b08b1 merge: hub notification badge slot 2026-05-02 10:13:21 +02:00
772c57fd85 feat(hub): add notification badge slot on tiles
Reserves a top-right corner badge on each chakra tile, hidden when
the module has no unread items. The Module interface gains an
optional \`unread?: number\`; tiles render a 18×18 red pill with the
count (capped at "99+") in the top-right when unread > 0.

No data source yet — this is a placeholder slot. Wires to the
per-standalone notification feeds defined in #32: each standalone
will publish its unread count, hub aggregates and projects into the
modules array. Until then every tile renders without a badge.

Picked a red pill over the theme's primary because red is the
universal "unread" signal across iOS / Slack / Discord / Gmail.
Ring-1 ring-background gives a subtle halo against any tile shade.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 10:13:15 +02:00
9a1e5e3994 chore(dev): pin standalone ports + add dev:all script
Fixed-port assignments for each standalone vite dev server, with
strictPort to fail loud if a port is taken (no silent +1 increment
that would break the hub's hardcoded VITE_HUB_<NAME>_URL targets):

  hub        5173  (npm run dev)
  castle     5180
  sortir     5181  (activities)
  wallet     5182
  chat       5183
  forum      5184
  market     5185
  tasks      5186

`npm run dev:all` boots the hub and all 7 standalones concurrently
via the existing concurrently devDep. The hub's chakra tiles point
at these ports via VITE_HUB_<NAME>_URL in .env.local for end-to-end
local testing of the cross-subdomain auth relay.

Pure dev infrastructure — no production behaviour change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 10:10:43 +02:00
96f691c891 merge: minimal AIO hub (chakra grid + bottom dock + i18n trim) 2026-05-02 10:10:03 +02:00
13ad6927c6 merge: forum standalone (with bottom bar) 2026-05-02 10:10:03 +02:00
d8468aba56 chore(i18n): drop unshipped locales (de, zh)
AVAILABLE_LOCALES advertised 'de' and 'zh' but src/i18n/locales/
only ships en.ts, es.ts, fr.ts. Selecting de or zh from the new
hub language picker would 404 the dynamic import.

- src/i18n/index.ts: AVAILABLE_LOCALES = ['en', 'es', 'fr']
- src/composables/useLocale.ts: trim flag map to match

VITE_DEFAULT_LOCALE still drives first-run default.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 10:08:50 +02:00
9a3e3ae0ed feat: minimal AIO hub with chakra grid + bottom dock
The all-in-one app at app.${domain} is a minimal hub: only the base
module (auth, profile, relays, PWA, image upload) plus a chakra-
themed entry point linking out to the seven standalone module PWAs
(market, sortir, wallet, chat, forum, tasks, castle), with an
eighth tile reserved for a forthcoming restaurant module.

UI:
- 2-column grid of 8 module tiles with Lucide icons, occupying the
  full viewport between the title and the bottom dock. Status hints
  (alpha/beta/coming soon) shown beneath each label.
- Faint chakra-mandala column rendered behind the tiles (peeks
  through their translucent backgrounds), plus a subtle vertical
  hue gradient (red at the bottom → violet at the top) — the chakras
  inform the visual frame without forcing a 1:1 module mapping.
- Bottom dock with system-level controls: Profile (Sheet hosting
  the existing ProfileSettings.vue), Theme (light/dark/system),
  Language (uses available locales), and a Currency placeholder.
- Each tile is a link to VITE_HUB_<NAME>_URL with the user's
  lnbits_access_token appended as ?token= so the destination logs
  in via the existing acceptTokenFromUrl() relay.

Wiring:
- src/App.vue: stripped to the same minimal shell as the standalone
  apps (no AppLayout/AppSidebar — the hub is the navigation).
- src/app.ts: only base module is registered. Hub is the / route.
- src/app.config.ts: only base module config remains.
- public/chakras/*.svg: 7 chakra mandala SVGs copied from the legacy
  frontend (Atitlan.io).
- nginx.conf.example: rewritten with one server block per subdomain
  pointing at its own dist-<name>/ output.

Closes #26.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 10:08:28 +02:00
a694dc2135 feat(forum): add bottom navigation bar
5 tabs at the bottom of the forum standalone:
  Posts (→ /forum), Spaces, Submit (→ /submit), Search, Alerts

Spaces, Search, and Alerts are dimmed and emit a "coming soon" toast
on tap pointing at the tracking issue:
  - Spaces  → #31 (NIP-72 communities)
  - Search  → #15 (link aggregator search)
  - Alerts  → #32 (per-standalone notifications, hub aggregation)

Mirrors the activities-app bottom-bar pattern (icon + 10px label,
fixed bottom, safe-area-aware) and replaces the previous bare
forum-app shell which had no way to compose a new submission.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 10:07:50 +02:00
0b37518ce2 merge: tasks standalone 2026-05-02 09:15:13 +02:00
c22b5de8bc merge: market standalone 2026-05-02 09:14:56 +02:00
820b2a0e64 merge: chat standalone 2026-05-02 09:14:38 +02:00
c0be2ca053 merge: wallet standalone 2026-05-02 09:14:13 +02:00
a162b0789f merge: forum rename 2026-05-02 09:14:13 +02:00
55324a0501 feat: add standalone forum PWA build
Adds a standalone forum PWA at forum.${domain}, built from the
existing src/modules/forum plugin (NIP-72 communities + kind 1111
posts + voting). Same standalone pattern as the other modules:
- forum.html entry, vite.forum.config.ts (outDir: dist-forum,
  manifest id: forum-app, theme: blue #2563eb — Vishuddha chakra)
- src/forum-app/{main.ts, app.ts, app.config.ts, App.vue} bootstraps
  base + forum only, with acceptTokenFromUrl for shared auth from hub
- new ForumListPage view + /forum route added to the forum module
  (previously the list was only embedded in Home.vue)
- npm run dev:forum / build:forum / preview:forum
- main app SW denylist extended with /forum/, /submit/, /submission/

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 09:00:58 +02:00
3f88ea731e feat: add standalone tasks PWA build
Adds a standalone tasks PWA at tasks.${domain}, built from the
existing src/modules/tasks plugin (Nostr calendar events, kind
31922/31925). Same standalone pattern as the other modules:
- tasks.html entry, vite.tasks.config.ts (outDir: dist-tasks,
  manifest id: tasks-app, theme: indigo #4338ca — Ajna chakra)
- src/tasks-app/{main.ts, app.ts, app.config.ts, App.vue} bootstraps
  base + tasks only, with acceptTokenFromUrl for shared auth from hub
- npm run dev:tasks / build:tasks / preview:tasks
- main app SW denylist extended with /tasks/

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 08:58:54 +02:00
455dc6571e feat: add standalone marketplace PWA build
Adds a standalone Nostr marketplace PWA at market.${domain}, built
from the existing src/modules/market plugin. Same standalone pattern
as wallet/chat/castle/activities:
- market.html entry, vite.market.config.ts (outDir: dist-market,
  manifest id: market-app, theme: red #dc2626 — Muladhara chakra)
- src/market-app/{main.ts, app.ts, app.config.ts, App.vue} bootstraps
  base + market only, with acceptTokenFromUrl for shared auth from hub
- npm run dev:market / build:market / preview:market
- main app SW denylist extended with /market/, /cart/, /checkout/

Closes #18.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 08:57:34 +02:00
ee8f1d9ba6 feat: add standalone chat PWA build
Adds a standalone encrypted chat PWA at chat.${domain}, built from
the existing src/modules/chat plugin. Same standalone pattern as
wallet/castle/activities:
- chat.html entry, vite.chat.config.ts (outDir: dist-chat,
  manifest id: chat-app, theme: green #16a34a — Anahata chakra)
- src/chat-app/{main.ts, app.ts, app.config.ts, App.vue} bootstraps
  base + chat only, with acceptTokenFromUrl for shared auth from hub
- npm run dev:chat / build:chat / preview:chat
- main app SW denylist extended with /chat/

Closes #20.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 08:56:13 +02:00
455cfbc764 feat: add standalone wallet PWA build
Adds a standalone Lightning wallet PWA at wallet.${domain}, built
from the existing src/modules/wallet plugin. Mirrors the Castle and
Activities standalone patterns:
- wallet.html entry, vite.wallet.config.ts (outDir: dist-wallet,
  manifest id: wallet-app, theme: yellow #eab308 — Manipura chakra)
- src/wallet-app/{main.ts, app.ts, app.config.ts, App.vue} bootstraps
  base + wallet only, with acceptTokenFromUrl for shared auth from hub
- npm run dev:wallet / build:wallet / preview:wallet
- main app SW denylist extended with /wallet/

Closes #19.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 08:54:36 +02:00
af338016c6 refactor: rename links module to forum
The links module already implements a reddit-style link aggregator
(NIP-72 communities + kind 1111 + voting). Renaming to forum aligns
the module name with its purpose ahead of extracting it as a
standalone PWA at forum.${domain}.

This is a pure rename — no behavior changes. Affects:
- src/modules/links → src/modules/forum (git mv)
- linksModule export → forumModule
- appConfig.modules.links → appConfig.modules.forum
- log/event source strings: 'links' → 'forum'

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 08:52:37 +02:00
f4d5594bef feat: add login icon in top-right of Castle app when not authenticated
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 19:55:45 +02:00
7181b55d52 fix: scope PWA service workers to prevent cross-app interference
When multiple SPAs share the same origin (e.g., /sortir/ and /castle/
on demo.aiolabs.dev), their service workers conflict. Each app's
workbox now scopes its navigateFallback with navigateFallbackAllowlist,
and the main app excludes standalone paths via navigateFallbackDenylist.

- Main app: denylist /sortir/ and /castle/ from its service worker
- Sortir: allowlist only /sortir/ paths, fallback to activities.html
- Castle: allowlist only /castle/ paths, fallback to castle.html
- Icon paths use relative URLs (work with any base path)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 19:48:45 +02:00
87f649f048 feat: add login icon button when user is not authenticated
Shows a LogIn icon next to the refresh button on the activities
page when the user isn't logged in.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 19:12:47 +02:00
f60b9ca1d4 fix: handle nullable event_end_date in EventsPage and useEvents
event_end_date is now optional (null when not provided). Update
formatDate to accept null, and pastEvents filter to fall back
to event_start_date.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 18:58:02 +02:00
5ec8f21986 feat: add geohash map picker coming soon indicator on event form
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 18:31:14 +02:00
31efc50fad refactor: use single POST /events endpoint with invoice key
Remove proposeEvent(), consolidate to createEvent() with invoice key.
Backend determines approval status based on user role and settings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 18:24:36 +02:00
f44c3827b1 feat: use propose endpoint for user event creation
Replace CreateActivityDialog (direct Nostr publish) with
CreateEventDialog (LNbits propose flow) on ActivitiesPage.
Users submit events via POST /events/propose with invoice key.
Admin reviews and approves before events go live.

Add proposeEvent() to TicketApiService for invoice-key auth.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 18:13:53 +02:00
dcb26db685 feat: simplify event creation form, add location + categories
- Only title and start date are required
- Description, location, categories, image, tickets visible by default
- End date and promo codes in collapsible "More options" section
- Categories use badge toggles matching the activities module
- Use ScrollArea for proper shadcn scrolling
- Update CreateEventRequest and TicketedEvent types for new fields

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 18:07:44 +02:00
38492ad592 fix: support demo login in standalone apps
Standalone apps now conditionally load LoginDemo.vue when
VITE_DEMO_MODE=true, matching the main app's behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 17:51:33 +02:00
1edea25862 feat: support path-based deployment for standalone apps
Add VITE_BASE_PATH support to standalone app configs so they can be
served under a path prefix (e.g., app.domain.com/sortir/) instead of
a separate subdomain. This enables shared auth via same-origin
localStorage.

- Vite configs: configurable base path via VITE_BASE_PATH env var
- Routers: use import.meta.env.BASE_URL for history base
- PWA manifests: use base path for start_url and scope
- Default: / (backward compatible with subdomain mode)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 17:43:49 +02:00
cf08b76515 fix: improve task event filtering in activities feed
Filter by both event-type:task tag and presence of status tag
(NIP-52 calendar events don't have status on kind 31922, only
on RSVP kind 31925). This catches manually-created task events
that may not have the event-type tag.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 00:12:12 +02:00
680b1a97e6 fix: filter out task events from activities feed
Tasks reuse NIP-52 kind 31922 but tag events with event-type:task.
Filter these out in parseNostrEventToActivity so household chores
don't show up as community activities.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 00:00:08 +02:00
357ec3f3e1 fix: use POST endpoint for ticket purchase (upstream API compat)
The GET /tickets/{event_id}/user/{user_id} endpoint was a custom
addition not present in the upstream LNbits events extension. Use
the canonical POST /tickets/{event_id} with user_id in the body.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 23:44:39 +02:00
b265296210 fix: register activities module in main app
The activities module was only registered in the standalone Sortir app,
not the main app. When events module was removed, its registration was
deleted but activities was never added in its place.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 23:26:09 +02:00
e61d3c4d46 Consolidate events ticketing into activities module
Absorb the disabled events module into the active activities module,
eliminating duplicated LNbits events extension API surface and legacy
imports. Activities now owns all ticketing UI (EventsPage, MyTicketsPage
with QR codes, PurchaseTicketDialog, CreateEventDialog) alongside its
existing Nostr NIP-52 calendar event discovery.

- Internalize payInvoiceWithWallet in PaymentService (core LNbits endpoint)
- Enhance TicketApiService with createEvent and getCurrencies methods
- Add TICKET_API DI token for canonical ticket service access
- Port composables (useTicketPurchase, useUserTickets, useEvents) with DI
- Port components (PurchaseTicketDialog, CreateEventDialog)
- Replace MyTicketsPage placeholder with full QR-code ticket display
- Add /events route to activities module
- Delete src/modules/events/, src/lib/api/events.ts, src/lib/types/event.ts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 22:26:28 +02:00
bac9fd091e Fix balance sign interpretation on Castle balance page
Castle API returns positive = user owes castle, negative = castle owes
user. The display was inverted, showing "you owe" after submitting an
expense when it should show "owed to you".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 17:07:26 +02:00
b0729ea23d Add demo login page behind VITE_DEMO_MODE feature flag
Restores LoginDemo.vue from the demo-login branch. When
VITE_DEMO_MODE=true, the main app uses LoginDemo.vue which allows
instant demo account creation with auto-generated credentials.

Production deployments are unaffected (flag defaults to false).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 16:39:55 +02:00
d498030da0 Add standalone Castle accounting app
New standalone app at castle.html with its own Vite config, app shell,
and bottom nav (Record, Transactions, Balance, Wallet, Settings). Reuses
existing expenses and wallet modules with base module for a focused
accounting experience.

Features:
- Expense submission via existing AddExpense dialog
- Income submission placeholder (feature-flagged, pending backend)
- Balance page with pending expense tracking
- Expense drafts with receipt photo upload and BTC price snapshots
- Cross-subdomain auth token relay via ?token= URL parameter
- i18n support (en/fr/es)
- PWA with offline support

Also adds token relay to activities-app for consistent cross-app auth.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 16:08:53 +02:00
Patrick Mulligan
b1e8534ca7 merge nostrized-events module into unified main
Adds the standalone activities/events PWA build:
- vite.activities.config.ts (standalone entry point)
- build:activities npm script
- i18n support (Spanish Latin American translations)
- Map/calendar UI improvements

Conflicts resolved keeping main-unified's module system
(links, tasks, expenses, di-container, navigation).
2026-04-25 07:38:17 -04:00
Patrick Mulligan
efacc43429 merge atio features into unified main branch
Merge atio's UI improvements (sidebar layout, chat fixes, checkout
simplification, z-index fixes) into cfaun's module system (links,
tasks, expenses).

Conflicts resolved keeping cfaun's versions for:
- Home.vue (multi-action FAB with quick actions)
- di-container.ts, useModularNavigation.ts (module registry)
- nostr-feed/index.ts (disabled, replaced by links)
- package.json/lock (cfaun's dependency tree)

Branding files kept as cfaun's — per-target branding should come
from build-time config, not branches.

Removed: target-ui.md (atio reference doc, no longer needed)

Next: refactor app.config.ts to read enabled modules from VITE_*
env vars so per-target config lives in the deploy flake.
2026-04-25 04:09:20 -04:00
93c2a73e21 Internationalize all UI strings and localize date formatting
All hardcoded English strings now use t() with i18n keys: bottom nav
tabs, search placeholder, empty states, favorites page, settings page.

Added useDateLocale composable that maps the current i18n language to
the corresponding date-fns locale (fr/es/enUS). All date formatting
across ActivityCard, ActivityDetailPage, DatePickerStrip, calendar
view, and search overlay now passes the locale to date-fns format().
Month names, day names, and date labels change with language switch.

Added nav, search, favorites, and settings i18n sections to all three
locales (EN/FR/ES).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-21 07:24:43 +02:00
f782cd1a7a Replace inline search with dropdown overlay for mobile
New ActivitySearchOverlay component: compact dropdown anchored to the
search input showing thumbnail, title, date, and location for each
result. Limited to 8 results, scrollable. Stays visible above the
keyboard on mobile. Tap a result to navigate, tap outside or clear
to dismiss. Uses the same Fuse.js fuzzy search under the hood.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 17:25:07 +02:00
a75885ca76 Only fit map bounds on initial load, not on every activity update
Prevents the map from resetting zoom/pan when new activities stream
in from relays. Users can now freely zoom and pan without being
snapped back to the world view.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 15:46:39 +02:00
276e1a8135 Fix empty state icon: use CalendarSearch with element opacity
Replaces Calendar with CalendarSearch for better empty-state semantics.
Uses opacity-30 on the element instead of text color opacity to avoid
visible stroke overlaps on SVG icons.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 15:43:57 +02:00
36c8cb8c7a Add Spanish (Latin American) activities translations
Full activities i18n for Spanish: categories, detail page, tickets,
filters. Uses Latin American terminology (boleto instead of entrada,
charla instead of ponencia). Added Spanish to the standalone app
Settings language picker alongside French and English.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 13:08:37 +02:00
2ceedf8bbf Add env vars for default locale and map center
VITE_DEFAULT_LOCALE (fr/en/es) sets the initial language for the
standalone app when no user preference is saved. VITE_DEFAULT_MAP_CENTER
(lat,lng) configures the default map center point. Both fall back to
sensible defaults (fr and France center) when not set.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 12:55:08 +02:00
8a3ff14568 Skip activities with invalid dates in calendar view
Prevents RangeError from format() on activities with unparseable
start timestamps.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 12:44:49 +02:00
4926c3a313 Add map and calendar views (Phase 5)
Map view: Leaflet + OpenStreetMap with markers from NIP-52 geohash
tags. Click popup navigates to activity detail. Auto-fits bounds to
show all markers. Geohash decoding via ngeohash added to Activity
model conversion.

Calendar view: Month grid with activity dots (up to 3 per day).
Click a day to see activities listed below the calendar. Month
navigation with prev/next buttons.

New dependencies: leaflet, @types/leaflet, ngeohash, @types/ngeohash.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 12:41:38 +02:00