@nomideusz/svelte-calendar 0.6.9 → 0.7.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 +88 -2
- package/dist/calendar/Calendar.svelte +129 -47
- package/dist/primitives/DayHeader.svelte +5 -5
- package/dist/primitives/EmptySlot.svelte +4 -4
- package/dist/primitives/EventBlock.svelte +13 -13
- package/dist/primitives/NowIndicator.svelte +1 -1
- package/dist/primitives/TimeGutter.svelte +4 -4
- package/dist/views/agenda/AgendaDay.svelte +35 -157
- package/dist/views/agenda/AgendaWeek.svelte +20 -109
- package/dist/views/mobile/MobileDay.svelte +3 -3
- package/dist/views/mobile/MobileWeek.svelte +4 -4
- package/dist/views/planner/PlannerDay.svelte +21 -135
- package/dist/views/planner/PlannerWeek.svelte +39 -99
- package/dist/views/shared/context.svelte.d.ts +0 -1
- package/dist/views/shared/context.svelte.js +0 -1
- package/package.json +14 -14
- package/widget/svelte-calendar.css +196 -380
- package/widget/widget.js +1882 -1659
package/README.md
CHANGED
|
@@ -50,6 +50,26 @@ Hide the pills when your app controls the view externally:
|
|
|
50
50
|
<Calendar {adapter} view="day-planner" showModePills={false} />
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
+
### Custom Views
|
|
54
|
+
|
|
55
|
+
The `views` prop replaces the built-in registry. Each entry maps a view ID to a Svelte component; your component receives `events`, `mode`, `focusDate`, `locale`, and the callbacks, and can read the calendar engines via context:
|
|
56
|
+
|
|
57
|
+
```svelte
|
|
58
|
+
<script lang="ts">
|
|
59
|
+
import { Calendar, type CalendarView } from '@nomideusz/svelte-calendar';
|
|
60
|
+
import KanbanDay from './KanbanDay.svelte';
|
|
61
|
+
|
|
62
|
+
const views: CalendarView[] = [
|
|
63
|
+
{ id: 'day-kanban', label: 'Kanban', mode: 'day', component: KanbanDay },
|
|
64
|
+
{ id: 'week-kanban', label: 'Kanban', mode: 'week', component: KanbanDay },
|
|
65
|
+
];
|
|
66
|
+
</script>
|
|
67
|
+
|
|
68
|
+
<Calendar {adapter} {views} view="day-kanban" />
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Building blocks for custom views are exported as primitives: `EventBlock` (a positioned event card), `TimeGutter` (hour labels), `DayHeader`, `NowIndicator`, and `EmptySlot` (click-to-create target).
|
|
72
|
+
|
|
53
73
|
## Mobile
|
|
54
74
|
|
|
55
75
|
On narrow screens (`< 768px`), the calendar automatically remaps Planner views to touch-first Mobile views with swipe navigation, a centralized header with Day/Week pills, and a compact layout:
|
|
@@ -69,7 +89,7 @@ Mobile views include:
|
|
|
69
89
|
- **MobileDay** — vertical time grid with hour labels, swipe left/right to change days, all-day event chips at the top, tap-to-create, and stable columns for overlapping events
|
|
70
90
|
- **MobileWeek** — vertical day list showing each day's events with relative labels (Today, Tomorrow, etc.) and accessible event buttons inside each row
|
|
71
91
|
|
|
72
|
-
Agenda views keep their list-based layout on mobile
|
|
92
|
+
Agenda views keep their list-based layout on mobile; navigation stays in the calendar header on all screen sizes.
|
|
73
93
|
|
|
74
94
|
## Callbacks
|
|
75
95
|
|
|
@@ -229,6 +249,8 @@ The default `auto` preset probes the host page's design and generates a calendar
|
|
|
229
249
|
|
|
230
250
|
It also watches for changes (e.g. dark mode toggle) and updates automatically.
|
|
231
251
|
|
|
252
|
+
The probing engine is exported for standalone use: `probeHostTheme(element, options?)` returns a `--dt-*` CSS string for the page around `element`; `observeHostTheme(element, callback, options?)` re-probes on theme changes and returns a stop function.
|
|
253
|
+
|
|
232
254
|
Fine-tune auto-detection with the `autoTheme` prop:
|
|
233
255
|
|
|
234
256
|
```svelte
|
|
@@ -355,6 +377,8 @@ const palette = generatePalette('#e11d48');
|
|
|
355
377
|
const adapter = createMemoryAdapter(events, { palette });
|
|
356
378
|
```
|
|
357
379
|
|
|
380
|
+
Related exports: `VIVID_PALETTE` (the default palette) and `extractAccent(themeString)` (pull the accent color out of a `--dt-*` theme string).
|
|
381
|
+
|
|
358
382
|
### Multi-day & All-day
|
|
359
383
|
|
|
360
384
|
Events spanning multiple days or flagged `allDay: true` render in a dedicated strip above timed events:
|
|
@@ -443,6 +467,31 @@ const adapter = createRestAdapter({
|
|
|
443
467
|
|
|
444
468
|
The adapter calls `GET /events?start=...&end=...`, `POST /events`, `PATCH /events/:id`, and `DELETE /events/:id`.
|
|
445
469
|
|
|
470
|
+
## JMAP Adapter
|
|
471
|
+
|
|
472
|
+
Read events from a [JMAP Calendars](https://jmap.io/) server (Fastmail, Stalwart, Cyrus):
|
|
473
|
+
|
|
474
|
+
```ts
|
|
475
|
+
import { createJmapAdapter, type JmapClient } from '@nomideusz/svelte-calendar';
|
|
476
|
+
|
|
477
|
+
const client: JmapClient = {
|
|
478
|
+
request: (calls) =>
|
|
479
|
+
fetch('https://api.example.com/jmap', {
|
|
480
|
+
method: 'POST',
|
|
481
|
+
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
|
|
482
|
+
body: JSON.stringify({ using: ['urn:ietf:params:jmap:calendars'], methodCalls: calls }),
|
|
483
|
+
}).then((r) => r.json()),
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
const adapter = createJmapAdapter(client, {
|
|
487
|
+
getAccountId: () => accountId,
|
|
488
|
+
calendarId: 'primary', // optional: restrict to one calendar
|
|
489
|
+
timeZone: 'Europe/Warsaw', // optional: default Etc/UTC
|
|
490
|
+
});
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
Handles all-day events, ISO-duration ends, and per-calendar colors (pass `calendars` to map them).
|
|
494
|
+
|
|
446
495
|
## Mapped Adapter
|
|
447
496
|
|
|
448
497
|
Wrap any static array of external records (yoga classes, gym schedules, appointments, timetables) without writing a custom adapter. Supply a declarative field mapping — or a `mapEvent` function for full control — and the adapter handles parsing, color assignment, tag extraction, and status coercion:
|
|
@@ -561,6 +610,8 @@ For full control over rendering, skip the `<Calendar>` component and drive every
|
|
|
561
610
|
|
|
562
611
|
`cal.days` gives flat `HeadlessDay[]` with events attached; `cal.weeks` groups them into periods. `cal.todayQueue` returns `{ past, current, upcoming }` for today — updates every second via the built-in clock. `cal.hours` yields the visible hour numbers (cropped by `visibleHours`). Drag support is fully wired: `beginDragMove`, `beginDragCreate`, `updateDrag`, `commitDrag`, `cancelDrag`, plus `isDragging` / `dragPayload` / `dragMode` signals. Raw engines (`store`, `viewState`, `selection`, `dragState`, `clock`) are exposed for advanced cases.
|
|
563
612
|
|
|
613
|
+
The engine factories behind them are also exported individually — `createEventStore(adapter)`, `createViewState(options)`, `createSelection()`, `createDragState()`, `createClock()` — if you want to compose your own calendar loop instead of using `createCalendar()`.
|
|
614
|
+
|
|
564
615
|
For a simpler day-only list view, use `createAgenda()`:
|
|
565
616
|
|
|
566
617
|
```svelte
|
|
@@ -589,6 +640,8 @@ The `locale` prop controls date/time formatting (BCP 47):
|
|
|
589
640
|
<Calendar {adapter} locale="de-DE" />
|
|
590
641
|
```
|
|
591
642
|
|
|
643
|
+
`setDefaultLocale('de-DE')` sets the locale globally instead of per component (`getDefaultLocale()` reads it back, `is24HourLocale(tag)` tells you how times will format).
|
|
644
|
+
|
|
592
645
|
Override UI labels for full translation:
|
|
593
646
|
|
|
594
647
|
```ts
|
|
@@ -601,7 +654,7 @@ setLabels({
|
|
|
601
654
|
});
|
|
602
655
|
```
|
|
603
656
|
|
|
604
|
-
Call `resetLabels()` to restore English defaults.
|
|
657
|
+
Call `resetLabels()` to restore English defaults (`defaultLabels` exports them; `getLabels()` reads the active set).
|
|
605
658
|
|
|
606
659
|
<details>
|
|
607
660
|
<summary>All label keys</summary>
|
|
@@ -651,8 +704,41 @@ const utc = fromZonedTime(localDate, 'America/New_York');
|
|
|
651
704
|
|
|
652
705
|
// Current time in a timezone
|
|
653
706
|
const now = nowInZone('Asia/Tokyo');
|
|
707
|
+
|
|
708
|
+
// Format a date directly in a timezone
|
|
709
|
+
formatInTimeZone(date, 'America/New_York', { hour: '2-digit', minute: '2-digit' });
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
## Text Fitting (optional)
|
|
713
|
+
|
|
714
|
+
Event cards fit their labels using character-width heuristics. For pixel-precise fitting (long titles, narrow columns, custom fonts), initialize the optional [Pretext](https://www.npmjs.com/package/pretext) measurement engine once at app startup — everything falls back gracefully if you don't:
|
|
715
|
+
|
|
716
|
+
```svelte
|
|
717
|
+
<script>
|
|
718
|
+
import { onMount } from 'svelte';
|
|
719
|
+
import { initTextMeasure } from '@nomideusz/svelte-calendar';
|
|
720
|
+
|
|
721
|
+
onMount(() => initTextMeasure()); // resolves true if Pretext loaded
|
|
722
|
+
</script>
|
|
654
723
|
```
|
|
655
724
|
|
|
725
|
+
Custom views can measure text themselves via `createTextMeasure(options)` → `fitContent({ title, subtitle, maxWidth, maxHeight, … })`.
|
|
726
|
+
|
|
727
|
+
## Utilities
|
|
728
|
+
|
|
729
|
+
Small helpers used by the built-in views, exported for custom rendering:
|
|
730
|
+
|
|
731
|
+
| Export | Purpose |
|
|
732
|
+
|--------|---------|
|
|
733
|
+
| `fmtTime(date, locale?)` / `fmtH(hour, locale?)` | Locale-aware time / hour labels |
|
|
734
|
+
| `fmtDuration(ms)` | `"1h 30m"`-style durations |
|
|
735
|
+
| `fmtDay` / `fmtWeekRange` / `dateShort` / `dateWithWeekday` | Date labels |
|
|
736
|
+
| `weekdayShort` / `weekdayLong` / `monthShort` / `monthLong` | Name parts from a day timestamp |
|
|
737
|
+
| `startOfWeek(ms, mondayStart)` | Start-of-week timestamp |
|
|
738
|
+
| `isAllDay(ev)` / `isMultiDay(ev)` | Event classification |
|
|
739
|
+
| `segmentForDay(ev, dayMs)` | The slice of a multi-day event that falls on one day |
|
|
740
|
+
| `createClock()` | Reactive clock (`tick`, `today`) driving now-lines and relative labels |
|
|
741
|
+
|
|
656
742
|
## Embeddable Widget
|
|
657
743
|
|
|
658
744
|
Drop into any HTML page — no build tools needed. Registers a `<day-calendar>` custom element:
|
|
@@ -353,7 +353,6 @@
|
|
|
353
353
|
get snapInterval() { return snapInterval; },
|
|
354
354
|
get eventSnippet() { return eventSnippet; },
|
|
355
355
|
get emptySnippet() { return emptySnippet; },
|
|
356
|
-
get showNavigation() { return showNavigation; },
|
|
357
356
|
get equalDays() { return equalDays; },
|
|
358
357
|
get showDates() { return showDates; },
|
|
359
358
|
get hideDays() { return hideDays; },
|
|
@@ -571,23 +570,44 @@
|
|
|
571
570
|
</div>
|
|
572
571
|
{/if}
|
|
573
572
|
|
|
574
|
-
<!-- ─── Desktop
|
|
575
|
-
{:else}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
class
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
573
|
+
<!-- ─── Desktop header ─── -->
|
|
574
|
+
{:else if showNavigation || (showModePills && modes.length > 1) || dateLabel}
|
|
575
|
+
<div class="cal-hd">
|
|
576
|
+
<div class="cal-hd-side">
|
|
577
|
+
{#if navigationSnippet}
|
|
578
|
+
{@render navigationSnippet(navCtx)}
|
|
579
|
+
{:else if showNavigation}
|
|
580
|
+
{#if !viewIncludesToday}
|
|
581
|
+
<button class="cal-hd-today" onclick={() => viewState.goToday()} title={L.goToToday}>
|
|
582
|
+
{L.today}
|
|
583
|
+
</button>
|
|
584
|
+
{/if}
|
|
585
|
+
<button class="cal-hd-btn" onclick={() => viewState.prev()} aria-label={viewState.mode === 'day' ? L.previousDay : L.previousWeek}>
|
|
586
|
+
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="16" height="16" aria-hidden="true"><path d="M10 3 5 8l5 5"/></svg>
|
|
587
587
|
</button>
|
|
588
|
-
|
|
588
|
+
<button class="cal-hd-btn" onclick={() => viewState.next()} aria-label={viewState.mode === 'day' ? L.nextDay : L.nextWeek}>
|
|
589
|
+
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="16" height="16" aria-hidden="true"><path d="M6 3l5 5-5 5"/></svg>
|
|
590
|
+
</button>
|
|
591
|
+
{/if}
|
|
589
592
|
</div>
|
|
590
|
-
|
|
593
|
+
<span class="cal-hd-title">{dateLabel}</span>
|
|
594
|
+
<div class="cal-hd-side cal-hd-side--end">
|
|
595
|
+
{#if showModePills && modes.length > 1}
|
|
596
|
+
<div class="cal-pills" role="group" aria-label={L.viewMode}>
|
|
597
|
+
{#each modes as g}
|
|
598
|
+
<button
|
|
599
|
+
class="cal-pill"
|
|
600
|
+
class:cal-pill--active={viewState.mode === g}
|
|
601
|
+
aria-pressed={viewState.mode === g}
|
|
602
|
+
onclick={() => switchMode(g)}
|
|
603
|
+
>
|
|
604
|
+
{g === 'day' ? L.day : L.week}
|
|
605
|
+
</button>
|
|
606
|
+
{/each}
|
|
607
|
+
</div>
|
|
608
|
+
{/if}
|
|
609
|
+
</div>
|
|
610
|
+
</div>
|
|
591
611
|
{/if}
|
|
592
612
|
|
|
593
613
|
<div class="cal-body">
|
|
@@ -629,7 +649,7 @@
|
|
|
629
649
|
overflow: clip;
|
|
630
650
|
display: flex;
|
|
631
651
|
flex-direction: column;
|
|
632
|
-
border: 1px solid var(--dt-border, rgba(
|
|
652
|
+
border: 1px solid var(--dt-border, rgba(0, 0, 0, 0.08));
|
|
633
653
|
box-sizing: border-box;
|
|
634
654
|
}
|
|
635
655
|
.cal--auto {
|
|
@@ -638,38 +658,105 @@
|
|
|
638
658
|
}
|
|
639
659
|
|
|
640
660
|
|
|
641
|
-
/* ──
|
|
661
|
+
/* ── Desktop header ── */
|
|
662
|
+
.cal-hd {
|
|
663
|
+
display: flex;
|
|
664
|
+
align-items: center;
|
|
665
|
+
gap: 8px;
|
|
666
|
+
padding: 8px 12px;
|
|
667
|
+
min-height: 48px;
|
|
668
|
+
box-sizing: border-box;
|
|
669
|
+
border-bottom: 1px solid var(--dt-border, rgba(0, 0, 0, 0.08));
|
|
670
|
+
flex-shrink: 0;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
.cal-hd-side {
|
|
674
|
+
display: flex;
|
|
675
|
+
align-items: center;
|
|
676
|
+
gap: 4px;
|
|
677
|
+
flex: 1;
|
|
678
|
+
min-width: 0;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
.cal-hd-side--end {
|
|
682
|
+
justify-content: flex-end;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
.cal-hd-title {
|
|
686
|
+
font: 600 14px/1.2 var(--dt-sans, system-ui, sans-serif);
|
|
687
|
+
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
688
|
+
white-space: nowrap;
|
|
689
|
+
overflow: hidden;
|
|
690
|
+
text-overflow: ellipsis;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
.cal-hd-btn {
|
|
694
|
+
display: flex;
|
|
695
|
+
align-items: center;
|
|
696
|
+
justify-content: center;
|
|
697
|
+
width: 28px;
|
|
698
|
+
height: 28px;
|
|
699
|
+
border: none;
|
|
700
|
+
background: transparent;
|
|
701
|
+
color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
|
|
702
|
+
border-radius: 6px;
|
|
703
|
+
cursor: pointer;
|
|
704
|
+
transition: background 120ms, color 120ms;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.cal-hd-btn:hover {
|
|
708
|
+
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
709
|
+
background: color-mix(in srgb, var(--dt-text, rgba(0, 0, 0, 0.87)) 8%, transparent);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
.cal-hd-btn:focus-visible,
|
|
713
|
+
.cal-hd-today:focus-visible,
|
|
714
|
+
.cal-pill:focus-visible {
|
|
715
|
+
outline: 2px solid color-mix(in srgb, var(--dt-accent, #2563eb) 55%, transparent);
|
|
716
|
+
outline-offset: 2px;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
.cal-hd-today {
|
|
720
|
+
font: 500 12px/1 var(--dt-sans, system-ui, sans-serif);
|
|
721
|
+
color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
|
|
722
|
+
background: transparent;
|
|
723
|
+
border: 1px solid var(--dt-border, rgba(0, 0, 0, 0.08));
|
|
724
|
+
padding: 6px 10px;
|
|
725
|
+
border-radius: 6px;
|
|
726
|
+
cursor: pointer;
|
|
727
|
+
white-space: nowrap;
|
|
728
|
+
margin-right: 2px;
|
|
729
|
+
transition: background 120ms, color 120ms, border-color 120ms;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
.cal-hd-today:hover {
|
|
733
|
+
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
734
|
+
border-color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
|
|
735
|
+
}
|
|
736
|
+
|
|
642
737
|
.cal-pills {
|
|
643
|
-
position: absolute;
|
|
644
|
-
top: 22px;
|
|
645
|
-
bottom: auto;
|
|
646
|
-
left: 10px;
|
|
647
|
-
z-index: 20;
|
|
648
738
|
display: flex;
|
|
649
739
|
gap: 2px;
|
|
650
740
|
background: color-mix(in srgb, var(--dt-surface, var(--dt-bg, #ffffff)) 85%, transparent);
|
|
651
|
-
backdrop-filter: blur(6px);
|
|
652
|
-
-webkit-backdrop-filter: blur(6px);
|
|
653
741
|
border-radius: 8px;
|
|
654
742
|
padding: 2px;
|
|
655
|
-
border: 1px solid var(--dt-border, rgba(
|
|
743
|
+
border: 1px solid var(--dt-border, rgba(0, 0, 0, 0.08));
|
|
744
|
+
flex-shrink: 0;
|
|
656
745
|
}
|
|
657
746
|
|
|
658
747
|
.cal-pill {
|
|
659
748
|
border: none;
|
|
660
749
|
background: transparent;
|
|
661
|
-
color: var(--dt-text-2, rgba(
|
|
750
|
+
color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
|
|
662
751
|
cursor: pointer;
|
|
663
|
-
font:
|
|
664
|
-
padding:
|
|
752
|
+
font: 500 12px/1 var(--dt-sans, system-ui, sans-serif);
|
|
753
|
+
padding: 5px 12px;
|
|
665
754
|
border-radius: 6px;
|
|
666
|
-
letter-spacing: 0.04em;
|
|
667
|
-
text-transform: uppercase;
|
|
668
755
|
transition: background 100ms, color 100ms;
|
|
669
756
|
}
|
|
670
757
|
|
|
671
758
|
.cal-pill:hover {
|
|
672
|
-
color: var(--dt-text, rgba(
|
|
759
|
+
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
673
760
|
}
|
|
674
761
|
|
|
675
762
|
.cal-pill--active {
|
|
@@ -677,11 +764,6 @@
|
|
|
677
764
|
color: var(--dt-btn-text, #fff);
|
|
678
765
|
}
|
|
679
766
|
|
|
680
|
-
.cal-pill:focus-visible {
|
|
681
|
-
outline: 2px solid color-mix(in srgb, var(--dt-accent, #2563eb) 55%, transparent);
|
|
682
|
-
outline-offset: 2px;
|
|
683
|
-
}
|
|
684
|
-
|
|
685
767
|
.cal-body {
|
|
686
768
|
flex: 1;
|
|
687
769
|
min-height: 0;
|
|
@@ -698,7 +780,7 @@
|
|
|
698
780
|
justify-content: center;
|
|
699
781
|
height: 100%;
|
|
700
782
|
font: 400 13px / 1 var(--dt-sans, system-ui, sans-serif);
|
|
701
|
-
color: var(--dt-text-3, rgba(
|
|
783
|
+
color: var(--dt-text-3, rgba(0, 0, 0, 0.38));
|
|
702
784
|
}
|
|
703
785
|
|
|
704
786
|
.cal-loading {
|
|
@@ -727,7 +809,7 @@
|
|
|
727
809
|
align-items: center;
|
|
728
810
|
gap: 4px;
|
|
729
811
|
padding: 8px 8px 6px;
|
|
730
|
-
border-bottom: 1px solid var(--dt-border, rgba(
|
|
812
|
+
border-bottom: 1px solid var(--dt-border, rgba(0, 0, 0, 0.08));
|
|
731
813
|
flex-shrink: 0;
|
|
732
814
|
min-height: 44px;
|
|
733
815
|
}
|
|
@@ -752,7 +834,7 @@
|
|
|
752
834
|
height: 32px;
|
|
753
835
|
border: none;
|
|
754
836
|
background: transparent;
|
|
755
|
-
color: var(--dt-text-2, rgba(
|
|
837
|
+
color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
|
|
756
838
|
border-radius: 50%;
|
|
757
839
|
cursor: pointer;
|
|
758
840
|
transition: background 120ms, color 120ms;
|
|
@@ -760,11 +842,11 @@
|
|
|
760
842
|
flex-shrink: 0;
|
|
761
843
|
}
|
|
762
844
|
.cal-m-nav:hover {
|
|
763
|
-
color: var(--dt-text, rgba(
|
|
764
|
-
background: color-mix(in srgb, var(--dt-text, rgba(
|
|
845
|
+
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
846
|
+
background: color-mix(in srgb, var(--dt-text, rgba(0, 0, 0, 0.87)) 8%, transparent);
|
|
765
847
|
}
|
|
766
848
|
.cal-m-nav:active {
|
|
767
|
-
background: var(--dt-accent-dim, rgba(
|
|
849
|
+
background: var(--dt-accent-dim, rgba(37, 99, 235, 0.12));
|
|
768
850
|
}
|
|
769
851
|
.cal-m-nav:focus-visible {
|
|
770
852
|
outline: 2px solid color-mix(in srgb, var(--dt-accent, #2563eb) 55%, transparent);
|
|
@@ -777,13 +859,13 @@
|
|
|
777
859
|
background: color-mix(in srgb, var(--dt-surface, var(--dt-bg, #ffffff)) 85%, transparent);
|
|
778
860
|
border-radius: 8px;
|
|
779
861
|
padding: 2px;
|
|
780
|
-
border: 1px solid var(--dt-border, rgba(
|
|
862
|
+
border: 1px solid var(--dt-border, rgba(0, 0, 0, 0.08));
|
|
781
863
|
flex-shrink: 0;
|
|
782
864
|
}
|
|
783
865
|
.cal-m-pill {
|
|
784
866
|
border: none;
|
|
785
867
|
background: transparent;
|
|
786
|
-
color: var(--dt-text-2, rgba(
|
|
868
|
+
color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
|
|
787
869
|
cursor: pointer;
|
|
788
870
|
font: 600 11px / 1 var(--dt-sans, system-ui, sans-serif);
|
|
789
871
|
padding: 5px 10px;
|
|
@@ -794,7 +876,7 @@
|
|
|
794
876
|
-webkit-tap-highlight-color: transparent;
|
|
795
877
|
}
|
|
796
878
|
.cal-m-pill:hover {
|
|
797
|
-
color: var(--dt-text, rgba(
|
|
879
|
+
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
798
880
|
}
|
|
799
881
|
.cal-m-pill--active {
|
|
800
882
|
background: var(--dt-accent, #2563eb);
|
|
@@ -805,7 +887,7 @@
|
|
|
805
887
|
flex: 1;
|
|
806
888
|
text-align: center;
|
|
807
889
|
font: 600 14px / 1.2 var(--dt-sans, system-ui, sans-serif);
|
|
808
|
-
color: var(--dt-text, rgba(
|
|
890
|
+
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
809
891
|
white-space: nowrap;
|
|
810
892
|
overflow: hidden;
|
|
811
893
|
text-overflow: ellipsis;
|
|
@@ -64,18 +64,18 @@
|
|
|
64
64
|
font: 500 10px / 1 var(--dt-sans, system-ui, sans-serif);
|
|
65
65
|
letter-spacing: 0.04em;
|
|
66
66
|
text-transform: uppercase;
|
|
67
|
-
color: var(--dt-text-2, rgba(
|
|
67
|
+
color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
|
|
68
68
|
}
|
|
69
69
|
.dh-name-long {
|
|
70
70
|
font-size: 12px;
|
|
71
71
|
text-transform: none;
|
|
72
72
|
letter-spacing: 0.01em;
|
|
73
|
-
color: var(--dt-text, rgba(
|
|
73
|
+
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
.dh-num {
|
|
77
77
|
font: 600 14px / 1 var(--dt-sans, system-ui, sans-serif);
|
|
78
|
-
color: var(--dt-text, rgba(
|
|
78
|
+
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
79
79
|
width: 28px;
|
|
80
80
|
height: 28px;
|
|
81
81
|
display: flex;
|
|
@@ -90,12 +90,12 @@
|
|
|
90
90
|
|
|
91
91
|
.dh-date {
|
|
92
92
|
font: 400 10px / 1 var(--dt-sans, system-ui, sans-serif);
|
|
93
|
-
color: var(--dt-text-2, rgba(
|
|
93
|
+
color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
.dh-rel {
|
|
97
97
|
font: 500 12px / 1.3 var(--dt-sans, system-ui, sans-serif);
|
|
98
|
-
color: var(--dt-text, rgba(
|
|
98
|
+
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
99
99
|
}
|
|
100
100
|
.dh-today .dh-rel {
|
|
101
101
|
color: var(--dt-accent, #2563eb);
|
|
@@ -64,13 +64,13 @@
|
|
|
64
64
|
min-height: 24px;
|
|
65
65
|
}
|
|
66
66
|
.es:hover {
|
|
67
|
-
border-color: var(--dt-accent-dim, rgba(
|
|
68
|
-
background: var(--dt-accent-dim, rgba(
|
|
67
|
+
border-color: var(--dt-accent-dim, rgba(37, 99, 235, 0.12));
|
|
68
|
+
background: var(--dt-accent-dim, rgba(37, 99, 235, 0.12));
|
|
69
69
|
}
|
|
70
70
|
.es:focus-visible {
|
|
71
71
|
outline: 2px solid var(--dt-accent, #2563eb);
|
|
72
72
|
outline-offset: 2px;
|
|
73
|
-
border-color: var(--dt-accent-dim, rgba(
|
|
73
|
+
border-color: var(--dt-accent-dim, rgba(37, 99, 235, 0.12));
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
.es-hint {
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
}
|
|
94
94
|
.es-range {
|
|
95
95
|
font: 400 10px / 1 var(--dt-mono, 'SF Mono', monospace);
|
|
96
|
-
color: var(--dt-text-2, rgba(
|
|
96
|
+
color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
.es-v {
|
|
@@ -226,7 +226,7 @@
|
|
|
226
226
|
align-items: center;
|
|
227
227
|
gap: 5px;
|
|
228
228
|
font: 400 11px / 1 var(--dt-sans, system-ui, sans-serif);
|
|
229
|
-
color: var(--dt-text, rgba(
|
|
229
|
+
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
230
230
|
white-space: nowrap;
|
|
231
231
|
overflow: hidden;
|
|
232
232
|
text-overflow: ellipsis;
|
|
@@ -253,7 +253,7 @@
|
|
|
253
253
|
display: flex;
|
|
254
254
|
border-radius: 8px;
|
|
255
255
|
background: var(--dt-surface, var(--dt-bg, #ffffff));
|
|
256
|
-
border: 1px solid var(--dt-border, rgba(
|
|
256
|
+
border: 1px solid var(--dt-border, rgba(0, 0, 0, 0.08));
|
|
257
257
|
overflow: hidden;
|
|
258
258
|
}
|
|
259
259
|
.eb-card .eb-stripe {
|
|
@@ -270,18 +270,18 @@
|
|
|
270
270
|
}
|
|
271
271
|
.eb-card .eb-title {
|
|
272
272
|
font: 500 12px / 1.3 var(--dt-sans, system-ui, sans-serif);
|
|
273
|
-
color: var(--dt-text, rgba(
|
|
273
|
+
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
274
274
|
overflow: hidden;
|
|
275
275
|
text-overflow: ellipsis;
|
|
276
276
|
white-space: nowrap;
|
|
277
277
|
}
|
|
278
278
|
.eb-card .eb-time {
|
|
279
279
|
font: 400 10px / 1 var(--dt-mono, 'SF Mono', monospace);
|
|
280
|
-
color: var(--dt-text-2, rgba(
|
|
280
|
+
color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
|
|
281
281
|
}
|
|
282
282
|
.eb-card .eb-dur {
|
|
283
283
|
font: 300 10px / 1 var(--dt-sans, system-ui, sans-serif);
|
|
284
|
-
color: var(--dt-text-3, rgba(
|
|
284
|
+
color: var(--dt-text-3, rgba(0, 0, 0, 0.38));
|
|
285
285
|
}
|
|
286
286
|
|
|
287
287
|
/* ── Row ── */
|
|
@@ -290,7 +290,7 @@
|
|
|
290
290
|
align-items: center;
|
|
291
291
|
gap: 10px;
|
|
292
292
|
padding: 6px 12px;
|
|
293
|
-
border-bottom: 1px solid var(--dt-border, rgba(
|
|
293
|
+
border-bottom: 1px solid var(--dt-border, rgba(0, 0, 0, 0.08));
|
|
294
294
|
}
|
|
295
295
|
.eb-row .eb-stripe {
|
|
296
296
|
width: 3px;
|
|
@@ -302,13 +302,13 @@
|
|
|
302
302
|
}
|
|
303
303
|
.eb-row .eb-time {
|
|
304
304
|
font: 400 10px / 1 var(--dt-mono, 'SF Mono', monospace);
|
|
305
|
-
color: var(--dt-text-2, rgba(
|
|
305
|
+
color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
|
|
306
306
|
flex-shrink: 0;
|
|
307
307
|
width: 90px;
|
|
308
308
|
}
|
|
309
309
|
.eb-row .eb-title {
|
|
310
310
|
font: 400 12px / 1.3 var(--dt-sans, system-ui, sans-serif);
|
|
311
|
-
color: var(--dt-text, rgba(
|
|
311
|
+
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
312
312
|
flex: 1;
|
|
313
313
|
overflow: hidden;
|
|
314
314
|
text-overflow: ellipsis;
|
|
@@ -316,14 +316,14 @@
|
|
|
316
316
|
}
|
|
317
317
|
.eb-row .eb-dur {
|
|
318
318
|
font: 300 10px / 1 var(--dt-sans, system-ui, sans-serif);
|
|
319
|
-
color: var(--dt-text-3, rgba(
|
|
319
|
+
color: var(--dt-text-3, rgba(0, 0, 0, 0.38));
|
|
320
320
|
flex-shrink: 0;
|
|
321
321
|
}
|
|
322
322
|
|
|
323
323
|
/* ── Shared ── */
|
|
324
324
|
.eb-subtitle {
|
|
325
325
|
font: 400 10px / 1.2 var(--dt-sans, system-ui, sans-serif);
|
|
326
|
-
color: var(--dt-text-2, rgba(
|
|
326
|
+
color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
|
|
327
327
|
overflow: hidden;
|
|
328
328
|
text-overflow: ellipsis;
|
|
329
329
|
white-space: nowrap;
|
|
@@ -345,7 +345,7 @@
|
|
|
345
345
|
}
|
|
346
346
|
.eb-location {
|
|
347
347
|
font: 400 9px / 1.2 var(--dt-sans, system-ui, sans-serif);
|
|
348
|
-
color: var(--dt-text-3, rgba(
|
|
348
|
+
color: var(--dt-text-3, rgba(0, 0, 0, 0.38));
|
|
349
349
|
overflow: hidden;
|
|
350
350
|
text-overflow: ellipsis;
|
|
351
351
|
white-space: nowrap;
|
|
@@ -361,8 +361,8 @@
|
|
|
361
361
|
width: fit-content;
|
|
362
362
|
}
|
|
363
363
|
.eb-cancelled-badge {
|
|
364
|
-
color: var(--dt-text-2, rgba(
|
|
365
|
-
background: color-mix(in srgb, var(--dt-text-2, rgba(
|
|
364
|
+
color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
|
|
365
|
+
background: color-mix(in srgb, var(--dt-text-2, rgba(0, 0, 0, 0.54)) 15%, transparent);
|
|
366
366
|
}
|
|
367
367
|
.eb-tentative-badge {
|
|
368
368
|
color: var(--_color);
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
height: 10px;
|
|
124
124
|
border-radius: 50%;
|
|
125
125
|
background: var(--ni-color, var(--dt-accent, #2563eb));
|
|
126
|
-
box-shadow: 0 0 6px var(--ni-color, var(--dt-glow, rgba(
|
|
126
|
+
box-shadow: 0 0 6px var(--ni-color, var(--dt-glow, rgba(37, 99, 235, 0.25)));
|
|
127
127
|
}
|
|
128
128
|
.ni-dot.vertical .ni-dot-circle {
|
|
129
129
|
margin-left: -5px;
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
top: 0;
|
|
69
69
|
bottom: 0;
|
|
70
70
|
width: 0;
|
|
71
|
-
border-left: 1px solid var(--dt-border, rgba(
|
|
71
|
+
border-left: 1px solid var(--dt-border, rgba(0, 0, 0, 0.08));
|
|
72
72
|
}
|
|
73
73
|
.tg-tick-half {
|
|
74
74
|
border-left-style: dashed;
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
top: 4px;
|
|
80
80
|
left: 6px;
|
|
81
81
|
font: 400 9px / 1 var(--dt-mono, 'SF Mono', 'Fira Code', monospace);
|
|
82
|
-
color: var(--dt-text-3, rgba(
|
|
82
|
+
color: var(--dt-text-3, rgba(0, 0, 0, 0.38));
|
|
83
83
|
white-space: nowrap;
|
|
84
84
|
}
|
|
85
85
|
|
|
@@ -96,10 +96,10 @@
|
|
|
96
96
|
align-items: flex-start;
|
|
97
97
|
justify-content: flex-end;
|
|
98
98
|
padding: 2px 8px 0 0;
|
|
99
|
-
border-top: 1px solid var(--dt-border, rgba(
|
|
99
|
+
border-top: 1px solid var(--dt-border, rgba(0, 0, 0, 0.08));
|
|
100
100
|
}
|
|
101
101
|
.tg-v .tg-label {
|
|
102
102
|
font: 400 9px / 1 var(--dt-mono, 'SF Mono', 'Fira Code', monospace);
|
|
103
|
-
color: var(--dt-text-3, rgba(
|
|
103
|
+
color: var(--dt-text-3, rgba(0, 0, 0, 0.38));
|
|
104
104
|
}
|
|
105
105
|
</style>
|