accomadesc 0.0.14 → 0.1.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/dist/AccoCard.svelte.d.ts +2 -1
- package/dist/AccoDescription.svelte.d.ts +2 -1
- package/dist/AmenitiesCore.svelte +2 -2
- package/dist/AmenitiesCore.svelte.d.ts +2 -1
- package/dist/BookingRequest.svelte +272 -0
- package/dist/BookingRequest.svelte.d.ts +5 -0
- package/dist/Calendar.svelte +25 -11
- package/dist/Calendar.svelte.d.ts +2 -1
- package/dist/CalendarAvailable.svelte +11 -18
- package/dist/CalendarAvailable.svelte.d.ts +2 -1
- package/dist/CalendarGrid.svelte +22 -0
- package/dist/CalendarGrid.svelte.d.ts +5 -0
- package/dist/CalendarRows.svelte +22 -0
- package/dist/CalendarRows.svelte.d.ts +5 -0
- package/dist/ContactForm.svelte +180 -0
- package/dist/ContactForm.svelte.d.ts +5 -0
- package/dist/Photo.svelte.d.ts +2 -1
- package/dist/PhotoGallery.svelte +89 -35
- package/dist/PhotoGallery.svelte.d.ts +2 -1
- package/dist/Pricing.svelte.d.ts +2 -1
- package/dist/PricingShort.svelte.d.ts +2 -1
- package/dist/Section.svelte.d.ts +2 -1
- package/dist/Text.svelte.d.ts +2 -1
- package/dist/Weather.svelte +1 -2
- package/dist/Weather.svelte.d.ts +2 -1
- package/dist/basic/Avatar.svelte.d.ts +3 -2
- package/dist/basic/Button.svelte +6 -3
- package/dist/basic/Button.svelte.d.ts +4 -3
- package/dist/basic/Icon.svelte.d.ts +3 -2
- package/dist/basic/Notes.svelte +83 -0
- package/dist/basic/Notes.svelte.d.ts +7 -0
- package/dist/basic/Spinner.svelte.d.ts +3 -2
- package/dist/basic/TextInput.svelte.d.ts +3 -2
- package/dist/helpers/debounce.d.ts +7 -0
- package/dist/helpers/debounce.js +49 -0
- package/dist/helpers/iCSEventExample.ics +14 -0
- package/dist/helpers/normalizeDate.d.ts +2 -0
- package/dist/helpers/normalizeDate.js +53 -0
- package/dist/helpers/readICS.d.ts +7 -0
- package/dist/helpers/readICS.js +94 -0
- package/dist/names/gen.js +3 -3
- package/dist/occuplan/OccuPlanAvailableInfo.svelte +38 -0
- package/dist/occuplan/OccuPlanAvailableInfo.svelte.d.ts +12 -0
- package/dist/occuplan/OccuPlanGrid.svelte +356 -0
- package/dist/occuplan/OccuPlanGrid.svelte.d.ts +13 -0
- package/dist/occuplan/OccuPlanPicker.svelte +559 -0
- package/dist/occuplan/OccuPlanPicker.svelte.d.ts +16 -0
- package/dist/occuplan/OccuPlanRows.svelte +360 -0
- package/dist/occuplan/OccuPlanRows.svelte.d.ts +13 -0
- package/dist/occuplan/OccuPlanWrapper.svelte +113 -0
- package/dist/occuplan/OccuPlanWrapper.svelte.d.ts +5 -0
- package/dist/occuplan/state.svelte.d.ts +90 -0
- package/dist/occuplan/state.svelte.js +383 -0
- package/dist/svg/ExtLinkSVG.svelte.d.ts +3 -2
- package/dist/svg/LinkSVG.svelte.d.ts +3 -2
- package/dist/types.d.ts +75 -4
- package/dist/types.js +20 -0
- package/package.json +64 -61
package/dist/PhotoGallery.svelte
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import Button from './basic/Button.svelte';
|
|
2
3
|
import PhotoComponent from './Photo.svelte';
|
|
3
|
-
import type { I18nFacade, Photo, PhotoGalleryContent
|
|
4
|
+
import type { I18nFacade, Photo, PhotoGalleryContent } from './types.js';
|
|
4
5
|
import { browser } from '$app/environment';
|
|
6
|
+
import { slide } from 'svelte/transition';
|
|
5
7
|
|
|
6
8
|
let { photos, gridPhotoWidth = 300, translateFunc }: PhotoGalleryContent & I18nFacade = $props();
|
|
7
9
|
|
|
@@ -13,42 +15,48 @@
|
|
|
13
15
|
};
|
|
14
16
|
}
|
|
15
17
|
let ratio = $derived(landscape ? '16/9' : '9/16');
|
|
16
|
-
|
|
17
18
|
let galleryContainer: HTMLDivElement | undefined = $state();
|
|
18
19
|
|
|
19
|
-
let gridPhotos: GridPhoto[] = $state(
|
|
20
|
-
photos.map((p: Photo): GridPhoto => {
|
|
21
|
-
return {
|
|
22
|
-
photo: p,
|
|
23
|
-
zoomed: false,
|
|
24
|
-
id: crypto.randomUUID(),
|
|
25
|
-
};
|
|
26
|
-
}),
|
|
27
|
-
);
|
|
28
|
-
|
|
29
20
|
let width = $state(1000);
|
|
30
21
|
let numberOfCols = $derived(
|
|
31
22
|
Math.floor(width / (gridPhotoWidth && Number.isInteger(gridPhotoWidth) ? gridPhotoWidth : 300)),
|
|
32
23
|
);
|
|
33
24
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (z.zoomed) {
|
|
37
|
-
unzoom = true;
|
|
38
|
-
}
|
|
25
|
+
let zoomed: number | null = $state(0);
|
|
26
|
+
let zoomedPhoto: Photo | null = $derived(zoomed != null ? photos[zoomed] : null);
|
|
39
27
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
gridPhotos = [z, ...gridPhotos];
|
|
28
|
+
const zoom = (i: number) => {
|
|
29
|
+
zoomed = i;
|
|
30
|
+
setTimeout(() => {
|
|
31
|
+
galleryContainer?.scrollIntoView({ behavior: 'smooth' });
|
|
32
|
+
}, 100);
|
|
33
|
+
};
|
|
47
34
|
|
|
35
|
+
const unzoom = () => {
|
|
36
|
+
zoomed = null;
|
|
48
37
|
setTimeout(() => {
|
|
49
|
-
galleryContainer?.scrollIntoView();
|
|
38
|
+
galleryContainer?.scrollIntoView({ behavior: 'smooth' });
|
|
50
39
|
}, 100);
|
|
51
40
|
};
|
|
41
|
+
|
|
42
|
+
const zoomNext = () => {
|
|
43
|
+
if (zoomed != null) {
|
|
44
|
+
if (zoomed == photos.length - 1) {
|
|
45
|
+
zoomed = 0;
|
|
46
|
+
} else {
|
|
47
|
+
zoomed = zoomed + 1;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const zoomPrev = () => {
|
|
52
|
+
if (zoomed != null) {
|
|
53
|
+
if (zoomed == 0) {
|
|
54
|
+
zoomed = photos.length - 1;
|
|
55
|
+
} else {
|
|
56
|
+
zoomed = zoomed - 1;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
52
60
|
</script>
|
|
53
61
|
|
|
54
62
|
<div
|
|
@@ -59,27 +67,72 @@
|
|
|
59
67
|
class="grid-container"
|
|
60
68
|
bind:clientWidth={width}
|
|
61
69
|
>
|
|
62
|
-
{#
|
|
70
|
+
{#if zoomed != null && zoomedPhoto != null}
|
|
63
71
|
<div
|
|
64
|
-
|
|
72
|
+
transition:slide
|
|
65
73
|
aria-label="resize"
|
|
66
74
|
role="button"
|
|
67
75
|
tabindex="-1"
|
|
68
|
-
onclick={() =>
|
|
69
|
-
onkeyup={() =>
|
|
76
|
+
onclick={() => unzoom()}
|
|
77
|
+
onkeyup={() => unzoom()}
|
|
78
|
+
class="photo-container complete-row"
|
|
79
|
+
>
|
|
80
|
+
<PhotoComponent {...zoomedPhoto.content} frame={true} {ratio} {translateFunc} />
|
|
81
|
+
|
|
82
|
+
<div class="next-wrapper" style="">
|
|
83
|
+
<Button
|
|
84
|
+
text=">"
|
|
85
|
+
size={3.3}
|
|
86
|
+
fontSize="3rem"
|
|
87
|
+
clicked={() => zoomNext()}
|
|
88
|
+
stopPropagation={true}
|
|
89
|
+
/>
|
|
90
|
+
</div>
|
|
91
|
+
<div class="prev-wrapper">
|
|
92
|
+
<Button
|
|
93
|
+
text="<"
|
|
94
|
+
size={3.3}
|
|
95
|
+
fontSize="3rem"
|
|
96
|
+
clicked={() => zoomPrev()}
|
|
97
|
+
stopPropagation={true}
|
|
98
|
+
/>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
{/if}
|
|
102
|
+
|
|
103
|
+
{#each photos as p, i (p.id)}
|
|
104
|
+
<div
|
|
105
|
+
aria-label="resize"
|
|
106
|
+
role="button"
|
|
107
|
+
tabindex="-1"
|
|
108
|
+
onclick={() => zoom(i)}
|
|
109
|
+
onkeyup={() => zoom(i)}
|
|
70
110
|
class="photo-container"
|
|
71
111
|
>
|
|
72
|
-
<PhotoComponent
|
|
73
|
-
{...p.photo.content}
|
|
74
|
-
frame={true}
|
|
75
|
-
ratio={p.zoomed ? ratio : '1'}
|
|
76
|
-
{translateFunc}
|
|
77
|
-
/>
|
|
112
|
+
<PhotoComponent {...p.content} frame={true} ratio="1" {translateFunc} />
|
|
78
113
|
</div>
|
|
79
114
|
{/each}
|
|
80
115
|
</div>
|
|
81
116
|
|
|
82
117
|
<style>
|
|
118
|
+
.next-wrapper {
|
|
119
|
+
position: absolute;
|
|
120
|
+
right: 1rem;
|
|
121
|
+
top: calc(50% - 1.65rem);
|
|
122
|
+
|
|
123
|
+
--bg-button-prim-color: rgba(242, 242, 242, 0.3);
|
|
124
|
+
--main-font-color: rgba(15, 14, 15, 0.6);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.prev-wrapper {
|
|
128
|
+
position: absolute;
|
|
129
|
+
left: 1rem;
|
|
130
|
+
top: calc(50% - 1.65rem);
|
|
131
|
+
|
|
132
|
+
--bg-button-prim-color: rgba(242, 242, 242, 0.3);
|
|
133
|
+
--main-font-color: rgba(15, 14, 15, 0.6);
|
|
134
|
+
}
|
|
135
|
+
|
|
83
136
|
.complete-row {
|
|
84
137
|
grid-column-start: firstLine;
|
|
85
138
|
grid-column-end: lastLine;
|
|
@@ -91,6 +144,7 @@
|
|
|
91
144
|
cursor: pointer;
|
|
92
145
|
width: 100%;
|
|
93
146
|
height: 100%;
|
|
147
|
+
position: relative;
|
|
94
148
|
}
|
|
95
149
|
|
|
96
150
|
.grid-container {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { I18nFacade, PhotoGalleryContent } from './types.js';
|
|
2
|
-
|
|
2
|
+
type $$ComponentProps = PhotoGalleryContent & I18nFacade;
|
|
3
|
+
declare const PhotoGallery: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
3
4
|
type PhotoGallery = ReturnType<typeof PhotoGallery>;
|
|
4
5
|
export default PhotoGallery;
|
package/dist/Pricing.svelte.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PricingContent, I18nFacade } from './types.js';
|
|
2
|
-
|
|
2
|
+
type $$ComponentProps = PricingContent & I18nFacade;
|
|
3
|
+
declare const Pricing: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
3
4
|
type Pricing = ReturnType<typeof Pricing>;
|
|
4
5
|
export default Pricing;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { I18nFacade, PricingShortContent } from './types.js';
|
|
2
|
-
|
|
2
|
+
type $$ComponentProps = PricingShortContent & I18nFacade;
|
|
3
|
+
declare const PricingShort: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
3
4
|
type PricingShort = ReturnType<typeof PricingShort>;
|
|
4
5
|
export default PricingShort;
|
package/dist/Section.svelte.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Section as SectionI, type I18nFacade } from './types.js';
|
|
2
|
-
|
|
2
|
+
type $$ComponentProps = SectionI & I18nFacade;
|
|
3
|
+
declare const Section: import("svelte").Component<$$ComponentProps, {}, "padding">;
|
|
3
4
|
type Section = ReturnType<typeof Section>;
|
|
4
5
|
export default Section;
|
package/dist/Text.svelte.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { TextContent, I18nFacade } from './types.js';
|
|
2
|
-
|
|
2
|
+
type $$ComponentProps = TextContent & I18nFacade;
|
|
3
|
+
declare const Text: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
3
4
|
type Text = ReturnType<typeof Text>;
|
|
4
5
|
export default Text;
|
package/dist/Weather.svelte
CHANGED
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
const callback = () => {
|
|
10
10
|
//TODO maybe do something here
|
|
11
|
-
// probably build something custom, not using weatherwidget.io
|
|
12
|
-
//
|
|
11
|
+
// probably build something custom, not using weatherwidget.io
|
|
13
12
|
//console.log("weather script loaded")
|
|
14
13
|
initialLoadDone = true;
|
|
15
14
|
};
|
package/dist/Weather.svelte.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { I18nFacade, WeatherContent } from './types.js';
|
|
2
|
-
|
|
2
|
+
type $$ComponentProps = WeatherContent & I18nFacade;
|
|
3
|
+
declare const Weather: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
3
4
|
type Weather = ReturnType<typeof Weather>;
|
|
4
5
|
export default Weather;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
type $$ComponentProps = {
|
|
2
2
|
email: string;
|
|
3
3
|
size?: number;
|
|
4
4
|
imageUrl?: string;
|
|
5
|
-
}
|
|
5
|
+
};
|
|
6
|
+
declare const Avatar: import("svelte").Component<$$ComponentProps, {}, "imageUrl">;
|
|
6
7
|
type Avatar = ReturnType<typeof Avatar>;
|
|
7
8
|
export default Avatar;
|
package/dist/basic/Button.svelte
CHANGED
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
clicked?: (event: Event) => void;
|
|
42
42
|
} = $props();
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
let disabled = $derived(!enabled);
|
|
45
45
|
|
|
46
46
|
const onClick = (event: Event) => {
|
|
47
47
|
if (stopPropagation) {
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
if (enabled) onclicked(event);
|
|
51
51
|
};
|
|
52
52
|
|
|
53
|
-
let focussed = false;
|
|
53
|
+
let focussed = $state(false);
|
|
54
54
|
const focussing = (event: Event) => {
|
|
55
55
|
if (stopPropagation) {
|
|
56
56
|
event.stopPropagation();
|
|
@@ -277,7 +277,7 @@
|
|
|
277
277
|
align-items: center;
|
|
278
278
|
|
|
279
279
|
background-color: var(--bg-button-prim-color);
|
|
280
|
-
color: var(--font-
|
|
280
|
+
color: var(--main-font-color);
|
|
281
281
|
|
|
282
282
|
cursor: pointer;
|
|
283
283
|
overflow: hidden;
|
|
@@ -288,6 +288,7 @@
|
|
|
288
288
|
}
|
|
289
289
|
.button:focus {
|
|
290
290
|
outline-style: none;
|
|
291
|
+
filter: drop-shadow(0 0 0.75rem var(--focussed-border-color));
|
|
291
292
|
}
|
|
292
293
|
|
|
293
294
|
.button.danger {
|
|
@@ -310,6 +311,8 @@
|
|
|
310
311
|
vertical-align: middle;
|
|
311
312
|
font-variant: small-caps;
|
|
312
313
|
|
|
314
|
+
color: var(--main-font-color);
|
|
315
|
+
|
|
313
316
|
margin-left: 0.4rem;
|
|
314
317
|
margin-right: 0.4rem;
|
|
315
318
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
type $$ComponentProps = {
|
|
2
2
|
text?: string | null;
|
|
3
3
|
iconName?: string;
|
|
4
4
|
ariaLabel?: string;
|
|
5
5
|
form?: string | null;
|
|
6
|
-
type?:
|
|
6
|
+
type?: 'button' | 'submit' | 'reset';
|
|
7
7
|
stopPropagation?: boolean;
|
|
8
8
|
pressed?: boolean;
|
|
9
9
|
fontSize?: string;
|
|
@@ -15,6 +15,7 @@ declare const Button: import("svelte").Component<{
|
|
|
15
15
|
onUp?: boolean;
|
|
16
16
|
preventDefault?: boolean;
|
|
17
17
|
clicked?: (event: Event) => void;
|
|
18
|
-
}
|
|
18
|
+
};
|
|
19
|
+
declare const Button: import("svelte").Component<$$ComponentProps, {}, "enabled">;
|
|
19
20
|
type Button = ReturnType<typeof Button>;
|
|
20
21
|
export default Button;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
type $$ComponentProps = {
|
|
2
2
|
color?: string;
|
|
3
3
|
iconName: string;
|
|
4
4
|
width?: string;
|
|
5
5
|
height?: string;
|
|
6
|
-
}
|
|
6
|
+
};
|
|
7
|
+
declare const Icon: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
8
|
type Icon = ReturnType<typeof Icon>;
|
|
8
9
|
export default Icon;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { randomID } from '../names/gen.ts';
|
|
3
|
+
|
|
4
|
+
let {
|
|
5
|
+
disabled,
|
|
6
|
+
changed,
|
|
7
|
+
}: {
|
|
8
|
+
disabled: boolean;
|
|
9
|
+
changed: (value: string) => void;
|
|
10
|
+
} = $props();
|
|
11
|
+
|
|
12
|
+
let divElement: HTMLDivElement;
|
|
13
|
+
let id = randomID();
|
|
14
|
+
|
|
15
|
+
const contentChanged = (e: Event) => {
|
|
16
|
+
const target = e.currentTarget as HTMLDivElement;
|
|
17
|
+
changed(target.getHTML());
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
$effect(() => {
|
|
21
|
+
if (disabled) {
|
|
22
|
+
divElement.innerText = '';
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<div
|
|
28
|
+
bind:this={divElement}
|
|
29
|
+
class:disabled
|
|
30
|
+
id="input-{id}"
|
|
31
|
+
contenteditable={disabled ? null : 'plaintext-only'}
|
|
32
|
+
class="question-input"
|
|
33
|
+
oninput={contentChanged}
|
|
34
|
+
></div>
|
|
35
|
+
|
|
36
|
+
<style>
|
|
37
|
+
.question-input {
|
|
38
|
+
position: relative;
|
|
39
|
+
|
|
40
|
+
min-width: 400px;
|
|
41
|
+
width: 100%;
|
|
42
|
+
max-width: 800px;
|
|
43
|
+
min-height: 5rem;
|
|
44
|
+
height: 100%;
|
|
45
|
+
|
|
46
|
+
border: var(--main-border);
|
|
47
|
+
border-radius: 1rem;
|
|
48
|
+
|
|
49
|
+
background-color: var(--longinput-bg-color);
|
|
50
|
+
|
|
51
|
+
padding-left: 1.3rem;
|
|
52
|
+
padding-right: 1.3rem;
|
|
53
|
+
padding-top: 0.5rem;
|
|
54
|
+
|
|
55
|
+
line-height: 24px;
|
|
56
|
+
|
|
57
|
+
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' height='24' width='24'><line x1='0' y1='4' x2='16' y2='4' stroke='rgba(15,15,15,0.5)' stroke-width='0.1' /></svg>");
|
|
58
|
+
background-repeat: repeat;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.question-input.disabled {
|
|
62
|
+
border-color: var(--disabled-border-color);
|
|
63
|
+
font: var(--font-disabled-color);
|
|
64
|
+
background-color: var(--longinput-disabled-bg-color);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.question-input::after {
|
|
68
|
+
content: '';
|
|
69
|
+
position: absolute;
|
|
70
|
+
border: var(--dashed-border);
|
|
71
|
+
right: 1rem;
|
|
72
|
+
top: 0;
|
|
73
|
+
bottom: 0;
|
|
74
|
+
}
|
|
75
|
+
.question-input::before {
|
|
76
|
+
content: '';
|
|
77
|
+
position: absolute;
|
|
78
|
+
border: var(--dashed-border);
|
|
79
|
+
left: 1rem;
|
|
80
|
+
top: 0;
|
|
81
|
+
bottom: 0;
|
|
82
|
+
}
|
|
83
|
+
</style>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
type $$ComponentProps = {
|
|
2
2
|
color?: string;
|
|
3
3
|
inline?: boolean;
|
|
4
4
|
height?: string;
|
|
5
5
|
width?: string;
|
|
6
|
-
}
|
|
6
|
+
};
|
|
7
|
+
declare const Spinner: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
8
|
type Spinner = ReturnType<typeof Spinner>;
|
|
8
9
|
export default Spinner;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
type $$ComponentProps = {
|
|
2
2
|
placeholder?: string;
|
|
3
3
|
phonePattern?: string;
|
|
4
4
|
name?: string;
|
|
@@ -28,6 +28,7 @@ declare const TextInput: import("svelte").Component<{
|
|
|
28
28
|
focussed?: (name: string, value: string | number) => void;
|
|
29
29
|
validityChanged?: (valid: boolean, name: string, value: string | number) => void;
|
|
30
30
|
valueChanged?: (valid: boolean, name: string, value: string | number) => void;
|
|
31
|
-
}
|
|
31
|
+
};
|
|
32
|
+
declare const TextInput: import("svelte").Component<$$ComponentProps, {}, "valid" | "value">;
|
|
32
33
|
type TextInput = ReturnType<typeof TextInput>;
|
|
33
34
|
export default TextInput;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type DebounceFunction = () => Promise<boolean>;
|
|
2
|
+
export interface DebounceConfig {
|
|
3
|
+
initialDelay: number;
|
|
4
|
+
debounceDelay: number;
|
|
5
|
+
}
|
|
6
|
+
export declare const DefaultDebounceConfig: DebounceConfig;
|
|
7
|
+
export declare const debounce: (id: string, func: DebounceFunction, config?: DebounceConfig) => Promise<boolean>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { DateTime as luxon } from 'luxon';
|
|
2
|
+
export const DefaultDebounceConfig = {
|
|
3
|
+
initialDelay: 0,
|
|
4
|
+
debounceDelay: 10000,
|
|
5
|
+
};
|
|
6
|
+
let updateTimestamps = {};
|
|
7
|
+
let nextUpdates = {};
|
|
8
|
+
let scheduled = {};
|
|
9
|
+
export const debounce = async (id, func, config = DefaultDebounceConfig) => {
|
|
10
|
+
//console.log(`DEBOUNCE: ${id}`)
|
|
11
|
+
nextUpdates[id] = func;
|
|
12
|
+
return doDebounce(id, true, config);
|
|
13
|
+
};
|
|
14
|
+
const doDebounce = async (id, firstRun, config) => {
|
|
15
|
+
const now = luxon.utc();
|
|
16
|
+
const priorExecTime = updateTimestamps[id];
|
|
17
|
+
//no prior timestamp, execute and store timestamp
|
|
18
|
+
if (!priorExecTime) {
|
|
19
|
+
if (firstRun && config.initialDelay > 0) {
|
|
20
|
+
setTimeout(() => {
|
|
21
|
+
return doDebounce(id, false, config);
|
|
22
|
+
}, config.initialDelay + 10);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
const result = await nextUpdates[id]();
|
|
26
|
+
updateTimestamps[id] = now;
|
|
27
|
+
//console.log('INITIAL')
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//last execution was more than debounceDelay ms ago
|
|
32
|
+
else if (priorExecTime < now.minus({ milliseconds: config.debounceDelay })) {
|
|
33
|
+
const result = await nextUpdates[id]();
|
|
34
|
+
updateTimestamps[id] = now;
|
|
35
|
+
//console.log('DUE')
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
//else retry after timeout
|
|
39
|
+
else if (firstRun && !scheduled[id]) {
|
|
40
|
+
//console.log('SCHEDULE')
|
|
41
|
+
scheduled[id] = true;
|
|
42
|
+
setTimeout(() => {
|
|
43
|
+
//console.log('RETRY')
|
|
44
|
+
scheduled[id] = false;
|
|
45
|
+
return doDebounce(id, false, config);
|
|
46
|
+
}, config.debounceDelay + 10);
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
BEGIN:VEVENT
|
|
2
|
+
DTSTART;VALUE=DATE:20230207
|
|
3
|
+
DTEND;VALUE=DATE:20230223
|
|
4
|
+
DTSTAMP:20230118T163615Z
|
|
5
|
+
UID:6cfjhjfvp50tldvkbrbgp9m6r0@google.com
|
|
6
|
+
CREATED:20230118T163028Z
|
|
7
|
+
DESCRIPTION:
|
|
8
|
+
LAST-MODIFIED:20230118T163028Z
|
|
9
|
+
LOCATION:
|
|
10
|
+
SEQUENCE:0
|
|
11
|
+
STATUS:CONFIRMED
|
|
12
|
+
SUMMARY:Mertens
|
|
13
|
+
TRANSP:TRANSPARENT
|
|
14
|
+
END:VEVENT
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { DateTime as luxon } from 'luxon';
|
|
2
|
+
export const normalizeDate = (date) => {
|
|
3
|
+
//initialize default return values, for the case the input is not
|
|
4
|
+
//"normalizable"
|
|
5
|
+
const nowUTC = luxon.utc().set({ hour: 12, minute: 0, second: 0, millisecond: 0 });
|
|
6
|
+
//no parameter or falsy
|
|
7
|
+
if (!date) {
|
|
8
|
+
return nowUTC;
|
|
9
|
+
}
|
|
10
|
+
//parameter is an instance of date;
|
|
11
|
+
if (date instanceof Date) {
|
|
12
|
+
// but invalid
|
|
13
|
+
if (Number.isNaN(Number(date))) {
|
|
14
|
+
return nowUTC;
|
|
15
|
+
}
|
|
16
|
+
return luxon.utc(date.getFullYear(), date.getMonth() + 1, date.getDate(), 12);
|
|
17
|
+
}
|
|
18
|
+
//otherwise try different parsing methods
|
|
19
|
+
let pDate;
|
|
20
|
+
//check if it's already a numeric value, assuming millis from start of time
|
|
21
|
+
if (Number.isInteger(date)) {
|
|
22
|
+
pDate = luxon.fromMillis(date);
|
|
23
|
+
if (pDate.isValid) {
|
|
24
|
+
return luxon.utc(pDate.year, pDate.month, pDate.day, 12);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//check if it has a valueOf function and if that function yields an integer
|
|
28
|
+
if (typeof date.valueOf === 'function' && Number.isInteger(date.valueOf())) {
|
|
29
|
+
pDate = luxon.fromMillis(date.valueOf());
|
|
30
|
+
if (pDate.isValid) {
|
|
31
|
+
return luxon.utc(pDate.year, pDate.month, pDate.day, 12);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//parse it, as if it is an ISO string
|
|
35
|
+
pDate = luxon.fromISO(date, { setZone: true });
|
|
36
|
+
if (pDate.isValid) {
|
|
37
|
+
return luxon.utc(pDate.year, pDate.month, pDate.day, 12);
|
|
38
|
+
}
|
|
39
|
+
//parse it, as if it is in HTTP format
|
|
40
|
+
//@ts-ignore
|
|
41
|
+
pDate = luxon.fromHTTP(date, { setZone: true });
|
|
42
|
+
if (pDate.isValid) {
|
|
43
|
+
return luxon.utc(pDate.year, pDate.month, pDate.day, 12);
|
|
44
|
+
}
|
|
45
|
+
//parse it, as if it is in SQL format
|
|
46
|
+
//@ts-ignore
|
|
47
|
+
pDate = luxon.fromSQL(date, { setZone: true });
|
|
48
|
+
if (pDate.isValid) {
|
|
49
|
+
return luxon.utc(pDate.year, pDate.month, pDate.day, 12);
|
|
50
|
+
}
|
|
51
|
+
//if nothing helps, return today at noon GMT
|
|
52
|
+
return nowUTC;
|
|
53
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { OccupationCallback } from '../occuplan/state.svelte.js';
|
|
2
|
+
export interface GetEventsResult {
|
|
3
|
+
message: string;
|
|
4
|
+
code: number;
|
|
5
|
+
error: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare const getEvents: (url: string, eventCallback: OccupationCallback) => Promise<GetEventsResult>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { DateTime as lx } from 'luxon';
|
|
2
|
+
const extractOccupationType = (line) => {
|
|
3
|
+
try {
|
|
4
|
+
const oTypes = line.split('CATEGORIES:')[1];
|
|
5
|
+
const [first] = oTypes.split(',');
|
|
6
|
+
return first.trim();
|
|
7
|
+
}
|
|
8
|
+
catch (e) {
|
|
9
|
+
console.log('Error occured extracting occupation type from line', line);
|
|
10
|
+
}
|
|
11
|
+
return 'one';
|
|
12
|
+
};
|
|
13
|
+
const readIcsFromResponse = async (resp, eventCallback) => {
|
|
14
|
+
const text = await resp.text();
|
|
15
|
+
//console.log(text)
|
|
16
|
+
let insideEvent = false;
|
|
17
|
+
let arrival = '';
|
|
18
|
+
let leave = '';
|
|
19
|
+
let oType = 'one';
|
|
20
|
+
text.split(/\r?\n/).forEach((line) => {
|
|
21
|
+
switch (true) {
|
|
22
|
+
case /^BEGIN:VEVENT$/.test(line):
|
|
23
|
+
insideEvent = true;
|
|
24
|
+
break;
|
|
25
|
+
case /^DTSTART;VALUE=.*/.test(line) && insideEvent:
|
|
26
|
+
arrival = line;
|
|
27
|
+
break;
|
|
28
|
+
case /^DTEND;VALUE=.*/.test(line) && insideEvent:
|
|
29
|
+
leave = line;
|
|
30
|
+
break;
|
|
31
|
+
case /^CATEGORIES:.*$/.test(line) && insideEvent:
|
|
32
|
+
oType = extractOccupationType(line);
|
|
33
|
+
break;
|
|
34
|
+
case /^END:VEVENT$/.test(line) && insideEvent:
|
|
35
|
+
insideEvent = false;
|
|
36
|
+
eventCallback({
|
|
37
|
+
type: oType,
|
|
38
|
+
arrival: getDate(arrival),
|
|
39
|
+
leave: getDate(leave),
|
|
40
|
+
});
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
export const getEvents = async (url, eventCallback) => {
|
|
46
|
+
let result = {
|
|
47
|
+
message: 'undefined',
|
|
48
|
+
code: 100,
|
|
49
|
+
error: false,
|
|
50
|
+
};
|
|
51
|
+
let resp;
|
|
52
|
+
try {
|
|
53
|
+
resp = await fetch(url, {
|
|
54
|
+
headers: {
|
|
55
|
+
Accept: 'text/calendar',
|
|
56
|
+
},
|
|
57
|
+
//mode: "no-cors"
|
|
58
|
+
});
|
|
59
|
+
result = {
|
|
60
|
+
message: resp.statusText,
|
|
61
|
+
code: resp.status,
|
|
62
|
+
error: resp.status > 299 ? true : false,
|
|
63
|
+
};
|
|
64
|
+
if (resp.status > 299)
|
|
65
|
+
return result;
|
|
66
|
+
await readIcsFromResponse(resp, eventCallback);
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
console.log('Error occured while fetching events from proxy via calUrl:', e);
|
|
70
|
+
return {
|
|
71
|
+
message: `Fetch threw error: ${e}`,
|
|
72
|
+
code: 500,
|
|
73
|
+
error: true,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
};
|
|
78
|
+
const getDate = (icsLine) => {
|
|
79
|
+
//e.g. DTEND;VALUE=DATE:20260818
|
|
80
|
+
const [typePart, valuePart] = icsLine.split('=');
|
|
81
|
+
const dateString = valuePart.split(':')[1];
|
|
82
|
+
let rawDateTime = lx.fromISO(dateString);
|
|
83
|
+
//end date has to be moved back when whole day ending
|
|
84
|
+
if (/^DTEND;VALUE$/.test(typePart)) {
|
|
85
|
+
if (rawDateTime.hour == 0 &&
|
|
86
|
+
rawDateTime.minute == 0 &&
|
|
87
|
+
rawDateTime.second == 0 &&
|
|
88
|
+
rawDateTime.millisecond == 0) {
|
|
89
|
+
rawDateTime = rawDateTime.plus({ hour: 12 });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//normalize to noon
|
|
93
|
+
return rawDateTime.set({ hour: 12, minute: 0, second: 0, millisecond: 0 });
|
|
94
|
+
};
|