fragment-tools 0.1.13 → 0.1.14

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.
Files changed (52) hide show
  1. package/bin/index.js +2 -2
  2. package/package.json +4 -5
  3. package/src/cli/log.js +31 -21
  4. package/src/cli/plugins/check-dependencies.js +47 -30
  5. package/src/cli/plugins/hot-shader-replacement.js +384 -0
  6. package/src/cli/plugins/hot-sketch-reload.js +3 -13
  7. package/src/cli/plugins/screenshot.js +57 -20
  8. package/src/cli/server.js +144 -133
  9. package/src/client/app/App.svelte +3 -3
  10. package/src/client/app/client.js +55 -39
  11. package/src/client/app/components/Init.svelte +12 -9
  12. package/src/client/app/helpers.js +42 -0
  13. package/src/client/app/hooks.js +20 -0
  14. package/src/client/app/inputs/Keyboard.js +13 -15
  15. package/src/client/app/inputs/MIDI.js +14 -15
  16. package/src/client/app/lib/canvas-recorder/CanvasRecorder.js +41 -21
  17. package/src/client/app/lib/gl/Renderer.js +127 -139
  18. package/src/client/app/modules/Exports.svelte +62 -43
  19. package/src/client/app/modules/MidiPanel.svelte +100 -101
  20. package/src/client/app/modules/Params.svelte +116 -103
  21. package/src/client/app/renderers/2DRenderer.js +3 -3
  22. package/src/client/app/renderers/FragmentRenderer.js +30 -23
  23. package/src/client/app/renderers/P5Renderer.js +10 -7
  24. package/src/client/app/renderers/THREERenderer.js +136 -94
  25. package/src/client/app/stores/exports.js +36 -20
  26. package/src/client/app/stores/props.js +28 -5
  27. package/src/client/app/stores/renderers.js +22 -15
  28. package/src/client/app/stores/sketches.js +7 -9
  29. package/src/client/app/stores/utils.js +95 -38
  30. package/src/client/app/triggers/Keyboard.js +88 -79
  31. package/src/client/app/triggers/MIDI.js +110 -84
  32. package/src/client/app/ui/Field.svelte +343 -240
  33. package/src/client/app/ui/FieldGroup.svelte +106 -94
  34. package/src/client/app/ui/FieldSection.svelte +125 -116
  35. package/src/client/app/ui/ParamsMultisampling.svelte +96 -95
  36. package/src/client/app/ui/ParamsOutput.svelte +113 -113
  37. package/src/client/app/ui/SelectChevrons.svelte +27 -15
  38. package/src/client/app/ui/SketchRenderer.svelte +761 -667
  39. package/src/client/app/ui/fields/ButtonInput.svelte +61 -48
  40. package/src/client/app/ui/fields/CheckboxInput.svelte +67 -61
  41. package/src/client/app/ui/fields/ColorInput.svelte +294 -238
  42. package/src/client/app/ui/fields/ImageInput.svelte +123 -121
  43. package/src/client/app/ui/fields/Input.svelte +100 -111
  44. package/src/client/app/ui/fields/ListInput.svelte +96 -96
  45. package/src/client/app/ui/fields/NumberInput.svelte +121 -116
  46. package/src/client/app/ui/fields/ProgressInput.svelte +80 -73
  47. package/src/client/app/ui/fields/Select.svelte +137 -124
  48. package/src/client/app/ui/fields/VectorInput.svelte +86 -82
  49. package/src/client/app/utils/canvas.utils.js +228 -201
  50. package/src/client/app/utils/file.utils.js +38 -34
  51. package/src/client/public/css/global.css +27 -21
  52. package/src/cli/plugins/hot-shader-reload.js +0 -86
@@ -1,266 +1,369 @@
1
1
  <script>
2
- import { createEventDispatcher } from "svelte";
3
-
4
- import Select from "./fields/Select.svelte";
5
- import NumberInput from "./fields/NumberInput.svelte";
6
- import CheckboxInput from "./fields/CheckboxInput.svelte";
7
- import VectorInput from "./fields/VectorInput.svelte";
8
- import TextInput from "./fields/TextInput.svelte";
9
- import ColorInput from "./fields/ColorInput.svelte";
10
- import ListInput from "./fields/ListInput.svelte";
11
- import ButtonInput from "./fields/ButtonInput.svelte";
12
- import ImageInput from "./fields/ImageInput.svelte";
13
- import FieldSection from "./FieldSection.svelte";
14
- import FieldTriggers from "./FieldTriggers.svelte";
15
- import { inferFromParams, inferFromValue } from "../utils/props.utils.js";
16
- import { download } from "../utils/file.utils.js";
17
- import { map } from "../utils/math.utils";
18
- import frameDebounce from "../lib/helpers/frameDebounce.js";
19
- import { getStore } from "../stores/utils";
20
- import { writable } from "svelte/store";
21
-
22
- export let key = "";
23
- export let value = null;
24
- export let context = null;
25
- export let params = {};
26
- export let type = null;
27
-
28
- let offsetWidth;
29
- let showTriggers = false;
30
-
31
- const store = getStore(context, { props: {}}, {
32
- persist: context !== null,
33
- });
34
-
35
- if (!$store.props[key]) {
36
- $store.props[key] = { triggers: [] };
37
- }
38
-
39
- let triggers = writable($store.props[key].triggers.filter((trigger) => trigger.inputType !== undefined));
40
- triggers.subscribe((all) => {
41
- store.update((curr) => {
42
- curr.props[key].triggers = all;
43
-
44
- return curr;
45
- });
46
- })
47
-
48
- const dispatch = createEventDispatcher();
49
- const fields = {
50
- "select": Select,
51
- "number": NumberInput,
52
- "vec": VectorInput,
53
- "checkbox": CheckboxInput,
54
- "text": TextInput,
55
- "list": ListInput,
56
- "color": ColorInput,
57
- "button": ButtonInput,
58
- "download": ButtonInput,
59
- "image": ImageInput,
60
- };
61
-
62
- const onTriggers = {
63
- 'checkbox': () => {
64
- value = !value;
65
-
66
- dispatch('change', value);
67
- },
68
- 'button': (event) => {
69
- value(event);
70
- dispatch('click', event);
71
- },
72
- 'download': (event) => {
73
- let [data, filename] = value(event);
74
-
75
- download(data, filename);
76
- },
77
- 'number': (event = {}) => {
78
- const isValueInRange = event.value >= 0 && event.value <= 1;
79
-
80
- if (isValueInRange && isFinite(params.min) && isFinite(params.max)) {
81
- let v = map(event.value, 0, 1, params.min, params.max);
82
- let step = params.step ? params.step : 1;
83
- let value = Math.round(v * (1 / step)) / (1 / step);
84
-
85
- dispatch('change', value);
86
- }
87
- },
88
- };
89
-
90
- $: fieldType = type ? type : (inferFromParams(params) || inferFromValue(value));
91
- $: fieldProps = composeFieldProps(params);
92
- $: onTrigger = frameDebounce(onTriggers[fieldType]);
93
- $: input = fields[fieldType];
94
- $: label = params.label !== undefined && typeof value !== "function" ? params.label : key;
95
- $: disabled = params.disabled;
96
- $: triggerable = params.triggerable !== false && (
97
- (fieldType === "number" && isFinite(params.min) && isFinite(params.max)) ||
98
- (fieldType === "button")
99
- );
100
- $: {
101
- if (fieldType === "download" || fieldType === "button") {
102
- if (params.label === undefined) {
103
- fieldProps.label = fieldType === "download" ? "download" : "run";
104
- }
105
- }
106
- }
107
- $: xxsmall = offsetWidth < 200;
108
- $: xsmall = !xxsmall && offsetWidth < 260;
109
- $: small = !xxsmall && !xsmall && offsetWidth < 320;
110
- $: triggersActive = $triggers.length > 0;
111
-
112
- function toggleTriggers(event) {
113
- event.preventDefault();
114
-
115
- showTriggers = !showTriggers;
116
- }
117
-
118
- function composeFieldProps(params) {
119
- const { triggerable, controllable, ...rest } = params;
120
-
121
- return {
122
- ...rest,
123
- key,
124
- context,
125
- };
126
- }
127
-
2
+ import { createEventDispatcher } from 'svelte';
3
+
4
+ import Select from './fields/Select.svelte';
5
+ import NumberInput from './fields/NumberInput.svelte';
6
+ import CheckboxInput from './fields/CheckboxInput.svelte';
7
+ import VectorInput from './fields/VectorInput.svelte';
8
+ import TextInput from './fields/TextInput.svelte';
9
+ import ColorInput from './fields/ColorInput.svelte';
10
+ import ListInput from './fields/ListInput.svelte';
11
+ import ButtonInput from './fields/ButtonInput.svelte';
12
+ import ImageInput from './fields/ImageInput.svelte';
13
+ import FieldSection from './FieldSection.svelte';
14
+ import FieldTriggers from './FieldTriggers.svelte';
15
+ import { inferFromParams, inferFromValue } from '../utils/props.utils.js';
16
+ import { download } from '../utils/file.utils.js';
17
+ import { map } from '../utils/math.utils';
18
+ import frameDebounce from '../lib/helpers/frameDebounce.js';
19
+ import { getStore } from '../stores/utils';
20
+ import { writable } from 'svelte/store';
21
+
22
+ export let key = '';
23
+ export let value = null;
24
+ export let context = null;
25
+ export let params = {};
26
+ export let type = null;
27
+ export let disabled = false;
28
+ export let displayName = undefined;
29
+
30
+ let offsetWidth;
31
+ let showTriggers = false;
32
+
33
+ const store = getStore(
34
+ context,
35
+ { props: {} },
36
+ {
37
+ persist: context !== null,
38
+ },
39
+ );
40
+
41
+ if (!$store.props[key]) {
42
+ $store.props[key] = { triggers: [] };
43
+ }
44
+
45
+ let triggers = writable(
46
+ $store.props[key].triggers.filter(
47
+ (trigger) => trigger.inputType !== undefined,
48
+ ),
49
+ );
50
+ triggers.subscribe((all) => {
51
+ store.update((curr) => {
52
+ curr.props[key].triggers = all;
53
+
54
+ return curr;
55
+ });
56
+ });
57
+
58
+ const dispatch = createEventDispatcher();
59
+ const fields = {
60
+ select: Select,
61
+ number: NumberInput,
62
+ vec: VectorInput,
63
+ checkbox: CheckboxInput,
64
+ text: TextInput,
65
+ list: ListInput,
66
+ color: ColorInput,
67
+ button: ButtonInput,
68
+ download: ButtonInput,
69
+ image: ImageInput,
70
+ };
71
+
72
+ const onTriggers = {
73
+ checkbox: () => {
74
+ value = !value;
75
+
76
+ dispatch('change', value);
77
+ },
78
+ button: (event) => {
79
+ value(event);
80
+ dispatch('click', event);
81
+ },
82
+ download: (event) => {
83
+ let [data, filename] = value(event);
84
+
85
+ download(data, filename);
86
+ },
87
+ number: (event = {}) => {
88
+ const isValueInRange = event.value >= 0 && event.value <= 1;
89
+
90
+ if (
91
+ isValueInRange &&
92
+ isFinite(params.min) &&
93
+ isFinite(params.max)
94
+ ) {
95
+ let v = map(event.value, 0, 1, params.min, params.max);
96
+ let step = params.step ? params.step : 1;
97
+ let value = Math.round(v * (1 / step)) / (1 / step);
98
+
99
+ dispatch('change', value);
100
+ }
101
+ },
102
+ };
103
+
104
+ $: fieldType = type
105
+ ? type
106
+ : inferFromParams(params) || inferFromValue(value);
107
+ $: fieldProps = composeFieldProps(params, disabled);
108
+ $: onTrigger = frameDebounce(onTriggers[fieldType]);
109
+ $: input = fields[fieldType];
110
+ $: triggerable =
111
+ params.triggerable !== false &&
112
+ ((fieldType === 'number' &&
113
+ isFinite(params.min) &&
114
+ isFinite(params.max)) ||
115
+ fieldType === 'button');
116
+ $: {
117
+ if (fieldType === 'download' || fieldType === 'button') {
118
+ if (params.label === undefined) {
119
+ fieldProps.label =
120
+ fieldType === 'download' ? 'download' : 'run';
121
+ }
122
+ }
123
+ }
124
+ $: xxsmall = offsetWidth < 200;
125
+ $: xsmall = !xxsmall && offsetWidth < 260;
126
+ $: small = !xxsmall && !xsmall && offsetWidth < 320;
127
+ $: triggersActive = $triggers.length > 0;
128
+
129
+ function toggleTriggers(event) {
130
+ event.preventDefault();
131
+
132
+ showTriggers = !showTriggers;
133
+ }
134
+
135
+ function composeFieldProps(params, disabled) {
136
+ const { triggerable, controllable, ...rest } = params;
137
+
138
+ return {
139
+ ...rest,
140
+ disabled,
141
+ key,
142
+ context,
143
+ };
144
+ }
128
145
  </script>
129
146
 
130
- <div class="field"
131
- class:disabled={disabled}
132
- class:xxsmall={xxsmall}
133
- class:xsmall={xsmall}
134
- class:small={small}
135
- bind:offsetWidth={offsetWidth}
147
+ <div
148
+ class="field"
149
+ class:disabled
150
+ class:xxsmall
151
+ class:xsmall
152
+ class:small
153
+ bind:offsetWidth
136
154
  >
137
- <FieldSection name={key} label={label} interactive={triggerable} on:click={toggleTriggers}>
138
- <div slot="infos" class="field__actions">
139
- {#if triggerable && !disabled }
140
- <button
141
- on:click={toggleTriggers}
142
- class="field__action field__action--triggers"
143
- class:active={triggersActive}>
144
- <svg width="16" height="16" fill="none" viewBox="0 0 24 24">
145
- <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M4.75 8H7.25"/>
146
- <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12.75 8H19.25"/>
147
- <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M4.75 16H12.25"/>
148
- <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M17.75 16H19.25"/>
149
- <circle cx="10" cy="8" r="2.25" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
150
- <circle cx="15" cy="16" r="2.25" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
151
- </svg>
152
- </button>
153
- {/if}
154
- {#if (fieldType === "vec") && !disabled }
155
- <button class="field__action field__action--lock" on:click={() => params.locked = !params.locked}>
156
- {#if params.locked}
157
- <svg class="action__icon" width="16" height="16" fill="none" viewBox="0 0 24 24">
158
- <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M5.75 11.75C5.75 11.1977 6.19772 10.75 6.75 10.75H17.25C17.8023 10.75 18.25 11.1977 18.25 11.75V17.25C18.25 18.3546 17.3546 19.25 16.25 19.25H7.75C6.64543 19.25 5.75 18.3546 5.75 17.25V11.75Z"></path>
159
- <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M7.75 10.5V10.3427C7.75 8.78147 7.65607 7.04125 8.74646 5.9239C9.36829 5.2867 10.3745 4.75 12 4.75C13.6255 4.75 14.6317 5.2867 15.2535 5.9239C16.3439 7.04125 16.25 8.78147 16.25 10.3427V10.5"></path>
160
- </svg>
161
- {:else}
162
- <svg class="action__icon" width="16" height="16" fill="none" viewBox="0 0 24 24">
163
- <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M5.75 11.75C5.75 11.1977 6.19772 10.75 6.75 10.75H17.25C17.8023 10.75 18.25 11.1977 18.25 11.75V17.25C18.25 18.3546 17.3546 19.25 16.25 19.25H7.75C6.64543 19.25 5.75 18.3546 5.75 17.25V11.75Z"></path>
164
- <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M7.75 10.5V9.84343C7.75 8.61493 7.70093 7.29883 8.42416 6.30578C8.99862 5.51699 10.0568 4.75 12 4.75C14 4.75 15.25 6.25 15.25 6.25"></path>
165
- </svg>
166
- {/if}
167
- </button>
168
- {/if}
169
- </div>
170
- <svelte:component
171
- this={input}
172
- {value}
173
- {...fieldProps}
174
- on:change
175
- on:click={onTrigger}
176
- />
177
- <slot></slot>
178
- </FieldSection>
179
- {#if triggerable }
180
- <FieldSection visible={showTriggers} secondary>
181
- <FieldTriggers
182
- {triggers}
183
- {onTrigger}
184
- {context}
185
- triggerable={fieldType === "button"}
186
- controllable={fieldType === "number"}
187
- />
188
- </FieldSection>
189
- {/if}
155
+ <FieldSection
156
+ {key}
157
+ {displayName}
158
+ interactive={triggerable}
159
+ on:click={toggleTriggers}
160
+ {disabled}
161
+ >
162
+ <div slot="infos" class="field__actions">
163
+ {#if triggerable && !disabled}
164
+ <button
165
+ on:click={toggleTriggers}
166
+ class="field__action field__action--triggers"
167
+ class:active={triggersActive}
168
+ >
169
+ <svg width="16" height="16" fill="none" viewBox="0 0 24 24">
170
+ <path
171
+ stroke="currentColor"
172
+ stroke-linecap="round"
173
+ stroke-linejoin="round"
174
+ stroke-width="1.5"
175
+ d="M4.75 8H7.25"
176
+ />
177
+ <path
178
+ stroke="currentColor"
179
+ stroke-linecap="round"
180
+ stroke-linejoin="round"
181
+ stroke-width="1.5"
182
+ d="M12.75 8H19.25"
183
+ />
184
+ <path
185
+ stroke="currentColor"
186
+ stroke-linecap="round"
187
+ stroke-linejoin="round"
188
+ stroke-width="1.5"
189
+ d="M4.75 16H12.25"
190
+ />
191
+ <path
192
+ stroke="currentColor"
193
+ stroke-linecap="round"
194
+ stroke-linejoin="round"
195
+ stroke-width="1.5"
196
+ d="M17.75 16H19.25"
197
+ />
198
+ <circle
199
+ cx="10"
200
+ cy="8"
201
+ r="2.25"
202
+ stroke="currentColor"
203
+ stroke-linecap="round"
204
+ stroke-linejoin="round"
205
+ stroke-width="1.5"
206
+ />
207
+ <circle
208
+ cx="15"
209
+ cy="16"
210
+ r="2.25"
211
+ stroke="currentColor"
212
+ stroke-linecap="round"
213
+ stroke-linejoin="round"
214
+ stroke-width="1.5"
215
+ />
216
+ </svg>
217
+ </button>
218
+ {/if}
219
+ {#if fieldType === 'vec' && !disabled}
220
+ <button
221
+ class="field__action field__action--lock"
222
+ on:click={() => (params.locked = !params.locked)}
223
+ >
224
+ {#if params.locked}
225
+ <svg
226
+ class="action__icon"
227
+ width="16"
228
+ height="16"
229
+ fill="none"
230
+ viewBox="0 0 24 24"
231
+ >
232
+ <path
233
+ stroke="currentColor"
234
+ stroke-linecap="round"
235
+ stroke-linejoin="round"
236
+ stroke-width="1.5"
237
+ d="M5.75 11.75C5.75 11.1977 6.19772 10.75 6.75 10.75H17.25C17.8023 10.75 18.25 11.1977 18.25 11.75V17.25C18.25 18.3546 17.3546 19.25 16.25 19.25H7.75C6.64543 19.25 5.75 18.3546 5.75 17.25V11.75Z"
238
+ />
239
+ <path
240
+ stroke="currentColor"
241
+ stroke-linecap="round"
242
+ stroke-linejoin="round"
243
+ stroke-width="1.5"
244
+ d="M7.75 10.5V10.3427C7.75 8.78147 7.65607 7.04125 8.74646 5.9239C9.36829 5.2867 10.3745 4.75 12 4.75C13.6255 4.75 14.6317 5.2867 15.2535 5.9239C16.3439 7.04125 16.25 8.78147 16.25 10.3427V10.5"
245
+ />
246
+ </svg>
247
+ {:else}
248
+ <svg
249
+ class="action__icon"
250
+ width="16"
251
+ height="16"
252
+ fill="none"
253
+ viewBox="0 0 24 24"
254
+ >
255
+ <path
256
+ stroke="currentColor"
257
+ stroke-linecap="round"
258
+ stroke-linejoin="round"
259
+ stroke-width="1.5"
260
+ d="M5.75 11.75C5.75 11.1977 6.19772 10.75 6.75 10.75H17.25C17.8023 10.75 18.25 11.1977 18.25 11.75V17.25C18.25 18.3546 17.3546 19.25 16.25 19.25H7.75C6.64543 19.25 5.75 18.3546 5.75 17.25V11.75Z"
261
+ />
262
+ <path
263
+ stroke="currentColor"
264
+ stroke-linecap="round"
265
+ stroke-linejoin="round"
266
+ stroke-width="1.5"
267
+ d="M7.75 10.5V9.84343C7.75 8.61493 7.70093 7.29883 8.42416 6.30578C8.99862 5.51699 10.0568 4.75 12 4.75C14 4.75 15.25 6.25 15.25 6.25"
268
+ />
269
+ </svg>
270
+ {/if}
271
+ </button>
272
+ {/if}
273
+ </div>
274
+ <svelte:component
275
+ this={input}
276
+ {value}
277
+ {...fieldProps}
278
+ on:change
279
+ on:click={onTrigger}
280
+ />
281
+ <slot />
282
+ </FieldSection>
283
+ {#if triggerable}
284
+ <FieldSection {key} visible={showTriggers} secondary>
285
+ <FieldTriggers
286
+ {triggers}
287
+ {onTrigger}
288
+ {context}
289
+ triggerable={fieldType === 'button'}
290
+ controllable={fieldType === 'number'}
291
+ />
292
+ </FieldSection>
293
+ {/if}
190
294
  </div>
191
295
 
192
296
  <style>
193
- .field {
194
- --column-gap: 3px;
195
- --padding: 6px;
297
+ .field {
298
+ --column-gap: 3px;
299
+ --padding: 6px;
196
300
 
197
- width: 100%;
301
+ width: 100%;
198
302
 
199
- padding: 3px 6px 3px 12px;
200
- border-bottom: 1px solid var(--color-spacing);
201
- }
303
+ padding: 3px 6px 3px 12px;
304
+ border-bottom: 1px solid var(--color-spacing);
305
+ }
202
306
 
203
- :global(.field__input .field) {
204
- padding-left: 0px !important;
205
- padding-right: 0px !important;
206
- }
307
+ :global(.field__input .field) {
308
+ padding-left: 0px !important;
309
+ padding-right: 0px !important;
310
+ }
207
311
 
208
- :global(.field__input .field:last-child) {
209
- border-bottom: 0px solid #323233 !important;
210
- padding-bottom: 0px !important;
211
-
212
- }
312
+ :global(.field__input .field:last-child) {
313
+ border-bottom: 0px solid #323233 !important;
314
+ padding-bottom: 0px !important;
315
+ }
213
316
 
214
- .field.disabled {
215
- pointer-events: none;
216
- }
317
+ .field.disabled {
318
+ pointer-events: none;
319
+ }
217
320
 
218
- .field__actions {
219
- display: flex;
220
- align-items: center;
221
- }
321
+ .field__actions {
322
+ display: flex;
323
+ align-items: center;
324
+ }
222
325
 
223
- .field__action {
224
- display: flex;
225
- align-items: center;
326
+ .field__action {
327
+ display: flex;
328
+ align-items: center;
226
329
 
227
- background: transparent;
228
- transition: opacity 0.1s ease;
229
- }
330
+ background: transparent;
331
+ transition: opacity 0.1s ease;
332
+ }
230
333
 
231
- .field__action:hover {
232
- opacity: 1;
233
- }
334
+ .field__action:hover {
335
+ opacity: 1;
336
+ }
234
337
 
235
- .field__action--triggers {
236
- --background-color: rgba(255, 255, 255, 0.5);
338
+ .field__action--triggers {
339
+ --background-color: rgba(255, 255, 255, 0.5);
237
340
 
238
- position: relative;
341
+ position: relative;
239
342
 
240
- width: 16px;
241
- height: 16px;
343
+ width: 16px;
344
+ height: 16px;
242
345
 
243
- background-color: transparent;
244
- cursor: pointer;
245
- }
346
+ background-color: transparent;
347
+ cursor: pointer;
348
+ }
246
349
 
247
- .field__action--triggers:not(.active) {
248
- display: none;
249
- }
350
+ .field__action--triggers:not(.active) {
351
+ display: none;
352
+ }
250
353
 
251
- .field__action {
252
- color: var(--color-text);
354
+ .field__action {
355
+ color: var(--color-text);
253
356
 
254
- opacity: 0.6;
255
- background-color: transparent;
256
- transition: opacity 0.1s ease;
257
- }
357
+ opacity: 0.6;
358
+ background-color: transparent;
359
+ transition: opacity 0.1s ease;
360
+ }
258
361
 
259
- .field__action--triggers svg {
260
- transform: rotate(90deg);
261
- }
362
+ .field__action--triggers svg {
363
+ transform: rotate(90deg);
364
+ }
262
365
 
263
- .field__action:hover {
264
- opacity: 1;
265
- }
366
+ .field__action:hover {
367
+ opacity: 1;
368
+ }
266
369
  </style>