@olares/lares-mobile 0.15.4 → 0.15.6

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 (44) hide show
  1. package/README.md +6 -2
  2. package/package.json +2 -2
  3. package/src/App.vue +924 -184
  4. package/src/chat/ChatBar.vue +2 -2
  5. package/src/chat/Composer.vue +467 -16
  6. package/src/chat/Deliverables.vue +22 -10
  7. package/src/chat/HistoryPanel.vue +747 -55
  8. package/src/chat/MessageActions.vue +88 -34
  9. package/src/chat/QuestionCard.vue +5 -5
  10. package/src/chat/StageRow.vue +8 -5
  11. package/src/chat/Transcript.vue +20 -6
  12. package/src/chat/composer-tokens.js +32 -0
  13. package/src/chat/format.js +37 -0
  14. package/src/desktop/DesktopComposer.vue +871 -0
  15. package/src/desktop/DesktopContextMeter.vue +81 -0
  16. package/src/desktop/DesktopGoal.vue +88 -0
  17. package/src/desktop/DesktopPreview.vue +58 -0
  18. package/src/desktop/DesktopPreviewTabs.vue +82 -0
  19. package/src/desktop/DesktopQuestions.vue +118 -0
  20. package/src/desktop/DesktopQueue.vue +203 -0
  21. package/src/desktop/DesktopShell.vue +203 -0
  22. package/src/desktop/DesktopSidebar.vue +645 -0
  23. package/src/desktop/DesktopTodos.vue +52 -0
  24. package/src/desktop/DirectoryBrowser.vue +170 -0
  25. package/src/desktop/DirectoryNewFolder.vue +124 -0
  26. package/src/desktop/ui/PcDialog.vue +85 -0
  27. package/src/desktop/ui/PcPopover.vue +110 -0
  28. package/src/desktop/ui/PcTooltip.vue +95 -0
  29. package/src/desktop/ui/place.js +24 -0
  30. package/src/desktop/workspace-view.js +121 -0
  31. package/src/host.js +20 -2
  32. package/src/index.d.ts +2 -0
  33. package/src/mobile/MobileDirectoryNewFolder.vue +121 -0
  34. package/src/mobile/MobileDirectorySheet.vue +162 -0
  35. package/src/mobile/MobileNewSession.vue +217 -0
  36. package/src/mobile/MobileShell.vue +367 -0
  37. package/src/motion.css +166 -0
  38. package/src/preview/Preview.vue +91 -150
  39. package/src/preview/PreviewBody.vue +185 -0
  40. package/src/settings/AgentSettings.vue +126 -36
  41. package/src/settings/Select.vue +183 -0
  42. package/src/settings/SettingRow.vue +5 -4
  43. package/src/settings/Sheet.vue +4 -4
  44. package/src/styles.css +9 -0
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="lares-agent" :aria-busy="loading ? 'true' : 'false'">
2
+ <div class="lares-agent" :data-device="layoutDevice" :aria-busy="loading ? 'true' : 'false'">
3
3
  <div v-if="loading" class="lares-agent__loading" role="status">
4
4
  <span class="lares-agent__spinner" aria-hidden="true" />
5
5
  <p>{{ t("agent.loading") }}</p>
@@ -7,7 +7,15 @@
7
7
  <div class="lares-agent__body" :inert="loading || undefined">
8
8
  <section class="lares-agent__group">
9
9
  <h2>{{ tModel("settings.title") }}</h2>
10
- <div class="lares-agent__list">
10
+ <LaresSelect
11
+ v-if="isDesktop"
12
+ :value="modelCurrent"
13
+ :sections="modelSelectSections"
14
+ :disabled="busy || !models"
15
+ :empty="tModel('settings.empty')"
16
+ @select="(item) => pick(item, 'model')"
17
+ />
18
+ <div v-else class="lares-agent__list">
11
19
  <LaresSettingRow
12
20
  :label="tModel('settings.default')"
13
21
  :value="modelLabel"
@@ -22,6 +30,17 @@
22
30
  </p>
23
31
  <p v-if="modelError" class="lares-agent__hint" data-status="error">{{ modelError }}</p>
24
32
  </section>
33
+ <section v-if="isDesktop" class="lares-agent__group">
34
+ <h2>{{ t("settings.input.title") }}</h2>
35
+ <LaresSelect
36
+ :value="conversation?.busyEnter || 'queue'"
37
+ :sections="busyEnterSections"
38
+ :disabled="busy || !conversation?.writable"
39
+ @select="chooseBusyEnter"
40
+ />
41
+ <p class="lares-agent__hint">{{ t("settings.input.busyEnter.hint") }}</p>
42
+ <p v-if="conversationError" class="lares-agent__hint" data-status="error">{{ conversationError }}</p>
43
+ </section>
25
44
  <!-- Voice input parked.
26
45
  <section class="lares-agent__group">
27
46
  <h2>{{ tVoice("settings.title") }}</h2>
@@ -48,7 +67,15 @@
48
67
  -->
49
68
  <section class="lares-agent__group">
50
69
  <h2>{{ tSearch("settings.title") }}</h2>
51
- <div class="lares-agent__list">
70
+ <LaresSelect
71
+ v-if="isDesktop"
72
+ :value="searchMenuId"
73
+ :sections="searchSelectSections"
74
+ :disabled="busy || !search"
75
+ :empty="tSearch('settings.default.empty')"
76
+ @select="(item) => pick(item, 'search')"
77
+ />
78
+ <div v-else class="lares-agent__list">
52
79
  <LaresSettingRow
53
80
  :label="tSearch('settings.default')"
54
81
  :value="searchLabel"
@@ -60,7 +87,7 @@
60
87
  </div>
61
88
  <p v-if="searchError" class="lares-agent__hint" data-status="error">{{ searchError }}</p>
62
89
  </section>
63
- <LaresSheet :open="Boolean(panel)" :title="sheetTitle" @close="panel = ''">
90
+ <LaresSheet v-if="!isDesktop" :open="Boolean(panel)" :title="sheetTitle" @close="panel = ''">
64
91
  <p v-if="sheetEmpty" class="lares-agent__hint lares-agent__hint--sheet">{{ sheetEmpty }}</p>
65
92
  <template v-for="section in sheetSections" :key="section.heading || 'main'">
66
93
  <p v-if="section.heading" class="lares-agent__heading">{{ section.heading }}</p>
@@ -100,8 +127,10 @@ import { hostKey as hostSessionKey } from "@olares/lares-core/larepass/host";
100
127
  import { createHostClient } from "../host.js";
101
128
  import { adoptHost } from "../runtime.js";
102
129
  import { createT } from "../i18n.js";
130
+ import { chatDevice, DEVICE_DESKTOP } from "../layout.js";
103
131
  import LaresSettingRow from "./SettingRow.vue";
104
132
  import LaresSheet from "./Sheet.vue";
133
+ import LaresSelect from "./Select.vue";
105
134
 
106
135
  const catalogs = {
107
136
  model: { zh: MODEL_ZH, en: MODEL_EN },
@@ -115,10 +144,11 @@ function itemLabel(items, id) {
115
144
 
116
145
  export default {
117
146
  name: "LaresAgentSettings",
118
- components: { LaresSettingRow, LaresSheet },
147
+ components: { LaresSettingRow, LaresSheet, LaresSelect },
119
148
  expose: ["reload"],
120
149
  props: {
121
150
  locale: { type: String, default: "en" },
151
+ device: { type: String, default: "mobile" },
122
152
  baseUrl: { type: String, default: undefined },
123
153
  proxyPrefix: { type: String, default: undefined },
124
154
  request: { type: Function, default: undefined },
@@ -133,15 +163,23 @@ export default {
133
163
  models: remembered.models,
134
164
  voice: remembered.voice,
135
165
  search: remembered.search,
166
+ conversation: remembered.conversation,
136
167
  modelError: "",
137
168
  voiceError: "",
138
169
  searchError: "",
170
+ conversationError: "",
139
171
  };
140
172
  },
141
173
  computed: {
142
174
  t() {
143
175
  return createT(this.locale);
144
176
  },
177
+ layoutDevice() {
178
+ return chatDevice(this.device);
179
+ },
180
+ isDesktop() {
181
+ return this.layoutDevice === DEVICE_DESKTOP;
182
+ },
145
183
  ports() {
146
184
  return {
147
185
  baseUrl: this.baseUrl,
@@ -200,9 +238,33 @@ export default {
200
238
  if (!this.voice) return "—";
201
239
  return itemLabel(this.voiceLanguages, voiceMenuValue(this.voice.config?.language));
202
240
  },
241
+ searchMenuId() {
242
+ return searchMenuValue(this.search?.defaultSearchModel);
243
+ },
203
244
  searchLabel() {
204
245
  if (!this.search) return "—";
205
- return itemLabel(this.searchItems, searchMenuValue(this.search.defaultSearchModel));
246
+ return itemLabel(this.searchItems, this.searchMenuId);
247
+ },
248
+ modelSelectSections() {
249
+ return this.modelGroups.map((group) => ({
250
+ heading: group.provider,
251
+ items: group.models.map((model) => ({
252
+ id: this.modelKey(model),
253
+ label: model.name,
254
+ model,
255
+ })),
256
+ }));
257
+ },
258
+ searchSelectSections() {
259
+ return [{ items: this.searchItems.map((item) => ({ id: item.id, label: item.label })) }];
260
+ },
261
+ busyEnterSections() {
262
+ return [{
263
+ items: [
264
+ { id: "queue", label: this.t("settings.input.busyEnter.queue") },
265
+ { id: "steer", label: this.t("settings.input.busyEnter.steer") },
266
+ ],
267
+ }];
206
268
  },
207
269
  sheetTitle() {
208
270
  if (this.panel === "model") return this.tModel("settings.title");
@@ -212,32 +274,17 @@ export default {
212
274
  return "";
213
275
  },
214
276
  sheetCurrent() {
215
- if (this.panel === "model") return this.modelCurrent;
216
- if (this.panel === "voiceModel") return voiceMenuValue(this.voice?.config?.model);
217
- if (this.panel === "voiceLang") return voiceMenuValue(this.voice?.config?.language);
218
- if (this.panel === "search") return searchMenuValue(this.search?.defaultSearchModel);
219
- return "";
277
+ return this.sheetCurrentFor(this.panel);
220
278
  },
221
279
  sheetSections() {
222
- if (this.panel === "model") {
223
- return this.modelGroups.map((group) => ({
224
- heading: group.provider,
225
- items: group.models.map((model) => ({
226
- id: this.modelKey(model),
227
- label: model.name,
228
- model,
229
- })),
230
- }));
231
- }
280
+ if (this.panel === "model") return this.modelSelectSections;
232
281
  if (this.panel === "voiceModel") {
233
282
  return [{ items: this.voiceModels.map((item) => ({ id: item.id, label: item.label })) }];
234
283
  }
235
284
  if (this.panel === "voiceLang") {
236
285
  return [{ items: this.voiceLanguages.map((item) => ({ id: item.id, label: item.label })) }];
237
286
  }
238
- if (this.panel === "search") {
239
- return [{ items: this.searchItems.map((item) => ({ id: item.id, label: item.label })) }];
240
- }
287
+ if (this.panel === "search") return this.searchSelectSections;
241
288
  return [];
242
289
  },
243
290
  sheetEmpty() {
@@ -255,9 +302,11 @@ export default {
255
302
  this.models = null;
256
303
  this.voice = null;
257
304
  this.search = null;
305
+ this.conversation = null;
258
306
  this.modelError = "";
259
307
  this.voiceError = "";
260
308
  this.searchError = "";
309
+ this.conversationError = "";
261
310
  this.load(true);
262
311
  },
263
312
  },
@@ -286,9 +335,8 @@ export default {
286
335
  if (!ready) return;
287
336
  this.panel = panel;
288
337
  },
289
- async pick(item) {
290
- const panel = this.panel;
291
- if (item.id === this.sheetCurrent) {
338
+ async pick(item, panel = this.panel) {
339
+ if (item.id === this.sheetCurrentFor(panel)) {
292
340
  this.panel = "";
293
341
  return;
294
342
  }
@@ -298,6 +346,13 @@ export default {
298
346
  if (panel === "voiceLang") await this.patchVoice("language", voiceValueFromMenu(item.id));
299
347
  if (panel === "search") await this.chooseSearch(item.id);
300
348
  },
349
+ sheetCurrentFor(panel) {
350
+ if (panel === "model") return this.modelCurrent;
351
+ if (panel === "voiceModel") return voiceMenuValue(this.voice?.config?.model);
352
+ if (panel === "voiceLang") return voiceMenuValue(this.voice?.config?.language);
353
+ if (panel === "search") return searchMenuValue(this.search?.defaultSearchModel);
354
+ return "";
355
+ },
301
356
  reload() {
302
357
  return this.load(true);
303
358
  },
@@ -307,17 +362,20 @@ export default {
307
362
  this.models = remembered.models ?? this.models;
308
363
  this.voice = remembered.voice ?? this.voice;
309
364
  this.search = remembered.search ?? this.search;
310
- if (this.models && this.voice && this.search) return;
365
+ this.conversation = remembered.conversation ?? this.conversation;
366
+ if (this.models && this.voice && this.search && this.conversation) return;
311
367
  }
312
368
  this.panel = "";
313
369
  this.loading = true;
314
370
  this.modelError = "";
315
371
  this.voiceError = "";
316
372
  this.searchError = "";
317
- const [models, voice, search] = await Promise.allSettled([
373
+ this.conversationError = "";
374
+ const [models, voice, search, conversation] = await Promise.allSettled([
318
375
  this.settings.models({ force }),
319
376
  this.settings.voice(force),
320
377
  this.settings.search({ force }),
378
+ this.settings.conversation({ force }),
321
379
  ]);
322
380
  if (models.status === "fulfilled") this.models = models.value;
323
381
  else this.modelError = this.failText(this.tModel, "settings.loadFailed", models.reason);
@@ -325,6 +383,8 @@ export default {
325
383
  else this.voiceError = this.tVoice("settings.loadFailed");
326
384
  if (search.status === "fulfilled") this.search = search.value;
327
385
  else this.searchError = this.failText(this.tSearch, "settings.loadFailed", search.reason);
386
+ if (conversation.status === "fulfilled") this.conversation = conversation.value;
387
+ else this.conversationError = conversation.reason instanceof Error ? conversation.reason.message : String(conversation.reason);
328
388
  this.loading = false;
329
389
  },
330
390
  async chooseModel(model) {
@@ -369,6 +429,18 @@ export default {
369
429
  this.pending = "";
370
430
  }
371
431
  },
432
+ async chooseBusyEnter(item) {
433
+ if (!item?.id || item.id === this.conversation?.busyEnter || this.busy) return;
434
+ this.pending = "busyEnter";
435
+ this.conversationError = "";
436
+ try {
437
+ this.conversation = await this.settings.setBusyEnter(item.id);
438
+ } catch (err) {
439
+ this.conversationError = err instanceof Error ? err.message : String(err);
440
+ } finally {
441
+ this.pending = "";
442
+ }
443
+ },
372
444
  },
373
445
  };
374
446
  </script>
@@ -382,6 +454,11 @@ export default {
382
454
  color: var(--q-ink-1);
383
455
  }
384
456
 
457
+ .lares-agent[data-device="desktop"] {
458
+ min-height: 0;
459
+ width: 100%;
460
+ }
461
+
385
462
  .lares-agent__body {
386
463
  display: flex;
387
464
  flex-direction: column;
@@ -389,6 +466,15 @@ export default {
389
466
  padding: 16px 20px 32px;
390
467
  }
391
468
 
469
+ .lares-agent[data-device="desktop"] .lares-agent__body {
470
+ gap: 16px;
471
+ padding: 0;
472
+ }
473
+
474
+ .lares-agent[data-device="desktop"] .lares-agent__group h2 {
475
+ font-size: 16px;
476
+ }
477
+
392
478
  .lares-agent__loading {
393
479
  position: absolute;
394
480
  inset: 0;
@@ -405,8 +491,12 @@ export default {
405
491
 
406
492
  .lares-agent__loading p {
407
493
  margin: 0;
408
- font-size: 14px;
409
- line-height: 20px;
494
+ font-size: 16px;
495
+ line-height: 22px;
496
+ }
497
+
498
+ .lares-agent[data-device="desktop"] .lares-agent__loading {
499
+ min-height: 96px;
410
500
  }
411
501
 
412
502
  .lares-agent__spinner {
@@ -436,9 +526,9 @@ export default {
436
526
 
437
527
  .lares-agent__group h2 {
438
528
  margin: 0;
439
- font-size: 16px;
529
+ font-size: 18px;
440
530
  font-weight: 500;
441
- line-height: 22px;
531
+ line-height: 24px;
442
532
  }
443
533
 
444
534
  .lares-agent__list {
@@ -449,7 +539,7 @@ export default {
449
539
 
450
540
  .lares-agent__hint {
451
541
  margin: 0;
452
- font-size: 13px;
542
+ font-size: 15px;
453
543
  color: var(--q-ink-3);
454
544
  }
455
545
 
@@ -465,8 +555,8 @@ export default {
465
555
  margin: 0;
466
556
  padding: 12px 16px 4px;
467
557
  color: var(--q-ink-3);
468
- font-size: 12px;
558
+ font-size: 14px;
469
559
  font-weight: 500;
470
- line-height: 16px;
560
+ line-height: 18px;
471
561
  }
472
562
  </style>
@@ -0,0 +1,183 @@
1
+ <template>
2
+ <div class="lares-select">
3
+ <LaresPcPopover v-model="open" width="anchor" placement="bottom-start">
4
+ <template #trigger="{ toggle }">
5
+ <button
6
+ type="button"
7
+ class="lares-select__trigger"
8
+ :disabled="disabled"
9
+ aria-haspopup="listbox"
10
+ :aria-expanded="open ? 'true' : 'false'"
11
+ @click="toggle"
12
+ >
13
+ <span class="lares-select__value">{{ currentLabel }}</span>
14
+ <svg class="lares-select__chevron" viewBox="0 0 24 24" aria-hidden="true">
15
+ <path d="M6.5 9 12 14.5 17.5 9" />
16
+ </svg>
17
+ </button>
18
+ </template>
19
+ <div class="lares-select__menu" role="listbox">
20
+ <p v-if="emptyText" class="lares-select__empty">{{ emptyText }}</p>
21
+ <template v-for="section in sections" :key="section.heading || 'main'">
22
+ <p v-if="section.heading" class="lares-select__heading">{{ section.heading }}</p>
23
+ <button
24
+ v-for="item in section.items"
25
+ :key="item.id"
26
+ type="button"
27
+ class="lares-select__option"
28
+ role="option"
29
+ :aria-selected="item.id === value"
30
+ :disabled="disabled"
31
+ @click="choose(item)"
32
+ >
33
+ <span>{{ item.label }}</span>
34
+ <svg v-if="item.id === value" class="lares-select__check" viewBox="0 0 24 24" aria-hidden="true">
35
+ <path d="M5 12.5 9.5 17 19 7.5" />
36
+ </svg>
37
+ </button>
38
+ </template>
39
+ </div>
40
+ </LaresPcPopover>
41
+ </div>
42
+ </template>
43
+
44
+ <script>
45
+ import LaresPcPopover from "../desktop/ui/PcPopover.vue";
46
+
47
+ export default {
48
+ name: "LaresSelect",
49
+ components: { LaresPcPopover },
50
+ props: {
51
+ value: { type: String, default: "" },
52
+ sections: { type: Array, default: () => [] },
53
+ disabled: { type: Boolean, default: false },
54
+ empty: { type: String, default: "" },
55
+ },
56
+ emits: ["select"],
57
+ data() {
58
+ return { open: false };
59
+ },
60
+ computed: {
61
+ currentLabel() {
62
+ for (const section of this.sections) {
63
+ for (const item of section.items) {
64
+ if (item.id === this.value) return item.label;
65
+ }
66
+ }
67
+ return "—";
68
+ },
69
+ itemCount() {
70
+ return this.sections.reduce((sum, section) => sum + section.items.length, 0);
71
+ },
72
+ emptyText() {
73
+ return this.itemCount === 0 ? this.empty : "";
74
+ },
75
+ },
76
+ methods: {
77
+ choose(item) {
78
+ this.open = false;
79
+ this.$emit("select", item);
80
+ },
81
+ },
82
+ };
83
+ </script>
84
+
85
+ <style scoped>
86
+ .lares-select {
87
+ width: 100%;
88
+ }
89
+
90
+ .lares-select__trigger {
91
+ display: flex;
92
+ align-items: center;
93
+ gap: 8px;
94
+ box-sizing: border-box;
95
+ width: 100%;
96
+ height: 32px;
97
+ padding: 0 8px 0 12px;
98
+ border: 1px solid var(--q-separator);
99
+ border-radius: 8px;
100
+ background: transparent;
101
+ color: var(--q-ink-2);
102
+ text-align: left;
103
+ cursor: pointer;
104
+ }
105
+
106
+ .lares-select__trigger:disabled {
107
+ cursor: default;
108
+ opacity: 0.5;
109
+ }
110
+
111
+ .lares-select__value {
112
+ min-width: 0;
113
+ flex: 1;
114
+ overflow: hidden;
115
+ font-size: 15px;
116
+ line-height: 20px;
117
+ text-overflow: ellipsis;
118
+ white-space: nowrap;
119
+ }
120
+
121
+ .lares-select__chevron,
122
+ .lares-select__check {
123
+ width: 20px;
124
+ height: 20px;
125
+ flex-shrink: 0;
126
+ fill: none;
127
+ stroke: var(--q-ink-3);
128
+ stroke-width: 1.75;
129
+ stroke-linecap: round;
130
+ stroke-linejoin: round;
131
+ }
132
+
133
+ .lares-select__check {
134
+ width: 16px;
135
+ height: 16px;
136
+ stroke: var(--q-blue-default);
137
+ }
138
+
139
+ .lares-select__menu {
140
+ margin: -2px;
141
+ }
142
+
143
+ .lares-select__empty,
144
+ .lares-select__heading {
145
+ margin: 0;
146
+ padding: 8px;
147
+ color: var(--q-ink-3);
148
+ font-size: 14px;
149
+ font-weight: 500;
150
+ line-height: 18px;
151
+ }
152
+
153
+ .lares-select__option {
154
+ display: flex;
155
+ align-items: center;
156
+ justify-content: space-between;
157
+ gap: 8px;
158
+ width: 100%;
159
+ padding: 8px;
160
+ border: 0;
161
+ border-radius: 4px;
162
+ background: transparent;
163
+ color: var(--q-ink-2);
164
+ font-size: 15px;
165
+ line-height: 20px;
166
+ text-align: left;
167
+ cursor: pointer;
168
+ }
169
+
170
+ .lares-select__option span {
171
+ min-width: 0;
172
+ overflow: hidden;
173
+ text-overflow: ellipsis;
174
+ }
175
+
176
+ .lares-select__option:hover:not(:disabled) {
177
+ background: var(--q-background-hover);
178
+ }
179
+
180
+ .lares-select__option[aria-selected="true"] span {
181
+ color: var(--q-blue-default);
182
+ }
183
+ </style>
@@ -52,6 +52,7 @@ export default {
52
52
  background: transparent;
53
53
  color: var(--q-ink-1);
54
54
  text-align: left;
55
+ transition: background var(--lares-duration-fast, 120ms) var(--lares-ease-out, ease);
55
56
  }
56
57
 
57
58
  .lares-set-row--boxed {
@@ -75,8 +76,8 @@ export default {
75
76
  .lares-set-row__label {
76
77
  min-width: 0;
77
78
  flex: 1;
78
- font-size: 14px;
79
- line-height: 20px;
79
+ font-size: 16px;
80
+ line-height: 22px;
80
81
  word-break: break-word;
81
82
  }
82
83
 
@@ -91,8 +92,8 @@ export default {
91
92
 
92
93
  .lares-set-row__value {
93
94
  overflow: hidden;
94
- font-size: 13px;
95
- line-height: 18px;
95
+ font-size: 15px;
96
+ line-height: 20px;
96
97
  color: var(--q-ink-2);
97
98
  text-align: right;
98
99
  text-overflow: ellipsis;
@@ -52,7 +52,7 @@ export default {
52
52
  inset: 0;
53
53
  background: rgb(0 0 0 / 32%);
54
54
  opacity: 0;
55
- transition: opacity 0.28s cubic-bezier(0.32, 0.72, 0, 1);
55
+ transition: opacity var(--lares-duration-sheet, 280ms) var(--lares-ease-out, cubic-bezier(0.32, 0.72, 0, 1));
56
56
  }
57
57
 
58
58
  .lares-sheet[data-open="true"] .lares-sheet__backdrop {
@@ -73,7 +73,7 @@ export default {
73
73
  background: var(--q-background-1);
74
74
  box-shadow: 0 -8px 32px rgb(0 0 0 / 12%);
75
75
  transform: translateY(100%);
76
- transition: transform 0.28s cubic-bezier(0.32, 0.72, 0, 1);
76
+ transition: transform var(--lares-duration-sheet, 280ms) var(--lares-ease-out, cubic-bezier(0.32, 0.72, 0, 1));
77
77
  }
78
78
 
79
79
  .lares-sheet[data-open="true"] .lares-sheet__panel {
@@ -91,9 +91,9 @@ export default {
91
91
 
92
92
  .lares-sheet__title {
93
93
  margin: 0;
94
- font-size: 18px;
94
+ font-size: 20px;
95
95
  font-weight: 500;
96
- line-height: 24px;
96
+ line-height: 26px;
97
97
  }
98
98
 
99
99
  .lares-sheet__close {
package/src/styles.css CHANGED
@@ -1,12 +1,21 @@
1
+ @import "./motion.css";
2
+
3
+ /* Own the base size instead of inheriting the host page, so unstyled text
4
+ (user bubbles, composer textareas) matches the transcript body. */
1
5
  .lares-shell {
2
6
  position: relative;
3
7
  display: flex;
4
8
  flex-direction: column;
5
9
  min-height: 0;
6
10
  flex: 1;
11
+ font-size: 17px;
7
12
  color: var(--q-ink-1);
8
13
  }
9
14
 
15
+ .lares-shell[data-device="desktop"] {
16
+ font-size: 15px;
17
+ }
18
+
10
19
  .lares-shell__conversation {
11
20
  display: flex;
12
21
  flex-direction: column;