gantt-source_management 3.37.5

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 (166) hide show
  1. package/.editorconfig +9 -0
  2. package/.eslintrc.json +39 -0
  3. package/.prettierrc.cjs +5 -0
  4. package/README.md +129 -0
  5. package/cypress/e2e/add-rows-items.test.ts +26 -0
  6. package/cypress/e2e/basic.test.ts +173 -0
  7. package/cypress/e2e/calculated-zoom-mode.test.ts +163 -0
  8. package/cypress/e2e/calendar-dates.test.ts +285 -0
  9. package/cypress/e2e/dst.test.ts +691 -0
  10. package/cypress/e2e/grid-cells.test.ts +72 -0
  11. package/cypress/e2e/items-vertical.test.ts +305 -0
  12. package/cypress/e2e/items.test.ts +501 -0
  13. package/cypress/e2e/list-columns-toggle.test.ts +124 -0
  14. package/cypress/e2e/list-header-resize.test.ts +30 -0
  15. package/cypress/e2e/locale.test.ts +102 -0
  16. package/cypress/e2e/move-items-outside.test.ts +437 -0
  17. package/cypress/e2e/rows.test.ts +50 -0
  18. package/cypress/e2e/scroll-bar.test.ts +357 -0
  19. package/cypress/e2e/time-bookmarks.test.ts +92 -0
  20. package/cypress/e2e/utc-mode.test.ts +51 -0
  21. package/cypress/fixtures/example.json +5 -0
  22. package/cypress/helpers.ts +12 -0
  23. package/cypress/plugins/index.js +22 -0
  24. package/cypress/support/commands.ts +175 -0
  25. package/cypress/support/e2e.ts +31 -0
  26. package/cypress.config.js +24 -0
  27. package/dist/api/api.d.ts +182 -0
  28. package/dist/api/helpers.d.ts +9 -0
  29. package/dist/api/id.d.ts +14 -0
  30. package/dist/api/locale.d.ts +3 -0
  31. package/dist/api/main.d.ts +47 -0
  32. package/dist/api/public.d.ts +32 -0
  33. package/dist/api/slots.d.ts +22 -0
  34. package/dist/api/time.d.ts +104 -0
  35. package/dist/assets/2f1f893a.wasm +0 -0
  36. package/dist/gstc.d.ts +708 -0
  37. package/dist/gstc.esm.min.d.ts +708 -0
  38. package/dist/gstc.esm.min.js +574 -0
  39. package/dist/gstc.umd.min.d.ts +708 -0
  40. package/dist/gstc.umd.min.js +701 -0
  41. package/dist/gstc.wasm.esm.min.d.ts +708 -0
  42. package/dist/gstc.wasm.esm.min.js +574 -0
  43. package/dist/gstc.wasm.umd.min.d.ts +708 -0
  44. package/dist/gstc.wasm.umd.min.js +701 -0
  45. package/dist/plugins/calendar-scroll.d.ts +15 -0
  46. package/dist/plugins/calendar-scroll.esm.min.d.ts +15 -0
  47. package/dist/plugins/calendar-scroll.esm.min.js +13 -0
  48. package/dist/plugins/calendar-scroll.umd.min.d.ts +15 -0
  49. package/dist/plugins/calendar-scroll.umd.min.js +13 -0
  50. package/dist/plugins/dependency-lines.d.ts +47 -0
  51. package/dist/plugins/dependency-lines.esm.min.d.ts +47 -0
  52. package/dist/plugins/dependency-lines.esm.min.js +38 -0
  53. package/dist/plugins/dependency-lines.umd.min.d.ts +47 -0
  54. package/dist/plugins/dependency-lines.umd.min.js +38 -0
  55. package/dist/plugins/export-image.d.ts +12 -0
  56. package/dist/plugins/export-image.esm.min.d.ts +12 -0
  57. package/dist/plugins/export-image.esm.min.js +28 -0
  58. package/dist/plugins/export-image.umd.min.d.ts +12 -0
  59. package/dist/plugins/export-image.umd.min.js +34 -0
  60. package/dist/plugins/export-pdf.d.ts +12 -0
  61. package/dist/plugins/export-pdf.esm.min.d.ts +12 -0
  62. package/dist/plugins/export-pdf.esm.min.js +389 -0
  63. package/dist/plugins/export-pdf.umd.min.d.ts +12 -0
  64. package/dist/plugins/export-pdf.umd.min.js +511 -0
  65. package/dist/plugins/grab-scroll.d.ts +14 -0
  66. package/dist/plugins/grab-scroll.esm.min.d.ts +14 -0
  67. package/dist/plugins/grab-scroll.umd.min.d.ts +14 -0
  68. package/dist/plugins/highlight-weekends.d.ts +12 -0
  69. package/dist/plugins/highlight-weekends.esm.min.d.ts +12 -0
  70. package/dist/plugins/highlight-weekends.esm.min.js +14 -0
  71. package/dist/plugins/highlight-weekends.umd.min.d.ts +12 -0
  72. package/dist/plugins/highlight-weekends.umd.min.js +14 -0
  73. package/dist/plugins/item-movement.d.ts +97 -0
  74. package/dist/plugins/item-movement.esm.min.d.ts +97 -0
  75. package/dist/plugins/item-movement.esm.min.js +25 -0
  76. package/dist/plugins/item-movement.umd.min.d.ts +97 -0
  77. package/dist/plugins/item-movement.umd.min.js +25 -0
  78. package/dist/plugins/item-resizing.d.ts +102 -0
  79. package/dist/plugins/item-resizing.esm.min.d.ts +102 -0
  80. package/dist/plugins/item-resizing.esm.min.js +37 -0
  81. package/dist/plugins/item-resizing.umd.min.d.ts +102 -0
  82. package/dist/plugins/item-resizing.umd.min.js +37 -0
  83. package/dist/plugins/item-types.d.ts +13 -0
  84. package/dist/plugins/item-types.esm.min.d.ts +13 -0
  85. package/dist/plugins/item-types.esm.min.js +127 -0
  86. package/dist/plugins/item-types.umd.min.d.ts +13 -0
  87. package/dist/plugins/item-types.umd.min.js +127 -0
  88. package/dist/plugins/progress-bar.d.ts +13 -0
  89. package/dist/plugins/progress-bar.esm.min.d.ts +13 -0
  90. package/dist/plugins/progress-bar.esm.min.js +27 -0
  91. package/dist/plugins/progress-bar.umd.min.d.ts +13 -0
  92. package/dist/plugins/progress-bar.umd.min.js +27 -0
  93. package/dist/plugins/selection.d.ts +94 -0
  94. package/dist/plugins/selection.esm.min.d.ts +94 -0
  95. package/dist/plugins/selection.esm.min.js +26 -0
  96. package/dist/plugins/selection.umd.min.d.ts +94 -0
  97. package/dist/plugins/selection.umd.min.js +26 -0
  98. package/dist/plugins/time-bookmarks.d.ts +38 -0
  99. package/dist/plugins/time-bookmarks.esm.min.d.ts +38 -0
  100. package/dist/plugins/time-bookmarks.esm.min.js +50 -0
  101. package/dist/plugins/time-bookmarks.umd.min.d.ts +38 -0
  102. package/dist/plugins/time-bookmarks.umd.min.js +50 -0
  103. package/dist/plugins/timeline-pointer.d.ts +83 -0
  104. package/dist/plugins/timeline-pointer.esm.min.d.ts +83 -0
  105. package/dist/plugins/timeline-pointer.esm.min.js +13 -0
  106. package/dist/plugins/timeline-pointer.umd.min.d.ts +83 -0
  107. package/dist/plugins/timeline-pointer.umd.min.js +13 -0
  108. package/dist/style.css +811 -0
  109. package/dist/vendor.esm.min.js +128 -0
  110. package/examples/complex-1/faces/face-1.jpg +0 -0
  111. package/examples/complex-1/faces/face-10.jpg +0 -0
  112. package/examples/complex-1/faces/face-11.jpg +0 -0
  113. package/examples/complex-1/faces/face-12.jpg +0 -0
  114. package/examples/complex-1/faces/face-13.jpg +0 -0
  115. package/examples/complex-1/faces/face-14.jpg +0 -0
  116. package/examples/complex-1/faces/face-15.jpg +0 -0
  117. package/examples/complex-1/faces/face-16.jpg +0 -0
  118. package/examples/complex-1/faces/face-17.jpg +0 -0
  119. package/examples/complex-1/faces/face-18.jpg +0 -0
  120. package/examples/complex-1/faces/face-19.jpg +0 -0
  121. package/examples/complex-1/faces/face-2.jpg +0 -0
  122. package/examples/complex-1/faces/face-20.jpg +0 -0
  123. package/examples/complex-1/faces/face-21.jpg +0 -0
  124. package/examples/complex-1/faces/face-22.jpg +0 -0
  125. package/examples/complex-1/faces/face-23.jpg +0 -0
  126. package/examples/complex-1/faces/face-24.jpg +0 -0
  127. package/examples/complex-1/faces/face-25.jpg +0 -0
  128. package/examples/complex-1/faces/face-26.jpg +0 -0
  129. package/examples/complex-1/faces/face-27.jpg +0 -0
  130. package/examples/complex-1/faces/face-28.jpg +0 -0
  131. package/examples/complex-1/faces/face-29.jpg +0 -0
  132. package/examples/complex-1/faces/face-3.jpg +0 -0
  133. package/examples/complex-1/faces/face-30.jpg +0 -0
  134. package/examples/complex-1/faces/face-31.jpg +0 -0
  135. package/examples/complex-1/faces/face-32.jpg +0 -0
  136. package/examples/complex-1/faces/face-33.jpg +0 -0
  137. package/examples/complex-1/faces/face-34.jpg +0 -0
  138. package/examples/complex-1/faces/face-35.jpg +0 -0
  139. package/examples/complex-1/faces/face-36.jpg +0 -0
  140. package/examples/complex-1/faces/face-37.jpg +0 -0
  141. package/examples/complex-1/faces/face-38.jpg +0 -0
  142. package/examples/complex-1/faces/face-39.jpg +0 -0
  143. package/examples/complex-1/faces/face-4.jpg +0 -0
  144. package/examples/complex-1/faces/face-40.jpg +0 -0
  145. package/examples/complex-1/faces/face-41.jpg +0 -0
  146. package/examples/complex-1/faces/face-42.jpg +0 -0
  147. package/examples/complex-1/faces/face-43.jpg +0 -0
  148. package/examples/complex-1/faces/face-44.jpg +0 -0
  149. package/examples/complex-1/faces/face-45.jpg +0 -0
  150. package/examples/complex-1/faces/face-46.jpg +0 -0
  151. package/examples/complex-1/faces/face-47.jpg +0 -0
  152. package/examples/complex-1/faces/face-48.jpg +0 -0
  153. package/examples/complex-1/faces/face-49.jpg +0 -0
  154. package/examples/complex-1/faces/face-5.jpg +0 -0
  155. package/examples/complex-1/faces/face-50.jpg +0 -0
  156. package/examples/complex-1/faces/face-6.jpg +0 -0
  157. package/examples/complex-1/faces/face-7.jpg +0 -0
  158. package/examples/complex-1/faces/face-8.jpg +0 -0
  159. package/examples/complex-1/faces/face-9.jpg +0 -0
  160. package/examples/complex-1/index.html +61 -0
  161. package/examples/complex-1/index.js +923 -0
  162. package/examples/index.html +22 -0
  163. package/examples/reset.css +455 -0
  164. package/examples/server.js +18 -0
  165. package/package.json +150 -0
  166. package/tsconfig.json +17 -0
@@ -0,0 +1,923 @@
1
+ import GSTC from '../../dist/gstc.wasm.esm.min.js';
2
+ import { Plugin as TimelinePointer } from '../../dist/plugins/timeline-pointer.esm.min.js';
3
+ import { Plugin as Selection } from '../../dist/plugins/selection.esm.min.js';
4
+ import { Plugin as ItemMovement } from '../../dist/plugins/item-movement.esm.min.js';
5
+ import { Plugin as ItemResizing } from '../../dist/plugins/item-resizing.esm.min.js';
6
+ import { Plugin as CalendarScroll } from '../../dist/plugins/calendar-scroll.esm.min.js';
7
+ import { Plugin as HighlightWeekends } from '../../dist/plugins/highlight-weekends.esm.min.js';
8
+ import { Plugin as ProgressBar } from '../../dist/plugins/progress-bar.esm.min.js';
9
+ import { Plugin as TimeBookmarks } from '../../dist/plugins/time-bookmarks.esm.min.js';
10
+ import { Plugin as DependencyLines } from '../../dist/plugins/dependency-lines.esm.min.js';
11
+ import { Plugin as ExportImage } from '../../dist/plugins/export-image.esm.min.js';
12
+ import { Plugin as ExportPDF } from '../../dist/plugins/export-pdf.esm.min.js';
13
+
14
+ globalThis.GSTC = GSTC;
15
+
16
+ const iterations = 100;
17
+ const GSTCID = GSTC.api.GSTCID;
18
+ const addDays = 30;
19
+
20
+ function getRandomFaceImage() {
21
+ return `./faces/face-${Math.ceil(Math.random() * 50)}.jpg`;
22
+ }
23
+
24
+ const colors = ['#E74C3C', '#DA3C78', '#7E349D', '#0077C0', '#07ABA0', '#0EAC51', '#F1892D'];
25
+ function getRandomColor() {
26
+ return colors[Math.floor(Math.random() * colors.length)];
27
+ }
28
+
29
+ const startDate = GSTC.api.date('2020-02-01');
30
+ const startTime = startDate.valueOf();
31
+ const endDate = GSTC.api.date('2020-03-31').endOf('day');
32
+
33
+ function getInitialRows() {
34
+ /**
35
+ * @type {import("../../dist/gstc").Rows}
36
+ */
37
+ const rows = {};
38
+ for (let i = 0; i < iterations; i++) {
39
+ const withParent = i > 0 && i % 2 === 0;
40
+ const id = GSTCID(String(i));
41
+ rows[id] = {
42
+ id,
43
+ label: `John Doe ${i}`,
44
+ parentId: withParent ? GSTCID(String(i - 1)) : undefined,
45
+ expanded: false,
46
+ vacations: [],
47
+ img: getRandomFaceImage(),
48
+ progress: Math.floor(Math.random() * 100),
49
+ visible: true,
50
+ };
51
+ }
52
+
53
+ rows[GSTCID('11')].label = 'NESTED TREE HERE';
54
+ rows[GSTCID('12')].parentId = GSTCID('11');
55
+ rows[GSTCID('13')].parentId = GSTCID('12');
56
+ rows[GSTCID('14')].parentId = GSTCID('13');
57
+ rows[GSTCID('3')].vacations = [
58
+ { from: startDate.add(5, 'days').startOf('day').valueOf(), to: startDate.add(5, 'days').endOf('day').valueOf() },
59
+ { from: startDate.add(6, 'days').startOf('day').valueOf(), to: startDate.add(6, 'days').endOf('day').valueOf() },
60
+ ];
61
+ rows[GSTCID('7')].birthday = [
62
+ {
63
+ from: startDate.add(3, 'day').startOf('day').valueOf(),
64
+ to: startDate.add(3, 'day').endOf('day').valueOf(),
65
+ },
66
+ ];
67
+ return rows;
68
+ }
69
+
70
+ function generateItemsForDaysView() {
71
+ /**
72
+ * @type {import("../../dist/gstc").Items}
73
+ */
74
+ const items = {};
75
+ for (let i = 0; i < iterations; i++) {
76
+ let rowId = GSTCID(i.toString());
77
+ let id = GSTCID(i.toString());
78
+ let startDayjs = GSTC.api
79
+ .date(startTime)
80
+ .startOf('day')
81
+ .add(Math.floor(Math.random() * addDays), 'day');
82
+ let end = startDayjs
83
+ .clone()
84
+ .add(Math.floor(Math.random() * 20) + 4, 'day')
85
+ .endOf('day')
86
+ .valueOf();
87
+ if (end > endDate.valueOf()) end = endDate.valueOf();
88
+ items[id] = {
89
+ id,
90
+ label: `John Doe ${i}`,
91
+ progress: Math.round(Math.random() * 100),
92
+ style: { background: getRandomColor() },
93
+ time: {
94
+ start: startDayjs.startOf('day').valueOf(),
95
+ end,
96
+ },
97
+ rowId,
98
+ img: getRandomFaceImage(),
99
+ classNames: ['additional-custom-class'],
100
+ description: 'Lorem ipsum dolor sit amet',
101
+ };
102
+ }
103
+
104
+ items[GSTCID('0')].linkedWith = [GSTCID('1')];
105
+ items[GSTCID('0')].label = 'Task 0 linked with 1';
106
+ items[GSTCID('0')].type = 'task';
107
+ items[GSTCID('1')].label = 'Task 1 linked with 0';
108
+ items[GSTCID('1')].type = 'task';
109
+ items[GSTCID('1')].time = { ...items[GSTCID('0')].time };
110
+
111
+ items[GSTCID('0')].style = { background: colors[3] };
112
+ items[GSTCID('1')].style = { background: colors[3] };
113
+
114
+ items[GSTCID('3')].dependant = [GSTCID('5')];
115
+ items[GSTCID('3')].label = 'Grab and move me into vacation area';
116
+ items[GSTCID('3')].time.start = GSTC.api.date(startTime).add(4, 'day').startOf('day').add(5, 'day').valueOf();
117
+ items[GSTCID('3')].time.end = GSTC.api.date(items[GSTCID('3')].time.start).endOf('day').add(5, 'day').valueOf();
118
+
119
+ items[GSTCID('5')].time.start = GSTC.api.date(items[GSTCID('3')].time.end).startOf('day').add(5, 'day').valueOf();
120
+ items[GSTCID('5')].time.end = GSTC.api.date(items[GSTCID('5')].time.start).endOf('day').add(2, 'day').valueOf();
121
+ items[GSTCID('5')].dependant = [GSTCID('7'), GSTCID('9')];
122
+
123
+ items[GSTCID('7')].time.start = GSTC.api.date(items[GSTCID('5')].time.end).startOf('day').add(3, 'day').valueOf();
124
+ items[GSTCID('7')].time.end = GSTC.api.date(items[GSTCID('7')].time.start).endOf('day').add(2, 'day').valueOf();
125
+ items[GSTCID('9')].time.start = GSTC.api.date(items[GSTCID('5')].time.end).startOf('day').add(2, 'day').valueOf();
126
+ items[GSTCID('9')].time.end = GSTC.api.date(items[GSTCID('9')].time.start).endOf('day').add(3, 'day').valueOf();
127
+ return items;
128
+ }
129
+
130
+ const columns = {
131
+ data: {
132
+ [GSTCID('id')]: {
133
+ id: GSTCID('id'),
134
+ data: ({ row }) => GSTC.api.sourceID(row.id),
135
+ width: 80,
136
+ sortable: ({ row }) => Number(GSTC.api.sourceID(row.id)),
137
+ header: {
138
+ content: 'ID',
139
+ },
140
+ },
141
+ [GSTCID('label')]: {
142
+ id: GSTCID('label'),
143
+ data: 'label',
144
+ sortable: 'label',
145
+ expander: true,
146
+ isHTML: false,
147
+ width: 315,
148
+ header: {
149
+ content: 'Label',
150
+ },
151
+ },
152
+ [GSTCID('progress')]: {
153
+ id: GSTCID('progress'),
154
+ data({ row, vido }) {
155
+ return vido.html`<div style="text-align:center">${row.progress}</div>`;
156
+ },
157
+ width: 100,
158
+ sortable: 'progress',
159
+ header: {
160
+ content: 'Progress',
161
+ },
162
+ },
163
+ },
164
+ };
165
+
166
+ /**
167
+ * @type {import("../../dist/plugins/time-bookmarks").Bookmarks}
168
+ */
169
+ const bookmarks = {};
170
+ for (let i = 0; i < 3; i++) {
171
+ const id = `Bookmark ${i}`;
172
+ bookmarks[id] = {
173
+ time: startDate
174
+ .add(Math.round(Math.random() * addDays), 'day')
175
+ .startOf('day')
176
+ .valueOf(),
177
+ label: id,
178
+ style: {
179
+ background: getRandomColor(),
180
+ },
181
+ };
182
+ }
183
+
184
+ function itemSlot(vido, props) {
185
+ const { html, onChange, update } = vido;
186
+
187
+ let imageSrc = '';
188
+ let description = '';
189
+ onChange((newProps) => {
190
+ props = newProps;
191
+ if (!props || !props.item) return;
192
+ imageSrc = props.item.img;
193
+ description = props.item.description;
194
+ update();
195
+ });
196
+
197
+ return (content) =>
198
+ html`<div
199
+ class="item-image"
200
+ style="background:url(${imageSrc}),transparent;flex-shrink:0;border-radius:100%;width:34px;height:34px;vertical-align: middle;background-size: 100%;margin: 4px 11px 0px 0px;"
201
+ ></div>
202
+ <div class="item-text">
203
+ <div class="item-label">${content}</div>
204
+ <div class="item-description" style="font-size:11px;margin-top:2px;color:#fffffff0;line-height:1em;">
205
+ ${description}
206
+ </div>
207
+ </div>`;
208
+ }
209
+
210
+ function rowSlot(vido, props) {
211
+ const { html, onChange, update, api } = vido;
212
+
213
+ let img = '';
214
+ onChange((newProps) => {
215
+ props = newProps;
216
+ if (!props || !props.row) return;
217
+ img = props.row.img;
218
+ update();
219
+ });
220
+
221
+ return (content) => {
222
+ if (!props || !props.column) return content;
223
+ return api.sourceID(props.column.id) === 'label'
224
+ ? html`<div class="row-content-wrapper" style="display:flex">
225
+ <div class="row-content" style="flex-grow:1;">${content}</div>
226
+ <div
227
+ class="row-image"
228
+ style="background:url(${img}),transparent;border-radius:100%;width:34px;height:34px;vertical-align: middle;background-size: 100%;margin: auto 10px;flex-shrink:0;"
229
+ ></div>
230
+ </div>`
231
+ : content;
232
+ };
233
+ }
234
+
235
+ let snapTime = true;
236
+ function snapStart({ startTime, vido }) {
237
+ if (!snapTime) return startTime;
238
+ const date = vido.api.time.findOrCreateMainDateAtTime(startTime.valueOf());
239
+ return date.leftGlobalDate;
240
+ }
241
+ function snapEnd({ endTime, vido }) {
242
+ if (!snapTime) return endTime;
243
+ const date = vido.api.time.findOrCreateMainDateAtTime(endTime.valueOf());
244
+ return date.rightGlobalDate;
245
+ }
246
+
247
+ function canMove(item) {
248
+ const row = gstc.api.getRow(item.rowId);
249
+ if (row.vacations) {
250
+ for (const vacation of row.vacations) {
251
+ const vacationStart = vacation.from;
252
+ const vacationEnd = vacation.to;
253
+ // item start time inside vacation
254
+ if (item.time.start >= vacationStart && item.time.start <= vacationEnd) {
255
+ return false;
256
+ }
257
+ // item end time inside vacation
258
+ if (item.time.end >= vacationStart && item.time.end <= vacationEnd) {
259
+ return false;
260
+ }
261
+ // vacation is between item start and end
262
+ if (item.time.start <= vacationStart && item.time.end >= vacationEnd) {
263
+ return false;
264
+ }
265
+ // item start and end time is inside vacation
266
+ if (item.time.start >= vacationStart && item.time.end <= vacationEnd) {
267
+ return false;
268
+ }
269
+ }
270
+ }
271
+ return true;
272
+ }
273
+
274
+ /**
275
+ * @type {import('../../dist/plugins/item-movement').Options}
276
+ */
277
+ const itemMovementOptions = {
278
+ threshold: {
279
+ horizontal: 25,
280
+ vertical: 25,
281
+ },
282
+ snapToTime: {
283
+ start: snapStart,
284
+ end({ endTime }) {
285
+ return endTime;
286
+ },
287
+ },
288
+ events: {
289
+ onMove({ items }) {
290
+ for (let i = 0, len = items.after.length; i < len; i++) {
291
+ const item = items.after[i];
292
+ if (!canMove(item)) return items.before;
293
+ }
294
+ return items.after;
295
+ },
296
+ },
297
+ };
298
+
299
+ /**
300
+ * @type {import('../../dist/plugins/item-resizing').Options}
301
+ */
302
+ const itemResizeOptions = {
303
+ threshold: 25,
304
+ snapToTime: {
305
+ start: snapStart,
306
+ end: snapEnd,
307
+ },
308
+ events: {
309
+ onResize({ items }) {
310
+ for (const item of items.after) {
311
+ if (!canMove(item)) return items.before;
312
+ }
313
+ return items.after;
314
+ },
315
+ },
316
+ };
317
+
318
+ let hideWeekends = false;
319
+ function onLevelDates({ dates, level, format, time }) {
320
+ if (time.period !== 'day') return dates;
321
+ if (format.period !== time.period) return dates;
322
+ if (!hideWeekends) return dates;
323
+ return dates.filter((date) => date.leftGlobalDate.day() !== 0 && date.leftGlobalDate.day() !== 6);
324
+ }
325
+
326
+ function onItemClick(ev) {
327
+ const itemElement = ev.target.closest('.gstc__chart-timeline-items-row-item');
328
+ const itemId = itemElement.dataset.gstcid;
329
+ const item = gstc.api.getItem(itemId);
330
+ console.log('Item click from template', item);
331
+ }
332
+
333
+ // Typescript usage:
334
+ // import { Template } from 'gantt-schedule-timeline-calendar';
335
+ // const chartTimelineItemsRowItemTemplate: Template = function chartTimelineItemsRowItemTemplate(...);
336
+ /**
337
+ * @type {import("../../dist/gstc").Template} // or {import("gantt-schedule-timeline-calendar").Template}
338
+ */
339
+ function chartTimelineItemsRowItemTemplate({
340
+ className,
341
+ labelClassName,
342
+ styleMap,
343
+ cache,
344
+ shouldDetach,
345
+ cutterLeft,
346
+ cutterRight,
347
+ getContent,
348
+ actions,
349
+ slots,
350
+ html,
351
+ vido,
352
+ props,
353
+ }) {
354
+ const detach = shouldDetach || !props || !props.item;
355
+ return cache(
356
+ detach
357
+ ? null
358
+ : slots.html(
359
+ 'outer',
360
+ html`
361
+ <div
362
+ class=${className}
363
+ data-gstcid=${props.item.id}
364
+ data-actions=${actions()}
365
+ style=${styleMap.directive()}
366
+ @click=${onItemClick}
367
+ >
368
+ ${slots.html(
369
+ 'inner',
370
+ html`
371
+ ${cutterLeft()}
372
+ <div class=${labelClassName}>${slots.html('content', getContent())}</div>
373
+ ${cutterRight()}
374
+ `
375
+ )}
376
+ </div>
377
+ `
378
+ )
379
+ );
380
+ }
381
+
382
+ function myItemSlot(vido, props) {
383
+ const { onChange } = vido;
384
+
385
+ function onClick() {
386
+ console.log('Item click from slot', props.item);
387
+ }
388
+
389
+ onChange((changedProps) => {
390
+ // if current element is reused to display other item data just update your data so when you click you will display right alert
391
+ props = changedProps;
392
+ });
393
+
394
+ // return render function
395
+ return (content) =>
396
+ vido.html`<div class="my-item-wrapper" @click=${onClick} style="width:100%;display:flex;overflow:hidden;pointer-events:none;">${content}</div>`;
397
+ }
398
+
399
+ function onCellCreateVacation({ time, row, vido, content }) {
400
+ if (!row.vacations) return content;
401
+ let isVacation = false;
402
+ for (const vacation of row.vacations) {
403
+ if (time.leftGlobal >= vacation.from && time.rightGlobal <= vacation.to) {
404
+ isVacation = true;
405
+ break;
406
+ }
407
+ }
408
+ if (isVacation) {
409
+ return vido.html`<div title="🏖️ VACATION" style="height:100%;width:100%;background:#A0A0A010;"></div>${content}`;
410
+ }
411
+ return content;
412
+ }
413
+
414
+ function myVacationRowSlot(vido, props) {
415
+ const { onChange, html, update, api, state } = vido;
416
+
417
+ let vacationContent = [];
418
+ onChange((changedProps) => {
419
+ props = changedProps;
420
+ if (!props || !props.row || !props.row.vacations) {
421
+ vacationContent = [];
422
+ return update();
423
+ }
424
+ const configTime = state.get('config.chart.time');
425
+ vacationContent = [];
426
+ for (const vacation of props.row.vacations) {
427
+ if (vacation.to < configTime.leftGlobal || vacation.from > configTime.rightGlobal) continue; // birthday date is out of the current view
428
+ const leftPx = api.time.getViewOffsetPxFromDates(api.time.date(vacation.from));
429
+ const rightPx = api.time.getViewOffsetPxFromDates(api.time.date(vacation.to));
430
+ const widthPx = rightPx - leftPx - 1;
431
+ if (widthPx < 0) continue;
432
+ let textAlign = 'left';
433
+ if (widthPx <= 100) textAlign = 'center';
434
+ vacationContent.push(
435
+ html`<div
436
+ style="position:absolute;left:${leftPx}px;width:${widthPx}px;height:14px;white-space: nowrap;text-overflow:ellipsis;overflow:hidden;font-size:11px;background:#A0A0A0;color:white;text-align:${textAlign};"
437
+ >
438
+ Vacation
439
+ </div>`
440
+ );
441
+ }
442
+ update();
443
+ });
444
+
445
+ return (content) => html`${vacationContent}${content}`;
446
+ }
447
+
448
+ function onCellCreateBirthday({ time, row, vido, content }) {
449
+ if (!row.birthday) return content;
450
+ let isBirthday = false;
451
+ for (const birthday of row.birthday) {
452
+ if (time.leftGlobal >= birthday.from && time.rightGlobal <= birthday.to) {
453
+ isBirthday = true;
454
+ break;
455
+ }
456
+ }
457
+ if (isBirthday) {
458
+ return vido.html`<div title="🎁 BIRTHDAY" style="height:100%;width:100%;font-size:18px;background:#F9B32F10;"></div>${content}`;
459
+ }
460
+ return content;
461
+ }
462
+
463
+ function myBirthdayRowSlot(vido, props) {
464
+ const { onChange, html, update, api, state } = vido;
465
+
466
+ let birthdayContent = [];
467
+ onChange((changedProps) => {
468
+ props = changedProps;
469
+ if (!props || !props.row || !props.row.birthday) {
470
+ birthdayContent = [];
471
+ return update();
472
+ }
473
+ const configTime = state.get('config.chart.time');
474
+ birthdayContent = [];
475
+ for (const birthday of props.row.birthday) {
476
+ if (birthday.to < configTime.leftGlobal || birthday.from > configTime.rightGlobal) continue; // birthday date is out of the current view
477
+ const leftPx = api.time.getViewOffsetPxFromDates(api.time.date(birthday.from));
478
+ const rightPx = api.time.getViewOffsetPxFromDates(api.time.date(birthday.to));
479
+ const widthPx = rightPx - leftPx - 1;
480
+ if (widthPx < 0) continue;
481
+ let textAlign = 'left';
482
+ if (widthPx <= 100) textAlign = 'center';
483
+ birthdayContent.push(
484
+ html`<div
485
+ style="position:absolute;left:${leftPx}px;width:${widthPx}px;height:14px;white-space: nowrap;text-overflow:ellipsis;overflow:hidden;font-size:11px;background:#F9B32F;color:white;text-align:${textAlign};"
486
+ >
487
+ 🎁 Birthday
488
+ </div>`
489
+ );
490
+ }
491
+ update();
492
+ });
493
+
494
+ return (content) => html`${birthdayContent}${content}`;
495
+ }
496
+
497
+ // Typescript usage:
498
+ // import { Config } from 'gantt-schedule-timeline-calendar';
499
+ // const config: Config = {...};
500
+ /**
501
+ * @type {import("../../dist/gstc").Config} // or {import("gantt-schedule-timeline-calendar").Config}
502
+ */
503
+ const config = {
504
+ licenseKey:
505
+ '====BEGIN LICENSE KEY====\nXOfH/lnVASM6et4Co473t9jPIvhmQ/l0X3Ewog30VudX6GVkOB0n3oDx42NtADJ8HjYrhfXKSNu5EMRb5KzCLvMt/pu7xugjbvpyI1glE7Ha6E5VZwRpb4AC8T1KBF67FKAgaI7YFeOtPFROSCKrW5la38jbE5fo+q2N6wAfEti8la2ie6/7U2V+SdJPqkm/mLY/JBHdvDHoUduwe4zgqBUYLTNUgX6aKdlhpZPuHfj2SMeB/tcTJfH48rN1mgGkNkAT9ovROwI7ReLrdlHrHmJ1UwZZnAfxAC3ftIjgTEHsd/f+JrjW6t+kL6Ef1tT1eQ2DPFLJlhluTD91AsZMUg==||U2FsdGVkX1/SWWqU9YmxtM0T6Nm5mClKwqTaoF9wgZd9rNw2xs4hnY8Ilv8DZtFyNt92xym3eB6WA605N5llLm0D68EQtU9ci1rTEDopZ1ODzcqtTVSoFEloNPFSfW6LTIC9+2LSVBeeHXoLEQiLYHWihHu10Xll3KsH9iBObDACDm1PT7IV4uWvNpNeuKJc\npY3C5SG+3sHRX1aeMnHlKLhaIsOdw2IexjvMqocVpfRpX4wnsabNA0VJ3k95zUPS3vTtSegeDhwbl6j+/FZcGk9i+gAy6LuetlKuARjPYn2LH5Be3Ah+ggSBPlxf3JW9rtWNdUoFByHTcFlhzlU9HnpnBUrgcVMhCQ7SAjN9h2NMGmCr10Rn4OE0WtelNqYVig7KmENaPvFT+k2I0cYZ4KWwxxsQNKbjEAxJxrzK4HkaczCvyQbzj4Ppxx/0q+Cns44OeyWcwYD/vSaJm4Kptwpr+L4y5BoSO/WeqhSUQQ85nvOhtE0pSH/ZXYo3pqjPdQRfNm6NFeBl2lwTmZUEuw==\n====END LICENSE KEY====',
506
+ innerHeight: 700,
507
+ //autoInnerHeight: true,
508
+ plugins: [
509
+ HighlightWeekends(),
510
+ TimelinePointer(), // timeline pointer must go first before selection, resizing and movement
511
+ Selection({
512
+ events: {
513
+ onEnd(selected) {
514
+ console.log('Selected', selected);
515
+ return selected;
516
+ },
517
+ },
518
+ }),
519
+ ItemResizing(itemResizeOptions), // resizing must fo before movement
520
+ ItemMovement(itemMovementOptions),
521
+ CalendarScroll(),
522
+ ProgressBar(),
523
+ TimeBookmarks({
524
+ bookmarks,
525
+ }),
526
+ DependencyLines({
527
+ onLine: [
528
+ (line) => {
529
+ line.type = GSTC.api.sourceID(line.fromItem.id) === '3' ? 'smooth' : 'square';
530
+ return line;
531
+ },
532
+ ],
533
+ }),
534
+ ExportImage(),
535
+ ExportPDF(),
536
+ ],
537
+ list: {
538
+ row: {
539
+ height: 68,
540
+ },
541
+ rows: getInitialRows(),
542
+ columns,
543
+ },
544
+ chart: {
545
+ time: {
546
+ from: startDate.valueOf(),
547
+ to: endDate.valueOf(),
548
+ onLevelDates: [onLevelDates],
549
+ },
550
+ item: {
551
+ height: 50,
552
+ gap: {
553
+ top: 14,
554
+ //bottom: 0,
555
+ },
556
+ },
557
+ items: generateItemsForDaysView(),
558
+ grid: {
559
+ cell: {
560
+ onCreate: [onCellCreateVacation, onCellCreateBirthday],
561
+ },
562
+ },
563
+ },
564
+ scroll: {
565
+ vertical: { precise: true, byPixels: true },
566
+ horizontal: { precise: true, byPixels: true },
567
+ },
568
+ slots: {
569
+ 'chart-timeline-items-row-item': { content: [itemSlot], inner: [myItemSlot] },
570
+ 'list-column-row': { content: [rowSlot] },
571
+ 'chart-timeline-grid-row': { content: [myBirthdayRowSlot, myVacationRowSlot] },
572
+ },
573
+ templates: {
574
+ 'chart-timeline-items-row-item': chartTimelineItemsRowItemTemplate,
575
+ },
576
+ //utcMode: true,
577
+ };
578
+
579
+ let gstc;
580
+ let state;
581
+ function mountGSTC() {
582
+ state = GSTC.api.stateFromConfig(config);
583
+ const element = document.createElement('div');
584
+ element.id = 'gstc';
585
+ document.querySelector('#toolbox')?.after(element);
586
+ gstc = GSTC({
587
+ element,
588
+ state,
589
+ });
590
+ //@ts-ignore
591
+ globalThis.state = state;
592
+ //@ts-ignore
593
+ globalThis.gstc = gstc;
594
+ }
595
+
596
+ mountGSTC();
597
+
598
+ // TOOLBOX BUTTONS
599
+
600
+ // Select first two cells
601
+ function selectCells() {
602
+ const api = gstc.api;
603
+ const allCells = api.getGridCells();
604
+ api.plugins.Selection.selectCells([allCells[0].id, allCells[1].id]);
605
+ console.log(api.plugins.Selection.getSelection());
606
+ }
607
+
608
+ // scroll to first item
609
+ function scrollToFirstItem() {
610
+ const api = gstc.api;
611
+ const firstItem = gstc.state.get(`config.chart.items.${api.GSTCID('1')}`);
612
+ api.scrollToTime(firstItem.time.start, false);
613
+ }
614
+
615
+ globalThis.scrollToFirstItem = scrollToFirstItem;
616
+
617
+ function downloadImage() {
618
+ gstc.api.plugins.ExportImage.download();
619
+ }
620
+
621
+ async function downloadPdf() {
622
+ await gstc.api.plugins.ExportPDF.download('timeline.pdf');
623
+ console.log('PDF downloaded');
624
+ }
625
+
626
+ async function takeShotPdf() {
627
+ const img = await gstc.api.plugins.ExportPDF.takeShot();
628
+ console.log('PDF shot taken', img);
629
+ alert(
630
+ `\nScreenshot taken\n\nYou can add more screenshots and then download them all together with "Get screenshots" button.`
631
+ );
632
+ }
633
+
634
+ async function getPdf() {
635
+ await gstc.api.plugins.ExportPDF.getPDF('timeline.pdf');
636
+ await gstc.api.plugins.ExportPDF.clearPDF(); // don't forget to clear pdf after you are done with it
637
+ console.log('PDF downloaded');
638
+ }
639
+
640
+ function downloadPdfFull() {
641
+ gstc.api.plugins.ExportPDF.downloadFull('timeline.pdf');
642
+ }
643
+
644
+ let darkModeEnabled = false;
645
+ function toggleDarkMode(ev) {
646
+ darkModeEnabled = ev.target.checked;
647
+ const el = document.getElementById('gstc');
648
+ if (darkModeEnabled) {
649
+ el?.classList.add('gstc--dark');
650
+ document.body.classList.add('gstc--dark');
651
+ } else {
652
+ el?.classList.remove('gstc--dark');
653
+ document.body.classList.remove('gstc--dark');
654
+ }
655
+ }
656
+
657
+ function toggleHideWeekends(ev) {
658
+ hideWeekends = ev.target.checked;
659
+ gstc.api.time.recalculateTime();
660
+ }
661
+
662
+ function toggleSnapTime(ev) {
663
+ snapTime = ev.target.checked;
664
+ }
665
+
666
+ function toggleExpandTime(ev) {
667
+ const expandTime = ev.target.checked;
668
+ const moveOutEl = document.getElementById('move-out');
669
+ if (moveOutEl && expandTime) {
670
+ // @ts-ignore
671
+ moveOutEl.checked = expandTime;
672
+ toggleMoveOut({ target: moveOutEl });
673
+ }
674
+ state.update('config.chart.time.autoExpandTimeFromItems', expandTime);
675
+ }
676
+
677
+ function toggleMoveOut(ev) {
678
+ const moveOut = ev.target.checked;
679
+ const expandTimeEl = document.getElementById('expand-time');
680
+ if (expandTimeEl && !moveOut) {
681
+ // @ts-ignore
682
+ expandTimeEl.checked = moveOut;
683
+ toggleExpandTime({ target: expandTimeEl });
684
+ }
685
+ state.update('config.plugin.ItemMovement.allowItemsToGoOutsideTheArea', moveOut);
686
+ state.update('config.plugin.ItemResizing.allowItemsToGoOutsideTheArea', moveOut);
687
+ }
688
+
689
+ function zoomChangeSelect(ev) {
690
+ const period = ev.target.value;
691
+ let zoom = 20;
692
+ let from = gstc.api.time.date('2020-02-01').startOf('day').valueOf();
693
+ let to = gstc.api.time.date('2020-03-01').endOf('month').valueOf();
694
+ switch (period) {
695
+ case 'hours':
696
+ zoom = 16;
697
+ from = gstc.api.time.date('2020-02-01').startOf('day').valueOf();
698
+ to = gstc.api.time.date('2020-03-01').endOf('month').valueOf();
699
+ break;
700
+ case 'days':
701
+ zoom = 20;
702
+ from = gstc.api.time.date('2020-02-01').startOf('day').valueOf();
703
+ to = gstc.api.time.date('2020-03-01').endOf('month').valueOf();
704
+ break;
705
+ case 'weeks':
706
+ zoom = 23;
707
+ from = gstc.api.time.date('2020-02-01').startOf('day').valueOf();
708
+ to = gstc.api.time.date('2020-08-01').endOf('month').valueOf();
709
+ break;
710
+ case 'months':
711
+ zoom = 26;
712
+ from = gstc.api.time.date('2020-01-01').startOf('day').valueOf();
713
+ to = gstc.api.time.date('2024-01-10').endOf('year').valueOf();
714
+ break;
715
+ }
716
+
717
+ state.update('config.chart.time', (time) => {
718
+ time.zoom = zoom;
719
+ time.from = from;
720
+ time.to = to;
721
+ return time;
722
+ });
723
+ const zoomRange = document.getElementById('zoom-range');
724
+ //@ts-ignore
725
+ if (zoomRange) zoomRange.value = zoom;
726
+ }
727
+
728
+ function zoomChangeRange(ev) {
729
+ const zoom = Number(ev.target.value);
730
+ let period = 'days';
731
+ let from = gstc.api.time.date('2020-02-01').startOf('day');
732
+ let to = gstc.api.time.date('2020-03-01').endOf('month');
733
+
734
+ if (zoom >= 16) {
735
+ period = 'hours';
736
+ from = gstc.api.time.date('2020-02-01').startOf('day');
737
+ to = gstc.api.time.date('2020-03-01').endOf('month');
738
+ }
739
+ if (zoom >= 20) {
740
+ period = 'days';
741
+ from = gstc.api.time.date('2020-02-01').startOf('day');
742
+ to = gstc.api.time.date('2020-03-01').endOf('month');
743
+ }
744
+ if (zoom >= 20) {
745
+ period = 'weeks';
746
+ from = gstc.api.time.date('2020-02-01').startOf('day');
747
+ to = gstc.api.time.date('2020-08-01').endOf('month');
748
+ }
749
+ if (zoom >= 23) {
750
+ period = 'months';
751
+ from = gstc.api.time.date('2020-01-01').startOf('day');
752
+ to = gstc.api.time.date('2024-01-10').endOf('year');
753
+ }
754
+
755
+ gstc.state.update('config.chart.time', (time) => {
756
+ time.zoom = zoom;
757
+ time.from = from.valueOf();
758
+ time.to = to.valueOf();
759
+ return time;
760
+ });
761
+ const zoomSelect = document.getElementById('zoom');
762
+ // @ts-ignore
763
+ if (zoomSelect) zoomSelect.value = period;
764
+ }
765
+
766
+ function searchRows(event) {
767
+ const copiedRows = getInitialRows();
768
+ const search = String(event.target.value).trim();
769
+ console.log('search', search);
770
+ const regex = new RegExp(`[\s\S]?${search}[\s\S]?`, 'gi');
771
+ const rowsToKeep = [];
772
+ for (const rowId in copiedRows) {
773
+ const row = copiedRows[rowId];
774
+ const rowData = gstc.api.getRowData(rowId);
775
+ if (regex.test(row.label)) {
776
+ rowsToKeep.push(rowId);
777
+ for (const childRowId of rowData.allChildren) {
778
+ rowsToKeep.push(childRowId);
779
+ }
780
+ for (const parentRowId of rowData.parents) {
781
+ rowsToKeep.push(parentRowId);
782
+ if (search) copiedRows[parentRowId].expanded = true;
783
+ }
784
+ }
785
+ regex.lastIndex = 0;
786
+ }
787
+ const uniqueRowsToKeep = [...new Set(rowsToKeep)]; // js way to get only unique row id's- we don't want duplicates here
788
+ for (const rowId in copiedRows) {
789
+ if (uniqueRowsToKeep.includes(rowId)) {
790
+ copiedRows[rowId].visible = true;
791
+ } else {
792
+ copiedRows[rowId].visible = false;
793
+ }
794
+ }
795
+ state.update('config.list.rows', (currentRows) => {
796
+ return copiedRows;
797
+ });
798
+ }
799
+
800
+ const historyStates = [];
801
+ globalThis.historyStates = historyStates;
802
+ let currentStateName = '';
803
+ function saveCurrentState(stateName) {
804
+ const items = GSTC.api.merge({}, state.get('config.chart.items'));
805
+ historyStates.push({ name: stateName, state: items });
806
+ currentStateName = stateName;
807
+ updateToolBox();
808
+ }
809
+
810
+ function restoreState(stateName) {
811
+ const historyState = historyStates.find((s) => s.name == stateName);
812
+ currentStateName = stateName;
813
+ const clonedState = GSTC.api.merge({}, historyState.state);
814
+ state.update('config.chart.items', clonedState);
815
+ updateToolBox();
816
+ }
817
+
818
+ function onRestoreStateChange(ev) {
819
+ const name = ev.target.value;
820
+ restoreState(name);
821
+ }
822
+
823
+ function openSaveCurrentStateDialog() {
824
+ const stateName = prompt('Enter current state name');
825
+ saveCurrentState(stateName);
826
+ }
827
+
828
+ function deleteSelectedItems() {
829
+ const selectedItems = gstc.api.plugins.Selection.getSelected()['chart-timeline-items-row-item']; // cloned items
830
+ gstc.api.plugins.Selection.selectItems([]); // clear selection
831
+ state.update('config.plugin.Selection.lastSelecting.chart-timeline-items-row-item', []);
832
+ state.update('config.chart.items', (items) => {
833
+ for (const item of selectedItems) {
834
+ delete items[item.id];
835
+ }
836
+ return items;
837
+ });
838
+ }
839
+
840
+ const html = GSTC.lithtml.html;
841
+
842
+ function updateToolBox() {
843
+ const searchBoxHTML = html`<input type="text" @input=${searchRows} placeholder="Search" />`;
844
+ const historyStateHTML = html`<button @click="${openSaveCurrentStateDialog}">Save items</button>
845
+ <label>Restore items:</label>
846
+ <select @change=${onRestoreStateChange}>
847
+ ${historyStates.map(
848
+ (historyState) =>
849
+ html`<option value=${historyState.name} ?selected=${historyState.name === currentStateName}>
850
+ ${historyState.name}
851
+ </option>`
852
+ )}
853
+ </select>`;
854
+
855
+ const toolboxButtons = html` <div class="toolbox-row">
856
+ <div class="toolbox-item"><button @click=${selectCells}>Select first cells</button></div>
857
+ <div class="toolbox-item"><button @click=${scrollToFirstItem}>Scroll to first item</button></div>
858
+ <div class="toolbox-item"><button @click=${downloadImage}>Download image</button></div>
859
+ <div class="toolbox-item"><button @click=${downloadPdf}>PDF (current view)</button></div>
860
+ <div class="toolbox-item"><button @click=${downloadPdfFull}>PDF (full)</button></div>
861
+ <div class="toolbox-item"><button @click=${takeShotPdf}>Take screenshot</button></div>
862
+ <div class="toolbox-item">-></div>
863
+ <div class="toolbox-item"><button @click=${getPdf}>Get screenshots</button></div>
864
+ <div class="toolbox-item">${historyStateHTML}</div>
865
+ <div class="toolbox-item">
866
+ <label>Zoom:</label>
867
+ <select @change="${zoomChangeSelect}" id="zoom">
868
+ <option value="hours">Hours</option>
869
+ <option value="days" selected>Days</option>
870
+ <option value="weeks">Weeks</option>
871
+ <option value="months">Months</option>
872
+ </select>
873
+ </div>
874
+ <div class="toolbox-item">
875
+ <button @click=${deleteSelectedItems}>Delete selected items</button>
876
+ </div>
877
+ </div>
878
+ <div class="toolbox-row">
879
+ <div class="toolbox-item">${searchBoxHTML}</div>
880
+ <div class="toolbox-item">
881
+ <input type="checkbox" id="dark-mode" @change=${toggleDarkMode} /> <label for="dark-mode">Dark mode</label>
882
+ </div>
883
+ <div class="toolbox-item">
884
+ <input type="checkbox" id="snap-time" @change=${toggleSnapTime} checked />
885
+ <label for="snap-time">Snap time (item movement)</label>
886
+ </div>
887
+ <div class="toolbox-item">
888
+ <input type="checkbox" id="hide-weekends" @change=${toggleHideWeekends} />
889
+ <label for="hide-weekends">Hide weekends</label>
890
+ </div>
891
+ <div class="toolbox-item">
892
+ <input type="checkbox" id="expand-time" @change=${toggleExpandTime} />
893
+ <label for="expand-time">Expand view when item is outside</label>
894
+ </div>
895
+ <div class="toolbox-item">
896
+ <input type="checkbox" id="move-out" @change=${toggleMoveOut} checked />
897
+ <label for="move-out">Alow items to move outside area</label>
898
+ </div>
899
+ <div class="toolbox-item">
900
+ <label for="zoom">Zoom:</label>
901
+ <input
902
+ id="zoom-range"
903
+ type="range"
904
+ min="16"
905
+ max="26"
906
+ value="20"
907
+ step="0.1"
908
+ @change=${zoomChangeRange}
909
+ style="width:200px"
910
+ />
911
+ </div>
912
+ </div>
913
+ </div>`;
914
+ // @ts-ignore
915
+ GSTC.lithtml.render(toolboxButtons, document.getElementById('toolbox'));
916
+ }
917
+ updateToolBox();
918
+
919
+ const gstcEl = document.getElementById('gstc');
920
+ gstcEl?.addEventListener('gstc-loaded', () => {
921
+ console.log('GSTC loaded!');
922
+ saveCurrentState('Initial');
923
+ });