@likable-hair/svelte 4.2.0 → 4.2.2

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 (38) hide show
  1. package/dist/components/composed/common/MenuOrDrawer.svelte +1 -1
  2. package/dist/components/composed/common/MenuOrDrawerOptions.svelte +1 -1
  3. package/dist/components/composed/dashboard/DashboardShaper.svelte +20 -13
  4. package/dist/components/composed/dashboard/DashboardShaper.svelte.d.ts +123 -100
  5. package/dist/components/composed/forms/AsyncAutocomplete.svelte.d.ts +1 -0
  6. package/dist/components/composed/forms/DatePickerTextField.svelte +10 -2
  7. package/dist/components/composed/forms/DatePickerTextField.svelte.d.ts +1 -0
  8. package/dist/components/composed/forms/Dropdown.svelte +15 -6
  9. package/dist/components/composed/forms/PeriodPicker.svelte +115 -0
  10. package/dist/components/composed/forms/PeriodPicker.svelte.d.ts +21 -0
  11. package/dist/components/composed/forms/PeriodSelector.svelte +633 -0
  12. package/dist/components/composed/forms/PeriodSelector.svelte.d.ts +75 -0
  13. package/dist/components/composed/list/DynamicTable.svelte +130 -82
  14. package/dist/components/composed/list/DynamicTable.svelte.d.ts +2 -0
  15. package/dist/components/composed/list/EnhancedPaginatedTable.svelte +1 -2
  16. package/dist/components/composed/list/EnhancedPaginatedTable.svelte.d.ts +2 -1
  17. package/dist/components/composed/list/PaginatedTable.svelte +20 -16
  18. package/dist/components/composed/list/PaginatedTable.svelte.d.ts +2 -1
  19. package/dist/components/composed/search/DynamicFilters.svelte +10 -10
  20. package/dist/components/composed/search/DynamicFilters.svelte.d.ts +6 -0
  21. package/dist/components/composed/search/FilterEditor.svelte +10 -9
  22. package/dist/components/simple/buttons/Button.css +1 -0
  23. package/dist/components/simple/buttons/Button.svelte +4 -1
  24. package/dist/components/simple/common/Menu.svelte +124 -104
  25. package/dist/components/simple/common/Menu.svelte.d.ts +2 -0
  26. package/dist/components/simple/dates/Calendar.css +2 -2
  27. package/dist/components/simple/dates/Calendar.svelte +76 -27
  28. package/dist/components/simple/dates/Calendar.svelte.d.ts +1 -0
  29. package/dist/components/simple/dates/DatePicker.svelte +30 -12
  30. package/dist/components/simple/dates/DatePicker.svelte.d.ts +8 -1
  31. package/dist/components/simple/forms/Autocomplete.svelte +2 -2
  32. package/dist/components/simple/forms/Autocomplete.svelte.d.ts +1 -0
  33. package/dist/components/simple/lists/SelectableVerticalList.svelte +5 -4
  34. package/dist/components/simple/lists/SimpleTable.svelte +86 -54
  35. package/dist/components/simple/lists/SimpleTable.svelte.d.ts +1 -1
  36. package/dist/index.d.ts +2 -0
  37. package/dist/index.js +2 -0
  38. package/package.json +1 -1
@@ -0,0 +1,633 @@
1
+ <script module lang="ts">export const defaultQuickOptions = {
2
+ 'it': [
3
+ { value: 'today', label: 'Oggi' },
4
+ { value: 'this-week', label: 'Questa settimana' },
5
+ { value: 'this-month', label: 'Questo mese' },
6
+ { value: 'last-3month', label: 'Ultimi 3 mesi' },
7
+ { value: 'last-6month', label: 'Ultimi 6 mesi' },
8
+ { value: 'this-year', label: "Quest'anno" },
9
+ { value: 'total', label: 'Sempre' },
10
+ ],
11
+ 'en': [
12
+ { value: 'today', label: 'Today' },
13
+ { value: 'this-week', label: 'This week' },
14
+ { value: 'this-month', label: 'This month' },
15
+ { value: 'last-3month', label: 'Last 3 months' },
16
+ { value: 'last-6month', label: 'Last 6 months' },
17
+ { value: 'this-year', label: 'This year' },
18
+ { value: 'total', label: 'All time' },
19
+ ],
20
+ };
21
+ export function getPeriodLabel(settings, lang = 'en', quickOptions = defaultQuickOptions[lang]) {
22
+ if (!settings?.method)
23
+ return lang == 'en' ? 'Select range mode' : 'Seleziona una modalità';
24
+ if (settings.method === 'picker') {
25
+ let fromStr = settings.values?.from ? new Date(settings.values.from).toLocaleDateString(lang) : '';
26
+ let toStr = settings.values?.to ? new Date(settings.values.to).toLocaleDateString(lang) : '';
27
+ if (fromStr && toStr)
28
+ return `${lang == 'en' ? 'From' : 'Dal'} ${fromStr} ${lang == 'en' ? 'to' : 'al'} ${toStr}`;
29
+ if (fromStr)
30
+ return `${lang == 'en' ? 'From' : 'Dal'} ${fromStr}`;
31
+ if (toStr)
32
+ return `${lang == 'en' ? 'Until' : 'Fino al'} ${toStr}`;
33
+ return lang == 'en' ? 'Select dates' : 'Seleziona date';
34
+ }
35
+ if (settings.method === 'quick') {
36
+ return quickOptions.find(o => o.value === settings.values)?.label || (lang == 'en' ? 'Select a period' : 'Seleziona un periodo');
37
+ }
38
+ if (settings.method === 'rolling') {
39
+ const num = settings.values?.numberOfUnits;
40
+ const unit = settings.values?.measurementUnit;
41
+ const dir = settings.values?.direction ?? 'last';
42
+ if (!unit || !num)
43
+ return lang == 'en' ? 'Configure rolling window' : 'Configura periodo';
44
+ let unitLabel = '';
45
+ if (unit === 'days')
46
+ unitLabel = lang == 'en' ? 'Days' : 'Giorni';
47
+ if (unit === 'weeks')
48
+ unitLabel = lang == 'en' ? 'Weeks' : 'Settimane';
49
+ if (unit === 'months')
50
+ unitLabel = lang == 'en' ? 'Months' : 'Mesi';
51
+ if (unit === 'years')
52
+ unitLabel = lang == 'en' ? 'Years' : 'Anni';
53
+ const dirLabel = dir === 'next'
54
+ ? (lang == 'en' ? 'Next' : unit == 'weeks' ? 'Prossime' : 'Prossimi')
55
+ : (lang == 'en' ? 'Last' : unit == 'weeks' ? 'Ultime' : 'Ultimi');
56
+ return `${dirLabel} ${num} ${unitLabel}`;
57
+ }
58
+ return lang == 'en' ? 'Select range mode' : 'Seleziona una modalità';
59
+ }
60
+ </script>
61
+
62
+ <script lang="ts" generics="T extends string = string">import Dropdown from "./Dropdown.svelte";
63
+ import SimpleTextField from "../../simple/forms/SimpleTextField.svelte";
64
+ import SelectableVerticalList from "../../simple/lists/SelectableVerticalList.svelte";
65
+ import DatePicker from "../../simple/dates/DatePicker.svelte";
66
+ import { fly } from "svelte/transition";
67
+ import Icon from "../../simple/media/Icon.svelte";
68
+ import Chip from "../../simple/navigation/Chip.svelte";
69
+ import { tick } from "svelte";
70
+ let { timespanSettings = $bindable(), lang = 'en', quickSelectOptions = defaultQuickOptions[lang], valid = $bindable(), mode = 'default', locale = lang, showTimeRangeLabel = false, isSelectionMode = $bindable(), onchange, quickRangeConvertor, setTimespanLabel, } = $props();
71
+ if (!timespanSettings) {
72
+ timespanSettings = {};
73
+ }
74
+ if (isSelectionMode == undefined) {
75
+ isSelectionMode = true;
76
+ }
77
+ $effect(() => {
78
+ if (localValid != valid)
79
+ valid = localValid;
80
+ });
81
+ let timeRangeLabel = $derived(setTimespanLabel ? setTimespanLabel({ timespanSettings }) : getPeriodLabel(timespanSettings, lang, quickSelectOptions));
82
+ let rollingAutocompleteValues = [
83
+ { value: 'days', label: lang == 'en' ? 'Days' : 'Giorni' },
84
+ { value: 'weeks', label: lang == 'en' ? 'Weeks' : 'Settimane' },
85
+ { value: 'months', label: lang == 'en' ? 'Months' : 'Mesi' },
86
+ { value: 'years', label: lang == 'en' ? 'Years' : 'Anni' },
87
+ ], rollingNumberOfUnits = $state(timespanSettings?.method === 'rolling'
88
+ ? timespanSettings.values?.numberOfUnits
89
+ : 0), rollingMeasurementOfUnit = $state(timespanSettings?.method === 'rolling' && timespanSettings.values?.measurementUnit
90
+ //@ts-ignore
91
+ ? rollingAutocompleteValues.find(v => v.value == timespanSettings.values.measurementUnit)
92
+ : undefined), rollingDirectionOptions = $derived([
93
+ { value: 'last', label: lang == 'en' ? 'Last' : rollingMeasurementOfUnit?.value == 'weeks' ? 'Ultime' : 'Ultimi' },
94
+ { value: 'next', label: lang == 'en' ? 'Next' : rollingMeasurementOfUnit?.value == 'weeks' ? 'Prossime' : 'Prossimi' },
95
+ ]), rollingDirection = $state(timespanSettings?.method === 'rolling'
96
+ ? timespanSettings.values?.direction ?? 'last'
97
+ : 'last'), pickerFromValue = $derived(timespanSettings?.method === 'picker' && timespanSettings.values?.from
98
+ ? new Date(timespanSettings.values.from)
99
+ : undefined), pickerToValue = $derived(timespanSettings?.method === 'picker' && timespanSettings.values?.to
100
+ ? new Date(timespanSettings.values.to)
101
+ : undefined), quickSelectCustomOption = {
102
+ title: lang == 'en' ? 'Custom Range' : 'Intervallo personalizzato',
103
+ name: 'picker',
104
+ }, quickSelectRollingOption = {
105
+ title: lang == 'en' ? 'Rolling Window' : 'Periodo dinamico',
106
+ name: 'rolling',
107
+ }, selectedOption = $state(timespanSettings?.method), quickSelectValue = $derived(mode == 'datepicker'
108
+ ? selectedOption == 'picker'
109
+ ? [quickSelectCustomOption]
110
+ : selectedOption == 'rolling'
111
+ ? [quickSelectRollingOption]
112
+ : [{
113
+ name: quickSelectOptions.find(o => o.value == selectedOption)?.value,
114
+ title: quickSelectOptions.find(o => o.value == selectedOption)?.label,
115
+ }]
116
+ : timespanSettings?.method === 'quick' && timespanSettings.values
117
+ ? [{
118
+ name: timespanSettings.values,
119
+ title: quickSelectOptions.find((item) => item.value === timespanSettings.values)?.label,
120
+ }]
121
+ : timespanSettings?.method == 'picker'
122
+ ? [quickSelectCustomOption]
123
+ : timespanSettings?.method == 'rolling'
124
+ ? [quickSelectRollingOption]
125
+ : []), localValid = $derived.by(() => {
126
+ if (timespanSettings?.method == 'picker') {
127
+ return !!timespanSettings.values?.from || !!timespanSettings.values?.to;
128
+ }
129
+ else if (timespanSettings?.method == 'quick') {
130
+ return !!timespanSettings.values;
131
+ }
132
+ else if (timespanSettings?.method == 'rolling') {
133
+ return !!rollingNumberOfUnits && !!rollingMeasurementOfUnit;
134
+ }
135
+ return false;
136
+ }), activeSlot = $state('from');
137
+ function getDatesFromRolling(num, unit, direction = 'last') {
138
+ const from = new Date();
139
+ const to = new Date();
140
+ if (direction === 'last') {
141
+ to.setHours(23, 59, 59, 999);
142
+ if (unit === 'days')
143
+ from.setDate(from.getDate() - num);
144
+ if (unit === 'weeks')
145
+ from.setDate(from.getDate() - (num * 7));
146
+ if (unit === 'months')
147
+ from.setMonth(from.getMonth() - num);
148
+ if (unit === 'years')
149
+ from.setFullYear(from.getFullYear() - num);
150
+ from.setHours(0, 0, 0, 0);
151
+ }
152
+ else {
153
+ from.setHours(0, 0, 0, 0);
154
+ if (unit === 'days')
155
+ to.setDate(to.getDate() + num);
156
+ if (unit === 'weeks')
157
+ to.setDate(to.getDate() + (num * 7));
158
+ if (unit === 'months')
159
+ to.setMonth(to.getMonth() + num);
160
+ if (unit === 'years')
161
+ to.setFullYear(to.getFullYear() + num);
162
+ to.setHours(23, 59, 59, 999);
163
+ }
164
+ return { from, to };
165
+ }
166
+ function getDatesFromQuick(value) {
167
+ if (!!quickRangeConvertor) {
168
+ return quickRangeConvertor(value);
169
+ }
170
+ let now = new Date();
171
+ let from = new Date(now);
172
+ let to = new Date(now);
173
+ to.setHours(23, 59, 59, 999);
174
+ from.setHours(0, 0, 0, 0);
175
+ if (value === 'today') {
176
+ }
177
+ else if (value === 'this-week') {
178
+ const day = now.getDay() || 7;
179
+ if (day !== 1)
180
+ from.setHours(-24 * (day - 1));
181
+ }
182
+ else if (value === 'this-month') {
183
+ from.setDate(1);
184
+ }
185
+ else if (value === 'last-3month') {
186
+ from.setMonth(from.getMonth() - 3);
187
+ }
188
+ else if (value === 'last-6month') {
189
+ from.setMonth(from.getMonth() - 6);
190
+ }
191
+ else if (value === 'this-year') {
192
+ from.setMonth(0, 1);
193
+ }
194
+ else if (value === 'total') {
195
+ from = undefined;
196
+ }
197
+ else {
198
+ return;
199
+ }
200
+ return { from, to };
201
+ }
202
+ function formatDateLabel(from, to) {
203
+ let fromStr = from ? from.toLocaleDateString(locale) : '';
204
+ let toStr = to ? to.toLocaleDateString(locale) : '';
205
+ if (fromStr && toStr)
206
+ return `${lang == 'en' ? 'From' : 'Dal'} ${fromStr} ${lang == 'en' ? 'to' : 'al'} ${toStr}`;
207
+ if (fromStr)
208
+ return `${lang == 'en' ? 'From' : 'Dal'} ${fromStr}`;
209
+ if (toStr)
210
+ return `${lang == 'en' ? 'Until' : 'Fino al'} ${toStr}`;
211
+ return lang == 'en' ? 'Select dates' : 'Seleziona date';
212
+ }
213
+ async function handleRollingInput(value, direction) {
214
+ rollingNumberOfUnits = Math.max(Number(rollingNumberOfUnits), 0);
215
+ if (value) {
216
+ rollingMeasurementOfUnit = rollingAutocompleteValues.find(v => v.value == value);
217
+ }
218
+ if (direction == 'next' || direction == 'last') {
219
+ rollingDirection = direction;
220
+ }
221
+ if (mode == 'datepicker' && rollingMeasurementOfUnit && rollingNumberOfUnits) {
222
+ const { from, to } = getDatesFromRolling(rollingNumberOfUnits, rollingMeasurementOfUnit.value, rollingDirection);
223
+ timespanSettings = {
224
+ method: 'picker',
225
+ values: {
226
+ from,
227
+ to,
228
+ }
229
+ };
230
+ }
231
+ else if (timespanSettings?.method == 'rolling') {
232
+ timespanSettings = {
233
+ method: 'rolling',
234
+ values: {
235
+ numberOfUnits: rollingNumberOfUnits,
236
+ measurementUnit: rollingMeasurementOfUnit?.value,
237
+ direction: rollingDirection
238
+ }
239
+ };
240
+ }
241
+ await tick();
242
+ onchange?.({
243
+ timespanSettings
244
+ });
245
+ }
246
+ async function handleQuickChange(value) {
247
+ if (timespanSettings) {
248
+ if (value == 'picker') {
249
+ if (selectedOption != 'picker') {
250
+ activeSlot = 'from';
251
+ timespanSettings = {
252
+ method: 'picker',
253
+ };
254
+ }
255
+ isSelectionMode = false;
256
+ }
257
+ else if (value == 'rolling') {
258
+ if (selectedOption != 'rolling') {
259
+ rollingNumberOfUnits = 0;
260
+ rollingMeasurementOfUnit = undefined;
261
+ timespanSettings = {
262
+ method: 'rolling'
263
+ };
264
+ }
265
+ isSelectionMode = false;
266
+ }
267
+ else {
268
+ let foundValue = quickSelectOptions.find(o => o.value == value)?.value;
269
+ if (mode === 'datepicker' && foundValue) {
270
+ const dates = getDatesFromQuick(foundValue);
271
+ if (dates) {
272
+ timespanSettings = {
273
+ method: 'picker',
274
+ values: dates
275
+ };
276
+ }
277
+ }
278
+ else {
279
+ timespanSettings = {
280
+ method: 'quick',
281
+ values: foundValue
282
+ };
283
+ }
284
+ }
285
+ await tick();
286
+ selectedOption = value?.toString();
287
+ onchange?.({
288
+ timespanSettings
289
+ });
290
+ }
291
+ }
292
+ async function handleSlotToggle(slot) {
293
+ activeSlot = slot;
294
+ if (timespanSettings?.method === 'picker' && timespanSettings.values) {
295
+ const { from, to } = timespanSettings.values;
296
+ const hasFrom = !!from;
297
+ const hasTo = !!to;
298
+ if (hasFrom && !hasTo && slot === 'to') {
299
+ timespanSettings.values = { from: undefined, to: from };
300
+ }
301
+ else if (!hasFrom && hasTo && slot === 'from') {
302
+ timespanSettings.values = { from: to, to: undefined };
303
+ }
304
+ }
305
+ await tick();
306
+ onchange?.({
307
+ timespanSettings
308
+ });
309
+ }
310
+ async function handleDatePickerDayClick(dateStat) {
311
+ const clickedDate = new Date(dateStat.year, dateStat.month, dateStat.dayOfMonth);
312
+ if (timespanSettings) {
313
+ if (timespanSettings.method != 'picker') {
314
+ timespanSettings = {
315
+ method: 'picker'
316
+ };
317
+ }
318
+ let nextFrom = timespanSettings.values?.from ? new Date(timespanSettings.values.from) : undefined;
319
+ let nextTo = timespanSettings.values?.to ? new Date(timespanSettings.values.to) : undefined;
320
+ if (activeSlot == 'from') {
321
+ if (!nextFrom) {
322
+ nextFrom = clickedDate;
323
+ }
324
+ else if (!nextTo) {
325
+ nextTo = clickedDate;
326
+ if (nextFrom > nextTo) {
327
+ const temp = nextFrom;
328
+ nextFrom = nextTo;
329
+ nextTo = temp;
330
+ }
331
+ }
332
+ else {
333
+ nextFrom = clickedDate;
334
+ nextTo = undefined;
335
+ }
336
+ }
337
+ else {
338
+ if (!nextTo) {
339
+ nextTo = clickedDate;
340
+ }
341
+ else if (!nextFrom) {
342
+ nextFrom = clickedDate;
343
+ if (nextFrom > nextTo) {
344
+ const temp = nextFrom;
345
+ nextFrom = nextTo;
346
+ nextTo = temp;
347
+ }
348
+ }
349
+ else {
350
+ nextTo = clickedDate;
351
+ nextFrom = undefined;
352
+ }
353
+ }
354
+ timespanSettings = {
355
+ method: 'picker',
356
+ values: {
357
+ from: nextFrom,
358
+ to: nextTo
359
+ }
360
+ };
361
+ await tick();
362
+ onchange?.({
363
+ timespanSettings
364
+ });
365
+ }
366
+ }
367
+ function handleBack() {
368
+ isSelectionMode = true;
369
+ }
370
+ </script>
371
+
372
+ <div class="period-selector-container">
373
+ {#if isSelectionMode}
374
+ <div
375
+ class="view-panel"
376
+ in:fly={{ x: -200, duration: 250, delay: 200 }}
377
+ out:fly={{ x: -200, duration: 250, }}
378
+ >
379
+ {#if showTimeRangeLabel}
380
+ <div class="time-range-label">
381
+ {timeRangeLabel}
382
+ </div>
383
+ {/if}
384
+ <SelectableVerticalList
385
+ elements={
386
+ [
387
+ ...quickSelectOptions.map(o => ({
388
+ title: o.label,
389
+ name: o.value
390
+ })),
391
+ quickSelectCustomOption,
392
+ quickSelectRollingOption
393
+ ]
394
+ }
395
+ selected={
396
+ quickSelectValue.length
397
+ ? quickSelectValue[0].name
398
+ : undefined
399
+ }
400
+ onselect={e => handleQuickChange(e.detail.element.name)}
401
+ --selectable-vertical-list-element-padding="var(--period-selector-list-element-padding, 4px)"
402
+ --selectable-vertical-list-element-border-radius="var(--period-selector-list-element-border-radius, 4px)"
403
+ --selectable-vertical-list-title-font-size="var(--period-selector-list-element-font-size, 0.95rem)"
404
+ ></SelectableVerticalList>
405
+ </div>
406
+ {:else}
407
+ <div
408
+ class="view-panel detail-layout"
409
+ in:fly={{ x: 200, duration: 250, delay: 200 }}
410
+ out:fly={{ x: 200, duration: 250 }}
411
+ >
412
+ <div class="detail-header">
413
+ <div class="detail-subheader">
414
+ <button class="back-button" onclick={handleBack} type="button">
415
+ <Icon name='mdi-chevron-left'></Icon> {lang == 'en' ? 'Back' : 'Indietro'}
416
+ </button>
417
+ <span class="detail-title">
418
+ {
419
+ timespanSettings?.method === 'rolling'
420
+ ? lang == 'en' ? 'Rolling Window' : 'Periodo dinamico'
421
+ : lang == 'en' ? 'Custom Range' : 'Intervallo personalizzato'
422
+ }
423
+ </span>
424
+ </div>
425
+
426
+ {#if timespanSettings?.method === 'picker' && (!timespanSettings.values?.from || !timespanSettings.values?.to) && timespanSettings.values}
427
+ <Chip
428
+ inactive
429
+ onclick={() => handleSlotToggle(activeSlot == 'from' ? 'to' : 'from')}
430
+ --chip-min-height=none
431
+ >
432
+ {
433
+ activeSlot == 'from'
434
+ ? lang == 'en' ? 'From' : 'Dal'
435
+ : lang == 'en' ? 'Until' : 'Fino al'
436
+ }
437
+ <Icon name="mdi-swap-horizontal"/>
438
+ </Chip>
439
+ {/if}
440
+ </div>
441
+
442
+ <div class="detail-content">
443
+ {#if selectedOption == 'rolling' || timespanSettings?.method == 'rolling'}
444
+ <div class="rolling-container">
445
+ <div class="rolling-controls">
446
+
447
+ <div class="dropdown-wrapper">
448
+ <Dropdown
449
+ items={rollingDirectionOptions}
450
+ values={[rollingDirectionOptions.find(o => o.value == rollingDirection)!]}
451
+ mandatory
452
+ {lang}
453
+ multiple={false}
454
+ onchange={(e) => handleRollingInput(undefined, e.detail.select?.value.toString())}
455
+ mobileDrawer
456
+ clearable={false}
457
+ menuWidth='fit-content'
458
+ openingId='rolling-direction'
459
+ ></Dropdown>
460
+ </div>
461
+
462
+ <div>
463
+ <SimpleTextField
464
+ type='number'
465
+ bind:value={rollingNumberOfUnits}
466
+ oninput={() => handleRollingInput()}
467
+ --simple-textfield-width="100%"
468
+ --simple-textfield-margin-bottom="0px"
469
+ ></SimpleTextField>
470
+ </div>
471
+
472
+ <div class="dropdown-wrapper">
473
+ <Dropdown
474
+ items={rollingAutocompleteValues}
475
+ values={rollingMeasurementOfUnit ? [rollingMeasurementOfUnit] : undefined}
476
+ mandatory
477
+ {lang}
478
+ multiple={false}
479
+ onchange={(e) => handleRollingInput(e.detail.select?.value.toString())}
480
+ mobileDrawer
481
+ clearable={false}
482
+ menuWidth='fit-content'
483
+ openingId='rolling-unit'
484
+ ></Dropdown>
485
+ </div>
486
+ </div>
487
+
488
+ {#if showTimeRangeLabel}
489
+ <div class="rolling-summary">
490
+ {timeRangeLabel}
491
+ </div>
492
+ {/if}
493
+ </div>
494
+ {:else if timespanSettings?.method == 'picker'}
495
+ <DatePicker
496
+ type='dateRange'
497
+ selectedDate={pickerFromValue}
498
+ selectedDateTo={pickerToValue}
499
+ ondayClick={e => handleDatePickerDayClick(e.detail.dateStat)}
500
+ {locale}
501
+ --date-picker-height="300px"
502
+ fillOpenRange
503
+ >
504
+ {#snippet headerLabelSnippet({ dateString, dateToString, })}
505
+ {#if !!dateString && !dateToString}
506
+ {lang == 'en' ? 'From' : 'Dal'} {dateString}
507
+ {:else if !dateString && !!dateToString}
508
+ {lang == 'en' ? 'Until' : 'Fino al'} {dateToString}
509
+ {:else if !!dateToString && !!dateToString}
510
+ {lang == 'en' ? 'From' : 'Dal'} {dateString} {lang == 'en' ? 'to' : 'al'} {dateToString}
511
+ {/if}
512
+ {/snippet}
513
+ </DatePicker>
514
+ {/if}
515
+ </div>
516
+ </div>
517
+ {/if}
518
+
519
+ </div>
520
+
521
+ <style>
522
+ .period-selector-container {
523
+ display: grid;
524
+ grid-template-areas: "stack";
525
+ width: var(
526
+ --period-selector-width,
527
+ 100%
528
+ );
529
+ max-width: var(
530
+ --period-selector-max-width,
531
+ 400px
532
+ );
533
+ min-height: var(
534
+ --period-selector-min-height,
535
+ 360px
536
+ );
537
+ overflow: hidden;
538
+ position: relative;
539
+ }
540
+
541
+ .view-panel {
542
+ grid-area: stack;
543
+ width: 100%;
544
+ height: 100%;
545
+ display: flex;
546
+ flex-direction: column;
547
+ }
548
+
549
+ .detail-layout {
550
+ display: flex;
551
+ flex-direction: column;
552
+ }
553
+
554
+ .detail-header {
555
+ display: flex;
556
+ justify-content: space-between;
557
+ margin-bottom: 8px;
558
+ }
559
+
560
+ .detail-subheader {
561
+ display: flex;
562
+ gap: 12px;
563
+ align-items: center;
564
+ }
565
+
566
+ .back-button {
567
+ background: none;
568
+ border: none;
569
+ cursor: pointer;
570
+ font-size: 0.9rem;
571
+ display: flex;
572
+ color: rgb(var(--global-color-conrast-800));
573
+ align-items: center;
574
+ gap: 4px;
575
+ padding: 4px 8px;
576
+ border-radius: 4px;
577
+ }
578
+
579
+
580
+ .detail-title {
581
+ font-weight: 600;
582
+ font-size: 1rem;
583
+ color: rgb(var(--global-color-conrast-900));
584
+ }
585
+
586
+ .detail-content {
587
+ flex: 1;
588
+ display: flex;
589
+ flex-direction: column;
590
+ }
591
+
592
+ .rolling-container {
593
+ display: flex;
594
+ flex-direction: column;
595
+ gap: 8px;
596
+ }
597
+
598
+ .rolling-controls {
599
+ display: flex;
600
+ justify-content: space-between;
601
+ gap: 8px;
602
+ }
603
+
604
+ .dropdown-wrapper {
605
+ width: 31%;
606
+ --button-width: 100%;
607
+ }
608
+
609
+ .rolling-summary {
610
+ padding: 12px;
611
+ display: flex;
612
+ align-items: center;
613
+ justify-content: center;
614
+ font-weight: 500;
615
+ color: rgb(var(--global-color-conrast-700));
616
+ }
617
+
618
+ .time-range-label {
619
+ display: flex;
620
+ align-items: center;
621
+ font-size: 1rem;
622
+ font-weight: 700;
623
+ color: rgb(var(--global-color-conrast-800));
624
+ margin-bottom: 12px;
625
+ padding-left: 4px;
626
+ }
627
+
628
+ @media (max-width: 450px) {
629
+ .period-selector-container {
630
+ max-width: 100%;
631
+ }
632
+ }
633
+ </style>