Files
Oxicloud/frontend/static/basemaps
Claude 5494efea35 feat(frontend): port Places, People & photo tabs to the Svelte app
Bring the Photos/People/Places UI that main added (in the legacy vanilla
frontend) into the SvelteKit rewrite, wired to the now-merged backend
(/api/photos/geo, /api/people/*).

Photos page (routes/photos/+page.svelte):
- Moments | Places | People sub-tabs (the People tab appears only when the
  faces feature is enabled, via a /api/people capability probe), mirroring
  the vanilla photos sub-nav.
- Square ↔ justified layout toggle. Justified uses a Flickr-style
  row-packer over the width/height the photos list endpoint returns
  (PhotoItem), falling back to 1:1 when dimensions are missing.

New components:
- PhotoLightbox.svelte — the lightbox extracted from the photos page into a
  reusable component (items + bindable index, onDelete callback) so the
  grid, People and Places all share one implementation (no duplication).
- PlacesMap.svelte — MapLibre GL map with server-clustered markers; the
  vector basemap is optional (probed at /basemaps/basemap.pmtiles, themed
  fallback otherwise). Cluster click zooms in or opens the lightbox.
- PeopleView.svelte — identity-cluster grid → per-person photo grid, with
  rename via the in-app prompt dialog.

Supporting:
- api/endpoints/people.ts (+ peopleEnabled probe); photos.ts gains
  fetchPhotosGeo + GeoCluster + PhotoItem; fileThumbnailUrl takes a size.
- lib/vendor/maplibre.ts — minimal typings + lazy loader for the vendored
  MapLibre GL + pmtiles globals (kept any-free for ESLint).
- utils/media.ts — shared isVideo / photoTimestamp / minimalPhotoItem.
- Vendored maplibre-gl 5.24.0 + pmtiles 4.4.1 under static/vendors and an
  optional static/basemaps dir, matching the PR's vendored-asset pattern.
- New photos.tab_*/layout_*/map_* + people.* keys in en.json.

Verified: npm run check (svelte-check + eslint + stylelint + prettier),
npm run test:unit (36 pass), and npm run build all green.
2026-06-19 12:59:16 +00:00
..

Places basemap (optional)

The Places photo map renders your geotagged photos as clusters. It works out of the box without a basemap (clusters on a plain background). To get a real street/terrain backdrop, drop a self-hosted vector basemap here — no third-party tile API, fully offline.

How it works (Approach "A")

OxiCloud already serves static/ through tower-http's ServeDir, which honours HTTP Range requests. A PMTiles basemap is a single file read directly by the browser via Range — so the basemap is just a static file the app already knows how to serve. No extra backend, no tile server, no API keys.

Enabling it

  1. Get a Protomaps .pmtiles basemap (vector, ODbL OpenStreetMap data):
    • Whole planet z0–15 (~120 GB) or a smaller global z0-6 (~60 MB), or
    • A regional extract (recommended — only the area you need, a few MB):
      # one-time, downloads only your bounding box from the remote planet
      pmtiles extract https://build.protomaps.com/<DATE>.pmtiles basemap.pmtiles \
        --bbox=<west>,<south>,<east>,<north>
      
      See https://docs.protomaps.com/basemaps/downloads
  2. Place it here as static/basemaps/basemap.pmtiles (this path is git-ignored on purpose — see .gitignore).
  3. Reload the Places view. The map will pick it up automatically.

The bundled style is label-light (water / land / roads / buildings, no text) so it needs no glyph/sprite assets. Attribution “© OpenStreetMap” (ODbL) is shown automatically when a basemap is present.