@viamrobotics/test-widgets 0.10.2 → 0.11.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/components/audio-properties.svelte +3 -3
- package/dist/components/connection-status.svelte +1 -3
- package/dist/components/error.svelte +15 -10
- package/dist/components/readings-list.svelte +30 -30
- package/dist/components/refetch-controller.svelte +2 -2
- package/dist/components/widgets/audio-input/audio-input.svelte +85 -83
- package/dist/components/widgets/audio-output/audio-output.svelte +93 -91
- package/dist/components/widgets/base/base.svelte +39 -37
- package/dist/components/widgets/base/move-straight.svelte +1 -1
- package/dist/components/widgets/base/set-power.svelte +1 -1
- package/dist/components/widgets/base/set-velocity.svelte +1 -1
- package/dist/components/widgets/base/spin.svelte +1 -1
- package/dist/components/widgets/board/pin-selector.svelte +1 -1
- package/dist/components/widgets/board/read-write-pins.svelte +1 -1
- package/dist/components/widgets/camera/camera.svelte +6 -5
- package/dist/components/widgets/camera/live-or-polling-video.svelte +2 -2
- package/dist/components/widgets/discovery/resources-list.svelte +35 -33
- package/dist/components/widgets/do-command/do-command.svelte +44 -41
- package/dist/components/widgets/gantry/gantry.svelte +102 -98
- package/dist/components/widgets/gantry/move-to-position.svelte +1 -1
- package/dist/components/widgets/gripper/gripper.svelte +41 -39
- package/dist/components/widgets/motor/go-for.svelte +1 -1
- package/dist/components/widgets/motor/go-to.svelte +1 -1
- package/dist/components/widgets/motor/motor.svelte +88 -86
- package/dist/components/widgets/pcd/inputs.svelte +1 -1
- package/dist/components/widgets/pcd/pcd-widget.svelte +19 -17
- package/dist/components/widgets/servo/servo.svelte +69 -64
- package/dist/components/widgets/vision-service/image.svelte +10 -3
- package/dist/components/widgets/vision-service/object-point-clouds.svelte +1 -1
- package/dist/components/widgets/vision-service/vision-service.svelte +5 -5
- package/package.json +16 -6
|
@@ -10,17 +10,17 @@
|
|
|
10
10
|
|
|
11
11
|
<dl class="font-roboto-mono flex flex-col gap-y-2 text-sm">
|
|
12
12
|
<div class="flex flex-col gap-0.5">
|
|
13
|
-
<dt class="text-default
|
|
13
|
+
<dt class="text-default pr-2 font-medium">Supported Codecs</dt>
|
|
14
14
|
<dd class="text-subtle-1">
|
|
15
15
|
{supportedCodecs.length > 0 ? supportedCodecs.join(', ') : 'None'}
|
|
16
16
|
</dd>
|
|
17
17
|
</div>
|
|
18
18
|
<div class="flex flex-col gap-0.5">
|
|
19
|
-
<dt class="text-default
|
|
19
|
+
<dt class="text-default pr-2 font-medium">Sample Rate</dt>
|
|
20
20
|
<dd class="text-subtle-1">{sampleRateHz} Hz</dd>
|
|
21
21
|
</div>
|
|
22
22
|
<div class="flex flex-col gap-0.5">
|
|
23
|
-
<dt class="text-default
|
|
23
|
+
<dt class="text-default pr-2 font-medium">Channels</dt>
|
|
24
24
|
<dd class="text-subtle-1">{numChannels}</dd>
|
|
25
25
|
</div>
|
|
26
26
|
</dl>
|
|
@@ -39,18 +39,23 @@
|
|
|
39
39
|
<div class="flex items-center justify-between gap-1">
|
|
40
40
|
<p
|
|
41
41
|
{id}
|
|
42
|
-
class={twMerge(
|
|
42
|
+
class={twMerge(
|
|
43
|
+
'font-roboto-mono text-danger-dark min-w-0 overflow-auto text-xs wrap-break-word',
|
|
44
|
+
className
|
|
45
|
+
)}
|
|
43
46
|
>
|
|
44
47
|
{errorText}
|
|
45
48
|
</p>
|
|
46
|
-
<
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
<div class="shrink-0">
|
|
50
|
+
<Tooltip let:tooltipID>
|
|
51
|
+
<IconButton
|
|
52
|
+
aria-describedby={tooltipID}
|
|
53
|
+
icon={showCopySuccess ? 'check' : 'content-copy'}
|
|
54
|
+
label="Copy error"
|
|
55
|
+
on:click={copyErrorToClipboard}
|
|
56
|
+
/>
|
|
57
|
+
<div slot="description">Copy error</div>
|
|
58
|
+
</Tooltip>
|
|
59
|
+
</div>
|
|
55
60
|
</div>
|
|
56
61
|
{/if}
|
|
@@ -39,35 +39,35 @@
|
|
|
39
39
|
<div slot="description">Copy JSON</div>
|
|
40
40
|
</Tooltip>
|
|
41
41
|
</div>
|
|
42
|
-
<
|
|
43
|
-
|
|
44
|
-
{
|
|
45
|
-
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
{
|
|
67
|
-
|
|
68
|
-
</
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
</
|
|
42
|
+
<div class="@container">
|
|
43
|
+
<dl class="font-roboto-mono flex flex-col gap-y-2">
|
|
44
|
+
{#each sortedData as [key, value] (key)}
|
|
45
|
+
{@const valueString = JSON.stringify(value, null, 2)}
|
|
46
|
+
<div class="flex flex-col gap-y-1 @lg:flex-row @lg:gap-y-0">
|
|
47
|
+
<dt
|
|
48
|
+
class="text-default truncate pr-2 font-medium @lg:w-50 @lg:min-w-50"
|
|
49
|
+
title={key}
|
|
50
|
+
>
|
|
51
|
+
{key}
|
|
52
|
+
</dt>
|
|
53
|
+
<dd class="text-subtle-1 min-w-0 grow wrap-break-word">
|
|
54
|
+
{#if value !== null && typeof value === 'object'}
|
|
55
|
+
<div class="border-light bg-extralight border px-3 py-2">
|
|
56
|
+
<pre class="whitespace-pre-wrap"><code>{valueString}</code></pre>
|
|
57
|
+
</div>
|
|
58
|
+
{:else if typeof value === 'string' && value.startsWith('data:image/')}
|
|
59
|
+
<img
|
|
60
|
+
class="max-h-80 max-w-full"
|
|
61
|
+
src={value}
|
|
62
|
+
alt={key}
|
|
63
|
+
/>
|
|
64
|
+
{:else}
|
|
65
|
+
{truncate(valueString, { length: 300 })}
|
|
66
|
+
{/if}
|
|
67
|
+
</dd>
|
|
68
|
+
</div>
|
|
69
|
+
{/each}
|
|
70
|
+
</dl>
|
|
71
|
+
</div>
|
|
72
72
|
</div>
|
|
73
73
|
{/if}
|
|
@@ -91,8 +91,8 @@
|
|
|
91
91
|
})
|
|
92
92
|
</script>
|
|
93
93
|
|
|
94
|
-
<div class="text-default flex flex-
|
|
95
|
-
<div class="w-50">
|
|
94
|
+
<div class="text-default flex flex-wrap gap-2 text-xs">
|
|
95
|
+
<div class="w-50 max-w-full">
|
|
96
96
|
<Select on:change={onChange}>
|
|
97
97
|
{#each refetchOptions as option (option)}
|
|
98
98
|
<option selected={selectedOption === option}>{option}</option>
|
|
@@ -58,97 +58,99 @@
|
|
|
58
58
|
/>
|
|
59
59
|
</div>
|
|
60
60
|
|
|
61
|
-
<div class="
|
|
62
|
-
<div class="flex
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
<
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
61
|
+
<div class="@container">
|
|
62
|
+
<div class="flex flex-col divide-y @2xl:flex-row @2xl:divide-x @2xl:divide-y-0">
|
|
63
|
+
<div class="flex w-full flex-col divide-y">
|
|
64
|
+
<MutationSection
|
|
65
|
+
title="GetAudio"
|
|
66
|
+
api="rdk:component:audio_input"
|
|
67
|
+
description="Capture audio from the device"
|
|
68
|
+
lastError={capture.error}
|
|
69
|
+
>
|
|
70
|
+
<div class="flex flex-col gap-2">
|
|
71
|
+
<Label cx="gap-1 text-xs">
|
|
72
|
+
Codec
|
|
73
|
+
<Select
|
|
74
|
+
slot="input"
|
|
75
|
+
value={selectedCodec}
|
|
76
|
+
on:change={(e) => {
|
|
77
|
+
captureCodec = (e.target as HTMLSelectElement).value
|
|
78
|
+
}}
|
|
79
|
+
>
|
|
80
|
+
{#each availableCodecs as codec (codec)}
|
|
81
|
+
<option value={codec}>{codec}</option>
|
|
82
|
+
{/each}
|
|
83
|
+
</Select>
|
|
84
|
+
</Label>
|
|
85
|
+
<Label cx="gap-1 text-xs">
|
|
86
|
+
Duration (seconds, 0 = stream until stopped)
|
|
87
|
+
<NumericInput
|
|
88
|
+
slot="input"
|
|
89
|
+
value={captureDuration}
|
|
90
|
+
on:change={(e) => {
|
|
91
|
+
captureDuration = numberValueFromEvent(e) ?? 3
|
|
92
|
+
}}
|
|
93
|
+
/>
|
|
94
|
+
</Label>
|
|
95
|
+
</div>
|
|
95
96
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
<p class="font-roboto-mono text-subtle-1 text-xs">
|
|
99
|
-
{(capture.totalBytes / 1024).toFixed(1)} kB captured
|
|
100
|
-
</p>
|
|
101
|
-
<Button
|
|
102
|
-
icon="stop-circle-outline"
|
|
103
|
-
onclick={capture.stop}
|
|
104
|
-
>
|
|
105
|
-
Stop
|
|
106
|
-
</Button>
|
|
107
|
-
{:else}
|
|
108
|
-
{#if capture.downloadUrl}
|
|
97
|
+
<div class="mt-auto flex flex-col items-start gap-2">
|
|
98
|
+
{#if capture.status === 'recording'}
|
|
109
99
|
<p class="font-roboto-mono text-subtle-1 text-xs">
|
|
110
100
|
{(capture.totalBytes / 1024).toFixed(1)} kB captured
|
|
111
101
|
</p>
|
|
112
|
-
<
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
102
|
+
<Button
|
|
103
|
+
icon="stop-circle-outline"
|
|
104
|
+
onclick={capture.stop}
|
|
105
|
+
>
|
|
106
|
+
Stop
|
|
107
|
+
</Button>
|
|
108
|
+
{:else}
|
|
109
|
+
{#if capture.downloadUrl}
|
|
110
|
+
<p class="font-roboto-mono text-subtle-1 text-xs">
|
|
111
|
+
{(capture.totalBytes / 1024).toFixed(1)} kB captured
|
|
112
|
+
</p>
|
|
113
|
+
<a
|
|
114
|
+
href={capture.downloadUrl}
|
|
115
|
+
download="audio-capture.{selectedCodec}"
|
|
116
|
+
rel="external"
|
|
117
|
+
>
|
|
118
|
+
<Button icon="download">Download</Button>
|
|
119
|
+
</a>
|
|
120
|
+
{/if}
|
|
121
|
+
<Button
|
|
122
|
+
icon="play-circle-outline"
|
|
123
|
+
onclick={() => capture.start(selectedCodec, captureDuration)}
|
|
124
|
+
disabled={!client.current}
|
|
116
125
|
>
|
|
117
|
-
|
|
118
|
-
</
|
|
126
|
+
{capture.status === 'done' ? 'Capture Again' : 'Start Capture'}
|
|
127
|
+
</Button>
|
|
119
128
|
{/if}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
disabled={!client.current}
|
|
124
|
-
>
|
|
125
|
-
{capture.status === 'done' ? 'Capture Again' : 'Start Capture'}
|
|
126
|
-
</Button>
|
|
127
|
-
{/if}
|
|
128
|
-
</div>
|
|
129
|
-
</MutationSection>
|
|
130
|
-
</div>
|
|
129
|
+
</div>
|
|
130
|
+
</MutationSection>
|
|
131
|
+
</div>
|
|
131
132
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
>
|
|
139
|
-
<Query
|
|
140
|
-
query={propertiesQuery}
|
|
141
|
-
contentCx="h-6"
|
|
133
|
+
<div class="flex w-full flex-col divide-y @2xl:ml-auto @2xl:max-w-1/2 @4xl:max-w-1/3">
|
|
134
|
+
<ApiSection
|
|
135
|
+
title="GetProperties"
|
|
136
|
+
api="rdk:component:audio_input"
|
|
137
|
+
description="Audio input properties"
|
|
138
|
+
class="relative"
|
|
142
139
|
>
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
140
|
+
<Query
|
|
141
|
+
query={propertiesQuery}
|
|
142
|
+
contentCx="h-6"
|
|
143
|
+
>
|
|
144
|
+
{#if propertiesQuery.data !== undefined}
|
|
145
|
+
<Properties
|
|
146
|
+
supportedCodecs={propertiesQuery.data.supportedCodecs}
|
|
147
|
+
sampleRateHz={propertiesQuery.data.sampleRateHz}
|
|
148
|
+
numChannels={propertiesQuery.data.numChannels}
|
|
149
|
+
/>
|
|
150
|
+
{/if}
|
|
151
|
+
</Query>
|
|
152
|
+
</ApiSection>
|
|
153
|
+
</div>
|
|
152
154
|
</div>
|
|
153
155
|
</div>
|
|
154
156
|
{/snippet}
|
|
@@ -103,99 +103,101 @@
|
|
|
103
103
|
/>
|
|
104
104
|
</div>
|
|
105
105
|
|
|
106
|
-
<div class="
|
|
107
|
-
<div class="flex
|
|
108
|
-
<
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
<
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
106
|
+
<div class="@container">
|
|
107
|
+
<div class="flex flex-col divide-y @2xl:flex-row @2xl:divide-x @2xl:divide-y-0">
|
|
108
|
+
<div class="flex w-full flex-col divide-y">
|
|
109
|
+
<MutationSection
|
|
110
|
+
title="Play"
|
|
111
|
+
api="rdk:component:audio_output"
|
|
112
|
+
description="Send audio data to the device"
|
|
113
|
+
lastError={playContext.error}
|
|
114
|
+
>
|
|
115
|
+
<div class="flex flex-col gap-2">
|
|
116
|
+
<Label cx="gap-1 text-xs">
|
|
117
|
+
Audio file
|
|
118
|
+
<input
|
|
119
|
+
slot="input"
|
|
120
|
+
type="file"
|
|
121
|
+
accept={availableCodecs.map((c) => `.${c}`).join(',')}
|
|
122
|
+
class="text-xs"
|
|
123
|
+
onchange={handleFileChange}
|
|
124
|
+
/>
|
|
125
|
+
</Label>
|
|
126
|
+
{#if fileInputError}
|
|
127
|
+
<p class="text-xs text-red-500">{fileInputError}</p>
|
|
128
|
+
{/if}
|
|
129
|
+
{#if selectedFile}
|
|
130
|
+
<p class="font-roboto-mono text-subtle-1 text-xs">{selectedFile.name}</p>
|
|
131
|
+
{/if}
|
|
132
|
+
<Label cx="gap-1 text-xs">
|
|
133
|
+
Codec
|
|
134
|
+
<Select
|
|
135
|
+
slot="input"
|
|
136
|
+
value={selectedCodec}
|
|
137
|
+
on:change={(e) => {
|
|
138
|
+
playCodec = (e.target as HTMLSelectElement).value
|
|
139
|
+
}}
|
|
140
|
+
>
|
|
141
|
+
{#each availableCodecs as codec (codec)}
|
|
142
|
+
<option value={codec}>{codec}</option>
|
|
143
|
+
{/each}
|
|
144
|
+
</Select>
|
|
145
|
+
</Label>
|
|
146
|
+
<Label cx="gap-1 text-xs">
|
|
147
|
+
Sample rate (Hz)
|
|
148
|
+
<NumericInput
|
|
149
|
+
slot="input"
|
|
150
|
+
value={selectedSampleRateHz}
|
|
151
|
+
on:change={(e) => {
|
|
152
|
+
playSampleRateHz = numberValueFromEvent(e) ?? null
|
|
153
|
+
}}
|
|
154
|
+
/>
|
|
155
|
+
</Label>
|
|
156
|
+
<Label cx="gap-1 text-xs">
|
|
157
|
+
Channels
|
|
158
|
+
<NumericInput
|
|
159
|
+
slot="input"
|
|
160
|
+
value={selectedNumChannels}
|
|
161
|
+
on:change={(e) => {
|
|
162
|
+
playNumChannels = numberValueFromEvent(e) ?? null
|
|
163
|
+
}}
|
|
164
|
+
/>
|
|
165
|
+
</Label>
|
|
166
|
+
</div>
|
|
167
|
+
|
|
168
|
+
<div class="mt-auto">
|
|
169
|
+
<Button
|
|
170
|
+
icon="play-circle-outline"
|
|
171
|
+
onclick={play}
|
|
172
|
+
disabled={!client.current || playContext.status === 'playing'}
|
|
139
173
|
>
|
|
140
|
-
{
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}}
|
|
153
|
-
/>
|
|
154
|
-
</Label>
|
|
155
|
-
<Label cx="gap-1 text-xs">
|
|
156
|
-
Channels
|
|
157
|
-
<NumericInput
|
|
158
|
-
slot="input"
|
|
159
|
-
value={selectedNumChannels}
|
|
160
|
-
on:change={(e) => {
|
|
161
|
-
playNumChannels = numberValueFromEvent(e) ?? null
|
|
162
|
-
}}
|
|
163
|
-
/>
|
|
164
|
-
</Label>
|
|
165
|
-
</div>
|
|
166
|
-
|
|
167
|
-
<div class="mt-auto">
|
|
168
|
-
<Button
|
|
169
|
-
icon="play-circle-outline"
|
|
170
|
-
onclick={play}
|
|
171
|
-
disabled={!client.current || playContext.status === 'playing'}
|
|
172
|
-
>
|
|
173
|
-
{playButtonLabel}
|
|
174
|
-
</Button>
|
|
175
|
-
</div>
|
|
176
|
-
</MutationSection>
|
|
177
|
-
</div>
|
|
178
|
-
|
|
179
|
-
<div class="ml-auto flex w-full max-w-1/2 flex-col divide-y sm:max-w-1/3">
|
|
180
|
-
<ApiSection
|
|
181
|
-
title="GetProperties"
|
|
182
|
-
api="rdk:component:audio_output"
|
|
183
|
-
description="Audio output properties"
|
|
184
|
-
class="relative"
|
|
185
|
-
>
|
|
186
|
-
<Query
|
|
187
|
-
query={propertiesQuery}
|
|
188
|
-
contentCx="h-6"
|
|
174
|
+
{playButtonLabel}
|
|
175
|
+
</Button>
|
|
176
|
+
</div>
|
|
177
|
+
</MutationSection>
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
<div class="flex w-full flex-col divide-y @2xl:ml-auto @2xl:max-w-1/2 @4xl:max-w-1/3">
|
|
181
|
+
<ApiSection
|
|
182
|
+
title="GetProperties"
|
|
183
|
+
api="rdk:component:audio_output"
|
|
184
|
+
description="Audio output properties"
|
|
185
|
+
class="relative"
|
|
189
186
|
>
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
187
|
+
<Query
|
|
188
|
+
query={propertiesQuery}
|
|
189
|
+
contentCx="h-6"
|
|
190
|
+
>
|
|
191
|
+
{#if propertiesQuery.data !== undefined}
|
|
192
|
+
<Properties
|
|
193
|
+
supportedCodecs={propertiesQuery.data.supportedCodecs}
|
|
194
|
+
sampleRateHz={propertiesQuery.data.sampleRateHz}
|
|
195
|
+
numChannels={propertiesQuery.data.numChannels}
|
|
196
|
+
/>
|
|
197
|
+
{/if}
|
|
198
|
+
</Query>
|
|
199
|
+
</ApiSection>
|
|
200
|
+
</div>
|
|
199
201
|
</div>
|
|
200
202
|
</div>
|
|
201
203
|
{/snippet}
|
|
@@ -60,46 +60,48 @@
|
|
|
60
60
|
|
|
61
61
|
<ConnectionStatus {partID}>
|
|
62
62
|
{#snippet connected()}
|
|
63
|
-
<div class="
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
63
|
+
<div class="@container">
|
|
64
|
+
<div class="flex flex-col divide-y @4xl:flex-row @4xl:divide-x @4xl:divide-y-0">
|
|
65
|
+
<MutationSection
|
|
66
|
+
title="Quick move"
|
|
67
|
+
lastError={quickSetPowerMutation.error}
|
|
68
|
+
>
|
|
69
|
+
{#snippet titleInput()}
|
|
70
|
+
<Label>
|
|
71
|
+
Keyboard control
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
<Switch
|
|
74
|
+
slot="input"
|
|
75
|
+
on={quickMoveKeyboardControl}
|
|
76
|
+
on:change={() => (quickMoveKeyboardControl = !quickMoveKeyboardControl)}
|
|
77
|
+
/>
|
|
78
|
+
</Label>
|
|
79
|
+
{/snippet}
|
|
79
80
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
81
|
+
<QuickMove
|
|
82
|
+
isKeyboardEnabled={quickMoveKeyboardControl}
|
|
83
|
+
setPower={quickSetPower}
|
|
84
|
+
/>
|
|
85
|
+
</MutationSection>
|
|
86
|
+
<div class="flex grow flex-col divide-y @4xl:ml-auto @4xl:w-full @4xl:max-w-40">
|
|
87
|
+
<ApiSection
|
|
88
|
+
title="Stop"
|
|
89
|
+
api="rdk:component:base"
|
|
90
|
+
>
|
|
91
|
+
<StopButton
|
|
92
|
+
error={stopMutation.error}
|
|
93
|
+
onStop={() => {
|
|
94
|
+
stopMutation.mutate([])
|
|
95
|
+
}}
|
|
96
|
+
/>
|
|
97
|
+
</ApiSection>
|
|
98
|
+
<IsMoving
|
|
99
|
+
client={BaseClient}
|
|
100
|
+
api="rdk:component:base"
|
|
101
|
+
{partID}
|
|
102
|
+
{resourceName}
|
|
95
103
|
/>
|
|
96
|
-
</
|
|
97
|
-
<IsMoving
|
|
98
|
-
client={BaseClient}
|
|
99
|
-
api="rdk:component:base"
|
|
100
|
-
{partID}
|
|
101
|
-
{resourceName}
|
|
102
|
-
/>
|
|
104
|
+
</div>
|
|
103
105
|
</div>
|
|
104
106
|
</div>
|
|
105
107
|
<MutationSection
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
let angularPower = $state<Vector3>({ x: 0, y: 0, z: 0.75 })
|
|
16
16
|
</script>
|
|
17
17
|
|
|
18
|
-
<div class="flex flex-
|
|
18
|
+
<div class="flex flex-wrap gap-4">
|
|
19
19
|
<Vec3Builder
|
|
20
20
|
title="Linear power"
|
|
21
21
|
titleTooltip="The percentage of max power of the base’s linear propulsion. In the range of –1.0 to 1.0, with 1.0 meaning 100% power."
|