@fmidev/smartmet-alert-client 4.4.19 → 4.7.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/.eslintignore +2 -14
  2. package/.github/workflows/test.yaml +26 -0
  3. package/.nvmrc +1 -0
  4. package/AGENTS.md +26 -0
  5. package/index.html +1 -1
  6. package/package.json +80 -22
  7. package/src/AlertClientVue.vue +160 -0
  8. package/src/App.vue +154 -296
  9. package/src/assets/img/ui/arrow-down.svg +4 -11
  10. package/src/assets/img/ui/arrow-up.svg +4 -11
  11. package/src/assets/img/ui/clear.svg +7 -21
  12. package/src/assets/img/ui/close.svg +4 -15
  13. package/src/assets/img/ui/toggle-selected.svg +5 -6
  14. package/src/assets/img/ui/toggle-unselected.svg +5 -6
  15. package/src/assets/img/warning/cold-weather.svg +3 -6
  16. package/src/assets/img/warning/flood-level-3.svg +4 -7
  17. package/src/assets/img/warning/forest-fire-weather.svg +2 -6
  18. package/src/assets/img/warning/grass-fire-weather.svg +2 -6
  19. package/src/assets/img/warning/hot-weather.svg +3 -6
  20. package/src/assets/img/warning/pedestrian-safety.svg +3 -7
  21. package/src/assets/img/warning/rain.svg +2 -7
  22. package/src/assets/img/warning/sea-icing.svg +2 -6
  23. package/src/assets/img/warning/sea-thunder-storm.svg +2 -5
  24. package/src/assets/img/warning/sea-water-height-high-water.svg +3 -8
  25. package/src/assets/img/warning/sea-water-height-shallow-water.svg +3 -7
  26. package/src/assets/img/warning/sea-wave-height.svg +4 -7
  27. package/src/assets/img/warning/sea-wind-legend.svg +2 -5
  28. package/src/assets/img/warning/sea-wind.svg +2 -5
  29. package/src/assets/img/warning/several.svg +2 -5
  30. package/src/assets/img/warning/thunder-storm.svg +2 -5
  31. package/src/assets/img/warning/traffic-weather.svg +2 -6
  32. package/src/assets/img/warning/uv-note.svg +2 -6
  33. package/src/assets/img/warning/wind.svg +2 -5
  34. package/src/components/AlertClient.vue +330 -251
  35. package/src/components/CollapsiblePanel.vue +281 -0
  36. package/src/components/DayLarge.vue +146 -110
  37. package/src/components/DaySmall.vue +97 -81
  38. package/src/components/Days.vue +229 -159
  39. package/src/components/DescriptionWarning.vue +63 -38
  40. package/src/components/GrayScaleToggle.vue +58 -54
  41. package/src/components/Legend.vue +102 -325
  42. package/src/components/MapLarge.vue +574 -351
  43. package/src/components/MapSmall.vue +137 -122
  44. package/src/components/PopupRow.vue +24 -12
  45. package/src/components/Region.vue +168 -118
  46. package/src/components/RegionWarning.vue +40 -33
  47. package/src/components/Regions.vue +189 -105
  48. package/src/components/Warning.vue +70 -45
  49. package/src/components/Warnings.vue +136 -72
  50. package/src/composables/useAlertClient.ts +360 -0
  51. package/src/composables/useConfig.ts +573 -0
  52. package/src/composables/useFields.ts +66 -0
  53. package/src/composables/useI18n.ts +62 -0
  54. package/src/composables/useKeyCodes.ts +16 -0
  55. package/src/composables/useMapPaths.ts +477 -0
  56. package/src/composables/useUtils.ts +683 -0
  57. package/src/composables/useWarningsProcessor.ts +1007 -0
  58. package/src/data/geometries.json +993 -0
  59. package/src/{main.js → main.ts} +1 -0
  60. package/src/mixins/geojsonsvg.d.ts +57 -0
  61. package/src/mixins/geojsonsvg.js +5 -3
  62. package/src/plugins/index.ts +5 -0
  63. package/src/scss/_utilities.scss +193 -0
  64. package/src/scss/constants.scss +2 -1
  65. package/src/scss/warningImages.scss +8 -3
  66. package/src/types/index.ts +509 -0
  67. package/src/vite-env.d.ts +23 -0
  68. package/src/vue.ts +41 -0
  69. package/svgo.config.js +45 -0
  70. package/tests/README.md +430 -0
  71. package/tests/fixtures/mockWarningData.ts +152 -0
  72. package/tests/integration/warning-flow.spec.ts +445 -0
  73. package/tests/setup.ts +41 -0
  74. package/tests/unit/components/AlertClient.spec.ts +701 -0
  75. package/tests/unit/components/DayLarge.spec.ts +348 -0
  76. package/tests/unit/components/DaySmall.spec.ts +352 -0
  77. package/tests/unit/components/Days.spec.ts +548 -0
  78. package/tests/unit/components/DescriptionWarning.spec.ts +385 -0
  79. package/tests/unit/components/GrayScaleToggle.spec.ts +318 -0
  80. package/tests/unit/components/Legend.spec.ts +295 -0
  81. package/tests/unit/components/MapLarge.spec.ts +448 -0
  82. package/tests/unit/components/MapSmall.spec.ts +367 -0
  83. package/tests/unit/components/PopupRow.spec.ts +270 -0
  84. package/tests/unit/components/Region.spec.ts +373 -0
  85. package/tests/unit/components/RegionWarning.snapshot.spec.ts +361 -0
  86. package/tests/unit/components/RegionWarning.spec.ts +381 -0
  87. package/tests/unit/components/Regions.spec.ts +503 -0
  88. package/tests/unit/components/Warning.snapshot.spec.ts +483 -0
  89. package/tests/unit/components/Warning.spec.ts +489 -0
  90. package/tests/unit/components/Warnings.spec.ts +343 -0
  91. package/tests/unit/components/__snapshots__/RegionWarning.snapshot.spec.ts.snap +41 -0
  92. package/tests/unit/components/__snapshots__/Warning.snapshot.spec.ts.snap +433 -0
  93. package/tests/unit/composables/useConfig.spec.ts +279 -0
  94. package/tests/unit/composables/useI18n.spec.ts +116 -0
  95. package/tests/unit/composables/useKeyCodes.spec.ts +27 -0
  96. package/tests/unit/composables/useUtils.spec.ts +213 -0
  97. package/tsconfig.json +43 -0
  98. package/tsconfig.node.json +11 -0
  99. package/vite.config.js +96 -26
  100. package/vitest.config.js +40 -0
  101. package/dist/favicon.ico +0 -0
  102. package/dist/index.dark.html +0 -20
  103. package/dist/index.en.html +0 -15
  104. package/dist/index.fi.html +0 -15
  105. package/dist/index.html +0 -15
  106. package/dist/index.js +0 -281
  107. package/dist/index.mjs +0 -281
  108. package/dist/index.mjs.map +0 -1
  109. package/dist/index.relative.html +0 -19
  110. package/dist/index.start.html +0 -20
  111. package/dist/index.sv.html +0 -15
  112. package/playwright.config.ts +0 -18
  113. package/public/index.relative.html +0 -19
  114. package/public/index.start.html +0 -20
  115. package/src/mixins/config.js +0 -1378
  116. package/src/mixins/fields.js +0 -26
  117. package/src/mixins/i18n.js +0 -25
  118. package/src/mixins/keycodes.js +0 -10
  119. package/src/mixins/panzoom.js +0 -900
  120. package/src/mixins/utils.js +0 -900
  121. package/src/plugins/index.js +0 -3
  122. package/test/snapshot.test.ts +0 -126
  123. package/vitest.config.ts +0 -6
@@ -3,8 +3,7 @@
3
3
  <div class="current-description-image-cell" aria-hidden="true">
4
4
  <div
5
5
  :class="`current-description-image warning-image symbol-image transform-rotate-${rotation} level-${input.severity} ${typeClass}`"
6
- :aria-label="`${warningLevel} ${warningTitle.toLowerCase()}${warningDetails}`"
7
- >
6
+ :aria-label="`${warningLevel} ${warningTitle.toLowerCase()}${warningDetails}`">
8
7
  <span
9
8
  :class="`symbol-text transform-rotate-${invertedRotation} region-warning-symbol-text`"
10
9
  >{{ input.text }}</span
@@ -38,42 +37,68 @@
38
37
  </div>
39
38
  </template>
40
39
 
41
- <script>
42
- import fields from '../mixins/fields'
43
- import i18n from '../mixins/i18n'
44
- import utils from '../mixins/utils'
45
-
46
- export default {
47
- name: 'DescriptionWarning',
48
- mixins: [fields, i18n, utils],
49
- props: ['input', 'language', 'theme'],
50
- computed: {
51
- warningTitle() {
52
- return this.t(this.input.type)
53
- },
54
- warningLevel() {
55
- return this.t(`warningLevel${this.input.severity}`)
56
- },
57
- warningDetails() {
58
- if (this.input.text == null || this.input.direction == null) {
59
- return ''
60
- }
61
- return ` (${this.input.text} m/s ${this.t("fromDirection")} ${this.input.direction + 180}°)`
62
- },
63
- info() {
64
- return this.input.info[this.language]
65
- },
66
- validText() {
67
- return this.t('valid')
68
- },
69
- linkHidden() {
70
- return this.input.link == null || this.input.link.length === 0
71
- },
72
- description() {
73
- return this.t(`${this.input.type}DescriptionLevel${this.input.severity}`)
74
- },
75
- },
76
- }
40
+ <script setup lang="ts">
41
+ import { computed, toRef } from 'vue'
42
+ import { useFields } from '@/composables/useFields'
43
+ import { useI18n } from '@/composables/useI18n'
44
+ import type { Warning, Language } from '@/types'
45
+
46
+ // Props
47
+ const props = defineProps<{
48
+ input: Warning
49
+ language?: Language | string
50
+ theme?: string
51
+ }>()
52
+
53
+ // Composables
54
+ const { typeClass, rotation, invertedRotation, severity } = useFields(
55
+ toRef(props, 'input')
56
+ )
57
+ const { t } = useI18n(toRef(props, 'language'))
58
+
59
+ // Expose for testing
60
+ defineExpose({
61
+ severity,
62
+ })
63
+
64
+ // Computed
65
+ const warningTitle = computed((): string => {
66
+ return t(props.input.type)
67
+ })
68
+
69
+ const warningLevel = computed((): string => {
70
+ return t(`warningLevel${props.input.severity}`)
71
+ })
72
+
73
+ const warningDetails = computed((): string => {
74
+ if (
75
+ props.input.text == null ||
76
+ props.input.text === '' ||
77
+ props.input.direction == null
78
+ ) {
79
+ return ''
80
+ }
81
+ return ` (${props.input.text} m/s ${t('fromDirection')} ${
82
+ props.input.direction + 180
83
+ }°)`
84
+ })
85
+
86
+ const info = computed((): string => {
87
+ const lang = props.language as Language
88
+ return props.input.info[lang] ?? ''
89
+ })
90
+
91
+ const validText = computed((): string => {
92
+ return t('valid')
93
+ })
94
+
95
+ const linkHidden = computed((): boolean => {
96
+ return props.input.link == null || props.input.link.length === 0
97
+ })
98
+
99
+ const description = computed((): string => {
100
+ return t(`${props.input.type}DescriptionLevel${props.input.severity}`)
101
+ })
77
102
  </script>
78
103
 
79
104
  <style scoped lang="scss">
@@ -16,65 +16,69 @@
16
16
  @click="toggleGrayScale"
17
17
  @keydown.enter="toggleGrayScale"
18
18
  @keydown.space="toggleGrayScale">
19
- <span>
20
- {{ toggleText }}
21
- </span>
22
- </div>
19
+ <span>
20
+ {{ toggleText }}
21
+ </span>
22
+ </div>
23
23
  </div>
24
24
  </div>
25
25
  </template>
26
26
 
27
- <script>
28
- import i18n from '../mixins/i18n'
27
+ <script setup lang="ts">
28
+ import { computed, toRef } from 'vue'
29
+ import { useI18n } from '@/composables/useI18n'
29
30
 
30
- export default {
31
- name: 'GrayScaleToggle',
32
- mixins: [i18n],
33
- props: {
34
- language: {
35
- type: String,
36
- default: import.meta.env.VITE_LANGUAGE || 'fi',
37
- },
38
- grayScaleSelector: {
39
- type: Boolean,
40
- default: false,
41
- },
42
- theme: {
43
- type: String,
44
- default: 'light-theme',
45
- },
46
- },
47
- computed: {
48
- grayScale() {
49
- if (this.theme == null || this.theme.length === 0) {
50
- return false
51
- }
52
- const themeParts = this.theme.split('-')
53
- return themeParts.length > 1 && themeParts[1] === 'gray'
54
- },
55
- grayScaleText() {
56
- return this.t('grayScale')
57
- },
58
- toggleText() {
59
- return this.grayScale ? this.t('toggleOn') : this.t('toggleOff')
60
- },
61
- },
62
- methods: {
63
- toggleGrayScale(event) {
64
- event.preventDefault()
65
- if (this.theme == null || this.theme.length === 0) {
66
- return
67
- }
68
- const baseTheme = this.theme.split('-')[0]
69
- this.$emit(
70
- 'themeChanged',
71
- this.grayScale ? baseTheme : `${baseTheme}-gray`
72
- )
73
- },
74
- preventEvents(event) {
75
- event.preventDefault()
76
- },
77
- },
31
+ // Props
32
+ const props = withDefaults(
33
+ defineProps<{
34
+ language?: string
35
+ grayScaleSelector?: boolean
36
+ theme?: string
37
+ }>(),
38
+ {
39
+ language: import.meta.env.VITE_LANGUAGE || 'fi',
40
+ grayScaleSelector: false,
41
+ theme: 'light-theme',
42
+ }
43
+ )
44
+
45
+ // Emits
46
+ const emit = defineEmits<{
47
+ themeChanged: [theme: string]
48
+ }>()
49
+
50
+ // Composables
51
+ const { t } = useI18n(toRef(props, 'language'))
52
+
53
+ // Computed
54
+ const grayScale = computed((): boolean => {
55
+ if (props.theme == null || props.theme.length === 0) {
56
+ return false
57
+ }
58
+ const themeParts = props.theme.split('-')
59
+ return themeParts.length > 1 && themeParts[1] === 'gray'
60
+ })
61
+
62
+ const grayScaleText = computed((): string => {
63
+ return t('grayScale')
64
+ })
65
+
66
+ const toggleText = computed((): string => {
67
+ return grayScale.value ? t('toggleOn') : t('toggleOff')
68
+ })
69
+
70
+ // Methods
71
+ function toggleGrayScale(event: Event): void {
72
+ event.preventDefault()
73
+ if (props.theme == null || props.theme.length === 0) {
74
+ return
75
+ }
76
+ const baseTheme = props.theme.split('-')[0] ?? 'light'
77
+ emit('themeChanged', grayScale.value ? baseTheme : `${baseTheme}-gray`)
78
+ }
79
+
80
+ function preventEvents(event: Event): void {
81
+ event.preventDefault()
78
82
  }
79
83
  </script>
80
84