@nomideusz/svelte-calendar 0.2.3 → 0.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.
Files changed (38) hide show
  1. package/README.md +207 -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 +7 -1
  5. package/dist/adapters/memory.js +35 -4
  6. package/dist/adapters/recurring.d.ts +39 -0
  7. package/dist/adapters/recurring.js +117 -0
  8. package/dist/calendar/Calendar.svelte +20 -5
  9. package/dist/calendar/Calendar.svelte.d.ts +4 -0
  10. package/dist/core/types.d.ts +4 -0
  11. package/dist/index.d.ts +4 -4
  12. package/dist/index.js +3 -3
  13. package/dist/primitives/EventBlock.svelte +42 -0
  14. package/dist/theme/index.d.ts +1 -1
  15. package/dist/theme/index.js +1 -1
  16. package/dist/theme/presets.d.ts +10 -15
  17. package/dist/theme/presets.js +5 -11
  18. package/dist/views/day/DayGrid.svelte +5 -0
  19. package/dist/views/day/DayGrid.svelte.d.ts +5 -0
  20. package/dist/views/index.d.ts +1 -0
  21. package/dist/views/index.js +1 -0
  22. package/dist/views/schedule/WeekSchedule.svelte +133 -0
  23. package/dist/views/schedule/WeekSchedule.svelte.d.ts +38 -0
  24. package/dist/views/schedule/index.d.ts +1 -0
  25. package/dist/views/schedule/index.js +2 -0
  26. package/dist/views/settings/Settings.svelte +1 -1
  27. package/dist/views/week/WeekGrid.svelte +7 -2
  28. package/dist/views/week/WeekGrid.svelte.d.ts +3 -0
  29. package/dist/views/week/WeekHeatmap.svelte +12 -5
  30. package/dist/views/week/WeekHeatmap.svelte.d.ts +5 -1
  31. package/dist/widget/CalendarWidget.svelte +138 -0
  32. package/dist/widget/CalendarWidget.svelte.d.ts +23 -0
  33. package/dist/widget/index.d.ts +1 -0
  34. package/dist/widget/index.js +1 -0
  35. package/dist/widget/widget.d.ts +7 -0
  36. package/dist/widget/widget.js +9 -0
  37. package/package.json +5 -2
  38. package/widget/widget.js +260 -0
@@ -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
- };
@@ -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 {
@@ -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>;
@@ -3,3 +3,4 @@ export { WeekGrid, WeekHeatmap } from './week/index.js';
3
3
  export { Agenda } from './agenda/index.js';
4
4
  export { Settings } from './settings/index.js';
5
5
  export type { SettingsField } from './settings/index.js';
6
+ export { WeekSchedule } from './schedule/index.js';
@@ -3,3 +3,4 @@ export { DayGrid, DayTimeline } from './day/index.js';
3
3
  export { WeekGrid, WeekHeatmap } from './week/index.js';
4
4
  export { Agenda } from './agenda/index.js';
5
5
  export { Settings } from './settings/index.js';
6
+ export { WeekSchedule } from './schedule/index.js';
@@ -0,0 +1,133 @@
1
+ <!--
2
+ WeekSchedule — zero-config weekly schedule display.
3
+
4
+ A convenience wrapper that pre-wires Calendar + WeekGrid + Agenda
5
+ so consumers can render a read-only weekly schedule with a single import.
6
+
7
+ Usage:
8
+ <WeekSchedule
9
+ events={events}
10
+ theme={neutral}
11
+ locale="pl-PL"
12
+ height={560}
13
+ readOnly
14
+ />
15
+
16
+ Or with a recurring adapter:
17
+ <WeekSchedule
18
+ schedule={weeklyClasses}
19
+ theme={neutral}
20
+ readOnly
21
+ />
22
+ -->
23
+ <script lang="ts">
24
+ import type { TimelineEvent } from '../../core/types.js';
25
+ import type { RecurringEvent } from '../../adapters/recurring.js';
26
+ import type { MemoryAdapterOptions } from '../../adapters/memory.js';
27
+ import { createMemoryAdapter } from '../../adapters/memory.js';
28
+ import { createRecurringAdapter, type RecurringAdapterOptions } from '../../adapters/recurring.js';
29
+ import Calendar from '../../calendar/Calendar.svelte';
30
+ import type { CalendarView } from '../../calendar/Calendar.svelte';
31
+ import { WeekGrid } from '../week/index.js';
32
+ import { Agenda } from '../agenda/index.js';
33
+
34
+ interface Props {
35
+ /** Concrete events (mutually exclusive with `schedule`) */
36
+ events?: TimelineEvent[];
37
+ /** Recurring weekly schedule (mutually exclusive with `events`) */
38
+ schedule?: RecurringEvent[];
39
+ /** CSS theme string */
40
+ theme?: string;
41
+ /** BCP 47 locale */
42
+ locale?: string;
43
+ /** Total height */
44
+ height?: number;
45
+ /** Start week on Monday */
46
+ mondayStart?: boolean;
47
+ /** Read-only mode (default: true for schedule display) */
48
+ readOnly?: boolean;
49
+ /** Visible hour range [startHour, endHour) */
50
+ visibleHours?: [number, number];
51
+ /** Show toolbar */
52
+ showToolbar?: boolean;
53
+ /** Show agenda view toggle */
54
+ showAgenda?: boolean;
55
+ /** Map of category/title to color */
56
+ colorMap?: Record<string, string>;
57
+ /** Auto-assign colors */
58
+ autoColor?: boolean;
59
+ /** Event click handler */
60
+ oneventclick?: (event: TimelineEvent) => void;
61
+ /** Event create handler (only works when readOnly is false) */
62
+ oneventcreate?: (range: { start: Date; end: Date }) => void;
63
+ }
64
+
65
+ let {
66
+ events,
67
+ schedule,
68
+ theme = '',
69
+ locale,
70
+ height = 560,
71
+ mondayStart = true,
72
+ readOnly = true,
73
+ visibleHours,
74
+ showToolbar = true,
75
+ showAgenda = true,
76
+ colorMap,
77
+ autoColor,
78
+ oneventclick,
79
+ oneventcreate,
80
+ }: Props = $props();
81
+
82
+ // Auto-create the adapter from events or schedule
83
+ const adapter = $derived.by(() => {
84
+ if (schedule) {
85
+ return createRecurringAdapter(schedule, {
86
+ mondayStart,
87
+ colorMap,
88
+ autoColor,
89
+ } satisfies RecurringAdapterOptions);
90
+ }
91
+ return createMemoryAdapter(events ?? [], {
92
+ colorMap,
93
+ autoColor,
94
+ } satisfies MemoryAdapterOptions);
95
+ });
96
+
97
+ // Pre-wired views
98
+ const views = $derived.by((): CalendarView[] => {
99
+ const v: CalendarView[] = [
100
+ {
101
+ id: 'week-grid',
102
+ label: 'Week',
103
+ granularity: 'week',
104
+ component: WeekGrid,
105
+ },
106
+ ];
107
+ if (showAgenda) {
108
+ v.push({
109
+ id: 'agenda',
110
+ label: 'Agenda',
111
+ granularity: 'week',
112
+ component: Agenda,
113
+ props: { mode: 'week' },
114
+ });
115
+ }
116
+ return v;
117
+ });
118
+ </script>
119
+
120
+ <Calendar
121
+ {adapter}
122
+ {views}
123
+ defaultView="week-grid"
124
+ {theme}
125
+ {locale}
126
+ {height}
127
+ {mondayStart}
128
+ {readOnly}
129
+ {visibleHours}
130
+ {showToolbar}
131
+ {oneventclick}
132
+ oneventcreate={readOnly ? undefined : oneventcreate}
133
+ />
@@ -0,0 +1,38 @@
1
+ import type { TimelineEvent } from '../../core/types.js';
2
+ import type { RecurringEvent } from '../../adapters/recurring.js';
3
+ interface Props {
4
+ /** Concrete events (mutually exclusive with `schedule`) */
5
+ events?: TimelineEvent[];
6
+ /** Recurring weekly schedule (mutually exclusive with `events`) */
7
+ schedule?: RecurringEvent[];
8
+ /** CSS theme string */
9
+ theme?: string;
10
+ /** BCP 47 locale */
11
+ locale?: string;
12
+ /** Total height */
13
+ height?: number;
14
+ /** Start week on Monday */
15
+ mondayStart?: boolean;
16
+ /** Read-only mode (default: true for schedule display) */
17
+ readOnly?: boolean;
18
+ /** Visible hour range [startHour, endHour) */
19
+ visibleHours?: [number, number];
20
+ /** Show toolbar */
21
+ showToolbar?: boolean;
22
+ /** Show agenda view toggle */
23
+ showAgenda?: boolean;
24
+ /** Map of category/title to color */
25
+ colorMap?: Record<string, string>;
26
+ /** Auto-assign colors */
27
+ autoColor?: boolean;
28
+ /** Event click handler */
29
+ oneventclick?: (event: TimelineEvent) => void;
30
+ /** Event create handler (only works when readOnly is false) */
31
+ oneventcreate?: (range: {
32
+ start: Date;
33
+ end: Date;
34
+ }) => void;
35
+ }
36
+ declare const WeekSchedule: import("svelte").Component<Props, {}, "">;
37
+ type WeekSchedule = ReturnType<typeof WeekSchedule>;
38
+ export default WeekSchedule;
@@ -0,0 +1 @@
1
+ export { default as WeekSchedule } from './WeekSchedule.svelte';
@@ -0,0 +1,2 @@
1
+ // ─── Schedule views barrel export ───────────────────────
2
+ export { default as WeekSchedule } from './WeekSchedule.svelte';
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { slide } from 'svelte/transition';
3
3
  import type { PresetName } from '../../theme/presets.js';
4
- import { presets, stageBg } from '../../theme/presets.js';
4
+ import { presets } from '../../theme/presets.js';
5
5
 
6
6
  /* ─── Field definition types ─────────────────────── */
7
7
  type RangeField = {
@@ -30,6 +30,9 @@
30
30
  oneventclick?: (event: TimelineEvent) => void;
31
31
  oneventcreate?: (range: { start: Date; end: Date }) => void;
32
32
  selectedEventId?: string | null;
33
+ readOnly?: boolean;
34
+ visibleHours?: [number, number];
35
+ [key: string]: unknown;
33
36
  }
34
37
 
35
38
  let {
@@ -41,6 +44,8 @@
41
44
  oneventclick,
42
45
  oneventcreate,
43
46
  selectedEventId = null,
47
+ readOnly = false,
48
+ ...rest
44
49
  }: Props = $props();
45
50
 
46
51
  // ── Drag support (available when inside Calendar) ──
@@ -162,7 +167,7 @@
162
167
  function handleDayCellClick(ms: number, e: Event) {
163
168
  const target = e.target as HTMLElement;
164
169
  if (target.closest('.wg-ev')) return;
165
- if (!oneventcreate) return;
170
+ if (readOnly || !oneventcreate) return;
166
171
  const start = new Date(ms + 9 * 3_600_000);
167
172
  const end = new Date(ms + 10 * 3_600_000);
168
173
  oneventcreate({ start, end });
@@ -182,7 +187,7 @@
182
187
  }
183
188
 
184
189
  function onEventPointerDown(e: PointerEvent, ev: TimelineEvent) {
185
- if (e.button !== 0 || !drag) return;
190
+ if (e.button !== 0 || !drag || readOnly) return;
186
191
  e.stopPropagation();
187
192
  evDragStartX = e.clientX;
188
193
  evDragStarted = false;
@@ -15,6 +15,9 @@ interface Props {
15
15
  end: Date;
16
16
  }) => void;
17
17
  selectedEventId?: string | null;
18
+ readOnly?: boolean;
19
+ visibleHours?: [number, number];
20
+ [key: string]: unknown;
18
21
  }
19
22
  declare const WeekGrid: import("svelte").Component<Props, {}, "">;
20
23
  type WeekGrid = ReturnType<typeof WeekGrid>;
@@ -27,7 +27,13 @@
27
27
  focusDate,
28
28
  oneventclick,
29
29
  selectedEventId = null,
30
- }: WeekTimelineProps = $props();
30
+ visibleHours,
31
+ ...rest
32
+ }: WeekTimelineProps & { visibleHours?: [number, number]; [key: string]: unknown } = $props();
33
+
34
+ const startHour = $derived(visibleHours?.[0] ?? 0);
35
+ const endHour = $derived(visibleHours?.[1] ?? 24);
36
+ const visibleHourCount = $derived(endHour - startHour);
31
37
 
32
38
  const clock = createClock();
33
39
 
@@ -66,7 +72,7 @@
66
72
  const isToday = ms === clock.today;
67
73
 
68
74
  const cells: HeatCell[] = [];
69
- for (let h = 0; h < 24; h++) {
75
+ for (let h = startHour; h < endHour; h++) {
70
76
  const cellStart = ms + h * 3600000;
71
77
  const cellEnd = cellStart + 3600000;
72
78
  const overlaps = events.filter((ev) => ev.start.getTime() < cellEnd && ev.end.getTime() > cellStart);
@@ -179,9 +185,10 @@
179
185
  <!-- Hour labels row -->
180
186
  <div class="hm-hours-row">
181
187
  <div class="hm-row-label"></div>
182
- {#each Array(24) as _, h}
183
- {#if h % 3 === 0}
184
- <span class="hm-hour-mark" style:left="calc({h} * (100% / 24))">{fmtH(h)}</span>
188
+ {#each Array(visibleHourCount) as _, idx}
189
+ {@const h = startHour + idx}
190
+ {#if (h - startHour) % 3 === 0}
191
+ <span class="hm-hour-mark" style:left="calc({idx} * (100% / {visibleHourCount}))">{fmtH(h)}</span>
185
192
  {/if}
186
193
  {/each}
187
194
  </div>
@@ -1,4 +1,8 @@
1
1
  import type { WeekTimelineProps } from '../../core/types.js';
2
- declare const WeekHeatmap: import("svelte").Component<WeekTimelineProps, {}, "">;
2
+ type $$ComponentProps = WeekTimelineProps & {
3
+ visibleHours?: [number, number];
4
+ [key: string]: unknown;
5
+ };
6
+ declare const WeekHeatmap: import("svelte").Component<$$ComponentProps, {}, "">;
3
7
  type WeekHeatmap = ReturnType<typeof WeekHeatmap>;
4
8
  export default WeekHeatmap;