@nomideusz/svelte-calendar 0.5.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +408 -178
- package/dist/adapters/memory.d.ts +7 -9
- package/dist/adapters/memory.js +8 -23
- package/dist/adapters/recurring.d.ts +3 -8
- package/dist/adapters/recurring.js +27 -30
- package/dist/calendar/Calendar.svelte +457 -46
- package/dist/calendar/Calendar.svelte.d.ts +55 -4
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +1 -1
- package/dist/core/locale.js +2 -2
- package/dist/core/palette.d.ts +5 -0
- package/dist/core/palette.js +8 -0
- package/dist/core/types.d.ts +14 -0
- package/dist/engine/event-store.svelte.d.ts +0 -17
- package/dist/engine/event-store.svelte.js +30 -17
- package/dist/engine/index.d.ts +1 -1
- package/dist/engine/view-state.svelte.d.ts +10 -5
- package/dist/engine/view-state.svelte.js +32 -16
- package/dist/index.d.ts +7 -7
- package/dist/index.js +3 -4
- package/dist/theme/auto.d.ts +53 -0
- package/dist/theme/auto.js +534 -0
- package/dist/theme/index.d.ts +3 -1
- package/dist/theme/index.js +3 -1
- package/dist/theme/presets.d.ts +20 -6
- package/dist/theme/presets.js +19 -6
- package/dist/views/agenda/AgendaDay.svelte +116 -37
- package/dist/views/agenda/AgendaWeek.svelte +219 -70
- package/dist/views/agenda/index.d.ts +0 -2
- package/dist/views/agenda/index.js +0 -2
- package/dist/views/index.d.ts +3 -2
- package/dist/views/index.js +3 -2
- package/dist/views/mobile/Mobile.svelte +17 -0
- package/dist/views/mobile/Mobile.svelte.d.ts +7 -0
- package/dist/views/mobile/MobileDay.svelte +665 -0
- package/dist/views/mobile/MobileDay.svelte.d.ts +20 -0
- package/dist/views/mobile/MobileWeek.svelte +456 -0
- package/dist/views/mobile/MobileWeek.svelte.d.ts +20 -0
- package/dist/views/mobile/index.d.ts +1 -0
- package/dist/views/mobile/index.js +1 -0
- package/dist/views/planner/PlannerDay.svelte +144 -10
- package/dist/views/planner/PlannerWeek.svelte +145 -40
- package/dist/widget/CalendarWidget.svelte +2 -17
- package/package.json +2 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
/**
|
|
3
|
-
* AgendaWeek — rolling
|
|
3
|
+
* AgendaWeek — rolling N-day agenda view.
|
|
4
4
|
*
|
|
5
5
|
* "The Week Ahead":
|
|
6
6
|
* Today + tomorrow expanded with time slots/countdowns.
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Answers: "What's coming up and when do I need to be ready?"
|
|
11
11
|
*/
|
|
12
|
-
import { getContext } from 'svelte';
|
|
12
|
+
import { getContext, type Snippet } from 'svelte';
|
|
13
13
|
import { createClock } from '../../core/clock.svelte.js';
|
|
14
14
|
import type { TimelineEvent } from '../../core/types.js';
|
|
15
15
|
import { sod, DAY_MS, startOfWeek, dayNum, isAllDay, isMultiDay } from '../../core/time.js';
|
|
16
|
-
import { weekdayLong,
|
|
16
|
+
import { weekdayLong, monthLong, fmtTime as _fmtTime, fmtDuration, getLabels } from '../../core/locale.js';
|
|
17
17
|
import type { ViewState } from '../../engine/view-state.svelte.js';
|
|
18
18
|
|
|
19
19
|
const L = $derived(getLabels());
|
|
@@ -43,6 +43,47 @@
|
|
|
43
43
|
|
|
44
44
|
const clock = createClock();
|
|
45
45
|
const viewState = getContext<ViewState>('calendar:viewState') as ViewState | undefined;
|
|
46
|
+
const showNavCtx = getContext<{ current: boolean }>('calendar:showNavigation') as { current: boolean } | undefined;
|
|
47
|
+
const equalDaysCtx = getContext<{ current: boolean }>('calendar:equalDays') as { current: boolean } | undefined;
|
|
48
|
+
const showDatesCtx = getContext<{ current: boolean }>('calendar:showDates') as { current: boolean } | undefined;
|
|
49
|
+
const hideDaysCtx = getContext<{ current: number[] | undefined }>('calendar:hideDays') as { current: number[] | undefined } | undefined;
|
|
50
|
+
const mobileCtx = getContext<{ current: boolean }>('calendar:mobile') as { current: boolean } | undefined;
|
|
51
|
+
const showNav = $derived(showNavCtx?.current ?? true);
|
|
52
|
+
const equalDays = $derived(equalDaysCtx?.current ?? false);
|
|
53
|
+
const showDates = $derived(showDatesCtx?.current ?? true);
|
|
54
|
+
const hideDays = $derived(hideDaysCtx?.current);
|
|
55
|
+
const isMobile = $derived(mobileCtx?.current ?? false);
|
|
56
|
+
|
|
57
|
+
// ── Swipe navigation (mobile) ──────────────────────
|
|
58
|
+
let swipeStartX = 0;
|
|
59
|
+
let swipeStartY = 0;
|
|
60
|
+
const SWIPE_THRESHOLD = 50;
|
|
61
|
+
|
|
62
|
+
function onPointerDown(e: PointerEvent) {
|
|
63
|
+
if (!isMobile) return;
|
|
64
|
+
swipeStartX = e.clientX;
|
|
65
|
+
swipeStartY = e.clientY;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function onPointerUp(e: PointerEvent) {
|
|
69
|
+
if (!isMobile) return;
|
|
70
|
+
const dx = e.clientX - swipeStartX;
|
|
71
|
+
const dy = e.clientY - swipeStartY;
|
|
72
|
+
if (Math.abs(dx) > SWIPE_THRESHOLD && Math.abs(dx) > Math.abs(dy) * 1.4) {
|
|
73
|
+
if (dx > 0) viewState?.prev();
|
|
74
|
+
else viewState?.next();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ── New feature contexts ──
|
|
79
|
+
const dayHeaderSnippetCtx = getContext<{ current: Snippet<[{ date: Date; isToday: boolean; dayName: string }]> | undefined }>('calendar:dayHeaderSnippet') as { current: Snippet<[{ date: Date; isToday: boolean; dayName: string }]> | undefined } | undefined;
|
|
80
|
+
const callbacksCtx = getContext<{ oneventhover?: (event: TimelineEvent) => void }>('calendar:callbacks') as { oneventhover?: (event: TimelineEvent) => void } | undefined;
|
|
81
|
+
const disabledDatesCtx = getContext<{ current: Date[] | undefined }>('calendar:disabledDates') as { current: Date[] | undefined } | undefined;
|
|
82
|
+
|
|
83
|
+
const dayHeaderSnippet = $derived(dayHeaderSnippetCtx?.current);
|
|
84
|
+
const oneventhover = $derived(callbacksCtx?.oneventhover);
|
|
85
|
+
const disabledDates = $derived(disabledDatesCtx?.current);
|
|
86
|
+
const disabledSet = $derived(new Set(disabledDates?.map(d => sod(d.getTime())) ?? []));
|
|
46
87
|
|
|
47
88
|
// ── Format helpers ──────────────────────────────────
|
|
48
89
|
function fmtTime(d: Date): string {
|
|
@@ -128,12 +169,20 @@
|
|
|
128
169
|
|
|
129
170
|
const weekStartMs = $derived(
|
|
130
171
|
focusDate
|
|
131
|
-
?
|
|
132
|
-
|
|
172
|
+
? (viewState?.dayCount === 7
|
|
173
|
+
? startOfWeek(sod(focusDate.getTime()), mondayStart)
|
|
174
|
+
: sod(focusDate.getTime()))
|
|
175
|
+
: (viewState?.dayCount === 7
|
|
176
|
+
? startOfWeek(clock.today, mondayStart)
|
|
177
|
+
: clock.today),
|
|
133
178
|
);
|
|
134
179
|
|
|
180
|
+
const customDays = $derived(viewState?.dayCount ?? 7);
|
|
181
|
+
|
|
135
182
|
const isThisWeek = $derived(
|
|
136
|
-
|
|
183
|
+
customDays === 7
|
|
184
|
+
? weekStartMs === startOfWeek(clock.today, mondayStart)
|
|
185
|
+
: clock.today >= weekStartMs && clock.today < weekStartMs + customDays * DAY_MS,
|
|
137
186
|
);
|
|
138
187
|
|
|
139
188
|
const weekDays = $derived.by((): DayGroup[] => {
|
|
@@ -141,7 +190,7 @@
|
|
|
141
190
|
const todayMs = clock.today;
|
|
142
191
|
const tomorrowMs = todayMs + DAY_MS;
|
|
143
192
|
const out: DayGroup[] = [];
|
|
144
|
-
for (let i = 0; i <
|
|
193
|
+
for (let i = 0; i < customDays; i++) {
|
|
145
194
|
const ms = weekStartMs + i * DAY_MS;
|
|
146
195
|
const dEnd = ms + DAY_MS;
|
|
147
196
|
const dayEvts = events
|
|
@@ -163,15 +212,22 @@
|
|
|
163
212
|
else upcomingEvents.push(ev);
|
|
164
213
|
}
|
|
165
214
|
let tier: DayTier;
|
|
166
|
-
if (
|
|
167
|
-
|
|
168
|
-
else if (ms
|
|
169
|
-
|
|
215
|
+
if (equalDays) {
|
|
216
|
+
tier = 'upcoming';
|
|
217
|
+
} else if (ms === todayMs) {
|
|
218
|
+
tier = 'today';
|
|
219
|
+
} else if (ms === tomorrowMs) {
|
|
220
|
+
tier = 'tomorrow';
|
|
221
|
+
} else if (ms < todayMs) {
|
|
222
|
+
tier = 'past';
|
|
223
|
+
} else {
|
|
224
|
+
tier = 'upcoming';
|
|
225
|
+
}
|
|
170
226
|
|
|
171
227
|
out.push({
|
|
172
228
|
ms,
|
|
173
|
-
dayName:
|
|
174
|
-
dateLabel: `${
|
|
229
|
+
dayName: weekdayLong(ms, locale),
|
|
230
|
+
dateLabel: `${monthLong(ms, locale)} ${dayNum(ms)}`,
|
|
175
231
|
tier,
|
|
176
232
|
events: dayEvts,
|
|
177
233
|
allDayEvents: allDayEvts,
|
|
@@ -182,12 +238,22 @@
|
|
|
182
238
|
totalHours: Math.round((totalMinutes / 60) * 10) / 10,
|
|
183
239
|
});
|
|
184
240
|
}
|
|
241
|
+
|
|
242
|
+
// Filter hidden days if hideDays is set
|
|
243
|
+
if (hideDays?.length) {
|
|
244
|
+
return out.filter((d) => {
|
|
245
|
+
const jsDay = new Date(d.ms).getDay();
|
|
246
|
+
const iso = jsDay === 0 ? 7 : jsDay;
|
|
247
|
+
return !hideDays.includes(iso);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
185
251
|
return out;
|
|
186
252
|
});
|
|
187
253
|
</script>
|
|
188
254
|
|
|
189
255
|
<!-- ═══ Shared event card snippet ═══ -->
|
|
190
|
-
{#snippet eventCard(ev: TimelineEvent, isNow: boolean)}
|
|
256
|
+
{#snippet eventCard(ev: TimelineEvent, isNow: boolean, eta?: string)}
|
|
191
257
|
<div
|
|
192
258
|
class="ag-card"
|
|
193
259
|
class:ag-card--selected={selectedEventId === ev.id}
|
|
@@ -196,9 +262,9 @@
|
|
|
196
262
|
tabindex="0"
|
|
197
263
|
aria-label="{ev.title}, {fmtTime(ev.start)} to {fmtTime(ev.end)}, {duration(ev)}"
|
|
198
264
|
onclick={() => handleClick(ev)}
|
|
265
|
+
onpointerenter={() => oneventhover?.(ev)}
|
|
199
266
|
onkeydown={(e) => handleKeydown(e, ev)}
|
|
200
267
|
>
|
|
201
|
-
<div class="ag-card-stripe"></div>
|
|
202
268
|
<div class="ag-card-body">
|
|
203
269
|
<span class="ag-card-title">{ev.title}</span>
|
|
204
270
|
{#if ev.subtitle}
|
|
@@ -211,6 +277,9 @@
|
|
|
211
277
|
{fmtTime(ev.start)} – {fmtTime(ev.end)}
|
|
212
278
|
{/if}
|
|
213
279
|
<span class="ag-card-dur">{duration(ev)}</span>
|
|
280
|
+
{#if eta}
|
|
281
|
+
<span class="ag-card-eta">{eta}</span>
|
|
282
|
+
{/if}
|
|
214
283
|
</span>
|
|
215
284
|
{#if ev.tags?.length}
|
|
216
285
|
<div class="ag-card-tags">
|
|
@@ -228,24 +297,30 @@
|
|
|
228
297
|
</div>
|
|
229
298
|
{/snippet}
|
|
230
299
|
|
|
300
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
231
301
|
<div
|
|
232
302
|
class="ag ag--week"
|
|
303
|
+
class:ag--mobile={isMobile}
|
|
233
304
|
style={style || undefined}
|
|
305
|
+
onpointerdown={onPointerDown}
|
|
306
|
+
onpointerup={onPointerUp}
|
|
234
307
|
>
|
|
235
308
|
<div class="ag-body" role="list" aria-label={L.weekAhead}>
|
|
236
309
|
{#each weekDays as day (day.ms)}
|
|
237
310
|
{@const expanded = day.tier === 'today' || day.tier === 'tomorrow'}
|
|
238
311
|
{#if day.tier === 'past'}
|
|
239
312
|
<!-- Past day: single collapsed line -->
|
|
240
|
-
<div class="ag-wday ag-wday--past" role="listitem">
|
|
313
|
+
<div class="ag-wday ag-wday--past" class:ag-wday--disabled={disabledSet.has(day.ms)} role="listitem">
|
|
241
314
|
<div class="ag-wday-head">
|
|
242
315
|
<div class="ag-wday-head-left">
|
|
243
316
|
<span class="ag-wday-name">{day.dayName}</span>
|
|
244
|
-
|
|
245
|
-
{#if day.events.length > 0}
|
|
246
|
-
<span class="ag-wday-done">✓ {day.events.length}</span>
|
|
247
|
-
{/if}
|
|
317
|
+
{#if showDates}<span class="ag-wday-date">{day.dateLabel}</span>{/if}
|
|
248
318
|
</div>
|
|
319
|
+
{#if dayHeaderSnippet}
|
|
320
|
+
<div class="ag-wday-custom-header">
|
|
321
|
+
{@render dayHeaderSnippet({ date: new Date(day.ms), isToday: false, dayName: day.dayName })}
|
|
322
|
+
</div>
|
|
323
|
+
{/if}
|
|
249
324
|
</div>
|
|
250
325
|
</div>
|
|
251
326
|
{:else}
|
|
@@ -253,6 +328,8 @@
|
|
|
253
328
|
class="ag-wday"
|
|
254
329
|
class:ag-wday--today={day.tier === 'today'}
|
|
255
330
|
class:ag-wday--tomorrow={day.tier === 'tomorrow'}
|
|
331
|
+
class:ag-wday--equal={equalDays}
|
|
332
|
+
class:ag-wday--disabled={disabledSet.has(day.ms)}
|
|
256
333
|
role="listitem"
|
|
257
334
|
>
|
|
258
335
|
<!-- Day header -->
|
|
@@ -264,8 +341,13 @@
|
|
|
264
341
|
<span class="ag-wday-badge ag-wday-badge--muted">{L.tomorrow}</span>
|
|
265
342
|
{/if}
|
|
266
343
|
<span class="ag-wday-name">{day.dayName}</span>
|
|
267
|
-
<span class="ag-wday-date">{day.dateLabel}</span>
|
|
344
|
+
{#if showDates}<span class="ag-wday-date">{day.dateLabel}</span>{/if}
|
|
268
345
|
</div>
|
|
346
|
+
{#if dayHeaderSnippet}
|
|
347
|
+
<div class="ag-wday-custom-header">
|
|
348
|
+
{@render dayHeaderSnippet({ date: new Date(day.ms), isToday: day.tier === 'today', dayName: day.dayName })}
|
|
349
|
+
</div>
|
|
350
|
+
{/if}
|
|
269
351
|
</div>
|
|
270
352
|
|
|
271
353
|
{#if day.allDayEvents.length > 0}
|
|
@@ -279,6 +361,7 @@
|
|
|
279
361
|
tabindex="0"
|
|
280
362
|
aria-label="{ev.title}, {L.allDay}"
|
|
281
363
|
onclick={() => handleClick(ev)}
|
|
364
|
+
onpointerenter={() => oneventhover?.(ev)}
|
|
282
365
|
onkeydown={(e) => handleKeydown(e, ev)}
|
|
283
366
|
>
|
|
284
367
|
<span class="ag-allday-dot"></span>
|
|
@@ -290,6 +373,20 @@
|
|
|
290
373
|
|
|
291
374
|
{#if day.events.length === 0}
|
|
292
375
|
<div class="ag-wday-empty">{L.noEvents}</div>
|
|
376
|
+
{:else if equalDays}
|
|
377
|
+
<!-- Equal days: card layout for all days, no time-relative badges -->
|
|
378
|
+
<div class="ag-wday-expanded">
|
|
379
|
+
{#each groupIntoSlots(day.timedEvents) as slot (slot.startMs)}
|
|
380
|
+
<div class="ag-wslot">
|
|
381
|
+
|
|
382
|
+
<div class="ag-wslot-cards" class:ag-wslot-cards--multi={slot.events.length > 1}>
|
|
383
|
+
{#each slot.events as ev (ev.id)}
|
|
384
|
+
{@render eventCard(ev, false)}
|
|
385
|
+
{/each}
|
|
386
|
+
</div>
|
|
387
|
+
</div>
|
|
388
|
+
{/each}
|
|
389
|
+
</div>
|
|
293
390
|
{:else if expanded}
|
|
294
391
|
<!-- Expanded: today/tomorrow get full slot treatment -->
|
|
295
392
|
<div class="ag-wday-expanded">
|
|
@@ -305,15 +402,10 @@
|
|
|
305
402
|
{/if}
|
|
306
403
|
{#each groupIntoSlots(day.upcomingEvents) as slot (slot.startMs)}
|
|
307
404
|
<div class="ag-wslot">
|
|
308
|
-
|
|
309
|
-
<span class="ag-wslot-time">{fmtTime(new Date(slot.startMs))}</span>
|
|
310
|
-
{#if day.tier === 'today'}
|
|
311
|
-
<span class="ag-wslot-eta">{timeUntilMs(slot.startMs)}</span>
|
|
312
|
-
{/if}
|
|
313
|
-
</div>
|
|
405
|
+
|
|
314
406
|
<div class="ag-wslot-cards" class:ag-wslot-cards--multi={slot.events.length > 1}>
|
|
315
407
|
{#each slot.events as ev (ev.id)}
|
|
316
|
-
{@render eventCard(ev, false)}
|
|
408
|
+
{@render eventCard(ev, false, day.tier === 'today' ? timeUntilMs(ev.start.getTime()) : undefined)}
|
|
317
409
|
{/each}
|
|
318
410
|
</div>
|
|
319
411
|
</div>
|
|
@@ -325,7 +417,7 @@
|
|
|
325
417
|
{:else}
|
|
326
418
|
<!-- Compact: future days get minimal rows -->
|
|
327
419
|
<div class="ag-wday-compact">
|
|
328
|
-
{#each day.
|
|
420
|
+
{#each day.timedEvents.slice(0, 4) as ev (ev.id)}
|
|
329
421
|
<div
|
|
330
422
|
class="ag-compact"
|
|
331
423
|
class:ag-compact--selected={selectedEventId === ev.id}
|
|
@@ -333,8 +425,7 @@
|
|
|
333
425
|
role="button"
|
|
334
426
|
tabindex="0"
|
|
335
427
|
aria-label="{ev.title}, {fmtTime(ev.start)}, {duration(ev)}"
|
|
336
|
-
onclick={() => handleClick(ev)}
|
|
337
|
-
onkeydown={(e) => handleKeydown(e, ev)}
|
|
428
|
+
onclick={() => handleClick(ev)} onpointerenter={() => oneventhover?.(ev)} onkeydown={(e) => handleKeydown(e, ev)}
|
|
338
429
|
>
|
|
339
430
|
<span class="ag-compact-dot"></span>
|
|
340
431
|
<span class="ag-compact-time">{fmtTime(ev.start)}</span>
|
|
@@ -350,8 +441,8 @@
|
|
|
350
441
|
<span class="ag-compact-dur">{duration(ev)}</span>
|
|
351
442
|
</div>
|
|
352
443
|
{/each}
|
|
353
|
-
{#if day.
|
|
354
|
-
<div class="ag-compact-more">{L.nMore(day.
|
|
444
|
+
{#if day.timedEvents.length > 4}
|
|
445
|
+
<div class="ag-compact-more">{L.nMore(day.timedEvents.length - 4)}</div>
|
|
355
446
|
{/if}
|
|
356
447
|
</div>
|
|
357
448
|
{/if}
|
|
@@ -360,7 +451,8 @@
|
|
|
360
451
|
{/each}
|
|
361
452
|
</div>
|
|
362
453
|
|
|
363
|
-
<!-- ── Floating nav pills ── -->
|
|
454
|
+
<!-- ── Floating nav pills (desktop only — mobile uses Calendar header) ── -->
|
|
455
|
+
{#if showNav && !isMobile}
|
|
364
456
|
<nav class="ag-nav" aria-label={L.weekNavigation}>
|
|
365
457
|
<button
|
|
366
458
|
class="ag-nav-pill ag-nav-today"
|
|
@@ -386,6 +478,7 @@
|
|
|
386
478
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="12" height="12" aria-hidden="true"><path d="M6 3l5 5-5 5"/></svg>
|
|
387
479
|
</button>
|
|
388
480
|
</nav>
|
|
481
|
+
{/if}
|
|
389
482
|
</div>
|
|
390
483
|
|
|
391
484
|
<style>
|
|
@@ -514,15 +607,16 @@
|
|
|
514
607
|
.ag-card {
|
|
515
608
|
display: flex;
|
|
516
609
|
align-items: stretch;
|
|
517
|
-
border-radius:
|
|
518
|
-
background: var(--dt-surface, #191919);
|
|
519
|
-
border: 1px solid var(--dt-border, rgba(255, 255, 255, 0.06));
|
|
610
|
+
border-radius: 6px;
|
|
611
|
+
background: color-mix(in srgb, var(--ev-color) 12%, var(--dt-surface, #191919));
|
|
612
|
+
border: 1px solid color-mix(in srgb, var(--ev-color) 8%, var(--dt-border, rgba(255, 255, 255, 0.06)));
|
|
520
613
|
overflow: hidden;
|
|
521
614
|
cursor: pointer;
|
|
522
|
-
transition: border-color 150ms;
|
|
615
|
+
transition: background 150ms, border-color 150ms;
|
|
523
616
|
}
|
|
524
617
|
.ag-card:hover {
|
|
525
|
-
|
|
618
|
+
background: color-mix(in srgb, var(--ev-color) 20%, var(--dt-surface, #191919));
|
|
619
|
+
border-color: color-mix(in srgb, var(--ev-color) 30%, transparent);
|
|
526
620
|
}
|
|
527
621
|
.ag-card:focus-visible {
|
|
528
622
|
outline: 2px solid var(--dt-accent, #ff6b4a);
|
|
@@ -530,18 +624,13 @@
|
|
|
530
624
|
}
|
|
531
625
|
.ag-card--selected {
|
|
532
626
|
border-color: var(--ev-color);
|
|
533
|
-
background: color-mix(in srgb, var(--ev-color)
|
|
534
|
-
}
|
|
535
|
-
.ag-card-stripe {
|
|
536
|
-
width: 3px;
|
|
537
|
-
background: var(--ev-color, var(--dt-accent));
|
|
538
|
-
flex-shrink: 0;
|
|
627
|
+
background: color-mix(in srgb, var(--ev-color) 20%, var(--dt-surface, #191919));
|
|
539
628
|
}
|
|
540
629
|
.ag-card-body {
|
|
541
|
-
padding: 10px
|
|
630
|
+
padding: 7px 10px;
|
|
542
631
|
display: flex;
|
|
543
632
|
flex-direction: column;
|
|
544
|
-
gap:
|
|
633
|
+
gap: 2px;
|
|
545
634
|
min-width: 0;
|
|
546
635
|
flex: 1;
|
|
547
636
|
}
|
|
@@ -555,6 +644,8 @@
|
|
|
555
644
|
flex: 1;
|
|
556
645
|
}
|
|
557
646
|
.ag-card-meta {
|
|
647
|
+
display: flex;
|
|
648
|
+
align-items: center;
|
|
558
649
|
font-size: 11px;
|
|
559
650
|
color: var(--dt-text-2, rgba(255, 255, 255, 0.5));
|
|
560
651
|
font-family: var(--dt-mono, monospace);
|
|
@@ -564,6 +655,14 @@
|
|
|
564
655
|
margin-left: 6px;
|
|
565
656
|
color: var(--dt-text-3, rgba(255, 255, 255, 0.3));
|
|
566
657
|
}
|
|
658
|
+
.ag-card-eta {
|
|
659
|
+
margin-left: auto;
|
|
660
|
+
font-size: 10px;
|
|
661
|
+
font-weight: 600;
|
|
662
|
+
color: color-mix(in srgb, var(--ev-color) 80%, var(--dt-text));
|
|
663
|
+
opacity: 0.85;
|
|
664
|
+
letter-spacing: 0.02em;
|
|
665
|
+
}
|
|
567
666
|
.ag-card-sub {
|
|
568
667
|
font-size: 11px;
|
|
569
668
|
color: var(--dt-text-2, rgba(255, 255, 255, 0.45));
|
|
@@ -601,19 +700,39 @@
|
|
|
601
700
|
border-bottom: 1px solid var(--dt-border, rgba(255, 255, 255, 0.06));
|
|
602
701
|
}
|
|
603
702
|
.ag-wday--today {
|
|
604
|
-
background: color-mix(in srgb, var(--dt-accent, #ff6b4a)
|
|
703
|
+
background: color-mix(in srgb, var(--dt-accent, #ff6b4a) 2%, transparent);
|
|
704
|
+
}
|
|
705
|
+
.ag-wday--tomorrow .ag-card {
|
|
706
|
+
opacity: 0.82;
|
|
605
707
|
}
|
|
606
708
|
.ag-wday--past {
|
|
607
|
-
opacity: 0.
|
|
709
|
+
opacity: 0.4;
|
|
608
710
|
}
|
|
609
711
|
.ag-wday--past .ag-wday-head {
|
|
610
|
-
padding:
|
|
712
|
+
padding: 8px 20px;
|
|
611
713
|
}
|
|
612
|
-
.ag-wday
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
714
|
+
.ag-wday--disabled {
|
|
715
|
+
opacity: 0.35;
|
|
716
|
+
pointer-events: none;
|
|
717
|
+
position: relative;
|
|
718
|
+
}
|
|
719
|
+
.ag-wday--disabled::after {
|
|
720
|
+
content: '';
|
|
721
|
+
position: absolute;
|
|
722
|
+
inset: 0;
|
|
723
|
+
background: repeating-linear-gradient(
|
|
724
|
+
135deg,
|
|
725
|
+
transparent,
|
|
726
|
+
transparent 4px,
|
|
727
|
+
rgba(128, 128, 128, 0.08) 4px,
|
|
728
|
+
rgba(128, 128, 128, 0.08) 8px
|
|
729
|
+
);
|
|
730
|
+
pointer-events: none;
|
|
616
731
|
}
|
|
732
|
+
.ag-wday-custom-header {
|
|
733
|
+
padding: 2px 0 4px;
|
|
734
|
+
}
|
|
735
|
+
|
|
617
736
|
.ag-wday-head {
|
|
618
737
|
display: flex;
|
|
619
738
|
justify-content: space-between;
|
|
@@ -652,29 +771,26 @@
|
|
|
652
771
|
font-family: var(--dt-mono, monospace);
|
|
653
772
|
color: var(--dt-text-3, rgba(255, 255, 255, 0.3));
|
|
654
773
|
}
|
|
774
|
+
|
|
655
775
|
.ag-wday-empty {
|
|
656
|
-
padding:
|
|
657
|
-
font-size:
|
|
658
|
-
color: var(--dt-text-3, rgba(255, 255, 255, 0.
|
|
776
|
+
padding: 2px 20px 10px;
|
|
777
|
+
font-size: 11px;
|
|
778
|
+
color: var(--dt-text-3, rgba(255, 255, 255, 0.2));
|
|
779
|
+
font-style: italic;
|
|
659
780
|
}
|
|
660
781
|
|
|
661
782
|
/* Expanded day */
|
|
662
783
|
.ag-wday-expanded {
|
|
663
|
-
padding: 0 20px
|
|
784
|
+
padding: 0 20px 10px;
|
|
664
785
|
}
|
|
665
786
|
.ag-wslot {
|
|
666
|
-
margin-bottom:
|
|
787
|
+
margin-bottom: 4px;
|
|
667
788
|
}
|
|
668
789
|
.ag-wslot-header {
|
|
669
790
|
display: flex;
|
|
670
791
|
align-items: baseline;
|
|
671
792
|
gap: 8px;
|
|
672
|
-
padding:
|
|
673
|
-
}
|
|
674
|
-
.ag-wslot-time {
|
|
675
|
-
font-size: 12px;
|
|
676
|
-
font-weight: 600;
|
|
677
|
-
font-family: var(--dt-mono, monospace);
|
|
793
|
+
padding: 2px 0;
|
|
678
794
|
}
|
|
679
795
|
.ag-wslot-now {
|
|
680
796
|
font-size: 9px;
|
|
@@ -683,11 +799,6 @@
|
|
|
683
799
|
text-transform: uppercase;
|
|
684
800
|
color: var(--dt-accent, #ff6b4a);
|
|
685
801
|
}
|
|
686
|
-
.ag-wslot-eta {
|
|
687
|
-
font-size: 11px;
|
|
688
|
-
font-weight: 500;
|
|
689
|
-
color: var(--dt-accent, #ff6b4a);
|
|
690
|
-
}
|
|
691
802
|
.ag-wslot-cards {
|
|
692
803
|
display: flex;
|
|
693
804
|
flex-direction: column;
|
|
@@ -716,6 +827,12 @@
|
|
|
716
827
|
padding: 4px 0;
|
|
717
828
|
cursor: pointer;
|
|
718
829
|
}
|
|
830
|
+
.ag-compact--selected {
|
|
831
|
+
background: color-mix(in srgb, var(--ev-color) 10%, transparent);
|
|
832
|
+
border-radius: 4px;
|
|
833
|
+
padding-left: 6px;
|
|
834
|
+
padding-right: 6px;
|
|
835
|
+
}
|
|
719
836
|
.ag-compact:hover .ag-compact-title {
|
|
720
837
|
color: var(--dt-text);
|
|
721
838
|
}
|
|
@@ -772,4 +889,36 @@
|
|
|
772
889
|
color: var(--dt-text-3);
|
|
773
890
|
padding: 2px 0 0 13px;
|
|
774
891
|
}
|
|
892
|
+
|
|
893
|
+
/* ═══ Mobile adaptations ═══ */
|
|
894
|
+
.ag--mobile .ag-wday-head {
|
|
895
|
+
padding: 12px 16px;
|
|
896
|
+
}
|
|
897
|
+
.ag--mobile .ag-wday-expanded {
|
|
898
|
+
padding: 0 16px 12px;
|
|
899
|
+
}
|
|
900
|
+
.ag--mobile .ag-wday-compact {
|
|
901
|
+
padding: 0 16px 12px;
|
|
902
|
+
}
|
|
903
|
+
.ag--mobile .ag-card-body {
|
|
904
|
+
padding: 12px 14px;
|
|
905
|
+
}
|
|
906
|
+
.ag--mobile .ag-card-title {
|
|
907
|
+
font-size: 14px;
|
|
908
|
+
}
|
|
909
|
+
.ag--mobile .ag-compact {
|
|
910
|
+
padding: 8px 0;
|
|
911
|
+
}
|
|
912
|
+
.ag--mobile .ag-compact-title {
|
|
913
|
+
font-size: 14px;
|
|
914
|
+
}
|
|
915
|
+
.ag--mobile .ag-compact-time {
|
|
916
|
+
font-size: 12px;
|
|
917
|
+
}
|
|
918
|
+
.ag--mobile .ag-nav-pill {
|
|
919
|
+
padding: 10px 16px;
|
|
920
|
+
}
|
|
921
|
+
.ag--mobile .ag-wslot-cards--multi {
|
|
922
|
+
grid-template-columns: 1fr;
|
|
923
|
+
}
|
|
775
924
|
</style>
|
package/dist/views/index.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export { Planner } from './planner/
|
|
2
|
-
export {
|
|
1
|
+
export { default as Planner } from './planner/Planner.svelte';
|
|
2
|
+
export { default as Agenda } from './agenda/Agenda.svelte';
|
|
3
|
+
export { default as Mobile } from './mobile/Mobile.svelte';
|
package/dist/views/index.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export { Planner } from './planner/
|
|
2
|
-
export {
|
|
1
|
+
export { default as Planner } from './planner/Planner.svelte';
|
|
2
|
+
export { default as Agenda } from './agenda/Agenda.svelte';
|
|
3
|
+
export { default as Mobile } from './mobile/Mobile.svelte';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import MobileDay from './MobileDay.svelte';
|
|
3
|
+
import MobileWeek from './MobileWeek.svelte';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
mode?: 'day' | 'week';
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let { mode = 'day', ...rest }: Props = $props();
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
{#if mode === 'day'}
|
|
14
|
+
<MobileDay {...rest} />
|
|
15
|
+
{:else}
|
|
16
|
+
<MobileWeek {...rest} />
|
|
17
|
+
{/if}
|