@olares/lares-mobile 0.15.7 → 0.15.9

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.
@@ -4,6 +4,8 @@
4
4
  class="lares-composer__card"
5
5
  data-composer-card
6
6
  :data-hero="hero ? 'true' : 'false'"
7
+ :data-mode="inputMode"
8
+ :data-expanded="expanded ? 'true' : 'false'"
7
9
  :data-holding="holding ? 'true' : 'false'"
8
10
  >
9
11
  <div v-if="referenceOpen" ref="referenceMenu" class="lares-composer__menu" role="listbox">
@@ -80,56 +82,53 @@
80
82
  </button>
81
83
  </figure>
82
84
  </div>
83
- <textarea
84
- ref="input"
85
- :value="draft"
86
- class="lares-composer__input"
87
- rows="1"
88
- :placeholder="placeholder"
89
- :disabled="sending"
90
- @input="onInput"
91
- @keydown="onKeydown"
92
- @click="onCaretMove"
93
- @keyup="onCaretMove"
94
- @select="onCaretMove"
95
- @pointerdown="onHoldDown"
96
- @pointerup="onHoldUp"
97
- @pointercancel="onHoldUp"
98
- @contextmenu="onContextMenu"
99
- />
100
- <p v-if="holding" class="lares-composer__hold">{{ t("composer.hold") }} · {{ elapsed }}</p>
101
- <div class="lares-composer__bar">
102
- <div v-if="!hero" class="lares-composer__pills">
103
- <button
104
- type="button"
105
- class="lares-composer__pill"
106
- :disabled="modelBusy"
107
- :aria-label="modelAria"
108
- @click="$emit('model')"
109
- >
110
- <svg viewBox="0 0 24 24" aria-hidden="true">
111
- <rect x="4" y="5" width="16" height="5" rx="1.2" />
112
- <rect x="4" y="14" width="16" height="5" rx="1.2" />
113
- </svg>
114
- <span>{{ modelLabel }}</span>
115
- </button>
116
- <button
117
- v-if="!effortDisabled"
118
- type="button"
119
- class="lares-composer__pill"
120
- :disabled="modelBusy"
121
- :aria-label="effortAria"
122
- @click="$emit('effort')"
123
- >
124
- <svg viewBox="0 0 24 24" aria-hidden="true">
125
- <circle class="lares-composer__nucleus" cx="12" cy="12" r="2.5" />
126
- <ellipse cx="12" cy="12" rx="9.2" ry="3.8" />
127
- <ellipse cx="12" cy="12" rx="9.2" ry="3.8" transform="rotate(60 12 12)" />
128
- <ellipse cx="12" cy="12" rx="9.2" ry="3.8" transform="rotate(-60 12 12)" />
85
+ <div class="lares-composer__line" :data-expanded="expanded ? 'true' : 'false'">
86
+ <button
87
+ type="button"
88
+ class="lares-composer__icon"
89
+ data-kind="attach"
90
+ :disabled="attachDisabled"
91
+ :aria-label="attachLabel"
92
+ @click="pickFiles"
93
+ >
94
+ <svg viewBox="0 0 24 24" aria-hidden="true">
95
+ <path d="M12 5v14M5 12h14" />
96
+ </svg>
97
+ </button>
98
+ <textarea
99
+ v-show="inputMode === 'text'"
100
+ ref="input"
101
+ :value="draft"
102
+ class="lares-composer__input"
103
+ rows="1"
104
+ :placeholder="placeholder"
105
+ :disabled="sending"
106
+ @input="onInput"
107
+ @keydown="onKeydown"
108
+ @click="onCaretMove"
109
+ @keyup="onCaretMove"
110
+ @select="onCaretMove"
111
+ @contextmenu="onContextMenu"
112
+ />
113
+ <button
114
+ v-show="inputMode === 'voice'"
115
+ type="button"
116
+ class="lares-composer__talk"
117
+ :data-phase="voicePhase"
118
+ :disabled="voiceBlocked"
119
+ :aria-label="voiceLabel"
120
+ @pointerdown="onVoiceDown"
121
+ @touchstart.prevent="onVoiceTouchStart"
122
+ @contextmenu.prevent
123
+ >
124
+ <span v-if="voicePhase === 'preparing' || voicePhase === 'transcribing'" class="lares-composer__talk-status">
125
+ <svg class="lares-composer__spin" viewBox="0 0 16 16" aria-hidden="true">
126
+ <circle cx="8" cy="8" r="6" />
129
127
  </svg>
130
- <span>{{ effortLabel }}</span>
131
- </button>
132
- </div>
128
+ <span>{{ talkLabel }}</span>
129
+ </span>
130
+ <span v-else>{{ talkLabel }}</span>
131
+ </button>
133
132
  <div class="lares-composer__tools">
134
133
  <input
135
134
  ref="picker"
@@ -139,17 +138,22 @@
139
138
  @change="onFiles"
140
139
  />
141
140
  <button
141
+ v-if="inputMode === 'text'"
142
142
  type="button"
143
143
  class="lares-composer__icon"
144
- :disabled="attachDisabled"
145
- :aria-label="attachLabel"
146
- @click="pickFiles"
144
+ data-kind="voice"
145
+ :disabled="sending"
146
+ :aria-label="t('composer.voice')"
147
+ @click="setMode('voice')"
147
148
  >
148
- <svg viewBox="0 0 24 24" aria-hidden="true">
149
- <path d="M12 5v14M5 12h14" />
149
+ <svg class="lares-composer__wave" viewBox="0 0 24 24" aria-hidden="true">
150
+ <path d="M5 8v8" />
151
+ <path d="M12 5v14" />
152
+ <path d="M19 8v8" />
150
153
  </svg>
151
154
  </button>
152
155
  <button
156
+ v-if="expanded"
153
157
  type="submit"
154
158
  class="lares-composer__icon"
155
159
  data-kind="send"
@@ -157,35 +161,27 @@
157
161
  :aria-label="t('chat.send')"
158
162
  >
159
163
  <svg viewBox="0 0 24 24" aria-hidden="true">
160
- <path d="M12 19V7M6.5 12.5 12 7l5.5 5.5" />
164
+ <path d="M12 19V5M5 12.5 12 5l7 7.5" />
161
165
  </svg>
162
166
  </button>
163
- <!-- Voice input parked.
164
167
  <button
165
- v-if="!showSend"
168
+ v-if="inputMode === 'voice'"
166
169
  type="button"
167
170
  class="lares-composer__icon"
168
- data-kind="voice"
169
- :data-phase="voicePhase"
170
- :disabled="voiceBlocked"
171
- :aria-label="voiceLabel"
172
- @click="$emit('voice')"
171
+ data-kind="keyboard"
172
+ :disabled="voiceBusy"
173
+ :aria-label="t('composer.keyboard')"
174
+ @click="setMode('text')"
173
175
  >
174
- <span v-if="voicePhase === 'recording'" class="lares-composer__live">{{ elapsed }}</span>
175
- <svg v-else-if="voicePhase === 'transcribing'" class="lares-composer__spin" viewBox="0 0 16 16" aria-hidden="true">
176
- <circle cx="8" cy="8" r="6" />
177
- </svg>
178
- <svg v-else class="lares-composer__wave" viewBox="0 0 24 24" aria-hidden="true">
179
- <path d="M6.5 9v6" />
180
- <path d="M12 4.5v15" />
181
- <path d="M17.5 9v6" />
176
+ <svg viewBox="0 0 24 24" aria-hidden="true">
177
+ <rect x="3.5" y="6" width="17" height="12" rx="2" />
178
+ <path d="M7 10h2M11 10h2M15 10h2M8 14h8" />
182
179
  </svg>
183
180
  </button>
184
- -->
185
181
  </div>
186
182
  </div>
187
183
  </div>
188
- <!-- <p v-if="voiceError" class="lares-composer__hint" data-status="error">{{ voiceError }}</p> -->
184
+ <p v-if="voiceError && voicePhase === 'error'" class="lares-composer__hint" data-status="error">{{ voiceError }}</p>
189
185
  <p v-for="item in failures" :key="item.id" class="lares-composer__hint" data-status="error">
190
186
  {{ t("upload.failed", { name: item.name, reason: t(`error.${item.code}`) }) }}
191
187
  </p>
@@ -204,18 +200,12 @@ import {
204
200
  } from "./composer-tokens.js";
205
201
  import { draftImageStatus } from "@olares/lares-core/files/draft-images";
206
202
 
207
- const HOLD_MS = 240;
208
-
209
203
  export default {
210
204
  name: "LaresComposer",
211
205
  props: {
212
206
  draft: { type: String, default: "" },
213
207
  sending: { type: Boolean, default: false },
214
208
  canSend: { type: Boolean, default: false },
215
- modelLabel: { type: String, default: "" },
216
- modelBusy: { type: Boolean, default: false },
217
- effortLabel: { type: String, default: "" },
218
- effortDisabled: { type: Boolean, default: false },
219
209
  attachPending: { type: Boolean, default: false },
220
210
  attachDisabled: { type: Boolean, default: false },
221
211
  voicePhase: { type: String, default: "idle" },
@@ -229,16 +219,16 @@ export default {
229
219
  commands: { type: Array, default: null },
230
220
  commandsError: { type: String, default: "" },
231
221
  hero: { type: Boolean, default: false },
222
+ inputMode: { type: String, default: "text" },
232
223
  t: { type: Function, required: true },
233
224
  },
234
225
  emits: [
235
- "update:draft", "send", "model", "effort", "files", "voice", "hold-start", "hold-end",
226
+ "update:draft", "update:inputMode", "send", "files", "voice", "hold-start", "hold-end",
236
227
  "open-commands", "open-references", "pick-command", "remove-image",
237
228
  ],
238
229
  data() {
239
230
  return {
240
231
  holding: false,
241
- holdTimer: 0,
242
232
  commandsOpen: false,
243
233
  commandTyped: false,
244
234
  commandIndex: 0,
@@ -249,17 +239,20 @@ export default {
249
239
  };
250
240
  },
251
241
  computed: {
252
- showSend() {
253
- return Boolean(this.draft.trim()) && this.voicePhase !== "recording" && !this.holding;
254
- },
255
242
  elapsed() {
256
243
  return formatElapsed(this.voiceElapsed);
257
244
  },
258
- modelAria() {
259
- return this.modelLabel ? this.t("model.switchAria", { label: this.modelLabel }) : this.t("model.select");
245
+ talkLabel() {
246
+ if (this.voicePhase === "preparing") return this.t("composer.opening");
247
+ if (this.voicePhase === "recording") return `${this.t("composer.hold")} · ${this.elapsed}`;
248
+ if (this.voicePhase === "transcribing") return this.t("mic.transcribing");
249
+ if (this.holding) return this.t("composer.hold");
250
+ return this.t("composer.holdToTalk");
260
251
  },
261
- effortAria() {
262
- return this.t("reasoning.switchAria", { label: this.effortLabel || this.t("reasoning.default") });
252
+ voiceBusy() {
253
+ return this.voicePhase === "preparing"
254
+ || this.voicePhase === "recording"
255
+ || this.voicePhase === "transcribing";
263
256
  },
264
257
  attachLabel() {
265
258
  return this.attachPending ? this.t("button.uploading", { count: 1 }) : this.t("composer.attach");
@@ -269,14 +262,18 @@ export default {
269
262
  return this.t("chat.placeholder");
270
263
  },
271
264
  voiceLabel() {
272
- if (this.voiceError) return this.voiceError;
273
- if (this.voicePhase === "recording") return this.t("mic.stop");
265
+ if (this.voicePhase === "error" && this.voiceError) return this.voiceError;
266
+ if (this.voicePhase === "preparing") return this.t("composer.opening");
267
+ if (this.voicePhase === "recording") return this.t("composer.hold");
274
268
  if (this.voicePhase === "transcribing") return this.t("mic.transcribing");
275
269
  return this.t("composer.voice");
276
270
  },
277
271
  voiceBlocked() {
278
272
  return this.voicePhase === "transcribing" || this.sending;
279
273
  },
274
+ expanded() {
275
+ return this.inputMode === "text" && (this.draft.trim().length > 0 || this.draftImages.length > 0);
276
+ },
280
277
  referenceMenuRows() {
281
278
  return referenceRows(this.references, this.t);
282
279
  },
@@ -288,8 +285,9 @@ export default {
288
285
  },
289
286
  },
290
287
  watch: {
291
- draft() {
288
+ draft(value) {
292
289
  this.autosize();
290
+ if (value && this.inputMode === "voice" && !this.voiceBusy) this.setMode("text");
293
291
  },
294
292
  overlayPointerActive(active) {
295
293
  if (active) window.addEventListener("pointerdown", this.onTokenPointer, true);
@@ -385,6 +383,18 @@ export default {
385
383
  imageStatus(image) {
386
384
  return draftImageStatus(image);
387
385
  },
386
+ setMode(mode) {
387
+ if (mode === this.inputMode) return;
388
+ if (mode === "text" && this.voiceBusy) return;
389
+ if (mode === "voice") {
390
+ this.closeReferences();
391
+ this.commandsOpen = false;
392
+ this.commandTyped = false;
393
+ this.$refs.input?.blur();
394
+ }
395
+ this.$emit("update:inputMode", mode);
396
+ if (mode === "text") this.$nextTick(() => this.focus());
397
+ },
388
398
  onSend() {
389
399
  if (this.referenceOpen || this.commandsOpen) return;
390
400
  if (this.canSend) this.$emit("send");
@@ -432,40 +442,59 @@ export default {
432
442
  event.preventDefault();
433
443
  this.onSend();
434
444
  },
435
- canHold(event) {
436
- // Voice input parked (hold-to-record).
437
- return false;
438
- if (this.draft.trim() || this.sending || this.voiceBlocked) return false;
439
- if (event.pointerType === "mouse") return false;
440
- return true;
441
- },
442
445
  onContextMenu(event) {
443
446
  if (typeof window !== "undefined" && window.matchMedia?.("(pointer: coarse)").matches) {
444
447
  event.preventDefault();
445
448
  }
446
449
  },
447
- onHoldDown(event) {
448
- if (!this.canHold(event)) return;
450
+ onVoiceDown(event) {
451
+ if (event.pointerType === "touch") return;
452
+ if (event.button > 0 || this.voiceBlocked || this.holding) return;
453
+ event.preventDefault();
449
454
  event.currentTarget.setPointerCapture?.(event.pointerId);
450
- this.holdTimer = window.setTimeout(() => {
451
- this.holding = true;
452
- this.$refs.input?.blur();
453
- this.$emit("hold-start");
454
- }, HOLD_MS);
455
- },
456
- onHoldUp(event) {
457
- event.currentTarget.releasePointerCapture?.(event.pointerId);
458
- this.clearHold(true);
459
- },
460
- clearHold(emitEnd = false) {
461
- if (this.holdTimer) {
462
- clearTimeout(this.holdTimer);
463
- this.holdTimer = 0;
464
- }
465
- if (this.holding) {
455
+ this.beginHold("mouse");
456
+ },
457
+ onVoiceTouchStart() {
458
+ if (this.voiceBlocked || this.holdKind === "touch") return;
459
+ this.beginHold("touch");
460
+ },
461
+ beginHold(kind) {
462
+ const starting = !this.holding;
463
+ this.detachHold();
464
+ this.holding = true;
465
+ this.holdKind = kind;
466
+ if (starting) this.$refs.input?.blur();
467
+ const end = (event) => {
468
+ if (kind === "touch" && event.type.startsWith("pointer")) return;
469
+ if (kind === "mouse" && event.type.startsWith("touch")) return;
470
+ this.detachHold();
471
+ if (!this.holding) return;
466
472
  this.holding = false;
467
- if (emitEnd) this.$emit("hold-end");
473
+ this.holdKind = "";
474
+ this.$emit("hold-end", { via: event.type });
475
+ };
476
+ this.holdEnd = end;
477
+ if (kind === "touch") {
478
+ window.addEventListener("touchend", end);
479
+ window.addEventListener("touchcancel", end);
480
+ } else {
481
+ window.addEventListener("pointerup", end, true);
482
+ window.addEventListener("pointercancel", end, true);
468
483
  }
484
+ if (starting) this.$emit("hold-start", { via: kind });
485
+ },
486
+ detachHold() {
487
+ if (!this.holdEnd) return;
488
+ window.removeEventListener("touchend", this.holdEnd);
489
+ window.removeEventListener("touchcancel", this.holdEnd);
490
+ window.removeEventListener("pointerup", this.holdEnd, true);
491
+ window.removeEventListener("pointercancel", this.holdEnd, true);
492
+ this.holdEnd = null;
493
+ },
494
+ clearHold() {
495
+ this.detachHold();
496
+ this.holding = false;
497
+ this.holdKind = "";
469
498
  },
470
499
  pickFiles() {
471
500
  this.$refs.picker?.click();
@@ -507,11 +536,12 @@ export default {
507
536
  position: relative;
508
537
  display: flex;
509
538
  flex-direction: column;
510
- gap: 6px;
511
- border: 1px solid var(--q-input-stroke);
512
- border-radius: 24px;
513
- padding: 12px 14px 10px;
539
+ gap: 8px;
540
+ border: 1px solid var(--q-separator);
541
+ border-radius: 999px;
542
+ padding: 10px 14px;
514
543
  background: var(--q-background-1);
544
+ box-shadow: 0 1px 3px rgb(0 0 0 / 6%);
515
545
  }
516
546
 
517
547
  .lares-composer__menu {
@@ -620,22 +650,14 @@ export default {
620
650
  white-space: nowrap;
621
651
  }
622
652
 
623
- .lares-composer__card[data-hero="true"] {
624
- gap: 4px;
625
- border-radius: 20px;
626
- padding: 10px 14px 8px;
627
- background: var(--q-background-2);
628
- }
629
-
630
- .lares-composer__card[data-hero="true"] .lares-composer__input {
631
- min-height: 44px;
632
- padding: 0;
633
- font-size: 16px;
634
- line-height: 1.45;
653
+ .lares-composer__card[data-expanded="true"] {
654
+ border-radius: 24px;
655
+ padding: 16px 14px 12px;
635
656
  }
636
657
 
637
- .lares-composer__card[data-hero="true"] .lares-composer__bar {
638
- min-height: 28px;
658
+ .lares-composer__card[data-holding="true"] {
659
+ border-color: var(--q-blue-default);
660
+ background: var(--q-blue-alpha);
639
661
  }
640
662
 
641
663
  .lares-composer__attachments {
@@ -712,90 +734,99 @@ export default {
712
734
  stroke-linecap: round;
713
735
  }
714
736
 
715
- .lares-composer__input {
737
+ .lares-composer__line {
738
+ display: flex;
716
739
  width: 100%;
717
- min-height: 28px;
718
- max-height: 176px;
719
- resize: none;
720
- overflow-y: auto;
740
+ align-items: center;
741
+ gap: 12px;
742
+ }
743
+
744
+ .lares-composer__line[data-expanded="true"] {
745
+ flex-wrap: wrap;
746
+ row-gap: 14px;
747
+ }
748
+
749
+ .lares-composer__line[data-expanded="true"] .lares-composer__input {
750
+ order: -1;
751
+ flex: 1 0 100%;
752
+ min-height: 26px;
753
+ padding: 0;
754
+ }
755
+
756
+ .lares-composer__input,
757
+ .lares-composer__talk {
758
+ min-width: 0;
759
+ min-height: 36px;
760
+ flex: 1;
721
761
  border: 0;
722
- padding: 2px 2px 4px;
723
762
  background: transparent;
724
- line-height: 1.45;
763
+ font-size: 16px;
764
+ line-height: 22px;
725
765
  }
726
766
 
727
- .lares-composer__input:focus {
728
- outline: none;
767
+ .lares-composer__input {
768
+ max-height: 176px;
769
+ resize: none;
770
+ overflow-y: auto;
771
+ padding: 7px 0;
772
+ color: var(--q-ink-1);
729
773
  }
730
774
 
731
- .lares-composer__hold {
732
- margin: 0;
733
- color: var(--q-blue-default);
734
- font-size: 15px;
735
- line-height: 20px;
775
+ .lares-composer__input::placeholder {
776
+ color: var(--q-ink-3);
736
777
  }
737
778
 
738
- .lares-composer__bar {
739
- display: flex;
740
- align-items: center;
741
- gap: 8px;
742
- min-height: 32px;
779
+ .lares-composer__input:focus {
780
+ outline: none;
743
781
  }
744
782
 
745
- .lares-composer__pills {
783
+ .lares-composer__talk {
746
784
  display: flex;
747
785
  align-items: center;
748
- flex-wrap: wrap;
749
- gap: 6px;
750
- min-width: 0;
786
+ justify-content: center;
787
+ padding: 9px 4px;
788
+ color: var(--q-ink-1);
789
+ font: inherit;
790
+ font-size: 16px;
791
+ font-weight: 600;
792
+ line-height: 22px;
793
+ touch-action: none;
794
+ user-select: none;
795
+ -webkit-user-select: none;
796
+ -webkit-touch-callout: none;
751
797
  }
752
798
 
753
- .lares-composer__pill {
754
- display: inline-flex;
755
- align-items: center;
756
- gap: 6px;
757
- box-sizing: border-box;
758
- width: 98px;
759
- flex: 0 0 98px;
760
- height: 32px;
761
- border: 0;
762
- border-radius: 999px;
763
- padding: 0 10px 0 8px;
764
- background: var(--q-background-3);
765
- color: var(--q-ink-2);
766
- font-size: 15px;
767
- font-weight: 500;
768
- line-height: 18px;
769
- white-space: nowrap;
799
+ .lares-composer__talk > * {
800
+ pointer-events: none;
770
801
  }
771
802
 
772
- .lares-composer__pill span {
773
- min-width: 0;
774
- overflow: hidden;
775
- text-overflow: ellipsis;
803
+ .lares-composer__talk[data-phase="recording"],
804
+ .lares-composer__card[data-holding="true"] .lares-composer__talk {
805
+ color: var(--q-blue-default);
776
806
  }
777
807
 
778
- .lares-composer__pill svg {
779
- width: 20px;
780
- height: 20px;
781
- flex-shrink: 0;
782
- fill: none;
783
- stroke: currentColor;
784
- stroke-width: 1.8;
785
- stroke-linecap: round;
786
- stroke-linejoin: round;
808
+ .lares-composer__talk-status {
809
+ display: inline-flex;
810
+ align-items: center;
811
+ justify-content: center;
812
+ gap: 6px;
787
813
  }
788
814
 
789
- .lares-composer__pill svg .lares-composer__nucleus {
790
- fill: currentColor;
815
+ .lares-composer__talk .lares-composer__spin {
816
+ width: 16px;
817
+ height: 16px;
818
+ flex: none;
791
819
  }
792
820
 
793
821
  .lares-composer__tools {
794
822
  display: flex;
795
823
  align-items: center;
796
- gap: 16px;
797
- margin-left: auto;
798
824
  flex-shrink: 0;
825
+ gap: 12px;
826
+ }
827
+
828
+ .lares-composer__line[data-expanded="true"] .lares-composer__tools {
829
+ margin-left: auto;
799
830
  }
800
831
 
801
832
  .lares-composer__picker {
@@ -806,9 +837,10 @@ export default {
806
837
  display: inline-flex;
807
838
  align-items: center;
808
839
  justify-content: center;
809
- width: 32px;
810
- height: 32px;
811
- border: 1.5px solid currentColor;
840
+ width: 36px;
841
+ height: 36px;
842
+ flex: 0 0 36px;
843
+ border: 1px solid var(--q-ink-3);
812
844
  border-radius: 999px;
813
845
  padding: 0;
814
846
  background: transparent;
@@ -819,23 +851,34 @@ export default {
819
851
  background: var(--q-btn-bg-pressed);
820
852
  }
821
853
 
822
- .lares-composer__icon[data-kind="send"],
823
- .lares-composer__icon[data-kind="voice"] {
854
+ .lares-composer__icon[data-kind="attach"],
855
+ .lares-composer__icon[data-kind="voice"],
856
+ .lares-composer__icon[data-kind="keyboard"] {
824
857
  border-color: transparent;
825
- color: var(--q-ink-on-brand);
858
+ background: var(--q-background-3);
859
+ color: var(--q-ink-1);
826
860
  }
827
861
 
828
- .lares-composer__icon[data-kind="send"] {
829
- background: var(--q-blue-default);
862
+ .lares-composer__icon[data-kind="attach"]:active,
863
+ .lares-composer__icon[data-kind="voice"]:active,
864
+ .lares-composer__icon[data-kind="keyboard"]:active {
865
+ background: var(--q-background-selected);
830
866
  }
831
867
 
832
- .lares-composer__icon[data-kind="voice"] {
868
+ .lares-composer__icon[data-kind="send"] {
869
+ border-color: transparent;
833
870
  background: var(--q-ink-1);
871
+ color: var(--q-background-1);
872
+ }
873
+
874
+ .lares-composer__icon[data-kind="send"]:disabled {
875
+ opacity: 0.4;
834
876
  }
835
877
 
836
878
  .lares-composer__icon svg {
837
- width: 20px;
838
- height: 20px;
879
+ width: 22px;
880
+ height: 22px;
881
+ flex: none;
839
882
  fill: none;
840
883
  stroke: currentColor;
841
884
  stroke-width: 2;
@@ -843,17 +886,6 @@ export default {
843
886
  stroke-linejoin: round;
844
887
  }
845
888
 
846
- .lares-composer__icon svg.lares-composer__wave {
847
- width: 18px;
848
- height: 18px;
849
- stroke-width: 2.75;
850
- }
851
-
852
- .lares-composer__live {
853
- font-size: 12px;
854
- font-variant-numeric: tabular-nums;
855
- }
856
-
857
889
  .lares-composer__spin {
858
890
  animation: lares-composer-spin 0.8s linear infinite;
859
891
  }