Skip to content

Commit

Permalink
Merge pull request #85 from Geoportail-Luxembourg/GSLUX-601-style-sel…
Browse files Browse the repository at this point in the history
…ector

GSLUX-601: Style selector
  • Loading branch information
tkohr authored May 3, 2024
2 parents 1e577fd + 94bc09f commit 3cf5e87
Show file tree
Hide file tree
Showing 12 changed files with 11,644 additions and 11,486 deletions.
22,800 changes: 11,417 additions & 11,383 deletions bundle/lux.dist.mjs

Large diffs are not rendered by default.

86 changes: 43 additions & 43 deletions bundle/lux.dist.umd.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion bundle/style.css

Large diffs are not rendered by default.

84 changes: 84 additions & 0 deletions cypress/e2e/style-selection.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
describe('Style selector', () => {
beforeEach(() => {
cy.visit('/')
cy.get('[data-cy="myLayersButton"]').click()
cy.get('.fa-pencil').click()
})

it('renders the style selector properly', () => {
cy.get('[data-cy="styleSelector"').should('not.be.hidden')
cy.get('[data-cy="styleSelector"')
.find('button')
.filter(':visible')
.should('have.length', 3)
})

it('has no style value in localStorage', () => {
expect(localStorage.getItem('basemap_2015_global')).to.eq('')
})

describe('Simple style selector', () => {
beforeEach(() => {
cy.get('[data-cy="styleSelector"')
.find('button')
.filter(':visible')
.first()
.as('simple')
cy.get('@simple').click()
})
it('renders the simple style selector properly', () => {
cy.get('@simple')
.siblings()
.find('button')
.filter(':visible')
.should('have.length', 6)
})
it('sets style to 4th style of list', () => {
const newStyle = `{"medium":[{"label":"Roads primary","color":"#f9c50d","lines":["lu_road_trunk_primary","lu_bridge_major","lu_tunnel_major","lu_road_major_motorway"],"visible":true},{"label":"Roads secondary","color":"#ffffff","lines":["lu_road_minor","lu_road_secondary_tertiary","lu_bridge_minor","lu_road_path","lu_bridge_path","lu_bridge_railway case","lu_bridge_path case"],"visible":true},{"label":"Vegetation","color":"#839836","opacity":"1","fills":["lu_landcover_wood","lu_landcover_grass","lu_landuse_stadium","lu_landuse_cemetery"],"visible":true},{"label":"Buildings","color":"#d6d3ce","opacity":"1","fillExtrusions":["lu_building-3d_public","lu_building-3d"],"fills":["lu_building","lu_building_public"],"lines":["lu_bridge_railway","lu_railway","lu_tunnel_railway"],"visible":true},{"label":"Water","color":"#2a5ba8","lines":["lu_waterway","lu_waterway_tunnel","lu_waterway_intermittent"],"fills":["lu_water"],"visible":true},{"label":"Background","color":"#eeeeee","backgrounds":["background"],"visible":true},{"label":"Hillshade","hillshades":["hillshade"],"visible":false}]}`
cy.get('@simple')
.siblings()
.find('button')
.filter(':visible')
.eq(3)
.click()
cy.window().then(win => {
expect(win.localStorage.getItem('basemap_2015_global')).to.eq(newStyle)
})
})
})

describe('Medium style selector', () => {
beforeEach(() => {
cy.get('[data-cy="styleSelector"')
.find('button')
.filter(':visible')
.eq(1)
.as('medium')
cy.get('@medium').click()
})
it('renders the medium style selector properly', () => {
cy.get('@medium')
.siblings()
.find('input[type="checkbox"]')
.filter(':visible')
.should('have.length', 7)
cy.get('@medium')
.siblings()
.find('input[type="color"]')
.filter(':visible')
.should('have.length', 6)
})
it('sets "Roads primary" to "visible":false', () => {
const newStyle = `{"medium":[{"label":"Roads primary","color":"#f7f7f7","lines":["lu_road_trunk_primary","lu_bridge_major","lu_tunnel_major","lu_road_major_motorway"],"visible":false},{"label":"Roads secondary","color":"#f7f7f7","lines":["lu_road_minor","lu_road_secondary_tertiary","lu_bridge_minor","lu_road_path","lu_bridge_path","lu_bridge_railway case","lu_bridge_path case"],"visible":true},{"label":"Vegetation","color":"#B8D293","opacity":"1","fills":["lu_landcover_wood","lu_landcover_grass","lu_landuse_stadium","lu_landuse_cemetery"],"visible":true},{"label":"Buildings","color":"#D6AA85","opacity":"1","fillExtrusions":["lu_building-3d_public","lu_building-3d"],"fills":["lu_building","lu_building_public"],"lines":["lu_bridge_railway","lu_railway","lu_tunnel_railway"],"visible":true},{"label":"Water","color":"#94c1e1","lines":["lu_waterway","lu_waterway_tunnel","lu_waterway_intermittent"],"fills":["lu_water"],"visible":true},{"label":"Background","color":"#e7e7e7","backgrounds":["background"],"visible":true},{"label":"Hillshade","hillshades":["hillshade"],"visible":true}]}`
cy.get('@medium')
.siblings()
.find('input[type="checkbox"]')
.filter(':visible')
.first()
.click()
cy.window().then(win => {
expect(win.localStorage.getItem('basemap_2015_global')).to.eq(newStyle)
})
})
})
})
2 changes: 2 additions & 0 deletions src/bundle/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { statePersistorMyMapService } from '@/services/state-persistor/state-per
import { proxyUrlHelper } from '@/services/proxyurl/proxyurl.helper'
import { themeSelectorService } from '@/components/theme-selector/theme-selector.service'
import MapLibreLayer from '@/lib/ol-mapbox-layer'
import StyleSelector from '@/components/style-selector/style-selector.vue'

import i18next from 'i18next'
import backend from 'i18next-http-backend'
Expand Down Expand Up @@ -120,4 +121,5 @@ export {
statePersistorMyMapService,
themeSelectorService,
MapLibreLayer,
StyleSelector,
}
30 changes: 30 additions & 0 deletions src/components/common/expandable-panel.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<script lang="ts" setup>
defineProps<{
expanded: boolean
title: string
}>()
defineEmits<{
(e: 'togglePanel'): void
}>()
</script>

<template>
<button
@click="$emit('togglePanel')"
class="group w-full text-left flex px-2 py-1.5 uppercase bg-tertiary"
:aria-expanded="expanded"
>
<div class="grow" :class="expanded ? 'text-white' : 'text-secondary'">
{{ title }}
</div>
<div class="leading-6">
<div
class="fa fa-sharp fa-solid group-hover:text-white text-primary"
:class="expanded ? 'fa-caret-up' : 'fa-caret-down'"
></div>
</div>
</button>
<div :class="expanded ? '' : 'hidden'">
<slot></slot>
</div>
</template>
30 changes: 9 additions & 21 deletions src/components/layer-tree/layer-tree-node.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { useTranslation } from 'i18next-vue'
import { computed } from 'vue'
import { useMetadataStore } from '@/stores/metadata.store'
import ExpandablePanel from '@/components/common/expandable-panel.vue'
import type { LayerTreeNodeModel } from './layer-tree.model'
Expand Down Expand Up @@ -32,28 +33,15 @@ function toggleParent(node: LayerTreeNodeModel) {
<template>
<div class="mb-px" v-if="isParent" key="node.id">
<!-- First level parents-->
<button
v-if="node.depth === 1"
class="group node-1 w-full text-left flex px-2 py-1.5 uppercase bg-tertiary"
:aria-expanded="node.expanded"
@click="toggleParent(node)"
:data-cy="`parentLayerLabel-${node.id}`"
>
<div
class="grow"
:class="node.expanded ? 'text-white' : 'text-secondary'"
>
{{ label }}
</div>
<div class="leading-6">
<div
class="fa fa-sharp fa-solid group-hover:text-white text-primary"
:class="node.expanded ? 'fa-caret-up' : 'fa-caret-down'"
></div>
</div>
</button>
<div v-if="node.depth === 1" :data-cy="`parentLayerLabel-${node.id}`">
<expandable-panel
:title="label"
:expanded="node.expanded"
@togglePanel="toggleParent(node)"
/>
</div>

<!-- Other parents-->
<!-- Other parents (with custom panel style)-->
<button
v-else-if="node.depth > 1 && !isMaxDepth"
class="w-full text-left flex px-2 py-1.5 pl-2"
Expand Down
10 changes: 7 additions & 3 deletions src/components/style-selector/expert-style-selector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,22 @@ function getStyleUrl() {
class="text-white border-2 relative h-[100px] w-[85px] mx-[10px] my-0 mb-[15px] z-5 text-sm after:absolute after:left-[20px] after:top-[10px] after:z-4 after:w-[3.6em] after:text-center after:content-download"
@click="downloadCustomStyleFile()"
>
<span class="absolute top-[70px] w-full text-center text-base">
<span
class="absolute top-[70px] w-full text-center text-base leading-3 font-medium text-white"
>
{{ t('Download style') }}
</span>
</a>
<div
class="text-white border-2 relative h-[100px] w-[85px] mx-[10px] my-0 mb-[15px] text-sm"
>
<label
class="'block z-[5] w-full h-full cursor-pointer after:absolute after:py-[15px] after:px-[15px] after:w-full after:text-center after:content-upload"
class="'block z-[5] w-full h-full cursor-pointer after:absolute after:pt-[15px] after:px-[15px] after:w-full after:text-center after:content-upload"
for="uploadMvtStyle"
>
<span class="absolute top-[70px] w-full text-center text-base">
<span
class="absolute top-[70px] w-full text-center text-base leading-3 font-medium"
>
{{ t('Upload style') }}
</span>
</label>
Expand Down
4 changes: 3 additions & 1 deletion src/components/style-selector/medium-style-item.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ function updateVisibility(visibilityChangeEvent: Event) {

<template>
<div class="flex w-full items-center">
<label for="colorId" class="w-40">{{ t(style.label) }}</label>
<label for="colorId" class="w-40 m-0 font-medium">{{
t(style.label)
}}</label>
<div class="grow">
<input
v-if="colorEditable && props.style.color"
Expand Down
79 changes: 46 additions & 33 deletions src/components/style-selector/style-selector.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { Ref, ref, computed, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { useTranslation } from 'i18next-vue'
import SimpleStyleSelector from '@/components/style-selector/simple-style-selector.vue'
import MediumStyleSelector from '@/components/style-selector/medium-style-selector.vue'
import ExpertStyleSelector from '@/components/style-selector/expert-style-selector.vue'
import ExpandablePanel from '@/components/common/expandable-panel.vue'
import { useAppStore } from '@/stores/app.store'
import { useMapStore } from '@/stores/map.store'
import { useStyleStore } from '@/stores/style.store'
Expand All @@ -15,6 +16,7 @@ const { t } = useTranslation()
const mapStore = useMapStore()
const appStore = useAppStore()
const styleStore = useStyleStore()
const { bgStyle } = storeToRefs(styleStore)
const { bgLayer } = storeToRefs(mapStore)
const styles = useMvtStyles()
Expand All @@ -28,50 +30,61 @@ watch(bgLayer, bgLayer => {
}
})
let isSimpleStyleOpen = ref(false)
let isMediumStyleOpen = ref(false)
let isAdvancedStyleOpen = ref(false)
let currentOpenPanel: Ref<
undefined | 'simpleStyle' | 'mediumStyle' | 'advancedStyle'
> = ref(undefined)
function resetStyle() {
styleStore.setStyle(null)
}
</script>

<template>
<div v-if="styleCapabilities.isEditable">
<button @click="() => appStore.closeStyleEditorPanel()">X close</button>
<h2 class="h-20 shrink-0 flex justify-between lux-panel-title">
{{ t('Style editor') }}
</h2>
<div v-if="styleCapabilities.hasSimpleStyle">
<button @click="() => (isSimpleStyleOpen = !isSimpleStyleOpen)">
{{ t('Choose a predefined style') }}
</button>
<simple-style-selector :class="isSimpleStyleOpen ? '' : 'hidden'" />
<div v-if="styleCapabilities.isEditable" data-cy="styleSelector">
<div v-if="styleCapabilities.hasSimpleStyle" class="mb-px">
<expandable-panel
:title="t('Simple')"
:expanded="currentOpenPanel === 'simpleStyle'"
@togglePanel="
() =>
(currentOpenPanel =
currentOpenPanel === 'simpleStyle' ? undefined : 'simpleStyle')
"
>
<simple-style-selector
/></expandable-panel>
</div>

<div v-if="styleCapabilities.hasAdvancedStyle">
<button @click="() => (isMediumStyleOpen = !isMediumStyleOpen)">
{{ t('Change main colours') }}
</button>
<medium-style-selector
:class="isMediumStyleOpen ? '' : 'hidden'"
v-if="bgLayer"
:layer="bgLayer"
/>
<div v-if="styleCapabilities.hasAdvancedStyle" class="mb-px">
<expandable-panel
:title="t('Medium')"
:expanded="currentOpenPanel === 'mediumStyle'"
@togglePanel="
() =>
(currentOpenPanel =
currentOpenPanel === 'mediumStyle' ? undefined : 'mediumStyle')
"
>
<medium-style-selector v-if="bgLayer" :layer="bgLayer"
/></expandable-panel>
</div>

<div v-if="styleCapabilities.hasExpertStyle">
<button @click="() => (isAdvancedStyleOpen = !isAdvancedStyleOpen)">
{{ t('Advanced settings') }}
</button>
<expert-style-selector
:class="isAdvancedStyleOpen ? '' : 'hidden'"
v-if="bgLayer"
:layer="bgLayer"
/>
<div v-if="styleCapabilities.hasExpertStyle" class="mb-px">
<expandable-panel
:title="t('Expert (style.json)')"
:expanded="currentOpenPanel === 'advancedStyle'"
@togglePanel="
() =>
(currentOpenPanel =
currentOpenPanel === 'advancedStyle'
? undefined
: 'advancedStyle')
"
>
<expert-style-selector v-if="bgLayer" :layer="bgLayer"
/></expandable-panel>
</div>
<button @click="resetStyle" class="lux-btn">
<button v-if="bgStyle" @click="resetStyle" class="lux-btn my-2">
{{ t('Reset style', { ns: 'client' }) }}
</button>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/composables/map/ol.composable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export default function useOpenLayers() {
olMap.addLayer(bgBaseLayer)
}
}
if (oldBgLayerId !== bgLayer?.id) {
if (oldBgLayerId && oldBgLayerId !== bgLayer?.id) {
statePersistorStyleService.restoreStyle(true)
}
}
Expand Down
1 change: 1 addition & 0 deletions src/composables/mvt-styles/mvt-styles.composable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ export default function useMvtStyles() {
.then(result => {
return result.id
})
.catch(error => console.warn(error))
})
}

Expand Down

0 comments on commit 3cf5e87

Please sign in to comment.