@nomideusz/svelte-calendar 0.11.0 → 0.13.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 +2 -16
- package/dist/calendar/Calendar.svelte +4 -0
- package/dist/calendar/Calendar.svelte.d.ts +8 -0
- package/dist/core/index.d.ts +0 -2
- package/dist/core/index.js +0 -2
- package/dist/engine/view-state.svelte.d.ts +5 -4
- package/dist/headless/create-range-agenda.svelte.d.ts +62 -0
- package/dist/headless/create-range-agenda.svelte.js +110 -0
- package/dist/headless/index.d.ts +2 -0
- package/dist/headless/index.js +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +2 -2
- package/dist/theme/auto.js +56 -21
- package/dist/theme/presets.d.ts +6 -5
- package/dist/theme/presets.js +2 -3
- package/dist/views/agenda/AgendaDay.svelte +15 -30
- package/dist/views/agenda/AgendaWeek.svelte +68 -30
- package/dist/views/planner/Planner.svelte +3 -7
- package/dist/views/planner/PlannerWeek.svelte +16 -7
- package/dist/views/planner/PlannerWeek.svelte.d.ts +2 -0
- package/dist/views/shared/context.svelte.d.ts +1 -0
- package/dist/views/shared/context.svelte.js +1 -0
- package/package.json +1 -8
- package/widget/widget.js +634 -1726
- package/dist/core/measure.d.ts +0 -104
- package/dist/core/measure.js +0 -195
- package/dist/views/planner/PlannerDay.svelte +0 -1279
- package/dist/views/planner/PlannerDay.svelte.d.ts +0 -30
package/README.md
CHANGED
|
@@ -46,7 +46,7 @@ Users can also switch via the built-in Day/Week/Month pills.
|
|
|
46
46
|
Planner views are designed for direct manipulation:
|
|
47
47
|
|
|
48
48
|
- **Move** — drag an event to another day or time; a ghost previews the target before the move commits.
|
|
49
|
-
- **Resize** — drag an event's edge handles
|
|
49
|
+
- **Resize** — drag an event's top/bottom edge handles to change its duration; `minDuration`/`maxDuration` clamp at commit.
|
|
50
50
|
- **Drag-to-create** — press on empty canvas and sweep to draw a new event; a plain click still creates a default-length slot. Both fire `oneventcreate` with the final range, after blocked-slot and disabled-date validation.
|
|
51
51
|
|
|
52
52
|
The month grid lists events as chips per day with a "+N more" overflow; clicking a day fires `ondayclick(date)` — the natural month → day drill-down.
|
|
@@ -743,21 +743,6 @@ const now = nowInZone('Asia/Tokyo');
|
|
|
743
743
|
formatInTimeZone(date, 'America/New_York', { hour: '2-digit', minute: '2-digit' });
|
|
744
744
|
```
|
|
745
745
|
|
|
746
|
-
## Text Fitting (optional)
|
|
747
|
-
|
|
748
|
-
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:
|
|
749
|
-
|
|
750
|
-
```svelte
|
|
751
|
-
<script>
|
|
752
|
-
import { onMount } from 'svelte';
|
|
753
|
-
import { initTextMeasure } from '@nomideusz/svelte-calendar';
|
|
754
|
-
|
|
755
|
-
onMount(() => initTextMeasure()); // resolves true if Pretext loaded
|
|
756
|
-
</script>
|
|
757
|
-
```
|
|
758
|
-
|
|
759
|
-
Custom views can measure text themselves via `createTextMeasure(options)` → `fitContent({ title, subtitle, maxWidth, maxHeight, … })`.
|
|
760
|
-
|
|
761
746
|
## Utilities
|
|
762
747
|
|
|
763
748
|
Small helpers used by the built-in views, exported for custom rendering:
|
|
@@ -838,6 +823,7 @@ The widget renders inside shadow DOM: host-page CSS (resets, theme stylesheets)
|
|
|
838
823
|
| `minDuration` | `number` | — | Minimum event duration in minutes (enforced on create & resize) |
|
|
839
824
|
| `maxDuration` | `number` | — | Maximum event duration in minutes (enforced on create & resize) |
|
|
840
825
|
| `compact` | `boolean` | `false` | Minimal text-row rendering in Agenda views (dot + time + title) |
|
|
826
|
+
| `columns` | `boolean` | `false` | Timetable layout: week-agenda days as side-by-side columns on desktop (mobile keeps the stacked list). Pairs well with `equalDays`; overrides `compact` while active |
|
|
841
827
|
| `dayHeader` | `Snippet<[{ date, isToday, dayName }]>` | — | Custom day header snippet for planner/agenda views |
|
|
842
828
|
| `header` | `Snippet<[HeaderContext]>` | — | Replace entire header chrome (date label + mode pills + nav) |
|
|
843
829
|
| `navigation` | `Snippet<[NavigationContext]>` | — | Replace just the prev/next/today controls |
|
|
@@ -69,6 +69,7 @@ let {
|
|
|
69
69
|
maxDuration,
|
|
70
70
|
disabledDates,
|
|
71
71
|
compact = false,
|
|
72
|
+
columns = false,
|
|
72
73
|
mobile: mobileProp = "auto",
|
|
73
74
|
event: eventSnippet,
|
|
74
75
|
empty: emptySnippet,
|
|
@@ -294,6 +295,9 @@ setContext("calendar", {
|
|
|
294
295
|
get compact() {
|
|
295
296
|
return compact;
|
|
296
297
|
},
|
|
298
|
+
get columns() {
|
|
299
|
+
return columns;
|
|
300
|
+
},
|
|
297
301
|
get labels() {
|
|
298
302
|
return mergedLabels;
|
|
299
303
|
},
|
|
@@ -81,6 +81,14 @@ interface Props {
|
|
|
81
81
|
disabledDates?: Date[];
|
|
82
82
|
/** Compact mode: use minimal text-row rendering in Agenda views (dot + time + title). */
|
|
83
83
|
compact?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Timetable layout: week-agenda days render as side-by-side columns
|
|
86
|
+
* (classic class-schedule grid) instead of a vertical list. Desktop
|
|
87
|
+
* only — mobile keeps the stacked layout. Pairs well with `equalDays`
|
|
88
|
+
* for recurring/template schedules. Overrides `compact` while active
|
|
89
|
+
* (single-line rows truncate at column width).
|
|
90
|
+
*/
|
|
91
|
+
columns?: boolean;
|
|
84
92
|
/**
|
|
85
93
|
* Mobile mode.
|
|
86
94
|
* - `'auto'` (default): detect via viewport width (< 768 px)
|
package/dist/core/index.d.ts
CHANGED
|
@@ -7,5 +7,3 @@ export type { CalendarLabels } from './locale.js';
|
|
|
7
7
|
export { toZonedTime, fromZonedTime, nowInZone, formatInTimeZone, } from './timezone.js';
|
|
8
8
|
export type { TimelineEvent, BlockedSlot, EventStatus, } from './types.js';
|
|
9
9
|
export { generatePalette, extractAccent, VIVID_PALETTE } from './palette.js';
|
|
10
|
-
export { createTextMeasure, initTextMeasure } from './measure.js';
|
|
11
|
-
export type { TextMeasure, TextMeasureOptions, ContentFit } from './measure.js';
|
package/dist/core/index.js
CHANGED
|
@@ -9,5 +9,3 @@ export { setDefaultLocale, getDefaultLocale, is24HourLocale, fmtH, fmtTime, fmtD
|
|
|
9
9
|
export { toZonedTime, fromZonedTime, nowInZone, formatInTimeZone, } from './timezone.js';
|
|
10
10
|
// Palette
|
|
11
11
|
export { generatePalette, extractAccent, VIVID_PALETTE } from './palette.js';
|
|
12
|
-
// Text measurement (optional Pretext integration)
|
|
13
|
-
export { createTextMeasure, initTextMeasure } from './measure.js';
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import type { DateRange } from '../adapters/types.js';
|
|
2
2
|
export type { DateRange };
|
|
3
3
|
/**
|
|
4
|
-
* Built-in view IDs. Custom view IDs are also supported — CalendarViewId
|
|
5
|
-
* is typed as `string` so consumers can register any ID.
|
|
4
|
+
* Built-in view IDs. Custom view IDs are also supported — see CalendarViewId.
|
|
6
5
|
*/
|
|
7
|
-
export type BuiltInViewId = 'day-planner' | 'day-agenda' | 'week-planner' | 'week-agenda' | 'month-grid';
|
|
6
|
+
export type BuiltInViewId = 'day-planner' | 'day-agenda' | 'day-mobile' | 'week-planner' | 'week-agenda' | 'week-mobile' | 'month-grid';
|
|
8
7
|
/**
|
|
9
8
|
* Any view identifier. Use built-in strings like 'day-planner' or your own
|
|
10
9
|
* custom IDs like 'day-kanban', 'week-resource', etc.
|
|
10
|
+
* (`string & {}` keeps the type open while preserving IDE autocomplete
|
|
11
|
+
* for the built-in IDs.)
|
|
11
12
|
*/
|
|
12
|
-
export type CalendarViewId = string;
|
|
13
|
+
export type CalendarViewId = BuiltInViewId | (string & {});
|
|
13
14
|
export type ViewMode = 'day' | 'week' | 'month';
|
|
14
15
|
export interface ViewStateOptions {
|
|
15
16
|
view?: CalendarViewId;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { TimelineEvent } from '../core/types.js';
|
|
2
|
+
import type { CalendarAdapter } from '../adapters/types.js';
|
|
3
|
+
export interface RangeAgendaOptions {
|
|
4
|
+
/** Data source (required). Can be a getter for reactive adapters. */
|
|
5
|
+
adapter: CalendarAdapter | (() => CalendarAdapter);
|
|
6
|
+
/** Days per page — prev()/next() move by this many (default: 7) */
|
|
7
|
+
days?: number;
|
|
8
|
+
/**
|
|
9
|
+
* First visible day (default: today). Not auto-aligned: pass the Monday
|
|
10
|
+
* of the week yourself if you want calendar-week pages.
|
|
11
|
+
*/
|
|
12
|
+
initialDate?: Date;
|
|
13
|
+
/** BCP 47 locale tag (e.g. 'en-US', 'pl-PL') for the format helpers */
|
|
14
|
+
locale?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface RangeAgendaDay {
|
|
17
|
+
/** Start-of-day timestamp (ms) */
|
|
18
|
+
ms: number;
|
|
19
|
+
/** Date object for this day */
|
|
20
|
+
date: Date;
|
|
21
|
+
/** ISO weekday (1=Mon … 7=Sun) */
|
|
22
|
+
weekday: number;
|
|
23
|
+
/** Is this today? (evaluated when the window derives — does not tick) */
|
|
24
|
+
isToday: boolean;
|
|
25
|
+
/** Is this day fully in the past? */
|
|
26
|
+
isPast: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Events overlapping this day, sorted by start. Multi-day events appear
|
|
29
|
+
* on every day they touch; all-day events sort first (00:00 start).
|
|
30
|
+
*/
|
|
31
|
+
events: TimelineEvent[];
|
|
32
|
+
}
|
|
33
|
+
export interface HeadlessRangeAgenda {
|
|
34
|
+
/** Every day in the current window, in order, with events attached */
|
|
35
|
+
readonly days: RangeAgendaDay[];
|
|
36
|
+
/** The current window */
|
|
37
|
+
readonly range: {
|
|
38
|
+
start: Date;
|
|
39
|
+
end: Date;
|
|
40
|
+
};
|
|
41
|
+
/** Total event count in the window */
|
|
42
|
+
readonly count: number;
|
|
43
|
+
/** Whether the adapter is loading */
|
|
44
|
+
readonly loading: boolean;
|
|
45
|
+
/** Last adapter error, if any */
|
|
46
|
+
readonly error: string | null;
|
|
47
|
+
/** Page back one window */
|
|
48
|
+
prev(): void;
|
|
49
|
+
/** Page forward one window */
|
|
50
|
+
next(): void;
|
|
51
|
+
/** Move the window start to today (not re-aligned; use setDate for aligned jumps) */
|
|
52
|
+
goToday(): void;
|
|
53
|
+
/** Set the window start to a specific date */
|
|
54
|
+
setDate(date: Date): void;
|
|
55
|
+
/** Format a Date to locale time string (e.g. "14:30") */
|
|
56
|
+
fmtTime(date: Date): string;
|
|
57
|
+
/** Format event duration (e.g. "1h 30m") */
|
|
58
|
+
fmtDuration(event: TimelineEvent): string;
|
|
59
|
+
/** Format time range (e.g. "14:00 – 15:30") */
|
|
60
|
+
fmtRange(event: TimelineEvent): string;
|
|
61
|
+
}
|
|
62
|
+
export declare function createRangeAgenda(options: RangeAgendaOptions): HeadlessRangeAgenda;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createRangeAgenda() — headless multi-day agenda state.
|
|
3
|
+
*
|
|
4
|
+
* Returns reactive state for rendering a window of days (default: one week)
|
|
5
|
+
* with events grouped per day — zero DOM, zero presentation opinions.
|
|
6
|
+
* Sits between createAgenda (live single day) and createCalendar (full grid
|
|
7
|
+
* engine): no clock, no drag, no selection — just "these days, these events",
|
|
8
|
+
* plus paging. Built for read-only schedule surfaces: public timetables,
|
|
9
|
+
* class listings, embeds.
|
|
10
|
+
*
|
|
11
|
+
* Must be called during component initialisation (Svelte 5 rune scope).
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```svelte
|
|
15
|
+
* <script>
|
|
16
|
+
* import { createRangeAgenda, createMemoryAdapter } from '@nomideusz/svelte-calendar';
|
|
17
|
+
*
|
|
18
|
+
* const adapter = createMemoryAdapter([...]);
|
|
19
|
+
* const agenda = createRangeAgenda({ adapter, days: 7 });
|
|
20
|
+
* </script>
|
|
21
|
+
*
|
|
22
|
+
* <button onclick={agenda.prev}>←</button>
|
|
23
|
+
* <button onclick={agenda.next}>→</button>
|
|
24
|
+
*
|
|
25
|
+
* {#each agenda.days.filter((d) => d.events.length > 0) as day}
|
|
26
|
+
* <h3>{day.date.toLocaleDateString()}</h3>
|
|
27
|
+
* {#each day.events as ev}
|
|
28
|
+
* <a href="/book?slot={ev.id}">{agenda.fmtTime(ev.start)} {ev.title}</a>
|
|
29
|
+
* {/each}
|
|
30
|
+
* {/each}
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
import { untrack } from 'svelte';
|
|
34
|
+
import { createEventStore } from '../engine/event-store.svelte.js';
|
|
35
|
+
import { sod, DAY_MS } from '../core/time.js';
|
|
36
|
+
import { fmtTime as _fmtTime, fmtDuration } from '../core/locale.js';
|
|
37
|
+
// ─── Implementation ─────────────────────────────────────
|
|
38
|
+
export function createRangeAgenda(options) {
|
|
39
|
+
const { initialDate, locale, days: dayCount = 7 } = options;
|
|
40
|
+
const resolveAdapter = typeof options.adapter === 'function'
|
|
41
|
+
? options.adapter
|
|
42
|
+
: () => options.adapter;
|
|
43
|
+
const store = $derived(createEventStore(resolveAdapter()));
|
|
44
|
+
// ── Window start (reactive, writable) ──
|
|
45
|
+
let startMs = $state(sod(initialDate?.getTime() ?? Date.now()));
|
|
46
|
+
const endMs = $derived(startMs + dayCount * DAY_MS);
|
|
47
|
+
// ── Load events for the window (re-runs on paging / adapter swap) ──
|
|
48
|
+
$effect(() => {
|
|
49
|
+
store.load({ start: new Date(startMs), end: new Date(endMs) });
|
|
50
|
+
});
|
|
51
|
+
// Eager initial load
|
|
52
|
+
untrack(() => {
|
|
53
|
+
store.load({ start: new Date(startMs), end: new Date(endMs) });
|
|
54
|
+
});
|
|
55
|
+
// ── Day derivations ──
|
|
56
|
+
const days = $derived.by(() => {
|
|
57
|
+
const todayMs = sod(Date.now());
|
|
58
|
+
const events = store.events;
|
|
59
|
+
return Array.from({ length: dayCount }, (_, i) => {
|
|
60
|
+
const ms = startMs + i * DAY_MS;
|
|
61
|
+
const dayEnd = ms + DAY_MS;
|
|
62
|
+
const date = new Date(ms);
|
|
63
|
+
// JS getDay(): 0=Sun … 6=Sat → ISO 1=Mon … 7=Sun
|
|
64
|
+
const weekday = ((date.getDay() + 6) % 7) + 1;
|
|
65
|
+
return {
|
|
66
|
+
ms,
|
|
67
|
+
date,
|
|
68
|
+
weekday,
|
|
69
|
+
isToday: ms === todayMs,
|
|
70
|
+
isPast: dayEnd <= todayMs,
|
|
71
|
+
events: events
|
|
72
|
+
.filter((ev) => ev.start.getTime() < dayEnd && ev.end.getTime() > ms)
|
|
73
|
+
.sort((a, b) => a.start.getTime() - b.start.getTime()),
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
const count = $derived(days.reduce((n, d) => n + d.events.length, 0));
|
|
78
|
+
return {
|
|
79
|
+
get days() {
|
|
80
|
+
return days;
|
|
81
|
+
},
|
|
82
|
+
get range() {
|
|
83
|
+
return { start: new Date(startMs), end: new Date(endMs) };
|
|
84
|
+
},
|
|
85
|
+
get count() {
|
|
86
|
+
return count;
|
|
87
|
+
},
|
|
88
|
+
get loading() {
|
|
89
|
+
return store.loading;
|
|
90
|
+
},
|
|
91
|
+
get error() {
|
|
92
|
+
return store.error;
|
|
93
|
+
},
|
|
94
|
+
prev() {
|
|
95
|
+
startMs -= dayCount * DAY_MS;
|
|
96
|
+
},
|
|
97
|
+
next() {
|
|
98
|
+
startMs += dayCount * DAY_MS;
|
|
99
|
+
},
|
|
100
|
+
goToday() {
|
|
101
|
+
startMs = sod(Date.now());
|
|
102
|
+
},
|
|
103
|
+
setDate(date) {
|
|
104
|
+
startMs = sod(date.getTime());
|
|
105
|
+
},
|
|
106
|
+
fmtTime: (d) => _fmtTime(d, locale),
|
|
107
|
+
fmtDuration: (ev) => fmtDuration(ev.start, ev.end),
|
|
108
|
+
fmtRange: (ev) => `${_fmtTime(ev.start, locale)} – ${_fmtTime(ev.end, locale)}`,
|
|
109
|
+
};
|
|
110
|
+
}
|
package/dist/headless/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { createCalendar } from './create-calendar.svelte.js';
|
|
2
2
|
export { createAgenda } from './create-agenda.svelte.js';
|
|
3
3
|
export type { AgendaOptions, HeadlessAgenda } from './create-agenda.svelte.js';
|
|
4
|
+
export { createRangeAgenda } from './create-range-agenda.svelte.js';
|
|
5
|
+
export type { RangeAgendaOptions, RangeAgendaDay, HeadlessRangeAgenda, } from './create-range-agenda.svelte.js';
|
|
4
6
|
export type { HeadlessCalendarOptions, HeadlessCalendar, HeadlessDay, HeadlessWeek, TodayQueue, HeaderContext, NavigationContext, } from './types.js';
|
package/dist/headless/index.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -4,14 +4,14 @@ export { Planner, Agenda, Mobile } from './views/index.js';
|
|
|
4
4
|
export { default as MonthGrid } from './views/month/MonthGrid.svelte';
|
|
5
5
|
export type { CalendarView } from './calendar/index.js';
|
|
6
6
|
export { createEventStore, createViewState, createSelection, createDragState, } from './engine/index.js';
|
|
7
|
-
export type { EventStore, ViewState, ViewStateOptions, CalendarViewId, BuiltInViewId, ViewMode, Selection, DragState, DragMode, DragPayload, } from './engine/index.js';
|
|
7
|
+
export type { EventStore, ViewState, ViewStateOptions, CalendarViewId, BuiltInViewId, ViewMode, Selection as CalendarSelection, DragState, DragMode, DragPayload, } from './engine/index.js';
|
|
8
8
|
export { createMemoryAdapter, createRestAdapter, createRecurringAdapter, createMappedAdapter, createCompositeAdapter, createJmapAdapter } from './adapters/index.js';
|
|
9
|
-
export type { CalendarAdapter, WritableCalendarAdapter, DateRange, RestAdapterOptions, RecurringEvent, RecurringAdapterOptions, FieldMapping, MappedAdapterOptions, MutationHandler, CompositeAdapterOptions, JmapClient, JmapCalendarAdapterOptions, } from './adapters/index.js';
|
|
10
|
-
export { createClock, startOfWeek, fmtH, fmtTime, fmtDuration, weekdayShort, weekdayLong, monthShort, monthLong, dateShort, dateWithWeekday, fmtDay, fmtWeekRange, setDefaultLocale, getDefaultLocale, is24HourLocale, defaultLabels, setLabels, resetLabels, getLabels, toZonedTime, fromZonedTime, nowInZone, formatInTimeZone, generatePalette, extractAccent, VIVID_PALETTE, isMultiDay, isAllDay, segmentForDay,
|
|
11
|
-
export type { Clock, TimelineEvent, BlockedSlot, DaySegment, CalendarLabels, EventStatus,
|
|
9
|
+
export type { CalendarAdapter, WritableCalendarAdapter, DateRange, MemoryAdapterOptions, RestAdapterOptions, RecurringEvent, RecurringAdapterOptions, FieldMapping, MappedAdapterOptions, MutationHandler, CompositeAdapterOptions, JmapClient, JmapCalendarAdapterOptions, } from './adapters/index.js';
|
|
10
|
+
export { createClock, startOfWeek, fmtH, fmtTime, fmtDuration, weekdayShort, weekdayLong, monthShort, monthLong, dateShort, dateWithWeekday, fmtDay, fmtWeekRange, setDefaultLocale, getDefaultLocale, is24HourLocale, defaultLabels, setLabels, resetLabels, getLabels, toZonedTime, fromZonedTime, nowInZone, formatInTimeZone, generatePalette, extractAccent, VIVID_PALETTE, isMultiDay, isAllDay, segmentForDay, } from './core/index.js';
|
|
11
|
+
export type { Clock, TimelineEvent, BlockedSlot, DaySegment, CalendarLabels, EventStatus, } from './core/index.js';
|
|
12
12
|
export { auto, neutral, midnight, presets } from './theme/index.js';
|
|
13
13
|
export { probeHostTheme, observeHostTheme } from './theme/index.js';
|
|
14
14
|
export { wrapAdapterWithTimezone } from './core/timezone.js';
|
|
15
15
|
export type { PresetName, AutoThemeOptions } from './theme/index.js';
|
|
16
|
-
export { createCalendar, createAgenda } from './headless/index.js';
|
|
17
|
-
export type { HeadlessCalendarOptions, HeadlessCalendar, HeadlessDay, HeadlessWeek, TodayQueue, HeaderContext, NavigationContext, AgendaOptions, HeadlessAgenda, } from './headless/index.js';
|
|
16
|
+
export { createCalendar, createAgenda, createRangeAgenda } from './headless/index.js';
|
|
17
|
+
export type { HeadlessCalendarOptions, HeadlessCalendar, HeadlessDay, HeadlessWeek, TodayQueue, HeaderContext, NavigationContext, AgendaOptions, HeadlessAgenda, RangeAgendaOptions, RangeAgendaDay, HeadlessRangeAgenda, } from './headless/index.js';
|
package/dist/index.js
CHANGED
|
@@ -10,10 +10,10 @@ export { createEventStore, createViewState, createSelection, createDragState, }
|
|
|
10
10
|
// ─── Adapters ───────────────────────────────────────────
|
|
11
11
|
export { createMemoryAdapter, createRestAdapter, createRecurringAdapter, createMappedAdapter, createCompositeAdapter, createJmapAdapter } from './adapters/index.js';
|
|
12
12
|
// ─── Core: clock, time, locale, types ───────────────────
|
|
13
|
-
export { createClock, startOfWeek, fmtH, fmtTime, fmtDuration, weekdayShort, weekdayLong, monthShort, monthLong, dateShort, dateWithWeekday, fmtDay, fmtWeekRange, setDefaultLocale, getDefaultLocale, is24HourLocale, defaultLabels, setLabels, resetLabels, getLabels, toZonedTime, fromZonedTime, nowInZone, formatInTimeZone, generatePalette, extractAccent, VIVID_PALETTE, isMultiDay, isAllDay, segmentForDay,
|
|
13
|
+
export { createClock, startOfWeek, fmtH, fmtTime, fmtDuration, weekdayShort, weekdayLong, monthShort, monthLong, dateShort, dateWithWeekday, fmtDay, fmtWeekRange, setDefaultLocale, getDefaultLocale, is24HourLocale, defaultLabels, setLabels, resetLabels, getLabels, toZonedTime, fromZonedTime, nowInZone, formatInTimeZone, generatePalette, extractAccent, VIVID_PALETTE, isMultiDay, isAllDay, segmentForDay, } from './core/index.js';
|
|
14
14
|
// ─── Themes ─────────────────────────────────────────────
|
|
15
15
|
export { auto, neutral, midnight, presets } from './theme/index.js';
|
|
16
16
|
export { probeHostTheme, observeHostTheme } from './theme/index.js';
|
|
17
17
|
export { wrapAdapterWithTimezone } from './core/timezone.js';
|
|
18
18
|
// ─── Headless API ───────────────────────────────────────
|
|
19
|
-
export { createCalendar, createAgenda } from './headless/index.js';
|
|
19
|
+
export { createCalendar, createAgenda, createRangeAgenda } from './headless/index.js';
|
package/dist/theme/auto.js
CHANGED
|
@@ -302,28 +302,59 @@ function probeAccent(root) {
|
|
|
302
302
|
return null;
|
|
303
303
|
}
|
|
304
304
|
// ── Font detection ──────────────────────────────────────
|
|
305
|
-
|
|
306
|
-
|
|
305
|
+
/** Common CSS variable names for the host's monospace font stack. */
|
|
306
|
+
const MONO_VAR_CANDIDATES = [
|
|
307
|
+
'--font-mono', // Tailwind v4 theme tokens, common convention
|
|
308
|
+
'--font-family-mono',
|
|
309
|
+
'--font-monospace',
|
|
310
|
+
'--mono-font',
|
|
311
|
+
'--code-font',
|
|
312
|
+
];
|
|
313
|
+
const MONO_FALLBACK = "ui-monospace, 'SFMono-Regular', monospace";
|
|
314
|
+
/**
|
|
315
|
+
* Adopt the host page's fonts.
|
|
316
|
+
*
|
|
317
|
+
* Sans: the host element's *computed* font-family — the resolved authored
|
|
318
|
+
* stack, so webfont names come through verbatim. (Declaring `--dt-sans:
|
|
319
|
+
* inherit` does NOT work: a custom property with no ancestor value computes
|
|
320
|
+
* to guaranteed-invalid, so `var(--dt-sans, fallback)` used the fallback and
|
|
321
|
+
* the host font never applied.)
|
|
322
|
+
*
|
|
323
|
+
* Mono: common CSS variables on :root, then any code-ish element's computed
|
|
324
|
+
* font, then a generic stack.
|
|
325
|
+
*/
|
|
326
|
+
function probeFonts(host) {
|
|
327
|
+
let sans = 'system-ui, sans-serif';
|
|
307
328
|
try {
|
|
308
|
-
const
|
|
309
|
-
if (
|
|
310
|
-
|
|
329
|
+
const f = getComputedStyle(host).fontFamily;
|
|
330
|
+
if (f)
|
|
331
|
+
sans = f;
|
|
311
332
|
}
|
|
312
333
|
catch {
|
|
313
334
|
// getComputedStyle may fail in test environments
|
|
314
335
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
336
|
+
let mono = '';
|
|
337
|
+
try {
|
|
338
|
+
const rootCs = getComputedStyle(document.documentElement);
|
|
339
|
+
for (const name of MONO_VAR_CANDIDATES) {
|
|
340
|
+
const val = rootCs.getPropertyValue(name).trim();
|
|
341
|
+
if (val) {
|
|
342
|
+
mono = val;
|
|
343
|
+
break;
|
|
344
|
+
}
|
|
323
345
|
}
|
|
324
|
-
catch { /* ignore */ }
|
|
325
346
|
}
|
|
326
|
-
|
|
347
|
+
catch { /* ignore */ }
|
|
348
|
+
if (!mono) {
|
|
349
|
+
const code = document.querySelector('pre, code, kbd, samp');
|
|
350
|
+
if (code) {
|
|
351
|
+
try {
|
|
352
|
+
mono = getComputedStyle(code).fontFamily || '';
|
|
353
|
+
}
|
|
354
|
+
catch { /* ignore */ }
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return { sans, mono: mono || MONO_FALLBACK };
|
|
327
358
|
}
|
|
328
359
|
// ── Background walking ──────────────────────────────────
|
|
329
360
|
/**
|
|
@@ -436,13 +467,9 @@ export function probeHostTheme(el, options = {}) {
|
|
|
436
467
|
}
|
|
437
468
|
const [aH, aS, aL] = rgbToHsl(...accent);
|
|
438
469
|
// ── Fonts ──
|
|
439
|
-
// When auto-probing, use `inherit` so the calendar naturally inherits the
|
|
440
|
-
// host page's font via CSS inheritance. Probing getComputedStyle().fontFamily
|
|
441
|
-
// and re-declaring it can break the cascade (resolved names differ from the
|
|
442
|
-
// authored font stack). Only use an explicit value if the user overrides.
|
|
443
470
|
const fonts = options.font
|
|
444
|
-
? { sans: options.font, mono:
|
|
445
|
-
:
|
|
471
|
+
? { sans: options.font, mono: MONO_FALLBACK }
|
|
472
|
+
: probeFonts(host);
|
|
446
473
|
// ── Text colors (probe host's actual text, validate contrast) ──
|
|
447
474
|
const probedText = probeTextColor(host, bg);
|
|
448
475
|
const textBase = probedText ?? (isDark ? [226, 232, 240] : [30, 30, 46]);
|
|
@@ -545,11 +572,19 @@ export function observeHostTheme(el, callback, options = {}) {
|
|
|
545
572
|
attributes: true,
|
|
546
573
|
attributeFilter: ['class', 'style', 'data-theme', 'data-mode', 'color-scheme'],
|
|
547
574
|
});
|
|
575
|
+
// 3. Re-probe once the document settles. A probe during initial load can
|
|
576
|
+
// read pre-stylesheet values (wrong background → wrong light/dark call);
|
|
577
|
+
// late webfonts change computed font stacks. Both are one-shot events.
|
|
578
|
+
if (document.readyState !== 'complete') {
|
|
579
|
+
window.addEventListener('load', scheduleUpdate, { once: true });
|
|
580
|
+
}
|
|
581
|
+
document.fonts?.ready?.then(scheduleUpdate).catch(() => { });
|
|
548
582
|
// Initial probe
|
|
549
583
|
update();
|
|
550
584
|
return () => {
|
|
551
585
|
cancelAnimationFrame(rafId);
|
|
552
586
|
mql?.removeEventListener('change', onScheme);
|
|
587
|
+
window.removeEventListener('load', scheduleUpdate);
|
|
553
588
|
observer.disconnect();
|
|
554
589
|
};
|
|
555
590
|
}
|
package/dist/theme/presets.d.ts
CHANGED
|
@@ -23,16 +23,17 @@
|
|
|
23
23
|
*/
|
|
24
24
|
export declare const auto = "";
|
|
25
25
|
/**
|
|
26
|
-
* Neutral — explicit light theme. White bg, blue accent,
|
|
26
|
+
* Neutral — explicit light theme. White bg, blue accent, system font stack
|
|
27
|
+
* (set --dt-sans on an ancestor or via CSS to use a custom font).
|
|
27
28
|
* Use when embedding standalone without ancestor --dt-* vars.
|
|
28
29
|
*/
|
|
29
|
-
export declare const neutral = "\n\t--dt-stage-bg: #ffffff;\n\t--dt-bg: #ffffff;\n\t--dt-surface: #f9fafb;\n\t--dt-border: rgba(0, 0, 0, 0.08);\n\t--dt-border-day: rgba(0, 0, 0, 0.14);\n\t--dt-text: rgba(0, 0, 0, 0.87);\n\t--dt-text-2: rgba(0, 0, 0, 0.54);\n\t--dt-text-3: rgba(0, 0, 0, 0.38);\n\t--dt-accent: var(--asini-accent, #2563eb);\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: color-mix(in srgb, var(--dt-accent) 7%, transparent);\n\t--dt-btn-text: #fff;\n\t--dt-scrollbar: rgba(0, 0, 0, 0.1);\n\t--dt-success: rgba(22, 163, 74, 0.7);\n\t--dt-weekend-bg: rgba(0, 0, 0, 0.02);\n\t--dt-hover: rgba(0, 0, 0, 0.04);\n\t--dt-
|
|
30
|
+
export declare const neutral = "\n\t--dt-stage-bg: #ffffff;\n\t--dt-bg: #ffffff;\n\t--dt-surface: #f9fafb;\n\t--dt-border: rgba(0, 0, 0, 0.08);\n\t--dt-border-day: rgba(0, 0, 0, 0.14);\n\t--dt-text: rgba(0, 0, 0, 0.87);\n\t--dt-text-2: rgba(0, 0, 0, 0.54);\n\t--dt-text-3: rgba(0, 0, 0, 0.38);\n\t--dt-accent: var(--asini-accent, #2563eb);\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: color-mix(in srgb, var(--dt-accent) 7%, transparent);\n\t--dt-btn-text: #fff;\n\t--dt-scrollbar: rgba(0, 0, 0, 0.1);\n\t--dt-success: rgba(22, 163, 74, 0.7);\n\t--dt-weekend-bg: rgba(0, 0, 0, 0.02);\n\t--dt-hover: rgba(0, 0, 0, 0.04);\n\t--dt-mono: ui-monospace, 'SFMono-Regular', monospace;\n";
|
|
30
31
|
/** Midnight Industrial — dark charcoal + red accent, tech monitoring */
|
|
31
|
-
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.55);\n\t--dt-text-3: rgba(100, 116, 139, 0.55);\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: rgba(239, 68, 68, 0.07);\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-
|
|
32
|
+
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.55);\n\t--dt-text-3: rgba(100, 116, 139, 0.55);\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: rgba(239, 68, 68, 0.07);\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-mono: ui-monospace, 'SFMono-Regular', monospace;\n";
|
|
32
33
|
/** All available presets keyed by name */
|
|
33
34
|
export declare const presets: {
|
|
34
35
|
readonly auto: "";
|
|
35
|
-
readonly neutral: "\n\t--dt-stage-bg: #ffffff;\n\t--dt-bg: #ffffff;\n\t--dt-surface: #f9fafb;\n\t--dt-border: rgba(0, 0, 0, 0.08);\n\t--dt-border-day: rgba(0, 0, 0, 0.14);\n\t--dt-text: rgba(0, 0, 0, 0.87);\n\t--dt-text-2: rgba(0, 0, 0, 0.54);\n\t--dt-text-3: rgba(0, 0, 0, 0.38);\n\t--dt-accent: var(--asini-accent, #2563eb);\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: color-mix(in srgb, var(--dt-accent) 7%, transparent);\n\t--dt-btn-text: #fff;\n\t--dt-scrollbar: rgba(0, 0, 0, 0.1);\n\t--dt-success: rgba(22, 163, 74, 0.7);\n\t--dt-weekend-bg: rgba(0, 0, 0, 0.02);\n\t--dt-hover: rgba(0, 0, 0, 0.04);\n\t--dt-
|
|
36
|
-
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.55);\n\t--dt-text-3: rgba(100, 116, 139, 0.55);\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: rgba(239, 68, 68, 0.07);\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-
|
|
36
|
+
readonly neutral: "\n\t--dt-stage-bg: #ffffff;\n\t--dt-bg: #ffffff;\n\t--dt-surface: #f9fafb;\n\t--dt-border: rgba(0, 0, 0, 0.08);\n\t--dt-border-day: rgba(0, 0, 0, 0.14);\n\t--dt-text: rgba(0, 0, 0, 0.87);\n\t--dt-text-2: rgba(0, 0, 0, 0.54);\n\t--dt-text-3: rgba(0, 0, 0, 0.38);\n\t--dt-accent: var(--asini-accent, #2563eb);\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: color-mix(in srgb, var(--dt-accent) 7%, transparent);\n\t--dt-btn-text: #fff;\n\t--dt-scrollbar: rgba(0, 0, 0, 0.1);\n\t--dt-success: rgba(22, 163, 74, 0.7);\n\t--dt-weekend-bg: rgba(0, 0, 0, 0.02);\n\t--dt-hover: rgba(0, 0, 0, 0.04);\n\t--dt-mono: ui-monospace, 'SFMono-Regular', monospace;\n";
|
|
37
|
+
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.55);\n\t--dt-text-3: rgba(100, 116, 139, 0.55);\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: rgba(239, 68, 68, 0.07);\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-mono: ui-monospace, 'SFMono-Regular', monospace;\n";
|
|
37
38
|
};
|
|
38
39
|
export type PresetName = keyof typeof presets;
|
package/dist/theme/presets.js
CHANGED
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
*/
|
|
24
24
|
export const auto = ``;
|
|
25
25
|
/**
|
|
26
|
-
* Neutral — explicit light theme. White bg, blue accent,
|
|
26
|
+
* Neutral — explicit light theme. White bg, blue accent, system font stack
|
|
27
|
+
* (set --dt-sans on an ancestor or via CSS to use a custom font).
|
|
27
28
|
* Use when embedding standalone without ancestor --dt-* vars.
|
|
28
29
|
*/
|
|
29
30
|
export const neutral = `
|
|
@@ -44,7 +45,6 @@ export const neutral = `
|
|
|
44
45
|
--dt-success: rgba(22, 163, 74, 0.7);
|
|
45
46
|
--dt-weekend-bg: rgba(0, 0, 0, 0.02);
|
|
46
47
|
--dt-hover: rgba(0, 0, 0, 0.04);
|
|
47
|
-
--dt-sans: inherit;
|
|
48
48
|
--dt-mono: ui-monospace, 'SFMono-Regular', monospace;
|
|
49
49
|
`;
|
|
50
50
|
/** Midnight Industrial — dark charcoal + red accent, tech monitoring */
|
|
@@ -66,7 +66,6 @@ export const midnight = `
|
|
|
66
66
|
--dt-success: rgba(74, 222, 128, 0.7);
|
|
67
67
|
--dt-weekend-bg: rgba(148, 163, 184, 0.03);
|
|
68
68
|
--dt-hover: rgba(148, 163, 184, 0.06);
|
|
69
|
-
--dt-sans: inherit;
|
|
70
69
|
--dt-mono: ui-monospace, 'SFMono-Regular', monospace;
|
|
71
70
|
`;
|
|
72
71
|
/** All available presets keyed by name */
|
|
@@ -19,6 +19,8 @@ let {
|
|
|
19
19
|
const clock = createClock(ctx.timezone);
|
|
20
20
|
const viewState = $derived(ctx.viewState);
|
|
21
21
|
const equalDays = $derived(ctx.equalDays);
|
|
22
|
+
const showDates = $derived(ctx.showDates);
|
|
23
|
+
const hideDayHead = $derived(showDates && !!viewState);
|
|
22
24
|
const isMobile = $derived(ctx.isMobile);
|
|
23
25
|
const autoHeight = $derived(ctx.autoHeight);
|
|
24
26
|
const compact = $derived(ctx.compact);
|
|
@@ -106,7 +108,8 @@ const hiddenDoneCount = $derived(showAllDone ? 0 : Math.max(0, dayCat.past.lengt
|
|
|
106
108
|
onpointercancel={onPointerCancel}
|
|
107
109
|
>
|
|
108
110
|
<div class="ag-body" role="group" aria-label={L.todaysLineup}>
|
|
109
|
-
<!-- ─── In-view date header (
|
|
111
|
+
<!-- ─── In-view date header (only when the chrome doesn't label the day) ─── -->
|
|
112
|
+
{#if !hideDayHead}
|
|
110
113
|
<div class="ag-day-head">
|
|
111
114
|
{#if !equalDays && isToday}
|
|
112
115
|
<span class="ag-day-head-badge">{L.today}</span>
|
|
@@ -116,6 +119,7 @@ const hiddenDoneCount = $derived(showAllDone ? 0 : Math.max(0, dayCat.past.lengt
|
|
|
116
119
|
<span class="ag-day-head-name">{weekdayLong(dayMs, locale)}</span>
|
|
117
120
|
<span class="ag-day-head-date">{monthLong(dayMs, locale)} {dayNum(dayMs)}</span>
|
|
118
121
|
</div>
|
|
122
|
+
{/if}
|
|
119
123
|
{#if allDayBanner.length > 0}
|
|
120
124
|
<!-- ─── All-day / multi-day events ─── -->
|
|
121
125
|
<div class="ag-allday">
|
|
@@ -160,7 +164,6 @@ const hiddenDoneCount = $derived(showAllDone ? 0 : Math.max(0, dayCat.past.lengt
|
|
|
160
164
|
onpointerenter={() => oneventhover?.(ev)}
|
|
161
165
|
>
|
|
162
166
|
<EventContent event={ev}>
|
|
163
|
-
<span class="ag-compact-row-dot"></span>
|
|
164
167
|
<span class="ag-compact-row-time">{fmt(ev.start)}</span>
|
|
165
168
|
<div class="ag-compact-row-main">
|
|
166
169
|
<span class="ag-compact-row-title">{ev.title}</span>
|
|
@@ -256,7 +259,6 @@ const hiddenDoneCount = $derived(showAllDone ? 0 : Math.max(0, dayCat.past.lengt
|
|
|
256
259
|
onpointerenter={() => oneventhover?.(ev)}
|
|
257
260
|
>
|
|
258
261
|
<EventContent event={ev}>
|
|
259
|
-
<span class="ag-compact-row-dot"></span>
|
|
260
262
|
<span class="ag-compact-row-time">{fmt(ev.start)}</span>
|
|
261
263
|
<div class="ag-compact-row-main">
|
|
262
264
|
<span class="ag-compact-row-title">{ev.title}</span>
|
|
@@ -1071,11 +1073,7 @@ const hiddenDoneCount = $derived(showAllDone ? 0 : Math.max(0, dayCat.past.lengt
|
|
|
1071
1073
|
.ag-log-row--selected {
|
|
1072
1074
|
background: color-mix(in srgb, var(--ev-color) 6%, transparent);
|
|
1073
1075
|
border-radius: 6px;
|
|
1074
|
-
|
|
1075
|
-
padding-right: 8px;
|
|
1076
|
-
margin-left: -8px;
|
|
1077
|
-
margin-right: -8px;
|
|
1078
|
-
width: calc(100% + 16px);
|
|
1076
|
+
box-shadow: 0 0 0 8px color-mix(in srgb, var(--ev-color) 6%, transparent);
|
|
1079
1077
|
}
|
|
1080
1078
|
.ag-log-check {
|
|
1081
1079
|
font-size: 10px;
|
|
@@ -1137,13 +1135,10 @@ const hiddenDoneCount = $derived(showAllDone ? 0 : Math.max(0, dayCat.past.lengt
|
|
|
1137
1135
|
.ag-compact-row--selected {
|
|
1138
1136
|
background: color-mix(in srgb, var(--ev-color) 10%, transparent);
|
|
1139
1137
|
border-radius: 4px;
|
|
1140
|
-
/*
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
margin-left: -6px;
|
|
1145
|
-
margin-right: -6px;
|
|
1146
|
-
width: calc(100% + 12px);
|
|
1138
|
+
/* The highlight bleeds into the gutter via a spread shadow — zero
|
|
1139
|
+
layout impact, so nothing shifts or clips even when the host
|
|
1140
|
+
reduces the gutters below the bleed width. */
|
|
1141
|
+
box-shadow: 0 0 0 6px color-mix(in srgb, var(--ev-color) 10%, transparent);
|
|
1147
1142
|
}
|
|
1148
1143
|
.ag-compact-row:hover .ag-compact-row-title,
|
|
1149
1144
|
.ag-compact-row:active .ag-compact-row-title { color: var(--dt-text); }
|
|
@@ -1156,18 +1151,14 @@ const hiddenDoneCount = $derived(showAllDone ? 0 : Math.max(0, dayCat.past.lengt
|
|
|
1156
1151
|
box-shadow: 0 0 0 2px var(--dt-accent, #2563eb);
|
|
1157
1152
|
border-radius: 4px;
|
|
1158
1153
|
}
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
border-radius: 50%;
|
|
1163
|
-
background: var(--ev-color, var(--dt-accent));
|
|
1164
|
-
flex-shrink: 0;
|
|
1165
|
-
align-self: center;
|
|
1166
|
-
}
|
|
1154
|
+
/* The time label doubles as the class-color signal (replaces the old
|
|
1155
|
+
dot): the event color mixed toward the text color, so it stays
|
|
1156
|
+
legible on any palette and costs zero horizontal space. */
|
|
1167
1157
|
.ag-compact-row-time {
|
|
1168
1158
|
font-size: 11px;
|
|
1169
1159
|
font-family: var(--dt-mono, monospace);
|
|
1170
|
-
|
|
1160
|
+
font-weight: 500;
|
|
1161
|
+
color: color-mix(in srgb, var(--ev-color, var(--dt-accent)) 60%, var(--dt-text, rgba(0, 0, 0, 0.87)));
|
|
1171
1162
|
min-width: 64px;
|
|
1172
1163
|
flex-shrink: 0;
|
|
1173
1164
|
line-height: 1.4;
|
|
@@ -1195,12 +1186,6 @@ const hiddenDoneCount = $derived(showAllDone ? 0 : Math.max(0, dayCat.past.lengt
|
|
|
1195
1186
|
.ag--mobile .ag-compact-row-sub {
|
|
1196
1187
|
max-width: 100%;
|
|
1197
1188
|
}
|
|
1198
|
-
/* Wrapped rows are two lines tall — center-aligning the dot floats it
|
|
1199
|
-
between lines; pin it optically to the first (title) line instead. */
|
|
1200
|
-
.ag--mobile .ag-compact-row-dot {
|
|
1201
|
-
align-self: flex-start;
|
|
1202
|
-
margin-top: 8px;
|
|
1203
|
-
}
|
|
1204
1189
|
.ag-compact-row-title {
|
|
1205
1190
|
font-size: 12px;
|
|
1206
1191
|
font-weight: 500;
|