@nomideusz/svelte-calendar 0.4.0 → 0.5.2

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 (73) hide show
  1. package/README.md +331 -568
  2. package/dist/adapters/recurring.d.ts +45 -8
  3. package/dist/adapters/recurring.js +227 -49
  4. package/dist/adapters/rest.js +6 -1
  5. package/dist/calendar/Calendar.svelte +118 -30
  6. package/dist/calendar/Calendar.svelte.d.ts +9 -8
  7. package/dist/calendar/index.d.ts +0 -1
  8. package/dist/calendar/index.js +0 -1
  9. package/dist/core/index.d.ts +5 -4
  10. package/dist/core/index.js +2 -3
  11. package/dist/core/locale.d.ts +74 -0
  12. package/dist/core/locale.js +96 -4
  13. package/dist/core/time.d.ts +30 -0
  14. package/dist/core/time.js +42 -0
  15. package/dist/core/types.d.ts +1 -72
  16. package/dist/core/types.js +1 -8
  17. package/dist/engine/event-store.svelte.js +2 -2
  18. package/dist/engine/index.d.ts +1 -1
  19. package/dist/engine/view-state.svelte.d.ts +11 -6
  20. package/dist/engine/view-state.svelte.js +5 -4
  21. package/dist/index.d.ts +6 -7
  22. package/dist/index.js +4 -4
  23. package/dist/primitives/EmptySlot.svelte +6 -16
  24. package/dist/primitives/EventBlock.svelte +6 -19
  25. package/dist/primitives/NowIndicator.svelte +7 -4
  26. package/dist/primitives/TimeGutter.svelte +1 -1
  27. package/dist/theme/index.d.ts +1 -1
  28. package/dist/theme/index.js +1 -1
  29. package/dist/theme/presets.d.ts +11 -19
  30. package/dist/theme/presets.js +25 -111
  31. package/dist/views/agenda/Agenda.svelte +17 -1516
  32. package/dist/views/agenda/Agenda.svelte.d.ts +0 -14
  33. package/dist/views/agenda/AgendaDay.svelte +976 -0
  34. package/dist/views/agenda/AgendaDay.svelte.d.ts +14 -0
  35. package/dist/views/agenda/AgendaWeek.svelte +775 -0
  36. package/dist/views/agenda/AgendaWeek.svelte.d.ts +15 -0
  37. package/dist/views/agenda/index.d.ts +2 -0
  38. package/dist/views/agenda/index.js +2 -0
  39. package/dist/views/index.d.ts +2 -6
  40. package/dist/views/index.js +2 -6
  41. package/dist/views/planner/Planner.svelte +17 -0
  42. package/dist/views/planner/Planner.svelte.d.ts +7 -0
  43. package/dist/views/planner/PlannerDay.svelte +957 -0
  44. package/dist/views/{day/DayGrid.svelte.d.ts → planner/PlannerDay.svelte.d.ts} +6 -16
  45. package/dist/views/planner/PlannerWeek.svelte +840 -0
  46. package/dist/views/{week/WeekGrid.svelte.d.ts → planner/PlannerWeek.svelte.d.ts} +4 -9
  47. package/dist/views/planner/index.d.ts +1 -0
  48. package/dist/views/planner/index.js +1 -0
  49. package/dist/widget/CalendarWidget.svelte +54 -33
  50. package/dist/widget/CalendarWidget.svelte.d.ts +1 -1
  51. package/package.json +70 -65
  52. package/widget/svelte-calendar.css +1 -0
  53. package/widget/widget.js +122 -260
  54. package/dist/calendar/Toolbar.svelte +0 -244
  55. package/dist/calendar/Toolbar.svelte.d.ts +0 -21
  56. package/dist/views/day/DayGrid.svelte +0 -1104
  57. package/dist/views/day/DayTimeline.svelte +0 -533
  58. package/dist/views/day/DayTimeline.svelte.d.ts +0 -8
  59. package/dist/views/day/index.d.ts +0 -2
  60. package/dist/views/day/index.js +0 -2
  61. package/dist/views/schedule/WeekSchedule.svelte +0 -137
  62. package/dist/views/schedule/WeekSchedule.svelte.d.ts +0 -40
  63. package/dist/views/schedule/index.d.ts +0 -1
  64. package/dist/views/schedule/index.js +0 -2
  65. package/dist/views/settings/Settings.svelte +0 -585
  66. package/dist/views/settings/Settings.svelte.d.ts +0 -39
  67. package/dist/views/settings/index.d.ts +0 -2
  68. package/dist/views/settings/index.js +0 -1
  69. package/dist/views/week/WeekGrid.svelte +0 -632
  70. package/dist/views/week/WeekHeatmap.svelte +0 -461
  71. package/dist/views/week/WeekHeatmap.svelte.d.ts +0 -9
  72. package/dist/views/week/index.d.ts +0 -2
  73. package/dist/views/week/index.js +0 -2
@@ -1,40 +0,0 @@
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
- /** Text direction */
13
- dir?: 'ltr' | 'rtl' | 'auto';
14
- /** Total height */
15
- height?: number;
16
- /** Start week on Monday */
17
- mondayStart?: boolean;
18
- /** Read-only mode (default: true for schedule display) */
19
- readOnly?: boolean;
20
- /** Visible hour range [startHour, endHour) */
21
- visibleHours?: [number, number];
22
- /** Show toolbar */
23
- showToolbar?: boolean;
24
- /** Show agenda view toggle */
25
- showAgenda?: boolean;
26
- /** Map of category/title to color */
27
- colorMap?: Record<string, string>;
28
- /** Auto-assign colors */
29
- autoColor?: boolean;
30
- /** Event click handler */
31
- oneventclick?: (event: TimelineEvent) => void;
32
- /** Event create handler (only works when readOnly is false) */
33
- oneventcreate?: (range: {
34
- start: Date;
35
- end: Date;
36
- }) => void;
37
- }
38
- declare const WeekSchedule: import("svelte").Component<Props, {}, "">;
39
- type WeekSchedule = ReturnType<typeof WeekSchedule>;
40
- export default WeekSchedule;
@@ -1 +0,0 @@
1
- export { default as WeekSchedule } from './WeekSchedule.svelte';
@@ -1,2 +0,0 @@
1
- // ─── Schedule views barrel export ───────────────────────
2
- export { default as WeekSchedule } from './WeekSchedule.svelte';
@@ -1,585 +0,0 @@
1
- <script lang="ts">
2
- import { slide } from 'svelte/transition';
3
- import type { PresetName } from '../../theme/presets.js';
4
- import { presets } from '../../theme/presets.js';
5
-
6
- /* ─── Field definition types ─────────────────────── */
7
- type BaseField = {
8
- key: string;
9
- label: string;
10
- group?: string;
11
- };
12
-
13
- type RangeField = BaseField & {
14
- type: 'range';
15
- min: number;
16
- max: number;
17
- step: number;
18
- enabledWhen?: string;
19
- };
20
-
21
- type ToggleField = BaseField & {
22
- type: 'toggle';
23
- };
24
-
25
- type SelectField = BaseField & {
26
- type: 'select';
27
- options: { value: string; label: string }[];
28
- };
29
-
30
- type SegmentField = BaseField & {
31
- type: 'segment';
32
- options: { value: string; label: string }[];
33
- };
34
-
35
- export type SettingsField = RangeField | ToggleField | SelectField | SegmentField;
36
-
37
- /* ─── Props ───────────────────────────────────────── */
38
- interface Props {
39
- fields: SettingsField[];
40
- values: Record<string, string | number | boolean>;
41
- theme: PresetName;
42
- }
43
-
44
- let { fields, values = $bindable(), theme = $bindable() }: Props = $props();
45
-
46
- const themeKeys: PresetName[] = ['midnight', 'parchment', 'indigo', 'neutral', 'bare'];
47
- const themeLabels: Record<PresetName, string> = {
48
- midnight: 'Midnight',
49
- parchment: 'Parchment',
50
- indigo: 'Indigo',
51
- neutral: 'Neutral',
52
- bare: 'Bare',
53
- };
54
- const darkThemes = new Set<PresetName>(['midnight']);
55
- const panelId = 'stg-panel';
56
-
57
- let open = $state(true);
58
-
59
- const themeStyle = $derived(presets[theme]);
60
- const colorScheme = $derived(darkThemes.has(theme) ? 'dark' : 'light');
61
-
62
- function setVal(key: string, v: string | number | boolean) {
63
- values = { ...values, [key]: v };
64
- }
65
-
66
- function fmt(v: string | number | boolean): string {
67
- if (typeof v === 'string') return v;
68
- if (typeof v === 'boolean') return v ? 'true' : 'false';
69
- if (Number.isInteger(v)) return String(v);
70
- return v.toFixed(2);
71
- }
72
-
73
- function controlId(key: string): string {
74
- return `stg-${key.replace(/[^a-zA-Z0-9_-]/g, '-')}`;
75
- }
76
-
77
- /* Split fields into top-level (no group name) and grouped */
78
- const { topFields, groupedFields } = $derived.by(() => {
79
- const top: SettingsField[] = [];
80
- const orderedGroups: { name: string; id: string; fields: SettingsField[] }[] = [];
81
- const indexByName = new Map<string, number>();
82
-
83
- for (const field of fields) {
84
- const groupName = field.group ?? '';
85
-
86
- if (!groupName) {
87
- top.push(field);
88
- continue;
89
- }
90
-
91
- const existingIndex = indexByName.get(groupName);
92
- if (existingIndex === undefined) {
93
- const id = groupName
94
- .toLowerCase()
95
- .replace(/[^a-z0-9]+/g, '-')
96
- .replace(/(^-|-$)/g, '');
97
- indexByName.set(groupName, orderedGroups.length);
98
- orderedGroups.push({ name: groupName, id: id || 'general', fields: [field] });
99
- } else {
100
- orderedGroups[existingIndex].fields.push(field);
101
- }
102
- }
103
-
104
- return { topFields: top, groupedFields: orderedGroups };
105
- });
106
- </script>
107
-
108
- <div class="stg" style="{themeStyle}; color-scheme: {colorScheme}">
109
- <button
110
- class="stg-hd"
111
- aria-expanded={open}
112
- aria-controls={panelId}
113
- onclick={() => (open = !open)}
114
- >
115
- <svg
116
- class="stg-chevron"
117
- class:stg-chevron--open={open}
118
- viewBox="0 0 16 16"
119
- fill="none"
120
- stroke="currentColor"
121
- stroke-width="1.5"
122
- stroke-linecap="round"
123
- >
124
- <path d="M6 4l4 4-4 4" />
125
- </svg>
126
- <span>Settings</span>
127
- </button>
128
-
129
- {#if open}
130
- <div class="stg-body" id={panelId} transition:slide={{ duration: 180 }}>
131
- <!-- ─── Top bar: theme + ungrouped fields ─── -->
132
- <div class="stg-bar">
133
- <div class="stg-bar-item">
134
- <span class="stg-col-title" id="stg-theme-label">Theme</span>
135
- <div class="stg-pills" role="radiogroup" aria-labelledby="stg-theme-label">
136
- {#each themeKeys as k (k)}
137
- <button
138
- type="button"
139
- class="stg-pill"
140
- class:stg-pill--on={theme === k}
141
- role="radio"
142
- aria-checked={theme === k}
143
- onclick={() => (theme = k)}
144
- >
145
- {themeLabels[k]}
146
- </button>
147
- {/each}
148
- </div>
149
- </div>
150
-
151
- {#each topFields as f (f.key)}
152
- {@const fid = controlId(f.key)}
153
- {#if f.type === 'segment'}
154
- <div class="stg-bar-item">
155
- {#if f.label}
156
- <span class="stg-col-title" id={`${fid}-label`}>{f.label}</span>
157
- {/if}
158
- <div class="stg-pills" role="radiogroup" aria-labelledby={f.label ? `${fid}-label` : undefined} aria-label={f.label ? undefined : f.key}>
159
- {#each f.options as option (option.value)}
160
- <button
161
- type="button"
162
- class="stg-pill"
163
- class:stg-pill--on={String(values[f.key]) === option.value}
164
- role="radio"
165
- aria-checked={String(values[f.key]) === option.value}
166
- onclick={() => setVal(f.key, option.value)}
167
- >
168
- {option.label}
169
- </button>
170
- {/each}
171
- </div>
172
- </div>
173
- {/if}
174
- {/each}
175
- </div>
176
-
177
- <!-- ─── Grouped fields in columns ─── -->
178
- {#if groupedFields.length > 0}
179
- <div class="stg-grid">
180
- {#each groupedFields as section (section.id)}
181
- <section class="stg-col" aria-labelledby={`stg-s-${section.id}`}>
182
- <h3 class="stg-col-title" id={`stg-s-${section.id}`}>{section.name}</h3>
183
-
184
- {#each section.fields as f (f.key)}
185
- {@const fid = controlId(f.key)}
186
-
187
- {#if f.type === 'toggle'}
188
- <label class="stg-row stg-row--toggle" for={fid}>
189
- <span class="stg-lbl">{f.label}</span>
190
- <input
191
- id={fid}
192
- class="stg-sr"
193
- type="checkbox"
194
- role="switch"
195
- checked={values[f.key] === true}
196
- onchange={(e) => setVal(f.key, (e.target as HTMLInputElement).checked)}
197
- />
198
- <span class="stg-sw" aria-hidden="true">
199
- <span class="stg-sw-knob"></span>
200
- </span>
201
- </label>
202
-
203
- {:else if f.type === 'range'}
204
- {@const disabled = !!f.enabledWhen && values[f.enabledWhen] !== true}
205
- <div class="stg-row stg-row--rng" class:stg-row--disabled={disabled}>
206
- <div class="stg-rng-hd">
207
- <label class="stg-lbl" for={fid}>{f.label}</label>
208
- <span class="stg-num">{fmt(values[f.key])}</span>
209
- </div>
210
- <input
211
- id={fid}
212
- class="stg-rng"
213
- type="range"
214
- min={f.min}
215
- max={f.max}
216
- step={f.step}
217
- value={values[f.key]}
218
- {disabled}
219
- oninput={(e) => setVal(f.key, Number((e.target as HTMLInputElement).value))}
220
- />
221
- </div>
222
-
223
- {:else if f.type === 'select'}
224
- <div class="stg-row">
225
- <label class="stg-lbl" for={fid}>{f.label}</label>
226
- <select
227
- id={fid}
228
- class="stg-sel"
229
- value={String(values[f.key] ?? '')}
230
- onchange={(e) => setVal(f.key, (e.target as HTMLSelectElement).value)}
231
- >
232
- {#each f.options as option (option.value)}
233
- <option value={option.value}>{option.label}</option>
234
- {/each}
235
- </select>
236
- </div>
237
-
238
- {:else if f.type === 'segment'}
239
- <div class="stg-row stg-row--seg">
240
- {#if f.label}
241
- <span class="stg-lbl" id={`${fid}-label`}>{f.label}</span>
242
- {/if}
243
- <div class="stg-pills" role="radiogroup" aria-labelledby={f.label ? `${fid}-label` : undefined} aria-label={f.label ? undefined : f.key}>
244
- {#each f.options as option (option.value)}
245
- <button
246
- type="button"
247
- class="stg-pill"
248
- class:stg-pill--on={String(values[f.key]) === option.value}
249
- role="radio"
250
- aria-checked={String(values[f.key]) === option.value}
251
- onclick={() => setVal(f.key, option.value)}
252
- >
253
- {option.label}
254
- </button>
255
- {/each}
256
- </div>
257
- </div>
258
- {/if}
259
- {/each}
260
- </section>
261
- {/each}
262
- </div>
263
- {/if}
264
- </div>
265
- {/if}
266
- </div>
267
-
268
- <style>
269
- /* ─── Root: themed via --dt-* tokens from inline style ─── */
270
- .stg {
271
- border: 1px solid var(--dt-border, rgba(148, 160, 180, 0.10));
272
- border-radius: 10px;
273
- background: var(--dt-surface, #10141c);
274
- overflow: hidden;
275
- font-family: var(--dt-sans, 'Outfit', system-ui, sans-serif);
276
- margin-bottom: 20px;
277
- }
278
-
279
- /* ─── Collapsible header ─────────────────────────── */
280
- .stg-hd {
281
- display: flex;
282
- align-items: center;
283
- gap: 7px;
284
- width: 100%;
285
- padding: 10px 14px;
286
- background: none;
287
- border: none;
288
- cursor: pointer;
289
- font-weight: 600;
290
- font-size: 12px;
291
- line-height: 1;
292
- letter-spacing: 0.06em;
293
- text-transform: uppercase;
294
- color: var(--dt-text-2, rgba(148, 160, 180, 0.62));
295
- transition: color 120ms;
296
- }
297
- .stg-hd:hover {
298
- color: var(--dt-text, rgba(228, 234, 245, 0.88));
299
- }
300
-
301
- .stg-chevron {
302
- width: 11px;
303
- height: 11px;
304
- flex-shrink: 0;
305
- transition: transform 150ms ease;
306
- }
307
- .stg-chevron--open {
308
- transform: rotate(90deg);
309
- }
310
-
311
- /* ─── Body ───────────────────────────────────────── */
312
- .stg-body {
313
- padding: 0 14px 12px;
314
- display: flex;
315
- flex-direction: column;
316
- gap: 6px;
317
- }
318
-
319
- /* ─── Top bar: theme + mode pills ────────────────── */
320
- .stg-bar {
321
- display: flex;
322
- flex-wrap: wrap;
323
- align-items: center;
324
- gap: 6px 20px;
325
- padding-bottom: 4px;
326
- }
327
-
328
- .stg-bar-item {
329
- display: flex;
330
- align-items: center;
331
- gap: 8px;
332
- }
333
-
334
- /* ─── Column grid for grouped fields ─────────────── */
335
- .stg-grid {
336
- display: grid;
337
- grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
338
- gap: 2px 20px;
339
- border-top: 1px solid color-mix(in srgb, var(--dt-border, rgba(148, 160, 180, 0.10)) 50%, transparent);
340
- padding-top: 6px;
341
- }
342
-
343
- .stg-col {
344
- padding: 4px 0 2px;
345
- min-width: 0;
346
- }
347
-
348
- .stg-col-title {
349
- margin: 0 0 2px;
350
- font-weight: 600;
351
- font-size: 11px;
352
- line-height: 1;
353
- letter-spacing: 0.08em;
354
- text-transform: uppercase;
355
- color: var(--dt-text-3, rgba(148, 160, 180, 0.40));
356
- }
357
-
358
- /* ─── Row (inline: label left, control right) ──── */
359
- .stg-row {
360
- display: flex;
361
- align-items: center;
362
- justify-content: space-between;
363
- gap: 10px;
364
- min-height: 26px;
365
- padding: 2px 0;
366
- }
367
-
368
- .stg-row--rng {
369
- flex-direction: column;
370
- align-items: stretch;
371
- justify-content: flex-start;
372
- gap: 2px;
373
- min-height: auto;
374
- padding: 4px 0;
375
- }
376
-
377
- .stg-row--disabled {
378
- opacity: 0.35;
379
- pointer-events: none;
380
- }
381
-
382
- .stg-rng-hd {
383
- display: flex;
384
- align-items: baseline;
385
- justify-content: space-between;
386
- gap: 8px;
387
- }
388
-
389
- .stg-row--seg {
390
- flex-direction: column;
391
- align-items: flex-start;
392
- justify-content: flex-start;
393
- gap: 3px;
394
- padding: 3px 0;
395
- }
396
-
397
- .stg-row--toggle {
398
- cursor: pointer;
399
- }
400
-
401
- /* ─── Label ──────────────────────────────────────── */
402
- .stg-lbl {
403
- font-weight: 400;
404
- font-size: 13px;
405
- line-height: 1.2;
406
- color: var(--dt-text-2, rgba(148, 160, 180, 0.62));
407
- white-space: nowrap;
408
- flex-shrink: 0;
409
- }
410
-
411
- /* ─── Toggle switch ──────────────────────────────── */
412
- .stg-sr {
413
- position: absolute;
414
- width: 1px;
415
- height: 1px;
416
- margin: -1px;
417
- padding: 0;
418
- overflow: hidden;
419
- clip: rect(0, 0, 0, 0);
420
- border: 0;
421
- }
422
-
423
- .stg-sw {
424
- position: relative;
425
- display: block;
426
- width: 32px;
427
- height: 18px;
428
- border-radius: 9px;
429
- border: 1px solid var(--dt-border, rgba(148, 160, 180, 0.10));
430
- background: color-mix(in srgb, var(--dt-text-3, rgba(148, 160, 180, 0.40)) 10%, transparent);
431
- cursor: pointer;
432
- flex-shrink: 0;
433
- transition: background 150ms, border-color 150ms;
434
- }
435
- .stg-sr:checked + .stg-sw {
436
- background: var(--dt-accent-dim, rgba(99, 102, 241, 0.12));
437
- border-color: color-mix(in srgb, var(--dt-accent, #6366f1) 35%, transparent);
438
- }
439
-
440
- .stg-sw-knob {
441
- position: absolute;
442
- top: 2px;
443
- left: 2px;
444
- width: 12px;
445
- height: 12px;
446
- border-radius: 50%;
447
- background: var(--dt-text-3, rgba(148, 160, 180, 0.40));
448
- transition: transform 150ms ease, background 150ms;
449
- }
450
- .stg-sr:checked + .stg-sw .stg-sw-knob {
451
- transform: translateX(14px);
452
- background: var(--dt-accent, #6366f1);
453
- }
454
-
455
- /* ─── Range slider ───────────────────────────────── */
456
- .stg-rng {
457
- width: 100%;
458
- -webkit-appearance: none;
459
- appearance: none;
460
- height: 3px;
461
- border-radius: 2px;
462
- background: color-mix(in srgb, var(--dt-text-3, rgba(148, 160, 180, 0.40)) 30%, transparent);
463
- outline: none;
464
- cursor: pointer;
465
- }
466
- .stg-rng::-webkit-slider-thumb {
467
- -webkit-appearance: none;
468
- width: 12px;
469
- height: 12px;
470
- border-radius: 50%;
471
- background: var(--dt-text-2, rgba(148, 160, 180, 0.62));
472
- border: none;
473
- cursor: grab;
474
- transition: background 100ms, transform 100ms;
475
- }
476
- .stg-rng::-webkit-slider-thumb:hover {
477
- background: var(--dt-text, rgba(228, 234, 245, 0.88));
478
- transform: scale(1.15);
479
- }
480
- .stg-rng::-webkit-slider-thumb:active {
481
- cursor: grabbing;
482
- }
483
- .stg-rng::-moz-range-thumb {
484
- width: 12px;
485
- height: 12px;
486
- border-radius: 50%;
487
- background: var(--dt-text-2, rgba(148, 160, 180, 0.62));
488
- border: none;
489
- cursor: grab;
490
- }
491
-
492
- .stg-rng:disabled {
493
- cursor: default;
494
- }
495
-
496
- .stg-num {
497
- flex-shrink: 0;
498
- min-width: 22px;
499
- text-align: right;
500
- font: 500 11px / 1 var(--dt-mono, 'SF Mono', 'Cascadia Code', ui-monospace, monospace);
501
- font-variant-numeric: tabular-nums;
502
- color: var(--dt-text-2, rgba(148, 160, 180, 0.62));
503
- }
504
-
505
- /* ─── Select dropdown ────────────────────────────── */
506
- .stg-sel {
507
- appearance: none;
508
- font-weight: 400;
509
- font-size: 13px;
510
- line-height: 1;
511
- padding: 5px 24px 5px 8px;
512
- border-radius: 6px;
513
- border: 1px solid var(--dt-border, rgba(148, 160, 180, 0.10));
514
- background: color-mix(in srgb, var(--dt-text-3, rgba(148, 160, 180, 0.40)) 8%, var(--dt-surface, #10141c));
515
- color: var(--dt-text, rgba(228, 234, 245, 0.88));
516
- outline: none;
517
- cursor: pointer;
518
- background-image: linear-gradient(45deg, transparent 50%, var(--dt-text-3, rgba(148, 160, 180, 0.40)) 50%),
519
- linear-gradient(135deg, var(--dt-text-3, rgba(148, 160, 180, 0.40)) 50%, transparent 50%);
520
- background-position: calc(100% - 12px) center, calc(100% - 8px) center;
521
- background-size: 4px 4px, 4px 4px;
522
- background-repeat: no-repeat;
523
- transition: border-color 120ms;
524
- }
525
- .stg-sel:hover {
526
- border-color: var(--dt-border-day, rgba(148, 160, 180, 0.14));
527
- }
528
- .stg-sel:focus {
529
- border-color: color-mix(in srgb, var(--dt-accent, #6366f1) 45%, transparent);
530
- }
531
- .stg-sel option {
532
- background: var(--dt-bg, #0b0e14);
533
- color: var(--dt-text, rgba(228, 234, 245, 0.88));
534
- }
535
-
536
- /* ─── Segment pills ──────────────────────────────── */
537
- .stg-pills {
538
- display: flex;
539
- flex-wrap: wrap;
540
- gap: 4px;
541
- }
542
-
543
- .stg-pill {
544
- padding: 4px 9px;
545
- border-radius: 100px;
546
- border: 1px solid color-mix(in srgb, var(--dt-border, rgba(148, 160, 180, 0.10)) 60%, transparent);
547
- background: color-mix(in srgb, var(--dt-text-3, rgba(148, 160, 180, 0.40)) 8%, transparent);
548
- color: var(--dt-text-2, rgba(148, 160, 180, 0.62));
549
- font-weight: 400;
550
- font-size: 12px;
551
- line-height: 1;
552
- cursor: pointer;
553
- transition: border-color 120ms, color 120ms, background 120ms;
554
- }
555
- .stg-pill:hover {
556
- color: var(--dt-text, rgba(228, 234, 245, 0.88));
557
- border-color: var(--dt-border, rgba(148, 160, 180, 0.10));
558
- }
559
- .stg-pill--on {
560
- color: var(--dt-accent, #6366f1);
561
- border-color: color-mix(in srgb, var(--dt-accent, #6366f1) 35%, transparent);
562
- background: var(--dt-accent-dim, rgba(99, 102, 241, 0.12));
563
- }
564
-
565
- /* ─── Focus rings ────────────────────────────────── */
566
- .stg-sr:focus-visible + .stg-sw,
567
- .stg-sel:focus-visible,
568
- .stg-rng:focus-visible,
569
- .stg-pill:focus-visible,
570
- .stg-hd:focus-visible {
571
- outline: 2px solid color-mix(in srgb, var(--dt-accent, #6366f1) 55%, transparent);
572
- outline-offset: 2px;
573
- }
574
-
575
- /* ─── Responsive: stack columns on small screens ── */
576
- @media (max-width: 600px) {
577
- .stg-grid {
578
- grid-template-columns: 1fr;
579
- }
580
- .stg-bar {
581
- flex-direction: column;
582
- gap: 6px;
583
- }
584
- }
585
- </style>
@@ -1,39 +0,0 @@
1
- import type { PresetName } from '../../theme/presets.js';
2
- type BaseField = {
3
- key: string;
4
- label: string;
5
- group?: string;
6
- };
7
- type RangeField = BaseField & {
8
- type: 'range';
9
- min: number;
10
- max: number;
11
- step: number;
12
- enabledWhen?: string;
13
- };
14
- type ToggleField = BaseField & {
15
- type: 'toggle';
16
- };
17
- type SelectField = BaseField & {
18
- type: 'select';
19
- options: {
20
- value: string;
21
- label: string;
22
- }[];
23
- };
24
- type SegmentField = BaseField & {
25
- type: 'segment';
26
- options: {
27
- value: string;
28
- label: string;
29
- }[];
30
- };
31
- export type SettingsField = RangeField | ToggleField | SelectField | SegmentField;
32
- interface Props {
33
- fields: SettingsField[];
34
- values: Record<string, string | number | boolean>;
35
- theme: PresetName;
36
- }
37
- declare const Settings: import("svelte").Component<Props, {}, "values" | "theme">;
38
- type Settings = ReturnType<typeof Settings>;
39
- export default Settings;
@@ -1,2 +0,0 @@
1
- export { default as Settings } from './Settings.svelte';
2
- export type { SettingsField } from './Settings.svelte';
@@ -1 +0,0 @@
1
- export { default as Settings } from './Settings.svelte';