@event-calendar/core 4.7.0 → 5.0.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.
- package/README.md +29 -51
- package/dist/index.css +627 -731
- package/dist/index.js +2500 -3191
- package/package.json +2 -2
- package/src/Auxiliary.svelte +2 -13
- package/src/Buttons.svelte +62 -52
- package/src/Calendar.svelte +9 -3
- package/src/lib/a11y.js +2 -2
- package/src/lib/attachments.js +61 -0
- package/src/lib/chunks.js +117 -0
- package/src/lib/components/BaseDay.svelte +50 -0
- package/src/lib/components/BaseEvent.svelte +3 -3
- package/src/lib/components/ColHead.svelte +34 -0
- package/src/lib/components/DayHeader.svelte +14 -0
- package/src/lib/components/InteractableEvent.svelte +1 -3
- package/src/lib/components/index.js +3 -0
- package/src/lib/date.js +1 -1
- package/src/lib/dom.js +0 -4
- package/src/lib/events.js +10 -134
- package/src/lib/index.js +3 -2
- package/src/lib/{times.js → slots.js} +14 -19
- package/src/lib/stores.js +0 -33
- package/src/lib/utils.js +11 -2
- package/src/lib/view.js +0 -4
- package/src/plugins/day-grid/Day.svelte +36 -129
- package/src/plugins/day-grid/Event.svelte +42 -41
- package/src/plugins/day-grid/Popup.svelte +65 -48
- package/src/plugins/day-grid/View.svelte +76 -4
- package/src/plugins/day-grid/index.js +5 -5
- package/src/plugins/day-grid/lib.js +61 -0
- package/src/plugins/day-grid/stores.js +2 -20
- package/src/plugins/interaction/Action.svelte +40 -45
- package/src/plugins/interaction/Auxiliary.svelte +4 -4
- package/src/plugins/interaction/Pointer.svelte +8 -12
- package/src/plugins/interaction/Resizer.svelte +2 -2
- package/src/plugins/interaction/lib/utils.js +1 -5
- package/src/plugins/list/Day.svelte +8 -24
- package/src/plugins/list/View.svelte +39 -2
- package/src/plugins/resource-time-grid/Label.svelte +2 -2
- package/src/plugins/resource-time-grid/View.svelte +38 -82
- package/src/plugins/resource-time-grid/index.js +18 -10
- package/src/plugins/resource-time-grid/lib.js +31 -0
- package/src/plugins/resource-time-grid/options.js +10 -0
- package/src/plugins/resource-time-grid/stores.js +34 -0
- package/src/plugins/resource-timeline/Day.svelte +10 -73
- package/src/plugins/resource-timeline/Event.svelte +14 -23
- package/src/plugins/resource-timeline/Header.svelte +5 -5
- package/src/plugins/resource-timeline/Label.svelte +4 -12
- package/src/plugins/resource-timeline/NowIndicator.svelte +33 -28
- package/src/plugins/resource-timeline/View.svelte +129 -14
- package/src/plugins/resource-timeline/index.js +26 -23
- package/src/plugins/resource-timeline/lib.js +115 -118
- package/src/plugins/resource-timeline/stores.js +11 -7
- package/src/plugins/time-grid/AllDayEvent.svelte +31 -0
- package/src/plugins/time-grid/Day.svelte +11 -99
- package/src/plugins/time-grid/Event.svelte +18 -20
- package/src/plugins/time-grid/NowIndicator.svelte +32 -10
- package/src/plugins/time-grid/View.svelte +127 -35
- package/src/plugins/time-grid/index.js +10 -8
- package/src/plugins/time-grid/lib.js +142 -0
- package/src/plugins/time-grid/options.js +57 -0
- package/src/plugins/time-grid/stores.js +41 -8
- package/src/storage/options.js +4 -39
- package/src/storage/state.js +1 -4
- package/src/storage/stores.js +42 -11
- package/src/styles/days.css +91 -0
- package/src/styles/events.css +180 -0
- package/src/styles/index.css +126 -0
- package/src/styles/now-indicator.css +35 -0
- package/src/styles/popup.css +30 -0
- package/src/styles/sidebar.css +59 -0
- package/src/styles/slots.css +42 -0
- package/src/styles/theme.css +68 -0
- package/src/styles/toolbar.css +80 -0
- package/src/lib/actions.js +0 -52
- package/src/plugins/day-grid/Body.svelte +0 -54
- package/src/plugins/day-grid/Header.svelte +0 -20
- package/src/plugins/day-grid/Week.svelte +0 -60
- package/src/plugins/list/Body.svelte +0 -44
- package/src/plugins/resource-timeline/Body.svelte +0 -67
- package/src/plugins/resource-timeline/Days.svelte +0 -72
- package/src/plugins/resource-timeline/Sidebar.svelte +0 -35
- package/src/plugins/time-grid/Body.svelte +0 -43
- package/src/plugins/time-grid/Section.svelte +0 -29
- package/src/plugins/time-grid/all-day/Day.svelte +0 -65
- package/src/plugins/time-grid/all-day/Event.svelte +0 -37
- package/src/plugins/time-grid/all-day/Week.svelte +0 -65
- package/src/plugins/time-grid/utils.js +0 -58
- package/src/styles/day-grid.scss +0 -51
- package/src/styles/index.scss +0 -553
- package/src/styles/theme.scss +0 -95
- package/src/styles/time-grid.scss +0 -83
- package/src/styles/timeline.scss +0 -152
|
@@ -1,39 +1,44 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import {getContext} from 'svelte';
|
|
3
|
-
import {
|
|
4
|
-
import {getSlotTimeLimits} from './lib.js';
|
|
3
|
+
import {datesEqual, toSeconds, intersectionObserver} from '#lib';
|
|
5
4
|
|
|
6
|
-
let {
|
|
7
|
-
_headerHeight, _dayTimeLimits, _now, _today, _viewDates} = getContext('state');
|
|
5
|
+
let {grid} = $props();
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (datesEqual(
|
|
15
|
-
|
|
16
|
-
let dayEnd = addDuration(cloneDate($_viewDates[i]), slotTimeLimits.max);
|
|
17
|
-
if ($_now >= dayStart && $_now <= dayEnd) {
|
|
18
|
-
offset += ($_now - dayStart) / 1000;
|
|
19
|
-
break;
|
|
20
|
-
} else {
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
} else {
|
|
24
|
-
offset += slotTimeLimits.max.seconds - slotTimeLimits.min.seconds;
|
|
7
|
+
let {_mainEl, _now, _today, _sidebarWidth, slotDuration, slotWidth, theme} = getContext('state');
|
|
8
|
+
|
|
9
|
+
// Layout
|
|
10
|
+
let {gridColumn, start, end} = $derived.by(() => {
|
|
11
|
+
for (let day of grid[0]) {
|
|
12
|
+
if (datesEqual(day.dayStart, $_today)) {
|
|
13
|
+
return day;
|
|
25
14
|
}
|
|
26
15
|
}
|
|
27
|
-
|
|
28
|
-
|
|
16
|
+
return {};
|
|
17
|
+
});
|
|
18
|
+
let left = $derived.by(() => {
|
|
19
|
+
if ($_now < start || $_now > end) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
let step = toSeconds($slotDuration);
|
|
23
|
+
return ($_now - start) / 1000 / step * $slotWidth;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Observe intersections
|
|
27
|
+
let observerOptions = $derived({
|
|
28
|
+
root: $_mainEl,
|
|
29
|
+
rootMargin: `0px 0px 0px -${$_sidebarWidth + 1}px`,
|
|
30
|
+
threshold: 0.0,
|
|
29
31
|
});
|
|
32
|
+
function onIntersect(el, entry) {
|
|
33
|
+
el.classList.toggle($theme.hidden, !entry.isIntersecting);
|
|
34
|
+
}
|
|
30
35
|
</script>
|
|
31
36
|
|
|
32
|
-
{#if
|
|
33
|
-
<div
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
{#if gridColumn && left !== null}
|
|
38
|
+
<div {@attach intersectionObserver(onIntersect, observerOptions)}
|
|
39
|
+
class="{$theme.nowIndicator}"
|
|
40
|
+
style:grid-column="{gridColumn + 1}"
|
|
41
|
+
style:grid-row="2 / span {grid.length}"
|
|
42
|
+
style:inset-inline-start="{left}px"
|
|
38
43
|
></div>
|
|
39
44
|
{/if}
|
|
@@ -1,20 +1,135 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import {getContext} from 'svelte';
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
2
|
+
import {getContext, tick} from 'svelte';
|
|
3
|
+
import {max, resizeObserver, runReposition, contentFrom, toSeconds, datesEqual, min} from "#lib";
|
|
4
|
+
import {createGrid, createEventChunks, createIEventChunks, getSlotTimeLimits} from './lib.js';
|
|
5
|
+
import {ColHead, DayHeader} from '#components';
|
|
6
|
+
import Day from './Day.svelte';
|
|
7
|
+
import Event from './Event.svelte';
|
|
8
|
+
import Label from './Label.svelte';
|
|
9
|
+
import Expander from './Expander.svelte';
|
|
6
10
|
import NowIndicator from './NowIndicator.svelte';
|
|
7
11
|
|
|
8
|
-
let {
|
|
12
|
+
let {_daySlots, _dayTimeLimits, _filteredEvents, _iEvents, _mainEl, _monthView, _nestedResources, _sidebarWidth,
|
|
13
|
+
_slotLabelPeriodicity, _today, _viewResources, _viewDates, columnWidth, highlightedDates, nowIndicator, scrollTime,
|
|
14
|
+
slotDuration, slotHeight, slotWidth, theme, validRange} = getContext('state');
|
|
15
|
+
|
|
16
|
+
let headerHeight = $state(0);
|
|
17
|
+
|
|
18
|
+
let grid = $derived(createGrid($_viewDates, $_viewResources, $_dayTimeLimits, $validRange, $highlightedDates));
|
|
19
|
+
let {chunks, bgChunks} = $derived(createEventChunks($_filteredEvents, grid));
|
|
20
|
+
let iChunks = $derived(createIEventChunks($_iEvents, grid));
|
|
21
|
+
|
|
22
|
+
// Handle scrollTime
|
|
23
|
+
$effect(() => {
|
|
24
|
+
$_viewDates;
|
|
25
|
+
$scrollTime;
|
|
26
|
+
tick().then(scrollToTime);
|
|
27
|
+
});
|
|
28
|
+
function scrollToTime() {
|
|
29
|
+
if ($_monthView) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
let scrollLeft = 0;
|
|
33
|
+
let gaps = 0;
|
|
34
|
+
let todayOutOfView = $_today < $_viewDates[0] || $_today > $_viewDates.at(-1);
|
|
35
|
+
for (let date of $_viewDates) {
|
|
36
|
+
let slotTimeLimits = getSlotTimeLimits($_dayTimeLimits, date);
|
|
37
|
+
if (todayOutOfView || datesEqual(date, $_today)) {
|
|
38
|
+
scrollLeft += max(
|
|
39
|
+
min(toSeconds($scrollTime), toSeconds(slotTimeLimits.max)) - toSeconds(slotTimeLimits.min),
|
|
40
|
+
0
|
|
41
|
+
);
|
|
42
|
+
break;
|
|
43
|
+
} else {
|
|
44
|
+
scrollLeft += toSeconds(slotTimeLimits.max) - toSeconds(slotTimeLimits.min);
|
|
45
|
+
++ gaps;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
$_mainEl.scrollLeft = scrollLeft / toSeconds($slotDuration) * $slotWidth + gaps;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Events reposition
|
|
52
|
+
let refs = [];
|
|
53
|
+
function reposition() {
|
|
54
|
+
runReposition(refs, chunks);
|
|
55
|
+
}
|
|
56
|
+
$effect(reposition);
|
|
9
57
|
</script>
|
|
10
58
|
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
59
|
+
<section
|
|
60
|
+
bind:this={$_mainEl}
|
|
61
|
+
class="{$theme.main}"
|
|
62
|
+
style:--ec-grid-cols="{grid[0].length}"
|
|
63
|
+
style:--ec-grid-rows="{grid.length}"
|
|
64
|
+
style:--ec-col-width="{$columnWidth ?? 'minmax(4em, 1fr)'}"
|
|
65
|
+
style:--ec-slot-label-periodicity="{$_slotLabelPeriodicity}"
|
|
66
|
+
style:--ec-slot-height="{$slotHeight}px"
|
|
67
|
+
style:--ec-slot-width="{$slotWidth}px"
|
|
68
|
+
style:--ec-header-height="{headerHeight}px"
|
|
69
|
+
style:--ec-sidebar-width="{$_sidebarWidth}px"
|
|
70
|
+
{@attach resizeObserver(reposition)}
|
|
71
|
+
>
|
|
72
|
+
<header bind:offsetHeight={headerHeight} class="{$theme.header}">
|
|
73
|
+
<aside class="{$theme.sidebar}" bind:offsetWidth={$_sidebarWidth}></aside>
|
|
74
|
+
<div class="{$theme.grid}" role="row">
|
|
75
|
+
{#each grid[0] as {dayStart: date, disabled, highlight}, i}
|
|
76
|
+
<ColHead {date} colIndex={1 + i} {disabled} {highlight}>
|
|
77
|
+
<DayHeader {date}/>
|
|
78
|
+
</ColHead>
|
|
79
|
+
{/each}
|
|
80
|
+
{#if !$_monthView}
|
|
81
|
+
{#each grid[0] as {dayStart: date, disabled, highlight}}
|
|
82
|
+
<ColHead {date} className={$theme.slots} {disabled} {highlight} ariaHidden>
|
|
83
|
+
{#each $_daySlots[date.getTime()] as slot}
|
|
84
|
+
<div
|
|
85
|
+
class="{$theme.slot}"
|
|
86
|
+
style:--ec-slot-label-periodicity={slot[2]}
|
|
87
|
+
>
|
|
88
|
+
<time
|
|
89
|
+
datetime="{slot[0]}"
|
|
90
|
+
{@attach contentFrom(slot[1])}
|
|
91
|
+
></time>
|
|
92
|
+
</div>
|
|
93
|
+
{/each}
|
|
94
|
+
</ColHead>
|
|
95
|
+
{/each}
|
|
96
|
+
{/if}
|
|
97
|
+
</div>
|
|
98
|
+
</header>
|
|
99
|
+
|
|
100
|
+
<div class="{$theme.body}" role="rowgroup">
|
|
101
|
+
<aside class="{$theme.sidebar}">
|
|
102
|
+
{#each $_viewResources as resource}
|
|
103
|
+
<div class="{$theme.rowHead}" role="rowheader">
|
|
104
|
+
{#if $_nestedResources}
|
|
105
|
+
<Expander {resource} />
|
|
106
|
+
{/if}
|
|
107
|
+
<Label {resource}/>
|
|
108
|
+
</div>
|
|
109
|
+
{/each}
|
|
110
|
+
</aside>
|
|
111
|
+
<div class="{$theme.grid}" role="row">
|
|
112
|
+
{#each grid as days}
|
|
113
|
+
{#each days as day}
|
|
114
|
+
<Day {day}/>
|
|
115
|
+
{/each}
|
|
116
|
+
{/each}
|
|
117
|
+
</div>
|
|
118
|
+
<div class="{$theme.events}">
|
|
119
|
+
{#each chunks as chunk, i}
|
|
120
|
+
<!-- svelte-ignore binding_property_non_reactive -->
|
|
121
|
+
<Event bind:this={refs[i]} {chunk}/>
|
|
122
|
+
{/each}
|
|
123
|
+
{#each bgChunks as chunk}
|
|
124
|
+
<Event {chunk}/>
|
|
125
|
+
{/each}
|
|
126
|
+
{#each iChunks as chunk}
|
|
127
|
+
<Event {chunk}/>
|
|
128
|
+
{/each}
|
|
129
|
+
</div>
|
|
19
130
|
</div>
|
|
20
|
-
|
|
131
|
+
|
|
132
|
+
{#if $nowIndicator && !$_monthView}
|
|
133
|
+
<NowIndicator {grid} />
|
|
134
|
+
{/if}
|
|
135
|
+
</section>
|
|
@@ -1,18 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import {btnTextDay, btnTextMonth, btnTextWeek, themeView} from '#lib';
|
|
2
|
+
import {dayTimeLimits, daySlots, nestedResources, monthView} from './stores.js';
|
|
3
|
+
import {createTRROptions, createTRRParsers} from '../time-grid/options.js';
|
|
4
|
+
import {createTRRStores} from '../time-grid/stores.js';
|
|
5
|
+
import {createRROptions} from '../resource-time-grid/options.js';
|
|
6
|
+
import {createRRStores} from '../resource-time-grid/stores.js';
|
|
4
7
|
import View from './View.svelte';
|
|
5
8
|
|
|
6
9
|
export default {
|
|
7
10
|
createOptions(options) {
|
|
11
|
+
createTRROptions(options);
|
|
12
|
+
createRROptions(options);
|
|
13
|
+
options.slotWidth = 16;
|
|
8
14
|
// Common options
|
|
9
15
|
options.buttonText.resourceTimelineDay = 'timeline';
|
|
10
16
|
options.buttonText.resourceTimelineWeek = 'timeline';
|
|
11
17
|
options.buttonText.resourceTimelineMonth = 'timeline';
|
|
12
18
|
options.theme.expander = 'ec-expander';
|
|
13
|
-
|
|
14
|
-
options.theme.
|
|
15
|
-
options.theme.container = 'ec-container';
|
|
19
|
+
options.theme.rowHead = 'ec-row-head';
|
|
20
|
+
options.theme.slots = 'ec-slots';
|
|
16
21
|
options.view = 'resourceTimelineWeek';
|
|
17
22
|
options.views.resourceTimelineDay = {
|
|
18
23
|
buttonText: btnTextDay,
|
|
@@ -20,8 +25,9 @@ export default {
|
|
|
20
25
|
displayEventEnd: false,
|
|
21
26
|
dayHeaderFormat: {weekday: 'long'},
|
|
22
27
|
duration: {days: 1},
|
|
23
|
-
|
|
24
|
-
|
|
28
|
+
slotLabelInterval: '01:00',
|
|
29
|
+
slotDuration: '00:15',
|
|
30
|
+
theme: themeView('ec-resource ec-timeline ec-day-view'),
|
|
25
31
|
titleFormat: {year: 'numeric', month: 'long', day: 'numeric'}
|
|
26
32
|
};
|
|
27
33
|
options.views.resourceTimelineWeek = {
|
|
@@ -29,8 +35,9 @@ export default {
|
|
|
29
35
|
component: View,
|
|
30
36
|
displayEventEnd: false,
|
|
31
37
|
duration: {weeks: 1},
|
|
32
|
-
|
|
33
|
-
|
|
38
|
+
slotLabelInterval: '01:00',
|
|
39
|
+
slotDuration: '00:15',
|
|
40
|
+
theme: themeView('ec-resource ec-timeline ec-week-view')
|
|
34
41
|
};
|
|
35
42
|
options.views.resourceTimelineMonth = {
|
|
36
43
|
buttonText: btnTextMonth,
|
|
@@ -42,25 +49,21 @@ export default {
|
|
|
42
49
|
},
|
|
43
50
|
duration: {months: 1},
|
|
44
51
|
slotDuration: {days: 1},
|
|
45
|
-
theme: themeView('ec-timeline ec-
|
|
52
|
+
theme: themeView('ec-resource ec-timeline ec-month-view'),
|
|
46
53
|
titleFormat: {year: 'numeric', month: 'long'}
|
|
47
54
|
};
|
|
48
55
|
},
|
|
49
56
|
|
|
57
|
+
createParsers(parsers) {
|
|
58
|
+
createTRRParsers(parsers);
|
|
59
|
+
},
|
|
60
|
+
|
|
50
61
|
createStores(state) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
state._bodyHeight = writable(0);
|
|
55
|
-
state._bodyWidth = writable(0);
|
|
56
|
-
state._bodyScrollLeft = writable(0);
|
|
57
|
-
state._headerEl = writable(undefined);
|
|
58
|
-
state._headerHeight = writable(0);
|
|
62
|
+
createTRRStores(state);
|
|
63
|
+
createRRStores(state);
|
|
59
64
|
state._dayTimeLimits = dayTimeLimits(state); // flexible time limits per day
|
|
60
|
-
|
|
61
|
-
|
|
65
|
+
state._daySlots = daySlots(state);
|
|
66
|
+
state._monthView = monthView(state);
|
|
62
67
|
state._nestedResources = nestedResources(state);
|
|
63
|
-
state._resHs = writable(new Map()); // resource row heights
|
|
64
|
-
state._sidebarEl = writable(undefined);
|
|
65
68
|
}
|
|
66
69
|
}
|
|
@@ -1,139 +1,136 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
addDay, addDuration, assign, bgEvent, cloneDate, createDuration, createEventChunk, datesEqual, eventIntersects, max,
|
|
3
|
+
min, outsideRange
|
|
4
|
+
} from '#lib';
|
|
2
5
|
|
|
3
|
-
export function
|
|
4
|
-
let
|
|
5
|
-
let
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
export function createGrid($_viewDates, $_viewResources, $_dayTimeLimits, $validRange, $highlightedDates) {
|
|
7
|
+
let grid = [];
|
|
8
|
+
let gridRow = 1
|
|
9
|
+
for (let resource of $_viewResources) {
|
|
10
|
+
let days = [];
|
|
11
|
+
let gridColumn = 1;
|
|
12
|
+
for (let date of $_viewDates) {
|
|
13
|
+
let slotTimeLimits = $_dayTimeLimits[date.getTime()];
|
|
14
|
+
days.push({
|
|
15
|
+
gridColumn,
|
|
16
|
+
gridRow,
|
|
17
|
+
resource,
|
|
18
|
+
start: addDuration(cloneDate(date), slotTimeLimits.min),
|
|
19
|
+
end: addDuration(cloneDate(date), slotTimeLimits.max),
|
|
20
|
+
dayStart: date,
|
|
21
|
+
dayEnd: addDay(cloneDate(date)),
|
|
22
|
+
disabled: outsideRange(date, $validRange),
|
|
23
|
+
highlight: $highlightedDates.some(d => datesEqual(d, date))
|
|
24
|
+
});
|
|
25
|
+
++ gridColumn;
|
|
26
|
+
}
|
|
27
|
+
grid.push(days);
|
|
28
|
+
++ gridRow;
|
|
29
|
+
}
|
|
30
|
+
return grid;
|
|
31
|
+
}
|
|
9
32
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
let slotTimeLimits = getSlotTimeLimits($_dayTimeLimits, $_viewDates[i]);
|
|
18
|
-
let dayStart = addDuration(cloneDate($_viewDates[i]), slotTimeLimits.min);
|
|
19
|
-
let dayEnd = addDuration(cloneDate($_viewDates[i]), slotTimeLimits.max);
|
|
20
|
-
if (!chunk.date) {
|
|
21
|
-
if (chunk.start < dayEnd && chunk.end > dayStart) {
|
|
22
|
-
// The first day is found
|
|
23
|
-
chunk.date = $_viewDates[i];
|
|
24
|
-
if (chunk.start < dayStart) {
|
|
25
|
-
// Adjust chunk start
|
|
26
|
-
chunk.start = dayStart;
|
|
27
|
-
}
|
|
28
|
-
// Calculate offset
|
|
29
|
-
chunk.offset = (chunk.start - dayStart) / 1000 / step;
|
|
30
|
-
// Calculate slots
|
|
31
|
-
if (chunk.end > dayEnd) {
|
|
32
|
-
slots += dayEnd - chunk.start;
|
|
33
|
-
} else {
|
|
34
|
-
slots += chunk.end - chunk.start || step * 1000;
|
|
35
|
-
break;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
} else {
|
|
39
|
-
if (chunk.end <= dayStart) {
|
|
40
|
-
// Adjust chunk end
|
|
41
|
-
chunk.end = prevDayEnd;
|
|
42
|
-
break;
|
|
43
|
-
}
|
|
44
|
-
// The chunk is long one
|
|
45
|
-
let key = $_viewDates[i].getTime();
|
|
46
|
-
if (longChunks[key]) {
|
|
47
|
-
longChunks[key].push(chunk);
|
|
48
|
-
} else {
|
|
49
|
-
longChunks[key] = [chunk];
|
|
50
|
-
}
|
|
51
|
-
// Calculate slots
|
|
52
|
-
if (chunk.end > dayEnd) {
|
|
53
|
-
slots += dayEnd - dayStart;
|
|
54
|
-
} else {
|
|
55
|
-
slots += chunk.end - dayStart;
|
|
56
|
-
break;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
prevDayEnd = dayEnd;
|
|
60
|
-
}
|
|
61
|
-
chunk.slots = slots / 1000 / step;
|
|
33
|
+
export function createEventChunks($_filteredEvents, grid) {
|
|
34
|
+
let chunks = [];
|
|
35
|
+
let bgChunks = [];
|
|
36
|
+
for (let event of $_filteredEvents) {
|
|
37
|
+
for (let days of grid) {
|
|
38
|
+
if (bgEvent(event.display)) {
|
|
39
|
+
bgChunks = bgChunks.concat(createChunks(event, days));
|
|
62
40
|
} else {
|
|
63
|
-
|
|
64
|
-
let days = 0;
|
|
65
|
-
for (let i = 0; i < $_viewDates.length; ++i) {
|
|
66
|
-
let dayStart = $_viewDates[i];
|
|
67
|
-
let dayEnd = addDay(cloneDate(dayStart));
|
|
68
|
-
if (!chunk.date) {
|
|
69
|
-
if (chunk.start < dayEnd) {
|
|
70
|
-
// The first day is found
|
|
71
|
-
chunk.date = dayStart;
|
|
72
|
-
if (chunk.start < dayStart) {
|
|
73
|
-
// Adjust chunk start
|
|
74
|
-
chunk.start = dayStart;
|
|
75
|
-
}
|
|
76
|
-
++days;
|
|
77
|
-
}
|
|
78
|
-
} else {
|
|
79
|
-
if (chunk.end <= dayStart) {
|
|
80
|
-
// Adjust chunk end
|
|
81
|
-
chunk.end = prevDayEnd;
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
// The chunk is long one
|
|
85
|
-
let key = dayStart.getTime();
|
|
86
|
-
if (longChunks[key]) {
|
|
87
|
-
longChunks[key].push(chunk);
|
|
88
|
-
} else {
|
|
89
|
-
longChunks[key] = [chunk];
|
|
90
|
-
}
|
|
91
|
-
++days;
|
|
92
|
-
}
|
|
93
|
-
prevDayEnd = dayEnd;
|
|
94
|
-
}
|
|
95
|
-
chunk.days = days;
|
|
41
|
+
chunks = chunks.concat(createChunks(event, days));
|
|
96
42
|
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
prepareChunks(chunks);
|
|
97
46
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
47
|
+
return {chunks, bgChunks};
|
|
48
|
+
}
|
|
102
49
|
|
|
103
|
-
|
|
104
|
-
|
|
50
|
+
export function createIEventChunks($_iEvents, grid) {
|
|
51
|
+
let iChunks = [];
|
|
52
|
+
for (let event of $_iEvents) {
|
|
53
|
+
if (!event) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
for (let days of grid) {
|
|
57
|
+
iChunks = iChunks.concat(createChunks(event, days));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return iChunks;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function createChunks(event, days) {
|
|
65
|
+
let dates = [];
|
|
66
|
+
let firstStart;
|
|
67
|
+
let lastEnd;
|
|
68
|
+
let gridColumn;
|
|
69
|
+
let gridRow;
|
|
70
|
+
let left;
|
|
71
|
+
let width = 0;
|
|
72
|
+
for (let {gridColumn: column, gridRow: row, resource, dayStart, start, end, disabled} of days) {
|
|
73
|
+
if (!disabled && eventIntersects(event, start, end, resource)) {
|
|
74
|
+
if (!dates.length) {
|
|
75
|
+
firstStart = start;
|
|
76
|
+
gridColumn = column;
|
|
77
|
+
gridRow = row;
|
|
78
|
+
left = max(event.start - start, 0) / 1000;
|
|
105
79
|
}
|
|
106
|
-
|
|
107
|
-
|
|
80
|
+
dates.push(dayStart);
|
|
81
|
+
lastEnd = end;
|
|
82
|
+
width += (min(end, event.end) - max(start, event.start)) / 1000;
|
|
108
83
|
}
|
|
109
84
|
}
|
|
85
|
+
if (dates.length) {
|
|
86
|
+
let chunk = createEventChunk(event, firstStart, lastEnd);
|
|
87
|
+
// Chunk layout
|
|
88
|
+
assign(chunk, {gridColumn, gridRow, dates, left, width});
|
|
110
89
|
|
|
111
|
-
|
|
90
|
+
return [chunk];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function prepareChunks(chunks) {
|
|
97
|
+
let dayChunks = {};
|
|
98
|
+
for (let chunk of chunks) {
|
|
99
|
+
let {gridColumn, gridRow} = chunk;
|
|
100
|
+
// Prepare day chunks
|
|
101
|
+
for (let i = 0; i < chunk.dates.length; ++ i) {
|
|
102
|
+
let key = `${gridRow}_${gridColumn + i}`;
|
|
103
|
+
if (dayChunks[key]) {
|
|
104
|
+
dayChunks[key].push(chunk);
|
|
105
|
+
} else {
|
|
106
|
+
dayChunks[key] = [chunk];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
let key = `${gridRow}_${gridColumn}`;
|
|
110
|
+
chunk.day = dayChunks[key];
|
|
111
|
+
}
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
export function repositionEvent(chunk,
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
let
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
chunks.sort((a, b) => (a.top ?? 0) - (b.top ?? 0) || a.start - b.start || b.event.allDay - a.event.allDay);
|
|
122
|
-
for (let dayChunk of chunks) {
|
|
123
|
-
if (dayChunk === chunk) {
|
|
114
|
+
export function repositionEvent(chunk, height, monthView) {
|
|
115
|
+
let top = 1;
|
|
116
|
+
let bottom = top + height;
|
|
117
|
+
let dayChunks = chunk.day;
|
|
118
|
+
dayChunks.sort((a, b) => (a.top ?? Number.POSITIVE_INFINITY) - (b.top ?? Number.POSITIVE_INFINITY));
|
|
119
|
+
for (let dayChunk of dayChunks) {
|
|
120
|
+
if (dayChunk === chunk || !('top' in dayChunk)) {
|
|
124
121
|
continue;
|
|
125
122
|
}
|
|
126
|
-
if ((
|
|
127
|
-
let offset = dayChunk.bottom -
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
chunk.bottom += offset;
|
|
123
|
+
if ((monthView || chunk.start < dayChunk.end && chunk.end > dayChunk.start) && top < dayChunk.bottom && bottom > dayChunk.top) {
|
|
124
|
+
let offset = dayChunk.bottom - top + 1;
|
|
125
|
+
top += offset;
|
|
126
|
+
bottom += offset;
|
|
131
127
|
}
|
|
132
128
|
}
|
|
129
|
+
assign(chunk, {top, bottom});
|
|
133
130
|
|
|
134
|
-
return
|
|
131
|
+
return top;
|
|
135
132
|
}
|
|
136
133
|
|
|
137
134
|
export function getSlotTimeLimits($_dayTimeLimits, date) {
|
|
138
|
-
return $_dayTimeLimits[date.getTime()] ?? {min: createDuration(0), max: createDuration(
|
|
135
|
+
return $_dayTimeLimits[date.getTime()] ?? {min: createDuration(0), max: createDuration('24:00:00')};
|
|
139
136
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {derived} from 'svelte/store';
|
|
2
|
-
import {createSlotTimeLimits,
|
|
2
|
+
import {createSlotTimeLimits, createSlots, getPayload, toSeconds} from '#lib';
|
|
3
3
|
|
|
4
4
|
// slotTimeLimits per day
|
|
5
5
|
export function dayTimeLimits(state) {
|
|
@@ -22,15 +22,15 @@ export function dayTimeLimits(state) {
|
|
|
22
22
|
);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export function
|
|
25
|
+
export function daySlots(state) {
|
|
26
26
|
return derived(
|
|
27
|
-
[state._viewDates, state.slotDuration, state.
|
|
28
|
-
([$_viewDates, $slotDuration, $
|
|
27
|
+
[state._viewDates, state.slotDuration, state._slotLabelPeriodicity, state._dayTimeLimits, state._intlSlotLabel],
|
|
28
|
+
([$_viewDates, $slotDuration, $_slotLabelPeriodicity, $_dayTimeLimits, $_intlSlotLabel]) => {
|
|
29
29
|
let dayTimes = {};
|
|
30
30
|
for (let date of $_viewDates) {
|
|
31
|
-
let
|
|
32
|
-
dayTimes[
|
|
33
|
-
?
|
|
31
|
+
let key = date.getTime();
|
|
32
|
+
dayTimes[key] = key in $_dayTimeLimits
|
|
33
|
+
? createSlots(date, $slotDuration, $_slotLabelPeriodicity, $_dayTimeLimits[key], $_intlSlotLabel)
|
|
34
34
|
: [];
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -42,3 +42,7 @@ export function dayTimes(state) {
|
|
|
42
42
|
export function nestedResources(state) {
|
|
43
43
|
return derived(state.resources, $resources => $resources.some(resource => getPayload(resource).children.length));
|
|
44
44
|
}
|
|
45
|
+
|
|
46
|
+
export function monthView(state) {
|
|
47
|
+
return derived(state.slotDuration, $slotDuration => !toSeconds($slotDuration));
|
|
48
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import {height, repositionEvent} from '#lib';
|
|
3
|
+
import {InteractableEvent} from '#components';
|
|
4
|
+
|
|
5
|
+
let {chunk} = $props();
|
|
6
|
+
|
|
7
|
+
let el = $state();
|
|
8
|
+
let margin = $state(0);
|
|
9
|
+
let event = $derived(chunk.event);
|
|
10
|
+
|
|
11
|
+
// Style
|
|
12
|
+
let styles = $derived(style => {
|
|
13
|
+
style['grid-column'] = `${chunk.gridColumn} / span ${chunk.dates.length}`;
|
|
14
|
+
if (margin || event._margin) {
|
|
15
|
+
style['margin-block-start'] = `${event._margin ?? margin}px`;
|
|
16
|
+
}
|
|
17
|
+
return style;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export function reposition() {
|
|
21
|
+
margin = repositionEvent(chunk, height(el));
|
|
22
|
+
}
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<InteractableEvent
|
|
26
|
+
bind:el
|
|
27
|
+
{chunk}
|
|
28
|
+
{styles}
|
|
29
|
+
axis="x"
|
|
30
|
+
forceMargin={margin}
|
|
31
|
+
/>
|