@nomideusz/svelte-calendar 1.1.1 → 1.3.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 +10 -5
- package/dist/calendar/Calendar.svelte +202 -296
- package/dist/theme/presets.d.ts +2 -2
- package/dist/theme/presets.js +2 -2
- package/dist/views/agenda/AgendaDay.svelte +162 -278
- package/dist/views/agenda/AgendaWeek.svelte +113 -191
- package/dist/views/mobile/MobileDay.svelte +51 -32
- package/dist/views/mobile/MobileWeek.svelte +17 -10
- package/dist/views/month/MonthGrid.svelte +54 -21
- package/dist/views/planner/PlannerScroll.svelte +34 -28
- package/dist/views/planner/PlannerWeek.svelte +146 -30
- package/dist/views/shared/format.d.ts +3 -0
- package/dist/views/shared/format.js +10 -1
- package/package.json +2 -4
- package/widget/widget.js +750 -662
package/README.md
CHANGED
|
@@ -24,13 +24,17 @@ Requirements:
|
|
|
24
24
|
<script>
|
|
25
25
|
import { Calendar, createMemoryAdapter } from '@nomideusz/svelte-calendar';
|
|
26
26
|
|
|
27
|
+
// Today at a given hour, so the events land in the week the calendar opens on
|
|
28
|
+
const today = new Date();
|
|
29
|
+
const at = (hour) => new Date(today.getFullYear(), today.getMonth(), today.getDate(), hour);
|
|
30
|
+
|
|
27
31
|
const adapter = createMemoryAdapter([
|
|
28
|
-
{ id: '1', title: 'Team Sync', start:
|
|
29
|
-
{ id: '2', title: 'Lunch', start:
|
|
32
|
+
{ id: '1', title: 'Team Sync', start: at(9), end: at(10) },
|
|
33
|
+
{ id: '2', title: 'Lunch', start: at(12), end: at(13) },
|
|
30
34
|
]);
|
|
31
35
|
</script>
|
|
32
36
|
|
|
33
|
-
<Calendar {adapter} />
|
|
37
|
+
<Calendar {adapter} view="week-planner" />
|
|
34
38
|
```
|
|
35
39
|
|
|
36
40
|
That's it — 8 built-in views, auto-coloring, drag-and-drop with live previews, all out of the box. The default `auto` theme probes your page's background, accent color and fonts, so the calendar adapts to any design.
|
|
@@ -80,6 +84,7 @@ When focus is inside the calendar:
|
|
|
80
84
|
- `t` — go to today.
|
|
81
85
|
- `←` / `→` — previous / next period (mirrored in RTL). Ignored while typing in a field or inside a pill group, where arrows move between pills.
|
|
82
86
|
- In `month-grid`: arrow keys move between days, `Enter` / `Space` opens the focused day (`ondayclick`).
|
|
87
|
+
- In `week-planner` / `day-planner`: the day columns are one tab stop; `←` / `→` move between days, `Enter` / `Space` creates an event (`oneventcreate`) at the next slot today, or 09:00. On a focused event, `Alt+↑` / `Alt+↓` move it one `snapInterval`, `Alt+←` / `Alt+→` move it a day, and `Alt+Shift+↑` / `Alt+Shift+↓` move its end; each goes through the same validation as a drag and fires `oneventmove`.
|
|
83
88
|
|
|
84
89
|
### Custom Views
|
|
85
90
|
|
|
@@ -146,7 +151,7 @@ When the calendar's **container** is narrower than 768px, it swaps to touch-firs
|
|
|
146
151
|
|
|
147
152
|
```svelte
|
|
148
153
|
<!-- Auto-detect (default) — switches at a 768px container width -->
|
|
149
|
-
<Calendar {adapter} />
|
|
154
|
+
<Calendar {adapter} view="week-planner" />
|
|
150
155
|
|
|
151
156
|
<!-- Force mobile layout -->
|
|
152
157
|
<Calendar {adapter} mobile={true} />
|
|
@@ -559,7 +564,7 @@ For fixed repeating events (class timetables, office hours):
|
|
|
559
564
|
]);
|
|
560
565
|
</script>
|
|
561
566
|
|
|
562
|
-
<Calendar {adapter} />
|
|
567
|
+
<Calendar {adapter} view="week-planner" />
|
|
563
568
|
```
|
|
564
569
|
|
|
565
570
|
<details>
|
|
@@ -479,6 +479,34 @@ const dateLabel = $derived.by(() => {
|
|
|
479
479
|
year: "numeric"
|
|
480
480
|
});
|
|
481
481
|
});
|
|
482
|
+
// ── Period title (the built-in header's big line) ──
|
|
483
|
+
// Names the month the user is looking at: "October 2026"; a week across two
|
|
484
|
+
// months reads "Oct – Nov 2026"; a day gives its date. `dateLabel` keeps the
|
|
485
|
+
// exact range for the header snippet and the screen-reader status line.
|
|
486
|
+
const periodTitle = $derived.by(() => {
|
|
487
|
+
if (!showDates) return "";
|
|
488
|
+
const loc = locale ?? getDefaultLocale();
|
|
489
|
+
if (viewState.mode === "day") {
|
|
490
|
+
return viewState.focusDate.toLocaleDateString(loc, {
|
|
491
|
+
weekday: useMobile ? "short" : "long",
|
|
492
|
+
month: "long",
|
|
493
|
+
day: "numeric",
|
|
494
|
+
year: "numeric"
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
const s = viewState.mode === "week" ? viewState.range.start : viewState.focusDate;
|
|
498
|
+
const e = viewState.mode === "week" ? new Date(viewState.range.end.getTime() - 1) : s;
|
|
499
|
+
if (s.getMonth() === e.getMonth() && s.getFullYear() === e.getFullYear()) {
|
|
500
|
+
return s.toLocaleDateString(loc, {
|
|
501
|
+
month: "long",
|
|
502
|
+
year: "numeric"
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
return new Intl.DateTimeFormat(loc, {
|
|
506
|
+
month: "short",
|
|
507
|
+
year: "numeric"
|
|
508
|
+
}).formatRange(s, e).replace(/[ ]/g, " ");
|
|
509
|
+
});
|
|
482
510
|
// Which modes are available?
|
|
483
511
|
const modes = $derived.by(() => {
|
|
484
512
|
const g = new Set(desktopViews.map((v) => v.mode));
|
|
@@ -623,70 +651,50 @@ const navCtx = $derived({
|
|
|
623
651
|
{#if headerSnippet}
|
|
624
652
|
{@render headerSnippet(headerCtx)}
|
|
625
653
|
|
|
626
|
-
<!-- ───
|
|
627
|
-
{:else if
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
<
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
{#if !titleBelow}
|
|
650
|
-
<span class="cal-m-title" role="status" aria-live="polite" aria-atomic="true">{dateLabel}</span>
|
|
654
|
+
<!-- ─── Built-in header: the period as the title, then view switch, then Today ‹ › ─── -->
|
|
655
|
+
{:else if showNavigation || (showModePills && modes.length > 1) || dateLabel}
|
|
656
|
+
<div class="cal-hd" class:cal-hd--mobile={useMobile} class:cal-hd--stack={stackHeader}>
|
|
657
|
+
<!-- The visible title names the month; the status line announces the exact range -->
|
|
658
|
+
<span class="cal-hd-title" aria-hidden="true">{periodTitle}</span>
|
|
659
|
+
<span class="cal-sr" role="status" aria-live="polite" aria-atomic="true">{dateLabel}</span>
|
|
660
|
+
{#if showModePills && !useMobile && labelsForMode.length > 1}
|
|
661
|
+
<!-- View-type switcher (e.g. Planner ↔ Agenda) for the current mode -->
|
|
662
|
+
<div class="cal-pills cal-pills--labels" role="radiogroup" aria-label={L.viewMode}>
|
|
663
|
+
{#each labelsForMode as label (label)}
|
|
664
|
+
<button
|
|
665
|
+
type="button"
|
|
666
|
+
class="cal-pill"
|
|
667
|
+
class:cal-pill--active={activeView?.label === label}
|
|
668
|
+
role="radio"
|
|
669
|
+
aria-checked={activeView?.label === label}
|
|
670
|
+
onclick={() => switchLabel(label)}
|
|
671
|
+
>
|
|
672
|
+
{viewLabel(label)}
|
|
673
|
+
</button>
|
|
674
|
+
{/each}
|
|
675
|
+
</div>
|
|
651
676
|
{/if}
|
|
652
|
-
|
|
653
|
-
|
|
677
|
+
{#if showModePills && modes.length > 1}
|
|
678
|
+
<div class="cal-pills" role="radiogroup" aria-label={L.viewMode}>
|
|
679
|
+
{#each modes as g (g)}
|
|
680
|
+
<button
|
|
681
|
+
type="button"
|
|
682
|
+
class="cal-pill"
|
|
683
|
+
class:cal-pill--active={viewState.mode === g}
|
|
684
|
+
role="radio"
|
|
685
|
+
aria-checked={viewState.mode === g}
|
|
686
|
+
onclick={() => switchMode(g)}
|
|
687
|
+
>
|
|
688
|
+
{g === 'day' ? L.day : g === 'week' ? L.week : L.month}
|
|
689
|
+
</button>
|
|
690
|
+
{/each}
|
|
691
|
+
</div>
|
|
692
|
+
{/if}
|
|
693
|
+
<div class="cal-hd-nav">
|
|
654
694
|
{#if navigationSnippet}
|
|
655
695
|
{@render navigationSnippet(navCtx)}
|
|
656
696
|
{:else if showNavigation}
|
|
657
697
|
<!-- Always rendered (disabled on today) so navigating never shifts layout -->
|
|
658
|
-
<button
|
|
659
|
-
type="button"
|
|
660
|
-
class="cal-m-today"
|
|
661
|
-
onclick={() => viewState.goToday()}
|
|
662
|
-
disabled={viewIncludesToday}
|
|
663
|
-
title={L.goToToday}
|
|
664
|
-
>
|
|
665
|
-
{L.today}
|
|
666
|
-
</button>
|
|
667
|
-
<button type="button" class="cal-m-nav" onclick={() => viewState.prev()} aria-label={viewState.mode === 'day' ? L.previousDay : viewState.mode === 'month' ? L.previousMonth : L.previousWeek}>
|
|
668
|
-
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" width="16" height="16" aria-hidden="true"><path d="M10 3 5 8l5 5"/></svg>
|
|
669
|
-
</button>
|
|
670
|
-
<button type="button" class="cal-m-nav" onclick={() => viewState.next()} aria-label={viewState.mode === 'day' ? L.nextDay : viewState.mode === 'month' ? L.nextMonth : L.nextWeek}>
|
|
671
|
-
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" width="16" height="16" aria-hidden="true"><path d="M6 3l5 5-5 5"/></svg>
|
|
672
|
-
</button>
|
|
673
|
-
{/if}
|
|
674
|
-
</div>
|
|
675
|
-
</div>
|
|
676
|
-
{#if titleBelow}
|
|
677
|
-
<div class="cal-m-titlebar">
|
|
678
|
-
<span class="cal-m-title" role="status" aria-live="polite" aria-atomic="true">{dateLabel}</span>
|
|
679
|
-
</div>
|
|
680
|
-
{/if}
|
|
681
|
-
|
|
682
|
-
<!-- ─── Desktop header ─── -->
|
|
683
|
-
{:else if showNavigation || (showModePills && modes.length > 1) || dateLabel}
|
|
684
|
-
<div class="cal-hd">
|
|
685
|
-
<div class="cal-hd-side">
|
|
686
|
-
{#if navigationSnippet}
|
|
687
|
-
{@render navigationSnippet(navCtx)}
|
|
688
|
-
{:else if showNavigation}
|
|
689
|
-
<!-- Always rendered (disabled on today) so navigating never shifts the centered title -->
|
|
690
698
|
<button
|
|
691
699
|
type="button"
|
|
692
700
|
class="cal-hd-today"
|
|
@@ -704,42 +712,6 @@ const navCtx = $derived({
|
|
|
704
712
|
</button>
|
|
705
713
|
{/if}
|
|
706
714
|
</div>
|
|
707
|
-
<span class="cal-hd-title" role="status" aria-live="polite" aria-atomic="true">{dateLabel}</span>
|
|
708
|
-
<div class="cal-hd-side cal-hd-side--end">
|
|
709
|
-
{#if showModePills && labelsForMode.length > 1}
|
|
710
|
-
<!-- View-type switcher (e.g. Planner ↔ Agenda) for the current mode -->
|
|
711
|
-
<div class="cal-pills cal-pills--labels" role="radiogroup" aria-label={L.viewMode}>
|
|
712
|
-
{#each labelsForMode as label (label)}
|
|
713
|
-
<button
|
|
714
|
-
type="button"
|
|
715
|
-
class="cal-pill"
|
|
716
|
-
class:cal-pill--active={activeView?.label === label}
|
|
717
|
-
role="radio"
|
|
718
|
-
aria-checked={activeView?.label === label}
|
|
719
|
-
onclick={() => switchLabel(label)}
|
|
720
|
-
>
|
|
721
|
-
{viewLabel(label)}
|
|
722
|
-
</button>
|
|
723
|
-
{/each}
|
|
724
|
-
</div>
|
|
725
|
-
{/if}
|
|
726
|
-
{#if showModePills && modes.length > 1}
|
|
727
|
-
<div class="cal-pills" role="radiogroup" aria-label={L.viewMode}>
|
|
728
|
-
{#each modes as g (g)}
|
|
729
|
-
<button
|
|
730
|
-
type="button"
|
|
731
|
-
class="cal-pill"
|
|
732
|
-
class:cal-pill--active={viewState.mode === g}
|
|
733
|
-
role="radio"
|
|
734
|
-
aria-checked={viewState.mode === g}
|
|
735
|
-
onclick={() => switchMode(g)}
|
|
736
|
-
>
|
|
737
|
-
{g === 'day' ? L.day : g === 'week' ? L.week : L.month}
|
|
738
|
-
</button>
|
|
739
|
-
{/each}
|
|
740
|
-
</div>
|
|
741
|
-
{/if}
|
|
742
|
-
</div>
|
|
743
715
|
</div>
|
|
744
716
|
{/if}
|
|
745
717
|
|
|
@@ -792,118 +764,186 @@ const navCtx = $derived({
|
|
|
792
764
|
}
|
|
793
765
|
|
|
794
766
|
|
|
795
|
-
/* ──
|
|
767
|
+
/* ── Header: the period set large as the page's title, the view switch as
|
|
768
|
+
plain text, Today ‹ › in 2px ink frames, one rule to the grid. ── */
|
|
796
769
|
.cal-hd {
|
|
770
|
+
/* Controls take a small corner that follows the calendar's own radius */
|
|
771
|
+
--cal-ctl-r: clamp(4px, calc(var(--cal-r, 0px) / 2), 8px);
|
|
772
|
+
--cal-ctl-h: 36px;
|
|
797
773
|
display: flex;
|
|
798
774
|
flex-wrap: wrap;
|
|
799
775
|
align-items: center;
|
|
800
|
-
gap:
|
|
801
|
-
padding:
|
|
802
|
-
min-height: 44px;
|
|
803
|
-
box-sizing: border-box;
|
|
776
|
+
gap: 10px 24px;
|
|
777
|
+
padding: 14px 16px 12px;
|
|
804
778
|
border-bottom: 1px solid var(--dt-border, rgba(0, 0, 0, 0.08));
|
|
805
779
|
flex-shrink: 0;
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
display: flex;
|
|
810
|
-
align-items: center;
|
|
811
|
-
gap: 4px;
|
|
812
|
-
flex: 1;
|
|
813
|
-
min-width: 0;
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
.cal-hd-side--end {
|
|
817
|
-
justify-content: flex-end;
|
|
780
|
+
box-sizing: border-box;
|
|
781
|
+
font-family: var(--dt-sans, system-ui, sans-serif);
|
|
782
|
+
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
818
783
|
}
|
|
819
784
|
|
|
820
785
|
.cal-hd-title {
|
|
821
|
-
|
|
786
|
+
flex: 1 1 auto;
|
|
787
|
+
min-width: 0;
|
|
788
|
+
font: 400 32px/1.1 var(--dt-sans, system-ui, sans-serif);
|
|
789
|
+
font-stretch: 90%;
|
|
822
790
|
font-variant-numeric: tabular-nums;
|
|
823
|
-
letter-spacing: -0.
|
|
824
|
-
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
791
|
+
letter-spacing: -0.02em;
|
|
825
792
|
white-space: nowrap;
|
|
826
793
|
overflow: hidden;
|
|
827
794
|
text-overflow: ellipsis;
|
|
828
795
|
}
|
|
829
796
|
|
|
830
|
-
.cal-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
border
|
|
840
|
-
cursor: pointer;
|
|
841
|
-
transition: background 120ms, color 120ms;
|
|
797
|
+
.cal-sr {
|
|
798
|
+
position: absolute;
|
|
799
|
+
width: 1px;
|
|
800
|
+
height: 1px;
|
|
801
|
+
margin: -1px;
|
|
802
|
+
padding: 0;
|
|
803
|
+
overflow: hidden;
|
|
804
|
+
clip-path: inset(50%);
|
|
805
|
+
white-space: nowrap;
|
|
806
|
+
border: 0;
|
|
842
807
|
}
|
|
843
808
|
|
|
844
|
-
.cal-hd-
|
|
845
|
-
|
|
846
|
-
|
|
809
|
+
.cal-hd-nav {
|
|
810
|
+
display: flex;
|
|
811
|
+
align-items: center;
|
|
812
|
+
gap: 8px;
|
|
847
813
|
}
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
.cal-hd-today:focus-visible,
|
|
851
|
-
.cal-pill:focus-visible {
|
|
852
|
-
outline: 2px solid color-mix(in srgb, var(--dt-accent, #2563eb) 55%, transparent);
|
|
853
|
-
outline-offset: 2px;
|
|
814
|
+
.cal-hd-nav:empty {
|
|
815
|
+
display: none;
|
|
854
816
|
}
|
|
855
817
|
|
|
856
|
-
.cal-hd-today
|
|
857
|
-
|
|
858
|
-
|
|
818
|
+
.cal-hd-today,
|
|
819
|
+
.cal-hd-btn {
|
|
820
|
+
box-sizing: border-box;
|
|
821
|
+
height: var(--cal-ctl-h);
|
|
822
|
+
border: 2px solid var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
823
|
+
border-radius: var(--cal-ctl-r);
|
|
859
824
|
background: transparent;
|
|
860
|
-
|
|
861
|
-
padding: 7px 10px;
|
|
862
|
-
border-radius: 0;
|
|
825
|
+
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
863
826
|
cursor: pointer;
|
|
827
|
+
transition: background-color 120ms, opacity 120ms;
|
|
828
|
+
-webkit-tap-highlight-color: transparent;
|
|
829
|
+
}
|
|
830
|
+
.cal-hd-today {
|
|
831
|
+
padding: 0 14px;
|
|
832
|
+
font: 400 15px/1 var(--dt-sans, system-ui, sans-serif);
|
|
864
833
|
white-space: nowrap;
|
|
865
|
-
margin-right: 2px;
|
|
866
|
-
transition: background 120ms, color 120ms, border-color 120ms;
|
|
867
834
|
}
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
835
|
+
.cal-hd-btn {
|
|
836
|
+
display: grid;
|
|
837
|
+
place-items: center;
|
|
838
|
+
width: var(--cal-ctl-h);
|
|
839
|
+
padding: 0;
|
|
840
|
+
}
|
|
841
|
+
/* The chevrons point along the reading direction */
|
|
842
|
+
.cal-hd-btn:dir(rtl) svg {
|
|
843
|
+
transform: scaleX(-1);
|
|
872
844
|
}
|
|
845
|
+
.cal-hd-today:hover:not(:disabled),
|
|
846
|
+
.cal-hd-btn:hover {
|
|
847
|
+
background: var(--dt-hover, color-mix(in srgb, currentColor 6%, transparent));
|
|
848
|
+
}
|
|
849
|
+
.cal-hd-today:active:not(:disabled),
|
|
850
|
+
.cal-hd-btn:active {
|
|
851
|
+
background: color-mix(in srgb, var(--dt-text, #000) 12%, transparent);
|
|
852
|
+
}
|
|
853
|
+
/* Today is already in view: the frame stays, quietly */
|
|
873
854
|
.cal-hd-today:disabled {
|
|
874
|
-
opacity: 0.
|
|
855
|
+
opacity: 0.4;
|
|
875
856
|
cursor: default;
|
|
876
857
|
}
|
|
877
858
|
|
|
878
|
-
|
|
859
|
+
.cal-hd-today:focus-visible,
|
|
860
|
+
.cal-hd-btn:focus-visible,
|
|
861
|
+
.cal-pill:focus-visible {
|
|
862
|
+
outline: 2px solid var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
863
|
+
outline-offset: 2px;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/* View switch: plain text; the chosen one is ink over a 2px ink rule.
|
|
867
|
+
The accent keeps its three jobs. */
|
|
879
868
|
.cal-pills {
|
|
880
869
|
display: flex;
|
|
881
|
-
gap:
|
|
870
|
+
gap: 16px;
|
|
882
871
|
flex-shrink: 0;
|
|
883
872
|
}
|
|
884
|
-
|
|
873
|
+
/* A hairline between the view-type and the day/week/month rows */
|
|
874
|
+
.cal-pills--labels + .cal-pills {
|
|
875
|
+
align-self: stretch;
|
|
876
|
+
align-items: center;
|
|
877
|
+
padding-inline-start: 24px;
|
|
878
|
+
border-inline-start: 1px solid var(--dt-border, rgba(0, 0, 0, 0.12));
|
|
879
|
+
}
|
|
885
880
|
.cal-pill {
|
|
886
881
|
border: none;
|
|
887
882
|
background: transparent;
|
|
888
883
|
color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
|
|
889
884
|
cursor: pointer;
|
|
890
|
-
font:
|
|
891
|
-
|
|
885
|
+
font: 400 15px/1 var(--dt-sans, system-ui, sans-serif);
|
|
886
|
+
min-height: var(--cal-ctl-h);
|
|
887
|
+
/* 4px of air for the focus ring, given back so the row keeps its rhythm */
|
|
888
|
+
padding: 0 4px;
|
|
889
|
+
margin: 0 -4px;
|
|
892
890
|
border-radius: 0;
|
|
893
|
-
|
|
894
|
-
|
|
891
|
+
white-space: nowrap;
|
|
892
|
+
text-decoration: underline 2px transparent;
|
|
893
|
+
text-underline-offset: 7px;
|
|
894
|
+
transition: color 120ms, text-decoration-color 120ms;
|
|
895
|
+
-webkit-tap-highlight-color: transparent;
|
|
895
896
|
}
|
|
896
|
-
|
|
897
|
-
/* :not(--active) — the hover rule otherwise outranks the active color,
|
|
898
|
-
and iOS keeps :hover stuck after a tap (dark text on the accent). */
|
|
897
|
+
/* :not(--active) — iOS keeps :hover stuck after a tap */
|
|
899
898
|
.cal-pill:hover:not(.cal-pill--active) {
|
|
900
899
|
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
900
|
+
text-decoration-color: var(--dt-border-day, var(--dt-border, rgba(0, 0, 0, 0.3)));
|
|
901
901
|
}
|
|
902
|
-
|
|
903
|
-
/* Selected = ink text over an ink rule; the accent keeps its three jobs. */
|
|
904
902
|
.cal-pill--active {
|
|
905
903
|
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
906
|
-
|
|
904
|
+
text-decoration-color: currentColor;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
/* Compact (mobile) header: same drawing, smaller title, tighter gaps */
|
|
908
|
+
.cal-hd--mobile {
|
|
909
|
+
--cal-ctl-h: 40px;
|
|
910
|
+
gap: 8px 12px;
|
|
911
|
+
padding: 10px 8px 8px;
|
|
912
|
+
}
|
|
913
|
+
.cal-hd--mobile .cal-hd-title {
|
|
914
|
+
font-size: 22px;
|
|
915
|
+
}
|
|
916
|
+
.cal-hd--mobile .cal-pills {
|
|
917
|
+
gap: 12px;
|
|
918
|
+
}
|
|
919
|
+
.cal-hd--mobile .cal-pill {
|
|
920
|
+
font-size: 14px;
|
|
921
|
+
}
|
|
922
|
+
.cal-hd--mobile .cal-hd-today {
|
|
923
|
+
padding: 0 10px;
|
|
924
|
+
font-size: 14px;
|
|
925
|
+
}
|
|
926
|
+
.cal-hd--mobile .cal-hd-nav {
|
|
927
|
+
gap: 6px;
|
|
928
|
+
margin-inline-start: auto;
|
|
929
|
+
}
|
|
930
|
+
/* Narrow containers: the title takes its own row above the controls */
|
|
931
|
+
.cal-hd--stack .cal-hd-title:not(:empty) {
|
|
932
|
+
flex-basis: 100%;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
@media (pointer: coarse) {
|
|
936
|
+
.cal-hd {
|
|
937
|
+
--cal-ctl-h: 44px;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
@media (prefers-reduced-motion: reduce) {
|
|
942
|
+
.cal-hd-today,
|
|
943
|
+
.cal-hd-btn,
|
|
944
|
+
.cal-pill {
|
|
945
|
+
transition: none;
|
|
946
|
+
}
|
|
907
947
|
}
|
|
908
948
|
|
|
909
949
|
.cal-body {
|
|
@@ -952,138 +992,4 @@ const navCtx = $derived({
|
|
|
952
992
|
}
|
|
953
993
|
}
|
|
954
994
|
|
|
955
|
-
/* ── Mobile header (flow layout) ── */
|
|
956
|
-
.cal-m-hd {
|
|
957
|
-
display: flex;
|
|
958
|
-
align-items: center;
|
|
959
|
-
gap: 4px;
|
|
960
|
-
padding: 8px 8px 6px;
|
|
961
|
-
border-bottom: 1px solid var(--dt-border, rgba(0, 0, 0, 0.08));
|
|
962
|
-
flex-shrink: 0;
|
|
963
|
-
min-height: 44px;
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
/* Narrow containers: the date label moves to its own row (.cal-m-titlebar),
|
|
967
|
-
so the controls row spreads pills and nav to the edges. */
|
|
968
|
-
.cal-m-hd--stack {
|
|
969
|
-
justify-content: space-between;
|
|
970
|
-
}
|
|
971
|
-
.cal-m-hd--titled {
|
|
972
|
-
border-bottom: none;
|
|
973
|
-
padding-bottom: 2px;
|
|
974
|
-
}
|
|
975
|
-
.cal-m-titlebar {
|
|
976
|
-
display: flex;
|
|
977
|
-
justify-content: center;
|
|
978
|
-
padding: 0 8px 8px;
|
|
979
|
-
border-bottom: 1px solid var(--dt-border, rgba(0, 0, 0, 0.08));
|
|
980
|
-
flex-shrink: 0;
|
|
981
|
-
}
|
|
982
|
-
.cal-m-titlebar .cal-m-title {
|
|
983
|
-
flex: 0 1 auto;
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
.cal-m-left,
|
|
987
|
-
.cal-m-right {
|
|
988
|
-
display: flex;
|
|
989
|
-
align-items: center;
|
|
990
|
-
gap: 2px;
|
|
991
|
-
flex-shrink: 0;
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
.cal-m-right {
|
|
995
|
-
justify-content: flex-end;
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
.cal-m-nav {
|
|
999
|
-
display: flex;
|
|
1000
|
-
align-items: center;
|
|
1001
|
-
justify-content: center;
|
|
1002
|
-
width: 40px;
|
|
1003
|
-
height: 40px;
|
|
1004
|
-
border: none;
|
|
1005
|
-
background: transparent;
|
|
1006
|
-
color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
|
|
1007
|
-
border-radius: 50%;
|
|
1008
|
-
cursor: pointer;
|
|
1009
|
-
transition: background 120ms, color 120ms;
|
|
1010
|
-
-webkit-tap-highlight-color: transparent;
|
|
1011
|
-
flex-shrink: 0;
|
|
1012
|
-
}
|
|
1013
|
-
.cal-m-nav:hover {
|
|
1014
|
-
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
1015
|
-
background: color-mix(in srgb, var(--dt-text, rgba(0, 0, 0, 0.87)) 8%, transparent);
|
|
1016
|
-
}
|
|
1017
|
-
.cal-m-nav:active {
|
|
1018
|
-
background: var(--dt-accent-dim, rgba(37, 99, 235, 0.12));
|
|
1019
|
-
}
|
|
1020
|
-
.cal-m-nav:focus-visible {
|
|
1021
|
-
outline: 2px solid color-mix(in srgb, var(--dt-accent, #2563eb) 55%, transparent);
|
|
1022
|
-
outline-offset: 2px;
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
.cal-m-pills {
|
|
1026
|
-
display: flex;
|
|
1027
|
-
gap: 2px;
|
|
1028
|
-
flex-shrink: 0;
|
|
1029
|
-
}
|
|
1030
|
-
.cal-m-pill {
|
|
1031
|
-
border: none;
|
|
1032
|
-
background: transparent;
|
|
1033
|
-
color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
|
|
1034
|
-
cursor: pointer;
|
|
1035
|
-
font: 500 13px / 1 var(--dt-sans, system-ui, sans-serif);
|
|
1036
|
-
padding: 11px 10px 9px;
|
|
1037
|
-
border-radius: 0;
|
|
1038
|
-
box-shadow: inset 0 -2px 0 transparent;
|
|
1039
|
-
transition: box-shadow 100ms, color 100ms;
|
|
1040
|
-
-webkit-tap-highlight-color: transparent;
|
|
1041
|
-
}
|
|
1042
|
-
.cal-m-pill:hover:not(.cal-m-pill--active) {
|
|
1043
|
-
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
1044
|
-
}
|
|
1045
|
-
.cal-m-pill--active {
|
|
1046
|
-
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
1047
|
-
box-shadow: inset 0 -2px 0 var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
.cal-m-title {
|
|
1051
|
-
flex: 1;
|
|
1052
|
-
text-align: center;
|
|
1053
|
-
font: 600 14px / 1.2 var(--dt-sans, system-ui, sans-serif);
|
|
1054
|
-
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
1055
|
-
white-space: nowrap;
|
|
1056
|
-
overflow: hidden;
|
|
1057
|
-
text-overflow: ellipsis;
|
|
1058
|
-
min-width: 0;
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
.cal-m-today {
|
|
1062
|
-
font: 600 13px / 1 var(--dt-sans, system-ui, sans-serif);
|
|
1063
|
-
color: var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
1064
|
-
background: transparent;
|
|
1065
|
-
border: 1px solid var(--dt-border-day, rgba(0, 0, 0, 0.12));
|
|
1066
|
-
min-height: 40px;
|
|
1067
|
-
padding: 5px 12px;
|
|
1068
|
-
border-radius: 0;
|
|
1069
|
-
cursor: pointer;
|
|
1070
|
-
white-space: nowrap;
|
|
1071
|
-
transition: background 120ms, color 120ms;
|
|
1072
|
-
-webkit-tap-highlight-color: transparent;
|
|
1073
|
-
flex-shrink: 0;
|
|
1074
|
-
}
|
|
1075
|
-
.cal-m-today:hover:not(:disabled) {
|
|
1076
|
-
border-color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
|
|
1077
|
-
}
|
|
1078
|
-
.cal-m-today:active:not(:disabled) {
|
|
1079
|
-
background: color-mix(in srgb, var(--dt-text, #000) 8%, transparent);
|
|
1080
|
-
}
|
|
1081
|
-
.cal-m-today:disabled {
|
|
1082
|
-
opacity: 0.45;
|
|
1083
|
-
cursor: default;
|
|
1084
|
-
}
|
|
1085
|
-
.cal-m-today:focus-visible {
|
|
1086
|
-
outline: 2px solid var(--dt-text, rgba(0, 0, 0, 0.87));
|
|
1087
|
-
outline-offset: 2px;
|
|
1088
|
-
}
|
|
1089
995
|
</style>
|
package/dist/theme/presets.d.ts
CHANGED
|
@@ -35,11 +35,11 @@ export declare const auto = "";
|
|
|
35
35
|
*/
|
|
36
36
|
export declare const neutral = "\n\t--dt-stage-bg: #efebe9;\n\t--dt-bg: #efebe9;\n\t--dt-surface: #f4f1ee;\n\t--dt-border: rgba(15, 15, 15, 0.3);\n\t--dt-border-day: rgba(15, 15, 15, 0.6);\n\t--dt-text: #0f0f0f;\n\t--dt-text-2: rgba(15, 15, 15, 0.66);\n\t--dt-text-3: rgba(15, 15, 15, 0.54);\n\t--dt-accent: var(--asini-accent, #1d4fd7);\n\t--dt-accent-dim: color-mix(in srgb, var(--dt-accent) 12%, transparent);\n\t--dt-glow: color-mix(in srgb, var(--dt-accent) 25%, transparent);\n\t--dt-today-bg: transparent;\n\t--dt-btn-text: #fff;\n\t--dt-scrollbar: rgba(15, 15, 15, 0.18);\n\t--dt-weekend-bg: rgba(15, 15, 15, 0.035);\n\t--dt-hover: rgba(15, 15, 15, 0.05);\n\t--dt-event: var(--dt-text);\n\t--dt-paper: none;\n\t--dt-mono: ui-monospace, 'SFMono-Regular', monospace;\n";
|
|
37
37
|
/** Midnight Industrial — dark charcoal + red accent, tech monitoring */
|
|
38
|
-
export declare const midnight = "\n\t--dt-stage-bg: #080a0f;\n\t--dt-bg: #0b0e14;\n\t--dt-surface: #10141c;\n\t--dt-border: rgba(148, 163, 184, 0.07);\n\t--dt-border-day: rgba(148, 163, 184, 0.14);\n\t--dt-text: rgba(226, 232, 240, 0.85);\n\t--dt-text-2: rgba(148, 163, 184, 0.
|
|
38
|
+
export declare const midnight = "\n\t--dt-stage-bg: #080a0f;\n\t--dt-bg: #0b0e14;\n\t--dt-surface: #10141c;\n\t--dt-border: rgba(148, 163, 184, 0.07);\n\t--dt-border-day: rgba(148, 163, 184, 0.14);\n\t--dt-text: rgba(226, 232, 240, 0.85);\n\t--dt-text-2: rgba(148, 163, 184, 0.75);\n\t--dt-text-3: rgba(148, 163, 184, 0.65);\n\t--dt-accent: #ef4444;\n\t--dt-accent-dim: rgba(239, 68, 68, 0.18);\n\t--dt-glow: rgba(239, 68, 68, 0.35);\n\t--dt-today-bg: transparent;\n\t--dt-btn-text: #fff;\n\t--dt-scrollbar: rgba(148, 163, 184, 0.12);\n\t--dt-success: rgba(74, 222, 128, 0.7);\n\t--dt-weekend-bg: rgba(148, 163, 184, 0.03);\n\t--dt-hover: rgba(148, 163, 184, 0.06);\n\t--dt-event: var(--dt-text);\n\t--dt-paper: none;\n\t--dt-mono: ui-monospace, 'SFMono-Regular', monospace;\n";
|
|
39
39
|
/** All available presets keyed by name */
|
|
40
40
|
export declare const presets: {
|
|
41
41
|
readonly auto: "";
|
|
42
42
|
readonly neutral: "\n\t--dt-stage-bg: #efebe9;\n\t--dt-bg: #efebe9;\n\t--dt-surface: #f4f1ee;\n\t--dt-border: rgba(15, 15, 15, 0.3);\n\t--dt-border-day: rgba(15, 15, 15, 0.6);\n\t--dt-text: #0f0f0f;\n\t--dt-text-2: rgba(15, 15, 15, 0.66);\n\t--dt-text-3: rgba(15, 15, 15, 0.54);\n\t--dt-accent: var(--asini-accent, #1d4fd7);\n\t--dt-accent-dim: color-mix(in srgb, var(--dt-accent) 12%, transparent);\n\t--dt-glow: color-mix(in srgb, var(--dt-accent) 25%, transparent);\n\t--dt-today-bg: transparent;\n\t--dt-btn-text: #fff;\n\t--dt-scrollbar: rgba(15, 15, 15, 0.18);\n\t--dt-weekend-bg: rgba(15, 15, 15, 0.035);\n\t--dt-hover: rgba(15, 15, 15, 0.05);\n\t--dt-event: var(--dt-text);\n\t--dt-paper: none;\n\t--dt-mono: ui-monospace, 'SFMono-Regular', monospace;\n";
|
|
43
|
-
readonly midnight: "\n\t--dt-stage-bg: #080a0f;\n\t--dt-bg: #0b0e14;\n\t--dt-surface: #10141c;\n\t--dt-border: rgba(148, 163, 184, 0.07);\n\t--dt-border-day: rgba(148, 163, 184, 0.14);\n\t--dt-text: rgba(226, 232, 240, 0.85);\n\t--dt-text-2: rgba(148, 163, 184, 0.
|
|
43
|
+
readonly midnight: "\n\t--dt-stage-bg: #080a0f;\n\t--dt-bg: #0b0e14;\n\t--dt-surface: #10141c;\n\t--dt-border: rgba(148, 163, 184, 0.07);\n\t--dt-border-day: rgba(148, 163, 184, 0.14);\n\t--dt-text: rgba(226, 232, 240, 0.85);\n\t--dt-text-2: rgba(148, 163, 184, 0.75);\n\t--dt-text-3: rgba(148, 163, 184, 0.65);\n\t--dt-accent: #ef4444;\n\t--dt-accent-dim: rgba(239, 68, 68, 0.18);\n\t--dt-glow: rgba(239, 68, 68, 0.35);\n\t--dt-today-bg: transparent;\n\t--dt-btn-text: #fff;\n\t--dt-scrollbar: rgba(148, 163, 184, 0.12);\n\t--dt-success: rgba(74, 222, 128, 0.7);\n\t--dt-weekend-bg: rgba(148, 163, 184, 0.03);\n\t--dt-hover: rgba(148, 163, 184, 0.06);\n\t--dt-event: var(--dt-text);\n\t--dt-paper: none;\n\t--dt-mono: ui-monospace, 'SFMono-Regular', monospace;\n";
|
|
44
44
|
};
|
|
45
45
|
export type PresetName = keyof typeof presets;
|
package/dist/theme/presets.js
CHANGED
|
@@ -62,8 +62,8 @@ export const midnight = `
|
|
|
62
62
|
--dt-border: rgba(148, 163, 184, 0.07);
|
|
63
63
|
--dt-border-day: rgba(148, 163, 184, 0.14);
|
|
64
64
|
--dt-text: rgba(226, 232, 240, 0.85);
|
|
65
|
-
--dt-text-2: rgba(148, 163, 184, 0.
|
|
66
|
-
--dt-text-3: rgba(
|
|
65
|
+
--dt-text-2: rgba(148, 163, 184, 0.75);
|
|
66
|
+
--dt-text-3: rgba(148, 163, 184, 0.65);
|
|
67
67
|
--dt-accent: #ef4444;
|
|
68
68
|
--dt-accent-dim: rgba(239, 68, 68, 0.18);
|
|
69
69
|
--dt-glow: rgba(239, 68, 68, 0.35);
|