diff --git a/components.d.ts b/components.d.ts
index c0bb715..9493f7a 100644
--- a/components.d.ts
+++ b/components.d.ts
@@ -18,6 +18,7 @@ declare module 'vue' {
HazardMenu: typeof import('./src/components/HazardMenu.vue')['default']
HazardSelect: typeof import('./src/components/HazardSelect.vue')['default']
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
+ LayerLegend: typeof import('./src/components/LayerLegend.vue')['default']
LayerList: typeof import('./src/components/LayerList.vue')['default']
MapComponent: typeof import('./src/components/MapComponent.vue')['default']
MapLayer: typeof import('./src/components/MapLayer.vue')['default']
diff --git a/src/App.vue b/src/App.vue
index 55a39d5..5d756fa 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -3,10 +3,12 @@
+
diff --git a/src/components/LayerLegend.vue b/src/components/LayerLegend.vue
new file mode 100644
index 0000000..22bef5b
--- /dev/null
+++ b/src/components/LayerLegend.vue
@@ -0,0 +1,191 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ getLayerName(layer.id) }}
+
+
+ mdi-chevron-down
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/lib/build-legend-url.js b/src/lib/build-legend-url.js
new file mode 100644
index 0000000..560ee71
--- /dev/null
+++ b/src/lib/build-legend-url.js
@@ -0,0 +1,32 @@
+import queryString from 'query-string'
+
+// GeoServer - GetLegendGraphic Docs
+// https://docs.geoserver.org/stable/en/user/services/wms/get_legend_graphic/index.html
+export default function buildLegendUrl (layerData) {
+ const { url: rawUrl, layer } = layerData
+
+ if (!rawUrl || !layer) {
+ return undefined
+ }
+
+ // Convert WMTS URL to WMS URL for GetLegendGraphic
+ // Standard GeoServer structure: /gwc/service/wmts? -> /wms?
+ let wmsUrl = rawUrl
+ if (rawUrl.includes('/gwc/service/wmts')) {
+ wmsUrl = rawUrl.replace('/gwc/service/wmts', '/wms')
+ }
+
+ // Remove trailing ? if present and add it back with params
+ const baseUrl = wmsUrl.endsWith('?') ? wmsUrl.slice(0, -1) : wmsUrl
+
+ const params = queryString.stringify({
+ 'request': 'GetLegendGraphic',
+ 'service': 'WMS',
+ 'version': '1.0.0',
+ 'format': 'image/png',
+ 'layer': layer,
+ 'legend_options': 'fontAntiAliasing:true;fontColor:0x000000;fontSize:16;labelMargin:8;dpi:90;',
+ }, { encode: true, sort: false })
+
+ return `${ baseUrl }?${ params }`
+}
diff --git a/src/stores/map.js b/src/stores/map.js
index cb51bb3..e44a944 100644
--- a/src/stores/map.js
+++ b/src/stores/map.js
@@ -32,6 +32,38 @@ export const useMapStore = defineStore('map', {
isLayerClickable: (state) => (layerId) => {
return state.layerClickable[layerId] ?? false
},
+
+ visibleLayersWithConfig: (state) => {
+ const visible = []
+ const seenIds = new Set()
+
+ for (const layerId in state.layerVisibility) {
+ if (state.layerVisibility[layerId] === true) {
+ // Skip raster layers with _raster suffix (only show base layer legends)
+ if (layerId.endsWith('_raster')) {
+ continue
+ }
+
+ // Avoid duplicates
+ if (seenIds.has(layerId)) {
+ continue
+ }
+ seenIds.add(layerId)
+
+ const layerConfig = state.layersConfig.find(config => config.id === layerId)
+ if (layerConfig && layerConfig.url && layerConfig.layer) {
+ visible.push({
+ id: layerId,
+ url: layerConfig.url,
+ layer: layerConfig.layer,
+ name: layerConfig.name,
+ })
+ }
+ }
+ }
+
+ return visible
+ },
},
actions: {
diff --git a/src/views/Home.vue b/src/views/Home.vue
index cdb5fab..a4846ab 100644
--- a/src/views/Home.vue
+++ b/src/views/Home.vue
@@ -1,6 +1,3 @@
-
-