@axium/calendar 0.1.4 → 0.2.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/db.json +15 -0
- package/dist/common.d.ts +16 -0
- package/dist/common.js +3 -0
- package/dist/server.js +29 -15
- package/package.json +3 -3
- package/routes/calendar/+page.svelte +29 -13
package/db.json
CHANGED
|
@@ -67,6 +67,21 @@
|
|
|
67
67
|
"attendees:eventId",
|
|
68
68
|
"attendees:userId"
|
|
69
69
|
]
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"delta": true,
|
|
73
|
+
"alter_tables": {
|
|
74
|
+
"calendars": {
|
|
75
|
+
"add_columns": {
|
|
76
|
+
"color": { "type": "integer" }
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"events": {
|
|
80
|
+
"add_columns": {
|
|
81
|
+
"color": { "type": "integer" }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
70
85
|
}
|
|
71
86
|
],
|
|
72
87
|
"wipe": ["calendars", "events", "acl.calendars"],
|
package/dist/common.d.ts
CHANGED
|
@@ -54,6 +54,7 @@ export declare const EventData: z.ZodObject<{
|
|
|
54
54
|
end: z.ZodCoercedDate<unknown>;
|
|
55
55
|
isAllDay: z.ZodCoercedBoolean<unknown>;
|
|
56
56
|
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
57
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodCustomStringFormat<"hex">>>;
|
|
57
58
|
recurrence: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
58
59
|
recurrenceExcludes: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
59
60
|
recurrenceId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
@@ -68,6 +69,7 @@ export declare const EventInit: z.ZodObject<{
|
|
|
68
69
|
end: z.ZodCoercedDate<unknown>;
|
|
69
70
|
isAllDay: z.ZodCoercedBoolean<unknown>;
|
|
70
71
|
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
72
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodCustomStringFormat<"hex">>>;
|
|
71
73
|
recurrence: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
72
74
|
recurrenceExcludes: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
73
75
|
recurrenceId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
@@ -89,6 +91,7 @@ export declare const Event: z.ZodObject<{
|
|
|
89
91
|
end: z.ZodCoercedDate<unknown>;
|
|
90
92
|
isAllDay: z.ZodCoercedBoolean<unknown>;
|
|
91
93
|
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
94
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodCustomStringFormat<"hex">>>;
|
|
92
95
|
recurrence: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
93
96
|
recurrenceExcludes: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
94
97
|
recurrenceId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
@@ -117,6 +120,7 @@ export declare const Calendar: z.ZodObject<{
|
|
|
117
120
|
id: z.ZodUUID;
|
|
118
121
|
userId: z.ZodUUID;
|
|
119
122
|
created: z.ZodCoercedDate<unknown>;
|
|
123
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodCustomStringFormat<"hex">>>;
|
|
120
124
|
acl: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
121
125
|
itemId: z.ZodUUID;
|
|
122
126
|
userId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
@@ -157,6 +161,7 @@ declare const CalendarAPI: {
|
|
|
157
161
|
id: z.ZodUUID;
|
|
158
162
|
userId: z.ZodUUID;
|
|
159
163
|
created: z.ZodCoercedDate<unknown>;
|
|
164
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodCustomStringFormat<"hex">>>;
|
|
160
165
|
acl: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
161
166
|
itemId: z.ZodUUID;
|
|
162
167
|
userId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
@@ -185,6 +190,7 @@ declare const CalendarAPI: {
|
|
|
185
190
|
id: z.ZodUUID;
|
|
186
191
|
userId: z.ZodUUID;
|
|
187
192
|
created: z.ZodCoercedDate<unknown>;
|
|
193
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodCustomStringFormat<"hex">>>;
|
|
188
194
|
acl: z.ZodNonOptional<z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
189
195
|
itemId: z.ZodUUID;
|
|
190
196
|
userId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
@@ -215,6 +221,7 @@ declare const CalendarAPI: {
|
|
|
215
221
|
id: z.ZodUUID;
|
|
216
222
|
userId: z.ZodUUID;
|
|
217
223
|
created: z.ZodCoercedDate<unknown>;
|
|
224
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodCustomStringFormat<"hex">>>;
|
|
218
225
|
acl: z.ZodNonOptional<z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
219
226
|
itemId: z.ZodUUID;
|
|
220
227
|
userId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
@@ -245,6 +252,7 @@ declare const CalendarAPI: {
|
|
|
245
252
|
id: z.ZodUUID;
|
|
246
253
|
userId: z.ZodUUID;
|
|
247
254
|
created: z.ZodCoercedDate<unknown>;
|
|
255
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodCustomStringFormat<"hex">>>;
|
|
248
256
|
acl: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
249
257
|
itemId: z.ZodUUID;
|
|
250
258
|
userId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
@@ -273,6 +281,7 @@ declare const CalendarAPI: {
|
|
|
273
281
|
id: z.ZodUUID;
|
|
274
282
|
userId: z.ZodUUID;
|
|
275
283
|
created: z.ZodCoercedDate<unknown>;
|
|
284
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodCustomStringFormat<"hex">>>;
|
|
276
285
|
acl: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
277
286
|
itemId: z.ZodUUID;
|
|
278
287
|
userId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
@@ -309,6 +318,7 @@ declare const CalendarAPI: {
|
|
|
309
318
|
end: z.ZodCoercedDate<unknown>;
|
|
310
319
|
isAllDay: z.ZodCoercedBoolean<unknown>;
|
|
311
320
|
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
321
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodCustomStringFormat<"hex">>>;
|
|
312
322
|
recurrence: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
313
323
|
recurrenceExcludes: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
314
324
|
recurrenceId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
@@ -331,6 +341,7 @@ declare const CalendarAPI: {
|
|
|
331
341
|
end: z.ZodCoercedDate<unknown>;
|
|
332
342
|
isAllDay: z.ZodCoercedBoolean<unknown>;
|
|
333
343
|
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
344
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodCustomStringFormat<"hex">>>;
|
|
334
345
|
recurrence: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
335
346
|
recurrenceExcludes: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
336
347
|
recurrenceId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
@@ -349,6 +360,7 @@ declare const CalendarAPI: {
|
|
|
349
360
|
end: z.ZodCoercedDate<unknown>;
|
|
350
361
|
isAllDay: z.ZodCoercedBoolean<unknown>;
|
|
351
362
|
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
363
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodCustomStringFormat<"hex">>>;
|
|
352
364
|
recurrence: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
353
365
|
recurrenceExcludes: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
354
366
|
recurrenceId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
@@ -373,6 +385,7 @@ declare const CalendarAPI: {
|
|
|
373
385
|
end: z.ZodCoercedDate<unknown>;
|
|
374
386
|
isAllDay: z.ZodCoercedBoolean<unknown>;
|
|
375
387
|
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
388
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodCustomStringFormat<"hex">>>;
|
|
376
389
|
recurrence: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
377
390
|
recurrenceExcludes: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
378
391
|
recurrenceId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
@@ -395,6 +408,7 @@ declare const CalendarAPI: {
|
|
|
395
408
|
end: z.ZodCoercedDate<unknown>;
|
|
396
409
|
isAllDay: z.ZodCoercedBoolean<unknown>;
|
|
397
410
|
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
411
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodCustomStringFormat<"hex">>>;
|
|
398
412
|
recurrence: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
399
413
|
recurrenceExcludes: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
400
414
|
recurrenceId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
@@ -413,6 +427,7 @@ declare const CalendarAPI: {
|
|
|
413
427
|
end: z.ZodCoercedDate<unknown>;
|
|
414
428
|
isAllDay: z.ZodCoercedBoolean<unknown>;
|
|
415
429
|
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
430
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodCustomStringFormat<"hex">>>;
|
|
416
431
|
recurrence: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
417
432
|
recurrenceExcludes: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
418
433
|
recurrenceId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
@@ -435,6 +450,7 @@ declare const CalendarAPI: {
|
|
|
435
450
|
end: z.ZodCoercedDate<unknown>;
|
|
436
451
|
isAllDay: z.ZodCoercedBoolean<unknown>;
|
|
437
452
|
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
453
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodCustomStringFormat<"hex">>>;
|
|
438
454
|
recurrence: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
439
455
|
recurrenceExcludes: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
440
456
|
recurrenceId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
package/dist/common.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { $API, AccessControl, pickPermissions } from '@axium/core';
|
|
2
2
|
import * as z from 'zod';
|
|
3
3
|
import $pkg from '../package.json' with { type: 'json' };
|
|
4
|
+
import { Color } from '@axium/core/color';
|
|
4
5
|
export function dayOfYear(date) {
|
|
5
6
|
const yearStart = new Date(date.getFullYear(), 0, 1);
|
|
6
7
|
return Math.round((date.getTime() - yearStart.getTime()) / 86400000 + 1);
|
|
@@ -81,6 +82,7 @@ export const EventData = z.object({
|
|
|
81
82
|
end: z.coerce.date(),
|
|
82
83
|
isAllDay: z.coerce.boolean(),
|
|
83
84
|
description: z.string().max(2000).nullish(),
|
|
85
|
+
color: Color.nullish(),
|
|
84
86
|
// note: recurrences are not support yet
|
|
85
87
|
recurrence: z.string().max(1000).nullish(),
|
|
86
88
|
recurrenceExcludes: z.string().max(100).array().max(100).nullish(),
|
|
@@ -111,6 +113,7 @@ export const Calendar = CalendarInit.extend({
|
|
|
111
113
|
id: z.uuid(),
|
|
112
114
|
userId: z.uuid(),
|
|
113
115
|
created: z.coerce.date(),
|
|
116
|
+
color: Color.nullish(),
|
|
114
117
|
acl: AccessControl.array().optional(),
|
|
115
118
|
});
|
|
116
119
|
export function getCalPermissionsInfo(cal, user) {
|
package/dist/server.js
CHANGED
|
@@ -7,28 +7,37 @@ import { sql } from 'kysely';
|
|
|
7
7
|
import { jsonArrayFrom, jsonObjectFrom } from 'kysely/helpers/postgres';
|
|
8
8
|
import * as z from 'zod';
|
|
9
9
|
import { Attendee, CalendarInit, EventFilter, EventInit } from './common.js';
|
|
10
|
+
function withEncoded(value) {
|
|
11
|
+
return (value.color === undefined || value.color === null
|
|
12
|
+
? value
|
|
13
|
+
: Object.assign(value, { color: value.color.toString(16).padStart(8, '0') }));
|
|
14
|
+
}
|
|
15
|
+
function withDecoded(value) {
|
|
16
|
+
return (value.color === undefined || value.color === null ? value : Object.assign(value, { color: parseInt(value.color, 16) }));
|
|
17
|
+
}
|
|
10
18
|
addRoute({
|
|
11
19
|
path: '/api/users/:id/calendars',
|
|
12
20
|
params: { id: z.uuid() },
|
|
13
21
|
async GET(request, { id: userId }) {
|
|
14
22
|
const { user } = await checkAuthForUser(request, userId);
|
|
15
|
-
|
|
23
|
+
const result = await database
|
|
16
24
|
.selectFrom('calendars')
|
|
17
25
|
.selectAll()
|
|
18
26
|
.select(aclFrom('calendars'))
|
|
19
27
|
.where(userHasAccess('calendars', user))
|
|
20
28
|
.execute()
|
|
21
29
|
.catch(withError('Could not get calendars'));
|
|
30
|
+
return result.map(c => withEncoded(c));
|
|
22
31
|
},
|
|
23
32
|
async PUT(request, { id: userId }) {
|
|
24
33
|
const init = await parseBody(request, CalendarInit);
|
|
25
34
|
await checkAuthForUser(request, userId);
|
|
26
|
-
return await database
|
|
35
|
+
return withEncoded(await database
|
|
27
36
|
.insertInto('calendars')
|
|
28
37
|
.values({ ...init, userId })
|
|
29
38
|
.returningAll()
|
|
30
39
|
.executeTakeFirstOrThrow()
|
|
31
|
-
.catch(withError('Could not create calendar'));
|
|
40
|
+
.catch(withError('Could not create calendar')));
|
|
32
41
|
},
|
|
33
42
|
});
|
|
34
43
|
addRoute({
|
|
@@ -36,27 +45,27 @@ addRoute({
|
|
|
36
45
|
params: { id: z.uuid() },
|
|
37
46
|
async GET(request, { id }) {
|
|
38
47
|
const { item } = await authRequestForItem(request, 'calendars', id, { read: true });
|
|
39
|
-
return item;
|
|
48
|
+
return withEncoded(item);
|
|
40
49
|
},
|
|
41
50
|
async PATCH(request, { id }) {
|
|
42
51
|
const body = await parseBody(request, CalendarInit);
|
|
43
52
|
await authRequestForItem(request, 'calendars', id, { edit: true });
|
|
44
|
-
return await database
|
|
53
|
+
return withEncoded(await database
|
|
45
54
|
.updateTable('calendars')
|
|
46
55
|
.set(body)
|
|
47
56
|
.where('id', '=', id)
|
|
48
57
|
.returningAll()
|
|
49
58
|
.executeTakeFirstOrThrow()
|
|
50
|
-
.catch(withError('Could not update calendar'));
|
|
59
|
+
.catch(withError('Could not update calendar')));
|
|
51
60
|
},
|
|
52
61
|
async DELETE(request, { id }) {
|
|
53
62
|
await authRequestForItem(request, 'calendars', id, { manage: true });
|
|
54
|
-
return await database
|
|
63
|
+
return withEncoded(await database
|
|
55
64
|
.deleteFrom('calendars')
|
|
56
65
|
.where('id', '=', id)
|
|
57
66
|
.returningAll()
|
|
58
67
|
.executeTakeFirstOrThrow()
|
|
59
|
-
.catch(withError('Could not delete calendar'));
|
|
68
|
+
.catch(withError('Could not delete calendar')));
|
|
60
69
|
},
|
|
61
70
|
});
|
|
62
71
|
function withAttendees(eb) {
|
|
@@ -81,9 +90,10 @@ addRoute({
|
|
|
81
90
|
.where(sql `(${sql.ref('start')}, ${sql.ref('end')}) OVERLAPS (${sql.val(filter.start)}, ${sql.val(filter.end)})`)
|
|
82
91
|
.limit(1000)
|
|
83
92
|
.execute()
|
|
93
|
+
.then(result => result.map(withEncoded))
|
|
84
94
|
.catch(withError('Could not get events'));
|
|
85
95
|
for (const event of events)
|
|
86
|
-
event.calendar = calendar;
|
|
96
|
+
event.calendar = withEncoded(calendar);
|
|
87
97
|
return events;
|
|
88
98
|
},
|
|
89
99
|
async PUT(request, { id }) {
|
|
@@ -93,7 +103,7 @@ addRoute({
|
|
|
93
103
|
try {
|
|
94
104
|
const event = await tx
|
|
95
105
|
.insertInto('events')
|
|
96
|
-
.values({ ...init, calId: id })
|
|
106
|
+
.values({ ...withDecoded(init), calId: id })
|
|
97
107
|
.returningAll()
|
|
98
108
|
.executeTakeFirstOrThrow()
|
|
99
109
|
.catch(withError('Could not create event'));
|
|
@@ -105,7 +115,11 @@ addRoute({
|
|
|
105
115
|
.execute()
|
|
106
116
|
: []);
|
|
107
117
|
await tx.commit().execute();
|
|
108
|
-
return Object.assign(event, {
|
|
118
|
+
return Object.assign(event, {
|
|
119
|
+
attendees,
|
|
120
|
+
calendar: withEncoded(calendar),
|
|
121
|
+
color: event.color?.toString(16)?.padStart(8, '0'),
|
|
122
|
+
});
|
|
109
123
|
}
|
|
110
124
|
catch (e) {
|
|
111
125
|
await tx.rollback().execute();
|
|
@@ -128,7 +142,7 @@ addRoute({
|
|
|
128
142
|
.catch(withError('Event does not exist', 404));
|
|
129
143
|
if (event.calendar.userId != userId && event.attendees.every(a => a.userId != userId))
|
|
130
144
|
error(403, 'You do not have access to this event');
|
|
131
|
-
return event;
|
|
145
|
+
return withEncoded(event);
|
|
132
146
|
},
|
|
133
147
|
async PATCH(request, { id }) {
|
|
134
148
|
const { attendees: attendeesInit = [], sendEmails, recurrenceUpdateAll, ...init } = await parseBody(request, EventInit);
|
|
@@ -145,7 +159,7 @@ addRoute({
|
|
|
145
159
|
try {
|
|
146
160
|
const event = await tx
|
|
147
161
|
.updateTable('events')
|
|
148
|
-
.set(init)
|
|
162
|
+
.set(withDecoded(init))
|
|
149
163
|
.where('id', '=', id)
|
|
150
164
|
.returningAll()
|
|
151
165
|
.returning(withAttendees)
|
|
@@ -173,7 +187,7 @@ addRoute({
|
|
|
173
187
|
*/
|
|
174
188
|
}
|
|
175
189
|
await tx.commit().execute();
|
|
176
|
-
return event;
|
|
190
|
+
return withEncoded(event);
|
|
177
191
|
}
|
|
178
192
|
catch (e) {
|
|
179
193
|
await tx.rollback().execute();
|
|
@@ -198,7 +212,7 @@ addRoute({
|
|
|
198
212
|
.where('id', '=', id)
|
|
199
213
|
.executeTakeFirstOrThrow();
|
|
200
214
|
await tx.commit().execute();
|
|
201
|
-
return event;
|
|
215
|
+
return withEncoded(event);
|
|
202
216
|
}
|
|
203
217
|
catch (e) {
|
|
204
218
|
await tx.rollback().execute();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axium/calendar",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"author": "James Prevett <axium@jamespre.dev>",
|
|
5
5
|
"description": "Calendar for Axium",
|
|
6
6
|
"funding": {
|
|
@@ -36,10 +36,10 @@
|
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@axium/client": ">=0.14.3",
|
|
39
|
-
"@axium/core": ">=0.
|
|
39
|
+
"@axium/core": ">=0.20.0",
|
|
40
40
|
"@axium/server": ">=0.36.0",
|
|
41
41
|
"@sveltejs/kit": "^2.27.3",
|
|
42
|
-
"utilium": "^2.
|
|
42
|
+
"utilium": "^2.7.0"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"zod": "^4.0.5"
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { getEvents, type EventInitFormData } from '@axium/calendar/client';
|
|
3
|
-
import type { Event, EventData } from '@axium/calendar/common';
|
|
3
|
+
import type { Calendar, Event, EventData } from '@axium/calendar/common';
|
|
4
4
|
import { AttendeeInit, dateToInputValue, formatEventTimes, getCalPermissionsInfo, weekDaysFor } from '@axium/calendar/common';
|
|
5
|
-
import * as
|
|
5
|
+
import * as Cal from '@axium/calendar/components';
|
|
6
6
|
import { contextMenu, dynamicRows } from '@axium/client/attachments';
|
|
7
|
-
import { AccessControlDialog, FormDialog, Icon, Popover, UserDiscovery } from '@axium/client/components';
|
|
7
|
+
import { AccessControlDialog, ColorPicker, FormDialog, Icon, Popover, UserDiscovery } from '@axium/client/components';
|
|
8
8
|
import { fetchAPI } from '@axium/client/requests';
|
|
9
|
+
import { colorHashHex, encodeColor, decodeColor } from '@axium/core/color';
|
|
9
10
|
import { SvelteDate } from 'svelte/reactivity';
|
|
10
11
|
import { _throw } from 'utilium';
|
|
11
12
|
import z from 'zod';
|
|
@@ -23,6 +24,7 @@
|
|
|
23
24
|
let events = $state<Event[]>([]);
|
|
24
25
|
|
|
25
26
|
$effect(() => {
|
|
27
|
+
for (const cal of calendars) cal.color ||= encodeColor(colorHashHex(cal.name));
|
|
26
28
|
getEvents(calendars, { start: new Date(start.getTime()), end: new Date(end.getTime()) }).then(e => (events = e));
|
|
27
29
|
});
|
|
28
30
|
|
|
@@ -42,16 +44,20 @@
|
|
|
42
44
|
|
|
43
45
|
let dialogs = $state<Record<string, HTMLDialogElement>>({});
|
|
44
46
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
const defaultEventInit = {
|
|
48
|
+
attendees: [],
|
|
49
|
+
recurrenceExcludes: [],
|
|
50
|
+
recurrenceId: null,
|
|
51
|
+
calId: calendars[0]?.id,
|
|
52
|
+
} as any;
|
|
53
|
+
|
|
54
|
+
let eventInit = $state<EventData & { attendees: AttendeeInit[]; calendar?: Calendar }>(defaultEventInit),
|
|
51
55
|
eventInitStart = $derived(dateToInputValue(eventInit.start)),
|
|
52
56
|
eventInitEnd = $derived(dateToInputValue(eventInit.end)),
|
|
53
57
|
eventEditId = $state<string>(),
|
|
54
58
|
eventEditCalId = $state<string>();
|
|
59
|
+
|
|
60
|
+
const defaultEventColor = $derived((eventInit.calendar || calendars[0])?.color || encodeColor(colorHashHex(user.name)));
|
|
55
61
|
</script>
|
|
56
62
|
|
|
57
63
|
<svelte:head>
|
|
@@ -79,7 +85,7 @@
|
|
|
79
85
|
<span class="label">{weekDays[0].toLocaleString('default', { month: 'long', year: 'numeric' })}</span>
|
|
80
86
|
</div>
|
|
81
87
|
<div id="cal-list">
|
|
82
|
-
<
|
|
88
|
+
<Cal.Select bind:start bind:end />
|
|
83
89
|
<div class="cal-list-header">
|
|
84
90
|
<h4>My Calendars</h4>
|
|
85
91
|
<button style:display="contents" command="show-modal" commandfor="add-calendar">
|
|
@@ -170,7 +176,16 @@
|
|
|
170
176
|
{#snippet toggle()}
|
|
171
177
|
{@const start = event.start.getHours() * 60 + event.start.getMinutes()}
|
|
172
178
|
{@const end = event.end.getHours() * 60 + event.end.getMinutes()}
|
|
173
|
-
<div
|
|
179
|
+
<div
|
|
180
|
+
class="event"
|
|
181
|
+
style:top="{start / 14.4}%"
|
|
182
|
+
style:height="{(end - start) / 14.4}%"
|
|
183
|
+
style="--event-color:{decodeColor(
|
|
184
|
+
event.color ||
|
|
185
|
+
event.calendar!.color ||
|
|
186
|
+
encodeColor(colorHashHex(event.calendar!.name), true)
|
|
187
|
+
)}"
|
|
188
|
+
>
|
|
174
189
|
<span>{event.summary}</span>
|
|
175
190
|
<span class="subtle">{formatEventTimes(event)}</span>
|
|
176
191
|
</div>
|
|
@@ -265,7 +280,7 @@
|
|
|
265
280
|
<FormDialog
|
|
266
281
|
id="event-init"
|
|
267
282
|
clearOnCancel
|
|
268
|
-
cancel={() => (eventInit =
|
|
283
|
+
cancel={() => (eventInit = defaultEventInit)}
|
|
269
284
|
submitText={eventEditId ? 'Update' : 'Create'}
|
|
270
285
|
submit={async (data: EventInitFormData) => {
|
|
271
286
|
Object.assign(eventInit, data);
|
|
@@ -327,6 +342,7 @@
|
|
|
327
342
|
<option value={cal.id}>{cal.name}</option>
|
|
328
343
|
{/each}
|
|
329
344
|
</select>
|
|
345
|
+
<ColorPicker bind:value={eventInit.color} defaultValue={defaultEventColor} />
|
|
330
346
|
</div>
|
|
331
347
|
|
|
332
348
|
<div class="attendees-container">
|
|
@@ -598,7 +614,7 @@
|
|
|
598
614
|
position: absolute;
|
|
599
615
|
border-radius: 0.5em;
|
|
600
616
|
padding: 0.25em;
|
|
601
|
-
background-color: var(--bg-alt);
|
|
617
|
+
background-color: var(--event-color, var(--bg-alt));
|
|
602
618
|
display: flex;
|
|
603
619
|
flex-direction: column;
|
|
604
620
|
align-items: flex-start;
|