accomadesc 0.4.7 → 0.4.9

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.
@@ -13,6 +13,8 @@
13
13
  height?: string;
14
14
  filter?: string;
15
15
  } = $props();
16
+
17
+ const icon = $derived(getIcon(iconName, color));
16
18
  </script>
17
19
 
18
20
  <div
@@ -23,5 +25,5 @@
23
25
  {filter ? `filter: ${filter};` : ''}
24
26
  "
25
27
  >
26
- {@html getIcon(iconName, color)}
28
+ {@html icon}
27
29
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "accomadesc",
3
- "version": "0.4.7",
3
+ "version": "0.4.9",
4
4
  "files": [
5
5
  "dist",
6
6
  "!dist/**/*.test.*",
@@ -41,7 +41,7 @@
41
41
  "prettier": "^3.8.1",
42
42
  "prettier-plugin-svelte": "^3.5.1",
43
43
  "publint": "^0.3.18",
44
- "svelte": "^5.53.11",
44
+ "svelte": "^5.53.12",
45
45
  "svelte-check": "^4.4.5",
46
46
  "typescript": "^5.9.3",
47
47
  "vite": "^6.4.1",
@@ -1,43 +0,0 @@
1
- <script lang="ts">
2
- import { DateTime } from 'luxon';
3
- import { normalizeDate } from '../helpers/normalizeDate.js';
4
- import { getContext, onMount, untrack, setContext, type Snippet } from 'svelte';
5
- import { OccupationState, contextKey, type AvailableSpans } from '../occuplan/state.svelte.js';
6
- import Spinner from '../basic/Spinner.svelte';
7
-
8
- let {
9
- url,
10
- debug = false,
11
- search = [3, 7, 14],
12
- maxFutureDate = normalizeDate(DateTime.utc().plus({ years: 1 })),
13
- children,
14
- }: {
15
- url: string;
16
- debug?: boolean | undefined;
17
- search?: number[];
18
- maxFutureDate?: DateTime;
19
- children: Snippet<[AvailableSpans]>;
20
- } = $props();
21
-
22
- const stateID = contextKey(untrack(() => url));
23
- let ss: OccupationState = getContext(stateID);
24
- if (!ss) {
25
- ss = new OccupationState(() => {
26
- return { iCalURL: url, debug };
27
- });
28
- setContext(stateID, ss);
29
- }
30
-
31
- let occupationState: OccupationState = $derived(ss);
32
- let av = $derived(occupationState ? occupationState.calcAvailability(search, maxFutureDate) : {});
33
-
34
- onMount(() => {
35
- occupationState.loadOccupations();
36
- });
37
- </script>
38
-
39
- {#if !occupationState || occupationState.loading}
40
- <Spinner />
41
- {/if}
42
-
43
- {@render children(av)}
@@ -1,383 +0,0 @@
1
- <script lang="ts">
2
- import { DateTime, type MonthNumbers } from 'luxon';
3
- import {
4
- contextKey,
5
- defaultMonthHeaderFormat,
6
- defaultMonthLabels,
7
- defaultWeekdayLabels,
8
- OccupationState,
9
- occupationTypeFormatting,
10
- realFirstMonth,
11
- type FirstMonth,
12
- type OccupationType,
13
- type OccuplanTranslations,
14
- } from './state.svelte.js';
15
- import Button from '../basic/Button.svelte';
16
- import Spinner from '../basic/Spinner.svelte';
17
- import { randomID } from '../names/gen.js';
18
- import { getContext, onMount, setContext, untrack } from 'svelte';
19
-
20
- let {
21
- url,
22
- debug = false,
23
- header = '',
24
- footer = '',
25
- nextPage = '>',
26
- prevPage = '<',
27
- weekdayLabels = defaultWeekdayLabels,
28
- monthLabels = defaultMonthLabels,
29
- monthHeaderFormat = defaultMonthHeaderFormat,
30
- numberOfMonth = 12,
31
- maxWidth = '1200px',
32
- firstMonth = DateTime.utc().month,
33
- maxDate = DateTime.utc().plus({ years: 2 }),
34
- minDate = DateTime.utc(),
35
- typeLabels = {
36
- one: 'BOOKING',
37
- two: 'RESERVATION',
38
- three: 'PERSONAL',
39
- },
40
- }: OccuplanTranslations & {
41
- url: string;
42
- debug?: boolean;
43
- numberOfMonth?: number;
44
- firstMonth?: FirstMonth;
45
- minDate?: DateTime;
46
- maxDate?: DateTime;
47
- maxWidth?: string;
48
- } = $props();
49
-
50
- const id = randomID();
51
-
52
- const stateID = contextKey(untrack(() => url));
53
- let ss: OccupationState = getContext(stateID);
54
- if (!ss) {
55
- ss = new OccupationState(() => {
56
- return { iCalURL: url, debug };
57
- });
58
- setContext(stateID, ss);
59
- }
60
- let occupationState: OccupationState = $derived(ss);
61
-
62
- //let formatFun = $derived(Sqrl.compile(monthHeaderFormat, { useWith: true }));
63
- const monthHeader = (monthNum: MonthNumbers, year: number): string => {
64
- const monthLabel = monthLabels[monthNum];
65
-
66
- let formatted = monthHeaderFormat.replace('{{month}}', monthLabel);
67
- formatted = formatted.replace('{{year}}', `${year}`);
68
-
69
- return formatted;
70
- };
71
-
72
- let page: number = $state(0);
73
- let rfMonth: DateTime = $derived(
74
- realFirstMonth(firstMonth, DateTime.utc().get('year'), numberOfMonth, page),
75
- );
76
-
77
- let currentMaxDate = $derived(rfMonth.plus({ month: numberOfMonth }));
78
-
79
- let months: DateTime[] = $derived.by(() => {
80
- const result = [];
81
-
82
- let fMonth: DateTime = DateTime.utc(rfMonth.year, rfMonth.month, 1);
83
-
84
- result.push(fMonth);
85
-
86
- let nMonth = fMonth.plus({ months: 1 });
87
- for (let c = 1; c < numberOfMonth; c++) {
88
- result.push(nMonth);
89
- nMonth = nMonth.plus({ months: 1 });
90
- }
91
- return result;
92
- });
93
-
94
- const nextClicked = () => {
95
- page += 1;
96
- };
97
-
98
- const prevClicked = () => {
99
- page -= 1;
100
- };
101
-
102
- let monthGridTemplateColumns = `[rowLegend] 1fr [d1] 1fr [d2] 1fr [d3] 1fr [d4] 1fr [d5] 1fr [d6] 1fr [d7] 1fr`;
103
-
104
- let monthGridTemplateRows = (m: DateTime): string => {
105
- let res = `[columnLegend] 1fr [w${m.weekNumber}] 1fr`;
106
- let n = m.plus({ weeks: 1 });
107
- for (let w = 1; w <= 5; w++) {
108
- res += ` [w${n.weekNumber}] 1fr`;
109
- n = n.plus({ weeks: 1 });
110
- }
111
- return res;
112
- };
113
-
114
- const weeks = (m: DateTime): DateTime[] => {
115
- let n = m.plus({ weeks: 1 });
116
- let res: DateTime[] = [m, n];
117
- for (let i = 1; i <= 4; i++) {
118
- n = n.plus({ weeks: 1 });
119
- res.push(n);
120
- }
121
- return res;
122
- };
123
-
124
- const days = (m: DateTime): DateTime[] => {
125
- //find first
126
- let firstDay = m.startOf('week');
127
-
128
- //find last
129
- let lastDayOfMonth = m.endOf('month');
130
- let lastDay = lastDayOfMonth.endOf('week');
131
-
132
- let n = firstDay.plus({ days: 1 });
133
- let res: DateTime[] = [firstDay];
134
-
135
- while (n <= lastDay) {
136
- res.push(n);
137
- n = n.plus({ days: 1 });
138
- }
139
-
140
- return res;
141
- };
142
-
143
- const hiddenWeekNum = (m: DateTime, w: DateTime): boolean => {
144
- let lastDayOfMonth = m.endOf('month');
145
- let firstDayOfWeek = w.startOf('week');
146
- return lastDayOfMonth < firstDayOfWeek;
147
- };
148
-
149
- let foundOccupationTypes: OccupationType[] = $derived(
150
- occupationState?.occupations.reduce((res, occupation) => {
151
- if (!res.includes(occupation.type)) {
152
- res.push(occupation.type);
153
- }
154
- return res;
155
- }, [] as OccupationType[]),
156
- );
157
-
158
- onMount(() => {
159
- occupationState.loadOccupations();
160
- });
161
- </script>
162
-
163
- {#if !occupationState || occupationState.loading}
164
- <Spinner />
165
- {/if}
166
-
167
- <section class="occuplan-wrapper" style="max-width: {maxWidth};">
168
- <header class="occupation-plan-header">
169
- <div class="header-controls">
170
- {#if rfMonth >= minDate}
171
- <Button text={`${prevPage}`} clicked={prevClicked} />
172
- {/if}
173
- </div>
174
- <div class="header-label"><h3>{@html header}</h3></div>
175
- <div class="header-controls">
176
- {#if currentMaxDate <= maxDate}
177
- <Button text={`${nextPage}`} clicked={nextClicked} />
178
- {/if}
179
- </div>
180
- </header>
181
- <main>
182
- {#each months as m (`${m.year}-${m.month}`)}
183
- <div class="month">
184
- <header class="month-header">{monthHeader(m.month as MonthNumbers, m.year)}</header>
185
- <div
186
- id={`${m.year}-${m.month}-${id}`}
187
- style="
188
- grid-template-columns: {monthGridTemplateColumns};
189
- grid-template-rows: {monthGridTemplateRows(m)};
190
- "
191
- class="days"
192
- >
193
- <div class="weekday-header" style="grid-area: columnLegend / d1 / columnLegend / d1;">
194
- {weekdayLabels[1]}
195
- </div>
196
- <div class="weekday-header" style="grid-area: columnLegend / d2 / columnLegend / d2;">
197
- {weekdayLabels[2]}
198
- </div>
199
- <div class="weekday-header" style="grid-area: columnLegend / d3 / columnLegend / d3;">
200
- {weekdayLabels[3]}
201
- </div>
202
- <div class="weekday-header" style="grid-area: columnLegend / d4 / columnLegend / d4;">
203
- {weekdayLabels[4]}
204
- </div>
205
- <div class="weekday-header" style="grid-area: columnLegend / d5 / columnLegend / d5;">
206
- {weekdayLabels[5]}
207
- </div>
208
- <div class="weekday-header" style="grid-area: columnLegend / d6 / columnLegend / d6;">
209
- {weekdayLabels[6]}
210
- </div>
211
- <div class="weekday-header" style="grid-area: columnLegend / d7 / columnLegend / d7;">
212
- {weekdayLabels[7]}
213
- </div>
214
-
215
- {#each days(m) as d (`${d.year}-${d.month}-${d.day}`)}
216
- <div
217
- id={`${m.year}-${m.month}-${m.day}-${id}`}
218
- class:weekend={[6, 7].includes(d.weekday)}
219
- class:other-month={m.month !== d.month}
220
- class="day"
221
- style="
222
- grid-area: w{d.weekNumber} / d{d.weekday} / w{d.weekNumber} / d{d.weekday};
223
- {occupationState?.occupationStyle(
224
- { day: d.day, month: d.month as MonthNumbers, year: d.year },
225
- false,
226
- maxDate,
227
- )}
228
- "
229
- >
230
- {d.day}
231
- </div>
232
- {/each}
233
-
234
- {#each weeks(m) as w (`${w.year}-${w.month}-${w.weekNumber}`)}
235
- <div
236
- id={`${w.year}-${w.month}-${w.weekNumber}-${id}`}
237
- class:hidden={hiddenWeekNum(m, w)}
238
- class="week-number"
239
- style="grid-area: w{w.weekNumber} / rowLegend / w{w.weekNumber} / rowLegend;"
240
- >
241
- {w.weekNumber}
242
- </div>
243
- {/each}
244
- </div>
245
- </div>
246
- {/each}
247
- </main>
248
- <footer>
249
- <div class="legend">
250
- {#each foundOccupationTypes as t}
251
- {@const format = occupationTypeFormatting(t)}
252
- <span>{typeLabels[t]}</span>
253
- <div
254
- id="occupation-type-{t}-legend"
255
- class="legend-entry-marker"
256
- style="background-color: {format.bgColor};"
257
- >
258
- &nbsp;
259
- </div>
260
- {/each}
261
- </div>
262
- <div class="footer-content">
263
- {@html footer}
264
- </div>
265
- </footer>
266
- </section>
267
-
268
- <style>
269
- .footer-content {
270
- display: flex;
271
- flex-direction: column;
272
- justify-content: flex-end;
273
- }
274
-
275
- .legend-entry-marker {
276
- outline: var(--occuplan-grid-border);
277
- }
278
-
279
- .month-header {
280
- text-align: center;
281
- color: var(--occuplan-main-font-color);
282
- }
283
-
284
- .hidden {
285
- display: none;
286
- }
287
-
288
- .occupation-plan-header {
289
- display: flex;
290
- flex-direction: row;
291
- width: 100%;
292
- justify-content: space-between;
293
- }
294
-
295
- .header-label {
296
- text-transform: capitalize;
297
- font-weight: bold;
298
- font-variant: small-caps;
299
-
300
- h3 {
301
- color: var(--occuplan-main-font-color);
302
- }
303
- }
304
-
305
- .week-number {
306
- text-align: left;
307
- font-style: italic;
308
- font-weight: lighter;
309
- background-color: var(--occuplan-weeknum-bg-color);
310
- color: var(--occuplan-weeknum-font-color);
311
- }
312
-
313
- .weekday-header {
314
- text-align: center;
315
- background-color: var(--occuplan-days-header-bg-color);
316
- color: var(--occuplan-days-header-font-color);
317
- grid-area: columnLegend / d1 / columnLegend / d1;
318
- }
319
-
320
- .day {
321
- text-align: center;
322
- color: var(--occuplan-main-font-color);
323
- }
324
-
325
- .weekend {
326
- font-weight: bold;
327
- }
328
-
329
- .occuplan-wrapper {
330
- height: 100%;
331
- width: calc(100% - 0.5rem);
332
- padding: 0.5rem;
333
- margin: 0;
334
- display: flex;
335
- flex-direction: column;
336
- flex-wrap: nowrap;
337
- align-items: center;
338
-
339
- border: var(--occuplan-main-border);
340
- color: var(--occuplan-main-font-color);
341
- background-color: var(--occuplan-main-bg-color);
342
- }
343
-
344
- main {
345
- display: grid;
346
- grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
347
- gap: 1rem;
348
- width: 100%;
349
- }
350
-
351
- .month {
352
- display: flex;
353
- flex-direction: column;
354
- }
355
-
356
- .days {
357
- display: grid;
358
- }
359
-
360
- footer {
361
- display: flex;
362
- flex-direction: row;
363
- align-items: stretch;
364
- justify-content: space-between;
365
- width: 100%;
366
- margin-top: 1rem;
367
- }
368
-
369
- .legend {
370
- display: grid;
371
- grid-template-columns: [label] 1fr [marker] 1rem;
372
- column-gap: 1rem;
373
- text-transform: capitalize;
374
- font-variant: small-caps;
375
-
376
- span {
377
- color: var(--occuplan-main-font-color);
378
- }
379
- }
380
- .header-controls {
381
- width: 2rem;
382
- }
383
- </style>