poe-svelte-ui-lib 1.38.0 → 1.38.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/dist/WidgetMap/FitIcon.svelte +12 -0
- package/dist/WidgetMap/FitIcon.svelte.d.ts +18 -0
- package/dist/WidgetMap/README.md +53 -24
- package/dist/WidgetMap/WidgetMap.svelte +46 -41
- package/dist/WidgetMap/WidgetMapProps.svelte +12 -6
- package/dist/locales/translations.js +6 -6
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<script lang="ts"></script>
|
|
2
|
+
|
|
3
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"
|
|
4
|
+
><path
|
|
5
|
+
fill="none"
|
|
6
|
+
stroke="currentColor"
|
|
7
|
+
stroke-linecap="round"
|
|
8
|
+
stroke-linejoin="round"
|
|
9
|
+
stroke-width="2"
|
|
10
|
+
d="M4 9V5a1 1 0 0 1 1-1h4m6 0h4a1 1 0 0 1 1 1v4m0 6v4a1 1 0 0 1-1 1h-4m-6 0H5a1 1 0 0 1-1-1v-4m5-3a3 3 0 1 0 6 0a3 3 0 1 0-6 0"
|
|
11
|
+
/></svg
|
|
12
|
+
>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const FitIcon: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {}, {}, string>;
|
|
17
|
+
type FitIcon = InstanceType<typeof FitIcon>;
|
|
18
|
+
export default FitIcon;
|
package/dist/WidgetMap/README.md
CHANGED
|
@@ -4,32 +4,59 @@
|
|
|
4
4
|
|
|
5
5
|
> **Размеры.** Ширина — 100% контейнера (в конструкторе — ширина ячейки сетки); высота карты задаётся пропом `height` (px), в сетке конструктора виджет занимает одну строку. Мастер-цвет (`componentClass`) перекрашивает шапку.
|
|
6
6
|
|
|
7
|
-
Смарт-виджет «Карта» — положение бортов на карте MapLibre с траекториями.
|
|
8
|
-
(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
Смарт-виджет «Карта» — положение бортов на карте MapLibre с траекториями. Каждый борт — одна **группа полей**
|
|
8
|
+
устройства (префикс, например `MAV`); виджет показывает сразу несколько групп, например `MAV GNSS` — автопилот
|
|
9
|
+
и собственный GNSS-приёмник модуля. Только отображение: ничего не отправляет и не знает про DeviceStore/WebSocket.
|
|
10
|
+
Заменяет удалённый компонент `Map`.
|
|
11
|
+
|
|
12
|
+
## Как работать с картой
|
|
13
|
+
|
|
14
|
+
1. **Устройство** шлёт поля группы в поток телеметрии (`Telemetry_SendObject`, ключ `Data`) — облако и WebApp
|
|
15
|
+
раскладывают их в переменные `<ModSN>|<группа>.<ключ>`. Координаты — раз в 0.5–1 с, имя и серийный номер
|
|
16
|
+
можно в том же пакете (строки передаются только при отправке, отдельной частоты не нужно).
|
|
17
|
+
2. **В конструкторе** добавьте «Карту» из смарт-виджетов и перечислите группы через пробел (`MAV` или
|
|
18
|
+
`MAV GNSS`). Переменные привязывать не нужно — виджет сам берёт ключи из таблицы ниже.
|
|
19
|
+
3. **Оператор** поверх карты включает траекторию, выбирает число её точек и таймаут маркеров. Кнопка
|
|
20
|
+
**«Все борта»** в шапке виджета вписывает все видимые борта в экран (один борт — приближение к нему).
|
|
21
|
+
Сама карта вид не меняет — бортов может быть много.
|
|
22
|
+
4. **Клик по маркеру** открывает карточку борта: имя, группа, координаты, высота, курс, спутники, серийный
|
|
23
|
+
номер; кнопки «Копировать» (всё в буфер обмена) и «Скрыть» (до следующего обновления борта).
|
|
24
|
+
|
|
25
|
+
```c
|
|
26
|
+
/* Прошивка: группа MAV — те же ключи читает и WidgetPFD, одна отправка кормит оба виджета */
|
|
27
|
+
const telemetry_kv_t mav[] = {
|
|
28
|
+
TLM_F("MAV.Lat", lat_deg), TLM_F("MAV.Lon", lon_deg), TLM_F("MAV.Alt", alt_m),
|
|
29
|
+
TLM_F("MAV.Heading", hdg_deg), TLM_F("MAV.Sat", (float) sats),
|
|
30
|
+
TLM_S("MAV.DevName", "Борт 1"), TLM_S("MAV.DevSN", g_mcfg.DevSN),
|
|
31
|
+
};
|
|
32
|
+
Telemetry_SendObject(g_telemetry_stream, g_mcfg.DevSN, "Data", mav, sizeof(mav) / sizeof(mav[0]));
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Ключи группы
|
|
36
|
+
|
|
37
|
+
Имена общие с другими виджетами: `Lat`/`Lon`/`Alt`/`Heading`/`Sat` — как у WidgetPFD, `DevName`/`DevSN` — как
|
|
38
|
+
у WidgetDeviceInfo. Поэтому одни и те же данные отображаются сразу в нескольких виджетах.
|
|
39
|
+
|
|
40
|
+
| Ключ | Тип | Обязателен | Что |
|
|
41
|
+
| --------- | ------ | ---------- | ------------------------------------------------------------------------------- |
|
|
42
|
+
| `Lat` | число | да | широта, ° (WGS-84); `Lat` и `Lon` = 0 или нечисло — нет фикса, борт не рисуется |
|
|
43
|
+
| `Lon` | число | да | долгота, ° |
|
|
44
|
+
| `Alt` | число | нет | высота, м — в карточке борта |
|
|
45
|
+
| `Heading` | число | нет | курс, 0..360° — поворот маркера |
|
|
46
|
+
| `Sat` | число | нет | число спутников — в карточке |
|
|
47
|
+
| `DevName` | строка | нет | имя борта — подпись маркера и заголовок карточки; без него — имя группы |
|
|
48
|
+
| `DevSN` | строка | нет | серийный номер — в карточке и при копировании |
|
|
49
|
+
|
|
50
|
+
Имена ключей можно переопределить пропом `keys` (например `{ Lat: "NavLat" }`), если прошивка шлёт их иначе.
|
|
51
|
+
|
|
52
|
+
## Поведение
|
|
53
|
+
|
|
15
54
|
- **Свежесть.** Борт зелёный, пока его значения менялись за таймаут; без изменений — красный; ещё через таймаут
|
|
16
|
-
скрывается до новых данных.
|
|
55
|
+
скрывается до новых данных.
|
|
17
56
|
- **Траектория** — точка добавляется только при смене координат (курс и высота могут обновляться чаще позиции).
|
|
18
57
|
- **Шапка** — сколько бортов на связи из заданных: зелёный — все, серый — часть, красный — ни одного.
|
|
19
58
|
- Карта светлая/тёмная по теме приложения (событие `ThemeChange`).
|
|
20
59
|
|
|
21
|
-
## Поля группы
|
|
22
|
-
|
|
23
|
-
| Поле | Что |
|
|
24
|
-
| --------- | ----------------------------------------- |
|
|
25
|
-
| `Lat` | широта, °; вместе с `Lon` = 0 — нет фикса |
|
|
26
|
-
| `Lon` | долгота, ° |
|
|
27
|
-
| `Alt` | высота, м — в карточке борта |
|
|
28
|
-
| `Heading` | курс, 0..360° — поворот маркера |
|
|
29
|
-
| `Sat` | спутников — в карточке борта |
|
|
30
|
-
|
|
31
|
-
В DevCloud и WebApp GUIPreview собирает `value` сам: `{ [группа]: { Lat: <ModSN>|<группа>.Lat, ... } }`.
|
|
32
|
-
|
|
33
60
|
## Пропсы
|
|
34
61
|
|
|
35
62
|
| Название | Тип | По умолчанию | Описание |
|
|
@@ -38,8 +65,8 @@
|
|
|
38
65
|
| `componentClass` | `string` | `""` | «Мастер-цвет» виджета — роль вида `"bg-blue"` |
|
|
39
66
|
| `label` | `{ name?: string }` | `{ name: "Карта" }` | Заголовок карточки |
|
|
40
67
|
| `groups` | `string[]` | `["MAV"]` | Префиксы групп полей — по борту на группу |
|
|
41
|
-
| `value` | `Record<string, Partial<IWidgetMapData>>` | `undefined` | Значения по
|
|
42
|
-
| `keys` | `Partial<Record<keyof IWidgetMapData, string>>` | `undefined` | Переопределение имён
|
|
68
|
+
| `value` | `Record<string, Partial<IWidgetMapData>>` | `undefined` | Значения по группам: `{ MAV: { Lat, Lon, ... }, GNSS: {...} }` |
|
|
69
|
+
| `keys` | `Partial<Record<keyof IWidgetMapData, string>>` | `undefined` | Переопределение имён ключей (применяет GUIPreview) |
|
|
43
70
|
| `height` | `number` | `400` | Высота карты, px |
|
|
44
71
|
| `markerIcon` | `ConstructorOfATypedSvelteComponent \| string` | `undefined` | Иконка маркера (SVG-строка или компонент), по умолчанию стрелка |
|
|
45
72
|
| `trackEnabled` | `boolean` | `false` | Начальное состояние «Траектория» (`$bindable`) |
|
|
@@ -54,9 +81,11 @@
|
|
|
54
81
|
<UI.WidgetMap groups={["MAV", "GNSS"]} value={{ MAV: mav, GNSS: gnss }} height={400} trackEnabled />
|
|
55
82
|
```
|
|
56
83
|
|
|
84
|
+
В DevCloud и WebApp `value` собирает GUIPreview: для каждой группы читает `<ModSN>|<группа>.<ключ>` по таблице выше.
|
|
85
|
+
|
|
57
86
|
## Конструктор свойств (WidgetMapProps.svelte)
|
|
58
87
|
|
|
59
|
-
Группы панели: общие (заголовок, группы полей через
|
|
88
|
+
Группы панели: общие (заголовок, группы полей через пробел, мастер-цвет), оформление (высота карты S/M/L/XL — 250/400/600/800 px, иконка
|
|
60
89
|
маркера), по умолчанию (траектория и её длина — оператор меняет их на карте).
|
|
61
90
|
|
|
62
91
|
## Внутренняя архитектура
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- $lib/WidgetMap/WidgetMap.svelte — смарт-виджет «Карта»: борта из групп полей устройства (по умолчанию MAV) с полями
|
|
2
|
-
Lat/Lon/Alt/Heading/Sat (см. IWidgetMapData), каждая группа — свой маркер и своя траектория. Только отображение:
|
|
3
|
-
ничего не отправляет и не знает про DeviceStore/WebSocket. Траекторию, длину
|
|
4
|
-
|
|
2
|
+
Lat/Lon/Alt/Heading/Sat/DevName/DevSN (см. IWidgetMapData), каждая группа — свой маркер и своя траектория. Только отображение:
|
|
3
|
+
ничего не отправляет и не знает про DeviceStore/WebSocket. Траекторию, длину трека и таймаут маркеров оператор
|
|
4
|
+
переключает прямо поверх карты, «Все борта» — кнопка в шапке; вид карта сама не меняет — бортов может быть много. -->
|
|
5
5
|
<script lang="ts">
|
|
6
6
|
import { onMount, untrack } from "svelte"
|
|
7
7
|
import { slide } from "svelte/transition"
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { widgetAccentStyle } from "../widgetAccent"
|
|
14
14
|
import { readPersistedCollapsed, writePersistedCollapsed } from "../widgetCollapse"
|
|
15
15
|
import MapIcon from "./MapIcon.svelte"
|
|
16
|
+
import FitIcon from "./FitIcon.svelte"
|
|
17
|
+
import * as UI from ".."
|
|
16
18
|
import { MapLibre, NavigationControl, ScaleControl, GeolocateControl, FullScreenControl, Marker, Popup, Line, CustomControl } from "./mapWrapper"
|
|
17
19
|
|
|
18
20
|
let {
|
|
@@ -49,6 +51,8 @@
|
|
|
49
51
|
alt: number
|
|
50
52
|
heading: number
|
|
51
53
|
sat: number
|
|
54
|
+
name: string
|
|
55
|
+
sn: string
|
|
52
56
|
track: [number, number][]
|
|
53
57
|
lastChange: number
|
|
54
58
|
hiddenAt: number
|
|
@@ -75,13 +79,25 @@
|
|
|
75
79
|
const alt = num(v.Alt)
|
|
76
80
|
const heading = num(v.Heading)
|
|
77
81
|
const sat = num(v.Sat)
|
|
82
|
+
const name = typeof v.DevName === "string" && v.DevName ? v.DevName : group
|
|
83
|
+
const sn = typeof v.DevSN === "string" ? v.DevSN : ""
|
|
78
84
|
untrack(() => {
|
|
79
85
|
const idx = boards.findIndex((b) => b.group === group)
|
|
80
86
|
const prev = idx === -1 ? null : boards[idx]
|
|
81
|
-
if (
|
|
87
|
+
if (
|
|
88
|
+
prev &&
|
|
89
|
+
prev.lat === lat &&
|
|
90
|
+
prev.lon === lon &&
|
|
91
|
+
prev.alt === alt &&
|
|
92
|
+
prev.heading === heading &&
|
|
93
|
+
prev.sat === sat &&
|
|
94
|
+
prev.name === name &&
|
|
95
|
+
prev.sn === sn
|
|
96
|
+
)
|
|
97
|
+
return
|
|
82
98
|
const moved = !prev || prev.lat !== lat || prev.lon !== lon
|
|
83
99
|
const track = moved ? [...(prev?.track ?? []), [lon, lat] as [number, number]].slice(-trackLength) : prev!.track
|
|
84
|
-
const next: Board = { group, lat, lon, alt, heading, sat, track, lastChange: Date.now(), hiddenAt: prev?.hiddenAt ?? 0 }
|
|
100
|
+
const next: Board = { group, lat, lon, alt, heading, sat, name, sn, track, lastChange: Date.now(), hiddenAt: prev?.hiddenAt ?? 0 }
|
|
85
101
|
if (idx === -1) boards.push(next)
|
|
86
102
|
else boards[idx] = next
|
|
87
103
|
})
|
|
@@ -126,7 +142,7 @@
|
|
|
126
142
|
|
|
127
143
|
const copyBoard = (b: Board) => {
|
|
128
144
|
navigator.clipboard.writeText(
|
|
129
|
-
|
|
145
|
+
`DevName: ${b.name}\nDevSN: ${b.sn}\nGroup: ${b.group}\nLat: ${b.lat.toFixed(6)} | Lon: ${b.lon.toFixed(6)} | Alt: ${b.alt.toFixed(1)}\nHeading: ${b.heading.toFixed(1)} | Satellites: ${b.sat}`,
|
|
130
146
|
)
|
|
131
147
|
isCopied = true
|
|
132
148
|
setTimeout(() => (isCopied = false), 1000)
|
|
@@ -159,16 +175,25 @@
|
|
|
159
175
|
>
|
|
160
176
|
<WidgetHeader icon={MapIcon} label={label?.name ?? "Карта"} bind:collapsed>
|
|
161
177
|
{#snippet right()}
|
|
162
|
-
<
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
178
|
+
<div class="flex items-center gap-3">
|
|
179
|
+
<UI.Button
|
|
180
|
+
wrapperClass="w-auto"
|
|
181
|
+
componentClass="bg-transparent px-3"
|
|
182
|
+
content={{ icon: FitIcon, name: $T("constructor.props.map.fitAll") }}
|
|
183
|
+
disabled={collapsed || visibleBoards.length === 0}
|
|
184
|
+
onClick={fitAllBoards}
|
|
185
|
+
/>
|
|
186
|
+
<span
|
|
187
|
+
class="text-[12px] font-semibold tabular-nums {freshCount === 0
|
|
188
|
+
? 'text-(--red-color)'
|
|
189
|
+
: freshCount < groupList.length
|
|
190
|
+
? 'text-(--muted-color)'
|
|
191
|
+
: 'text-(--green-color)'}"
|
|
192
|
+
title={$T("constructor.props.map.boards")}
|
|
193
|
+
>
|
|
194
|
+
{freshCount} / {groupList.length}
|
|
195
|
+
</span>
|
|
196
|
+
</div>
|
|
172
197
|
{/snippet}
|
|
173
198
|
</WidgetHeader>
|
|
174
199
|
|
|
@@ -214,29 +239,6 @@
|
|
|
214
239
|
</div>
|
|
215
240
|
</CustomControl>
|
|
216
241
|
|
|
217
|
-
<!-- Штатная кнопка карты в колонке зума/геолокации/полного экрана -->
|
|
218
|
-
<CustomControl position="top-right">
|
|
219
|
-
<button
|
|
220
|
-
type="button"
|
|
221
|
-
class="flex! items-center justify-center text-[#333] disabled:opacity-40"
|
|
222
|
-
title={$T("constructor.props.map.fitAll")}
|
|
223
|
-
aria-label={$T("constructor.props.map.fitAll")}
|
|
224
|
-
disabled={visibleBoards.length === 0}
|
|
225
|
-
onclick={fitAllBoards}
|
|
226
|
-
>
|
|
227
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
|
|
228
|
-
<path
|
|
229
|
-
fill="none"
|
|
230
|
-
stroke="currentColor"
|
|
231
|
-
stroke-linecap="round"
|
|
232
|
-
stroke-linejoin="round"
|
|
233
|
-
stroke-width="2"
|
|
234
|
-
d="M4 9V5a1 1 0 0 1 1-1h4m6 0h4a1 1 0 0 1 1 1v4m0 6v4a1 1 0 0 1-1 1h-4m-6 0H5a1 1 0 0 1-1-1v-4m5-3a3 3 0 1 0 6 0a3 3 0 1 0-6 0"
|
|
235
|
-
/>
|
|
236
|
-
</svg>
|
|
237
|
-
</button>
|
|
238
|
-
</CustomControl>
|
|
239
|
-
|
|
240
242
|
{#if trackEnabled}
|
|
241
243
|
{#each visibleBoards as board (board.group)}
|
|
242
244
|
{#if board.track.length >= 2}
|
|
@@ -276,7 +278,7 @@
|
|
|
276
278
|
</div>
|
|
277
279
|
{/if}
|
|
278
280
|
</div>
|
|
279
|
-
<p class="font-bold">{board.
|
|
281
|
+
<p class="font-bold">{board.name}</p>
|
|
280
282
|
</div>
|
|
281
283
|
{/snippet}
|
|
282
284
|
|
|
@@ -284,7 +286,8 @@
|
|
|
284
286
|
<div class="flex flex-col gap-1.5">
|
|
285
287
|
<div class="flex items-center gap-1.5">
|
|
286
288
|
<span class="size-2 shrink-0 rounded-full {isFresh(board) ? 'bg-(--green-color)' : 'bg-(--red-color)'}"></span>
|
|
287
|
-
<h6 class="text-sm leading-none font-bold">{board.
|
|
289
|
+
<h6 class="text-sm leading-none font-bold">{board.name}</h6>
|
|
290
|
+
{#if board.name !== board.group}<span class="text-[0.6rem] font-semibold uppercase opacity-60">{board.group}</span>{/if}
|
|
288
291
|
</div>
|
|
289
292
|
|
|
290
293
|
<div class="grid grid-cols-2 gap-x-3 gap-y-1 rounded-lg bg-(--container-color) p-2 text-xs">
|
|
@@ -306,6 +309,8 @@
|
|
|
306
309
|
</div>
|
|
307
310
|
</div>
|
|
308
311
|
|
|
312
|
+
{#if board.sn}<p class="text-center font-mono text-[0.6rem] tracking-wide uppercase">{board.sn}</p>{/if}
|
|
313
|
+
|
|
309
314
|
<div class="flex items-center justify-between border-t border-(--hairline-color) pt-1">
|
|
310
315
|
<div class="relative flex items-center">
|
|
311
316
|
<button
|
|
@@ -14,14 +14,20 @@
|
|
|
14
14
|
onPropertyChange: (updates: Partial<{ properties?: string | object; name?: string; access?: string }>) => void
|
|
15
15
|
}>()
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
/* Высота карты размерами, как у текстового поля: S/M/L/XL */
|
|
18
|
+
const HEIGHT_OPTIONS = [
|
|
19
|
+
{ value: 250, name: "S" },
|
|
20
|
+
{ value: 400, name: "M" },
|
|
21
|
+
{ value: 600, name: "L" },
|
|
22
|
+
{ value: 800, name: "XL" },
|
|
23
|
+
].map((o) => ({ id: crypto.randomUUID(), ...o }))
|
|
18
24
|
const TRACK_LENGTH_OPTIONS = [100, 500, 1000, 5000, 10000, 50000].map((value) => ({ id: crypto.randomUUID(), value, name: String(value) }))
|
|
19
25
|
|
|
20
|
-
/* Группы
|
|
26
|
+
/* Группы через пробел, как переменные кнопки (имя группы не содержит пробелов): "MAV GNSS" */
|
|
21
27
|
const setGroups = (raw: unknown) => {
|
|
22
28
|
const list = String(raw ?? "")
|
|
23
|
-
.
|
|
24
|
-
.
|
|
29
|
+
.trim()
|
|
30
|
+
.split(/[\s,]+/)
|
|
25
31
|
.filter(Boolean)
|
|
26
32
|
updateProperty("groups", list.length ? list : ["MAV"], component, onPropertyChange)
|
|
27
33
|
}
|
|
@@ -34,7 +40,7 @@
|
|
|
34
40
|
value={component.properties.label?.name}
|
|
35
41
|
onUpdate={(value) => updateProperty("label.name", value as string, component, onPropertyChange)}
|
|
36
42
|
/>
|
|
37
|
-
<UI.Input label={{ name: "Группы полей (через
|
|
43
|
+
<UI.Input label={{ name: "Группы полей (через пробел)" }} value={(component.properties.groups ?? ["MAV"]).join(" ")} onUpdate={setGroups} />
|
|
38
44
|
<WidgetAccentPicker
|
|
39
45
|
value={component.properties.componentClass ?? ""}
|
|
40
46
|
onUpdate={(value) => updateProperty("componentClass", value, component, onPropertyChange)}
|
|
@@ -45,7 +51,7 @@
|
|
|
45
51
|
label={{ name: "Высота карты" }}
|
|
46
52
|
type="buttons"
|
|
47
53
|
options={HEIGHT_OPTIONS}
|
|
48
|
-
value={HEIGHT_OPTIONS.find((opt) => opt.value === (component.properties.height ?? 400))}
|
|
54
|
+
value={HEIGHT_OPTIONS.find((opt) => opt.value === (component.properties.height ?? 400)) ?? HEIGHT_OPTIONS[1]}
|
|
49
55
|
onUpdate={(option) => updateProperty("height", (option as { value: number }).value, component, onPropertyChange)}
|
|
50
56
|
/>
|
|
51
57
|
<CommonSnippets
|
|
@@ -129,9 +129,9 @@ const translations = {
|
|
|
129
129
|
"🎯 **主飞行显示器(PFD)** —— 飞行监控的主要仪表:姿态、速度、高度、航向和系统状态。\n\n**🔗 与设备的关联** —— `MAV` 分组的字段(MAVLink 自驾仪遥测),无需绑定变量\n- ✈️ `Roll`、`Pitch`、`Heading` —— 姿态仪和航向带(约每秒 20 次,运动经过平滑)\n- 📈 `GSpeed`、`ASpeed` —— 地速带和空速数值;`Alt`、`Climb` —— 相对起飞点高度带和升降速度\n- 🧭 `Vx`、`Vy` —— 航迹(航向带上的粉色标记),`HomeLat`/`HomeLon` —— 到起飞点的距离和方向(绿色标记)\n- 🛰️ 状态栏:`Armed`、`Mode`(按机型 `VType` 显示名称)、GPS `Fix`/`Sat`、电池 `BV`/`BC`/`BRem`\n- 📍 仪表下方:`Lat`/`Lon`、`AltMSL`、`Press`、`Temp`\n\n**🚦 限值**(在组件设置中)\n- 最小/最大速度、最大高度 —— 速度带和高度带上的红色区域;最大坡度 —— 红色弧线,坡度指针变红\n- 低电量 —— 电池高亮\n- 超过设定时间无数据 —— 仪表被划叉并标记「无数据」\n\n**📱 尺寸** —— 在窄单元格中,速度带和高度带变为地平线上的数字。\n\n⚙️ 若分组不是 `MAV`(例如设备自身的航姿系统)—— 在组件设置中修改前缀(ID)。",
|
|
130
130
|
],
|
|
131
131
|
"component.info.WidgetMap": [
|
|
132
|
-
"🎯 **Карта** — положение бортов на карте с траекториями.\n\n**🔗 Связь с устройством** — поля групп, привязывать переменные не нужно\n- 🛰️ Каждая группа из настроек (по умолчанию `MAV`, можно несколько через
|
|
133
|
-
|
|
134
|
-
"🎯 **地图** —— 在地图上显示各载具位置及轨迹。\n\n**🔗 与设备的关联** —— 分组字段,无需绑定变量\n- 🛰️ 设置中的每个分组(默认 `MAV
|
|
132
|
+
"🎯 **Карта** — положение бортов на карте с траекториями.\n\n**🔗 Связь с устройством** — поля групп, привязывать переменные не нужно\n- 🛰️ Каждая группа из настроек (по умолчанию `MAV`, можно несколько через пробел: `MAV GNSS`) — отдельный борт: свой маркер и своя траектория\n- 📍 `Lat`, `Lon` — координаты (0, 0 — нет фикса); `Heading` — поворот маркера; `Alt`, `Sat` — в карточке борта\n- 🏷️ `DevName` — подпись маркера (без него — имя группы), `DevSN` — серийный номер в карточке\n- 🔁 Имена ключей общие с «Пилотажным дисплеем» и «Об устройстве» — одни данные идут в несколько виджетов\n\n**👆 Клик по борту** — карточка: имя, координаты, высота, курс, спутники, серийный номер; копировать или скрыть борт\n\n**🕹️ Поверх карты** (оператор)\n- Траектория и число её точек, таймаут маркеров: борт без новых данных краснеет, ещё через таймаут — скрывается\n- Кнопка «Все борта» в шапке — вписать все борта в экран; сама карта вид не меняет\n\n**📱 В шапке** — сколько бортов на связи из заданных.\n\n⚙️ Высота карты, иконка маркера и начальные значения переключателей — в настройках виджета.",
|
|
133
|
+
'🎯 **Map** — vehicle positions on the map with tracks.\n\n**🔗 Device link** — group fields, no variable binding needed\n- 🛰️ Each group from the settings (default `MAV`, several separated by spaces: `MAV GNSS`) is a separate vehicle with its own marker and track\n- 📍 `Lat`, `Lon` — coordinates (0, 0 — no fix); `Heading` — marker rotation; `Alt`, `Sat` — in the vehicle card\n- 🏷️ `DevName` — marker label (group name if absent), `DevSN` — serial number in the card\n- 🔁 Key names are shared with the flight display and device info widgets — the same data feeds several widgets\n\n**👆 Click a vehicle** — card with name, coordinates, altitude, heading, satellites, serial number; copy or hide the vehicle\n\n**🕹️ On the map** (operator)\n- Track and its point count, marker timeout: a vehicle without new data turns red, after one more timeout it is hidden\n- "All vehicles" button in the header — fit all vehicles into view; the map never moves by itself\n\n**📱 Header** — how many of the configured vehicles are online.\n\n⚙️ Map height, marker icon and default switch values — in widget settings.',
|
|
134
|
+
"🎯 **地图** —— 在地图上显示各载具位置及轨迹。\n\n**🔗 与设备的关联** —— 分组字段,无需绑定变量\n- 🛰️ 设置中的每个分组(默认 `MAV`,可用空格分隔多个:`MAV GNSS`)都是一个独立载具,有自己的标记和轨迹\n- 📍 `Lat`、`Lon` —— 坐标(0, 0 表示无定位);`Heading` —— 标记旋转;`Alt`、`Sat` —— 显示在载具卡片中\n- 🏷️ `DevName` —— 标记标签(缺省时为分组名),`DevSN` —— 卡片中的序列号\n- 🔁 键名与主飞行显示器和设备信息组件通用 —— 同一数据可用于多个组件\n\n**👆 点击载具** —— 卡片显示名称、坐标、高度、航向、卫星数、序列号;可复制或隐藏\n\n**🕹️ 地图上**(操作员)\n- 轨迹及点数、标记超时:无新数据的载具变红,再过一个超时后隐藏\n- 标题栏中的「全部设备」按钮 —— 将所有载具纳入视野;地图本身不会自动移动\n\n**📱 标题栏** —— 已配置载具中在线的数量。\n\n⚙️ 地图高度、标记图标和开关默认值 —— 在组件设置中。",
|
|
135
135
|
],
|
|
136
136
|
"component.info.WidgetStackInfo": [
|
|
137
137
|
"🎯 **Виджет «Память и задачи»** — отладка: свободная память и запас стека задач прошивки.\n\n**🔗 Связь с устройством** — один объект `StackInfo` из ответа на `GET StackInfo`\n- 📊 **Кучи** `Heap[]`: занято / всего, свободно и минимум свободного с момента старта; светлая часть полосы — пик занятости\n- 🧵 **Задачи** `Tasks[]`: имя, состояние, приоритет, ядро (ESP32), минимальный запас стека в байтах\n\n**⚙️ Настройки**\n- Порог запаса стека — меньше порога красным, меньше удвоенного — оранжевым\n- Автоопрос: выкл / 1 / 5 / 10 с; свёрнутый виджет не опрашивает\n\n💡 Задачи всегда отсортированы по запасу стека — самые рискованные сверху.",
|
|
@@ -194,7 +194,7 @@ const translations = {
|
|
|
194
194
|
"constructor.props.defaultcolor": ["Первоначальный цвет", "Initial color", "初始颜色"],
|
|
195
195
|
"constructor.props.file.accept": ["Допустимые файлы", "Allowed files", "允许的文件"],
|
|
196
196
|
"constructor.props.file.accept.help": [
|
|
197
|
-
"'audio/*', 'video/*', 'image/*' или расширения файлов через
|
|
197
|
+
"'audio/*', 'video/*', 'image/*' или расширения файлов через пробел в формате '.pdf'",
|
|
198
198
|
"'audio/*', 'video/*', 'image/*' or comma-separated file extensions like '.pdf'",
|
|
199
199
|
"'audio/*'、'video/*'、'image/*' 或以逗号分隔的文件扩展名,如 '.pdf'",
|
|
200
200
|
],
|
|
@@ -327,8 +327,8 @@ const translations = {
|
|
|
327
327
|
"constructor.props.bits.title": ["Биты", "Bits", "位"],
|
|
328
328
|
"constructor.props.tabs.title": ["Вкладки меню", "Menu tabs", "菜单标签"],
|
|
329
329
|
"constructor.props.periodchart.title": ["Уровни детализации", "Detail levels", "详细级别"],
|
|
330
|
-
"constructor.props.periodchart.data": ["Данные (через
|
|
331
|
-
"constructor.props.periodchart.labels": ["Подписи столбиков (через
|
|
330
|
+
"constructor.props.periodchart.data": ["Данные (через пробел)", "Data (comma-separated)", "数据(逗号分隔)"],
|
|
331
|
+
"constructor.props.periodchart.labels": ["Подписи столбиков (через пробел)", "Bar labels (comma-separated)", "柱标签(逗号分隔)"],
|
|
332
332
|
"constructor.props.valuetype": ["Тип значения", "Value type", "值类型"],
|
|
333
333
|
"constructor.props.action": ["Действие при переключении", "Action on switch", "切换时的操作"],
|
|
334
334
|
"constructor.props.caption.left": ["Надпись слева", "Left caption", "左侧标题"],
|
package/dist/types.d.ts
CHANGED