point docs at library/layouts and fix the stale bunx and provider-ladder claims

The top-level layouts/ directory does not exist; the wrappers live in library/layouts/.
Six references across four docs named the phantom path, including a copy-pasteable
cd command and a README-longform link that resolved to docs/layouts/README.md (a 404).

how-to.md taught bunx for the iOS scaffold. bunx is not on PATH here, which is the
exact failure package.json already documents in cap:sync; point both at the local bin.

useMapProvider.js's own header listed three resolution rungs, omitting ?provider= and
misnumbering window.MAP_PROVIDER. The function implements four. how-to.md was correct.
This commit is contained in:
doxa-maps-88655c70 2026-09-21 10:43:11 +00:00
parent 70d0e36ad3
commit 2fa4bf992a
5 changed files with 25 additions and 14 deletions

View file

@ -268,7 +268,7 @@ Your map data has to come from somewhere. Common sources:
| **[docs/why.md](./docs/why.md)** | 2 min — the problem, the idea, one diagram |
| **[docs/tutorial.md](./docs/tutorial.md)** | build your first map, step by step (great to hand to your agent) |
| **[docs/how-to.md](./docs/how-to.md)** | task recipes (embed, data, mobile) |
| **[layouts/README.md](./layouts/README.md)** | the SPA composition machinery (many maps → one app) |
| **[library/layouts/README.md](../library/layouts/README.md)** | the SPA composition machinery (many maps → one app) |
| **[docs/architecture/](./docs/architecture/)** | the deep end — embeddability, app-wrappers, file map |
---

View file

@ -1,9 +1,9 @@
# Architecture — app wrappers
> The simple overview is in `layouts/README.md`. This is the full contract for building and wiring
> an app wrapper.
> The simple overview is in `library/layouts/README.md`. This is the full contract for building and
> wiring an app wrapper.
Each folder in `layouts/` is an **app wrapper**: a host shell that composes doxa-maps plugin-designs
Each folder in `library/layouts/` is an **app wrapper**: a host shell that composes doxa-maps plugin-designs
(the independently-built custom elements) into one application.
## Terminology (deliberate — don't drift)
@ -57,7 +57,7 @@ local assets. Paths follow the Lucide idiom (24×24, 2px stroke, round caps).
## Local staging
```bash
cd layouts/app-wrapper-material
cd library/layouts/app-wrapper-material
python3 -m http.server 4173 --bind 0.0.0.0
```
@ -86,7 +86,7 @@ FILENAMES (`prayer-progress.js` → `'prayerProgress'`).
## How a wrapper becomes the served SPA
`bun run shell` (`internal/install-shell.mjs`) **copies** `layouts/<wrapper>/` to the root of
`bun run shell` (`internal/install-shell.mjs`) **copies** `library/layouts/<wrapper>/` to the root of
`public/`, so `public/index.html` is the shell and `public/doxa-maps/…` are the bundles it
mounts — one served tree, two roles. Copy (not symlink) keeps Railway/Capacitor/file:// happy;
`--no-token` omits the local-only `token.local.js` (mandatory for release builds). Capacitor

View file

@ -159,7 +159,7 @@ Steps:
> **Trap: `onMounted` runs last and overwrites your default.** If the source initializes a
> value in its mount handler, setting it at declaration is not enough — one constant must
> drive both the initial `ref` and the `onMounted` path.
4. **Wire it into the shell registry** (`layouts/app-wrapper-material/index.html`, the
4. **Wire it into the shell registry** (`library/layouts/app-wrapper-material/index.html`, the
`PROFILES` object). A nav entry with no registry entry renders a silent placeholder. Take
`src` from the folder, `tag` from `customElements.define` in `index.js`, `profile` from the
`.vue` filename — never from a guess.
@ -234,7 +234,7 @@ snippets (leave it empty for relative URLs that work wherever the folder is drop
Several maps + one layout = a single-page app, served from the same `public/` tree.
1. **Pick a wrapper** in `layouts/` (`app-wrapper-material` is the full shell: sidebar,
1. **Pick a wrapper** in `library/layouts/` (`app-wrapper-material` is the full shell: sidebar,
lazy-loading, i18n).
2. **Register your map** in two places inside the wrapper:
- `nav.js` — add a sidebar entry (`{ kind, id, label, icon, target }`; `target` controls
@ -268,8 +268,13 @@ bun run apk:install # adb install onto a connected device/emulator
Step by step instead: `bun run build` → `bun run cap:sync` → open `capacitor/android` in Android Studio.
**iOS** (scaffold once on a Mac): `bunx cap add ios`, then `bun run build && bunx cap sync ios`, and
open `capacitor/ios` in Xcode. Same `webDir: public`.
**iOS** (scaffold once on a Mac): `./node_modules/.bin/cap add ios`, then `bun run build &&
./node_modules/.bin/cap sync ios`, and open `capacitor/ios` in Xcode. Same `webDir: public`.
> **Invoke the local bin, not `bunx`.** `bunx` is not on PATH in every environment (it exits 127,
> *command not found*), which is what broke `cap:sync` → `apk:debug` → `phone` at step one. The
> Capacitor CLI is installed locally, so `./node_modules/.bin/cap` always resolves. Elsewhere this
> repo uses the spaced `bun x` form for the same reason.
> `cap sync` copies `public/` into the native project's assets. A wrong `webDir` gives a **blank
> white screen** at launch (empty assets), not an error — `bun run cap:verify` guards against it.

View file

@ -80,7 +80,6 @@ doxa-maps/
│ (folders starting with _ or . are SKIPPED by the build)
│
├── internal/ ← the bundler's own build scripts — never edited by map builders
├── layouts/ ← the app shell: mounts several bundles as one single-page app
├── capacitor/ ← native projects (android/, ios/)
├── public/ ← THE SERVED WEB-ROOT, committed:
│ ├── index.html the app shell

View file

@ -1,12 +1,19 @@
/**
* useMapProvider.js — resolve the active map engine ("provider").
*
* Resolution order (first defined wins):
* Resolution order (first defined wins) — matches resolveMapProvider below EXACTLY:
* 1. profile-config `provider` — per-map, set in the profile-config JSON
* 2. window.MAP_PROVIDER — runtime override (e.g. a host reads ?provider=…)
* 3. 'mapbox' — default; existing behaviour, never regresses
* 2. ?provider= in the page URL — read here directly, so any generated leaf page can be
* flipped from the URL without the host doing anything
* 3. window.MAP_PROVIDER — host global, for a host that sets it programmatically
* 4. 'mapbox' — default; existing behaviour, never regresses
*
* Valid values: 'mapbox' | 'maplibre'. Anything else falls back to the default.
*
* ★ This header previously listed only THREE rungs, omitting ?provider= and numbering
* window.MAP_PROVIDER as step 2 — it described a ladder the function does not implement.
* docs/how-to.md ("Swap the map engine") carries the correct four-rung order; keep the two
* in sync, and treat THIS function as the authority when they disagree.
*/
import { inject } from 'vue'