poe-svelte-ui-lib 1.26.3 → 1.28.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.
- package/dist/Accordion/AccordionProps.svelte +1 -1
- package/dist/Button/Button.svelte +2 -2
- package/dist/CommonSnippets.svelte +2 -2
- package/dist/FileAttach/FileAttach.svelte +2 -2
- package/dist/Input/Input.svelte +3 -3
- package/dist/Map/Map.svelte +12 -2
- package/dist/Map/MapProps.svelte +8 -0
- package/dist/PeriodChart/PeriodChartProps.svelte +22 -22
- package/dist/ProgressBar/ProgressBarProps.svelte +23 -23
- package/dist/Select/Select.svelte +2 -2
- package/dist/Select/SelectProps.svelte +23 -23
- package/dist/Switch/SwitchProps.svelte +11 -14
- package/dist/Table/TableProps.svelte +29 -30
- package/dist/Tabs/TabsProps.svelte +28 -28
- package/dist/VideoViewer/VideoViewer.svelte +8 -1
- package/dist/VideoViewer/VideoViewerProps.svelte +9 -0
- package/dist/Widget/WidgetProps.svelte +12 -18
- package/dist/WidgetHeader.svelte +7 -5
- package/dist/WidgetWiFi/WidgetWiFi.svelte +1 -1
- package/dist/options.js +5 -4
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Что изменилось внутри:
|
|
4
4
|
• роль определяется значением bg-* (намерение), а не фактом его наличия;
|
|
5
5
|
• убрано автоподчёркивание текста — кнопка больше не выглядит ссылкой;
|
|
6
|
-
• единый радиус 10px (иконка без подписи — круг), высота
|
|
6
|
+
• единый радиус 10px (иконка без подписи — круг), высота 32px (стандарт полей h-8), кегль 14/600;
|
|
7
7
|
• кольцо фокуса вместо размытой тени;
|
|
8
8
|
• disabled через токены, а не opacity: 0.5;
|
|
9
9
|
• иконка встала в поток (flex + gap) вместо absolute left-3. -->
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
`relative inline-flex w-full items-center justify-center gap-2 leading-none font-semibold text-[14px] select-none
|
|
109
109
|
transition-[background-color,filter,box-shadow] duration-150
|
|
110
110
|
focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--accent-color)
|
|
111
|
-
${isIconOnly ? "aspect-square rounded-full p-0" : "
|
|
111
|
+
${isIconOnly ? "aspect-square rounded-full p-0" : "h-8 rounded-[10px] px-4 py-2"}
|
|
112
112
|
${disabled ? "" : "cursor-pointer active:scale-[0.97]"}`,
|
|
113
113
|
roleClass,
|
|
114
114
|
componentClass,
|
|
@@ -257,7 +257,7 @@
|
|
|
257
257
|
updateProperty: (icon: string | string[]) => {}
|
|
258
258
|
})}
|
|
259
259
|
<div class="relative mt-6 flex w-full gap-2">
|
|
260
|
-
<UI.Button content={{ name: initialValue.name }} componentClass="
|
|
260
|
+
<UI.Button content={{ name: initialValue.name }} componentClass="bg-blue" onClick={() => (showIconLib = true)} />
|
|
261
261
|
{#if showIconLib}
|
|
262
262
|
<UI.Modal bind:isOpen={showIconLib} wrapperClass="w-130">
|
|
263
263
|
{#snippet main()}
|
|
@@ -288,7 +288,7 @@
|
|
|
288
288
|
</UI.Modal>
|
|
289
289
|
{/if}
|
|
290
290
|
{#if initialValue.icon}
|
|
291
|
-
<UI.Button wrapperClass="w-8
|
|
291
|
+
<UI.Button wrapperClass="w-8" componentClass="p-0.5 bg-red" content={{ icon: CrossIcon }} onClick={() => initialValue.updateProperty("")} />
|
|
292
292
|
{/if}
|
|
293
293
|
</div>
|
|
294
294
|
{/snippet}
|
|
@@ -82,13 +82,13 @@
|
|
|
82
82
|
<input
|
|
83
83
|
id={ID}
|
|
84
84
|
type="file"
|
|
85
|
-
class="absolute left-0 z-1 h-
|
|
85
|
+
class="absolute left-0 z-1 h-8 w-full opacity-0 {disabled ? 'cursor-not-allowed' : 'cursor-pointer'}"
|
|
86
86
|
{accept}
|
|
87
87
|
{disabled}
|
|
88
88
|
onchange={handleFileChange}
|
|
89
89
|
/>
|
|
90
90
|
<div
|
|
91
|
-
class="flex h-
|
|
91
|
+
class="flex h-8 w-full overflow-hidden rounded-[10px] border border-(--border-color) text-[14px] transition-colors duration-150
|
|
92
92
|
{disabled ? 'opacity-45' : 'hover:border-(--faint-color)'}"
|
|
93
93
|
>
|
|
94
94
|
<div class="flex shrink-0 items-center justify-center bg-(--accent-color) px-3 font-semibold whitespace-nowrap text-(--on-accent)">
|
package/dist/Input/Input.svelte
CHANGED
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
{#if type === "number"}
|
|
93
93
|
<input
|
|
94
94
|
bind:value
|
|
95
|
-
class={twMerge(fieldBase, "h-
|
|
95
|
+
class={twMerge(fieldBase, "h-8 pr-9", componentClass)}
|
|
96
96
|
id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
|
|
97
97
|
{placeholder}
|
|
98
98
|
{disabled}
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
{:else if type !== "text-area"}
|
|
110
110
|
<input
|
|
111
111
|
bind:value
|
|
112
|
-
class={twMerge(fieldBase, `h-
|
|
112
|
+
class={twMerge(fieldBase, `h-8 ${help.copyButton || type === "password" ? "pr-9" : ""}`, componentClass)}
|
|
113
113
|
id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
|
|
114
114
|
{placeholder}
|
|
115
115
|
{disabled}
|
|
@@ -190,7 +190,7 @@
|
|
|
190
190
|
|
|
191
191
|
{#if (type === "number" || type === "bitMode") && !readonly && !disabled}
|
|
192
192
|
<!-- Счётчик: узкая колонка со стрелками, отделена волосяной линией -->
|
|
193
|
-
<div class="absolute right-0 flex h-
|
|
193
|
+
<div class="absolute right-0 flex h-8 w-8 flex-col overflow-hidden rounded-r-[10px] border-l border-(--hairline-color)">
|
|
194
194
|
<button
|
|
195
195
|
class="flex h-1/2 w-full items-center justify-center border-b border-(--hairline-color) text-[11px] leading-none text-(--muted-color) transition-colors duration-150 hover:bg-(--container-color) hover:text-(--font-color)"
|
|
196
196
|
onclick={() => {
|
package/dist/Map/Map.svelte
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
let {
|
|
10
10
|
id = crypto.randomUUID(),
|
|
11
|
+
wrapperClass = "",
|
|
11
12
|
label = { name: "", class: "" },
|
|
12
13
|
data = $bindable(),
|
|
13
14
|
markerIcon,
|
|
@@ -15,6 +16,15 @@
|
|
|
15
16
|
trackLength = $bindable(1000),
|
|
16
17
|
}: IMapProps = $props()
|
|
17
18
|
|
|
19
|
+
/* Мастер-цвет (тот же bg-* из optionsStore.COLOR_OPTIONS, что и у остальных примитивов) —
|
|
20
|
+
проявляется как акцентная рамка карты, т.к. заливать фон самой карты цветом нет смысла. */
|
|
21
|
+
const roleBorderClass = $derived.by(() => {
|
|
22
|
+
const role = wrapperClass.match(/bg-(\w+)/)?.[1]
|
|
23
|
+
/* border-(--border-color) — реальная utility, красящая рамку; border-{role} лишь задаёт
|
|
24
|
+
переменную --border-color (см. app.css), как и bg-* для --bg-color (см. Button.svelte). */
|
|
25
|
+
return role && role !== "max" ? `border-2 border-(--border-color) border-${role}` : ""
|
|
26
|
+
})
|
|
27
|
+
|
|
18
28
|
interface MapDevice extends IDeviceGNSS {
|
|
19
29
|
isFresh: boolean
|
|
20
30
|
staleTimeoutId: number | null
|
|
@@ -131,12 +141,12 @@
|
|
|
131
141
|
}
|
|
132
142
|
</script>
|
|
133
143
|
|
|
134
|
-
<div id={`${id}-${crypto.randomUUID().slice(0, 6)}`} class="h-full min-h-50">
|
|
144
|
+
<div id={`${id}-${crypto.randomUUID().slice(0, 6)}`} class={twMerge("h-full min-h-50", wrapperClass)}>
|
|
135
145
|
{#if label.name}
|
|
136
146
|
<h5 class={twMerge(` w-full px-4 text-center`, label.class)}>{label.name}</h5>
|
|
137
147
|
{/if}
|
|
138
148
|
<MapLibre
|
|
139
|
-
class="h-[calc(100%-2rem)] min-h-50 overflow-hidden rounded-xl shadow-sm transition duration-200 hover:shadow-md"
|
|
149
|
+
class={twMerge("h-[calc(100%-2rem)] min-h-50 overflow-hidden rounded-xl shadow-sm transition duration-200 hover:shadow-md", roleBorderClass)}
|
|
140
150
|
style={isDarkMode ? "https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json" : "https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json"}
|
|
141
151
|
zoom={1.5}
|
|
142
152
|
center={{ lat: 30, lng: 0 }}
|
package/dist/Map/MapProps.svelte
CHANGED
|
@@ -28,6 +28,12 @@
|
|
|
28
28
|
(a.value as string).includes(component.properties.label?.class?.split(" ").find((cls: string) => cls.startsWith("text-"))),
|
|
29
29
|
),
|
|
30
30
|
)
|
|
31
|
+
|
|
32
|
+
const initialColor = $derived(
|
|
33
|
+
$optionsStore.COLOR_OPTIONS.find((c) =>
|
|
34
|
+
(c.value as string).includes(component.properties.wrapperClass?.split(" ").find((cls: string) => cls.startsWith("bg-"))),
|
|
35
|
+
),
|
|
36
|
+
)
|
|
31
37
|
</script>
|
|
32
38
|
|
|
33
39
|
{#if forConstructor}
|
|
@@ -67,6 +73,7 @@
|
|
|
67
73
|
onUpdate={(option) => updateProperty("trackLength", (option as { value: number }).value, component, onPropertyChange)}
|
|
68
74
|
/>
|
|
69
75
|
{/if}
|
|
76
|
+
<CommonSnippets snippet="Colors" initialValue={{ color: initialColor }} {component} {onPropertyChange} />
|
|
70
77
|
</PropsGroup>
|
|
71
78
|
</div>
|
|
72
79
|
{:else}
|
|
@@ -106,6 +113,7 @@
|
|
|
106
113
|
onUpdate={(option) => updateProperty("trackLength", (option as { value: number }).value, component, onPropertyChange)}
|
|
107
114
|
/>
|
|
108
115
|
{/if}
|
|
116
|
+
<CommonSnippets snippet="Colors" initialValue={{ color: initialColor }} {component} {onPropertyChange} />
|
|
109
117
|
</PropsGroup>
|
|
110
118
|
</div>
|
|
111
119
|
{/if}
|
|
@@ -77,28 +77,17 @@
|
|
|
77
77
|
|
|
78
78
|
<div bind:this={itemsContainer} class="flex flex-col gap-2">
|
|
79
79
|
{#each component.properties.levels || [] as level, index}
|
|
80
|
-
<div
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
<UI.Button
|
|
92
|
-
wrapperClass="w-8 shrink-0"
|
|
93
|
-
content={{ icon: ButtonDelete }}
|
|
94
|
-
onClick={() => {
|
|
95
|
-
const levels = [...(component.properties?.levels || [])]
|
|
96
|
-
levels.splice(index, 1)
|
|
97
|
-
updateLevels(levels)
|
|
98
|
-
}}
|
|
99
|
-
/>
|
|
100
|
-
{/if}
|
|
101
|
-
</div>
|
|
80
|
+
<div
|
|
81
|
+
id="item-{index}"
|
|
82
|
+
class="grid grid-cols-[auto_1fr_auto] items-center gap-2 rounded-lg border border-(--hairline-color) bg-(--container-color)/60 p-2"
|
|
83
|
+
>
|
|
84
|
+
<UI.Dragging
|
|
85
|
+
wrapperClass="shrink-0"
|
|
86
|
+
container={itemsContainer}
|
|
87
|
+
array={component.properties.levels}
|
|
88
|
+
elementIndex={index}
|
|
89
|
+
onUpdate={(updatedArray) => updateLevels(updatedArray)}
|
|
90
|
+
/>
|
|
102
91
|
<div class="flex flex-wrap items-end gap-2">
|
|
103
92
|
<UI.Input
|
|
104
93
|
label={{ name: $T("constructor.props.optionname") }}
|
|
@@ -143,6 +132,17 @@
|
|
|
143
132
|
}}
|
|
144
133
|
/>
|
|
145
134
|
</div>
|
|
135
|
+
{#if (component.properties.levels?.length ?? 0) > 1}
|
|
136
|
+
<UI.Button
|
|
137
|
+
wrapperClass="w-8 shrink-0"
|
|
138
|
+
content={{ icon: ButtonDelete }}
|
|
139
|
+
onClick={() => {
|
|
140
|
+
const levels = [...(component.properties?.levels || [])]
|
|
141
|
+
levels.splice(index, 1)
|
|
142
|
+
updateLevels(levels)
|
|
143
|
+
}}
|
|
144
|
+
/>
|
|
145
|
+
{/if}
|
|
146
146
|
</div>
|
|
147
147
|
{/each}
|
|
148
148
|
<div id="item-{component.properties.levels?.length ?? 0}" class="min-h-4"></div>
|
|
@@ -74,28 +74,19 @@
|
|
|
74
74
|
|
|
75
75
|
<div bind:this={itemsContainer} class="flex flex-col gap-2">
|
|
76
76
|
{#each component.properties.items || [] as progress, index}
|
|
77
|
-
<div
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
wrapperClass="w-8 shrink-0"
|
|
91
|
-
content={{ icon: ButtonDelete }}
|
|
92
|
-
onClick={() => {
|
|
93
|
-
const progresses = [...(component.properties?.items || [])]
|
|
94
|
-
progresses.splice(index, 1)
|
|
95
|
-
updateProperty("items", progresses, component, onPropertyChange)
|
|
96
|
-
}}
|
|
97
|
-
/>
|
|
98
|
-
</div>
|
|
77
|
+
<div
|
|
78
|
+
id="item-{index}"
|
|
79
|
+
class="grid grid-cols-[auto_1fr_auto] items-center gap-2 rounded-lg border border-(--hairline-color) bg-(--container-color)/60 p-2"
|
|
80
|
+
>
|
|
81
|
+
<UI.Dragging
|
|
82
|
+
wrapperClass="shrink-0"
|
|
83
|
+
container={itemsContainer}
|
|
84
|
+
array={component.properties.items}
|
|
85
|
+
elementIndex={index}
|
|
86
|
+
onUpdate={(updatedArray) => {
|
|
87
|
+
updateProperty("items", updatedArray, component, onPropertyChange)
|
|
88
|
+
}}
|
|
89
|
+
/>
|
|
99
90
|
<div class="flex flex-wrap items-end gap-2">
|
|
100
91
|
<UI.Input
|
|
101
92
|
label={{ name: $T("constructor.props.optionname") }}
|
|
@@ -110,7 +101,7 @@
|
|
|
110
101
|
{#if forConstructor}
|
|
111
102
|
<UI.Select
|
|
112
103
|
label={{ name: $T("constructor.props.colors") }}
|
|
113
|
-
wrapperClass="min-w-56 flex-[2]
|
|
104
|
+
wrapperClass="min-w-56 flex-[2]"
|
|
114
105
|
type="buttons"
|
|
115
106
|
options={$optionsStore.COLOR_OPTIONS.filter((option) => option.value !== "bg-max")}
|
|
116
107
|
value={$optionsStore.COLOR_OPTIONS.find((c) =>
|
|
@@ -154,6 +145,15 @@
|
|
|
154
145
|
/>
|
|
155
146
|
{/if}
|
|
156
147
|
</div>
|
|
148
|
+
<UI.Button
|
|
149
|
+
wrapperClass="w-8 shrink-0"
|
|
150
|
+
content={{ icon: ButtonDelete }}
|
|
151
|
+
onClick={() => {
|
|
152
|
+
const progresses = [...(component.properties?.items || [])]
|
|
153
|
+
progresses.splice(index, 1)
|
|
154
|
+
updateProperty("items", progresses, component, onPropertyChange)
|
|
155
|
+
}}
|
|
156
|
+
/>
|
|
157
157
|
</div>
|
|
158
158
|
{/each}
|
|
159
159
|
<div id="item-{component.properties.items.length}" class="min-h-4"></div>
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
/* Общая база поля — та же, что у Input */
|
|
133
|
-
const fieldBase = `h-
|
|
133
|
+
const fieldBase = `h-8 w-full rounded-[10px] border border-(--border-color) bg-(--field-color) px-3 text-left text-[14px]
|
|
134
134
|
transition-[border-color,box-shadow] duration-150 outline-none
|
|
135
135
|
focus:border-(--accent-color) focus:shadow-(--focus-shadow-color)`
|
|
136
136
|
|
|
@@ -222,7 +222,7 @@
|
|
|
222
222
|
<button
|
|
223
223
|
id={option.id}
|
|
224
224
|
class="{twMerge(
|
|
225
|
-
`
|
|
225
|
+
`h-8 min-w-0 flex-1 px-3 py-2 text-[13px] font-semibold transition-colors duration-150
|
|
226
226
|
${index === 0 ? 'rounded-l-[9px]' : ''} ${index === options.length - 1 ? 'rounded-r-[9px]' : ''}
|
|
227
227
|
${index > 0 ? 'border-l border-(--border-color)' : ''}
|
|
228
228
|
${
|
|
@@ -191,28 +191,19 @@
|
|
|
191
191
|
|
|
192
192
|
<div bind:this={itemsContainer} class="flex flex-col gap-2">
|
|
193
193
|
{#each component.properties.options || [] as option, index (option.id)}
|
|
194
|
-
<div
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
wrapperClass="w-8 shrink-0"
|
|
208
|
-
content={{ icon: ButtonDelete }}
|
|
209
|
-
onClick={() => {
|
|
210
|
-
const options = [...(component.properties?.options || [])]
|
|
211
|
-
options.splice(index, 1)
|
|
212
|
-
updateProperty("options", options, component, onPropertyChange)
|
|
213
|
-
}}
|
|
214
|
-
/>
|
|
215
|
-
</div>
|
|
194
|
+
<div
|
|
195
|
+
id="item-{index}"
|
|
196
|
+
class="grid grid-cols-[auto_1fr_auto] items-center gap-2 rounded-lg border border-(--hairline-color) bg-(--container-color)/60 p-2"
|
|
197
|
+
>
|
|
198
|
+
<UI.Dragging
|
|
199
|
+
wrapperClass="shrink-0"
|
|
200
|
+
container={itemsContainer}
|
|
201
|
+
array={component.properties.options}
|
|
202
|
+
elementIndex={index}
|
|
203
|
+
onUpdate={(updatedArray) => {
|
|
204
|
+
updateProperty("options", updatedArray, component, onPropertyChange)
|
|
205
|
+
}}
|
|
206
|
+
/>
|
|
216
207
|
<div class="flex flex-wrap items-end gap-2">
|
|
217
208
|
<UI.Input
|
|
218
209
|
label={{ name: $T("constructor.props.optionname") }}
|
|
@@ -240,7 +231,7 @@
|
|
|
240
231
|
/>
|
|
241
232
|
{#if forConstructor}
|
|
242
233
|
<UI.Select
|
|
243
|
-
wrapperClass="min-w-56 flex-[2]
|
|
234
|
+
wrapperClass="min-w-56 flex-[2]"
|
|
244
235
|
label={{ name: $T("constructor.props.colors") }}
|
|
245
236
|
type="buttons"
|
|
246
237
|
options={$optionsStore.COLOR_OPTIONS}
|
|
@@ -266,6 +257,15 @@
|
|
|
266
257
|
/>
|
|
267
258
|
{/if}
|
|
268
259
|
</div>
|
|
260
|
+
<UI.Button
|
|
261
|
+
wrapperClass="w-8 shrink-0"
|
|
262
|
+
content={{ icon: ButtonDelete }}
|
|
263
|
+
onClick={() => {
|
|
264
|
+
const options = [...(component.properties?.options || [])]
|
|
265
|
+
options.splice(index, 1)
|
|
266
|
+
updateProperty("options", options, component, onPropertyChange)
|
|
267
|
+
}}
|
|
268
|
+
/>
|
|
269
269
|
</div>
|
|
270
270
|
{/each}
|
|
271
271
|
<div id="item-{component.properties.options.length}" class="min-h-4"></div>
|
|
@@ -109,19 +109,7 @@
|
|
|
109
109
|
{/snippet}
|
|
110
110
|
|
|
111
111
|
{#each component.properties.options || [] as option, index (option.id)}
|
|
112
|
-
<div class="
|
|
113
|
-
<div class="flex items-center gap-2">
|
|
114
|
-
<span class="flex-1"></span>
|
|
115
|
-
<UI.Button
|
|
116
|
-
wrapperClass="w-8 shrink-0"
|
|
117
|
-
content={{ icon: ButtonDelete }}
|
|
118
|
-
onClick={() => {
|
|
119
|
-
const options = [...(component.properties?.options || [])]
|
|
120
|
-
options.splice(index, 1)
|
|
121
|
-
updateProperty("options", options, component, onPropertyChange)
|
|
122
|
-
}}
|
|
123
|
-
/>
|
|
124
|
-
</div>
|
|
112
|
+
<div class="grid grid-cols-[1fr_auto] items-center gap-2 rounded-lg border border-(--hairline-color) bg-(--container-color)/60 p-2">
|
|
125
113
|
<div class="flex flex-wrap items-end gap-2">
|
|
126
114
|
<UI.Input
|
|
127
115
|
label={{ name: $T("constructor.props.optionname") }}
|
|
@@ -147,7 +135,7 @@
|
|
|
147
135
|
}}
|
|
148
136
|
/>
|
|
149
137
|
<UI.Select
|
|
150
|
-
wrapperClass="min-w-56 flex-[2]
|
|
138
|
+
wrapperClass="min-w-56 flex-[2]"
|
|
151
139
|
label={{ name: $T("constructor.props.colors") }}
|
|
152
140
|
type="buttons"
|
|
153
141
|
options={$optionsStore.COLOR_OPTIONS.filter((option) => option.value !== "bg-max" && option.value !== "bg-gray")}
|
|
@@ -172,6 +160,15 @@
|
|
|
172
160
|
}}
|
|
173
161
|
/>
|
|
174
162
|
</div>
|
|
163
|
+
<UI.Button
|
|
164
|
+
wrapperClass="w-8 shrink-0"
|
|
165
|
+
content={{ icon: ButtonDelete }}
|
|
166
|
+
onClick={() => {
|
|
167
|
+
const options = [...(component.properties?.options || [])]
|
|
168
|
+
options.splice(index, 1)
|
|
169
|
+
updateProperty("options", options, component, onPropertyChange)
|
|
170
|
+
}}
|
|
171
|
+
/>
|
|
175
172
|
</div>
|
|
176
173
|
{/each}
|
|
177
174
|
</PropsGroup>
|
|
@@ -238,36 +238,25 @@
|
|
|
238
238
|
<div class="flex flex-col gap-2" bind:this={settingsContainer[columnIndex]}>
|
|
239
239
|
{#if typeof column.content !== "function"}
|
|
240
240
|
{#each column.content as content, index}
|
|
241
|
-
<div
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
updateProperty("header", headers, component, onPropertyChange)
|
|
256
|
-
}
|
|
257
|
-
}}
|
|
258
|
-
/>
|
|
259
|
-
<span class="flex-1"></span>
|
|
260
|
-
<UI.Button
|
|
261
|
-
wrapperClass="w-8 shrink-0"
|
|
262
|
-
content={{ icon: ButtonDelete }}
|
|
263
|
-
onClick={() => {
|
|
264
|
-
const headers = [...(component.properties.header || [])]
|
|
265
|
-
;((headers as ITableHeader<object>[])[columnIndex].content as ITableContent<object>[]).splice(index, 1)
|
|
241
|
+
<div
|
|
242
|
+
id={`item-${index}-${columnIndex}`}
|
|
243
|
+
class="grid grid-cols-[auto_1fr_auto] items-center gap-2 rounded-lg border border-(--hairline-color) bg-(--back-color)/60 p-2"
|
|
244
|
+
>
|
|
245
|
+
<Dragging
|
|
246
|
+
wrapperClass="shrink-0"
|
|
247
|
+
container={settingsContainer[columnIndex]}
|
|
248
|
+
array={column.content}
|
|
249
|
+
elementIndex={index}
|
|
250
|
+
containerIndex={columnIndex}
|
|
251
|
+
onUpdate={(updatedArray, index) => {
|
|
252
|
+
if (index === columnIndex) {
|
|
253
|
+
const headers = [...component.properties.header]
|
|
254
|
+
headers[columnIndex].content = updatedArray
|
|
266
255
|
updateProperty("header", headers, component, onPropertyChange)
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
256
|
+
}
|
|
257
|
+
}}
|
|
258
|
+
/>
|
|
259
|
+
<div class="flex min-w-0 flex-col gap-2">
|
|
271
260
|
{#if content.type == "text"}
|
|
272
261
|
{@const text = content.data}
|
|
273
262
|
<div class="flex flex-wrap items-end gap-2">
|
|
@@ -359,7 +348,7 @@
|
|
|
359
348
|
content={{ icon: InfoIcon, info: { text: $T("constructor.props.button.colors.hint"), side: "right" } }}
|
|
360
349
|
/>
|
|
361
350
|
<UI.Select
|
|
362
|
-
wrapperClass="min-w-0 flex-1
|
|
351
|
+
wrapperClass="min-w-0 flex-1"
|
|
363
352
|
label={{ name: $T("constructor.props.colors") }}
|
|
364
353
|
type="buttons"
|
|
365
354
|
options={$optionsStore.COLOR_OPTIONS.filter((option) => option.value !== "bg-max")}
|
|
@@ -495,6 +484,16 @@
|
|
|
495
484
|
/>
|
|
496
485
|
</div>
|
|
497
486
|
{/if}
|
|
487
|
+
</div>
|
|
488
|
+
<UI.Button
|
|
489
|
+
wrapperClass="w-8 shrink-0"
|
|
490
|
+
content={{ icon: ButtonDelete }}
|
|
491
|
+
onClick={() => {
|
|
492
|
+
const headers = [...(component.properties.header || [])]
|
|
493
|
+
;((headers as ITableHeader<object>[])[columnIndex].content as ITableContent<object>[]).splice(index, 1)
|
|
494
|
+
updateProperty("header", headers, component, onPropertyChange)
|
|
495
|
+
}}
|
|
496
|
+
/>
|
|
498
497
|
</div>
|
|
499
498
|
{/each}
|
|
500
499
|
{/if}
|
|
@@ -112,34 +112,19 @@
|
|
|
112
112
|
|
|
113
113
|
<div bind:this={itemsContainer} class="flex flex-col gap-2">
|
|
114
114
|
{#each component.properties.items || [] as tab, index}
|
|
115
|
-
<div
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
<UI.Button
|
|
129
|
-
wrapperClass="w-8 shrink-0"
|
|
130
|
-
content={{ icon: ButtonDelete }}
|
|
131
|
-
onClick={() => {
|
|
132
|
-
const items = [...(component.properties?.items || [])]
|
|
133
|
-
items.splice(index, 1)
|
|
134
|
-
items.forEach((_item: any, index: number) => {
|
|
135
|
-
items[index]["class"] = twMerge(items[index].class, initialWidth() ? `w-[${(1 / items.length) * 100}%]` : "w-auto")
|
|
136
|
-
updateProperty("items", items, component, onPropertyChange)
|
|
137
|
-
})
|
|
138
|
-
updateProperty("items", items, component, onPropertyChange)
|
|
139
|
-
}}
|
|
140
|
-
/>
|
|
141
|
-
{/if}
|
|
142
|
-
</div>
|
|
115
|
+
<div
|
|
116
|
+
id="item-{index}"
|
|
117
|
+
class="grid grid-cols-[auto_1fr_auto] items-center gap-2 rounded-lg border border-(--hairline-color) bg-(--container-color)/60 p-2"
|
|
118
|
+
>
|
|
119
|
+
<UI.Dragging
|
|
120
|
+
wrapperClass="shrink-0"
|
|
121
|
+
container={itemsContainer}
|
|
122
|
+
array={component.properties.items}
|
|
123
|
+
elementIndex={index}
|
|
124
|
+
onUpdate={(updatedArray) => {
|
|
125
|
+
updateProperty("items", updatedArray, component, onPropertyChange)
|
|
126
|
+
}}
|
|
127
|
+
/>
|
|
143
128
|
<div class="flex flex-wrap items-end gap-2">
|
|
144
129
|
<UI.Input
|
|
145
130
|
label={{ name: $T("constructor.props.optionname") }}
|
|
@@ -181,6 +166,21 @@
|
|
|
181
166
|
}}
|
|
182
167
|
/>
|
|
183
168
|
</div>
|
|
169
|
+
{#if component.properties.items.length > 1}
|
|
170
|
+
<UI.Button
|
|
171
|
+
wrapperClass="w-8 shrink-0"
|
|
172
|
+
content={{ icon: ButtonDelete }}
|
|
173
|
+
onClick={() => {
|
|
174
|
+
const items = [...(component.properties?.items || [])]
|
|
175
|
+
items.splice(index, 1)
|
|
176
|
+
items.forEach((_item: any, index: number) => {
|
|
177
|
+
items[index]["class"] = twMerge(items[index].class, initialWidth() ? `w-[${(1 / items.length) * 100}%]` : "w-auto")
|
|
178
|
+
updateProperty("items", items, component, onPropertyChange)
|
|
179
|
+
})
|
|
180
|
+
updateProperty("items", items, component, onPropertyChange)
|
|
181
|
+
}}
|
|
182
|
+
/>
|
|
183
|
+
{/if}
|
|
184
184
|
</div>
|
|
185
185
|
{/each}
|
|
186
186
|
<div id="item-{component.properties.items.length}" class="min-h-4"></div>
|
|
@@ -19,6 +19,13 @@
|
|
|
19
19
|
|
|
20
20
|
const isRemote = $derived(source === "remote")
|
|
21
21
|
|
|
22
|
+
/* Мастер-цвет (тот же bg-* из optionsStore.COLOR_OPTIONS, что и у остальных примитивов) —
|
|
23
|
+
проявляется как акцентная рамка кадра, см. Map.svelte для того же приёма. */
|
|
24
|
+
const roleBorderClass = $derived.by(() => {
|
|
25
|
+
const role = wrapperClass?.match(/bg-(\w+)/)?.[1]
|
|
26
|
+
return role && role !== "max" ? `border-2 border-(--border-color) border-${role}` : ""
|
|
27
|
+
})
|
|
28
|
+
|
|
22
29
|
let videoElement = $state<HTMLVideoElement | null>(null)
|
|
23
30
|
let stream = $state<MediaStream | null>(null)
|
|
24
31
|
let error = $state<string | null>(null)
|
|
@@ -139,7 +146,7 @@
|
|
|
139
146
|
{#if label.name}
|
|
140
147
|
<h5 class={twMerge(`w-full px-4 text-center`, label.class)}>{label.name}</h5>
|
|
141
148
|
{/if}
|
|
142
|
-
<div class="relative flex flex-1 w-full items-center justify-center">
|
|
149
|
+
<div class={twMerge("relative flex flex-1 w-full items-center justify-center rounded-2xl", roleBorderClass)}>
|
|
143
150
|
{#if isRemote}
|
|
144
151
|
{#if status !== "live" || !remoteImgSrc}
|
|
145
152
|
<div class="absolute h-full w-full rounded-2xl px-40 py-15 flex flex-col items-center justify-center bg-(--border-color)/50 gap-4 z-10">
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import * as UI from ".."
|
|
5
5
|
import CommonSnippets from "../CommonSnippets.svelte"
|
|
6
6
|
import PropsGroup from "../PropsGroup.svelte"
|
|
7
|
+
import { optionsStore } from "../options"
|
|
7
8
|
|
|
8
9
|
const {
|
|
9
10
|
component,
|
|
@@ -14,6 +15,12 @@
|
|
|
14
15
|
onPropertyChange: (updates: Partial<{ properties?: string | object; name?: string; access?: string; eventHandler?: IUIComponentHandler }>) => void
|
|
15
16
|
forConstructor?: boolean
|
|
16
17
|
}>()
|
|
18
|
+
|
|
19
|
+
const initialColor = $derived(
|
|
20
|
+
$optionsStore.COLOR_OPTIONS.find((c) =>
|
|
21
|
+
(c.value as string).includes(component.properties.wrapperClass?.split(" ").find((cls: string) => cls.startsWith("bg-"))),
|
|
22
|
+
),
|
|
23
|
+
)
|
|
17
24
|
</script>
|
|
18
25
|
|
|
19
26
|
{#snippet VideoViewershowSelect()}
|
|
@@ -60,6 +67,7 @@
|
|
|
60
67
|
{#if component.properties?.source === "remote"}
|
|
61
68
|
{@render VideoViewerStreamKey()}
|
|
62
69
|
{/if}
|
|
70
|
+
<CommonSnippets snippet="Colors" initialValue={{ color: initialColor }} {component} {onPropertyChange} />
|
|
63
71
|
</PropsGroup>
|
|
64
72
|
</div>
|
|
65
73
|
{:else}
|
|
@@ -78,6 +86,7 @@
|
|
|
78
86
|
{#if component.properties?.source === "remote"}
|
|
79
87
|
{@render VideoViewerStreamKey()}
|
|
80
88
|
{/if}
|
|
89
|
+
<CommonSnippets snippet="Colors" initialValue={{ color: initialColor }} {component} {onPropertyChange} />
|
|
81
90
|
</PropsGroup>
|
|
82
91
|
</div>
|
|
83
92
|
{/if}
|
|
@@ -27,6 +27,15 @@
|
|
|
27
27
|
(c.value as string).includes(component.properties.settings.class?.split(" ").find((cls: string) => cls.startsWith("bg-"))),
|
|
28
28
|
),
|
|
29
29
|
)
|
|
30
|
+
|
|
31
|
+
/* Один мастер-цвет вместо двух независимых пикеров: цвет иконки больше не выбирается отдельно,
|
|
32
|
+
а выводится из того же bg-* (COLOR_OPTIONS и TEXT_COLOR_OPTIONS — одна и та же ролевая палитра
|
|
33
|
+
red/yellow/green/blue/purple/gray, см. options.ts). */
|
|
34
|
+
const deriveIconColorClass = (bgClass: string): string => {
|
|
35
|
+
const role = bgClass.match(/bg-(\w+)/)?.[1]
|
|
36
|
+
const match = role && role !== "max" ? $optionsStore.TEXT_COLOR_OPTIONS.find((c) => c.id === `TEXT_COLOR_${role.toUpperCase()}`) : null
|
|
37
|
+
return (match ?? $optionsStore.TEXT_COLOR_OPTIONS[0]).value as string
|
|
38
|
+
}
|
|
30
39
|
</script>
|
|
31
40
|
|
|
32
41
|
{#snippet WidgetSettingsLabel()}
|
|
@@ -45,22 +54,9 @@
|
|
|
45
54
|
options={$optionsStore.COLOR_OPTIONS}
|
|
46
55
|
value={initialColor}
|
|
47
56
|
onUpdate={(option) => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
{/snippet}
|
|
52
|
-
|
|
53
|
-
{#snippet WidgetIconColor()}
|
|
54
|
-
<UI.Select
|
|
55
|
-
wrapperClass="!h-14"
|
|
56
|
-
label={{ name: $T("constructor.props.iconcolor") }}
|
|
57
|
-
type="buttons"
|
|
58
|
-
options={$optionsStore.TEXT_COLOR_OPTIONS}
|
|
59
|
-
value={$optionsStore.TEXT_COLOR_OPTIONS.find((c) =>
|
|
60
|
-
(c.value as string).includes(component.properties.icons.class?.split(" ").find((cls: string) => cls.startsWith("text-"))),
|
|
61
|
-
)}
|
|
62
|
-
onUpdate={(option) => {
|
|
63
|
-
updateProperty("icons.class", twMerge(component.properties.icons.class, (option as UI.IOption<string>).value), component, onPropertyChange)
|
|
57
|
+
const bgClass = (option as UI.IOption<string>).value as string
|
|
58
|
+
updateProperty("settings.class", twMerge(component.properties.settings.class, bgClass), component, onPropertyChange)
|
|
59
|
+
updateProperty("icons.class", twMerge(component.properties.icons.class, deriveIconColorClass(bgClass)), component, onPropertyChange)
|
|
64
60
|
}}
|
|
65
61
|
/>
|
|
66
62
|
{/snippet}
|
|
@@ -132,7 +128,6 @@
|
|
|
132
128
|
<CommonSnippets snippet="Label" {component} {onPropertyChange} />
|
|
133
129
|
{@render WidgetUnits()}
|
|
134
130
|
{@render WidgetIcons()}
|
|
135
|
-
{@render WidgetIconColor()}
|
|
136
131
|
{@render WidgetSwitchingMode()}
|
|
137
132
|
</PropsGroup>
|
|
138
133
|
<PropsGroup label={$T("constructor.props.group.appearance")}>
|
|
@@ -169,7 +164,6 @@
|
|
|
169
164
|
<PropsGroup label={$T("constructor.props.group.content")}>
|
|
170
165
|
{@render WidgetSettingsLabel()}
|
|
171
166
|
{@render WidgetIcons()}
|
|
172
|
-
{@render WidgetIconColor()}
|
|
173
167
|
{@render WidgetSwitchingMode()}
|
|
174
168
|
</PropsGroup>
|
|
175
169
|
<PropsGroup label={$T("constructor.props.group.appearance")}>
|
package/dist/WidgetHeader.svelte
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
<!-- $lib/WidgetHeader.svelte — общая шапка смарт-виджетов конструктора: значок + заголовок
|
|
2
2
|
сворачивают/разворачивают тело виджета по клику (как аккордеон), справа — снипет с любым
|
|
3
3
|
содержимым шапки конкретного виджета (переключатель режима, кнопка "Перезагрузить" и т.п.),
|
|
4
|
-
клик по нему сворачивание не триггерит.
|
|
4
|
+
клик по нему сворачивание не триггерит. Визуально — та же полоса-заголовок, что и у Accordion
|
|
5
|
+
(px-3/py-2, bg-container, мелкая 18px иконка без бейджа) вместо прежнего тяжёлого 32px
|
|
6
|
+
значка-бейджа, который делал шапку заметно выше аккордеона. -->
|
|
5
7
|
<script lang="ts">
|
|
6
8
|
import type { Component, Snippet } from "svelte"
|
|
7
9
|
import ArrowIcon from "./libIcons/ArrowIcon.svelte"
|
|
@@ -21,19 +23,19 @@
|
|
|
21
23
|
const Icon = $derived(icon)
|
|
22
24
|
</script>
|
|
23
25
|
|
|
24
|
-
<div class="flex flex-wrap items-center justify-between gap-3">
|
|
26
|
+
<div class="flex flex-wrap items-center justify-between gap-3 rounded-[10px] bg-(--container-color) px-3 py-2">
|
|
25
27
|
<button
|
|
26
28
|
type="button"
|
|
27
|
-
class="flex min-w-0 cursor-pointer items-center gap-2 border-none bg-transparent p-0 text-left"
|
|
29
|
+
class="flex min-w-0 flex-1 cursor-pointer items-center gap-2 border-none bg-transparent p-0 text-left"
|
|
28
30
|
onclick={() => (collapsed = !collapsed)}
|
|
29
31
|
aria-expanded={!collapsed}
|
|
30
32
|
>
|
|
31
|
-
<span class="flex
|
|
33
|
+
<span class="flex h-[18px] w-[18px] shrink-0 items-center justify-center text-(--accent-color) [&_svg]:h-full [&_svg]:w-full">
|
|
32
34
|
<Icon />
|
|
33
35
|
</span>
|
|
34
36
|
<span class="min-w-0 truncate text-[14px] font-semibold">{label}</span>
|
|
35
37
|
<span
|
|
36
|
-
class="flex
|
|
38
|
+
class="flex h-[14px] w-[14px] shrink-0 items-center justify-center text-(--faint-color) transition-transform duration-150 [&_svg]:h-full [&_svg]:w-full"
|
|
37
39
|
style="transform: rotate({collapsed ? 0 : 90}deg)"
|
|
38
40
|
>
|
|
39
41
|
<ArrowIcon />
|
|
@@ -153,7 +153,7 @@
|
|
|
153
153
|
onUpdate={(option) => (cfg.StaSSID = (option as IOption<string>).name ?? "")}
|
|
154
154
|
/>
|
|
155
155
|
<UI.Button
|
|
156
|
-
wrapperClass="w-
|
|
156
|
+
wrapperClass="w-8"
|
|
157
157
|
componentClass="p-1"
|
|
158
158
|
content={{ icon: scanning ? LoaderIcon : SearchIcon, info: { text: "Сканировать сети", side: "top" } }}
|
|
159
159
|
disabled={scanning || !onScan}
|
package/dist/options.js
CHANGED
|
@@ -57,17 +57,18 @@ export const optionsStore = derived(T, ($T) => {
|
|
|
57
57
|
/* Единая семантическая палитра (app.css: --X-color/--X-soft, светлая и тёмная тема уже учтены) —
|
|
58
58
|
тот же набор ролей, что и в "мастер-цвете" виджетов конструктора (widgetAccent.ts на стороне
|
|
59
59
|
приложения). bg-max — нейтральный вариант (= --back-color), с ним свотч отмечается рамкой
|
|
60
|
-
(Select.svelte: hasOwnColor), а не акцентной синей заливкой, как обычный сегмент-контрол.
|
|
60
|
+
(Select.svelte: hasOwnColor), а не акцентной синей заливкой, как обычный сегмент-контрол.
|
|
61
|
+
7 пунктов вместо прежних 9: orange/cyan/pink убраны — на глаз сливались с yellow/green/red
|
|
62
|
+
соответственно; состав теперь 1:1 с TEXT_COLOR_OPTIONS (red/yellow/green/blue/purple/gray) —
|
|
63
|
+
там уже давно только явно различимые цвета. */
|
|
61
64
|
COLOR_OPTIONS: [
|
|
62
65
|
{ id: id(), name: "-", value: "bg-max", class: "bg-max text-transparent" },
|
|
63
66
|
{ id: id(), name: "", value: "bg-red", class: "bg-red" },
|
|
64
|
-
{ id: id(), name: "", value: "bg-orange", class: "bg-orange" },
|
|
65
67
|
{ id: id(), name: "", value: "bg-yellow", class: "bg-yellow" },
|
|
66
68
|
{ id: id(), name: "", value: "bg-green", class: "bg-green" },
|
|
67
|
-
{ id: id(), name: "", value: "bg-cyan", class: "bg-cyan" },
|
|
68
69
|
{ id: id(), name: "", value: "bg-blue", class: "bg-blue" },
|
|
69
70
|
{ id: id(), name: "", value: "bg-purple", class: "bg-purple" },
|
|
70
|
-
{ id: id(), name: "", value: "bg-
|
|
71
|
+
{ id: id(), name: "", value: "bg-gray", class: "bg-gray" },
|
|
71
72
|
],
|
|
72
73
|
TEXT_COLOR_OPTIONS: [
|
|
73
74
|
{
|