@nomideusz/svelte-calendar 0.1.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 (77) hide show
  1. package/README.md +168 -0
  2. package/dist/adapters/index.d.ts +4 -0
  3. package/dist/adapters/index.js +2 -0
  4. package/dist/adapters/memory.d.ts +14 -0
  5. package/dist/adapters/memory.js +33 -0
  6. package/dist/adapters/rest.d.ts +20 -0
  7. package/dist/adapters/rest.js +48 -0
  8. package/dist/adapters/types.d.ts +23 -0
  9. package/dist/adapters/types.js +1 -0
  10. package/dist/assets/favicon.svg +1 -0
  11. package/dist/calendar/Calendar.svelte +213 -0
  12. package/dist/calendar/Calendar.svelte.d.ts +45 -0
  13. package/dist/calendar/Toolbar.svelte +241 -0
  14. package/dist/calendar/Toolbar.svelte.d.ts +19 -0
  15. package/dist/calendar/index.d.ts +3 -0
  16. package/dist/calendar/index.js +3 -0
  17. package/dist/core/clock.svelte.d.ts +21 -0
  18. package/dist/core/clock.svelte.js +53 -0
  19. package/dist/core/index.d.ts +6 -0
  20. package/dist/core/index.js +8 -0
  21. package/dist/core/locale.d.ts +38 -0
  22. package/dist/core/locale.js +96 -0
  23. package/dist/core/time.d.ts +37 -0
  24. package/dist/core/time.js +68 -0
  25. package/dist/core/types.d.ts +91 -0
  26. package/dist/core/types.js +11 -0
  27. package/dist/engine/drag.svelte.d.ts +31 -0
  28. package/dist/engine/drag.svelte.js +58 -0
  29. package/dist/engine/event-store.svelte.d.ts +47 -0
  30. package/dist/engine/event-store.svelte.js +120 -0
  31. package/dist/engine/index.d.ts +8 -0
  32. package/dist/engine/index.js +5 -0
  33. package/dist/engine/selection.svelte.d.ts +24 -0
  34. package/dist/engine/selection.svelte.js +58 -0
  35. package/dist/engine/view-state.svelte.d.ts +24 -0
  36. package/dist/engine/view-state.svelte.js +74 -0
  37. package/dist/index.d.ts +13 -0
  38. package/dist/index.js +14 -0
  39. package/dist/primitives/DayHeader.svelte +103 -0
  40. package/dist/primitives/DayHeader.svelte.d.ts +15 -0
  41. package/dist/primitives/EmptySlot.svelte +101 -0
  42. package/dist/primitives/EmptySlot.svelte.d.ts +16 -0
  43. package/dist/primitives/EventBlock.svelte +241 -0
  44. package/dist/primitives/EventBlock.svelte.d.ts +24 -0
  45. package/dist/primitives/NowIndicator.svelte +175 -0
  46. package/dist/primitives/NowIndicator.svelte.d.ts +22 -0
  47. package/dist/primitives/TimeGutter.svelte +105 -0
  48. package/dist/primitives/TimeGutter.svelte.d.ts +14 -0
  49. package/dist/primitives/index.d.ts +5 -0
  50. package/dist/primitives/index.js +6 -0
  51. package/dist/theme/index.d.ts +2 -0
  52. package/dist/theme/index.js +2 -0
  53. package/dist/theme/presets.d.ts +24 -0
  54. package/dist/theme/presets.js +89 -0
  55. package/dist/views/agenda/Agenda.svelte +1404 -0
  56. package/dist/views/agenda/Agenda.svelte.d.ts +20 -0
  57. package/dist/views/agenda/index.d.ts +1 -0
  58. package/dist/views/agenda/index.js +1 -0
  59. package/dist/views/day/DayGrid.svelte +1063 -0
  60. package/dist/views/day/DayGrid.svelte.d.ts +33 -0
  61. package/dist/views/day/DayTimeline.svelte +505 -0
  62. package/dist/views/day/DayTimeline.svelte.d.ts +4 -0
  63. package/dist/views/day/index.d.ts +2 -0
  64. package/dist/views/day/index.js +2 -0
  65. package/dist/views/index.d.ts +5 -0
  66. package/dist/views/index.js +5 -0
  67. package/dist/views/settings/Settings.svelte +303 -0
  68. package/dist/views/settings/Settings.svelte.d.ts +23 -0
  69. package/dist/views/settings/index.d.ts +2 -0
  70. package/dist/views/settings/index.js +1 -0
  71. package/dist/views/week/WeekGrid.svelte +594 -0
  72. package/dist/views/week/WeekGrid.svelte.d.ts +21 -0
  73. package/dist/views/week/WeekHeatmap.svelte +453 -0
  74. package/dist/views/week/WeekHeatmap.svelte.d.ts +4 -0
  75. package/dist/views/week/index.d.ts +2 -0
  76. package/dist/views/week/index.js +2 -0
  77. package/package.json +62 -0
@@ -0,0 +1,303 @@
1
+ <script lang="ts">
2
+ import { slide } from 'svelte/transition';
3
+ import type { PresetName } from '../../theme/presets.js';
4
+ import { presets, stageBg } from '../../theme/presets.js';
5
+
6
+ /* ─── Field definition types ─────────────────────── */
7
+ type RangeField = {
8
+ key: string;
9
+ label: string;
10
+ type: 'range';
11
+ min: number;
12
+ max: number;
13
+ step: number;
14
+ };
15
+
16
+ type ToggleField = {
17
+ key: string;
18
+ label: string;
19
+ type: 'toggle';
20
+ };
21
+
22
+ export type SettingsField = RangeField | ToggleField;
23
+
24
+ /* ─── Props ───────────────────────────────────────── */
25
+ interface Props {
26
+ fields: SettingsField[];
27
+ values: Record<string, number | boolean>;
28
+ theme: PresetName;
29
+ }
30
+
31
+ let { fields, values = $bindable(), theme = $bindable() }: Props = $props();
32
+
33
+ const themeKeys: PresetName[] = ['midnight', 'parchment', 'indigo'];
34
+ const themeLabels: Record<PresetName, string> = {
35
+ midnight: 'Midnight',
36
+ parchment: 'Parchment',
37
+ indigo: 'Indigo',
38
+ };
39
+ const themeAccents: Record<PresetName, string> = {
40
+ midnight: '#ef4444',
41
+ parchment: '#b85c2f',
42
+ indigo: '#6366f1',
43
+ };
44
+
45
+ let open = $state(true);
46
+
47
+ function setVal(key: string, v: number | boolean) {
48
+ values = { ...values, [key]: v };
49
+ }
50
+
51
+ function fmt(v: number | boolean): string {
52
+ if (typeof v === 'boolean') return v ? 'true' : 'false';
53
+ if (Number.isInteger(v)) return String(v);
54
+ return v.toFixed(2);
55
+ }
56
+ </script>
57
+
58
+ <div class="stg">
59
+ <button class="stg-toggle" onclick={() => (open = !open)}>
60
+ <svg class="stg-icon" class:stg-icon--open={open} viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
61
+ <path d="M6 4l4 4-4 4" />
62
+ </svg>
63
+ <span>Settings</span>
64
+ </button>
65
+
66
+ {#if open}
67
+ <div class="stg-body" transition:slide={{ duration: 180 }}>
68
+ <!-- Theme picker -->
69
+ <div class="stg-row">
70
+ <span class="stg-label">Theme</span>
71
+ <div class="stg-themes">
72
+ {#each themeKeys as k (k)}
73
+ <button
74
+ class="stg-chip"
75
+ class:stg-chip--active={theme === k}
76
+ style="--chip-c: {themeAccents[k]}"
77
+ onclick={() => (theme = k)}
78
+ >
79
+ <span class="stg-chip-dot"></span>
80
+ {themeLabels[k]}
81
+ </button>
82
+ {/each}
83
+ </div>
84
+ </div>
85
+
86
+ <!-- Dynamic fields -->
87
+ {#each fields as f (f.key)}
88
+ <div class="stg-row">
89
+ <span class="stg-label">{f.label}</span>
90
+ {#if f.type === 'range'}
91
+ <div class="stg-slider-wrap">
92
+ <input
93
+ class="stg-slider"
94
+ type="range"
95
+ min={f.min}
96
+ max={f.max}
97
+ step={f.step}
98
+ value={values[f.key]}
99
+ oninput={(e) => setVal(f.key, Number((e.target as HTMLInputElement).value))}
100
+ />
101
+ <span class="stg-val">{fmt(values[f.key])}</span>
102
+ </div>
103
+ {:else if f.type === 'toggle'}
104
+ <button
105
+ class="stg-sw"
106
+ class:stg-sw--on={values[f.key] === true}
107
+ onclick={() => setVal(f.key, !values[f.key])}
108
+ aria-pressed={values[f.key] === true}
109
+ aria-label={f.label}
110
+ >
111
+ <span class="stg-sw-knob"></span>
112
+ </button>
113
+ {/if}
114
+ </div>
115
+ {/each}
116
+ </div>
117
+ {/if}
118
+ </div>
119
+
120
+ <style>
121
+ .stg {
122
+ border: 1px solid rgba(148, 160, 180, 0.06);
123
+ border-radius: 10px;
124
+ background: rgba(148, 160, 180, 0.02);
125
+ overflow: hidden;
126
+ margin-bottom: 20px;
127
+ }
128
+
129
+ /* ─── Toggle header ──────────────────────────────── */
130
+ .stg-toggle {
131
+ display: flex;
132
+ align-items: center;
133
+ gap: 6px;
134
+ width: 100%;
135
+ padding: 10px 14px;
136
+ background: none;
137
+ border: none;
138
+ cursor: pointer;
139
+ font: 500 10px / 1 'Outfit', system-ui, sans-serif;
140
+ letter-spacing: 0.08em;
141
+ text-transform: uppercase;
142
+ color: rgba(148, 160, 180, 0.4);
143
+ transition: color 120ms;
144
+ }
145
+ .stg-toggle:hover {
146
+ color: rgba(220, 225, 235, 0.7);
147
+ }
148
+
149
+ .stg-icon {
150
+ width: 12px;
151
+ height: 12px;
152
+ transition: transform 160ms ease;
153
+ flex-shrink: 0;
154
+ }
155
+ .stg-icon--open {
156
+ transform: rotate(90deg);
157
+ }
158
+
159
+ /* ─── Body ────────────────────────────────────────── */
160
+ .stg-body {
161
+ padding: 2px 14px 14px;
162
+ display: flex;
163
+ flex-direction: column;
164
+ gap: 10px;
165
+ }
166
+
167
+ /* ─── Row ─────────────────────────────────────────── */
168
+ .stg-row {
169
+ display: flex;
170
+ align-items: center;
171
+ gap: 12px;
172
+ min-height: 28px;
173
+ }
174
+ .stg-label {
175
+ flex-shrink: 0;
176
+ width: 100px;
177
+ font: 400 10px / 1 'SF Mono', 'Cascadia Code', 'Fira Code', Consolas, monospace;
178
+ color: rgba(148, 160, 180, 0.35);
179
+ white-space: nowrap;
180
+ }
181
+
182
+ /* ─── Theme chips ────────────────────────────────── */
183
+ .stg-themes {
184
+ display: flex;
185
+ gap: 6px;
186
+ flex-wrap: wrap;
187
+ }
188
+ .stg-chip {
189
+ display: inline-flex;
190
+ align-items: center;
191
+ gap: 5px;
192
+ padding: 4px 10px;
193
+ border-radius: 100px;
194
+ border: 1px solid rgba(148, 160, 180, 0.08);
195
+ background: rgba(148, 160, 180, 0.03);
196
+ cursor: pointer;
197
+ font: 400 10px / 1 'Outfit', system-ui, sans-serif;
198
+ color: rgba(148, 160, 180, 0.4);
199
+ transition: border-color 140ms, background 140ms, color 140ms;
200
+ }
201
+ .stg-chip:hover {
202
+ border-color: rgba(148, 160, 180, 0.15);
203
+ color: rgba(220, 225, 235, 0.6);
204
+ }
205
+ .stg-chip--active {
206
+ border-color: var(--chip-c);
207
+ background: color-mix(in srgb, var(--chip-c) 8%, transparent);
208
+ color: var(--chip-c);
209
+ }
210
+ .stg-chip-dot {
211
+ width: 7px;
212
+ height: 7px;
213
+ border-radius: 50%;
214
+ background: var(--chip-c);
215
+ opacity: 0.6;
216
+ }
217
+ .stg-chip--active .stg-chip-dot {
218
+ opacity: 1;
219
+ box-shadow: 0 0 6px var(--chip-c);
220
+ }
221
+
222
+ /* ─── Range slider ───────────────────────────────── */
223
+ .stg-slider-wrap {
224
+ flex: 1;
225
+ display: flex;
226
+ align-items: center;
227
+ gap: 10px;
228
+ }
229
+ .stg-slider {
230
+ flex: 1;
231
+ -webkit-appearance: none;
232
+ appearance: none;
233
+ height: 3px;
234
+ border-radius: 2px;
235
+ background: rgba(148, 160, 180, 0.1);
236
+ outline: none;
237
+ cursor: pointer;
238
+ }
239
+ .stg-slider::-webkit-slider-thumb {
240
+ -webkit-appearance: none;
241
+ width: 14px;
242
+ height: 14px;
243
+ border-radius: 50%;
244
+ background: rgba(220, 225, 235, 0.5);
245
+ border: 2px solid rgba(220, 225, 235, 0.15);
246
+ cursor: grab;
247
+ transition: background 100ms, transform 100ms;
248
+ }
249
+ .stg-slider::-webkit-slider-thumb:hover {
250
+ background: rgba(220, 225, 235, 0.7);
251
+ transform: scale(1.15);
252
+ }
253
+ .stg-slider::-webkit-slider-thumb:active {
254
+ cursor: grabbing;
255
+ }
256
+ .stg-slider::-moz-range-thumb {
257
+ width: 14px;
258
+ height: 14px;
259
+ border-radius: 50%;
260
+ background: rgba(220, 225, 235, 0.5);
261
+ border: 2px solid rgba(220, 225, 235, 0.15);
262
+ cursor: grab;
263
+ }
264
+ .stg-val {
265
+ flex-shrink: 0;
266
+ min-width: 38px;
267
+ text-align: right;
268
+ font: 500 10px / 1 'SF Mono', 'Cascadia Code', monospace;
269
+ color: rgba(220, 225, 235, 0.45);
270
+ font-variant-numeric: tabular-nums;
271
+ }
272
+
273
+ /* ─── Toggle switch ──────────────────────────────── */
274
+ .stg-sw {
275
+ position: relative;
276
+ width: 34px;
277
+ height: 18px;
278
+ border-radius: 9px;
279
+ border: 1px solid rgba(148, 160, 180, 0.12);
280
+ background: rgba(148, 160, 180, 0.08);
281
+ cursor: pointer;
282
+ padding: 0;
283
+ transition: background 160ms, border-color 160ms;
284
+ }
285
+ .stg-sw--on {
286
+ background: rgba(99, 102, 241, 0.25);
287
+ border-color: rgba(99, 102, 241, 0.35);
288
+ }
289
+ .stg-sw-knob {
290
+ position: absolute;
291
+ top: 2px;
292
+ left: 2px;
293
+ width: 12px;
294
+ height: 12px;
295
+ border-radius: 50%;
296
+ background: rgba(148, 160, 180, 0.4);
297
+ transition: transform 160ms ease, background 160ms;
298
+ }
299
+ .stg-sw--on .stg-sw-knob {
300
+ transform: translateX(16px);
301
+ background: rgba(99, 102, 241, 0.9);
302
+ }
303
+ </style>
@@ -0,0 +1,23 @@
1
+ import type { PresetName } from '../../theme/presets.js';
2
+ type RangeField = {
3
+ key: string;
4
+ label: string;
5
+ type: 'range';
6
+ min: number;
7
+ max: number;
8
+ step: number;
9
+ };
10
+ type ToggleField = {
11
+ key: string;
12
+ label: string;
13
+ type: 'toggle';
14
+ };
15
+ export type SettingsField = RangeField | ToggleField;
16
+ interface Props {
17
+ fields: SettingsField[];
18
+ values: Record<string, number | boolean>;
19
+ theme: PresetName;
20
+ }
21
+ declare const Settings: import("svelte").Component<Props, {}, "values" | "theme">;
22
+ type Settings = ReturnType<typeof Settings>;
23
+ export default Settings;
@@ -0,0 +1,2 @@
1
+ export { default as Settings } from './Settings.svelte';
2
+ export type { SettingsField } from './Settings.svelte';
@@ -0,0 +1 @@
1
+ export { default as Settings } from './Settings.svelte';