4.5 KiB
Architecture — the shared component tree
The simple overviews are in
library/components/README.mdand 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 directuseXxxStore()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
sizeprop ('sm' | 'md' | 'lg') and follows theMapControlButtonshape. - Click handlers go through
inject('mapStore')orgetMap()— never a captured Mapbox instance. - The geocoder z-index sits above the legend and below popups.
- To add a button: copy
ZoomInButton.vueand register it inMapToolbar.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:
PosterDialogreads open/close state frominject('uiStore').- The preview is fed by
useMapPoster()(library/composables/poster/useMapPoster.js). - Page sizes come from
library/constants/posterSizes.js; defaults (font, padding, theme) fromlibrary/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.