doxa-maps/library/components/map-controls/MapToolbar.vue
Doxa Maps 31f98c51ec
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Update from source 1d569edd
2026-09-26 17:45:31 +00:00

73 lines
No EOL
3 KiB
Vue

<!--
MapToolbar.vue — Positioned layout shell for map control buttons.
ONLY responsible for the visual column layout
(position: absolute, flex-direction: column, gap, z-index).
Contains NO button logic and NO map reference. Exposes a default slot so
the application profile can place any combination of button components
inside — each bound explicitly to their own map instance.
Multi-map usage pattern (two separate maps in one profile):
MapToolbar > ZoomInButton :map="mapA" ...
MapToolbar > ZoomInButton :map="mapB" ...
Props:
has-geocoder (Boolean, default true) — whether a geocoder/search pill is
rendered above the toolbar on mobile. When false, the mobile top offset
collapses to the same 10px used on desktop (no wasted space above the
first control button). Default preserves the legacy mobile layout for
profiles that DO mount a geocoder.
-->
<script setup>
import { ref, provide } from 'vue'
import { useShadowStyles } from '../../composables/useShadowStyles.js'
defineProps({
hasGeocoder: { type: Boolean, default: true },
})
// The toolbar's element is provided to its controls: MapControlMenu measures it to place
// every menu at the toolbar's top, on its inner side, no taller than the control column.
const toolbarEl = ref(null)
provide('mapToolbar', { el: toolbarEl })
useShadowStyles(`
.map-toolbar {
position: absolute;
top: 6px;
/* Sit the control column near the edge with a small symmetric padding (3px) —
same value works whether the toolbar is swapped to the left or right side, and
it lines up with the search bar's 3px side inset. coder 2026-06-24. */
inset-inline-end: 3px; /* mirrors to the left on right-to-left pages */
display: flex;
flex-direction: column;
gap: var(--map-toolbar-gap, 8px);
z-index: 10;
}
/* Slim every toolbar control to a fixed 32px (coder 2026-06-24: "buttons can be
smaller"): smaller but still tappable, and uniform so they all align. The icons
inside stay their own fixed px sizes (they don't scale with the button), so they
remain legible — "icons fixed in their sizing". Caps the responsive
--map-btn-size (40/36/32). FullscreenButton.vue is not edited; it slims here too. */
.map-toolbar .mcb,
.map-toolbar .hbg-btn { width: 32px; height: 32px; }
.map-toolbar .hbg-ctrl { margin: 10px 0 0 0; } /* drop the 6px left offset so it lines up with the rest */
@media (max-width: 767px) {
/* Mobile (with geocoder): drop the toolbar well below the search bar so
it doesn't sit flush against the search pill. Search = top:10,
height ~36, bottom:46. top:72 leaves a comfortable ~26px gap. */
.map-toolbar { top: 72px; gap: 6px; }
/* Mobile (no geocoder): collapse the reserved gap — controls sit flush
to the top of the map area with the same 6px inset used on desktop. */
.map-toolbar.map-toolbar--no-geocoder { top: 6px; gap: 6px; }
}
`, 'map-toolbar')
</script>
<template>
<div ref="toolbarEl" class="map-toolbar" :class="{ 'map-toolbar--no-geocoder': !hasGeocoder }">
<slot />
</div>
</template>