doxa-maps/documentation/architecture/components.md
Doxa Maps e19697673d
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Doxa Maps — the map bundler, 7 production plugins and the Experimental shelf
2026-09-25 20:07:59 +00:00

98 lines
4.5 KiB
Markdown

# Architecture — the shared component tree
> The simple overviews are in `library/components/README.md` and its subfolder READMEs. This is
> the full catalog and the wiring conventions every shared component follows.
`library/components/` holds the **shared, parameterized Vue components** every app-profile reuses.
Fix one here and every map benefits — never edit a shared component to customize one map.
## Catalog
| File / folder | Role |
|---|---|
| `legends/` | Legend UI — `LegendDesktop.vue`, `LegendMobile.vue`, `LegendRows.vue`, `LegendTools.vue`, `SemanticTreeLegend.vue` |
| `map-controls/` | Per-button toolbar controls (see below) |
| `poster/` | Poster export UI — dialog, preview, wall, slots (see below) |
| `charts/` | Chart components |
| `tables/` | Table components |
| `PeopleGroupDetail.vue` | Feature record card (right-side panel content); renders the live prayer-count bar |
| `ResearchMapFilterPanel.vue` | Research-map filter panel |
| `ResearchMapSideMenu.vue` | Research-map side menu |
| `SideMenuDrawer.vue` | Generic slide-in side-panel primitive |
Per-file roles and gotchas for the whole catalog are in `documentation/reference.md`.
## Conventions (every shared component)
- Every component uses `<script setup>` (Vue 3.5+).
- Every component that renders CSS calls `useShadowStyles()` so styles attach to the shadow root.
- Stores are reached via `inject('mapStore' | 'uiStore' | 'dataStore')` — never a direct
`useXxxStore()` import (LL-010, LL-023).
- The Mapbox token is reached via `inject('mapboxToken')`.
To add a component: follow the conventions above and add a matching entry to the catalog.
## map-controls/
Per-button toolbar controls. Each file is a single, focused button or input that mounts inside the
map's control area. Replaces the older monolithic `MapControlsComponent.vue`.
| File | Role |
|---|---|
| `MapToolbar.vue` | Container that lays out the buttons |
| `MapControlButton.vue` | Base button primitive (icon + tooltip + accessibility) |
| `ZoomInButton.vue` | `+` — `map.zoomIn()` |
| `ZoomOutButton.vue` | `-` — `map.zoomOut()` |
| `LocationButton.vue` | Geolocation — fly to user's position |
| `FullscreenButton.vue` | Toggle fullscreen on the map container |
| `HamburgerButton.vue` | Open/close side menu |
| `ThemeToggleButton.vue` | Light/dark theme toggle (delegates to `uiStore.theme`) |
| `HelpButton.vue` | Opens help |
| `ShareButton.vue` | Share the current view |
| `GeocoderComponent.vue` | Mapbox Geocoder wrapper — Carmen-format aware, shadow-DOM-safe (LL-004, LL-015) |
Conventions:
- Every button takes a `size` prop (`'sm' | 'md' | 'lg'`) and follows the `MapControlButton` shape.
- Click handlers go through `inject('mapStore')` or `getMap()` — never a captured Mapbox instance.
- The geocoder z-index sits above the legend and below popups.
- To add a button: copy `ZoomInButton.vue` and register it in `MapToolbar.vue`.
## poster/
Poster export UI — the dialog and preview surfaces that drive the poster composables. Used by
`research-map.vue` for printable posters.
| File / folder | Role |
|---|---|
| `PosterDialog.vue` | Modal to pick page size, orientation, and title; triggers the export |
| `PosterPreview.vue` | Live preview of the assembled poster; updates as settings change |
| `PosterWall.vue` | Grid of poster previews |
| `slots/` | Composable poster slots (see below) |
Wiring:
- `PosterDialog` reads open/close state from `inject('uiStore')`.
- The preview is fed by `useMapPoster()` (`library/composables/poster/useMapPoster.js`).
- Page sizes come from `library/constants/posterSizes.js`; defaults (font, padding, theme) from
`library/constants/posterDefaults.js`.
- To add a page size, edit `constants/posterSizes.js`.
## poster/slots/
Each slot is a small Vue component that fills one named region of the assembled poster.
| File | Slot region |
|---|---|
| `TitleSlot.vue` | Top title block (text + optional subtitle) |
| `FooterSlot.vue` | Bottom footer region |
| `LegendSlot.vue` | Legend region |
| `NorthArrowSlot.vue` | North arrow |
| `ScaleBarSlot.vue` | Scale bar |
Conventions:
- Each slot is self-contained: it receives data via props and reads no stores.
- Slot dimensions come from the layout returned by `usePosterLayout()`
(`library/composables/poster/usePosterLayout.js`).
- Styling stays inside the component; print CSS lives at the poster-document level (iframe), not in
the slot.
- To add a slot: create the component here, register it in the layout config
(`constants/posterDefaults.js`), and add it to the table above.