Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8dc462a
Bump @commitlint/cli from 20.2.0 to 20.3.0
dependabot[bot] Jan 2, 2026
0328f14
ci(iceberg): make tsc acknowledge vitest-caused node types
oeninghe-dataport Jan 5, 2026
07048a5
fix(core): enforce usage of `Icon` type
oeninghe-dataport Jan 7, 2026
2fa72f1
feat(filter): migrate plugin
oeninghe-dataport Jan 2, 2026
6aabb56
Merge branch 'next' into vue3/migrate-plugin-filter
dopenguin Jan 16, 2026
cd23d05
fix(filter): use correct import for export store
dopenguin Jan 16, 2026
56ea116
Merge branch 'next' into vue3/migrate-plugin-filter
dopenguin Jan 19, 2026
9c92633
Merge branch 'next' into vue3/migrate-plugin-filter
dopenguin Jan 20, 2026
e6916db
Merge branch 'next' into vue3/migrate-plugin-filter
dopenguin Jan 22, 2026
25d11ec
style: apply new linting rule for self-closing
oeninghe-dataport Jan 23, 2026
b7b6c3b
Merge branch 'next' into vue3/migrate-plugin-filter
dopenguin Jan 23, 2026
0d1200c
Merge branch 'next' into vue3/migrate-plugin-filter
dopenguin Jan 23, 2026
52c14f3
Merge branch 'next' into vue3/migrate-plugin-filter
dopenguin Jan 28, 2026
e973288
fix(filter): remove bottom padding that was mitigation for a fixed bug
oeninghe-dataport Jan 30, 2026
1a1516e
fix(filter): use sensible defaults for user-defined locales
oeninghe-dataport Jan 30, 2026
7c65f97
docs(filter): recommend l10n
oeninghe-dataport Feb 2, 2026
8daf691
fix(filter): show layer name instead of ID
oeninghe-dataport Feb 2, 2026
0fb038b
fix(filter): show layer name if only one layer is offered
oeninghe-dataport Feb 2, 2026
bdb3cd6
refactor(filter): use `PluginId` as namespace for i18n
oeninghe-dataport Feb 2, 2026
952f425
refactor: move `getVectorSource` to global lib functions
oeninghe-dataport Feb 2, 2026
e573790
refactor(filter): move common getters to store
oeninghe-dataport Feb 3, 2026
49d36bb
refactor(filter): introduce store logic for time-related filters
oeninghe-dataport Feb 3, 2026
20d3c31
fix: reserve space for border in KernBlockButtonX
oeninghe-dataport Feb 3, 2026
36777db
chore(filter): add missing store files
oeninghe-dataport Feb 3, 2026
ac723a0
refactor: show focus for KernBlockButtonX
oeninghe-dataport Feb 3, 2026
715c37b
chore: remove now unused @ts-expect-error directives
oeninghe-dataport Feb 3, 2026
01f8943
Merge branch 'next' into vue3/migrate-plugin-filter
dopenguin Feb 4, 2026
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
1 change: 1 addition & 0 deletions examples/iceberg/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"types": [
"vitest/importMeta",
"vitest/jsdom",
"node",
"../../src/@types/vite-env.d.ts",
"../../src/@types/i18next.d.ts",
"../../src/@types/pinia.d.ts",
Expand Down
73 changes: 73 additions & 0 deletions examples/snowbox/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
subscribe,
updateState,
} from '@polar/polar'
import pluginFilter from '@polar/polar/plugins/filter'
import pluginFooter from '@polar/polar/plugins/footer'
import pluginFullscreen from '@polar/polar/plugins/fullscreen'
import pluginGeoLocation from '@polar/polar/plugins/geoLocation'
Expand Down Expand Up @@ -65,7 +66,7 @@
},
}

// TODO: Re-enable with isSelectable

Check warning on line 69 in examples/snowbox/index.js

View workflow job for this annotation

GitHub Actions / Linting

Unexpected 'todo' comment: 'TODO: Re-enable with isSelectable'
/*
// arbitrary condition for testing
const isEvenId = (mmlid) => Number(mmlid.slice(-1)) % 2 === 0
Expand All @@ -85,7 +86,7 @@
colorScheme,
startCenter: [573364, 6028874],
layers: [
// TODO: Add internalization to snowbox

Check warning on line 89 in examples/snowbox/index.js

View workflow job for this annotation

GitHub Actions / Linting

Unexpected 'todo' comment: 'TODO: Add internalization to snowbox'
{
id: basemapId,
visibility: true,
Expand Down Expand Up @@ -165,20 +166,43 @@
stroke: '#FFFFFF',
fill: '#333333',
},
// TODO(dopenguin): Has some HMR issues, needs to be fixed

Check warning on line 169 in examples/snowbox/index.js

View workflow job for this annotation

GitHub Actions / Linting

Unexpected 'todo' comment: 'TODO(dopenguin): Has some HMR issues,...'
// isSelectable: isReportSelectable,
},
],
clusterClickZoom: true,
},
// theme: dataportTheme,
/*

Check warning on line 176 in examples/snowbox/index.js

View workflow job for this annotation

GitHub Actions / Linting

Unexpected 'todo' comment: 'TODO(dopenguin): Surrounding application...'
TODO(dopenguin): Surrounding application should be able give information about dark or light mode via update of a state parameter; light mode by default
*/
locales: [
{
type: 'de',
resources: {
filter: {
layer: {
[reports]: {
category: {
skat: {
title: 'Schadensart',
knownValue: {
100: 'Wege und Straßen',
101: 'Schlagloch und Wegeschaden',
102: 'Verunreinigung und Vandalismus',
},
},
statu: {
title: 'Bearbeitungsstatus',
knownValue: {
'In Bearbeitung': 'In Bearbeitung',
abgeschlossen: 'Abgeschlossen',
},
},
},
},
},
},
fullscreen: {
button: {
label_on: 'Mach groß',
Expand Down Expand Up @@ -261,7 +285,7 @@
key: 'coordinate',
},
],
// TODO: Check if this works when addressSearch is implemented

Check warning on line 288 in examples/snowbox/index.js

View workflow job for this annotation

GitHub Actions / Linting

Unexpected 'todo' comment: 'TODO: Check if this works when...'
addressTarget: {
plugin: 'addressSearch',
key: 'selectResult',
Expand All @@ -286,7 +310,7 @@
},
],
menus: [
// TODO: Delete the mock plugins including the components once the correct plugins have been implemented

Check warning on line 313 in examples/snowbox/index.js

View workflow job for this annotation

GitHub Actions / Linting

Unexpected 'todo' comment: 'TODO: Delete the mock plugins including...'
[
{
plugin: pluginGeoLocation({
Expand All @@ -312,6 +336,55 @@
icon: 'kern-icon-fill--share',
},
],
[
{
plugin: pluginFilter({
layers: {
[reports]: {
categories: [
{
targetProperty: 'skat',
knownValues: [
{
value: '100',
icon: 'kern-icon--road',
},
{
value: '101',
icon: 'kern-icon--remove-road',
},
{
value: '102',
icon: 'kern-icon--destruction',
},
],
selectAll: true,
},
{
targetProperty: 'statu',
knownValues: [
{
value: 'In Bearbeitung',
icon: 'kern-icon--assignment',
},
{
value: 'abgeschlossen',
icon: 'kern-icon--check',
},
],
},
],
time: {
targetProperty: 'start',
freeSelection: 'until',
last: [0, 7, 30],
pattern: 'YYYYMMDD',
},
},
},
}),
},
],
[
{
plugin: pluginLayerChooser({}),
Expand Down
37 changes: 37 additions & 0 deletions src/components/kern/KernBlockButton.ce.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<template>
<button
class="kern-btn kern-btn--block kern-btn--tertiary"
@click="emit('click')"
>
<span
v-if="props.icon"
:class="{ 'kern-icon': true, [props.icon]: true }"
aria-hidden="true"
/>
<span class="kern-label">{{ props.label }}</span>
</button>
</template>

<script setup lang="ts">
import type { Icon } from '@/core'

const props = defineProps<{
icon?: Icon | false
label: string
}>()

const emit = defineEmits<{
click: []
}>()
</script>

<style scoped>
.kern-btn--tertiary {
background-color: #edf1fa;
justify-content: left;

.kern-label {
text-decoration: none;
}
}
</style>
46 changes: 46 additions & 0 deletions src/components/kern/KernBlockButtonCheckbox.ce.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<template>
<input :id="id" v-model="model" type="checkbox" />
<label :for="id" class="kern-btn kern-btn--block kern-btn--tertiary">
<span
v-if="props.icon"
:class="{ 'kern-icon': true, [props.icon]: true }"
aria-hidden="true"
/>
<span class="kern-label">{{ props.label }}</span>
</label>
</template>

<script setup lang="ts">
import { useId } from 'vue'

import type { Icon } from '@/core'

const props = defineProps<{
icon?: Icon | false
label: string
}>()

const model = defineModel<boolean>({ required: true })

const id = useId()
</script>

<style scoped>
.kern-btn--tertiary {
background-color: #edf1fa;
justify-content: left;

.kern-label {
text-decoration: none;
}
}

input[type='checkbox'] {
display: none;

&:checked + label {
border: var(--kern-metric-border-width-default) solid
var(--kern-color-action-default);
}
}
</style>
60 changes: 60 additions & 0 deletions src/components/kern/KernBlockButtonRadioGroup.ce.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<template>
<template v-for="item of props.items" :key="item.value">
<input
:id="id + '*' + item.value"
v-model="model"
type="radio"
:name="id"
:value="item.value"
/>
<label
:for="id + '*' + item.value"
class="kern-btn kern-btn--block kern-btn--tertiary"
>
<span
v-if="item.icon"
:class="{ 'kern-icon': true, [item.icon]: true }"
aria-hidden="true"
/>
<span class="kern-label">{{ item.label }}</span>
</label>
</template>
</template>

<script setup lang="ts">
import { useId } from 'vue'

import type { Icon } from '@/core'

const props = defineProps<{
items: {
value: string
label: string
icon?: Icon | false
}[]
}>()

const model = defineModel<string>({ required: true })

const id = useId()
</script>

<style scoped>
.kern-btn--tertiary {
background-color: #edf1fa;
justify-content: left;

.kern-label {
text-decoration: none;
}
}

input[type='radio'] {
display: none;

&:checked + label {
border: var(--kern-metric-border-width-default) solid
var(--kern-color-action-default);
}
}
</style>
29 changes: 29 additions & 0 deletions src/components/kern/KernDatePicker.ce.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<template>
<input
v-model="inputModel"
type="date"
class="kern-form-input__input"
:min="dateToString(props.min ?? null)"
:max="dateToString(props.max ?? null)"
/>
</template>

<script setup lang="ts">
import { computed } from 'vue'

import { dateToString, stringToDate } from '@/lib/dateUtils'

const props = defineProps<{
min?: Date
max?: Date
}>()

const model = defineModel<Date | null>({ required: true })

const inputModel = computed({
get: () => dateToString(model.value),
set: (value) => {
model.value = stringToDate(value)
},
})
</script>
28 changes: 28 additions & 0 deletions src/components/kern/KernDateRangePicker.ce.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<template>
<div class="range-picker">
<KernDatePicker v-model="start" v-bind="props" />
<KernDatePicker v-model="end" v-bind="props" />
</div>
</template>

<script setup lang="ts">
import KernDatePicker from './KernDatePicker.ce.vue'

const props = defineProps<{
min?: Date
max?: Date
}>()

const start = defineModel<Date | null>('start', { required: true })
const end = defineModel<Date | null>('end', { required: true })
</script>

<style scoped>
.range-picker {
display: flex;
align-items: center;
justify-content: space-between;
margin: 0.3em 0;
}
</style>
9 changes: 8 additions & 1 deletion src/core/types/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import type { SetupStoreDefinition } from 'pinia'
import type { Component } from 'vue'

import type { PluginId as FilterPluginId } from '@/plugins/filter'
import type { resourcesEn as FilterResources } from '@/plugins/filter/locales'
import type { useFilterStore as FilterStore } from '@/plugins/filter/store'
import type { PluginId as FooterPluginId } from '@/plugins/footer'
import type { resourcesEn as FooterResources } from '@/plugins/footer/locales'
import type { useFooterStore as FooterStore } from '@/plugins/footer/store'
Expand Down Expand Up @@ -29,6 +32,7 @@ import type { useToastStore as ToastStore } from '@/plugins/toast/store'

import type { NineLayoutTag } from '../utils/NineLayoutTag'
import type { Locale } from './locales'
import type { Icon } from './theme'

export interface PluginOptions {
displayComponent?: boolean
Expand Down Expand Up @@ -81,6 +85,7 @@ export type PolarPluginStore<

/** @internal */
export type BundledPluginId =
| typeof FilterPluginId
| typeof FooterPluginId
| typeof FullscreenPluginId
| typeof GeoLocationPluginId
Expand All @@ -102,6 +107,7 @@ type GetPluginStore<

/** @internal */
export type BundledPluginStores<T extends BundledPluginId> =
| GetPluginStore<T, typeof FilterPluginId, typeof FilterStore>
| GetPluginStore<T, typeof FooterPluginId, typeof FooterStore>
| GetPluginStore<T, typeof FullscreenPluginId, typeof FullscreenStore>
| GetPluginStore<T, typeof GeoLocationPluginId, typeof GeoLocationStore>
Expand All @@ -124,6 +130,7 @@ type GetPluginResources<

/** @internal */
export type BundledPluginLocaleResources<T extends BundledPluginId> =
| GetPluginResources<T, typeof FilterPluginId, typeof FilterResources>
| GetPluginResources<T, typeof FooterPluginId, typeof FooterResources>
| GetPluginResources<T, typeof FullscreenPluginId, typeof FullscreenResources>
| GetPluginResources<
Expand Down Expand Up @@ -175,7 +182,7 @@ export interface PluginContainer {
* Icon class for the plugin.
* This icon will be used as the default for rendering in menus.
*/
icon?: string
icon?: Icon

/**
* Whether the plugin is independently rendered.
Expand Down
2 changes: 1 addition & 1 deletion src/core/types/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export type Color = { oklch: OklchColor } | { rgba: RgbaColor } | string
/**
* An icon.
*/
export type Icon = `kern-icon--${string}`
export type Icon = `kern-icon--${string}` | `kern-icon-fill--${string}`

/**
* A theme for the POLAR map client.
Expand Down
16 changes: 16 additions & 0 deletions src/lib/dateUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export function dateToString(date: Date | null) {
if (date === null) {
return ''
}
return [date.getFullYear(), date.getMonth() + 1, date.getDate()]
.map((v) => v.toString().padStart(2, '0'))
.join('-')
}

export function stringToDate(date: string) {
if (date.length === 0) {
return null
}
const [y, m, d] = date.split('-')
return new Date(Number(y), Number(m) - 1, Number(d))
}
Loading
Loading