@papu1337/builder 0.0.5 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/builder/BuilderView.svelte +158 -0
- package/dist/builder/BuilderView.svelte.d.ts +8 -0
- package/dist/builder/builder.vanilla.es.js +6514 -0
- package/dist/builder/builder.vanilla.umd.js +89 -0
- package/dist/builder/canvas/canvas.svelte +92 -0
- package/dist/builder/canvas/canvas.svelte.d.ts +17 -0
- package/dist/builder/canvas/styles.css +63 -0
- package/dist/builder/createBuilder.svelte.d.ts +9 -0
- package/dist/builder/createBuilder.svelte.js +17 -0
- package/dist/builder/index.d.ts +8 -0
- package/dist/builder/index.js +7 -0
- package/dist/builder/leftbar/leftBar.svelte +740 -0
- package/dist/builder/leftbar/leftBar.svelte.d.ts +8 -0
- package/dist/builder/leftbar/styles.css +152 -0
- package/dist/builder/pageMeta.svelte.d.ts +13 -0
- package/dist/builder/pageMeta.svelte.js +25 -0
- package/dist/builder/rightbar/rightBar.svelte +100 -0
- package/dist/builder/rightbar/rightBar.svelte.d.ts +10 -0
- package/dist/builder/rightbar/styles.css +167 -0
- package/dist/builder/topbar/TopBar.svelte +337 -0
- package/dist/builder/topbar/TopBar.svelte.d.ts +12 -0
- package/dist/builder/topbar/styles.css +123 -0
- package/dist/builder/viewport.svelte.d.ts +9 -0
- package/dist/builder/viewport.svelte.js +17 -0
- package/dist/elements/_shared/Arrow.svelte +58 -0
- package/dist/elements/_shared/Arrow.svelte.d.ts +11 -0
- package/dist/elements/_shared/GradientBorder.svelte +55 -0
- package/dist/elements/_shared/GradientBorder.svelte.d.ts +10 -0
- package/dist/elements/banner/bannerElement.svelte +101 -33
- package/dist/elements/banner/settings.d.ts +13 -3
- package/dist/elements/banner/settings.js +88 -8
- package/dist/elements/button/buttonElement.svelte +27 -21
- package/dist/elements/button/settings.d.ts +11 -9
- package/dist/elements/button/settings.js +18 -39
- package/dist/elements/globalSettings.js +5 -4
- package/dist/elements/howItWorks/howItWorksElement.svelte +221 -0
- package/dist/elements/howItWorks/howItWorksElement.svelte.d.ts +7 -0
- package/dist/elements/howItWorks/settings.d.ts +16 -0
- package/dist/elements/howItWorks/settings.js +70 -0
- package/dist/elements/steps/settings.d.ts +17 -0
- package/dist/elements/steps/settings.js +69 -0
- package/dist/elements/steps/stepsElement.svelte +220 -0
- package/dist/elements/steps/stepsElement.svelte.d.ts +7 -0
- package/dist/elements/terms/settings.d.ts +14 -0
- package/dist/elements/terms/settings.js +32 -0
- package/dist/elements/terms/termsElement.svelte +209 -0
- package/dist/elements/terms/termsElement.svelte.d.ts +7 -0
- package/dist/elements/text/settings.d.ts +8 -11
- package/dist/elements/text/settings.js +21 -51
- package/dist/elements/text/textElement.svelte +23 -23
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useTranslation.svelte.d.ts +9 -0
- package/dist/hooks/useTranslation.svelte.js +10 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/renderer/BuilderRenderer.svelte +30 -2
- package/dist/renderer/registry.js +6 -6
- package/dist/renderer/renderer.vanilla.es.js +1547 -1188
- package/dist/renderer/renderer.vanilla.umd.js +64 -39
- package/dist/renderer/resolve.d.ts +1 -1
- package/dist/renderer/resolve.js +28 -14
- package/dist/renderer/types.d.ts +2 -0
- package/dist/service/element.action.svelte.d.ts +21 -0
- package/dist/service/element.action.svelte.js +125 -0
- package/dist/service/element.history.svelte.d.ts +8 -0
- package/dist/service/element.history.svelte.js +36 -0
- package/dist/service/element.io.svelte.d.ts +4 -0
- package/dist/service/element.io.svelte.js +232 -0
- package/dist/service/element.reader.svelte.d.ts +4 -0
- package/dist/service/element.reader.svelte.js +51 -0
- package/dist/service/element.translate.svelte.d.ts +12 -0
- package/dist/service/element.translate.svelte.js +81 -0
- package/dist/service/index.d.ts +5 -0
- package/dist/service/index.js +5 -0
- package/dist/service/types.d.ts +13 -0
- package/dist/service/types.js +1 -0
- package/dist/settings/base.svelte.d.ts +6 -1
- package/dist/settings/base.svelte.js +61 -17
- package/dist/settings/components/ColorSettings.svelte +169 -40
- package/dist/settings/components/ColorSettings.svelte.d.ts +3 -2
- package/dist/settings/components/ListSettings.svelte +4 -5
- package/dist/settings/components/NumberSettings.svelte +117 -20
- package/dist/settings/components/RepeaterSettings.svelte +145 -0
- package/dist/settings/components/RepeaterSettings.svelte.d.ts +14 -0
- package/dist/settings/components/SegmentSettings.svelte +85 -0
- package/dist/settings/components/SegmentSettings.svelte.d.ts +5 -0
- package/dist/settings/components/SelectSettings.svelte +2 -3
- package/dist/settings/components/SettingsGroup.svelte +14 -69
- package/dist/settings/components/SettingsRenderer.svelte +76 -0
- package/dist/settings/components/SettingsRenderer.svelte.d.ts +8 -0
- package/dist/settings/components/TextSettings.svelte +2 -3
- package/dist/settings/components/TranslatableSettings.svelte +3 -4
- package/dist/settings/components/UploadSettings.svelte +2 -3
- package/dist/settings/groups.d.ts +23 -7
- package/dist/settings/groups.js +48 -24
- package/dist/settings/implementation.svelte.js +4 -0
- package/dist/settings/index.d.ts +2 -0
- package/dist/settings/index.js +2 -0
- package/dist/settings/mode.svelte.d.ts +4 -0
- package/dist/settings/mode.svelte.js +4 -0
- package/dist/settings/repeater.svelte.d.ts +26 -0
- package/dist/settings/repeater.svelte.js +70 -0
- package/dist/settings/types.d.ts +28 -2
- package/package.json +8 -2
- package/dist/elements/accordion/accordionElement.svelte +0 -101
- package/dist/elements/accordion/accordionElement.svelte.d.ts +0 -7
- package/dist/elements/accordion/settings.d.ts +0 -17
- package/dist/elements/accordion/settings.js +0 -54
- package/dist/elements/badge/badgeElement.svelte +0 -49
- package/dist/elements/badge/badgeElement.svelte.d.ts +0 -7
- package/dist/elements/badge/settings.d.ts +0 -14
- package/dist/elements/badge/settings.js +0 -47
- package/dist/elements/ctaCard/ctaCardElement.svelte +0 -132
- package/dist/elements/ctaCard/ctaCardElement.svelte.d.ts +0 -7
- package/dist/elements/ctaCard/settings.d.ts +0 -22
- package/dist/elements/ctaCard/settings.js +0 -64
|
@@ -1,21 +1,42 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import type { BaseSettingProps } from '../types';
|
|
2
|
+
import type { BaseSettingProps, ColorExtra } from '../types';
|
|
3
3
|
|
|
4
|
-
let { title, value, onchange, onpreview }: BaseSettingProps<string> =
|
|
4
|
+
let { title, value, onchange, onpreview, allowGradient }: BaseSettingProps<string> & ColorExtra =
|
|
5
|
+
$props();
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const isGradientValue = (candidate: string): boolean => /gradient\(/i.test(candidate);
|
|
8
|
+
const gradient = $derived(isGradientValue(value));
|
|
9
|
+
|
|
10
|
+
const HEX_RE = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
|
|
11
|
+
|
|
12
|
+
let from = $state('#E0AE5A');
|
|
13
|
+
let to = $state('#FFFFFF');
|
|
14
|
+
let angle = $state(90);
|
|
15
|
+
|
|
16
|
+
$effect(() => {
|
|
17
|
+
if (!isGradientValue(value)) return;
|
|
18
|
+
const hexes = value.match(/#[0-9a-fA-F]{3,8}/g);
|
|
19
|
+
const deg = value.match(/(-?\d+)deg/);
|
|
20
|
+
if (hexes?.[0]) from = hexes[0];
|
|
21
|
+
if (hexes?.[1]) to = hexes[1];
|
|
22
|
+
if (deg) angle = Number(deg[1]);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const build = (): string => `linear-gradient(${angle}deg, ${from}, ${to})`;
|
|
26
|
+
|
|
27
|
+
function setSolid(): void {
|
|
28
|
+
if (!gradient) return;
|
|
29
|
+
onchange(HEX_RE.test(from) ? from : '#FFFFFF');
|
|
9
30
|
}
|
|
10
31
|
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
|
|
32
|
+
function setGradient(): void {
|
|
33
|
+
if (gradient) return;
|
|
34
|
+
if (HEX_RE.test(value)) from = value;
|
|
35
|
+
onchange(build());
|
|
14
36
|
}
|
|
15
37
|
|
|
16
|
-
function
|
|
17
|
-
|
|
18
|
-
onchange(input.value);
|
|
38
|
+
function pickerValue(candidate: string): string {
|
|
39
|
+
return candidate.startsWith('#') && candidate.length <= 7 ? candidate : '#000000';
|
|
19
40
|
}
|
|
20
41
|
</script>
|
|
21
42
|
|
|
@@ -23,27 +44,52 @@
|
|
|
23
44
|
<div class="label-row">
|
|
24
45
|
<label for={title}>{title}</label>
|
|
25
46
|
</div>
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
<div class="swatch" style="background: {value}">
|
|
36
|
-
<div class="checker"></div>
|
|
37
|
-
</div>
|
|
47
|
+
|
|
48
|
+
{#if allowGradient}
|
|
49
|
+
<div class="mode">
|
|
50
|
+
<button type="button" class="mode__btn" class:mode__btn--active={!gradient} onclick={setSolid}>
|
|
51
|
+
Solid
|
|
52
|
+
</button>
|
|
53
|
+
<button type="button" class="mode__btn" class:mode__btn--active={gradient} onclick={setGradient}>
|
|
54
|
+
Gradient
|
|
55
|
+
</button>
|
|
38
56
|
</div>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
57
|
+
{/if}
|
|
58
|
+
|
|
59
|
+
{#if allowGradient && gradient}
|
|
60
|
+
<div class="preview" style="background-image: {value};"></div>
|
|
61
|
+
<div class="grad-row">
|
|
62
|
+
<span class="swatch-wrapper">
|
|
63
|
+
<input type="color" value={pickerValue(from)} oninput={(e) => { from = e.currentTarget.value; onpreview?.(build()); }} onchange={(e) => { from = e.currentTarget.value; onchange(build()); }} />
|
|
64
|
+
<span class="swatch" style="background: {from}"></span>
|
|
65
|
+
</span>
|
|
66
|
+
<span class="grad-lbl">From</span>
|
|
67
|
+
<span class="grad-val">{from}</span>
|
|
68
|
+
</div>
|
|
69
|
+
<div class="grad-row">
|
|
70
|
+
<span class="swatch-wrapper">
|
|
71
|
+
<input type="color" value={pickerValue(to)} oninput={(e) => { to = e.currentTarget.value; onpreview?.(build()); }} onchange={(e) => { to = e.currentTarget.value; onchange(build()); }} />
|
|
72
|
+
<span class="swatch" style="background: {to}"></span>
|
|
73
|
+
</span>
|
|
74
|
+
<span class="grad-lbl">To</span>
|
|
75
|
+
<span class="grad-val">{to}</span>
|
|
76
|
+
</div>
|
|
77
|
+
<div class="grad-row">
|
|
78
|
+
<span class="grad-lbl">Angle</span>
|
|
79
|
+
<input class="range" type="range" min="0" max="360" value={angle} oninput={(e) => { angle = Number(e.currentTarget.value); onpreview?.(build()); }} onchange={(e) => { angle = Number(e.currentTarget.value); onchange(build()); }} />
|
|
80
|
+
<span class="grad-val">{angle}°</span>
|
|
81
|
+
</div>
|
|
82
|
+
<textarea class="custom" spellcheck="false" rows="2" placeholder="linear-gradient(90deg, #E0AE5A, #FFFFFF)" {value} onchange={(e) => onchange(e.currentTarget.value)}></textarea>
|
|
83
|
+
{:else}
|
|
84
|
+
<div class="color-row">
|
|
85
|
+
<span class="swatch-wrapper">
|
|
86
|
+
<input type="color" value={pickerValue(value)} oninput={(e) => onpreview?.(e.currentTarget.value)} onchange={(e) => onchange(e.currentTarget.value)} />
|
|
87
|
+
<span class="swatch" style="background: {value}"><span class="checker"></span></span>
|
|
88
|
+
</span>
|
|
89
|
+
<span class="hash">#</span>
|
|
90
|
+
<input type="text" class="color-text-input" value={value.replace(/^#/, '')} onchange={(e) => onchange(`#${e.currentTarget.value.replace(/^#/, '')}`)} placeholder="FFFFFF" />
|
|
91
|
+
</div>
|
|
92
|
+
{/if}
|
|
47
93
|
</div>
|
|
48
94
|
|
|
49
95
|
<style>
|
|
@@ -64,13 +110,41 @@
|
|
|
64
110
|
font-size: 0.8rem;
|
|
65
111
|
font-weight: 500;
|
|
66
112
|
color: var(--text-secondary);
|
|
67
|
-
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.mode {
|
|
116
|
+
display: flex;
|
|
117
|
+
gap: 3px;
|
|
118
|
+
padding: 3px;
|
|
119
|
+
background: var(--bg-elevated);
|
|
120
|
+
border: 1px solid var(--border-light);
|
|
121
|
+
border-radius: var(--radius-md);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.mode__btn {
|
|
125
|
+
flex: 1;
|
|
126
|
+
height: 30px;
|
|
127
|
+
border: none;
|
|
128
|
+
background: transparent;
|
|
129
|
+
border-radius: 6px;
|
|
130
|
+
cursor: pointer;
|
|
131
|
+
font: inherit;
|
|
132
|
+
font-size: 0.8rem;
|
|
133
|
+
font-weight: 600;
|
|
134
|
+
color: var(--text-secondary);
|
|
135
|
+
transition: background var(--transition), color var(--transition);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.mode__btn--active {
|
|
139
|
+
background: var(--bg-surface);
|
|
140
|
+
color: var(--accent);
|
|
141
|
+
box-shadow: var(--shadow-sm);
|
|
68
142
|
}
|
|
69
143
|
|
|
70
144
|
.color-row {
|
|
71
145
|
display: flex;
|
|
72
146
|
align-items: center;
|
|
73
|
-
gap:
|
|
147
|
+
gap: 8px;
|
|
74
148
|
background: var(--bg-elevated);
|
|
75
149
|
border: 1px solid var(--border-light);
|
|
76
150
|
border-radius: var(--radius-md);
|
|
@@ -85,9 +159,9 @@
|
|
|
85
159
|
|
|
86
160
|
.swatch-wrapper {
|
|
87
161
|
position: relative;
|
|
88
|
-
width:
|
|
89
|
-
height:
|
|
90
|
-
border-radius:
|
|
162
|
+
width: 24px;
|
|
163
|
+
height: 24px;
|
|
164
|
+
border-radius: 6px;
|
|
91
165
|
overflow: hidden;
|
|
92
166
|
flex-shrink: 0;
|
|
93
167
|
border: 1px solid var(--border-light);
|
|
@@ -122,20 +196,75 @@
|
|
|
122
196
|
background-size: 8px 8px;
|
|
123
197
|
}
|
|
124
198
|
|
|
199
|
+
.hash {
|
|
200
|
+
font-family: var(--font-mono);
|
|
201
|
+
font-size: 0.8rem;
|
|
202
|
+
color: var(--text-muted);
|
|
203
|
+
}
|
|
204
|
+
|
|
125
205
|
.color-text-input {
|
|
126
206
|
flex: 1;
|
|
127
207
|
min-width: 0;
|
|
128
208
|
background: none;
|
|
129
209
|
border: none;
|
|
130
210
|
outline: none;
|
|
131
|
-
font-size: 0.
|
|
211
|
+
font-size: 0.8rem;
|
|
132
212
|
font-family: var(--font-mono);
|
|
133
|
-
color: var(--text-
|
|
213
|
+
color: var(--text-primary);
|
|
134
214
|
letter-spacing: 0.04em;
|
|
215
|
+
text-transform: uppercase;
|
|
135
216
|
padding: 0;
|
|
136
217
|
}
|
|
137
218
|
|
|
138
|
-
.
|
|
139
|
-
|
|
219
|
+
.preview {
|
|
220
|
+
height: 44px;
|
|
221
|
+
border-radius: var(--radius-md);
|
|
222
|
+
box-shadow: inset 0 0 0 1px var(--border);
|
|
223
|
+
background-size: cover;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.grad-row {
|
|
227
|
+
display: flex;
|
|
228
|
+
align-items: center;
|
|
229
|
+
gap: 9px;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.grad-lbl {
|
|
233
|
+
font-size: 0.75rem;
|
|
234
|
+
color: var(--text-secondary);
|
|
235
|
+
width: 38px;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.grad-val {
|
|
239
|
+
flex: 1;
|
|
240
|
+
text-align: right;
|
|
241
|
+
font-family: var(--font-mono);
|
|
242
|
+
font-size: 0.72rem;
|
|
243
|
+
text-transform: uppercase;
|
|
244
|
+
color: var(--text-secondary);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.range {
|
|
248
|
+
flex: 1;
|
|
249
|
+
accent-color: var(--accent);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.custom {
|
|
253
|
+
width: 100%;
|
|
254
|
+
resize: vertical;
|
|
255
|
+
min-height: 44px;
|
|
256
|
+
padding: 8px 10px;
|
|
257
|
+
font-family: var(--font-mono);
|
|
258
|
+
font-size: 0.7rem;
|
|
259
|
+
line-height: 1.4;
|
|
260
|
+
color: var(--text-primary);
|
|
261
|
+
background: var(--bg-elevated);
|
|
262
|
+
border: 1px solid var(--border-light);
|
|
263
|
+
border-radius: var(--radius-md);
|
|
264
|
+
outline: none;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.custom:focus {
|
|
268
|
+
border-color: var(--accent);
|
|
140
269
|
}
|
|
141
270
|
</style>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { BaseSettingProps } from '../types';
|
|
2
|
-
|
|
1
|
+
import type { BaseSettingProps, ColorExtra } from '../types';
|
|
2
|
+
type $$ComponentProps = BaseSettingProps<string> & ColorExtra;
|
|
3
|
+
declare const ColorSettings: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
3
4
|
type ColorSettings = ReturnType<typeof ColorSettings>;
|
|
4
5
|
export default ColorSettings;
|
|
@@ -78,7 +78,6 @@
|
|
|
78
78
|
font-size: 0.8rem;
|
|
79
79
|
font-weight: 500;
|
|
80
80
|
color: var(--text-secondary);
|
|
81
|
-
text-transform: capitalize;
|
|
82
81
|
}
|
|
83
82
|
|
|
84
83
|
.list-items {
|
|
@@ -128,12 +127,12 @@
|
|
|
128
127
|
input,
|
|
129
128
|
textarea {
|
|
130
129
|
width: 100%;
|
|
131
|
-
padding:
|
|
130
|
+
padding: 9px 11px;
|
|
132
131
|
background: var(--bg-base, #1a1a2e);
|
|
133
132
|
border: 1px solid var(--border-light);
|
|
134
133
|
border-radius: var(--radius-md);
|
|
135
134
|
color: var(--text-primary);
|
|
136
|
-
font-size: 0.
|
|
135
|
+
font-size: 0.8rem;
|
|
137
136
|
font-family: var(--font);
|
|
138
137
|
outline: none;
|
|
139
138
|
resize: vertical;
|
|
@@ -149,12 +148,12 @@
|
|
|
149
148
|
}
|
|
150
149
|
|
|
151
150
|
.add-btn {
|
|
152
|
-
padding:
|
|
151
|
+
padding: 9px 11px;
|
|
153
152
|
background: var(--bg-elevated);
|
|
154
153
|
border: 1px dashed var(--border-light);
|
|
155
154
|
border-radius: var(--radius-md);
|
|
156
155
|
color: var(--text-secondary);
|
|
157
|
-
font-size: 0.
|
|
156
|
+
font-size: 0.8rem;
|
|
158
157
|
cursor: pointer;
|
|
159
158
|
transition: all 0.15s;
|
|
160
159
|
}
|
|
@@ -1,21 +1,52 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { BaseSettingProps, NumberExtra } from '../types';
|
|
3
3
|
|
|
4
|
-
let { title, value, onchange, min, max, step }: BaseSettingProps<number> & NumberExtra =
|
|
4
|
+
let { title, value, onchange, onpreview, min, max, step }: BaseSettingProps<number> & NumberExtra =
|
|
5
|
+
$props();
|
|
6
|
+
|
|
7
|
+
const hasRange = $derived(min !== undefined && max !== undefined);
|
|
5
8
|
</script>
|
|
6
9
|
|
|
7
10
|
<div class="setting-item">
|
|
8
11
|
<div class="label-row">
|
|
9
12
|
<label for={title}>{title}</label>
|
|
10
13
|
</div>
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
|
|
15
|
+
{#if hasRange}
|
|
16
|
+
<div class="number-slider">
|
|
17
|
+
<input
|
|
18
|
+
class="range"
|
|
19
|
+
type="range"
|
|
20
|
+
{min}
|
|
21
|
+
{max}
|
|
22
|
+
step={step ?? 1}
|
|
23
|
+
{value}
|
|
24
|
+
oninput={(e) => onpreview?.(Number(e.currentTarget.value))}
|
|
25
|
+
onchange={(e) => onchange(Number(e.currentTarget.value))}
|
|
26
|
+
/>
|
|
27
|
+
<div class="number-box">
|
|
28
|
+
<input
|
|
29
|
+
type="number"
|
|
30
|
+
{min}
|
|
31
|
+
{max}
|
|
32
|
+
{step}
|
|
33
|
+
{value}
|
|
34
|
+
onchange={(e) => onchange(Number(e.currentTarget.value))}
|
|
35
|
+
/>
|
|
36
|
+
<span class="number-unit">px</span>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
{:else}
|
|
40
|
+
<input
|
|
41
|
+
class="number-plain"
|
|
42
|
+
type="number"
|
|
43
|
+
{value}
|
|
44
|
+
{min}
|
|
45
|
+
{max}
|
|
46
|
+
{step}
|
|
47
|
+
onchange={(e) => onchange(Number(e.currentTarget.value))}
|
|
48
|
+
/>
|
|
49
|
+
{/if}
|
|
19
50
|
</div>
|
|
20
51
|
|
|
21
52
|
<style>
|
|
@@ -36,17 +67,89 @@
|
|
|
36
67
|
font-size: 0.8rem;
|
|
37
68
|
font-weight: 500;
|
|
38
69
|
color: var(--text-secondary);
|
|
39
|
-
text-transform: capitalize;
|
|
40
70
|
}
|
|
41
71
|
|
|
42
|
-
|
|
72
|
+
.number-slider {
|
|
73
|
+
display: flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
gap: 12px;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.range {
|
|
79
|
+
flex: 1;
|
|
80
|
+
-webkit-appearance: none;
|
|
81
|
+
appearance: none;
|
|
82
|
+
height: 4px;
|
|
83
|
+
border-radius: 999px;
|
|
84
|
+
background: var(--bg-hover);
|
|
85
|
+
outline: none;
|
|
86
|
+
cursor: pointer;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.range::-webkit-slider-thumb {
|
|
90
|
+
-webkit-appearance: none;
|
|
91
|
+
appearance: none;
|
|
92
|
+
width: 16px;
|
|
93
|
+
height: 16px;
|
|
94
|
+
border-radius: 50%;
|
|
95
|
+
background: var(--accent);
|
|
96
|
+
cursor: pointer;
|
|
97
|
+
border: 2px solid var(--bg-surface);
|
|
98
|
+
box-shadow: var(--shadow-sm);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.range::-moz-range-thumb {
|
|
102
|
+
width: 16px;
|
|
103
|
+
height: 16px;
|
|
104
|
+
border-radius: 50%;
|
|
105
|
+
background: var(--accent);
|
|
106
|
+
cursor: pointer;
|
|
107
|
+
border: 2px solid var(--bg-surface);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.number-box {
|
|
111
|
+
display: flex;
|
|
112
|
+
align-items: center;
|
|
113
|
+
gap: 4px;
|
|
114
|
+
width: 92px;
|
|
115
|
+
flex: none;
|
|
116
|
+
padding: 0 11px;
|
|
117
|
+
background: var(--bg-elevated);
|
|
118
|
+
border: 1px solid var(--border-light);
|
|
119
|
+
border-radius: var(--radius-md);
|
|
120
|
+
transition: border-color var(--transition);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.number-box:focus-within {
|
|
124
|
+
border-color: var(--accent);
|
|
125
|
+
box-shadow: 0 0 0 3px var(--accent-glow);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.number-box input {
|
|
43
129
|
width: 100%;
|
|
44
|
-
|
|
130
|
+
height: 36px;
|
|
131
|
+
border: none;
|
|
132
|
+
background: transparent;
|
|
133
|
+
outline: none;
|
|
134
|
+
text-align: right;
|
|
135
|
+
font: inherit;
|
|
136
|
+
font-size: 0.8rem;
|
|
137
|
+
color: var(--text-primary);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.number-unit {
|
|
141
|
+
font-size: 0.75rem;
|
|
142
|
+
color: var(--text-muted);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.number-plain {
|
|
146
|
+
width: 100%;
|
|
147
|
+
padding: 9px 11px;
|
|
45
148
|
background: var(--bg-elevated);
|
|
46
149
|
border: 1px solid var(--border-light);
|
|
47
150
|
border-radius: var(--radius-md);
|
|
48
151
|
color: var(--text-primary);
|
|
49
|
-
font-size: 0.
|
|
152
|
+
font-size: 0.8rem;
|
|
50
153
|
font-family: var(--font);
|
|
51
154
|
outline: none;
|
|
52
155
|
transition:
|
|
@@ -54,13 +157,7 @@
|
|
|
54
157
|
box-shadow var(--transition);
|
|
55
158
|
}
|
|
56
159
|
|
|
57
|
-
|
|
58
|
-
input[type='number']::-webkit-outer-spin-button {
|
|
59
|
-
opacity: 0.4;
|
|
60
|
-
filter: invert(1);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
input[type='number']:focus {
|
|
160
|
+
.number-plain:focus {
|
|
64
161
|
border-color: var(--accent);
|
|
65
162
|
box-shadow: 0 0 0 3px var(--accent-glow);
|
|
66
163
|
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Settings } from '../base.svelte';
|
|
3
|
+
import type { SettingMap } from '../types';
|
|
4
|
+
import SettingsRenderer from './SettingsRenderer.svelte';
|
|
5
|
+
|
|
6
|
+
interface RepeaterProps {
|
|
7
|
+
title: string;
|
|
8
|
+
itemLabel: string;
|
|
9
|
+
addButtonText: string;
|
|
10
|
+
items: Settings<SettingMap>[];
|
|
11
|
+
onadd: () => void;
|
|
12
|
+
onremove: (index: number) => void;
|
|
13
|
+
onmove: (from: number, to: number) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let { title, itemLabel, addButtonText, items, onadd, onremove, onmove }: RepeaterProps = $props();
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<div class="repeater">
|
|
20
|
+
<div class="repeater-title">{title}</div>
|
|
21
|
+
|
|
22
|
+
{#each items as item, index (index)}
|
|
23
|
+
<div class="repeater-item">
|
|
24
|
+
<div class="repeater-item-head">
|
|
25
|
+
<span class="repeater-item-label">{itemLabel} {index + 1}</span>
|
|
26
|
+
<div class="repeater-item-actions">
|
|
27
|
+
<button
|
|
28
|
+
type="button"
|
|
29
|
+
title="Move up"
|
|
30
|
+
disabled={index === 0}
|
|
31
|
+
onclick={() => onmove(index, index - 1)}
|
|
32
|
+
>
|
|
33
|
+
↑
|
|
34
|
+
</button>
|
|
35
|
+
<button
|
|
36
|
+
type="button"
|
|
37
|
+
title="Move down"
|
|
38
|
+
disabled={index === items.length - 1}
|
|
39
|
+
onclick={() => onmove(index, index + 1)}
|
|
40
|
+
>
|
|
41
|
+
↓
|
|
42
|
+
</button>
|
|
43
|
+
<button type="button" class="remove" title="Remove" onclick={() => onremove(index)}>
|
|
44
|
+
✕
|
|
45
|
+
</button>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="repeater-item-body">
|
|
49
|
+
<SettingsRenderer entries={item.entries} />
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
{/each}
|
|
53
|
+
|
|
54
|
+
<button type="button" class="repeater-add" onclick={onadd}>{addButtonText}</button>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<style>
|
|
58
|
+
.repeater {
|
|
59
|
+
display: flex;
|
|
60
|
+
flex-direction: column;
|
|
61
|
+
gap: 10px;
|
|
62
|
+
padding: 12px 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.repeater-title {
|
|
66
|
+
font-size: 0.72rem;
|
|
67
|
+
font-weight: 600;
|
|
68
|
+
color: var(--text-secondary);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.repeater-item {
|
|
72
|
+
border: 1px solid var(--border-light);
|
|
73
|
+
border-radius: var(--radius-md);
|
|
74
|
+
background: var(--bg-surface);
|
|
75
|
+
overflow: hidden;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.repeater-item-head {
|
|
79
|
+
display: flex;
|
|
80
|
+
align-items: center;
|
|
81
|
+
justify-content: space-between;
|
|
82
|
+
padding: 8px 10px;
|
|
83
|
+
background: var(--bg-elevated);
|
|
84
|
+
border-bottom: 1px solid var(--border-light);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.repeater-item-label {
|
|
88
|
+
font-size: 0.72rem;
|
|
89
|
+
font-weight: 700;
|
|
90
|
+
letter-spacing: 0.06em;
|
|
91
|
+
text-transform: uppercase;
|
|
92
|
+
color: var(--text-secondary);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.repeater-item-actions {
|
|
96
|
+
display: flex;
|
|
97
|
+
gap: 4px;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.repeater-item-actions button {
|
|
101
|
+
width: 24px;
|
|
102
|
+
height: 22px;
|
|
103
|
+
display: inline-flex;
|
|
104
|
+
align-items: center;
|
|
105
|
+
justify-content: center;
|
|
106
|
+
border: 1px solid var(--border-light);
|
|
107
|
+
background: var(--bg-surface);
|
|
108
|
+
border-radius: var(--radius-sm);
|
|
109
|
+
color: var(--text-secondary);
|
|
110
|
+
cursor: pointer;
|
|
111
|
+
font-size: 0.7rem;
|
|
112
|
+
line-height: 1;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.repeater-item-actions button:disabled {
|
|
116
|
+
opacity: 0.35;
|
|
117
|
+
cursor: not-allowed;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.repeater-item-actions .remove:hover:not(:disabled) {
|
|
121
|
+
color: #e5484d;
|
|
122
|
+
border-color: #e5484d;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.repeater-item-body {
|
|
126
|
+
padding: 4px 10px 10px;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.repeater-add {
|
|
130
|
+
height: 36px;
|
|
131
|
+
border: 1px dashed var(--border);
|
|
132
|
+
background: var(--bg-elevated);
|
|
133
|
+
border-radius: var(--radius-md);
|
|
134
|
+
color: var(--text-secondary);
|
|
135
|
+
font-size: 0.72rem;
|
|
136
|
+
font-weight: 600;
|
|
137
|
+
cursor: pointer;
|
|
138
|
+
transition: border-color var(--transition), color var(--transition);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.repeater-add:hover {
|
|
142
|
+
border-color: var(--accent);
|
|
143
|
+
color: var(--accent);
|
|
144
|
+
}
|
|
145
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Settings } from '../base.svelte';
|
|
2
|
+
import type { SettingMap } from '../types';
|
|
3
|
+
interface RepeaterProps {
|
|
4
|
+
title: string;
|
|
5
|
+
itemLabel: string;
|
|
6
|
+
addButtonText: string;
|
|
7
|
+
items: Settings<SettingMap>[];
|
|
8
|
+
onadd: () => void;
|
|
9
|
+
onremove: (index: number) => void;
|
|
10
|
+
onmove: (from: number, to: number) => void;
|
|
11
|
+
}
|
|
12
|
+
declare const RepeaterSettings: import("svelte").Component<RepeaterProps, {}, "">;
|
|
13
|
+
type RepeaterSettings = ReturnType<typeof RepeaterSettings>;
|
|
14
|
+
export default RepeaterSettings;
|