docs: add performance section (one inlined bundle > vue-from-CDN); simplify app-profiles + template-bundle READMEs
This commit is contained in:
parent
6785dd826b
commit
81db8dbebb
3 changed files with 95 additions and 337 deletions
15
README.md
15
README.md
|
|
@ -38,6 +38,21 @@ standalone embeds *and* the building blocks of a full site.
|
|||
is a runtime setting, not baked in. You can point a map at a different API — or swap the map engine
|
||||
itself (Mapbox ↔ MapLibre) — by changing config, no rebuild. Portable and future-proof.
|
||||
|
||||
## Why it's fast (one self-contained file)
|
||||
|
||||
Everything a map needs is built into **one file** — the Vue runtime, the components, and the CSS
|
||||
are all inlined. The browser makes **one request** and the map runs. There's no waterfall of extra
|
||||
downloads and no dependency on a separate Vue CDN being online or version-matched.
|
||||
|
||||
- **One output file.** The JS carries its own CSS (`cssCodeSplit: false`) and its own Vue, built as
|
||||
a single IIFE. Nothing to wire up, nothing that can 404 on its own.
|
||||
- **Faster than loading Vue from a CDN.** A CDN copy of Vue is an extra request plus a version you
|
||||
have to keep in sync; inlining removes both. Fewer moving parts, less technical debt.
|
||||
- **Lean.** Tree-shaking drops unused code, so the single file stays small even though it's complete.
|
||||
|
||||
(The one deliberate exception is the heavy PDF-export library — loaded from a CDN only if someone
|
||||
actually exports — so the everyday map load never pays for it.)
|
||||
|
||||
## Quickstart
|
||||
|
||||
Bun is required (`bun.lock` is the committed lockfile — install from <https://bun.sh>).
|
||||
|
|
|
|||
|
|
@ -1,224 +1,72 @@
|
|||
# app-profiles/ — where YOUR maps live
|
||||
|
||||
> **Zero-context summary:** the `doxa-maps` repo is a **shared Apache template**
|
||||
> in `../library/` (aliased `@map`). You never edit it per-map. Instead, you make a
|
||||
> folder **here**, in `app-profiles/<your-map>/`, and build *your* map by
|
||||
> composing the template's building blocks. Your folder is **yours** — your
|
||||
> color strategy, your API connections, your i18n. The template is **shared** —
|
||||
> Apache-2.0, common to everyone, propagated to every map on the next build.
|
||||
The shared template lives in `../library/` (aliased `@map`) — you never edit it per-map.
|
||||
You build your map by making a folder **here**, `app-profiles/<your-map>/`, and composing the
|
||||
template's building blocks. Your folder is yours (colors, API, i18n); the template is shared
|
||||
(Apache-2.0, propagated to every map on the next build).
|
||||
|
||||
If you only remember one thing: **shared template → `app-profiles/<your-map>/` →
|
||||
your custom color + API + i18n.** Read on for exactly where each piece goes.
|
||||
|
||||
---
|
||||
|
||||
## The bundle pattern (folder → bundle → profiles → script tags)
|
||||
|
||||
This is the whole convention in one picture:
|
||||
## The pattern in one picture
|
||||
|
||||
```
|
||||
app-profiles/<your-map>/ ← a FOLDER here = one JS BUNDLE named after the folder
|
||||
├── index.js ← entry: registers the custom element, discovers profiles
|
||||
├── overview.vue ← one .vue = one APP PROFILE (FLAT — directly in the folder)
|
||||
└── detail.vue ← another profile in the SAME bundle
|
||||
app-profiles/<your-map>/ ← one FOLDER = one BUNDLE, named after the folder
|
||||
├── index.js ← entry: registers the custom element, finds the profiles
|
||||
├── overview.vue ← one .vue = one PROFILE (flat in the folder — no profiles/ subfolder)
|
||||
└── detail.vue ← another profile in the SAME bundle
|
||||
|
||||
builds to ─────────────► public/doxa-maps/<your-map>/<your-map>.js (one file)
|
||||
builds to ─────────────► public/doxa-maps/<your-map>/<your-map>.js (one file)
|
||||
```
|
||||
|
||||
- **Folder name = bundle name.** `app-profiles/<your-map>/` builds to exactly one
|
||||
file, `public/doxa-maps/<your-map>/<your-map>.js`. (Folders starting with `_` or `.` are
|
||||
skipped — handy for staging WIP.)
|
||||
- **Each `.vue` in the folder = one app profile.** Profiles sit **flat, directly
|
||||
in the bundle folder** — there is **no `profiles/` subfolder**. A profile is one
|
||||
map screen; one bundle can hold many. (See `template-bundle/` for a minimal
|
||||
two-profile example.)
|
||||
- **Each profile is reachable from a single `<script src>` + custom element.** The
|
||||
page loads the one bundle, then picks which profile to show with the
|
||||
`profile` field in the element's `profile-config`. So every profile has a
|
||||
paste-ready embed snippet that differs only in that one field.
|
||||
- **Folder name = bundle name.** Folders starting with `_` or `.` are skipped (handy for WIP).
|
||||
- **Each `.vue` = one profile** (one map screen). One bundle can hold many.
|
||||
- **Pick the profile at embed time** with the `profile` field — every profile shares one bundle:
|
||||
|
||||
```html
|
||||
<!-- same bundle, two profiles, chosen by `profile` -->
|
||||
<script src="/doxa-maps/<your-map>/<your-map>.js"></script>
|
||||
<doxa-map profile-config='{"profile":"overview","tk":"pk.eyJ..."}'></doxa-map>
|
||||
<doxa-map profile-config='{"profile":"detail","tk":"pk.eyJ..."}'></doxa-map>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## The embed template (paste-ready — just swap the bundle name)
|
||||
|
||||
Copy this onto any page. Change **`<your-map>`** to your folder name and
|
||||
**`profile`** to one of your `.vue` filenames (without `.vue`). Nothing else
|
||||
changes between maps.
|
||||
|
||||
```html
|
||||
<!-- 1. Mapbox peer (loaded once per page, before any bundle) -->
|
||||
<link href="https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css" rel="stylesheet" />
|
||||
<script src="https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js"></script>
|
||||
<script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v5.0.0/mapbox-gl-geocoder.min.js"></script>
|
||||
|
||||
<!-- 2. Your bundle — swap <your-map> for the app-profiles folder name -->
|
||||
<script src="/doxa-maps/<your-map>/<your-map>.js"></script>
|
||||
|
||||
<!-- 3. The map — swap `profile` for one of your <name>.vue files (without .vue) -->
|
||||
<doxa-map profile-config='{
|
||||
"profile": "<your-map>",
|
||||
"tk": "pk.eyJ...", // your Mapbox token
|
||||
"dataSource": { "type": "rest-api",
|
||||
"endpoint": "https://your-api.example/api/people-groups/list" }
|
||||
}'></doxa-map>
|
||||
```
|
||||
|
||||
- The `<script src>` URL is the only thing that changes between hosting modes:
|
||||
a **relative** path (`/doxa-maps/<your-map>/<your-map>.js`) when the host serves the file, or an
|
||||
**absolute CDN** URL (`https://cdn.example.org/.../<your-map>.js`) when an
|
||||
external/partner site serves it. The bundle is identical either way. See
|
||||
`../CONTRIBUTING.md` for the two CDN modes.
|
||||
- The same bundle can point at different data with no rebuild — `profile-config`
|
||||
is read at runtime, so swapping `dataSource` or `tk` on the page is enough.
|
||||
|
||||
---
|
||||
|
||||
## The three-step agent workflow
|
||||
|
||||
Adding a map is three steps, start to finish:
|
||||
## Add a map — three steps
|
||||
|
||||
```bash
|
||||
# ── Step 1: create the folder + at least one profile .vue ──────────────────
|
||||
# 1. create the folder + one profile
|
||||
mkdir -p app-profiles/<your-map>
|
||||
# app-profiles/<your-map>/index.js ← copy doxa-simple-map/index.js, rename the tag
|
||||
# app-profiles/<your-map>/<name>.vue ← your screen (FLAT in the folder), built from @map/* blocks
|
||||
# index.js ← copy doxa-simple-map/index.js, rename the tag
|
||||
# <name>.vue ← your screen, built from @map/* blocks (flat in the folder)
|
||||
|
||||
# ── Step 2: build ──────────────────────────────────────────────────────────
|
||||
npm run build
|
||||
# → public/doxa-maps/<your-map>/<your-map>.js appears
|
||||
# (or, for just this one: BUNDLE=<your-map> npm run build:bundle)
|
||||
# 2. build
|
||||
npm run build # → public/doxa-maps/<your-map>/<your-map>.js
|
||||
# (just this one: BUNDLE=<your-map> npm run build:bundle)
|
||||
|
||||
# ── Step 3: get the script tag and embed ──────────────────────────────────
|
||||
# <script src="/doxa-maps/<your-map>/<your-map>.js"></script>
|
||||
# <doxa-map profile-config='{"profile":"<name>","tk":"pk.eyJ..."}'></doxa-map>
|
||||
# 3. embed the script tag + element (dev staging at `npm run dev` shows a paste-ready snippet)
|
||||
```
|
||||
|
||||
The dev staging index (`npm run dev`, served at `/`) also **auto-detects** the new
|
||||
folder and shows a copy-paste embed snippet for each profile — no edit to any
|
||||
index needed. See `../CONTRIBUTING.md` for the build-vs-dev distinction.
|
||||
## Your three things (everything else is shared)
|
||||
|
||||
---
|
||||
- **Colors** — how pins are colored. Pick one the template ships (`getColorStrategy('language-family')`),
|
||||
or drop your own in `app-profiles/<your-map>/src/colors/` (start from
|
||||
`template-bundle/src/colors/example-mode.js`). Never edit `@map/colors/` to recolor your map.
|
||||
- **API** — your map reads its data from the `profile-config` on the page, so the same bundle points
|
||||
at different data with no rebuild. `DataSourceManager` accepts `csv` (bundled file), `api` (one JSON
|
||||
URL), or `rest-api` (a live REST endpoint, the default). Prefer the real API over inlined JSON.
|
||||
- **i18n** — the template ships 11 base locales in `@map/i18n/locales/`. Use `useI18n()` for strings
|
||||
and `RTL_LOCALES` for right-to-left; add or override strings from your own profile.
|
||||
|
||||
## The model — three zones, never mixed
|
||||
## The one hosting variable
|
||||
|
||||
```
|
||||
doxa-maps/
|
||||
├── library/ (alias @map) ← THE SHARED APACHE TEMPLATE — do not customize per-map
|
||||
│ ├── components/ reusable map UI (legends, toolbar, buttons, drawers)
|
||||
│ ├── composables/ useMapInstance, useMapData, useMapLayers, …
|
||||
│ ├── colors/ the menu of ways to color pins (one strategy per file)
|
||||
│ ├── config/ posterDefaults.js · posterSizes.js (map defaults: constants/mapDefaults.js)
|
||||
│ ├── api/ DataSourceManager (csv | api | rest-api), sources.json, registry
|
||||
│ ├── i18n/locales/ 11 base languages: ar de en es fr hi it pt ro ru zh
|
||||
│ ├── utils/ shared helpers
|
||||
│ └── stores/ Pinia stores (map / data / ui)
|
||||
│
|
||||
├── internal/ ← THE BUNDLER'S OWN BUILD SCRIPTS — never edited by map builders
|
||||
│
|
||||
└── app-profiles/<your-map>/ ← YOUR PRIVATE APP PROFILE — everything here is yours
|
||||
├── index.js bundle entry (registers the web component)
|
||||
├── *.vue your map screen(s) — FLAT in the folder, one per profile
|
||||
└── data/*.json (optional) your own bundled data
|
||||
```
|
||||
The only thing that changes between hosting modes is the `<script src>`: a **relative** path when
|
||||
your own site serves the file, or an **absolute CDN URL** when a partner site serves it. The bundle
|
||||
is identical either way. See `../CONTRIBUTING.md` for the two CDN modes and partner-site embedding.
|
||||
|
||||
**Shared template (`library/`, `@map`)** is the Apache-2.0 base everyone shares. Fix a
|
||||
bug or improve a legend *once* here and **every** map gets it on the next build.
|
||||
Because it is shared, never bake one map's private choices into it.
|
||||
## Profile patterns (mix freely)
|
||||
|
||||
**Your app profile (`app-profiles/<your-map>/`)** is the only place your map's
|
||||
identity lives. Nothing here leaks to anyone else's map.
|
||||
- **Individual** — one `.vue` per bundle (simplest).
|
||||
- **Parameterized** — one profile, behavior driven by `profile-config` props (e.g. `tabs[]`).
|
||||
- **Nested** — one profile that renders others (workbench-style, like `doxa-research-map`).
|
||||
|
||||
---
|
||||
## See also
|
||||
|
||||
## Where YOUR three things go
|
||||
|
||||
### 1. Your color strategy
|
||||
A *color strategy* decides how pins get colored (by language family, progress,
|
||||
religion, …). The shared menu lives in `@map/colors/` — one
|
||||
strategy per file, auto-registered by `_registry.js` (see that folder's README for the
|
||||
contract).
|
||||
|
||||
- **Pick one** the template already ships — your profile selects it by color
|
||||
mode (e.g. `getColorStrategy('language-family')`).
|
||||
- **Add your own** — drop `my-strategy.js` into your own
|
||||
`app-profiles/<your-map>/src/colors/` folder following the strategy
|
||||
contract (start from `template-bundle/src/colors/example-mode.js`). It
|
||||
merges over the shared set for **your map only** — never edit `@map/colors/`
|
||||
to recolor your own map.
|
||||
|
||||
### 2. Your API connections
|
||||
Your map gets its data through the **`profile-config`** attribute on the host
|
||||
page — so the *same* bundle can point at different data without a rebuild (see the
|
||||
embed template above). Inside your `.vue` profile you read it via
|
||||
`inject('profileConfig')`, `inject('mapboxToken')`, `inject('dataSource')`, and
|
||||
hand the source to `@map/api/DataSourceManager`, which supports three
|
||||
shapes:
|
||||
|
||||
| `type` | What | Source |
|
||||
|---|---|---|
|
||||
| `csv` | a local CSV parsed at load | a file you bundle under your own `data/` |
|
||||
| `api` | a single JSON URL | any plain JSON endpoint |
|
||||
| `rest-api` | a versioned REST endpoint (the default) | a live REST API, base URL resolved at runtime |
|
||||
|
||||
Prefer the **real API** — do not inline JSON into the bundle. If you must ship
|
||||
static data, put it in **your** `app-profiles/<your-map>/data/*.json`.
|
||||
|
||||
### 3. Your i18n
|
||||
The template ships 11 base locales in `@map/i18n/locales/`. Your profile uses
|
||||
`useI18n()` (from `vue-i18n`) for translated strings and `RTL_LOCALES`
|
||||
(from `@map/i18n`) for right-to-left handling. Add or override strings for your
|
||||
map from your own profile — the shared locales stay shared.
|
||||
|
||||
---
|
||||
|
||||
## Build conventions (how a folder becomes a bundle)
|
||||
|
||||
- **Folder name = bundle name** → builds to `public/doxa-maps/<folder-name>/<folder-name>.js`.
|
||||
- Folders prefixed with `_` or `.` are **skipped** at build time (use for staging).
|
||||
- Each folder MUST have an `index.js` entry that:
|
||||
- evaluates `import.meta.glob('./*.vue')` locally (bundle-private registry —
|
||||
profiles are **flat** in the folder, so the glob is `./*.vue`, not
|
||||
`./profiles/*.vue`) and hands it to `ProfileLoader` via
|
||||
`app.provide('profileModules', …)`,
|
||||
- registers the web component(s) via `defineCustomElement`,
|
||||
- lets `ProfileLoader` parse the host's `profile-config`.
|
||||
|
||||
The `profile` field in `profile-config` MUST match a `.vue` file sitting directly
|
||||
in your bundle folder (the design is flat — no `profiles/` subfolder). See
|
||||
`doxa-simple-map/index.js` for a complete, commented example, or
|
||||
`template-bundle/` for a minimal two-profile skeleton.
|
||||
|
||||
## Three profile patterns (mix freely)
|
||||
|
||||
- **Individual** — one `.vue` profile per bundle (simplest).
|
||||
- **Parameterized** — one profile, behavior driven by `profile-config` props at
|
||||
runtime (e.g. `tabs[]`).
|
||||
- **Nested** — one profile that internally renders others (workbench-style, like
|
||||
`doxa-research-map`).
|
||||
|
||||
## License & provenance
|
||||
|
||||
The shared template (`library/` / `@map`, build tooling, this scaffold) is
|
||||
**Apache-2.0** — a permissive base everyone shares. Your **app profiles** under
|
||||
`app-profiles/<your-map>/` are **yours**: your color strategy, API connections,
|
||||
and i18n. Building on the shared Apache template is exactly what lets you keep
|
||||
your own maps private, custom, and uniquely yours.
|
||||
|
||||
## See also — the shared `library/` (`@map`) components you build from
|
||||
|
||||
- `../library/components/` — reusable map UI: legends, toolbars, buttons, drawers
|
||||
- `../library/composables/` — `useMapInstance`, `useMapData`, `useMapLayers`, …
|
||||
- `../library/colors/README.md` — the color-strategy contract
|
||||
- `../library/api/` — `DataSourceManager` + the source registry
|
||||
- `../library/i18n/` — base locales and RTL handling
|
||||
- `../library/ProfileLoader.vue` — parses `profile-config`, mounts the right profile
|
||||
- `../README.md` — repo overview & build pipeline
|
||||
- `../CONTRIBUTING.md` — build vs dev, the two CDN modes, partner-site embedding
|
||||
- `doxa-simple-map/index.js` — fully commented reference bundle entry
|
||||
- `template-bundle/` — minimal two-profile skeleton to copy
|
||||
- `../library/colors/README.md` — the color-strategy contract
|
||||
- `../README.md` — repo overview & build pipeline · `../CONTRIBUTING.md` — build vs dev, CDN modes
|
||||
|
|
|
|||
|
|
@ -1,176 +1,71 @@
|
|||
# template-bundle — copy this to start a new map
|
||||
|
||||
You're a **programmer** (a *coder*, a *map-maker*) about to build a map. This folder
|
||||
is your starting point. **Copy it, then build your map inside the copy.** It's a
|
||||
tiny working bundle — two trivial profiles that render a colored box, no Mapbox, no
|
||||
data — plus a `src/` sandbox laid out for the real code you'll add.
|
||||
Your starting point. **Copy this folder, then build your map inside the copy** — don't start from
|
||||
blank. It's a tiny working bundle (two trivial profiles that render a colored box, no Mapbox, no
|
||||
data) plus a `src/` sandbox laid out for your real code.
|
||||
|
||||
Don't build from a blank folder. Start here.
|
||||
## Two zones — know which one a file is in
|
||||
|
||||
---
|
||||
|
||||
## The two zones
|
||||
|
||||
Know which zone a file is in before you touch it.
|
||||
|
||||
| Zone | What it is | Can you edit it? |
|
||||
| Zone | What | Edit it? |
|
||||
|---|---|---|
|
||||
| **`library/`** (imported as `@map/…`) | The shared, reusable, parameterized building blocks — map, legends, toolbars, composables, the color + API registries. | **No — reuse only.** Editing it breaks other maps. |
|
||||
| **`app-profiles/<your-map>/src/`** | Your **safe sandbox**. Your screens, colors, API wiring, components, utils. | **Yes — build anything.** Nothing here leaks to any other map. |
|
||||
| **`library/`** (imported as `@map/…`) | shared, reusable building blocks — map, legends, toolbars, composables, color + API registries | **No — reuse only.** A change here can break every other map. |
|
||||
| **`app-profiles/<your-map>/src/`** | your private sandbox — screens, colors, API wiring, components, utils | **Yes — build anything.** Nothing here leaks to another map. |
|
||||
|
||||
To see everything `library/` gives you, read **`docs/reference.md`** at the bundler
|
||||
root. That's the menu you pick from.
|
||||
Rule of thumb: **local by default.** Code only moves into `library/` once a *second* map genuinely
|
||||
needs it — an expert move, not a first move. To see everything `library/` offers, read
|
||||
`../../docs/reference.md` (that's the menu you pick from).
|
||||
|
||||
## The three rules
|
||||
## Build a new map — the steps
|
||||
|
||||
1. **Reference the template.** Start every new map by copying this folder.
|
||||
2. **Build everything for your map inside your app-profile.** Colors, APIs,
|
||||
components, utils, data — all of it goes in `app-profiles/<your-map>/`.
|
||||
3. **Don't edit `library/`** (nor `internal/`) unless you're an expert and know
|
||||
exactly why. `library/` is shared; a change there can break every other map.
|
||||
|
||||
Rule of thumb: **local by default.** Code only moves into `library/` once a
|
||||
*second* map genuinely needs it — and that's an expert move, not a first move.
|
||||
|
||||
---
|
||||
|
||||
## To build a new map — the steps
|
||||
|
||||
1. **Copy this folder.** `app-profiles/template-bundle/` → `app-profiles/<your-map>/`.
|
||||
The folder name becomes your bundle name (and its output file, `<your-map>.js`).
|
||||
2. **List your requirements.** Write down what your map needs: which data, which
|
||||
colors, which controls (legend, search, share, fullscreen…).
|
||||
3. **Pick pieces from `docs/reference.md`.** Match your list to the reusable
|
||||
`@map/…` components, composables, and utils. Import them **by reference** — never
|
||||
1. **Copy this folder** → `app-profiles/<your-map>/`. The folder name becomes your bundle name (and
|
||||
output file `<your-map>.js`). Rename the custom-element tag in `index.js` to your map's tag.
|
||||
2. **List what your map needs** — data, colors, controls (legend, search, share, fullscreen…).
|
||||
3. **Pick pieces from `../../docs/reference.md`** and import them by reference (`@map/…`) — never
|
||||
copy library code into your folder.
|
||||
4. **Put your custom code in `src/`.** Anything that's yours and specific to this
|
||||
map — screens, components, hooks, helpers — goes in `src/` (see the map below).
|
||||
Rename the custom-element tag in `index.js` to your map's tag.
|
||||
5. **Edit your colors in `src/colors/colors.json`.** Change the hex values — no
|
||||
code. For color that varies by data value, use a strategy in `src/colors/`
|
||||
(start from `example-mode.js` there — a strategy is any `<mode>.js` in that folder).
|
||||
6. **Run the build.** `bun run build` (or `npm run build`) → your `<your-map>.js`
|
||||
appears. For just yours: `BUNDLE=<your-map> bun run build:bundle`.
|
||||
|
||||
---
|
||||
4. **Put your own code in `src/`** — screens, components, hooks, helpers.
|
||||
5. **Set colors in `src/colors/colors.json`** (plain hex, no code). For color that varies by data,
|
||||
use a strategy `.js` in `src/colors/` (copy `example-mode.js`).
|
||||
6. **Build** — `bun run build` (or just this one: `BUNDLE=<your-map> bun run build:bundle`).
|
||||
|
||||
## What's in this folder
|
||||
|
||||
```
|
||||
app-profiles/template-bundle/
|
||||
├── index.js ← bundle entry: registers <template-bundle>, globs ./*.vue
|
||||
├── index.html ← dev staging page (required for the build to find the bundle)
|
||||
├── template-map-a.vue ← profile "template-map-a" ← FLAT, at the bundle root
|
||||
├── template-map-b.vue ← profile "template-map-b" ← FLAT, at the bundle root
|
||||
└── src/ ← YOUR SANDBOX — build your map's own code here
|
||||
├── api/ which data source this map reads
|
||||
├── colors/ ALL your colors: colors.json (plain values) + strategy .js
|
||||
│ files (data-driven — example-mode.js to copy)
|
||||
├── components/ your map's own .vue pieces
|
||||
├── composables/ your map's own logic hooks
|
||||
└── utils/ your map's own helper functions
|
||||
```
|
||||
|
||||
**The map-maker's rule:** the bundle **root** holds ONLY the application
|
||||
profile(s) (`.vue`) plus the scanner-contract files (`index.js`, `index.html`,
|
||||
`*.instances.json`, `README.md`). Everything else lives in `src/`.
|
||||
|
||||
Each `src/` subfolder has its own README explaining what belongs there. It builds
|
||||
into **one** file: `public/doxa-maps/template-bundle/template-bundle.js`.
|
||||
|
||||
---
|
||||
|
||||
## The flat design (profiles at the bundle root)
|
||||
|
||||
The `.vue` profile files sit **directly in the bundle folder**, side by side with
|
||||
`index.js`. There is **no nested `profiles/` subfolder** — because the entry
|
||||
discovers profiles with a **flat glob**:
|
||||
|
||||
```js
|
||||
// index.js
|
||||
const profileModules = import.meta.glob('./*.vue') // ← './*.vue', not './profiles/*.vue'
|
||||
```
|
||||
|
||||
```
|
||||
template-bundle/
|
||||
index.js
|
||||
template-map-a.vue ✅ flat — discovered
|
||||
template-map-b.vue ✅ flat — discovered
|
||||
profiles/
|
||||
template-map-c.vue ❌ would NOT be discovered
|
||||
├── index.js ← bundle entry: registers <template-bundle>, globs ./*.vue
|
||||
├── index.html ← dev staging page (the build needs it to find the bundle)
|
||||
├── template-map-a.vue ← profile "template-map-a" ← FLAT at the bundle root
|
||||
├── template-map-b.vue ← profile "template-map-b" ← FLAT at the bundle root
|
||||
└── src/ ← YOUR SANDBOX (each subfolder has its own README)
|
||||
├── api/ colors/ components/ composables/ utils/
|
||||
```
|
||||
|
||||
Keep your **profile screens flat** at the root. The *pieces those screens are built
|
||||
from* (small components, hooks, helpers) live in `src/`.
|
||||
**The flat rule:** profile `.vue` files sit **directly in the bundle folder** — there is no
|
||||
`profiles/` subfolder, because the entry discovers them with a flat glob
|
||||
(`import.meta.glob('./*.vue')`). A `.vue` inside a `profiles/` subfolder would NOT be found. Keep
|
||||
your profile screens flat; the small pieces they're built from live in `src/`.
|
||||
|
||||
## How the pieces map together
|
||||
|
||||
| Thing | Value here | Rule |
|
||||
|---|---|---|
|
||||
| Folder name | `template-bundle` | = the bundle name |
|
||||
| Output file | `public/doxa-maps/template-bundle/template-bundle.js` | `<folder>.js` |
|
||||
| Custom element tag | `<template-bundle>` | registered in `index.js` |
|
||||
| Profile files | `template-map-a.vue`, `template-map-b.vue` | each `*.vue` = one profile |
|
||||
| Profile name | `template-map-a` / `template-map-b` | the filename without `.vue` |
|
||||
|
||||
One bundle, two profiles. The page picks which profile to render with the
|
||||
`profile` field of `profile-config` — both share the single `template-bundle.js`.
|
||||
Everything builds into **one** file: `public/doxa-maps/template-bundle/template-bundle.js`.
|
||||
|
||||
## The two ways you import
|
||||
|
||||
- **Reuse from the library** → the **`@map/…` alias** (points at `library/`):
|
||||
`import { useMapInstance } from '@map/composables/useMapInstance.js'`
|
||||
- **Use your own sandbox code** → a **relative `./src/...` path**:
|
||||
`import colors from './src/colors/colors.json'`
|
||||
- **Reuse from the library** → the `@map/…` alias: `import { useMapInstance } from '@map/composables/useMapInstance.js'`
|
||||
- **Your own sandbox code** → a relative path: `import colors from './src/colors/colors.json'`
|
||||
|
||||
There is no `@map/`-style alias for your sandbox — your own code is always a
|
||||
relative path. That boundary is what keeps your sandbox private to your map.
|
||||
|
||||
---
|
||||
There's no alias for your sandbox — your code is always relative. That boundary keeps it private.
|
||||
|
||||
## Embed it
|
||||
|
||||
```html
|
||||
<script src="/doxa-maps/template-bundle/template-bundle.js"></script>
|
||||
|
||||
<!-- profile A -->
|
||||
<template-bundle profile-config='{"profile":"template-map-a"}'></template-bundle>
|
||||
|
||||
<!-- profile B — same bundle, different profile -->
|
||||
<template-bundle profile-config='{"profile":"template-map-b"}'></template-bundle>
|
||||
```
|
||||
|
||||
(`profile` must match a `.vue` filename in this folder, without the `.vue`.)
|
||||
|
||||
## Build / preview
|
||||
|
||||
```bash
|
||||
# build just this bundle → public/doxa-maps/template-bundle/template-bundle.js
|
||||
BUNDLE=template-bundle npm run build:bundle
|
||||
|
||||
# or build every bundle
|
||||
npm run build
|
||||
|
||||
# preview in isolation (HMR) — open the staging page for this bundle
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Add a third profile
|
||||
|
||||
Drop another flat `.vue` next to the others — no config to edit:
|
||||
|
||||
```bash
|
||||
# app-profiles/template-bundle/template-map-c.vue
|
||||
npm run build # → still one file, template-bundle.js, now with 3 profiles
|
||||
```
|
||||
|
||||
Then request it: `<template-bundle profile-config='{"profile":"template-map-c"}'></template-bundle>`.
|
||||
(`profile` must match a `.vue` filename in this folder, without `.vue`. Add a third profile by
|
||||
dropping another flat `.vue` next to these and rebuilding — no config to edit.)
|
||||
|
||||
## See also
|
||||
|
||||
- `src/README.md` — the sandbox layout and the two import styles.
|
||||
- `../../docs/tutorial.md` — the 3 zones + 3 rules, in one page.
|
||||
- `../../docs/reference.md` — the menu of reusable `@map/…` pieces.
|
||||
- `../README.md` — the app-profiles authoring guide (bundle pattern, embed template).
|
||||
- `../../CONTRIBUTING.md` — build vs dev, the two CDN modes, partner-site embedding.
|
||||
- `../doxa-simple-map/index.js` — a fuller, real-map reference bundle entry.
|
||||
- `src/README.md` — sandbox layout · `../README.md` — the app-profiles authoring guide
|
||||
- `../../docs/tutorial.md` — 3 zones + 3 rules in one page · `../../docs/reference.md` — the `@map/…` menu
|
||||
- `../doxa-simple-map/index.js` — a fuller, real-map reference entry
|
||||
|
|
|
|||
Loading…
Reference in a new issue