From 877cb1a55cd9036d0ac48f67890607201395198c Mon Sep 17 00:00:00 2001 From: Jason Staack Date: Thu, 19 Mar 2026 20:56:43 -0500 Subject: [PATCH] feat(map): auto-switch map theme with app light/dark toggle Map theme now follows the app's dark/light mode setting automatically. Added light sprite assets. Device layers persist across theme switches. Co-Authored-By: Claude Opus 4.6 (1M context) --- frontend/public/map-assets/sprites/light.json | 1 + frontend/public/map-assets/sprites/light.png | Bin 0 -> 16174 bytes .../public/map-assets/sprites/light@2x.json | 1 + .../public/map-assets/sprites/light@2x.png | Bin 0 -> 28852 bytes frontend/src/components/map/FleetMap.tsx | 63 ++++++++++++++++-- 5 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 frontend/public/map-assets/sprites/light.json create mode 100644 frontend/public/map-assets/sprites/light.png create mode 100644 frontend/public/map-assets/sprites/light@2x.json create mode 100644 frontend/public/map-assets/sprites/light@2x.png diff --git a/frontend/public/map-assets/sprites/light.json b/frontend/public/map-assets/sprites/light.json new file mode 100644 index 0000000..a8514fd --- /dev/null +++ b/frontend/public/map-assets/sprites/light.json @@ -0,0 +1 @@ +{"NL:S-road-1char":{"height":21,"pixelRatio":1,"width":21,"x":0,"y":36},"NL:S-road-2char":{"height":21,"pixelRatio":1,"width":22,"x":38,"y":21},"NL:S-road-3char":{"height":21,"pixelRatio":1,"width":25,"x":202,"y":18},"NL:S-road-4char":{"height":21,"pixelRatio":1,"width":29,"x":173,"y":0},"NL:S-road-5char":{"height":21,"pixelRatio":1,"width":32,"x":79,"y":0},"US:I-1char":{"height":21,"pixelRatio":1,"width":20,"x":84,"y":21},"US:I-2char":{"height":21,"pixelRatio":1,"width":23,"x":227,"y":18},"US:I-3char":{"height":21,"pixelRatio":1,"width":30,"x":143,"y":0},"US:I-4char":{"height":21,"pixelRatio":1,"width":32,"x":111,"y":0},"US:I-5char":{"height":21,"pixelRatio":1,"width":34,"x":45,"y":0},"aerodrome":{"height":19,"pixelRatio":1,"width":19,"x":60,"y":39},"animal":{"height":19,"pixelRatio":1,"width":19,"x":21,"y":42},"arrow":{"height":19,"pixelRatio":1,"width":19,"x":0,"y":57},"artwork":{"height":19,"pixelRatio":1,"width":19,"x":40,"y":42},"attraction":{"height":19,"pixelRatio":1,"width":19,"x":104,"y":21},"bar":{"height":19,"pixelRatio":1,"width":19,"x":123,"y":21},"beach":{"height":19,"pixelRatio":1,"width":19,"x":142,"y":21},"beauty":{"height":19,"pixelRatio":1,"width":19,"x":161,"y":21},"bench":{"height":19,"pixelRatio":1,"width":19,"x":180,"y":21},"books":{"height":19,"pixelRatio":1,"width":19,"x":199,"y":39},"building":{"height":17,"pixelRatio":1,"width":17,"x":193,"y":77},"bus_stop":{"height":19,"pixelRatio":1,"width":19,"x":218,"y":39},"cafe":{"height":19,"pixelRatio":1,"width":19,"x":237,"y":39},"capital":{"height":10,"pixelRatio":1,"width":10,"x":210,"y":77},"clothes":{"height":19,"pixelRatio":1,"width":19,"x":104,"y":40},"convenience":{"height":19,"pixelRatio":1,"width":19,"x":79,"y":42},"drinking_water":{"height":19,"pixelRatio":1,"width":19,"x":59,"y":58},"electronics":{"height":19,"pixelRatio":1,"width":19,"x":19,"y":61},"fast_food":{"height":19,"pixelRatio":1,"width":19,"x":0,"y":76},"ferry_terminal":{"height":19,"pixelRatio":1,"width":19,"x":38,"y":61},"forest":{"height":19,"pixelRatio":1,"width":19,"x":123,"y":40},"garden":{"height":19,"pixelRatio":1,"width":19,"x":142,"y":40},"generic_shield-1char":{"height":18,"pixelRatio":1,"width":19,"x":235,"y":0},"generic_shield-2char":{"height":18,"pixelRatio":1,"width":24,"x":60,"y":21},"generic_shield-3char":{"height":18,"pixelRatio":1,"width":33,"x":202,"y":0},"generic_shield-4char":{"height":18,"pixelRatio":1,"width":38,"x":0,"y":18},"generic_shield-5char":{"height":18,"pixelRatio":1,"width":45,"x":0,"y":0},"library":{"height":19,"pixelRatio":1,"width":19,"x":161,"y":40},"marina":{"height":19,"pixelRatio":1,"width":19,"x":180,"y":40},"museum":{"height":19,"pixelRatio":1,"width":19,"x":199,"y":58},"park":{"height":19,"pixelRatio":1,"width":19,"x":218,"y":58},"peak":{"height":19,"pixelRatio":1,"width":19,"x":237,"y":58},"post_office":{"height":19,"pixelRatio":1,"width":19,"x":98,"y":59},"restaurant":{"height":19,"pixelRatio":1,"width":19,"x":78,"y":61},"school":{"height":19,"pixelRatio":1,"width":19,"x":57,"y":77},"stadium":{"height":19,"pixelRatio":1,"width":19,"x":19,"y":80},"supermarket":{"height":19,"pixelRatio":1,"width":19,"x":0,"y":95},"theatre":{"height":19,"pixelRatio":1,"width":19,"x":38,"y":80},"toilets":{"height":19,"pixelRatio":1,"width":19,"x":117,"y":59},"townspot":{"height":10,"pixelRatio":1,"width":10,"x":220,"y":77},"train_station":{"height":19,"pixelRatio":1,"width":19,"x":136,"y":59},"university":{"height":19,"pixelRatio":1,"width":19,"x":155,"y":59},"zoo":{"height":19,"pixelRatio":1,"width":19,"x":174,"y":59}} \ No newline at end of file diff --git a/frontend/public/map-assets/sprites/light.png b/frontend/public/map-assets/sprites/light.png new file mode 100644 index 0000000000000000000000000000000000000000..b2b90d9c21bd312e037bf0e74fb43ae6f622d1b3 GIT binary patch literal 16174 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 literal 0 HcmV?d00001 diff --git a/frontend/public/map-assets/sprites/light@2x.json b/frontend/public/map-assets/sprites/light@2x.json new file mode 100644 index 0000000..4e98508 --- /dev/null +++ b/frontend/public/map-assets/sprites/light@2x.json @@ -0,0 +1 @@ +{"NL:S-road-1char":{"height":42,"pixelRatio":2,"width":42,"x":0,"y":72},"NL:S-road-2char":{"height":42,"pixelRatio":2,"width":44,"x":76,"y":42},"NL:S-road-3char":{"height":42,"pixelRatio":2,"width":50,"x":404,"y":36},"NL:S-road-4char":{"height":42,"pixelRatio":2,"width":58,"x":346,"y":0},"NL:S-road-5char":{"height":42,"pixelRatio":2,"width":64,"x":158,"y":0},"US:I-1char":{"height":42,"pixelRatio":2,"width":40,"x":168,"y":42},"US:I-2char":{"height":42,"pixelRatio":2,"width":46,"x":454,"y":36},"US:I-3char":{"height":42,"pixelRatio":2,"width":60,"x":286,"y":0},"US:I-4char":{"height":42,"pixelRatio":2,"width":64,"x":222,"y":0},"US:I-5char":{"height":42,"pixelRatio":2,"width":68,"x":90,"y":0},"aerodrome":{"height":38,"pixelRatio":2,"width":38,"x":120,"y":78},"animal":{"height":38,"pixelRatio":2,"width":38,"x":42,"y":84},"arrow":{"height":38,"pixelRatio":2,"width":38,"x":0,"y":114},"artwork":{"height":38,"pixelRatio":2,"width":38,"x":80,"y":84},"attraction":{"height":38,"pixelRatio":2,"width":38,"x":208,"y":42},"bar":{"height":38,"pixelRatio":2,"width":38,"x":246,"y":42},"beach":{"height":38,"pixelRatio":2,"width":38,"x":284,"y":42},"beauty":{"height":38,"pixelRatio":2,"width":38,"x":322,"y":42},"bench":{"height":38,"pixelRatio":2,"width":38,"x":360,"y":42},"books":{"height":38,"pixelRatio":2,"width":38,"x":398,"y":78},"building":{"height":34,"pixelRatio":2,"width":34,"x":386,"y":154},"bus_stop":{"height":38,"pixelRatio":2,"width":38,"x":436,"y":78},"cafe":{"height":38,"pixelRatio":2,"width":38,"x":474,"y":78},"capital":{"height":20,"pixelRatio":2,"width":20,"x":420,"y":154},"clothes":{"height":38,"pixelRatio":2,"width":38,"x":208,"y":80},"convenience":{"height":38,"pixelRatio":2,"width":38,"x":158,"y":84},"drinking_water":{"height":38,"pixelRatio":2,"width":38,"x":118,"y":116},"electronics":{"height":38,"pixelRatio":2,"width":38,"x":38,"y":122},"fast_food":{"height":38,"pixelRatio":2,"width":38,"x":0,"y":152},"ferry_terminal":{"height":38,"pixelRatio":2,"width":38,"x":76,"y":122},"forest":{"height":38,"pixelRatio":2,"width":38,"x":246,"y":80},"garden":{"height":38,"pixelRatio":2,"width":38,"x":284,"y":80},"generic_shield-1char":{"height":36,"pixelRatio":2,"width":38,"x":470,"y":0},"generic_shield-2char":{"height":36,"pixelRatio":2,"width":48,"x":120,"y":42},"generic_shield-3char":{"height":36,"pixelRatio":2,"width":66,"x":404,"y":0},"generic_shield-4char":{"height":36,"pixelRatio":2,"width":76,"x":0,"y":36},"generic_shield-5char":{"height":36,"pixelRatio":2,"width":90,"x":0,"y":0},"library":{"height":38,"pixelRatio":2,"width":38,"x":322,"y":80},"marina":{"height":38,"pixelRatio":2,"width":38,"x":360,"y":80},"museum":{"height":38,"pixelRatio":2,"width":38,"x":398,"y":116},"park":{"height":38,"pixelRatio":2,"width":38,"x":436,"y":116},"peak":{"height":38,"pixelRatio":2,"width":38,"x":474,"y":116},"post_office":{"height":38,"pixelRatio":2,"width":38,"x":196,"y":118},"restaurant":{"height":38,"pixelRatio":2,"width":38,"x":156,"y":122},"school":{"height":38,"pixelRatio":2,"width":38,"x":114,"y":154},"stadium":{"height":38,"pixelRatio":2,"width":38,"x":38,"y":160},"supermarket":{"height":38,"pixelRatio":2,"width":38,"x":0,"y":190},"theatre":{"height":38,"pixelRatio":2,"width":38,"x":76,"y":160},"toilets":{"height":38,"pixelRatio":2,"width":38,"x":234,"y":118},"townspot":{"height":20,"pixelRatio":2,"width":20,"x":440,"y":154},"train_station":{"height":38,"pixelRatio":2,"width":38,"x":272,"y":118},"university":{"height":38,"pixelRatio":2,"width":38,"x":310,"y":118},"zoo":{"height":38,"pixelRatio":2,"width":38,"x":348,"y":118}} \ No newline at end of file diff --git a/frontend/public/map-assets/sprites/light@2x.png b/frontend/public/map-assets/sprites/light@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6765ac7c2b832c6d5b38f47b8f6ddf72e64d573 GIT binary patch literal 28852 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 literal 0 HcmV?d00001 diff --git a/frontend/src/components/map/FleetMap.tsx b/frontend/src/components/map/FleetMap.tsx index adecf6d..43535a6 100644 --- a/frontend/src/components/map/FleetMap.tsx +++ b/frontend/src/components/map/FleetMap.tsx @@ -4,6 +4,7 @@ import { Protocol } from 'pmtiles' import { layers, namedFlavor } from '@protomaps/basemaps' import type { FleetDevice } from '@/lib/api' import { formatUptime } from '@/lib/utils' +import { useUIStore } from '@/lib/store' import 'maplibre-gl/dist/maplibre-gl.css' @@ -25,11 +26,11 @@ const STATUS_COLORS: Record = { unknown: '#eab308', } -function buildMapStyle() { +function buildMapStyle(theme: 'dark' | 'light') { return { version: 8 as const, glyphs: '/map-fonts/{fontstack}/{range}.pbf', - sprite: '/map-assets/sprites/dark', + sprite: `/map-assets/sprites/${theme}`, sources: { protomaps: { type: 'vector' as const, @@ -37,7 +38,7 @@ function buildMapStyle() { attribution: '© OpenStreetMap', }, }, - layers: layers('protomaps', namedFlavor('dark'), { lang: 'en' }), + layers: layers('protomaps', namedFlavor(theme), { lang: 'en' }), } } @@ -73,6 +74,7 @@ function deviceToGeoJSON(devices: FleetDevice[]): GeoJSON.FeatureCollection { export function FleetMap({ devices, tenantId }: FleetMapProps) { const containerRef = useRef(null) const mapRef = useRef(null) + const theme = useUIStore((s) => s.theme) const geojson = useMemo(() => deviceToGeoJSON(devices), [devices]) @@ -82,7 +84,7 @@ export function FleetMap({ devices, tenantId }: FleetMapProps) { const map = new maplibregl.Map({ container: containerRef.current, - style: buildMapStyle(), + style: buildMapStyle(theme), center: DEFAULT_CENTER, zoom: DEFAULT_ZOOM, maxZoom: 17, @@ -228,6 +230,59 @@ export function FleetMap({ devices, tenantId }: FleetMapProps) { // eslint-disable-next-line react-hooks/exhaustive-deps }, []) + // Re-add device layers after style change (setStyle wipes all sources/layers) + const addDeviceLayers = (map: maplibregl.Map) => { + if (map.getSource('devices')) return + map.addSource('devices', { + type: 'geojson', + data: geojson, + cluster: true, + clusterMaxZoom: 14, + clusterRadius: 50, + }) + map.addLayer({ + id: 'clusters', + type: 'circle', + source: 'devices', + filter: ['has', 'point_count'], + paint: { + 'circle-color': ['step', ['get', 'point_count'], '#22c55e', 10, '#f59e0b', 50, '#ef4444'], + 'circle-radius': ['step', ['get', 'point_count'], 18, 10, 24, 50, 32], + 'circle-stroke-width': 2, + 'circle-stroke-color': '#ffffff', + }, + }) + map.addLayer({ + id: 'cluster-count', + type: 'symbol', + source: 'devices', + filter: ['has', 'point_count'], + layout: { 'text-field': '{point_count_abbreviated}', 'text-font': ['Noto Sans Medium'], 'text-size': 13 }, + paint: { 'text-color': '#ffffff' }, + }) + map.addLayer({ + id: 'device-points', + type: 'circle', + source: 'devices', + filter: ['!', ['has', 'point_count']], + paint: { + 'circle-color': ['get', 'color'], + 'circle-radius': 7, + 'circle-stroke-width': 2, + 'circle-stroke-color': '#ffffff', + }, + }) + } + + // Switch map theme when app theme changes + useEffect(() => { + const map = mapRef.current + if (!map) return + map.setStyle(buildMapStyle(theme)) + map.once('styledata', () => addDeviceLayers(map)) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [theme]) + // Update device data when it changes useEffect(() => { const map = mapRef.current