@nomideusz/svelte-calendar 0.2.3 → 0.3.1

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.
Files changed (44) hide show
  1. package/README.md +234 -6
  2. package/dist/adapters/index.d.ts +3 -0
  3. package/dist/adapters/index.js +1 -0
  4. package/dist/adapters/memory.d.ts +12 -1
  5. package/dist/adapters/memory.js +38 -4
  6. package/dist/adapters/recurring.d.ts +44 -0
  7. package/dist/adapters/recurring.js +120 -0
  8. package/dist/calendar/Calendar.svelte +20 -5
  9. package/dist/calendar/Calendar.svelte.d.ts +4 -0
  10. package/dist/core/index.d.ts +1 -0
  11. package/dist/core/index.js +2 -0
  12. package/dist/core/palette.d.ts +23 -0
  13. package/dist/core/palette.js +109 -0
  14. package/dist/core/types.d.ts +4 -0
  15. package/dist/index.d.ts +5 -5
  16. package/dist/index.js +4 -4
  17. package/dist/primitives/EventBlock.svelte +42 -0
  18. package/dist/theme/index.d.ts +1 -1
  19. package/dist/theme/index.js +1 -1
  20. package/dist/theme/presets.d.ts +10 -15
  21. package/dist/theme/presets.js +5 -11
  22. package/dist/views/agenda/Agenda.svelte +110 -0
  23. package/dist/views/day/DayGrid.svelte +38 -0
  24. package/dist/views/day/DayGrid.svelte.d.ts +5 -0
  25. package/dist/views/day/DayTimeline.svelte +27 -0
  26. package/dist/views/index.d.ts +1 -0
  27. package/dist/views/index.js +1 -0
  28. package/dist/views/schedule/WeekSchedule.svelte +133 -0
  29. package/dist/views/schedule/WeekSchedule.svelte.d.ts +38 -0
  30. package/dist/views/schedule/index.d.ts +1 -0
  31. package/dist/views/schedule/index.js +2 -0
  32. package/dist/views/settings/Settings.svelte +1 -1
  33. package/dist/views/week/WeekGrid.svelte +42 -5
  34. package/dist/views/week/WeekGrid.svelte.d.ts +3 -0
  35. package/dist/views/week/WeekHeatmap.svelte +12 -5
  36. package/dist/views/week/WeekHeatmap.svelte.d.ts +5 -1
  37. package/dist/widget/CalendarWidget.svelte +138 -0
  38. package/dist/widget/CalendarWidget.svelte.d.ts +23 -0
  39. package/dist/widget/index.d.ts +1 -0
  40. package/dist/widget/index.js +1 -0
  41. package/dist/widget/widget.d.ts +7 -0
  42. package/dist/widget/widget.js +9 -0
  43. package/package.json +5 -2
  44. package/widget/widget.js +260 -0
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Smart auto-color palette generator.
3
+ *
4
+ * Given a base accent hex (e.g. from `--dt-accent`), generates a
5
+ * palette of perceptually distinct colors that harmonize with the theme.
6
+ *
7
+ * Usage:
8
+ * generatePalette('#ef4444', 8) // 8 theme-harmonious colors
9
+ * generatePalette(undefined, 8) // falls back to the vivid default
10
+ */
11
+ // ── Hardcoded vivid fallback (original behavior) ────────
12
+ export const VIVID_PALETTE = [
13
+ '#ef4444', '#f97316', '#eab308', '#22c55e', '#14b8a6',
14
+ '#3b82f6', '#6366f1', '#a855f7', '#ec4899', '#f43f5e',
15
+ '#06b6d4', '#84cc16', '#d946ef', '#0ea5e9', '#10b981',
16
+ ];
17
+ // ── Color math (hex ↔ HSL) ──────────────────────────────
18
+ function hexToRgb(hex) {
19
+ const h = hex.replace('#', '');
20
+ const n = h.length === 3
21
+ ? parseInt(h[0] + h[0] + h[1] + h[1] + h[2] + h[2], 16)
22
+ : parseInt(h, 16);
23
+ return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
24
+ }
25
+ function rgbToHsl(r, g, b) {
26
+ r /= 255;
27
+ g /= 255;
28
+ b /= 255;
29
+ const max = Math.max(r, g, b), min = Math.min(r, g, b);
30
+ const l = (max + min) / 2;
31
+ if (max === min)
32
+ return [0, 0, l];
33
+ const d = max - min;
34
+ const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
35
+ let h = 0;
36
+ if (max === r)
37
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
38
+ else if (max === g)
39
+ h = ((b - r) / d + 2) / 6;
40
+ else
41
+ h = ((r - g) / d + 4) / 6;
42
+ return [h, s, l];
43
+ }
44
+ function hslToHex(h, s, l) {
45
+ h = ((h % 1) + 1) % 1; // normalize to [0, 1)
46
+ const hue2rgb = (p, q, t) => {
47
+ if (t < 0)
48
+ t += 1;
49
+ if (t > 1)
50
+ t -= 1;
51
+ if (t < 1 / 6)
52
+ return p + (q - p) * 6 * t;
53
+ if (t < 1 / 2)
54
+ return q;
55
+ if (t < 2 / 3)
56
+ return p + (q - p) * (2 / 3 - t) * 6;
57
+ return p;
58
+ };
59
+ let r, g, b;
60
+ if (s === 0) {
61
+ r = g = b = l;
62
+ }
63
+ else {
64
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
65
+ const p = 2 * l - q;
66
+ r = hue2rgb(p, q, h + 1 / 3);
67
+ g = hue2rgb(p, q, h);
68
+ b = hue2rgb(p, q, h - 1 / 3);
69
+ }
70
+ const toHex = (v) => Math.round(v * 255).toString(16).padStart(2, '0');
71
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
72
+ }
73
+ // ── Palette generation ──────────────────────────────────
74
+ /**
75
+ * Generate `count` visually distinct and theme-harmonious colors
76
+ * by rotating hue evenly from the base accent, keeping saturation
77
+ * and lightness within a pleasant range.
78
+ *
79
+ * Dark themes (l < 0.5): bump lightness to 0.55–0.65 so colors pop on dark bg.
80
+ * Light themes (l ≥ 0.5): pull lightness to 0.38–0.48 so colors read on light bg.
81
+ *
82
+ * @param accent Hex color string (e.g. '#ef4444'). If undefined, returns VIVID_PALETTE.
83
+ * @param count Number of colors to generate (default: 15).
84
+ */
85
+ export function generatePalette(accent, count = 15) {
86
+ if (!accent)
87
+ return VIVID_PALETTE.slice(0, count);
88
+ const [r, g, b] = hexToRgb(accent);
89
+ const [baseH, baseS, baseL] = rgbToHsl(r, g, b);
90
+ // Determine a good saturation range
91
+ const sat = Math.max(0.45, Math.min(0.8, baseS));
92
+ // Light vs dark theme: adjust lightness for contrast
93
+ const isDark = baseL < 0.5;
94
+ const lCenter = isDark ? 0.6 : 0.43;
95
+ const lRange = 0.05;
96
+ const colors = [];
97
+ for (let i = 0; i < count; i++) {
98
+ // Golden-angle hue rotation for maximum perceptual spread
99
+ const hue = baseH + (i * 0.618033988749895);
100
+ // Slight lightness oscillation for differentiation
101
+ const lOff = ((i % 3) - 1) * lRange;
102
+ // Slight saturation variation
103
+ const sOff = ((i % 2) === 0 ? 0.04 : -0.04);
104
+ const s = Math.max(0.35, Math.min(0.85, sat + sOff));
105
+ const l = Math.max(0.3, Math.min(0.7, lCenter + lOff));
106
+ colors.push(hslToHex(hue, s, l));
107
+ }
108
+ return colors;
109
+ }
@@ -19,6 +19,10 @@ export interface TimelineEvent {
19
19
  recurrence?: string;
20
20
  /** Whether this event can be moved / resized by the user */
21
21
  editable?: boolean;
22
+ /** Subtitle displayed below the title (e.g. instructor name, level) */
23
+ subtitle?: string;
24
+ /** Tags displayed as small pills (e.g. ["Beginner", "Yoga"]) */
25
+ tags?: string[];
22
26
  /** Arbitrary payload from the source app (bookings, attendees, etc.) */
23
27
  data?: Record<string, unknown>;
24
28
  }
package/dist/index.d.ts CHANGED
@@ -1,13 +1,13 @@
1
- export { DayGrid, DayTimeline, WeekGrid, WeekHeatmap, Agenda, Settings, } from './views/index.js';
1
+ export { DayGrid, DayTimeline, WeekGrid, WeekHeatmap, Agenda, Settings, WeekSchedule, } from './views/index.js';
2
2
  export type { SettingsField } from './views/index.js';
3
3
  export { NowIndicator, EventBlock, TimeGutter, DayHeader, EmptySlot, } from './primitives/index.js';
4
4
  export { Calendar, Toolbar } from './calendar/index.js';
5
5
  export type { CalendarView } from './calendar/index.js';
6
6
  export { createEventStore, createViewState, createSelection, createDragState, } from './engine/index.js';
7
7
  export type { EventStore, ViewState, ViewStateOptions, CalendarViewId, BuiltInViewId, ViewGranularity, ViewDateRange, Selection, DragState, DragMode, DragPayload, } from './engine/index.js';
8
- export { createMemoryAdapter, createRestAdapter } from './adapters/index.js';
9
- export type { CalendarAdapter, DateRange, RestAdapterOptions } from './adapters/index.js';
10
- export { createClock, DAY_MS, HOUR_MS, HOURS, sod, startOfWeek, addDaysMs, diffDays, pad, fractionalHour, fmtHM, fmtS, dayNum, dayOfWeek, fmtH, weekdayShort, weekdayLong, monthShort, monthLong, dateShort, dateWithWeekday, fmtDay, fmtWeekRange, setDefaultLocale, getDefaultLocale, is24HourLocale, timeToX, toZonedTime, fromZonedTime, nowInZone, formatInTimeZone, } from './core/index.js';
8
+ export { createMemoryAdapter, createRestAdapter, createRecurringAdapter } from './adapters/index.js';
9
+ export type { CalendarAdapter, DateRange, RestAdapterOptions, RecurringEvent, RecurringAdapterOptions, MemoryAdapterOptions, } from './adapters/index.js';
10
+ export { createClock, DAY_MS, HOUR_MS, HOURS, sod, startOfWeek, addDaysMs, diffDays, pad, fractionalHour, fmtHM, fmtS, dayNum, dayOfWeek, fmtH, weekdayShort, weekdayLong, monthShort, monthLong, dateShort, dateWithWeekday, fmtDay, fmtWeekRange, setDefaultLocale, getDefaultLocale, is24HourLocale, timeToX, toZonedTime, fromZonedTime, nowInZone, formatInTimeZone, generatePalette, VIVID_PALETTE, } from './core/index.js';
11
11
  export type { Clock, TimelineEvent, WeekTimelineProps, DayTimelineProps, } from './core/index.js';
12
- export { midnight, parchment, indigo, neutral, bare, presets, stageBg } from './theme/index.js';
12
+ export { midnight, parchment, indigo, neutral, bare, presets } from './theme/index.js';
13
13
  export type { PresetName } from './theme/index.js';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // ─── Views ──────────────────────────────────────────────
2
- export { DayGrid, DayTimeline, WeekGrid, WeekHeatmap, Agenda, Settings, } from './views/index.js';
2
+ export { DayGrid, DayTimeline, WeekGrid, WeekHeatmap, Agenda, Settings, WeekSchedule, } from './views/index.js';
3
3
  // ─── Primitives ─────────────────────────────────────────
4
4
  export { NowIndicator, EventBlock, TimeGutter, DayHeader, EmptySlot, } from './primitives/index.js';
5
5
  // ─── Calendar shell ─────────────────────────────────────
@@ -7,8 +7,8 @@ export { Calendar, Toolbar } from './calendar/index.js';
7
7
  // ─── Engine (reactive state) ────────────────────────────
8
8
  export { createEventStore, createViewState, createSelection, createDragState, } from './engine/index.js';
9
9
  // ─── Adapters ───────────────────────────────────────────
10
- export { createMemoryAdapter, createRestAdapter } from './adapters/index.js';
10
+ export { createMemoryAdapter, createRestAdapter, createRecurringAdapter } from './adapters/index.js';
11
11
  // ─── Core: clock, time, locale, types ───────────────────
12
- export { createClock, DAY_MS, HOUR_MS, HOURS, sod, startOfWeek, addDaysMs, diffDays, pad, fractionalHour, fmtHM, fmtS, dayNum, dayOfWeek, fmtH, weekdayShort, weekdayLong, monthShort, monthLong, dateShort, dateWithWeekday, fmtDay, fmtWeekRange, setDefaultLocale, getDefaultLocale, is24HourLocale, timeToX, toZonedTime, fromZonedTime, nowInZone, formatInTimeZone, } from './core/index.js';
12
+ export { createClock, DAY_MS, HOUR_MS, HOURS, sod, startOfWeek, addDaysMs, diffDays, pad, fractionalHour, fmtHM, fmtS, dayNum, dayOfWeek, fmtH, weekdayShort, weekdayLong, monthShort, monthLong, dateShort, dateWithWeekday, fmtDay, fmtWeekRange, setDefaultLocale, getDefaultLocale, is24HourLocale, timeToX, toZonedTime, fromZonedTime, nowInZone, formatInTimeZone, generatePalette, VIVID_PALETTE, } from './core/index.js';
13
13
  // ─── Themes ─────────────────────────────────────────────
14
- export { midnight, parchment, indigo, neutral, bare, presets, stageBg } from './theme/index.js';
14
+ export { midnight, parchment, indigo, neutral, bare, presets } from './theme/index.js';
@@ -89,12 +89,22 @@
89
89
  <div class="eb-stripe"></div>
90
90
  <div class="eb-body">
91
91
  <span class="eb-title">{event.title}</span>
92
+ {#if event.subtitle}
93
+ <span class="eb-subtitle">{event.subtitle}</span>
94
+ {/if}
92
95
  {#if showTime}
93
96
  <span class="eb-time">{fmtTime(event.start)} – {fmtTime(event.end)}</span>
94
97
  {/if}
95
98
  {#if showDuration}
96
99
  <span class="eb-dur">{fmtDuration(event.start, event.end)}</span>
97
100
  {/if}
101
+ {#if event.tags && event.tags.length > 0}
102
+ <div class="eb-tags">
103
+ {#each event.tags as tag}
104
+ <span class="eb-tag">{tag}</span>
105
+ {/each}
106
+ </div>
107
+ {/if}
98
108
  {#if active}<span class="eb-live-badge">now</span>{/if}
99
109
  </div>
100
110
  {:else}
@@ -102,9 +112,19 @@
102
112
  <span class="eb-stripe"></span>
103
113
  <span class="eb-time">{fmtTime(event.start)} – {fmtTime(event.end)}</span>
104
114
  <span class="eb-title">{event.title}</span>
115
+ {#if event.subtitle}
116
+ <span class="eb-subtitle">{event.subtitle}</span>
117
+ {/if}
105
118
  {#if showDuration}
106
119
  <span class="eb-dur">{fmtDuration(event.start, event.end)}</span>
107
120
  {/if}
121
+ {#if event.tags && event.tags.length > 0}
122
+ <span class="eb-tags">
123
+ {#each event.tags as tag}
124
+ <span class="eb-tag">{tag}</span>
125
+ {/each}
126
+ </span>
127
+ {/if}
108
128
  {#if active}<span class="eb-live-badge">now</span>{/if}
109
129
  {/if}
110
130
  {/snippet}
@@ -262,6 +282,28 @@
262
282
  }
263
283
 
264
284
  /* ── Shared ── */
285
+ .eb-subtitle {
286
+ font: 400 10px / 1.2 var(--dt-sans, 'Outfit', system-ui, sans-serif);
287
+ color: var(--dt-text-2, rgba(148, 163, 184, 0.65));
288
+ overflow: hidden;
289
+ text-overflow: ellipsis;
290
+ white-space: nowrap;
291
+ }
292
+ .eb-tags {
293
+ display: inline-flex;
294
+ flex-wrap: wrap;
295
+ gap: 3px;
296
+ }
297
+ .eb-tag {
298
+ display: inline-block;
299
+ font: 500 8px / 1 var(--dt-sans, 'Outfit', system-ui, sans-serif);
300
+ letter-spacing: 0.04em;
301
+ text-transform: uppercase;
302
+ padding: 2px 5px;
303
+ border-radius: 3px;
304
+ background: color-mix(in srgb, var(--_color) 18%, transparent);
305
+ color: var(--_color);
306
+ }
265
307
  .eb-live-badge {
266
308
  display: inline-flex;
267
309
  align-items: center;
@@ -1,2 +1,2 @@
1
- export { midnight, parchment, indigo, neutral, bare, presets, stageBg, } from './presets.js';
1
+ export { midnight, parchment, indigo, neutral, bare, presets, } from './presets.js';
2
2
  export type { PresetName } from './presets.js';
@@ -1,2 +1,2 @@
1
1
  // ─── Theme barrel export ────────────────────────────────
2
- export { midnight, parchment, indigo, neutral, bare, presets, stageBg, } from './presets.js';
2
+ export { midnight, parchment, indigo, neutral, bare, presets, } from './presets.js';
@@ -5,33 +5,28 @@
5
5
  * Pass to the `style` prop of any timeline component.
6
6
  */
7
7
  /** Midnight Industrial — dark charcoal + red accent, tech monitoring */
8
- export declare const midnight = "\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.02);\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-serif: Georgia, 'Times New Roman', serif;\n\t--dt-hm-empty: rgba(80, 80, 120, 0.06);\n\t--dt-hm-low: rgba(239, 68, 68, 0.15);\n\t--dt-hm-mid: rgba(239, 68, 68, 0.3);\n\t--dt-hm-high: rgba(239, 68, 68, 0.5);\n\t--dt-hm-max: rgba(239, 68, 68, 0.72);\n";
8
+ 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.02);\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-serif: Georgia, 'Times New Roman', serif;\n\t--dt-hm-empty: rgba(80, 80, 120, 0.06);\n\t--dt-hm-low: rgba(239, 68, 68, 0.15);\n\t--dt-hm-mid: rgba(239, 68, 68, 0.3);\n\t--dt-hm-high: rgba(239, 68, 68, 0.5);\n\t--dt-hm-max: rgba(239, 68, 68, 0.72);\n";
9
9
  /** Desert Parchment — warm analog planner, burnt sienna on aged paper */
10
- export declare const parchment = "\n\t--dt-bg: #f0e9dd;\n\t--dt-surface: #e8dfd0;\n\t--dt-border: rgba(139, 110, 70, 0.12);\n\t--dt-border-day: rgba(139, 110, 70, 0.22);\n\t--dt-text: rgba(55, 40, 22, 0.88);\n\t--dt-text-2: rgba(110, 85, 52, 0.62);\n\t--dt-text-3: rgba(139, 110, 70, 0.42);\n\t--dt-accent: #b85c2f;\n\t--dt-accent-dim: rgba(184, 92, 47, 0.14);\n\t--dt-glow: rgba(184, 92, 47, 0.25);\n\t--dt-today-bg: rgba(184, 92, 47, 0.04);\n\t--dt-btn-text: #fdf6ee;\n\t--dt-scrollbar: rgba(139, 110, 70, 0.15);\n\t--dt-success: rgba(76, 153, 76, 0.7);\n\t--dt-serif: Georgia, 'Times New Roman', serif;\n\t--dt-mono: 'Courier New', 'Courier', monospace;\n\t--dt-sans: 'Outfit', Georgia, serif;\n\t--dt-hm-empty: rgba(139, 110, 70, 0.06);\n\t--dt-hm-low: rgba(184, 92, 47, 0.15);\n\t--dt-hm-mid: rgba(184, 92, 47, 0.3);\n\t--dt-hm-high: rgba(184, 92, 47, 0.5);\n\t--dt-hm-max: rgba(184, 92, 47, 0.72);\n";
10
+ export declare const parchment = "\n\t--dt-stage-bg: #e4dace;\n\t--dt-bg: #f0e9dd;\n\t--dt-surface: #e8dfd0;\n\t--dt-border: rgba(139, 110, 70, 0.12);\n\t--dt-border-day: rgba(139, 110, 70, 0.22);\n\t--dt-text: rgba(55, 40, 22, 0.88);\n\t--dt-text-2: rgba(110, 85, 52, 0.62);\n\t--dt-text-3: rgba(139, 110, 70, 0.42);\n\t--dt-accent: #b85c2f;\n\t--dt-accent-dim: rgba(184, 92, 47, 0.14);\n\t--dt-glow: rgba(184, 92, 47, 0.25);\n\t--dt-today-bg: rgba(184, 92, 47, 0.04);\n\t--dt-btn-text: #fdf6ee;\n\t--dt-scrollbar: rgba(139, 110, 70, 0.15);\n\t--dt-success: rgba(76, 153, 76, 0.7);\n\t--dt-serif: Georgia, 'Times New Roman', serif;\n\t--dt-mono: 'Courier New', 'Courier', monospace;\n\t--dt-sans: 'Outfit', Georgia, serif;\n\t--dt-hm-empty: rgba(139, 110, 70, 0.06);\n\t--dt-hm-low: rgba(184, 92, 47, 0.15);\n\t--dt-hm-mid: rgba(184, 92, 47, 0.3);\n\t--dt-hm-high: rgba(184, 92, 47, 0.5);\n\t--dt-hm-max: rgba(184, 92, 47, 0.72);\n";
11
11
  /** Soft Indigo — calm productivity, muted lavender with indigo markers */
12
- export declare const indigo = "\n\t--dt-bg: #f7f6fc;\n\t--dt-surface: #eeedf8;\n\t--dt-border: rgba(99, 102, 241, 0.08);\n\t--dt-border-day: rgba(99, 102, 241, 0.14);\n\t--dt-text: rgba(30, 27, 55, 0.82);\n\t--dt-text-2: rgba(75, 70, 120, 0.55);\n\t--dt-text-3: rgba(99, 102, 241, 0.3);\n\t--dt-accent: #6366f1;\n\t--dt-accent-dim: rgba(99, 102, 241, 0.12);\n\t--dt-glow: rgba(99, 102, 241, 0.25);\n\t--dt-today-bg: rgba(99, 102, 241, 0.03);\n\t--dt-btn-text: #fff;\n\t--dt-scrollbar: rgba(99, 102, 241, 0.1);\n\t--dt-success: rgba(34, 197, 94, 0.7);\n\t--dt-serif: Georgia, 'Times New Roman', serif;\n\t--dt-sans: 'Outfit', system-ui, sans-serif;\n\t--dt-hm-empty: rgba(99, 102, 241, 0.04);\n\t--dt-hm-low: rgba(99, 102, 241, 0.12);\n\t--dt-hm-mid: rgba(99, 102, 241, 0.28);\n\t--dt-hm-high: rgba(99, 102, 241, 0.48);\n\t--dt-hm-max: rgba(99, 102, 241, 0.7);\n";
12
+ export declare const indigo = "\n\t--dt-stage-bg: #efedf8;\n\t--dt-bg: #f7f6fc;\n\t--dt-surface: #eeedf8;\n\t--dt-border: rgba(99, 102, 241, 0.08);\n\t--dt-border-day: rgba(99, 102, 241, 0.14);\n\t--dt-text: rgba(30, 27, 55, 0.82);\n\t--dt-text-2: rgba(75, 70, 120, 0.55);\n\t--dt-text-3: rgba(99, 102, 241, 0.3);\n\t--dt-accent: #6366f1;\n\t--dt-accent-dim: rgba(99, 102, 241, 0.12);\n\t--dt-glow: rgba(99, 102, 241, 0.25);\n\t--dt-today-bg: rgba(99, 102, 241, 0.03);\n\t--dt-btn-text: #fff;\n\t--dt-scrollbar: rgba(99, 102, 241, 0.1);\n\t--dt-success: rgba(34, 197, 94, 0.7);\n\t--dt-serif: Georgia, 'Times New Roman', serif;\n\t--dt-sans: 'Outfit', system-ui, sans-serif;\n\t--dt-hm-empty: rgba(99, 102, 241, 0.04);\n\t--dt-hm-low: rgba(99, 102, 241, 0.12);\n\t--dt-hm-mid: rgba(99, 102, 241, 0.28);\n\t--dt-hm-high: rgba(99, 102, 241, 0.48);\n\t--dt-hm-max: rgba(99, 102, 241, 0.7);\n";
13
13
  /**
14
14
  * Neutral — inherits fonts from host page, uses standard grays + safe blue accent.
15
15
  * Drop-in preset that blends into any website without fighting its design.
16
16
  */
17
- export declare const neutral = "\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: #2563eb;\n\t--dt-accent-dim: rgba(37, 99, 235, 0.12);\n\t--dt-glow: rgba(37, 99, 235, 0.25);\n\t--dt-today-bg: rgba(37, 99, 235, 0.04);\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-serif: inherit;\n\t--dt-sans: inherit;\n\t--dt-mono: ui-monospace, 'SFMono-Regular', monospace;\n\t--dt-hm-empty: rgba(0, 0, 0, 0.03);\n\t--dt-hm-low: rgba(37, 99, 235, 0.12);\n\t--dt-hm-mid: rgba(37, 99, 235, 0.28);\n\t--dt-hm-high: rgba(37, 99, 235, 0.48);\n\t--dt-hm-max: rgba(37, 99, 235, 0.7);\n";
17
+ 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: #2563eb;\n\t--dt-accent-dim: rgba(37, 99, 235, 0.12);\n\t--dt-glow: rgba(37, 99, 235, 0.25);\n\t--dt-today-bg: rgba(37, 99, 235, 0.04);\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-serif: inherit;\n\t--dt-sans: inherit;\n\t--dt-mono: ui-monospace, 'SFMono-Regular', monospace;\n\t--dt-hm-empty: rgba(0, 0, 0, 0.03);\n\t--dt-hm-low: rgba(37, 99, 235, 0.12);\n\t--dt-hm-mid: rgba(37, 99, 235, 0.28);\n\t--dt-hm-high: rgba(37, 99, 235, 0.48);\n\t--dt-hm-max: rgba(37, 99, 235, 0.7);\n";
18
18
  /**
19
19
  * Bare — transparent skeleton that inherits everything from the host page.
20
20
  * All colors use currentColor/transparent/inherit so the calendar fully absorbs
21
21
  * the parent site's design. Override individual --dt-* tokens as needed.
22
22
  */
23
- export declare const bare = "\n\t--dt-bg: transparent;\n\t--dt-surface: transparent;\n\t--dt-border: currentColor;\n\t--dt-border-day: currentColor;\n\t--dt-text: inherit;\n\t--dt-text-2: inherit;\n\t--dt-text-3: inherit;\n\t--dt-accent: currentColor;\n\t--dt-accent-dim: transparent;\n\t--dt-glow: transparent;\n\t--dt-today-bg: transparent;\n\t--dt-btn-text: inherit;\n\t--dt-scrollbar: currentColor;\n\t--dt-success: currentColor;\n\t--dt-serif: inherit;\n\t--dt-sans: inherit;\n\t--dt-mono: inherit;\n\t--dt-hm-empty: transparent;\n\t--dt-hm-low: currentColor;\n\t--dt-hm-mid: currentColor;\n\t--dt-hm-high: currentColor;\n\t--dt-hm-max: currentColor;\n";
23
+ export declare const bare = "\n\t--dt-stage-bg: transparent;\n\t--dt-bg: transparent;\n\t--dt-surface: transparent;\n\t--dt-border: currentColor;\n\t--dt-border-day: currentColor;\n\t--dt-text: inherit;\n\t--dt-text-2: inherit;\n\t--dt-text-3: inherit;\n\t--dt-accent: currentColor;\n\t--dt-accent-dim: transparent;\n\t--dt-glow: transparent;\n\t--dt-today-bg: transparent;\n\t--dt-btn-text: inherit;\n\t--dt-scrollbar: currentColor;\n\t--dt-success: currentColor;\n\t--dt-serif: inherit;\n\t--dt-sans: inherit;\n\t--dt-mono: inherit;\n\t--dt-hm-empty: transparent;\n\t--dt-hm-low: currentColor;\n\t--dt-hm-mid: currentColor;\n\t--dt-hm-high: currentColor;\n\t--dt-hm-max: currentColor;\n";
24
24
  /** All available presets keyed by name */
25
25
  export declare const presets: {
26
- readonly midnight: "\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.02);\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-serif: Georgia, 'Times New Roman', serif;\n\t--dt-hm-empty: rgba(80, 80, 120, 0.06);\n\t--dt-hm-low: rgba(239, 68, 68, 0.15);\n\t--dt-hm-mid: rgba(239, 68, 68, 0.3);\n\t--dt-hm-high: rgba(239, 68, 68, 0.5);\n\t--dt-hm-max: rgba(239, 68, 68, 0.72);\n";
27
- readonly parchment: "\n\t--dt-bg: #f0e9dd;\n\t--dt-surface: #e8dfd0;\n\t--dt-border: rgba(139, 110, 70, 0.12);\n\t--dt-border-day: rgba(139, 110, 70, 0.22);\n\t--dt-text: rgba(55, 40, 22, 0.88);\n\t--dt-text-2: rgba(110, 85, 52, 0.62);\n\t--dt-text-3: rgba(139, 110, 70, 0.42);\n\t--dt-accent: #b85c2f;\n\t--dt-accent-dim: rgba(184, 92, 47, 0.14);\n\t--dt-glow: rgba(184, 92, 47, 0.25);\n\t--dt-today-bg: rgba(184, 92, 47, 0.04);\n\t--dt-btn-text: #fdf6ee;\n\t--dt-scrollbar: rgba(139, 110, 70, 0.15);\n\t--dt-success: rgba(76, 153, 76, 0.7);\n\t--dt-serif: Georgia, 'Times New Roman', serif;\n\t--dt-mono: 'Courier New', 'Courier', monospace;\n\t--dt-sans: 'Outfit', Georgia, serif;\n\t--dt-hm-empty: rgba(139, 110, 70, 0.06);\n\t--dt-hm-low: rgba(184, 92, 47, 0.15);\n\t--dt-hm-mid: rgba(184, 92, 47, 0.3);\n\t--dt-hm-high: rgba(184, 92, 47, 0.5);\n\t--dt-hm-max: rgba(184, 92, 47, 0.72);\n";
28
- readonly indigo: "\n\t--dt-bg: #f7f6fc;\n\t--dt-surface: #eeedf8;\n\t--dt-border: rgba(99, 102, 241, 0.08);\n\t--dt-border-day: rgba(99, 102, 241, 0.14);\n\t--dt-text: rgba(30, 27, 55, 0.82);\n\t--dt-text-2: rgba(75, 70, 120, 0.55);\n\t--dt-text-3: rgba(99, 102, 241, 0.3);\n\t--dt-accent: #6366f1;\n\t--dt-accent-dim: rgba(99, 102, 241, 0.12);\n\t--dt-glow: rgba(99, 102, 241, 0.25);\n\t--dt-today-bg: rgba(99, 102, 241, 0.03);\n\t--dt-btn-text: #fff;\n\t--dt-scrollbar: rgba(99, 102, 241, 0.1);\n\t--dt-success: rgba(34, 197, 94, 0.7);\n\t--dt-serif: Georgia, 'Times New Roman', serif;\n\t--dt-sans: 'Outfit', system-ui, sans-serif;\n\t--dt-hm-empty: rgba(99, 102, 241, 0.04);\n\t--dt-hm-low: rgba(99, 102, 241, 0.12);\n\t--dt-hm-mid: rgba(99, 102, 241, 0.28);\n\t--dt-hm-high: rgba(99, 102, 241, 0.48);\n\t--dt-hm-max: rgba(99, 102, 241, 0.7);\n";
29
- readonly neutral: "\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: #2563eb;\n\t--dt-accent-dim: rgba(37, 99, 235, 0.12);\n\t--dt-glow: rgba(37, 99, 235, 0.25);\n\t--dt-today-bg: rgba(37, 99, 235, 0.04);\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-serif: inherit;\n\t--dt-sans: inherit;\n\t--dt-mono: ui-monospace, 'SFMono-Regular', monospace;\n\t--dt-hm-empty: rgba(0, 0, 0, 0.03);\n\t--dt-hm-low: rgba(37, 99, 235, 0.12);\n\t--dt-hm-mid: rgba(37, 99, 235, 0.28);\n\t--dt-hm-high: rgba(37, 99, 235, 0.48);\n\t--dt-hm-max: rgba(37, 99, 235, 0.7);\n";
30
- readonly bare: "\n\t--dt-bg: transparent;\n\t--dt-surface: transparent;\n\t--dt-border: currentColor;\n\t--dt-border-day: currentColor;\n\t--dt-text: inherit;\n\t--dt-text-2: inherit;\n\t--dt-text-3: inherit;\n\t--dt-accent: currentColor;\n\t--dt-accent-dim: transparent;\n\t--dt-glow: transparent;\n\t--dt-today-bg: transparent;\n\t--dt-btn-text: inherit;\n\t--dt-scrollbar: currentColor;\n\t--dt-success: currentColor;\n\t--dt-serif: inherit;\n\t--dt-sans: inherit;\n\t--dt-mono: inherit;\n\t--dt-hm-empty: transparent;\n\t--dt-hm-low: currentColor;\n\t--dt-hm-mid: currentColor;\n\t--dt-hm-high: currentColor;\n\t--dt-hm-max: currentColor;\n";
26
+ 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.02);\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-serif: Georgia, 'Times New Roman', serif;\n\t--dt-hm-empty: rgba(80, 80, 120, 0.06);\n\t--dt-hm-low: rgba(239, 68, 68, 0.15);\n\t--dt-hm-mid: rgba(239, 68, 68, 0.3);\n\t--dt-hm-high: rgba(239, 68, 68, 0.5);\n\t--dt-hm-max: rgba(239, 68, 68, 0.72);\n";
27
+ readonly parchment: "\n\t--dt-stage-bg: #e4dace;\n\t--dt-bg: #f0e9dd;\n\t--dt-surface: #e8dfd0;\n\t--dt-border: rgba(139, 110, 70, 0.12);\n\t--dt-border-day: rgba(139, 110, 70, 0.22);\n\t--dt-text: rgba(55, 40, 22, 0.88);\n\t--dt-text-2: rgba(110, 85, 52, 0.62);\n\t--dt-text-3: rgba(139, 110, 70, 0.42);\n\t--dt-accent: #b85c2f;\n\t--dt-accent-dim: rgba(184, 92, 47, 0.14);\n\t--dt-glow: rgba(184, 92, 47, 0.25);\n\t--dt-today-bg: rgba(184, 92, 47, 0.04);\n\t--dt-btn-text: #fdf6ee;\n\t--dt-scrollbar: rgba(139, 110, 70, 0.15);\n\t--dt-success: rgba(76, 153, 76, 0.7);\n\t--dt-serif: Georgia, 'Times New Roman', serif;\n\t--dt-mono: 'Courier New', 'Courier', monospace;\n\t--dt-sans: 'Outfit', Georgia, serif;\n\t--dt-hm-empty: rgba(139, 110, 70, 0.06);\n\t--dt-hm-low: rgba(184, 92, 47, 0.15);\n\t--dt-hm-mid: rgba(184, 92, 47, 0.3);\n\t--dt-hm-high: rgba(184, 92, 47, 0.5);\n\t--dt-hm-max: rgba(184, 92, 47, 0.72);\n";
28
+ readonly indigo: "\n\t--dt-stage-bg: #efedf8;\n\t--dt-bg: #f7f6fc;\n\t--dt-surface: #eeedf8;\n\t--dt-border: rgba(99, 102, 241, 0.08);\n\t--dt-border-day: rgba(99, 102, 241, 0.14);\n\t--dt-text: rgba(30, 27, 55, 0.82);\n\t--dt-text-2: rgba(75, 70, 120, 0.55);\n\t--dt-text-3: rgba(99, 102, 241, 0.3);\n\t--dt-accent: #6366f1;\n\t--dt-accent-dim: rgba(99, 102, 241, 0.12);\n\t--dt-glow: rgba(99, 102, 241, 0.25);\n\t--dt-today-bg: rgba(99, 102, 241, 0.03);\n\t--dt-btn-text: #fff;\n\t--dt-scrollbar: rgba(99, 102, 241, 0.1);\n\t--dt-success: rgba(34, 197, 94, 0.7);\n\t--dt-serif: Georgia, 'Times New Roman', serif;\n\t--dt-sans: 'Outfit', system-ui, sans-serif;\n\t--dt-hm-empty: rgba(99, 102, 241, 0.04);\n\t--dt-hm-low: rgba(99, 102, 241, 0.12);\n\t--dt-hm-mid: rgba(99, 102, 241, 0.28);\n\t--dt-hm-high: rgba(99, 102, 241, 0.48);\n\t--dt-hm-max: rgba(99, 102, 241, 0.7);\n";
29
+ 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: #2563eb;\n\t--dt-accent-dim: rgba(37, 99, 235, 0.12);\n\t--dt-glow: rgba(37, 99, 235, 0.25);\n\t--dt-today-bg: rgba(37, 99, 235, 0.04);\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-serif: inherit;\n\t--dt-sans: inherit;\n\t--dt-mono: ui-monospace, 'SFMono-Regular', monospace;\n\t--dt-hm-empty: rgba(0, 0, 0, 0.03);\n\t--dt-hm-low: rgba(37, 99, 235, 0.12);\n\t--dt-hm-mid: rgba(37, 99, 235, 0.28);\n\t--dt-hm-high: rgba(37, 99, 235, 0.48);\n\t--dt-hm-max: rgba(37, 99, 235, 0.7);\n";
30
+ readonly bare: "\n\t--dt-stage-bg: transparent;\n\t--dt-bg: transparent;\n\t--dt-surface: transparent;\n\t--dt-border: currentColor;\n\t--dt-border-day: currentColor;\n\t--dt-text: inherit;\n\t--dt-text-2: inherit;\n\t--dt-text-3: inherit;\n\t--dt-accent: currentColor;\n\t--dt-accent-dim: transparent;\n\t--dt-glow: transparent;\n\t--dt-today-bg: transparent;\n\t--dt-btn-text: inherit;\n\t--dt-scrollbar: currentColor;\n\t--dt-success: currentColor;\n\t--dt-serif: inherit;\n\t--dt-sans: inherit;\n\t--dt-mono: inherit;\n\t--dt-hm-empty: transparent;\n\t--dt-hm-low: currentColor;\n\t--dt-hm-mid: currentColor;\n\t--dt-hm-high: currentColor;\n\t--dt-hm-max: currentColor;\n";
31
31
  };
32
32
  export type PresetName = keyof typeof presets;
33
- /**
34
- * Stage background color matching each theme.
35
- * Useful for the container behind the timeline component.
36
- */
37
- export declare const stageBg: Record<PresetName, string>;
@@ -6,6 +6,7 @@
6
6
  */
7
7
  /** Midnight Industrial — dark charcoal + red accent, tech monitoring */
8
8
  export const midnight = `
9
+ --dt-stage-bg: #080a0f;
9
10
  --dt-bg: #0b0e14;
10
11
  --dt-surface: #10141c;
11
12
  --dt-border: rgba(148, 163, 184, 0.07);
@@ -29,6 +30,7 @@ export const midnight = `
29
30
  `;
30
31
  /** Desert Parchment — warm analog planner, burnt sienna on aged paper */
31
32
  export const parchment = `
33
+ --dt-stage-bg: #e4dace;
32
34
  --dt-bg: #f0e9dd;
33
35
  --dt-surface: #e8dfd0;
34
36
  --dt-border: rgba(139, 110, 70, 0.12);
@@ -54,6 +56,7 @@ export const parchment = `
54
56
  `;
55
57
  /** Soft Indigo — calm productivity, muted lavender with indigo markers */
56
58
  export const indigo = `
59
+ --dt-stage-bg: #efedf8;
57
60
  --dt-bg: #f7f6fc;
58
61
  --dt-surface: #eeedf8;
59
62
  --dt-border: rgba(99, 102, 241, 0.08);
@@ -81,6 +84,7 @@ export const indigo = `
81
84
  * Drop-in preset that blends into any website without fighting its design.
82
85
  */
83
86
  export const neutral = `
87
+ --dt-stage-bg: #ffffff;
84
88
  --dt-bg: #ffffff;
85
89
  --dt-surface: #f9fafb;
86
90
  --dt-border: rgba(0, 0, 0, 0.08);
@@ -110,6 +114,7 @@ export const neutral = `
110
114
  * the parent site's design. Override individual --dt-* tokens as needed.
111
115
  */
112
116
  export const bare = `
117
+ --dt-stage-bg: transparent;
113
118
  --dt-bg: transparent;
114
119
  --dt-surface: transparent;
115
120
  --dt-border: currentColor;
@@ -135,14 +140,3 @@ export const bare = `
135
140
  `;
136
141
  /** All available presets keyed by name */
137
142
  export const presets = { midnight, parchment, indigo, neutral, bare };
138
- /**
139
- * Stage background color matching each theme.
140
- * Useful for the container behind the timeline component.
141
- */
142
- export const stageBg = {
143
- midnight: '#080a0f',
144
- parchment: '#e4dace',
145
- indigo: '#efedf8',
146
- neutral: '#ffffff',
147
- bare: 'transparent',
148
- };
@@ -287,6 +287,9 @@
287
287
  <div class="ag-card-stripe"></div>
288
288
  <div class="ag-card-body">
289
289
  <span class="ag-card-title">{ev.title}</span>
290
+ {#if ev.subtitle}
291
+ <span class="ag-card-sub">{ev.subtitle}</span>
292
+ {/if}
290
293
  <span class="ag-card-meta">
291
294
  {#if isNow}
292
295
  until {fmtTime(ev.end)}
@@ -295,6 +298,13 @@
295
298
  {/if}
296
299
  <span class="ag-card-dur">{duration(ev)}</span>
297
300
  </span>
301
+ {#if ev.tags?.length}
302
+ <div class="ag-card-tags">
303
+ {#each ev.tags as tag}
304
+ <span class="ag-card-tag">{tag}</span>
305
+ {/each}
306
+ </div>
307
+ {/if}
298
308
  {#if isNow}
299
309
  <div class="ag-card-progress">
300
310
  <div class="ag-card-progress-fill" style:width="{progress(ev) * 100}%"></div>
@@ -411,10 +421,20 @@
411
421
  <span class="ag-q-card-title">{ev.title}</span>
412
422
  <span class="ag-q-card-eta">{timeUntilEv(ev)}</span>
413
423
  </div>
424
+ {#if ev.subtitle}
425
+ <span class="ag-q-card-sub">{ev.subtitle}</span>
426
+ {/if}
414
427
  <div class="ag-q-card-meta">
415
428
  {fmtTime(ev.start)} – {fmtTime(ev.end)}
416
429
  <span class="ag-q-card-dur">{duration(ev)}</span>
417
430
  </div>
431
+ {#if ev.tags?.length}
432
+ <div class="ag-q-card-tags">
433
+ {#each ev.tags as tag}
434
+ <span class="ag-q-card-tag">{tag}</span>
435
+ {/each}
436
+ </div>
437
+ {/if}
418
438
  </div>
419
439
  </div>
420
440
  {/each}
@@ -494,10 +514,20 @@
494
514
  <span class="ag-plan-order">{i + 1}</span>
495
515
  <span class="ag-plan-title">{ev.title}</span>
496
516
  </div>
517
+ {#if ev.subtitle}
518
+ <span class="ag-plan-sub">{ev.subtitle}</span>
519
+ {/if}
497
520
  <div class="ag-plan-meta">
498
521
  {fmtTime(ev.start)} – {fmtTime(ev.end)}
499
522
  <span class="ag-plan-dur">{duration(ev)}</span>
500
523
  </div>
524
+ {#if ev.tags?.length}
525
+ <div class="ag-plan-tags">
526
+ {#each ev.tags as tag}
527
+ <span class="ag-plan-tag">{tag}</span>
528
+ {/each}
529
+ </div>
530
+ {/if}
501
531
  </div>
502
532
  </div>
503
533
  {/each}
@@ -584,6 +614,14 @@
584
614
  <span class="ag-compact-dot"></span>
585
615
  <span class="ag-compact-time">{fmtTime(ev.start)}</span>
586
616
  <span class="ag-compact-title">{ev.title}</span>
617
+ {#if ev.subtitle}
618
+ <span class="ag-compact-sub">{ev.subtitle}</span>
619
+ {/if}
620
+ {#if ev.tags?.length}
621
+ {#each ev.tags as tag}
622
+ <span class="ag-compact-tag">{tag}</span>
623
+ {/each}
624
+ {/if}
587
625
  <span class="ag-compact-dur">{duration(ev)}</span>
588
626
  </div>
589
627
  {/each}
@@ -740,6 +778,24 @@
740
778
  margin-left: 6px;
741
779
  color: var(--dt-text-3, rgba(255, 255, 255, 0.3));
742
780
  }
781
+ .ag-card-sub {
782
+ font-size: 11px;
783
+ color: var(--dt-text-2, rgba(255, 255, 255, 0.45));
784
+ line-height: 1;
785
+ }
786
+ .ag-card-tags {
787
+ display: flex;
788
+ gap: 4px;
789
+ flex-wrap: wrap;
790
+ }
791
+ .ag-card-tag {
792
+ font: 500 9px / 1 var(--dt-sans, system-ui, sans-serif);
793
+ color: var(--ev-color, var(--dt-accent));
794
+ background: color-mix(in srgb, var(--ev-color, var(--dt-accent)) 15%, transparent);
795
+ padding: 2px 5px;
796
+ border-radius: 3px;
797
+ white-space: nowrap;
798
+ }
743
799
  .ag-card-progress {
744
800
  height: 3px;
745
801
  background: var(--dt-border, rgba(255, 255, 255, 0.06));
@@ -998,6 +1054,25 @@
998
1054
  margin-left: 6px;
999
1055
  color: var(--dt-text-3, rgba(255, 255, 255, 0.3));
1000
1056
  }
1057
+ .ag-q-card-sub {
1058
+ font-size: 11px;
1059
+ color: var(--dt-text-2, rgba(255, 255, 255, 0.45));
1060
+ line-height: 1;
1061
+ }
1062
+ .ag-q-card-tags {
1063
+ display: flex;
1064
+ gap: 4px;
1065
+ flex-wrap: wrap;
1066
+ margin-top: 2px;
1067
+ }
1068
+ .ag-q-card-tag {
1069
+ font: 500 9px / 1 var(--dt-sans, system-ui, sans-serif);
1070
+ color: var(--ev-color, var(--dt-accent));
1071
+ background: color-mix(in srgb, var(--ev-color, var(--dt-accent)) 15%, transparent);
1072
+ padding: 2px 5px;
1073
+ border-radius: 3px;
1074
+ white-space: nowrap;
1075
+ }
1001
1076
 
1002
1077
  /* ── PAST: minimal right gutter ── */
1003
1078
  .ag-q-done {
@@ -1214,6 +1289,27 @@
1214
1289
  margin-left: 6px;
1215
1290
  color: var(--dt-text-3, rgba(255, 255, 255, 0.3));
1216
1291
  }
1292
+ .ag-plan-sub {
1293
+ font-size: 11px;
1294
+ color: var(--dt-text-2, rgba(255, 255, 255, 0.45));
1295
+ line-height: 1;
1296
+ padding-left: 22px;
1297
+ }
1298
+ .ag-plan-tags {
1299
+ display: flex;
1300
+ gap: 4px;
1301
+ flex-wrap: wrap;
1302
+ padding-left: 22px;
1303
+ margin-top: 2px;
1304
+ }
1305
+ .ag-plan-tag {
1306
+ font: 500 9px / 1 var(--dt-sans, system-ui, sans-serif);
1307
+ color: var(--ev-color, var(--dt-accent));
1308
+ background: color-mix(in srgb, var(--ev-color, var(--dt-accent)) 15%, transparent);
1309
+ padding: 2px 5px;
1310
+ border-radius: 3px;
1311
+ white-space: nowrap;
1312
+ }
1217
1313
 
1218
1314
  /* Header badges for past/future days */
1219
1315
  .ag-badge {
@@ -1396,6 +1492,20 @@
1396
1492
  color: var(--dt-text-3, rgba(255, 255, 255, 0.3));
1397
1493
  flex-shrink: 0;
1398
1494
  }
1495
+ .ag-compact-sub {
1496
+ font-size: 10px;
1497
+ color: var(--dt-text-3, rgba(255, 255, 255, 0.35));
1498
+ flex-shrink: 0;
1499
+ }
1500
+ .ag-compact-tag {
1501
+ font: 500 8px / 1 var(--dt-sans, system-ui, sans-serif);
1502
+ color: var(--ev-color, var(--dt-accent));
1503
+ background: color-mix(in srgb, var(--ev-color, var(--dt-accent)) 12%, transparent);
1504
+ padding: 1px 4px;
1505
+ border-radius: 3px;
1506
+ white-space: nowrap;
1507
+ flex-shrink: 0;
1508
+ }
1399
1509
  .ag-compact-more {
1400
1510
  font-size: 11px;
1401
1511
  color: var(--dt-text-3);
@@ -43,6 +43,11 @@
43
43
  selectedEventId?: string | null;
44
44
  /** Start weeks on Monday */
45
45
  mondayStart?: boolean;
46
+ /** Read-only mode */
47
+ readOnly?: boolean;
48
+ /** Visible hour range [startHour, endHour) — adjusts night collapse */
49
+ visibleHours?: [number, number];
50
+ [key: string]: unknown;
46
51
  }
47
52
 
48
53
  let {
@@ -651,6 +656,16 @@
651
656
  </span>
652
657
  {/if}
653
658
  <span class="fs-ev-title">{p.ev.title}</span>
659
+ {#if p.ev.subtitle && p.heightPx > 48}
660
+ <span class="fs-ev-sub">{p.ev.subtitle}</span>
661
+ {/if}
662
+ {#if p.ev.tags?.length && p.heightPx > 72}
663
+ <span class="fs-ev-tags">
664
+ {#each p.ev.tags as tag}
665
+ <span class="fs-ev-tag">{tag}</span>
666
+ {/each}
667
+ </span>
668
+ {/if}
654
669
  </div>
655
670
  </div>
656
671
  {/each}
@@ -1050,6 +1065,29 @@
1050
1065
  white-space: nowrap;
1051
1066
  }
1052
1067
 
1068
+ .fs-ev-sub {
1069
+ font: 400 11px / 1 var(--dt-sans);
1070
+ color: var(--dt-text-2);
1071
+ opacity: 0.6;
1072
+ white-space: nowrap;
1073
+ overflow: hidden;
1074
+ text-overflow: ellipsis;
1075
+ }
1076
+
1077
+ .fs-ev-tags {
1078
+ display: flex;
1079
+ gap: 4px;
1080
+ }
1081
+
1082
+ .fs-ev-tag {
1083
+ font: 500 8px / 1 var(--dt-sans);
1084
+ color: var(--ev-color, var(--dt-accent));
1085
+ background: color-mix(in srgb, var(--ev-color, var(--dt-accent)) 18%, transparent);
1086
+ padding: 1px 4px;
1087
+ border-radius: 3px;
1088
+ white-space: nowrap;
1089
+ }
1090
+
1053
1091
  /* ─── Focus-visible (accessibility) ──────────── */
1054
1092
  .fs-event:focus-visible,
1055
1093
  .fs-night:focus-visible {
@@ -27,6 +27,11 @@ interface Props {
27
27
  selectedEventId?: string | null;
28
28
  /** Start weeks on Monday */
29
29
  mondayStart?: boolean;
30
+ /** Read-only mode */
31
+ readOnly?: boolean;
32
+ /** Visible hour range [startHour, endHour) — adjusts night collapse */
33
+ visibleHours?: [number, number];
34
+ [key: string]: unknown;
30
35
  }
31
36
  declare const DayGrid: import("svelte").Component<Props, {}, "">;
32
37
  type DayGrid = ReturnType<typeof DayGrid>;
@@ -269,6 +269,14 @@
269
269
  onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); oneventclick?.(p.ev); } }}
270
270
  >
271
271
  <span class="dt-ev-title">{p.ev.title}</span>
272
+ {#if p.ev.subtitle}
273
+ <span class="dt-ev-sub">{p.ev.subtitle}</span>
274
+ {/if}
275
+ {#if p.ev.tags?.length}
276
+ {#each p.ev.tags as tag}
277
+ <span class="dt-ev-tag">{tag}</span>
278
+ {/each}
279
+ {/if}
272
280
  </div>
273
281
  {/each}
274
282
  </div>
@@ -476,6 +484,7 @@
476
484
  padding: 0 8px;
477
485
  display: flex;
478
486
  align-items: center;
487
+ gap: 4px;
479
488
  cursor: pointer;
480
489
  background: color-mix(in srgb, var(--ev-color) 22%, transparent);
481
490
  border-left: 3px solid var(--ev-color);
@@ -502,4 +511,22 @@
502
511
  overflow: hidden;
503
512
  text-overflow: ellipsis;
504
513
  }
514
+
515
+ .dt-ev-sub {
516
+ font: 400 9px / 1 var(--dt-sans, 'Outfit', system-ui, sans-serif);
517
+ color: var(--dt-text-2, rgba(148, 163, 184, 0.6));
518
+ white-space: nowrap;
519
+ overflow: hidden;
520
+ text-overflow: ellipsis;
521
+ }
522
+
523
+ .dt-ev-tag {
524
+ font: 500 7px / 1 var(--dt-sans, 'Outfit', system-ui, sans-serif);
525
+ color: var(--ev-color, var(--dt-accent));
526
+ background: color-mix(in srgb, var(--ev-color, var(--dt-accent)) 20%, transparent);
527
+ padding: 1px 3px;
528
+ border-radius: 2px;
529
+ white-space: nowrap;
530
+ flex-shrink: 0;
531
+ }
505
532
  </style>