Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@
"types": "./dist/runtime/lib/util/index.d.ts",
"import": "./dist/runtime/lib/util/index.js"
},
"./lib/basemaps": {
"types": "./dist/runtime/composables/useBasemapLayers.d.ts",
"import": "./dist/runtime/composables/useBasemapLayers.js"
},
"./apps/admin": {
"types": "./dist/runtime/apps/admin/index.d.ts",
"import": "./dist/runtime/apps/admin/index.js"
Expand Down Expand Up @@ -124,6 +128,7 @@
"@maplibre/maplibre-gl-geocoder": "1.9.0",
"@mdi/font": "7.4.47",
"@observablehq/plot": "0.6.17",
"@protomaps/basemaps": "5.7.0",
"@turf/centroid": "7.3.0",
"@vue/apollo-composable": "4.2.2",
"@vue/apollo-option": "4.2.2",
Expand All @@ -145,7 +150,6 @@
"maplibre-gl": "5.2.0",
"mixpanel-browser": "2.61.2",
"nuxt-csurf": "1.6.5",
"protomaps-themes-base": "1.3.1",
"tiny-emitter": "2.1.0",
"unstorage": "1.15.0",
"vega": "6.2.0",
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/apps/stations/basemap-control.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ interface Props {
}

withDefaults(defineProps<Props>(), {
modelValue: 'carto'
modelValue: 'protomaps-grayscale'
})

defineEmits<{
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/apps/stations/level-editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ const _emit = defineEmits<{
}>()

const level = ref(new Level(props.value).setDefaults())
const basemap = ref('carto')
const basemap = ref('protomaps-grayscale')
const showGeojsonEditor = ref(false)
const geojsonError = ref<string | null>(null)
const geojsonGeometryBuffer = ref('')
Expand Down
47 changes: 39 additions & 8 deletions src/runtime/apps/stations/level-map.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
<script setup lang="ts">
import { ref, computed, watch, onMounted, nextTick } from 'vue'
import { Map as MaplibreMap, AttributionControl } from 'maplibre-gl'
import { useBasemapLayers } from '../../composables/useBasemapLayers'
import { useBasemapLayers, PROTOMAPS_GLYPHS_URL } from '../../composables/useBasemapLayers'
import { PeliasIcons } from './basemaps'
import MapboxDraw from '@mapbox/mapbox-gl-draw'
import { layers } from '@protomaps/basemaps'
import type { Feature, Point, LineString, Polygon, MultiPolygon } from 'geojson'

// https://github.com/maplibre/maplibre-gl-js/issues/2601
Expand Down Expand Up @@ -48,7 +49,7 @@ interface Props {
}

const props = withDefaults(defineProps<Props>(), {
basemap: 'carto',
basemap: 'protomaps-grayscale',
width: '100px',
height: '100px',
showAttribution: true,
Expand Down Expand Up @@ -99,10 +100,29 @@ function initMap () {
if (!mapelem.value) return

const sources: Record<string, any> = {}
const layers: any[] = []
const layerList: any[] = []

for (const [k, v] of Object.entries(basemapLayers.value)) {
sources[k] = v.source
layers.push({ id: k, source: k, ...v.layer })

// Handle vector basemaps (Protomaps) differently from raster
if ((v.layer as any).isVector && (v.layer as any).flavor) {
// Add all Protomaps layers for this flavor
const protomapsLayers = layers(k, (v.layer as any).flavor)
// Set visibility based on whether this is the active basemap
for (const layer of protomapsLayers) {
layer.layout = layer.layout || {}
layer.layout.visibility = k === props.basemap ? 'visible' : 'none'
}
layerList.push(...protomapsLayers)
} else {
// Raster layers (Carto, Nearmap)
const layer: any = { id: k, source: k, ...v.layer }
// Set initial visibility for raster layers
layer.layout = layer.layout || {}
layer.layout.visibility = k === props.basemap ? 'visible' : 'none'
layerList.push(layer)
}
}

map.value = new MaplibreMap({
Expand All @@ -113,9 +133,9 @@ function initMap () {
attributionControl: false,
style: {
version: 8,
glyphs: '/fonts/{fontstack}/{range}.pbf',
glyphs: PROTOMAPS_GLYPHS_URL,
sources,
layers
layers: layerList
}
})

Expand Down Expand Up @@ -252,8 +272,19 @@ function drawMap () {
// Watchers
watch(() => props.basemap, (cur, prev) => {
if (!map.value || !prev) return
map.value.setLayoutProperty(prev, 'visibility', 'none')
map.value.setLayoutProperty(cur, 'visibility', 'visible')

// Hide/show all layers for each basemap source
const style = map.value.getStyle()
if (style?.layers) {
for (const layer of style.layers) {
// Check if this layer belongs to the previous or current basemap
if (layer.source === prev) {
map.value.setLayoutProperty(layer.id, 'visibility', 'none')
} else if (layer.source === cur) {
map.value.setLayoutProperty(layer.id, 'visibility', 'visible')
}
}
}
})

watch(() => props.lines, () => {
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/apps/stations/pages/station-pathways.vue
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ const selectMode = ref<SelectMode>('select')
const selectedPoint = ref<LngLat | null>(null)
const selectedStops = ref<Stop[]>([])
const selectedPathways = ref<Pathway[]>([])
const basemap = ref('carto')
const basemap = ref('protomaps-grayscale')

// Computed properties
const selectedPath = computed((): PathwayEdge[] | null => {
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/apps/stations/pages/station-stops.vue
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ const nearbyStopsQuery = gql`

// Reactive data
const nearbyStops = ref<Stop[]>([])
const basemap = ref('carto')
const basemap = ref('protomaps-grayscale')
const selectedLocationTypes = ref(['0', '2']) // must be stringy
const selectedSources = ref(['nearby', 'station'])
const selectedAgenciesShadow = ref<string[] | null>(null)
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/apps/stations/pathway-map.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ interface Props {

const props = withDefaults(defineProps<Props>(), {
station: null,
basemap: 'carto',
basemap: 'protomaps-grayscale',
zoom: 17,
center: () => [0, 0],
otherStops: () => [],
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/apps/stations/station-editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ const _emit = defineEmits<{
}>()

const station = ref(new Station(props.value.stop))
const basemap = ref('carto')
const basemap = ref('protomaps-grayscale')
const showDeleteModal = ref(false)

const editFeatures = computed((): Feature[] => {
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/apps/transfers/platform-pathway-map.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ interface Props {

const props = withDefaults(defineProps<Props>(), {
station: null,
basemap: 'carto',
basemap: 'protomaps-grayscale',
zoom: 17,
center: () => [0, 0] as [number, number],
selectedPathways: () => [],
Expand Down
19 changes: 8 additions & 11 deletions src/runtime/apps/transfers/station-bbox-select-map.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
import { Map as MapLibreMap, NavigationControl } from 'maplibre-gl'
import type { LngLatLike } from 'maplibre-gl'
import { useBasemapLayers } from '../../composables/useBasemapLayers'
import { useBasemapLayers, layers, GRAYSCALE, PROTOMAPS_GLYPHS_URL } from '../../composables/useBasemapLayers'

interface Props {
modelValue?: string | null
Expand Down Expand Up @@ -65,28 +65,25 @@ const dragStartY = ref(0)
const dragStartWidth = ref(0)
const dragStartHeight = ref(0)

// Get basemap configuration from composable
const { basemapLayers } = useBasemapLayers()

function initMap (): void {
if (!mapContainer.value) return

const { basemapLayers } = useBasemapLayers()
const basemaps = basemapLayers.value
const grayscaleBasemap = basemapLayers.value['protomaps-grayscale']

const mapValue = new MapLibreMap({
container: mapContainer.value,
center: props.center as LngLatLike,
zoom: props.zoom,
style: {
glyphs: PROTOMAPS_GLYPHS_URL,
version: 8,
sources: {
carto: basemaps.carto.source
'protomaps-base': grayscaleBasemap.source as any
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using 'as any' type assertion bypasses TypeScript's type safety. The source configuration should match MapLibre's expected source type. Consider properly typing the grayscaleBasemap.source or using a more specific type assertion to maintain type safety.

Copilot uses AI. Check for mistakes.
},
layers: [
{
id: 'carto',
source: 'carto',
...basemaps.carto.layer
}
]
layers: layers('protomaps-base', GRAYSCALE)
}
} as any)

Expand Down
21 changes: 8 additions & 13 deletions src/runtime/apps/transfers/station-select-map.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import { ref, onMounted, onBeforeUnmount, watch, nextTick } from 'vue'
import { Map as MapLibreMap, NavigationControl, Popup, LngLatBounds } from 'maplibre-gl'
import type { LngLatLike, MapMouseEvent, GeoJSONSource } from 'maplibre-gl'
import { useBasemapLayers } from '../../composables/useBasemapLayers'
import { useBasemapLayers, layers, GRAYSCALE, PROTOMAPS_GLYPHS_URL } from '../../composables/useBasemapLayers'
import type { StationHub } from './types'
import { haversinePosition } from '../../lib/geom'

Expand Down Expand Up @@ -66,23 +66,23 @@ const emit = defineEmits<{
const mapContainer = ref<HTMLElement>()
const map = ref<MapLibreMap | null>(null)

// Get basemap configuration from composable
const { basemapLayers } = useBasemapLayers()

function initMap (): void {
if (!mapContainer.value) return

const { basemapLayers } = useBasemapLayers()
const basemaps = basemapLayers.value
const grayscaleBasemap = basemapLayers.value['protomaps-grayscale']

const mapValue = new MapLibreMap({
container: mapContainer.value,
center: props.center as LngLatLike,
zoom: props.zoom,
style: {
glyphs: PROTOMAPS_GLYPHS_URL,
version: 8,
sources: {
'carto': {
type: 'raster',
tiles: basemaps.carto.source.tiles,
},
'protomaps-base': grayscaleBasemap.source as any,
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using 'as any' type assertion bypasses TypeScript's type safety. The source configuration should match MapLibre's expected source type. Consider properly typing the grayscaleBasemap.source or using a more specific type assertion to maintain type safety.

Copilot uses AI. Check for mistakes.
'station-hubs': {
type: 'geojson',
data: {
Expand All @@ -93,12 +93,7 @@ function initMap (): void {
}
},
layers: [
{
id: 'carto',
source: 'carto',
type: 'raster',
...basemaps.carto.layer
},
...layers('protomaps-base', GRAYSCALE),
{
id: 'station-hubs-fill',
type: 'fill',
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/components/pathway-map.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ interface Props {

const props = withDefaults(defineProps<Props>(), {
station: null,
basemap: 'carto',
basemap: 'protomaps-grayscale',
zoom: 17,
center: () => [0, 0],
otherStops: () => [],
Expand Down
Loading