@event-calendar/core 2.7.2 → 3.0.1

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.
package/index.js CHANGED
@@ -172,6 +172,13 @@ function copyTime(toDate, fromDate) {
172
172
  return toDate;
173
173
  }
174
174
 
175
+ /**
176
+ * Get duration value in seconds or default value if duration is undefined
177
+ */
178
+ function toSeconds(duration, defaultValue = 0) {
179
+ return duration?.seconds ?? defaultValue;
180
+ }
181
+
175
182
  /**
176
183
  * Private functions
177
184
  */
@@ -230,6 +237,10 @@ function floor(value) {
230
237
  return Math.floor(value);
231
238
  }
232
239
 
240
+ function ceil(value) {
241
+ return Math.ceil(value);
242
+ }
243
+
233
244
  function min(...args) {
234
245
  return Math.min(...args);
235
246
  }
@@ -332,26 +343,47 @@ function listView(view) {
332
343
  return view.startsWith('list');
333
344
  }
334
345
 
346
+ function timelineView(view) {
347
+ return view.includes('Timeline');
348
+ }
349
+
335
350
  let eventId = 1;
336
351
  function createEvents(input) {
337
- return input.map(event => ({
338
- id: 'id' in event ? String(event.id) : `{generated-${eventId++}}`,
339
- resourceIds: Array.isArray(event.resourceIds)
340
- ? event.resourceIds.map(String)
341
- : ('resourceId' in event ? [String(event.resourceId)] : []),
342
- allDay: event.allDay ?? (noTimePart(event.start) && noTimePart(event.end)),
343
- start: createDate(event.start),
344
- end: createDate(event.end),
345
- title: event.title || '',
346
- titleHTML: event.titleHTML || '',
347
- editable: event.editable,
348
- startEditable: event.startEditable,
349
- durationEditable: event.durationEditable,
350
- display: event.display || 'auto',
351
- extendedProps: event.extendedProps || {},
352
- backgroundColor: event.backgroundColor || event.color,
353
- textColor: event.textColor
354
- }));
352
+ return input.map(event => {
353
+ let result = {
354
+ id: 'id' in event ? String(event.id) : `{generated-${eventId++}}`,
355
+ resourceIds: Array.isArray(event.resourceIds)
356
+ ? event.resourceIds.map(String)
357
+ : ('resourceId' in event ? [String(event.resourceId)] : []),
358
+ allDay: event.allDay ?? (noTimePart(event.start) && noTimePart(event.end)),
359
+ start: createDate(event.start),
360
+ end: createDate(event.end),
361
+ title: event.title || '',
362
+ titleHTML: event.titleHTML || '',
363
+ editable: event.editable,
364
+ startEditable: event.startEditable,
365
+ durationEditable: event.durationEditable,
366
+ display: event.display || 'auto',
367
+ extendedProps: event.extendedProps || {},
368
+ backgroundColor: event.backgroundColor || event.color,
369
+ textColor: event.textColor
370
+ };
371
+
372
+ if (result.allDay) {
373
+ // Make sure all-day events start and end at midnight
374
+ setMidnight(result.start);
375
+ let end = cloneDate(result.end);
376
+ setMidnight(result.end);
377
+ if (
378
+ !datesEqual(result.end, end) ||
379
+ datesEqual(result.end, result.start) /** @see https://github.com/vkurko/calendar/issues/50 */
380
+ ) {
381
+ addDay(result.end);
382
+ }
383
+ }
384
+
385
+ return result;
386
+ });
355
387
  }
356
388
 
357
389
  function createEventSources(input) {
@@ -486,12 +518,6 @@ function prepareEventChunks(chunks, hiddenDays) {
486
518
  chunk.date = dates[0];
487
519
  chunk.days = dates.length;
488
520
  chunk.dates = dates;
489
- if (chunk.start < dates[0]) {
490
- chunk.start = dates[0];
491
- }
492
- if (setMidnight(cloneDate(chunk.end)) > dates[dates.length - 1]) {
493
- chunk.end = dates[dates.length - 1];
494
- }
495
521
  } else {
496
522
  chunk.date = setMidnight(cloneDate(chunk.start));
497
523
  chunk.days = 1;
@@ -516,7 +542,7 @@ function repositionEvent(chunk, longChunks, height) {
516
542
  chunk.bottom = chunk.top + height;
517
543
  let margin = 1;
518
544
  let key = chunk.date.getTime();
519
- if (longChunks[key]?.sorted || longChunks[key]?.chunks.every(chunk => 'top' in chunk)) {
545
+ if (longChunks[key]) {
520
546
  if (!longChunks[key].sorted) {
521
547
  longChunks[key].chunks.sort((a, b) => a.top - b.top);
522
548
  longChunks[key].sorted = true;
@@ -536,9 +562,11 @@ function repositionEvent(chunk, longChunks, height) {
536
562
 
537
563
  function runReposition(refs, data) {
538
564
  refs.length = data.length;
565
+ let result = [];
539
566
  for (let ref of refs) {
540
- ref?.reposition?.();
567
+ result.push(ref?.reposition?.());
541
568
  }
569
+ return result;
542
570
  }
543
571
 
544
572
  /**
@@ -547,13 +575,10 @@ function runReposition(refs, data) {
547
575
  * @param start
548
576
  * @param end
549
577
  * @param [resource]
550
- * @param [timeMode] Zero-length events should be allowed (@see https://github.com/vkurko/calendar/issues/50), except in time mode
551
578
  * @return boolean
552
579
  */
553
- function eventIntersects(event, start, end, resource, timeMode) {
554
- return (
555
- event.start < end && event.end > start || !timeMode && datesEqual(event.start, event.end, start)
556
- ) && (
580
+ function eventIntersects(event, start, end, resource) {
581
+ return event.start < end && event.end > start && (
557
582
  resource === undefined || event.resourceIds.includes(resource.id)
558
583
  );
559
584
  }
@@ -666,6 +691,69 @@ function _getParts(source, parts) {
666
691
  return result;
667
692
  }
668
693
 
694
+ function createTimes(date, $slotDuration, $_slotTimeLimits, $_intlSlotLabel, $_intlDayHeaderAL) {
695
+ date = cloneDate(date);
696
+ let compact = $slotDuration.seconds < 3600;
697
+ let times = [];
698
+ let end = cloneDate(date);
699
+ let i = 1;
700
+ addDuration(date, $_slotTimeLimits.min);
701
+ addDuration(end, $_slotTimeLimits.max);
702
+ while (date < end) {
703
+ times.push([
704
+ toISOString(date),
705
+ $_intlSlotLabel.format(date),
706
+ times.length && (i || !compact),
707
+ $_intlDayHeaderAL && $_intlDayHeaderAL.format(date)
708
+ ]);
709
+ addDuration(date, $slotDuration);
710
+ i = 1 - i;
711
+ }
712
+
713
+ return times;
714
+ }
715
+
716
+ function createSlotTimeLimits($slotMinTime, $slotMaxTime, $flexibleSlotTimeLimits, $_viewDates, $_events) {
717
+ let min$1 = createDuration($slotMinTime);
718
+ let max$1 = createDuration($slotMaxTime);
719
+
720
+ if ($flexibleSlotTimeLimits) {
721
+ // If slotMaxTime goes past midnight, then extend it back by a maximum of 24 hours
722
+ let minMin = createDuration(min(toSeconds(min$1), max(0, toSeconds(max$1) - DAY_IN_SECONDS)));
723
+ let maxMax = createDuration(max(toSeconds(max$1), toSeconds(minMin) + DAY_IN_SECONDS));
724
+ let filter = is_function($flexibleSlotTimeLimits?.eventFilter)
725
+ ? $flexibleSlotTimeLimits.eventFilter
726
+ : event => !bgEvent(event.display);
727
+ loop: for (let date of $_viewDates) {
728
+ let start = addDuration(cloneDate(date), min$1);
729
+ let end = addDuration(cloneDate(date), max$1);
730
+ let minStart = addDuration(cloneDate(date), minMin);
731
+ let maxEnd = addDuration(cloneDate(date), maxMax);
732
+ for (let event of $_events) {
733
+ if (!event.allDay && filter(event) && event.start < maxEnd && event.end > minStart) {
734
+ if (event.start < start) {
735
+ let seconds = max((event.start - date) / 1000, toSeconds(minMin));
736
+ if (seconds < toSeconds(min$1)) {
737
+ min$1.seconds = seconds;
738
+ }
739
+ }
740
+ if (event.end > end) {
741
+ let seconds = min((event.end - date) / 1000, toSeconds(maxMax));
742
+ if (seconds > toSeconds(max$1)) {
743
+ max$1.seconds = seconds;
744
+ }
745
+ }
746
+ if (toSeconds(min$1) === toSeconds(minMin) && toSeconds(max$1) === toSeconds(maxMax)) {
747
+ break loop;
748
+ }
749
+ }
750
+ }
751
+ }
752
+ }
753
+
754
+ return {min: min$1, max: max$1};
755
+ }
756
+
669
757
  function createOptions(plugins) {
670
758
  let options = {
671
759
  allDayContent: undefined,
@@ -716,6 +804,9 @@ function createOptions(plugins) {
716
804
  loading: undefined,
717
805
  locale: undefined,
718
806
  nowIndicator: false,
807
+ resourceLabelContent: undefined,
808
+ resourceLabelDidMount: undefined,
809
+ resources: [],
719
810
  selectable: false,
720
811
  scrollTime: '06:00:00',
721
812
  slotDuration: '00:30:00',
@@ -727,6 +818,7 @@ function createOptions(plugins) {
727
818
  },
728
819
  slotMaxTime: '24:00:00',
729
820
  slotMinTime: '00:00:00',
821
+ slotWidth: 52,
730
822
  theme: {
731
823
  allDay: 'ec-all-day',
732
824
  active: 'ec-active',
@@ -756,6 +848,7 @@ function createOptions(plugins) {
756
848
  lines: 'ec-lines',
757
849
  nowIndicator: 'ec-now-indicator',
758
850
  otherMonth: 'ec-other-month',
851
+ resource: 'ec-resource',
759
852
  sidebar: 'ec-sidebar',
760
853
  sidebarTitle: 'ec-sidebar-title',
761
854
  today: 'ec-today',
@@ -2499,7 +2592,7 @@ function instance($$self, $$props, $$invalidate) {
2499
2592
 
2500
2593
  function dateFromPoint(x, y) {
2501
2594
  let dayEl = getElementWithPayload(x, y);
2502
- return dayEl ? getPayload(dayEl)(y) : null;
2595
+ return dayEl ? getPayload(dayEl)(x, y) : null;
2503
2596
  }
2504
2597
 
2505
2598
  function destroy() {
@@ -2650,4 +2743,4 @@ class Calendar extends SvelteComponent {
2650
2743
  }
2651
2744
  }
2652
2745
 
2653
- export { DAY_IN_SECONDS, addDay, addDuration, ancestor, assign, bgEvent, btnTextDay, btnTextMonth, btnTextWeek, btnTextYear, cloneDate, cloneEvent, copyTime, createDate, createDuration, createElement, createEventChunk, createEventClasses, createEventContent, createEventSources, createEvents, createView, datesEqual, debounce, Calendar as default, eventIntersects, floor, flushDebounce, getElementWithPayload, getPayload, ghostEvent, hasPayload, hasYScroll, height, helperEvent, intl, intlRange, keyEnter, keys, listView, max, min, nextClosestDay, noTimePart, outsideEvent, pointerEvent, prepareEventChunks, prevClosestDay, previewEvent, rect, repositionEvent, runReposition, setContent, setMidnight, setPayload, sortEventChunks, subtractDay, subtractDuration, symbol, task, themeView, toEventWithLocalDates, toISOString, toLocalDate, toViewWithLocalDates };
2746
+ export { DAY_IN_SECONDS, addDay, addDuration, ancestor, assign, bgEvent, btnTextDay, btnTextMonth, btnTextWeek, btnTextYear, ceil, cloneDate, cloneEvent, copyTime, createDate, createDuration, createElement, createEventChunk, createEventClasses, createEventContent, createEventSources, createEvents, createSlotTimeLimits, createTimes, createView, datesEqual, debounce, Calendar as default, eventIntersects, floor, flushDebounce, getElementWithPayload, getPayload, ghostEvent, hasPayload, hasYScroll, height, helperEvent, intl, intlRange, keyEnter, keys, listView, max, min, nextClosestDay, noTimePart, outsideEvent, pointerEvent, prepareEventChunks, prevClosestDay, previewEvent, rect, repositionEvent, runReposition, setContent, setMidnight, setPayload, sortEventChunks, subtractDay, subtractDuration, symbol, task, themeView, timelineView, toEventWithLocalDates, toISOString, toLocalDate, toSeconds, toViewWithLocalDates };
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@event-calendar/core",
3
- "version": "2.7.2",
3
+ "version": "3.0.1",
4
4
  "title": "Event Calendar Core package",
5
- "description": "Full-sized drag & drop event calendar with resource view",
5
+ "description": "Full-sized drag & drop event calendar with resource & timeline views",
6
6
  "keywords": [
7
7
  "calendar",
8
8
  "event",
9
9
  "resource",
10
+ "timeline",
10
11
  "full-sized"
11
12
  ],
12
13
  "homepage": "https://vkurko.github.io/calendar/",
@@ -104,7 +104,7 @@
104
104
 
105
105
  export function dateFromPoint(x, y) {
106
106
  let dayEl = getElementWithPayload(x, y);
107
- return dayEl ? getPayload(dayEl)(y) : null;
107
+ return dayEl ? getPayload(dayEl)(x, y) : null;
108
108
  }
109
109
 
110
110
  export function destroy() {
package/src/lib/date.js CHANGED
@@ -123,6 +123,13 @@ export function copyTime(toDate, fromDate) {
123
123
  return toDate;
124
124
  }
125
125
 
126
+ /**
127
+ * Get duration value in seconds or default value if duration is undefined
128
+ */
129
+ export function toSeconds(duration, defaultValue = 0) {
130
+ return duration?.seconds ?? defaultValue;
131
+ }
132
+
126
133
  /**
127
134
  * Private functions
128
135
  */
package/src/lib/events.js CHANGED
@@ -6,24 +6,41 @@ import {is_function} from 'svelte/internal';
6
6
 
7
7
  let eventId = 1;
8
8
  export function createEvents(input) {
9
- return input.map(event => ({
10
- id: 'id' in event ? String(event.id) : `{generated-${eventId++}}`,
11
- resourceIds: Array.isArray(event.resourceIds)
12
- ? event.resourceIds.map(String)
13
- : ('resourceId' in event ? [String(event.resourceId)] : []),
14
- allDay: event.allDay ?? (noTimePart(event.start) && noTimePart(event.end)),
15
- start: createDate(event.start),
16
- end: createDate(event.end),
17
- title: event.title || '',
18
- titleHTML: event.titleHTML || '',
19
- editable: event.editable,
20
- startEditable: event.startEditable,
21
- durationEditable: event.durationEditable,
22
- display: event.display || 'auto',
23
- extendedProps: event.extendedProps || {},
24
- backgroundColor: event.backgroundColor || event.color,
25
- textColor: event.textColor
26
- }));
9
+ return input.map(event => {
10
+ let result = {
11
+ id: 'id' in event ? String(event.id) : `{generated-${eventId++}}`,
12
+ resourceIds: Array.isArray(event.resourceIds)
13
+ ? event.resourceIds.map(String)
14
+ : ('resourceId' in event ? [String(event.resourceId)] : []),
15
+ allDay: event.allDay ?? (noTimePart(event.start) && noTimePart(event.end)),
16
+ start: createDate(event.start),
17
+ end: createDate(event.end),
18
+ title: event.title || '',
19
+ titleHTML: event.titleHTML || '',
20
+ editable: event.editable,
21
+ startEditable: event.startEditable,
22
+ durationEditable: event.durationEditable,
23
+ display: event.display || 'auto',
24
+ extendedProps: event.extendedProps || {},
25
+ backgroundColor: event.backgroundColor || event.color,
26
+ textColor: event.textColor
27
+ };
28
+
29
+ if (result.allDay) {
30
+ // Make sure all-day events start and end at midnight
31
+ setMidnight(result.start);
32
+ let end = cloneDate(result.end);
33
+ setMidnight(result.end);
34
+ if (
35
+ !datesEqual(result.end, end) ||
36
+ datesEqual(result.end, result.start) /** @see https://github.com/vkurko/calendar/issues/50 */
37
+ ) {
38
+ addDay(result.end);
39
+ }
40
+ }
41
+
42
+ return result;
43
+ });
27
44
  }
28
45
 
29
46
  export function createEventSources(input) {
@@ -158,12 +175,6 @@ export function prepareEventChunks(chunks, hiddenDays) {
158
175
  chunk.date = dates[0];
159
176
  chunk.days = dates.length;
160
177
  chunk.dates = dates;
161
- if (chunk.start < dates[0]) {
162
- chunk.start = dates[0];
163
- }
164
- if (setMidnight(cloneDate(chunk.end)) > dates[dates.length - 1]) {
165
- chunk.end = dates[dates.length - 1];
166
- }
167
178
  } else {
168
179
  chunk.date = setMidnight(cloneDate(chunk.start));
169
180
  chunk.days = 1;
@@ -188,7 +199,7 @@ export function repositionEvent(chunk, longChunks, height) {
188
199
  chunk.bottom = chunk.top + height;
189
200
  let margin = 1;
190
201
  let key = chunk.date.getTime();
191
- if (longChunks[key]?.sorted || longChunks[key]?.chunks.every(chunk => 'top' in chunk)) {
202
+ if (longChunks[key]) {
192
203
  if (!longChunks[key].sorted) {
193
204
  longChunks[key].chunks.sort((a, b) => a.top - b.top);
194
205
  longChunks[key].sorted = true;
@@ -208,9 +219,11 @@ export function repositionEvent(chunk, longChunks, height) {
208
219
 
209
220
  export function runReposition(refs, data) {
210
221
  refs.length = data.length;
222
+ let result = [];
211
223
  for (let ref of refs) {
212
- ref?.reposition?.();
224
+ result.push(ref?.reposition?.());
213
225
  }
226
+ return result;
214
227
  }
215
228
 
216
229
  /**
@@ -219,13 +232,10 @@ export function runReposition(refs, data) {
219
232
  * @param start
220
233
  * @param end
221
234
  * @param [resource]
222
- * @param [timeMode] Zero-length events should be allowed (@see https://github.com/vkurko/calendar/issues/50), except in time mode
223
235
  * @return boolean
224
236
  */
225
- export function eventIntersects(event, start, end, resource, timeMode) {
226
- return (
227
- event.start < end && event.end > start || !timeMode && datesEqual(event.start, event.end, start)
228
- ) && (
237
+ export function eventIntersects(event, start, end, resource) {
238
+ return event.start < end && event.end > start && (
229
239
  resource === undefined || event.resourceIds.includes(resource.id)
230
240
  );
231
241
  }
@@ -0,0 +1,67 @@
1
+ import {is_function} from 'svelte/internal';
2
+ import {addDuration, cloneDate, createDuration, DAY_IN_SECONDS, toISOString, toSeconds} from './date.js';
3
+ import {max as maxFn, min as minFn} from './utils.js';
4
+ import {bgEvent} from './events.js';
5
+
6
+ export function createTimes(date, $slotDuration, $_slotTimeLimits, $_intlSlotLabel, $_intlDayHeaderAL) {
7
+ date = cloneDate(date);
8
+ let compact = $slotDuration.seconds < 3600;
9
+ let times = [];
10
+ let end = cloneDate(date);
11
+ let i = 1;
12
+ addDuration(date, $_slotTimeLimits.min);
13
+ addDuration(end, $_slotTimeLimits.max);
14
+ while (date < end) {
15
+ times.push([
16
+ toISOString(date),
17
+ $_intlSlotLabel.format(date),
18
+ times.length && (i || !compact),
19
+ $_intlDayHeaderAL && $_intlDayHeaderAL.format(date)
20
+ ]);
21
+ addDuration(date, $slotDuration);
22
+ i = 1 - i;
23
+ }
24
+
25
+ return times;
26
+ }
27
+
28
+ export function createSlotTimeLimits($slotMinTime, $slotMaxTime, $flexibleSlotTimeLimits, $_viewDates, $_events) {
29
+ let min = createDuration($slotMinTime);
30
+ let max = createDuration($slotMaxTime);
31
+
32
+ if ($flexibleSlotTimeLimits) {
33
+ // If slotMaxTime goes past midnight, then extend it back by a maximum of 24 hours
34
+ let minMin = createDuration(minFn(toSeconds(min), maxFn(0, toSeconds(max) - DAY_IN_SECONDS)));
35
+ let maxMax = createDuration(maxFn(toSeconds(max), toSeconds(minMin) + DAY_IN_SECONDS));
36
+ let filter = is_function($flexibleSlotTimeLimits?.eventFilter)
37
+ ? $flexibleSlotTimeLimits.eventFilter
38
+ : event => !bgEvent(event.display);
39
+ loop: for (let date of $_viewDates) {
40
+ let start = addDuration(cloneDate(date), min);
41
+ let end = addDuration(cloneDate(date), max);
42
+ let minStart = addDuration(cloneDate(date), minMin);
43
+ let maxEnd = addDuration(cloneDate(date), maxMax);
44
+ for (let event of $_events) {
45
+ if (!event.allDay && filter(event) && event.start < maxEnd && event.end > minStart) {
46
+ if (event.start < start) {
47
+ let seconds = maxFn((event.start - date) / 1000, toSeconds(minMin));
48
+ if (seconds < toSeconds(min)) {
49
+ min.seconds = seconds;
50
+ }
51
+ }
52
+ if (event.end > end) {
53
+ let seconds = minFn((event.end - date) / 1000, toSeconds(maxMax));
54
+ if (seconds > toSeconds(max)) {
55
+ max.seconds = seconds;
56
+ }
57
+ }
58
+ if (toSeconds(min) === toSeconds(minMin) && toSeconds(max) === toSeconds(maxMax)) {
59
+ break loop;
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }
65
+
66
+ return {min, max};
67
+ }
package/src/lib/utils.js CHANGED
@@ -10,6 +10,10 @@ export function floor(value) {
10
10
  return Math.floor(value);
11
11
  }
12
12
 
13
+ export function ceil(value) {
14
+ return Math.ceil(value);
15
+ }
16
+
13
17
  export function min(...args) {
14
18
  return Math.min(...args);
15
19
  }
package/src/lib/view.js CHANGED
@@ -26,3 +26,7 @@ export function toViewWithLocalDates(view) {
26
26
  export function listView(view) {
27
27
  return view.startsWith('list');
28
28
  }
29
+
30
+ export function timelineView(view) {
31
+ return view.includes('Timeline');
32
+ }
package/src/lib.js CHANGED
@@ -1,10 +1,11 @@
1
1
  export * from './lib/a11y.js';
2
- export * from './lib/actions';
3
- export * from './lib/date';
4
- export * from './lib/debounce';
5
- export * from './lib/dom';
6
- export * from './lib/events';
7
- export * from './lib/options';
8
- export * from './lib/stores';
9
- export * from './lib/utils';
10
- export * from './lib/view';
2
+ export * from './lib/actions.js';
3
+ export * from './lib/date.js';
4
+ export * from './lib/debounce.js';
5
+ export * from './lib/dom.js';
6
+ export * from './lib/events.js';
7
+ export * from './lib/options.js';
8
+ export * from './lib/stores.js';
9
+ export * from './lib/times.js';
10
+ export * from './lib/utils.js';
11
+ export * from './lib/view.js';
@@ -50,6 +50,9 @@ export function createOptions(plugins) {
50
50
  loading: undefined,
51
51
  locale: undefined,
52
52
  nowIndicator: false,
53
+ resourceLabelContent: undefined,
54
+ resourceLabelDidMount: undefined,
55
+ resources: [],
53
56
  selectable: false,
54
57
  scrollTime: '06:00:00',
55
58
  slotDuration: '00:30:00',
@@ -61,6 +64,7 @@ export function createOptions(plugins) {
61
64
  },
62
65
  slotMaxTime: '24:00:00',
63
66
  slotMinTime: '00:00:00',
67
+ slotWidth: 52,
64
68
  theme: {
65
69
  allDay: 'ec-all-day',
66
70
  active: 'ec-active',
@@ -90,6 +94,7 @@ export function createOptions(plugins) {
90
94
  lines: 'ec-lines',
91
95
  nowIndicator: 'ec-now-indicator',
92
96
  otherMonth: 'ec-other-month',
97
+ resource: 'ec-resource',
93
98
  sidebar: 'ec-sidebar',
94
99
  sidebarTitle: 'ec-sidebar-title',
95
100
  today: 'ec-today',