@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.
- package/README.md +331 -568
- package/dist/adapters/recurring.d.ts +45 -8
- package/dist/adapters/recurring.js +227 -49
- package/dist/adapters/rest.js +6 -1
- package/dist/calendar/Calendar.svelte +118 -30
- package/dist/calendar/Calendar.svelte.d.ts +9 -8
- package/dist/calendar/index.d.ts +0 -1
- package/dist/calendar/index.js +0 -1
- package/dist/core/index.d.ts +5 -4
- package/dist/core/index.js +2 -3
- package/dist/core/locale.d.ts +74 -0
- package/dist/core/locale.js +96 -4
- package/dist/core/time.d.ts +30 -0
- package/dist/core/time.js +42 -0
- package/dist/core/types.d.ts +1 -72
- package/dist/core/types.js +1 -8
- package/dist/engine/event-store.svelte.js +2 -2
- package/dist/engine/index.d.ts +1 -1
- package/dist/engine/view-state.svelte.d.ts +11 -6
- package/dist/engine/view-state.svelte.js +5 -4
- package/dist/index.d.ts +6 -7
- package/dist/index.js +4 -4
- package/dist/primitives/EmptySlot.svelte +6 -16
- package/dist/primitives/EventBlock.svelte +6 -19
- package/dist/primitives/NowIndicator.svelte +7 -4
- package/dist/primitives/TimeGutter.svelte +1 -1
- package/dist/theme/index.d.ts +1 -1
- package/dist/theme/index.js +1 -1
- package/dist/theme/presets.d.ts +11 -19
- package/dist/theme/presets.js +25 -111
- package/dist/views/agenda/Agenda.svelte +17 -1516
- package/dist/views/agenda/Agenda.svelte.d.ts +0 -14
- package/dist/views/agenda/AgendaDay.svelte +976 -0
- package/dist/views/agenda/AgendaDay.svelte.d.ts +14 -0
- package/dist/views/agenda/AgendaWeek.svelte +775 -0
- package/dist/views/agenda/AgendaWeek.svelte.d.ts +15 -0
- package/dist/views/agenda/index.d.ts +2 -0
- package/dist/views/agenda/index.js +2 -0
- package/dist/views/index.d.ts +2 -6
- package/dist/views/index.js +2 -6
- package/dist/views/planner/Planner.svelte +17 -0
- package/dist/views/planner/Planner.svelte.d.ts +7 -0
- package/dist/views/planner/PlannerDay.svelte +957 -0
- package/dist/views/{day/DayGrid.svelte.d.ts → planner/PlannerDay.svelte.d.ts} +6 -16
- package/dist/views/planner/PlannerWeek.svelte +840 -0
- package/dist/views/{week/WeekGrid.svelte.d.ts → planner/PlannerWeek.svelte.d.ts} +4 -9
- package/dist/views/planner/index.d.ts +1 -0
- package/dist/views/planner/index.js +1 -0
- package/dist/widget/CalendarWidget.svelte +54 -33
- package/dist/widget/CalendarWidget.svelte.d.ts +1 -1
- package/package.json +70 -65
- package/widget/svelte-calendar.css +1 -0
- package/widget/widget.js +122 -260
- package/dist/calendar/Toolbar.svelte +0 -244
- package/dist/calendar/Toolbar.svelte.d.ts +0 -21
- package/dist/views/day/DayGrid.svelte +0 -1104
- package/dist/views/day/DayTimeline.svelte +0 -533
- package/dist/views/day/DayTimeline.svelte.d.ts +0 -8
- package/dist/views/day/index.d.ts +0 -2
- package/dist/views/day/index.js +0 -2
- package/dist/views/schedule/WeekSchedule.svelte +0 -137
- package/dist/views/schedule/WeekSchedule.svelte.d.ts +0 -40
- package/dist/views/schedule/index.d.ts +0 -1
- package/dist/views/schedule/index.js +0 -2
- package/dist/views/settings/Settings.svelte +0 -585
- package/dist/views/settings/Settings.svelte.d.ts +0 -39
- package/dist/views/settings/index.d.ts +0 -2
- package/dist/views/settings/index.js +0 -1
- package/dist/views/week/WeekGrid.svelte +0 -632
- package/dist/views/week/WeekHeatmap.svelte +0 -461
- package/dist/views/week/WeekHeatmap.svelte.d.ts +0 -9
- package/dist/views/week/index.d.ts +0 -2
- 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,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 +0,0 @@
|
|
|
1
|
-
export { default as Settings } from './Settings.svelte';
|