# Prague 4-Day Interactive Map

Static single-page Leaflet map of a Prague trip — sights, museums, viewpoints,
parks, food, beer, art, markets, optional and practical stops, plus an optional
**Marathon / hiking layer** with 10 km+ days. Each place carries its Czech name,
etymology (EN + Romanian), historical context, and cultural notes.

Deployed as a static site (Vercel).

## Files

| Path                  | Purpose                                                                 |
|-----------------------|-------------------------------------------------------------------------|
| `index.html`          | App shell: styles, map, UI wiring. Loads JSON at runtime.               |
| `data/places.json`    | All places (one array).                                                 |
| `data/routes.json`    | Per-day standard + marathon routes, plus route summary notes.           |
| `data/config.json`    | Category colors/labels, filter + legend order, tile layers, local image IDs. |
| `images/*.jpg`        | Local place photos (sourced from Wikipedia/Wikimedia Commons).          |
| `fetch_images.sh`     | Re-runnable script that fetches images by Wikipedia page title.         |
| `README.md`           | This file.                                                              |

## Run locally

```
python3 -m http.server 8000
# open http://localhost:8000/
```

No build step. No dependencies beyond the Leaflet CDN. Note that `file://` will
fail because the app uses `fetch()` to load the JSON data.

## Deploy

Any static host. For Vercel: this lives in the `prague/` subfolder of the repo
and is served at `/prague/` — `index.html` plus the sibling `data/` and `images/`
folders (all paths are relative, so the subfolder works with no config). The
repo root serves a small picker page linking to each trip.

## Data model

### `data/places.json`

Array of place objects:

```json
{
  "id": "charles",
  "name": "Charles Bridge",
  "day": 1,
  "category": "sight",
  "mode": "both",
  "lat": 50.0865, "lng": 14.4114,
  "time": "20–30 min",
  "desc": "…",
  "tip": "…",
  "czech": "Karlův most",
  "meaning": "…",
  "meaningRo": "…",
  "history": "…",
  "culture": "…"
}
```

- `day`: `0` = any / base, `1`–`4` = Thu–Sun
- `category`: one of the keys in `data/config.json` → `categories`
  (`sight, museum, viewpoint, park, food, beer, art, market, optional, practical, hike, base`)
- `mode`: `both` (default visible) or `marathon` (only when marathon toggle is on)
- `czech`, `meaning`, `meaningRo`, `history`, `culture`, `tip`: all optional — rendered only if present

### `data/routes.json`

```json
{
  "standard": { "1": ["id1","id2",…], "2": […], "3": […], "4": […] },
  "marathon": { "1": […], "2": […], "3": […], "4": […] },
  "notes":    { "standard": { "1":"…", … }, "marathon": { "1":"…", … } }
}
```

### `data/config.json`

- `categories` — per-category `{ label, color, palette }`. Palette is used for the SVG placeholder image gradient.
- `filters` — ordered list of filter buttons (including `"all"`).
- `legend` — ordered list of categories shown in the sidebar legend.
- `tiles` — map base layers available in the "Map style" switcher. Mark one with `"default": true`.
- `localImages` — IDs for which a file exists at `images/<id>.jpg`. IDs not listed fall back to a colored placeholder.

## UI controls

| Control                  | Effect                                                     |
|--------------------------|------------------------------------------------------------|
| Language (EN/RO)         | Swaps `meaning` ↔ `meaningRo` everywhere                   |
| Mode (Standard/Marathon) | Shows/hides `mode:"marathon"` places and switches route set |
| Day (All/Thu–Sun)        | Filters places and draws that day's route polyline         |
| Category filter          | Filters by `category` (respects current mode)              |
| Map style                | Switches the Leaflet tile layer (OSM / Light / Dark / Satellite) |

## Images

Each place auto-resolves its image:

1. If `id` is in `config.localImages` → uses `images/<id>.jpg`.
2. Otherwise → inline SVG placeholder colored by category (from `categories[cat].palette`).
3. If the local file is missing on load, `onerror` swaps to the SVG placeholder.

To add an image for a place `foo`:
```
# drop images/foo.jpg (any reasonable aspect ratio)
# add "foo" to data/config.json → localImages
```

To fetch fresh Wikipedia images:
```
# edit the `pairs` array in fetch_images.sh with "id|Wikipedia_Title"
./fetch_images.sh
cd images && for f in *.jpg; do sips -Z 1200 -s format jpeg -s formatOptions 80 "$f" --out "$f"; done
```

## Adding a new place

1. Append an object to `data/places.json` with at minimum `id, name, day, category, mode, lat, lng, time, desc`.
2. Optionally fill `tip, czech, meaning, meaningRo, history, culture`.
3. If you want it in a day's route, add its `id` to `routes.standard[<day>]` or `routes.marathon[<day>]` in `data/routes.json`.
4. For an image: add it to `images/<id>.jpg` and to `data/config.json` → `localImages`.

## Adding a new category

1. Add a new entry to `data/config.json` → `categories` with `label`, `color`, `palette`.
2. Add the key to `filters` (and optionally `legend`) in `data/config.json`.
3. Start tagging places with that `category`.

## Adding a new tile layer

Add an entry under `data/config.json` → `tiles`. Any `{s}`, `{z}`, `{x}`, `{y}` template URL
that Leaflet supports works. Mark one layer `"default": true` to set the initial tile set.

## Design notes

- Data is split out of the page so it can be edited and diffed cleanly.
- Categories, filters, legend, and tile choices are driven entirely by `config.json` — no HTML changes needed to add one.
- Images are served locally so the map works offline and on any static host.
- Czech name + etymology is rendered in an italic gold line under the English title so it reads like a subtitle; history is a blue-bordered block, cultural notes are pink.
- The marathon layer is additive: standard mode never shows `mode:"marathon"` pins, and the filter auto-resets when you switch back to standard if "hike" was selected.

## Known gaps

- A few marathon waypoints are descriptive (warmup loop, southriver, hiking checkpoint, etc.) — they intentionally don't have Wikipedia content.
- Romanian translations are provided for places with distinctive Czech names; purely-English names (e.g. "Bad Flash Bar") have no translation field.
- Newly added places (museums, viewpoints, parks, art, markets, new sights) don't yet have local images — they render as colored placeholders until images are fetched.

## Resuming work

- Source of truth for place facts: Wikipedia pages for each landmark. Cross-check any edits there.
- The session that built this iterated from `prague-interactive-map.html` → `-v2` → `-v3` → `-v4-marathon.html` in the parent `Downloads` folder; `v4` added the marathon layer, and this repo merged it into `index.html`, then split data into `data/*.json`.
- Git remote: `origin` points to `pirvu/prague` on GitHub. Branch: `master`.
