Skip to content

Commit 67148fb

Browse files
authored
Merge pull request #509 from Dataport/vue3/migrate-plugin-attributionsf
feat(attributions): migrate plugin
2 parents 662d26a + 0378f44 commit 67148fb

34 files changed

+755
-1031
lines changed

examples/iceberg/components/IcebergMap.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import type { PolarContainer } from '@polar/polar'
3030
3131
import { addPlugins, getStore, subscribe } from '@polar/polar'
3232
import pluginAddressSearch from '@polar/polar/plugins/addressSearch'
33+
import pluginAttributions from '@polar/polar/plugins/attributions'
3334
import pluginFullscreen from '@polar/polar/plugins/fullscreen'
3435
import pluginIconMenu from '@polar/polar/plugins/iconMenu'
3536
import pluginLayerChooser from '@polar/polar/plugins/layerChooser'
@@ -67,6 +68,7 @@ watch(map, (map) => {
6768
],
6869
],
6970
}),
71+
pluginAttributions({ displayComponent: true, layoutTag: 'BOTTOM_RIGHT' }),
7072
pluginScale({
7173
displayComponent: true,
7274
layoutTag: 'BOTTOM_RIGHT',

examples/iceberg/stores/iceberg.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,27 @@ export const useIcebergStore = defineStore('iceberg', () => {
8888
},
8989
},
9090
},
91+
attributions: {
92+
layerAttributions: [
93+
{
94+
id: '23420',
95+
title: 'Basemap © basemap.de / BKG <MONTH> <YEAR>',
96+
},
97+
{
98+
id: '23421',
99+
title: 'Basemap Grey © basemap.de / BKG <MONTH> <YEAR>',
100+
},
101+
{
102+
id: '1454',
103+
title:
104+
'Compensation area © Freie und Hansestadt Hamburg, Behörde für Umwelt und Energie',
105+
},
106+
{
107+
id: 'denkmaelerWMS',
108+
title: `Karte Kulturdenkmale (Denkmalliste): © <a href="https://www.schleswig-holstein.de/DE/landesregierung/ministerien-behoerden/LD/ld_node.html" target="_blank">Landesamt für Denkmalpflege</a> <MONTH> <YEAR>`,
109+
},
110+
],
111+
},
91112
fullscreen: {
92113
displayComponent: true,
93114
layoutTag: 'TOP_RIGHT',

examples/snowbox/MockAttributions.ce.vue

Lines changed: 0 additions & 16 deletions
This file was deleted.

examples/snowbox/index.js

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
updateState,
99
} from '@polar/polar'
1010
import pluginAddressSearch from '@polar/polar/plugins/addressSearch'
11+
import pluginAttributions from '@polar/polar/plugins/attributions'
1112
import pluginFooter from '@polar/polar/plugins/footer'
1213
import pluginFullscreen from '@polar/polar/plugins/fullscreen'
1314
import pluginGeoLocation from '@polar/polar/plugins/geoLocation'
@@ -20,7 +21,6 @@ import pluginScale from '@polar/polar/plugins/scale'
2021
import pluginToast from '@polar/polar/plugins/toast'
2122

2223
import EmptyComponent from './EmptyComponent.vue'
23-
import MockAttributions from './MockAttributions.ce.vue'
2424
import MockPointerPosition from './MockPointerPosition.ce.vue'
2525
import services from './services.js'
2626
import styleJsonUrl from './style.json?url'
@@ -31,7 +31,7 @@ const basemapGreyId = '23421'
3131
const ausgleichsflaechen = '1454'
3232
const reports = '6059'
3333
const denkmal = 'denkmaelerWMS'
34-
const hamburgBorder = '1693'
34+
const hamburgBorder = '6074'
3535

3636
let colorScheme = 'light'
3737
// eslint-disable-next-line no-unused-vars
@@ -329,7 +329,7 @@ addPlugin(
329329
{
330330
plugin: {
331331
component: YetAnotherEmptyComponent,
332-
id: 'attributions',
332+
id: 'other',
333333
locales: [],
334334
},
335335
icon: 'kern-icon--near-me',
@@ -379,7 +379,46 @@ addPlugin(
379379
leftEntries: [{ id: 'mockPointer', component: MockPointerPosition }],
380380
rightEntries: [
381381
pluginScale({}),
382-
{ id: 'mockAttributions', component: MockAttributions },
382+
pluginAttributions({
383+
icons: {
384+
close: 'kern-icon--keyboard-arrow-up',
385+
},
386+
listenToChanges: [
387+
{
388+
key: 'activeBackgroundId',
389+
plugin: 'layerChooser',
390+
},
391+
{
392+
key: 'activeMaskIds',
393+
plugin: 'layerChooser',
394+
},
395+
{
396+
key: 'zoom',
397+
},
398+
],
399+
layerAttributions: [
400+
{
401+
id: basemapId,
402+
title: 'snowbox.attributions.basemap',
403+
},
404+
{
405+
id: basemapGreyId,
406+
title: 'snowbox.attributions.basemapGrey',
407+
},
408+
{
409+
id: reports,
410+
title: 'snowbox.attributions.reports',
411+
},
412+
{
413+
id: ausgleichsflaechen,
414+
title: 'snowbox.attributions.ausgleichsflaechen',
415+
},
416+
{
417+
id: denkmal,
418+
title: `Karte Kulturdenkmale (Denkmalliste): © <a href="https://www.schleswig-holstein.de/DE/landesregierung/ministerien-behoerden/LD/ld_node.html" target="_blank">Landesamt für Denkmalpflege</a> <MONTH> <YEAR>`,
419+
},
420+
],
421+
}),
383422
],
384423
})
385424
)

src/core/types/main.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { VueElement } from 'vue'
22

33
import type { AddressSearchPluginOptions } from '@/plugins/addressSearch'
4+
import type { AttributionsPluginOptions } from '@/plugins/attributions'
45
import type { FooterPluginOptions } from '@/plugins/footer'
56
import type { FullscreenPluginOptions } from '@/plugins/fullscreen'
67
import type { GeoLocationPluginOptions } from '@/plugins/geoLocation'
@@ -307,6 +308,9 @@ export interface MapConfiguration extends MasterportalApiConfiguration {
307308
/** Configuration for addressSearch plugin. */
308309
addressSearch?: AddressSearchPluginOptions
309310

311+
/** Configuration for attributions plugin. */
312+
attributions?: AttributionsPluginOptions
313+
310314
/** Configuration for footer plugin. */
311315
footer?: FooterPluginOptions
312316

src/core/types/plugin.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import type { Component } from 'vue'
44
import type { PluginId as AddressSearchPluginId } from '@/plugins/addressSearch'
55
import type { resourcesEn as AddressSearchResources } from '@/plugins/addressSearch/locales'
66
import type { useAddressSearchStore as AddressSearchStore } from '@/plugins/addressSearch/store'
7+
import type { PluginId as AttributionsPluginId } from '@/plugins/attributions'
8+
import type { resourcesEn as AttributionsResources } from '@/plugins/attributions/locales'
9+
import type { useAttributionsStore as AttributionsStore } from '@/plugins/attributions/store'
710
import type { PluginId as FooterPluginId } from '@/plugins/footer'
811
import type { resourcesEn as FooterResources } from '@/plugins/footer/locales'
912
import type { useFooterStore as FooterStore } from '@/plugins/footer/store'
@@ -88,6 +91,7 @@ export type PolarPluginStore<
8891
/** @internal */
8992
export type BundledPluginId =
9093
| typeof AddressSearchPluginId
94+
| typeof AttributionsPluginId
9195
| typeof FooterPluginId
9296
| typeof FullscreenPluginId
9397
| typeof GeoLocationPluginId
@@ -111,6 +115,7 @@ type GetPluginStore<
111115
/** @internal */
112116
export type BundledPluginStores<T extends BundledPluginId> =
113117
| GetPluginStore<T, typeof AddressSearchPluginId, typeof AddressSearchStore>
118+
| GetPluginStore<T, typeof AttributionsPluginId, typeof AttributionsStore>
114119
| GetPluginStore<T, typeof FooterPluginId, typeof FooterStore>
115120
| GetPluginStore<T, typeof FullscreenPluginId, typeof FullscreenStore>
116121
| GetPluginStore<T, typeof GeoLocationPluginId, typeof GeoLocationStore>
@@ -139,6 +144,11 @@ export type BundledPluginLocaleResources<T extends BundledPluginId> =
139144
typeof AddressSearchPluginId,
140145
typeof AddressSearchResources
141146
>
147+
| GetPluginResources<
148+
T,
149+
typeof AttributionsPluginId,
150+
typeof AttributionsResources
151+
>
142152
| GetPluginResources<T, typeof FooterPluginId, typeof FooterResources>
143153
| GetPluginResources<T, typeof FullscreenPluginId, typeof FullscreenResources>
144154
| GetPluginResources<
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<template>
2+
<PolarCard
3+
:style="`width: ${width}; max-width: ${maxWidth}`"
4+
:class="
5+
renderType === 'footer' && layout === 'nineRegions'
6+
? 'polar-plugin-attributions-footer'
7+
: ''
8+
"
9+
>
10+
<header v-if="renderType !== 'footer'" class="kern-card__header">
11+
<h2 class="kern-title">{{ $t(($) => $.title, { ns: PluginId }) }}</h2>
12+
</header>
13+
<section ref="sources" class="kern-card__body">
14+
<!-- NOTE: The usage of v-html is considered unsafe as it
15+
opens a window for XSS attacks. In this case, the information is retrieved
16+
from the mapConfiguration. This is fine by configuration. -->
17+
<!-- eslint-disable vue/no-v-html -->
18+
<p
19+
v-for="(text, i) in cardText"
20+
:key="i"
21+
class="kern-body"
22+
v-html="text"
23+
/>
24+
<!-- eslint-enable vue/no-v-html -->
25+
</section>
26+
</PolarCard>
27+
</template>
28+
29+
<script lang="ts" setup>
30+
import { t } from 'i18next'
31+
import { storeToRefs } from 'pinia'
32+
import { computed, nextTick, onMounted, useTemplateRef } from 'vue'
33+
34+
import PolarCard from '@/components/PolarCard.ce.vue'
35+
import { useCoreStore } from '@/core/stores'
36+
37+
import { useAttributionsStore } from '../store'
38+
import { PluginId } from '../types'
39+
40+
const coreStore = useCoreStore()
41+
const attributionsStore = useAttributionsStore()
42+
43+
const { renderType } = storeToRefs(attributionsStore)
44+
const { layout } = storeToRefs(coreStore)
45+
46+
const sources = useTemplateRef('sources')
47+
48+
const cardText = computed(() =>
49+
attributionsStore.mapInfo.map((x) => {
50+
// This reactive value needs to recompute on language changes.
51+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
52+
coreStore.language
53+
return t(($) => $[x], {
54+
MONTH: `${new Date().getMonth() + 1}`.padStart(2, '0'),
55+
YEAR: new Date().getFullYear().toString(),
56+
ns: PluginId,
57+
})
58+
})
59+
)
60+
const maxWidth = computed(() =>
61+
renderType.value === 'independent'
62+
? coreStore.hasWindowSize && coreStore.hasSmallWidth
63+
? coreStore.clientWidth * 0.85
64+
: 1080
65+
: 'inherit'
66+
)
67+
const width = computed(() =>
68+
renderType.value === 'independent' ? attributionsStore.windowWidth : 'inherit'
69+
)
70+
71+
onMounted(() => {
72+
// NOTE: sources will always be defined unless someone removes the ref from the section element
73+
const links = (sources.value as HTMLElement).getElementsByTagName('a')
74+
if (links.length > 0) {
75+
void nextTick(() => {
76+
;(links[0] as HTMLAnchorElement).focus()
77+
})
78+
}
79+
})
80+
</script>
81+
82+
<style scoped>
83+
.kern-card {
84+
margin: 0 var(--kern-metric-space-small);
85+
86+
.kern-body {
87+
padding: 0;
88+
}
89+
}
90+
91+
.polar-plugin-attributions-footer {
92+
margin: var(--kern-metric-space-small);
93+
}
94+
</style>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<template>
2+
<StandardLayoutAttributions v-if="layout === 'standard'" />
3+
<NineLayoutAttributions v-else />
4+
</template>
5+
6+
<script lang="ts" setup>
7+
import { storeToRefs } from 'pinia'
8+
9+
import { useCoreStore } from '@/core/stores'
10+
11+
import NineLayoutAttributions from './NineLayoutAttributions.ce.vue'
12+
import StandardLayoutAttributions from './StandardLayoutAttributions.ce.vue'
13+
14+
const { layout } = storeToRefs(useCoreStore())
15+
</script>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<template>
2+
<div
3+
v-if="renderType === 'independent'"
4+
class="polar-plugin-attributions-wrapper"
5+
>
6+
<template v-if="openLeft">
7+
<PolarIconButton
8+
:hint="
9+
$t(($) => $.button.title, {
10+
ns: PluginId,
11+
context: windowIsOpen ? 'close' : 'open',
12+
})
13+
"
14+
:icon="mapInfoIcon"
15+
tooltip-position="left"
16+
@click="toggleMapInfo"
17+
/>
18+
<AttributionContent v-if="windowIsOpen" />
19+
</template>
20+
<template v-else>
21+
<AttributionContent v-if="windowIsOpen" />
22+
<PolarIconButton
23+
:hint="
24+
$t(($) => $.button.title, {
25+
ns: PluginId,
26+
context: windowIsOpen ? 'close' : 'open',
27+
})
28+
"
29+
:icon="mapInfoIcon"
30+
tooltip-position="right"
31+
@click="toggleMapInfo"
32+
/>
33+
</template>
34+
</div>
35+
<AttributionContent v-else />
36+
</template>
37+
38+
<script lang="ts" setup>
39+
import { storeToRefs } from 'pinia'
40+
import { computed } from 'vue'
41+
42+
import PolarIconButton from '@/components/PolarIconButton.ce.vue'
43+
44+
import { useAttributionsStore } from '../store'
45+
import { PluginId } from '../types'
46+
import AttributionContent from './AttributionContent.ce.vue'
47+
48+
const attributionsStore = useAttributionsStore()
49+
const { mapInfoIcon, renderType, windowIsOpen } = storeToRefs(attributionsStore)
50+
const openLeft = computed(() =>
51+
attributionsStore.configuration.layoutTag?.includes('RIGHT')
52+
)
53+
function toggleMapInfo() {
54+
windowIsOpen.value = !windowIsOpen.value
55+
}
56+
</script>
57+
58+
<style scoped>
59+
.polar-plugin-attributions-wrapper {
60+
display: flex;
61+
flex-direction: row;
62+
justify-content: flex-end;
63+
align-items: flex-end;
64+
padding: 6px;
65+
}
66+
</style>

0 commit comments

Comments
 (0)