mirror of
https://github.com/tabler/tabler.git
synced 2026-10-12 05:06:55 +04:00
Style MapLibre controls and popups, follow the page theme
This commit is contained in:
1 parent
8a2998ba47
commit
5b2cddc30b
9 files changed
+237
-14
No files matched your search
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@tabler/core": minor
|
||||
"@tabler/preview": patch
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Added MapLibre GL styles to `tabler-vendors.css`: map controls, popups and attribution, in light and dark mode.
|
||||
+6
-6
@@ -196,19 +196,19 @@
|
||||
},
|
||||
{
|
||||
"path": "./dist/css/tabler-vendors.css",
|
||||
"maxSize": "4 kB"
|
||||
"maxSize": "4.5 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/css/tabler-vendors.min.css",
|
||||
"maxSize": "3.5 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/css/tabler-vendors.rtl.css",
|
||||
"maxSize": "4 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/css/tabler-vendors.rtl.css",
|
||||
"maxSize": "4.5 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/css/tabler-vendors.rtl.min.css",
|
||||
"maxSize": "3.5 kB"
|
||||
"maxSize": "4 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/tabler.js",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
@forward 'vendor/tom-select';
|
||||
@forward 'vendor/apexcharts';
|
||||
@forward 'vendor/jsvectormap';
|
||||
@forward 'vendor/maplibre';
|
||||
@forward 'vendor/dropzone';
|
||||
@forward 'vendor/fslightbox';
|
||||
@forward 'vendor/plyr';
|
||||
|
||||
@@ -90,6 +90,7 @@ exports[`css custom-property prefixing > leaves vendor-owned names alone and pre
|
||||
"--tblr-secondary",
|
||||
"--tblr-secondary-bg",
|
||||
"--tblr-shadow-card",
|
||||
"--tblr-shadow-color",
|
||||
"--tblr-shadow-dropdown",
|
||||
"--tblr-shadow-input",
|
||||
"--tblr-signal-color",
|
||||
|
||||
Vendored
+133
@@ -0,0 +1,133 @@
|
||||
@use '../config' as *;
|
||||
|
||||
.maplibregl-map {
|
||||
font-family: inherit;
|
||||
font-size: $h5-font-size;
|
||||
line-height: $line-height-base;
|
||||
}
|
||||
|
||||
// Controls: zoom, compass, fullscreen, locate
|
||||
.maplibregl-ctrl-group {
|
||||
overflow: hidden;
|
||||
background: var(--bg-surface);
|
||||
@include border-radius(var(--border-radius));
|
||||
|
||||
&:not(:empty) {
|
||||
box-shadow:
|
||||
0 0 0 var(--border-width) var(--border-color),
|
||||
#{$card-box-shadow};
|
||||
}
|
||||
|
||||
button {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
|
||||
+ button {
|
||||
border-top: var(--border-width) var(--border-style) var(--border-color);
|
||||
}
|
||||
|
||||
&:focus:focus-visible {
|
||||
outline-offset: calc(-1 * var(--focus-ring-width));
|
||||
box-shadow: none;
|
||||
@include focus-ring();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.maplibregl-ctrl button:not(:disabled):hover,
|
||||
.maplibregl-ctrl button:not(:disabled):active {
|
||||
background-color: var(--bg-surface-secondary);
|
||||
}
|
||||
|
||||
// Attribution
|
||||
.maplibregl-ctrl.maplibregl-ctrl-attrib {
|
||||
color: var(--secondary);
|
||||
background-color: color-transparent(var(--bg-surface), 0.7);
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.maplibregl-ctrl-attrib.maplibregl-compact {
|
||||
color: var(--secondary);
|
||||
background-color: var(--bg-surface);
|
||||
}
|
||||
|
||||
.maplibregl-ctrl-attrib-button:focus {
|
||||
box-shadow: none;
|
||||
@include focus-ring();
|
||||
}
|
||||
|
||||
.maplibregl-ctrl-scale {
|
||||
color: var(--body-color);
|
||||
background-color: color-transparent(var(--bg-surface), 0.75);
|
||||
border-color: var(--body-color);
|
||||
}
|
||||
|
||||
// Popup
|
||||
.maplibregl-popup-content {
|
||||
padding: 0.75rem 1rem;
|
||||
color: var(--body-color);
|
||||
background: var(--bg-surface);
|
||||
box-shadow:
|
||||
0 0 0 var(--border-width) var(--border-color),
|
||||
#{$box-shadow-md};
|
||||
@include border-radius(var(--border-radius));
|
||||
}
|
||||
|
||||
// Room for the close button, which MapLibre pins to the right edge in both directions
|
||||
.maplibregl-popup-content:has(.maplibregl-popup-close-button) {
|
||||
/* rtl:ignore */
|
||||
padding-right: 2.25rem;
|
||||
}
|
||||
|
||||
.maplibregl-popup-close-button {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
padding: 0;
|
||||
margin: 0.375rem;
|
||||
font-size: 1rem;
|
||||
line-height: 1;
|
||||
color: var(--secondary);
|
||||
@include border-radius(var(--border-radius));
|
||||
|
||||
&:hover {
|
||||
color: var(--body-color);
|
||||
background-color: var(--bg-surface-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.maplibregl-popup-anchor-top,
|
||||
.maplibregl-popup-anchor-top-left,
|
||||
.maplibregl-popup-anchor-top-right {
|
||||
.maplibregl-popup-tip {
|
||||
border-bottom-color: var(--bg-surface);
|
||||
}
|
||||
}
|
||||
|
||||
.maplibregl-popup-anchor-bottom,
|
||||
.maplibregl-popup-anchor-bottom-left,
|
||||
.maplibregl-popup-anchor-bottom-right {
|
||||
.maplibregl-popup-tip {
|
||||
border-top-color: var(--bg-surface);
|
||||
}
|
||||
}
|
||||
|
||||
.maplibregl-popup-anchor-left .maplibregl-popup-tip {
|
||||
border-right-color: var(--bg-surface);
|
||||
}
|
||||
|
||||
.maplibregl-popup-anchor-right .maplibregl-popup-tip {
|
||||
border-left-color: var(--bg-surface);
|
||||
}
|
||||
|
||||
// The control icons are black SVG images
|
||||
@if $enable-dark-mode {
|
||||
@include color-mode(dark) {
|
||||
.maplibregl-ctrl-icon,
|
||||
.maplibregl-ctrl-attrib-button {
|
||||
@include autodark-image();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,13 @@ Or include it from a CDN. You need two files: the stylesheet and the library.
|
||||
<script src="${site.cdnUrl}/dist/libs/maplibre-gl/dist/maplibre-gl.js"></script>`}
|
||||
/>
|
||||
|
||||
Tabler styles the map controls, popups and attribution to match the interface, in light and dark mode. These styles are in `tabler-vendors.css`, so load it after the MapLibre stylesheet:
|
||||
|
||||
<Code
|
||||
lang="html"
|
||||
code={`<link rel="stylesheet" href="${site.cdnUrl}/dist/css/tabler-vendors.min.css" />`}
|
||||
/>
|
||||
|
||||
## Usage
|
||||
|
||||
### Markup
|
||||
@@ -115,6 +122,53 @@ cities.forEach(function (coords) {
|
||||
|
||||
The `color` option is written to the `fill` attribute of the marker icon. A CSS variable works there, so `var(--tblr-primary)` keeps the markers in your theme color, including after a theme change.
|
||||
|
||||
### Popups
|
||||
|
||||
Attach a popup to a marker with `setPopup`. It opens when the marker is clicked. Click a marker on the map above to see one.
|
||||
|
||||
```js
|
||||
new maplibregl.Marker({ color: 'var(--tblr-primary)' })
|
||||
.setLngLat([16.366667, 48.2])
|
||||
.setPopup(new maplibregl.Popup({ offset: 32 }).setText('Vienna'))
|
||||
.addTo(map)
|
||||
```
|
||||
|
||||
Use `setHTML` instead of `setText` for richer content. Only pass HTML you trust, as it is not escaped.
|
||||
|
||||
### Controls
|
||||
|
||||
Add the zoom and compass buttons with `NavigationControl`. They go to the top right corner by default.
|
||||
|
||||
```js
|
||||
map.addControl(new maplibregl.NavigationControl())
|
||||
```
|
||||
|
||||
MapLibre also has `FullscreenControl`, `GeolocateControl` and `ScaleControl`. Pass a corner as the second argument, for example `'bottom-left'`.
|
||||
|
||||
### Dark mode
|
||||
|
||||
A map style does not change with the page theme on its own. Pick the style from the `data-bs-theme` attribute, and set it again when the attribute changes:
|
||||
|
||||
```js
|
||||
const themeStyle = function () {
|
||||
const dark = document.documentElement.getAttribute('data-bs-theme') === 'dark'
|
||||
return 'https://tiles.openfreemap.org/styles/' + (dark ? 'dark' : 'liberty')
|
||||
}
|
||||
|
||||
const map = new maplibregl.Map({
|
||||
container: 'map-simple',
|
||||
style: themeStyle(),
|
||||
zoom: 13,
|
||||
center: [13.4049, 52.518827],
|
||||
})
|
||||
|
||||
new MutationObserver(function () {
|
||||
map.setStyle(themeStyle())
|
||||
}).observe(document.documentElement, { attributeFilter: ['data-bs-theme'] })
|
||||
```
|
||||
|
||||
Markers and popups stay on the map when the style changes. The maps on this page follow the theme this way.
|
||||
|
||||
### Attribution
|
||||
|
||||
MapLibre adds the credit for the map data in the corner of the map. OpenFreeMap requires it, so do not hide it.
|
||||
|
||||
@@ -12,15 +12,20 @@ import CaptureScript from '@shared/components/CaptureScript.astro'
|
||||
window.tabler_map ??= {}
|
||||
|
||||
function initMap() {
|
||||
const themeStyle = () => `https://tiles.openfreemap.org/styles/${document.documentElement.getAttribute('data-bs-theme') === 'dark' ? 'dark' : 'liberty'}`
|
||||
|
||||
const map = new maplibregl.Map({
|
||||
container: 'map-fullsize',
|
||||
style: 'https://tiles.openfreemap.org/styles/liberty',
|
||||
style: themeStyle(),
|
||||
zoom: 12,
|
||||
center: [13.4049, 52.518827],
|
||||
})
|
||||
|
||||
map.addControl(new maplibregl.NavigationControl())
|
||||
|
||||
// Change the map style when the page theme changes
|
||||
new MutationObserver(() => map.setStyle(themeStyle())).observe(document.documentElement, { attributeFilter: ['data-bs-theme'] })
|
||||
|
||||
window.tabler_map['map-fullsize'] = map
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
// MapLibre GL map on OpenFreeMap tiles: no account and no access token.
|
||||
// The map follows the page theme: `style` in light mode, `darkStyle` in dark.
|
||||
// Renders nothing unless maps[mapId] exists.
|
||||
import maps from '@data/maps.json';
|
||||
import CaptureScript from '../CaptureScript.astro';
|
||||
@@ -18,6 +19,10 @@ type MapData = {
|
||||
card?: boolean;
|
||||
/** OpenFreeMap style name: liberty (default), bright, positron, dark or fiord */
|
||||
style?: string;
|
||||
/** style used in dark mode, `dark` by default */
|
||||
darkStyle?: string;
|
||||
/** adds the zoom and compass buttons */
|
||||
controls?: boolean;
|
||||
zoom?: number;
|
||||
center?: [number, number];
|
||||
markers?: { name?: string; center: [number, number] }[];
|
||||
@@ -26,10 +31,13 @@ type MapData = {
|
||||
const data = (maps as unknown as Record<string, MapData>)[mapId];
|
||||
|
||||
const mapContainerId = `map-${mapId}`;
|
||||
const style = `https://tiles.openfreemap.org/styles/${data?.style ?? 'liberty'}`;
|
||||
const styleUrl = (name: string) => `https://tiles.openfreemap.org/styles/${name}`;
|
||||
const style = styleUrl(data?.style ?? 'liberty');
|
||||
const darkStyle = styleUrl(data?.darkStyle ?? 'dark');
|
||||
const controls = data?.controls ?? false;
|
||||
const zoom = data?.zoom ?? 13;
|
||||
const center = data?.center ? [data.center[1], data.center[0]] : [13.4049, 52.518827];
|
||||
const markers = (data?.markers ?? []).map((marker) => [marker.center[1], marker.center[0]]);
|
||||
const markers = (data?.markers ?? []).map((marker) => ({ name: marker.name, coords: [marker.center[1], marker.center[0]] }));
|
||||
|
||||
const ratioClass = data?.ratio ?? ratio ?? '16x9';
|
||||
---
|
||||
@@ -47,21 +55,33 @@ const ratioClass = data?.ratio ?? ratio ?? '16x9';
|
||||
data && (
|
||||
<CaptureScript>
|
||||
<!-- BEGIN MAP -->
|
||||
<script is:inline define:vars={{ mapContainerId, style, zoom, center, markers }}>
|
||||
<script is:inline define:vars={{ mapContainerId, style, darkStyle, controls, zoom, center, markers }}>
|
||||
window.tabler_map ??= {};
|
||||
|
||||
function initMap() {
|
||||
const themeStyle = () => (document.documentElement.getAttribute('data-bs-theme') === 'dark' ? darkStyle : style);
|
||||
|
||||
const map = new maplibregl.Map({
|
||||
container: mapContainerId,
|
||||
style,
|
||||
style: themeStyle(),
|
||||
zoom,
|
||||
center,
|
||||
});
|
||||
|
||||
markers.forEach((coords) => {
|
||||
new maplibregl.Marker({ color: 'var(--tblr-primary)' }).setLngLat(coords).addTo(map);
|
||||
if (controls) {
|
||||
map.addControl(new maplibregl.NavigationControl());
|
||||
}
|
||||
|
||||
markers.forEach((marker) => {
|
||||
new maplibregl.Marker({ color: 'var(--tblr-primary)' })
|
||||
.setLngLat(marker.coords)
|
||||
.setPopup(new maplibregl.Popup({ offset: 32 }).setText(marker.name))
|
||||
.addTo(map);
|
||||
});
|
||||
|
||||
// Change the map style when the page theme changes
|
||||
new MutationObserver(() => map.setStyle(themeStyle())).observe(document.documentElement, { attributeFilter: ['data-bs-theme'] });
|
||||
|
||||
window.tabler_map[mapContainerId] = map;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"simple": {
|
||||
"title": "Simple map"
|
||||
"title": "Simple map",
|
||||
"controls": true
|
||||
},
|
||||
"light": {
|
||||
"title": "Light map style",
|
||||
@@ -73,6 +74,7 @@
|
||||
],
|
||||
"zoom": 1,
|
||||
"style": "bright",
|
||||
"darkStyle": "fiord",
|
||||
"card": true
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user