@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
@@ -26,88 +26,104 @@
26
26
  </div>
27
27
  </template>
28
28
 
29
- <script>
30
- import i18n from '../mixins/i18n'
29
+ <script setup lang="ts">
30
+ import { computed, toRef } from 'vue'
31
+ import { useI18n } from '@/composables/useI18n'
31
32
  import MapSmall from './MapSmall.vue'
32
-
33
- export default {
34
- name: 'DaySmall',
35
- components: {
36
- MapSmall,
37
- },
38
- mixins: [i18n],
39
- props: {
40
- index: {
41
- type: Number,
42
- },
43
- input: {
44
- type: Object,
45
- default: () => ({}),
46
- },
47
- visibleWarnings: {
48
- type: Array,
49
- default: () => [],
50
- },
51
- warnings: {
52
- type: Object,
53
- default: null,
54
- },
55
- regions: {
56
- type: Object,
57
- default: () => ({}),
58
- },
59
- geometryId: {
60
- type: Number,
61
- },
62
- active: {
63
- type: Boolean,
64
- },
65
- staticDays: {
66
- type: Boolean,
67
- default: true,
68
- },
69
- loading: {
70
- type: Boolean,
71
- default: true,
72
- },
73
- theme: {
74
- type: String,
75
- default: 'light-theme',
76
- },
77
- language: {
78
- type: String,
79
- },
80
- },
81
- computed: {
82
- weekday() {
83
- return this.t(this.input.weekdayName) || ''
84
- },
85
- severity() {
86
- return this.input.severity
87
- },
88
- date() {
89
- if (!this.staticDays) {
90
- return [
91
- '0...24 h',
92
- '24...48 h',
93
- '48...72 h',
94
- '72...96 h',
95
- '96...120 h',
96
- ][this.index]
97
- }
98
- return this.input.day != null && this.input.month != null
99
- ? `${this.input.day}.${this.input.month}.`
100
- : ''
101
- },
102
- ariaLabel() {
103
- return `${this.t(this.input.weekdayName)} ${this.input.day}.${
104
- this.input.month
105
- }. ${this.t('warningsInEffect')} ${this.regions.land.length} ${this.t(
106
- 'landAreas'
107
- )} ${this.regions.sea.length} ${this.t('seaAreas')}.`
108
- },
109
- },
110
- }
33
+ import type {
34
+ Day,
35
+ DayRegions,
36
+ WarningsMap,
37
+ Theme,
38
+ Language,
39
+ Severity,
40
+ } from '@/types'
41
+
42
+ // ============================================================================
43
+ // Props
44
+ // ============================================================================
45
+
46
+ const props = withDefaults(
47
+ defineProps<{
48
+ index: number
49
+ input?: Day
50
+ visibleWarnings?: string[]
51
+ warnings?: WarningsMap | null
52
+ regions?: DayRegions
53
+ geometryId?: number
54
+ active?: boolean
55
+ staticDays?: boolean
56
+ loading?: boolean
57
+ theme?: Theme | string
58
+ language?: Language
59
+ }>(),
60
+ {
61
+ input: () => ({}) as Day,
62
+ visibleWarnings: () => [],
63
+ warnings: null,
64
+ regions: () => ({ land: [], sea: [] }),
65
+ geometryId: undefined,
66
+ active: false,
67
+ staticDays: true,
68
+ loading: true,
69
+ theme: 'light-theme',
70
+ language: undefined,
71
+ }
72
+ )
73
+
74
+ // ============================================================================
75
+ // Composables
76
+ // ============================================================================
77
+
78
+ const { t } = useI18n(toRef(() => props.language))
79
+
80
+ // ============================================================================
81
+ // Computed Properties
82
+ // ============================================================================
83
+
84
+ const weekday = computed<string>(() => {
85
+ return t(props.input?.weekdayName) || ''
86
+ })
87
+
88
+ const severity = computed<Severity>(() => {
89
+ return props.input?.severity ?? 0
90
+ })
91
+
92
+ const date = computed<string>(() => {
93
+ if (!props.staticDays) {
94
+ const timeRanges = [
95
+ '0...24 h',
96
+ '24...48 h',
97
+ '48...72 h',
98
+ '72...96 h',
99
+ '96...120 h',
100
+ ]
101
+ return timeRanges[props.index] || ''
102
+ }
103
+ return props.input?.day != null && props.input?.month != null
104
+ ? `${props.input.day}.${props.input.month}.`
105
+ : ''
106
+ })
107
+
108
+ const ariaLabel = computed<string>(() => {
109
+ const landCount = props.regions?.land?.length || 0
110
+ const seaCount = props.regions?.sea?.length || 0
111
+ return `${t(props.input?.weekdayName)} ${props.input?.day}.${props.input
112
+ ?.month}. ${t('warningsInEffect')} ${landCount} ${t(
113
+ 'landAreas'
114
+ )} ${seaCount} ${t('seaAreas')}.`
115
+ })
116
+
117
+ // ============================================================================
118
+ // Expose for tests
119
+ // ============================================================================
120
+
121
+ defineExpose({
122
+ weekday,
123
+ severity,
124
+ date,
125
+ ariaLabel,
126
+ })
111
127
  </script>
112
128
 
113
129
  <style scoped lang="scss">
@@ -1,179 +1,241 @@
1
1
  <template>
2
2
  <div class="row date-selector" :class="theme">
3
- <b-tabs
4
- id="fmi-warnings-date-selector"
5
- v-model="day"
6
- :lazy="true"
7
- :no-fade="true"
8
- nav-class="fmi-warnings-date-nav"
9
- nav-wrapper-class="fmi-warnings-date-wrapper"
10
- :justified="true">
11
- <b-tab
12
- v-for="(n, i) in numberOfDays"
13
- :key="i"
14
- :active="i === day"
15
- :title-link-class="['day', `day${i}`]">
16
- <template #title>
17
- <DaySmall
3
+ <div id="fmi-warnings-date-selector" class="tabs">
4
+ <div class="fmi-warnings-date-wrapper">
5
+ <ul class="nav nav-tabs fmi-warnings-date-nav" role="tablist">
6
+ <li
7
+ v-for="(_n, i) in numberOfDays"
8
+ :key="i"
9
+ class="nav-item"
10
+ role="presentation">
11
+ <button
12
+ :class="['nav-link', 'day', `day${i}`, { active: i === day }]"
13
+ type="button"
14
+ role="tab"
15
+ :aria-selected="i === day"
16
+ @click="day = i">
17
+ <DaySmall
18
+ :index="i"
19
+ :input="input[i]"
20
+ :visible-warnings="visibleWarnings"
21
+ :warnings="warnings"
22
+ :regions="regions?.[i]"
23
+ :geometry-id="geometryId"
24
+ :active="i === day"
25
+ :static-days="staticDays"
26
+ :loading="loading"
27
+ :theme="theme"
28
+ :language="language" />
29
+ </button>
30
+ </li>
31
+ </ul>
32
+ </div>
33
+ <div class="tab-content">
34
+ <div
35
+ v-for="(_n, i) in numberOfDays"
36
+ :key="i"
37
+ :class="['tab-pane', { active: i === day, show: i === day }]"
38
+ role="tabpanel">
39
+ <DayLarge
40
+ v-if="i === day"
18
41
  :index="i"
19
42
  :input="input[i]"
20
43
  :visible-warnings="visibleWarnings"
21
44
  :warnings="warnings"
22
- :regions="regions[i]"
45
+ :regions="regions?.[i]"
23
46
  :geometry-id="geometryId"
24
- :active="i === day"
25
47
  :static-days="staticDays"
48
+ :time-offset="timeOffset"
26
49
  :loading="loading"
27
50
  :theme="theme"
28
- :language="language" />
29
- </template>
30
- <DayLarge
31
- :index="i"
32
- :input="input[i]"
33
- :visible-warnings="visibleWarnings"
34
- :warnings="warnings"
35
- :regions="regions[i]"
36
- :geometry-id="geometryId"
37
- :static-days="staticDays"
38
- :time-offset="timeOffset"
39
- :loading="loading"
40
- :theme="theme"
41
- :language="language"
42
- :spinner-enabled="spinnerEnabled"
43
- @loaded="onLoaded" />
44
- </b-tab>
45
- </b-tabs>
51
+ :language="language"
52
+ :spinner-enabled="spinnerEnabled"
53
+ @loaded="onLoaded" />
54
+ </div>
55
+ </div>
56
+ </div>
46
57
  </div>
47
58
  </template>
48
59
 
49
- <script>
60
+ <script setup lang="ts">
61
+ import {
62
+ ref,
63
+ computed,
64
+ watch,
65
+ onMounted,
66
+ onBeforeUnmount,
67
+ onUpdated,
68
+ getCurrentInstance,
69
+ } from 'vue'
70
+ import { useKeyCodes } from '@/composables/useKeyCodes'
71
+ import { NUMBER_OF_DAYS } from '@/composables/useUtils'
50
72
  import DayLarge from './DayLarge.vue'
51
73
  import DaySmall from './DaySmall.vue'
52
- import keycodes from '../mixins/keycodes'
53
-
54
- export default {
55
- name: 'Days',
56
- mixins: [keycodes],
57
- components: {
58
- DaySmall,
59
- DayLarge,
60
- },
61
- props: {
62
- input: {
63
- type: Array,
64
- default: () => [],
65
- },
66
- visibleWarnings: {
67
- type: Array,
68
- default: () => [],
69
- },
70
- selectedDay: {
71
- type: Number,
72
- default: 0,
73
- validator(value) {
74
- return [0, 1, 2, 3, 4].includes(value)
75
- },
76
- },
77
- staticDays: {
78
- type: Boolean,
79
- default: true,
80
- },
81
- timeOffset: {
82
- type: Number,
83
- default: 0,
84
- },
85
- warnings: {
86
- type: Object,
87
- default: null,
88
- },
89
- regions: Array,
90
- geometryId: Number,
91
- loading: {
92
- type: Boolean,
93
- default: true,
94
- },
95
- theme: {
96
- type: String,
97
- default: 'light-theme',
98
- },
99
- language: {
100
- type: String,
101
- },
102
- spinnerEnabled: {
103
- type: Boolean,
104
- default: true,
105
- },
106
- },
107
- data() {
108
- return {
109
- day: this.selectedDay,
110
- }
111
- },
112
- computed: {
113
- numberOfDays() {
114
- return 5
115
- },
116
- },
117
- watch: {
118
- day(newSelectedDay) {
119
- this.onDaySelected(newSelectedDay)
120
- },
121
- },
122
- mounted() {
123
- const button = Array.from(this.$el.querySelectorAll('button.day')).forEach(
74
+ import type { Day, RegionsData, WarningsMap, Theme, Language } from '@/types'
75
+
76
+ // ============================================================================
77
+ // Props
78
+ // ============================================================================
79
+
80
+ const props = withDefaults(
81
+ defineProps<{
82
+ input?: Day[]
83
+ visibleWarnings?: string[]
84
+ selectedDay?: 0 | 1 | 2 | 3 | 4
85
+ staticDays?: boolean
86
+ timeOffset?: number
87
+ warnings?: WarningsMap | null
88
+ regions?: RegionsData
89
+ geometryId?: number
90
+ loading?: boolean
91
+ theme?: Theme | string
92
+ language?: Language
93
+ spinnerEnabled?: boolean
94
+ }>(),
95
+ {
96
+ input: () => [],
97
+ visibleWarnings: () => [],
98
+ selectedDay: 0,
99
+ staticDays: true,
100
+ timeOffset: 0,
101
+ warnings: null,
102
+ regions: undefined,
103
+ geometryId: undefined,
104
+ loading: true,
105
+ theme: 'light-theme',
106
+ language: undefined,
107
+ spinnerEnabled: true,
108
+ }
109
+ )
110
+
111
+ // ============================================================================
112
+ // Emits
113
+ // ============================================================================
114
+
115
+ const emit = defineEmits<{
116
+ daySelected: [day: number]
117
+ loaded: [value: boolean]
118
+ }>()
119
+
120
+ // ============================================================================
121
+ // Composables
122
+ // ============================================================================
123
+
124
+ const { KEY_CODE_LEFT, KEY_CODE_RIGHT, KEY_CODE_HOME, KEY_CODE_END } =
125
+ useKeyCodes()
126
+
127
+ // ============================================================================
128
+ // State
129
+ // ============================================================================
130
+
131
+ const day = ref<number>(props.selectedDay)
132
+ const instance = getCurrentInstance()
133
+
134
+ // ============================================================================
135
+ // Computed
136
+ // ============================================================================
137
+
138
+ const numberOfDays = computed<number>(() => NUMBER_OF_DAYS)
139
+
140
+ // ============================================================================
141
+ // Methods
142
+ // ============================================================================
143
+
144
+ const onDaySelected = (newSelectedDay: number): void => {
145
+ emit('daySelected', newSelectedDay)
146
+ }
147
+
148
+ const onLoaded = (loaded: boolean): void => {
149
+ if (loaded) {
150
+ emit('loaded', true)
151
+ }
152
+ }
153
+
154
+ const switchDay = (event: KeyboardEvent): void => {
155
+ switch (event.keyCode) {
156
+ case KEY_CODE_LEFT:
157
+ day.value = Math.max(day.value - 1, 0)
158
+ event.preventDefault()
159
+ break
160
+ case KEY_CODE_RIGHT:
161
+ day.value = Math.min(day.value + 1, 4)
162
+ event.preventDefault()
163
+ break
164
+ case KEY_CODE_HOME:
165
+ day.value = 0
166
+ event.preventDefault()
167
+ break
168
+ case KEY_CODE_END:
169
+ day.value = 4
170
+ event.preventDefault()
171
+ break
172
+ }
173
+ const el = instance?.proxy?.$el as HTMLElement | undefined
174
+ el?.querySelector<HTMLButtonElement>(`button.day.day${day.value}`)?.focus()
175
+ }
176
+
177
+ // ============================================================================
178
+ // Watchers
179
+ // ============================================================================
180
+
181
+ watch(day, (newSelectedDay) => {
182
+ onDaySelected(newSelectedDay)
183
+ })
184
+
185
+ // ============================================================================
186
+ // Lifecycle Hooks
187
+ // ============================================================================
188
+
189
+ onMounted(() => {
190
+ const el = instance?.proxy?.$el as HTMLElement | undefined
191
+ if (el) {
192
+ Array.from(el.querySelectorAll<HTMLButtonElement>('button.day')).forEach(
124
193
  (button) => {
125
- button.addEventListener('keydown', this.switchDay, true)
194
+ button.addEventListener('keydown', switchDay, true)
126
195
  }
127
196
  )
128
- },
129
- beforeUnmount() {
130
- const button = Array.from(this.$el.querySelectorAll('button.day')).forEach(
197
+ }
198
+ })
199
+
200
+ onBeforeUnmount(() => {
201
+ const el = instance?.proxy?.$el as HTMLElement | undefined
202
+ if (el) {
203
+ Array.from(el.querySelectorAll<HTMLButtonElement>('button.day')).forEach(
131
204
  (button) => {
132
- button.removeEventListener('keydown', this.switchDay, true)
205
+ button.removeEventListener('keydown', switchDay, true)
133
206
  }
134
207
  )
135
- },
136
- updated() {
137
- Array.from(this.$el.querySelectorAll('button.day')).forEach((button) => {
138
- if (button.classList.contains('active')) {
139
- button.removeAttribute('tabindex')
140
- } else {
141
- button.setAttribute('tabindex', -1)
142
- }
143
- })
144
- },
145
- methods: {
146
- onDaySelected(newSelectedDay) {
147
- this.$emit('daySelected', newSelectedDay)
148
- },
149
- onLoaded(loaded) {
150
- if (loaded) {
151
- this.$emit('loaded', true)
152
- }
153
- },
154
- switchDay(event) {
155
- switch (event.keyCode) {
156
- case this.KEY_CODE_LEFT:
157
- this.day = Math.max(this.day - 1, 0)
158
- event.preventDefault()
159
- break
160
- case this.KEY_CODE_RIGHT:
161
- this.day = Math.min(this.day + 1, 4)
162
- event.preventDefault()
163
- break
164
- case this.KEY_CODE_HOME:
165
- this.day = 0
166
- event.preventDefault()
167
- break
168
- case this.KEY_CODE_END:
169
- this.day = 4
170
- event.preventDefault()
171
- break
208
+ }
209
+ })
210
+
211
+ onUpdated(() => {
212
+ const el = instance?.proxy?.$el as HTMLElement | undefined
213
+ if (el) {
214
+ Array.from(el.querySelectorAll<HTMLButtonElement>('button.day')).forEach(
215
+ (button) => {
216
+ if (button.classList.contains('active')) {
217
+ button.removeAttribute('tabindex')
218
+ } else {
219
+ button.setAttribute('tabindex', '-1')
220
+ }
172
221
  }
173
- this.$el.querySelector(`button.day.day${this.day}`).focus()
174
- },
175
- },
176
- }
222
+ )
223
+ }
224
+ })
225
+
226
+ // ============================================================================
227
+ // Expose for tests
228
+ // ============================================================================
229
+
230
+ defineExpose({
231
+ day,
232
+ numberOfDays,
233
+ switchDay,
234
+ onDaySelected,
235
+ onLoaded,
236
+ // Props exposed for tests
237
+ input: computed(() => props.input),
238
+ })
177
239
  </script>
178
240
 
179
241
  <style scoped lang="scss">
@@ -210,8 +272,17 @@ div#fmi-warnings-date-selector.tabs {
210
272
  flex-wrap: nowrap;
211
273
  }
212
274
 
275
+ :deep(
276
+ div.fmi-warnings-date-wrapper
277
+ > ul.nav.nav-tabs.fmi-warnings-date-nav
278
+ > li.nav-item
279
+ ) {
280
+ flex: 1;
281
+ margin: 0;
282
+ }
283
+
213
284
  :deep(div.fmi-warnings-date-wrapper li.nav-item button.day) {
214
- width: $day-small-width;
285
+ width: 100%;
215
286
  height: $day-small-height;
216
287
  border-radius: 0;
217
288
  border: 0;
@@ -222,8 +293,8 @@ div#fmi-warnings-date-selector.tabs {
222
293
  }
223
294
 
224
295
  :deep(button.day div.date-selector-cell) {
225
- height: $day-small-height;
226
- overflow: hidden;
296
+ min-height: $day-small-height;
297
+ overflow: visible;
227
298
  }
228
299
 
229
300
  :deep(button.day) {
@@ -298,7 +369,7 @@ div#fmi-warnings-date-selector.tabs {
298
369
  }
299
370
 
300
371
  :deep(div.tab-content) {
301
- margin-top: 4px;
372
+ margin-top: 20px;
302
373
  }
303
374
 
304
375
  @media (max-width: 767px) {
@@ -318,6 +389,5 @@ div#fmi-warnings-date-selector.tabs {
318
389
  :deep(button.day div.date-selector-cell) {
319
390
  height: $day-small-mobile-height;
320
391
  }
321
-
322
392
  }
323
393
  </style>