@olares/lares-mobile 0.15.5 → 0.15.7

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 +918 -178
  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 +942 -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 +229 -0
  22. package/src/desktop/DesktopSidebar.vue +645 -0
  23. package/src/desktop/DesktopTodos.vue +52 -0
  24. package/src/desktop/DirectoryBrowser.vue +231 -0
  25. package/src/desktop/DirectoryNewFolder.vue +124 -0
  26. package/src/desktop/ui/PcDialog.vue +100 -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
@@ -10,6 +10,43 @@
10
10
  <header class="lares-history__head">
11
11
  <h2 class="lares-history__title">{{ t("bar.history") }}</h2>
12
12
  </header>
13
+ <header class="lares-history__toolbar">
14
+ <span v-if="!searchOpen" class="lares-history__section-label">{{ sectionTitle }}</span>
15
+ <div v-else class="lares-history__search">
16
+ <svg viewBox="0 0 24 24" aria-hidden="true">
17
+ <circle cx="11" cy="11" r="6" />
18
+ <path d="m16 16 4 4" />
19
+ </svg>
20
+ <input
21
+ ref="searchInput"
22
+ v-model="query"
23
+ :placeholder="t('desktop.searchSessions')"
24
+ @keydown.esc="closeSearch"
25
+ />
26
+ <button type="button" :aria-label="t('desktop.clearSearch')" @click="closeSearch">×</button>
27
+ </div>
28
+ <div v-if="!searchOpen" class="lares-history__toolbar-actions">
29
+ <button type="button" :aria-label="t('desktop.searchSessions')" @click="openSearch">
30
+ <svg viewBox="0 0 24 24" aria-hidden="true">
31
+ <circle cx="11" cy="11" r="6" />
32
+ <path d="m16 16 4 4" />
33
+ </svg>
34
+ </button>
35
+ <button type="button" :aria-label="t('desktop.viewOptions')" @click="viewSheet = true">
36
+ <svg viewBox="0 0 24 24" aria-hidden="true">
37
+ <path d="M4 9h9M17 9h3M4 15h3M11 15h9" />
38
+ <circle cx="15" cy="9" r="2" />
39
+ <circle cx="9" cy="15" r="2" />
40
+ </svg>
41
+ </button>
42
+ <button type="button" :aria-label="t('desktop.addWorkspace')" @click="$emit('browse-workspaces')">
43
+ <svg viewBox="0 0 24 24" aria-hidden="true">
44
+ <path d="M15 5.5H7A2.5 2.5 0 0 0 4.5 8v9A2.5 2.5 0 0 0 7 19.5h8a2.5 2.5 0 0 0 2.5-2.5v-3.5" />
45
+ <path d="M19 4.5v4M17 6.5h4" />
46
+ </svg>
47
+ </button>
48
+ </div>
49
+ </header>
13
50
  <div class="lares-history__list">
14
51
  <div
15
52
  v-if="pending"
@@ -21,48 +58,404 @@
21
58
  <span class="lares-history__bone lares-history__bone--label" />
22
59
  <span class="lares-history__bone" />
23
60
  <span class="lares-history__bone" />
24
- <span class="lares-history__bone" />
25
- <span class="lares-history__bone" />
26
61
  </section>
27
62
  </div>
28
- <p v-else-if="sections.length === 0" class="lares-history__empty">{{ t("history.empty") }}</p>
29
- <section v-for="section in sections" :key="section.id" class="lares-history__section">
30
- <h3 class="lares-history__label">{{ t(section.key) }}</h3>
31
- <button
32
- v-for="row in section.rows"
33
- :key="row.sessionId"
34
- type="button"
35
- class="lares-history__item"
36
- :data-current="row.sessionId === sessionId ? 'true' : 'false'"
37
- @click="$emit('pick', row.sessionId)"
38
- >
39
- {{ row.title || t("history.untitled") }}
40
- </button>
63
+ <p v-else-if="workspaceError" class="lares-history__empty">
64
+ {{ workspaceError }}
65
+ <button type="button" @click="$emit('refresh-workspaces')">{{ t("agent.refresh") }}</button>
66
+ </p>
67
+ <p v-else-if="groups.length === 0" class="lares-history__empty">{{ t("history.empty") }}</p>
68
+ <section v-for="group in groups" :key="group.key" class="lares-history__section">
69
+ <div v-if="!flat" class="lares-history__group-head">
70
+ <button
71
+ type="button"
72
+ class="lares-history__group-toggle"
73
+ :data-active="holdsCurrent(group)"
74
+ @click="toggleGroup(group.key)"
75
+ >
76
+ <span class="lares-history__group-icon" :data-expanded="isExpanded(group.key)">
77
+ <svg class="lares-history__folder" viewBox="0 0 24 24" aria-hidden="true">
78
+ <path d="M3.5 7.5h6l1.6 2H20.5v9H3.5z" />
79
+ </svg>
80
+ <svg class="lares-history__caret" viewBox="0 0 24 24" aria-hidden="true">
81
+ <path d="M8.5 6 15.5 12l-7 6z" />
82
+ </svg>
83
+ </span>
84
+ <span>{{ group.title || t("desktop.ungrouped") }}</span>
85
+ </button>
86
+ <button
87
+ v-if="group.workspaceId"
88
+ type="button"
89
+ class="lares-history__group-new"
90
+ :aria-label="t('desktop.newSession')"
91
+ @click="$emit('create', group.workspaceId)"
92
+ >
93
+ <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg>
94
+ </button>
95
+ </div>
96
+ <div v-show="flat || isExpanded(group.key)" class="lares-history__sessions">
97
+ <div
98
+ v-for="row in visibleSessions(group)"
99
+ :key="row.sessionId"
100
+ class="lares-history__session-row"
101
+ :data-current="row.sessionId === sessionId ? 'true' : 'false'"
102
+ :data-unseen="Boolean(unseen?.[row.sessionId])"
103
+ >
104
+ <button
105
+ type="button"
106
+ class="lares-history__item"
107
+ @click="$emit('pick', row.sessionId)"
108
+ >
109
+ <span class="lares-history__unseen" aria-hidden="true" />
110
+ <span>{{ row.title || t("history.untitled") }}</span>
111
+ </button>
112
+ <button
113
+ type="button"
114
+ class="lares-history__more"
115
+ :aria-label="t('desktop.sessionActions')"
116
+ @click="openSessionActions(row, group)"
117
+ >
118
+ <svg viewBox="0 0 24 24" aria-hidden="true">
119
+ <circle cx="6" cy="12" r="1.35" />
120
+ <circle cx="12" cy="12" r="1.35" />
121
+ <circle cx="18" cy="12" r="1.35" />
122
+ </svg>
123
+ </button>
124
+ </div>
125
+ <button
126
+ v-if="!flat && overflowCount(group) > 0"
127
+ type="button"
128
+ class="lares-history__overflow"
129
+ @click="toggleSessions(group.key)"
130
+ >
131
+ {{
132
+ isSessionsExpanded(group.key)
133
+ ? t("desktop.showLessSessions")
134
+ : t("desktop.showMoreSessions", { n: overflowCount(group) })
135
+ }}
136
+ </button>
137
+ </div>
41
138
  </section>
42
139
  </div>
43
140
  </aside>
141
+
142
+ <LaresSheet :open="viewSheet" :title="t('desktop.viewOptions')" @close="viewSheet = false">
143
+ <p class="lares-history__sheet-label">{{ t("desktop.groupBy") }}</p>
144
+ <LaresSettingRow
145
+ :label="t('desktop.byWorkspace')"
146
+ :checked="!flat"
147
+ @click="setGroupBy(false)"
148
+ />
149
+ <LaresSettingRow
150
+ :label="t('desktop.oneList')"
151
+ :checked="flat"
152
+ @click="setGroupBy(true)"
153
+ />
154
+ <p class="lares-history__sheet-label">{{ t("desktop.orderBy") }}</p>
155
+ <LaresSettingRow
156
+ :label="t('desktop.recent')"
157
+ :checked="orderBy === 'updated'"
158
+ @click="setOrderBy('updated')"
159
+ />
160
+ <LaresSettingRow
161
+ :label="t('desktop.manual')"
162
+ :checked="orderBy === 'manual'"
163
+ @click="setOrderBy('manual')"
164
+ />
165
+ </LaresSheet>
166
+
167
+ <LaresSheet :open="Boolean(sessionSheet)" :title="t('desktop.sessionActions')" @close="sessionSheet = null">
168
+ <LaresSettingRow :label="t('desktop.rename')" @click="beginRenameSession" />
169
+ <LaresSettingRow :label="t('desktop.moveSession')" @click="beginMoveSession" />
170
+ <LaresSettingRow :label="t('desktop.archiveSession')" @click="beginArchiveSession" />
171
+ </LaresSheet>
172
+
173
+ <LaresSheet
174
+ :open="Boolean(renameSheet)"
175
+ :title="renameSheet?.kind === 'workspace' ? t('desktop.renameWorkspace') : t('desktop.renameSession')"
176
+ @close="renameSheet = null"
177
+ >
178
+ <input
179
+ ref="renameInput"
180
+ v-model="renameValue"
181
+ class="lares-history__input"
182
+ @keydown.enter.prevent="submitRename"
183
+ />
184
+ <div class="lares-history__sheet-actions">
185
+ <button type="button" class="lares-history__cancel" @click="renameSheet = null">{{ t("desktop.cancel") }}</button>
186
+ <button
187
+ type="button"
188
+ class="lares-history__confirm"
189
+ :disabled="!renameValue.trim()"
190
+ @click="submitRename"
191
+ >
192
+ {{ t("desktop.save") }}
193
+ </button>
194
+ </div>
195
+ </LaresSheet>
196
+
197
+ <LaresSheet
198
+ :open="Boolean(confirmSheet)"
199
+ :title="confirmSheet?.title || ''"
200
+ @close="confirmSheet = null"
201
+ >
202
+ <p class="lares-history__confirm-copy">{{ confirmSheet?.description }}</p>
203
+ <div class="lares-history__sheet-actions">
204
+ <button type="button" class="lares-history__cancel" @click="confirmSheet = null">{{ t("desktop.cancel") }}</button>
205
+ <button type="button" class="lares-history__confirm lares-history__confirm--danger" @click="submitConfirm">
206
+ {{ confirmSheet?.confirmLabel }}
207
+ </button>
208
+ </div>
209
+ </LaresSheet>
210
+
211
+ <LaresSheet :open="Boolean(moveSheet)" :title="t('desktop.moveSession')" @close="moveSheet = null">
212
+ <p v-if="moveTargets.length === 0" class="lares-history__empty">{{ t("history.noMoveTargets") }}</p>
213
+ <LaresSettingRow
214
+ v-for="workspace in moveTargets"
215
+ :key="workspace.workspaceId"
216
+ :label="workspace.title"
217
+ @click="submitMove(workspace.workspaceId)"
218
+ />
219
+ </LaresSheet>
44
220
  </div>
45
221
  </template>
46
222
 
47
223
  <script>
48
- import { groupSessionsByRecency, visibleHistorySessions } from "@olares/lares-core/larepass/chat";
224
+ import {
225
+ collapsedSessions,
226
+ groupWorkspaceSessions,
227
+ hiddenSessionCount,
228
+ workspaceForSession,
229
+ } from "@olares/lares-core/larepass/workspace";
230
+ import LaresSheet from "../settings/Sheet.vue";
231
+ import LaresSettingRow from "../settings/SettingRow.vue";
232
+ import {
233
+ loadWorkspaceView,
234
+ saveWorkspaceView,
235
+ syncWorkspaceViewOrders,
236
+ } from "../desktop/workspace-view.js";
49
237
 
50
238
  export default {
51
239
  name: "LaresHistoryPanel",
240
+ components: { LaresSheet, LaresSettingRow },
52
241
  props: {
53
242
  open: { type: Boolean, default: false },
54
243
  sessions: { type: Array, default: () => [] },
244
+ workspaces: { type: Array, default: () => [] },
245
+ workspacesReady: { type: Boolean, default: false },
246
+ workspaceError: { type: String, default: "" },
247
+ archivedSessionIds: { type: Array, default: () => [] },
55
248
  sessionId: { type: String, default: "" },
56
249
  ready: { type: Boolean, default: false },
250
+ unseen: { type: Object, default: null },
57
251
  t: { type: Function, required: true },
58
252
  },
59
- emits: ["close", "pick"],
253
+ emits: [
254
+ "close", "pick", "create", "browse-workspaces", "refresh-workspaces",
255
+ "rename-session", "archive-session", "move-session",
256
+ ],
257
+ data() {
258
+ const view = loadWorkspaceView();
259
+ return {
260
+ query: "",
261
+ searchOpen: false,
262
+ viewSheet: false,
263
+ flat: view.groupBy === "flat",
264
+ orderBy: view.orderBy,
265
+ expanded: view.groupExpansion,
266
+ sessionOrderByAccount: view.sessionOrderByAccount,
267
+ sessionUpdatedAtByAccount: view.sessionUpdatedAtByAccount,
268
+ sessionsExpanded: {},
269
+ sessionSheet: null,
270
+ renameSheet: null,
271
+ renameValue: "",
272
+ confirmSheet: null,
273
+ moveSheet: null,
274
+ };
275
+ },
60
276
  computed: {
61
277
  pending() {
62
- return !this.ready && this.sections.length === 0;
278
+ return (!this.ready || !this.workspacesReady) && this.groups.length === 0;
279
+ },
280
+ sectionTitle() {
281
+ return this.flat ? this.t("desktop.sessions") : this.t("desktop.workspaces");
282
+ },
283
+ groups() {
284
+ return groupWorkspaceSessions(
285
+ this.sessions,
286
+ this.workspaces,
287
+ this.archivedSessionIds,
288
+ {
289
+ query: this.query,
290
+ orderBy: this.orderBy,
291
+ flat: this.flat,
292
+ currentSessionId: this.sessionId,
293
+ sessionOrderByAccount: this.sessionOrderByAccount,
294
+ },
295
+ );
296
+ },
297
+ orderRevision() {
298
+ return JSON.stringify({
299
+ current: this.sessionId,
300
+ sessions: this.sessions.map((row) => [row.sessionId, row.updatedAt, row.blank]),
301
+ workspaces: this.workspaces.map((row) => [row.workspaceId, row.sessionIds]),
302
+ });
303
+ },
304
+ moveTargets() {
305
+ const current = this.moveSheet?.workspaceId;
306
+ return (this.workspaces ?? []).filter((row) => row.workspaceId && row.workspaceId !== current);
307
+ },
308
+ },
309
+ watch: {
310
+ orderRevision: {
311
+ immediate: true,
312
+ handler() {
313
+ this.syncOrders();
314
+ },
315
+ },
316
+ flat() {
317
+ this.persistView();
318
+ },
319
+ orderBy(next, previous) {
320
+ this.syncOrders(next === "updated" && previous !== "updated");
321
+ },
322
+ workspaces: {
323
+ immediate: true,
324
+ handler(workspaces) {
325
+ const next = { ...this.expanded };
326
+ for (const workspace of workspaces ?? []) {
327
+ if (!(workspace.workspaceId in next)) next[workspace.workspaceId] = true;
328
+ }
329
+ if (!("" in next)) next[""] = true;
330
+ this.expanded = next;
331
+ this.persistView();
332
+ },
333
+ },
334
+ renameSheet(open) {
335
+ if (!open) return;
336
+ this.$nextTick(() => {
337
+ this.$refs.renameInput?.focus();
338
+ this.$refs.renameInput?.select();
339
+ });
63
340
  },
64
- sections() {
65
- return groupSessionsByRecency(visibleHistorySessions(this.sessions, this.sessionId));
341
+ },
342
+ methods: {
343
+ openSearch() {
344
+ this.searchOpen = true;
345
+ this.$nextTick(() => this.$refs.searchInput?.focus());
346
+ },
347
+ closeSearch() {
348
+ this.query = "";
349
+ this.searchOpen = false;
350
+ },
351
+ setGroupBy(flat) {
352
+ this.flat = flat;
353
+ this.viewSheet = false;
354
+ },
355
+ setOrderBy(orderBy) {
356
+ this.orderBy = orderBy;
357
+ this.viewSheet = false;
358
+ },
359
+ isExpanded(key) {
360
+ return this.expanded[key] !== false;
361
+ },
362
+ toggleGroup(key) {
363
+ this.expanded = { ...this.expanded, [key]: !this.isExpanded(key) };
364
+ this.persistView();
365
+ },
366
+ isSessionsExpanded(key) {
367
+ return this.sessionsExpanded[key] === true;
368
+ },
369
+ toggleSessions(key) {
370
+ this.sessionsExpanded = { ...this.sessionsExpanded, [key]: !this.isSessionsExpanded(key) };
371
+ },
372
+ holdsCurrent(group) {
373
+ return group.sessions.some((row) => row.sessionId === this.sessionId);
374
+ },
375
+ visibleSessions(group) {
376
+ if (this.flat) return group.sessions;
377
+ return collapsedSessions(group.sessions, this.isSessionsExpanded(group.key));
378
+ },
379
+ overflowCount(group) {
380
+ return hiddenSessionCount(group.sessions);
381
+ },
382
+ viewState() {
383
+ return {
384
+ groupBy: this.flat ? "flat" : "workspace",
385
+ orderBy: this.orderBy,
386
+ groupExpansion: this.expanded,
387
+ sessionOrderByAccount: this.sessionOrderByAccount,
388
+ sessionUpdatedAtByAccount: this.sessionUpdatedAtByAccount,
389
+ };
390
+ },
391
+ persistView() {
392
+ saveWorkspaceView(this.viewState());
393
+ },
394
+ syncOrders(sortByRecency = false) {
395
+ const next = syncWorkspaceViewOrders(this.viewState(), {
396
+ sessions: this.sessions,
397
+ workspaces: this.workspaces,
398
+ currentSessionId: this.sessionId,
399
+ sortByRecency,
400
+ });
401
+ this.sessionOrderByAccount = next.sessionOrderByAccount;
402
+ this.sessionUpdatedAtByAccount = next.sessionUpdatedAtByAccount;
403
+ this.persistView();
404
+ },
405
+ openSessionActions(session, group) {
406
+ this.sessionSheet = {
407
+ session,
408
+ workspaceId: group.workspaceId || workspaceForSession(this.workspaces, session.sessionId)?.workspaceId || "",
409
+ groupKey: group.key,
410
+ };
411
+ },
412
+ beginRenameSession() {
413
+ const row = this.sessionSheet?.session;
414
+ if (!row) return;
415
+ this.sessionSheet = null;
416
+ this.renameSheet = { kind: "session", sessionId: row.sessionId };
417
+ this.renameValue = row.title || "";
418
+ },
419
+ beginArchiveSession() {
420
+ const row = this.sessionSheet?.session;
421
+ if (!row) return;
422
+ this.sessionSheet = null;
423
+ this.confirmSheet = {
424
+ kind: "archive-session",
425
+ sessionId: row.sessionId,
426
+ title: this.t("desktop.archiveSession"),
427
+ description: this.t("desktop.archiveSessionConfirm"),
428
+ confirmLabel: this.t("desktop.archiveSession"),
429
+ };
430
+ },
431
+ beginMoveSession() {
432
+ const sheet = this.sessionSheet;
433
+ if (!sheet) return;
434
+ this.sessionSheet = null;
435
+ this.moveSheet = {
436
+ sessionId: sheet.session.sessionId,
437
+ workspaceId: sheet.workspaceId,
438
+ };
439
+ },
440
+ submitRename() {
441
+ if (!this.renameSheet || !this.renameValue.trim()) return;
442
+ if (this.renameSheet.kind === "session") {
443
+ this.$emit("rename-session", this.renameSheet.sessionId, this.renameValue.trim());
444
+ }
445
+ this.renameSheet = null;
446
+ this.renameValue = "";
447
+ },
448
+ submitConfirm() {
449
+ if (!this.confirmSheet) return;
450
+ if (this.confirmSheet.kind === "archive-session") {
451
+ this.$emit("archive-session", this.confirmSheet.sessionId);
452
+ }
453
+ this.confirmSheet = null;
454
+ },
455
+ submitMove(targetWorkspaceId) {
456
+ if (!this.moveSheet || !targetWorkspaceId) return;
457
+ this.$emit("move-session", targetWorkspaceId, this.moveSheet.sessionId, "");
458
+ this.moveSheet = null;
66
459
  },
67
460
  },
68
461
  };
@@ -74,10 +467,14 @@ export default {
74
467
  inset: 0;
75
468
  z-index: 4;
76
469
  pointer-events: none;
470
+ visibility: hidden;
471
+ transition: visibility 0s linear var(--lares-duration-sheet, 280ms);
77
472
  }
78
473
 
79
474
  .lares-history[data-open="true"] {
80
475
  pointer-events: auto;
476
+ visibility: visible;
477
+ transition: visibility 0s linear 0s;
81
478
  }
82
479
 
83
480
  .lares-history__backdrop {
@@ -85,7 +482,7 @@ export default {
85
482
  inset: 0;
86
483
  background: var(--q-background-alpha);
87
484
  opacity: 0;
88
- transition: opacity 0.28s cubic-bezier(0.32, 0.72, 0, 1);
485
+ transition: opacity var(--lares-duration-sheet, 280ms) var(--lares-ease-out, cubic-bezier(0.32, 0.72, 0, 1));
89
486
  }
90
487
 
91
488
  .lares-history[data-open="true"] .lares-history__backdrop {
@@ -104,12 +501,15 @@ export default {
104
501
  min-height: 0;
105
502
  background: var(--q-background-1);
106
503
  box-shadow: 8px 0 32px rgb(0 0 0 / 8%);
107
- transform: translateX(-100%);
108
- transition: transform 0.28s cubic-bezier(0.32, 0.72, 0, 1);
504
+ transform: translate3d(-100%, 0, 0);
505
+ transition: transform var(--lares-duration-sheet, 280ms) var(--lares-ease-out, cubic-bezier(0.32, 0.72, 0, 1));
506
+ backface-visibility: hidden;
507
+ contain: layout style paint;
109
508
  }
110
509
 
111
510
  .lares-history[data-open="true"] .lares-history__sheet {
112
- transform: translateX(0);
511
+ transform: translate3d(0, 0, 0);
512
+ will-change: transform;
113
513
  }
114
514
 
115
515
  .lares-history__head {
@@ -122,9 +522,102 @@ export default {
122
522
 
123
523
  .lares-history__title {
124
524
  margin: 0;
125
- font-size: 18px;
525
+ font-size: 20px;
126
526
  font-weight: 500;
127
- line-height: 24px;
527
+ line-height: 26px;
528
+ }
529
+
530
+ .lares-history__toolbar {
531
+ display: flex;
532
+ flex-shrink: 0;
533
+ align-items: center;
534
+ gap: 6px;
535
+ min-height: 36px;
536
+ padding: 0 12px 8px 20px;
537
+ color: var(--q-ink-3);
538
+ font-size: 15px;
539
+ }
540
+
541
+ .lares-history__section-label {
542
+ min-width: 0;
543
+ flex: 1;
544
+ overflow: hidden;
545
+ text-overflow: ellipsis;
546
+ white-space: nowrap;
547
+ }
548
+
549
+ .lares-history__toolbar-actions {
550
+ display: flex;
551
+ flex-shrink: 0;
552
+ align-items: center;
553
+ gap: 2px;
554
+ }
555
+
556
+ .lares-history__toolbar-actions button,
557
+ .lares-history__search button {
558
+ display: grid;
559
+ width: 36px;
560
+ height: 36px;
561
+ place-items: center;
562
+ border: 0;
563
+ border-radius: 999px;
564
+ background: transparent;
565
+ color: var(--q-ink-3);
566
+ }
567
+
568
+ .lares-history__toolbar-actions button:active,
569
+ .lares-history__search button:active {
570
+ background: var(--q-background-hover);
571
+ color: var(--q-ink-1);
572
+ }
573
+
574
+ .lares-history__toolbar-actions svg,
575
+ .lares-history__search > svg {
576
+ width: 20px;
577
+ height: 20px;
578
+ fill: none;
579
+ stroke: currentColor;
580
+ stroke-width: 1.75;
581
+ stroke-linecap: round;
582
+ stroke-linejoin: round;
583
+ }
584
+
585
+ .lares-history__search {
586
+ display: flex;
587
+ width: 100%;
588
+ align-items: center;
589
+ gap: 6px;
590
+ border-radius: 10px;
591
+ padding: 0 4px 0 8px;
592
+ background: var(--q-background-3);
593
+ }
594
+
595
+ .lares-history__search input {
596
+ min-width: 0;
597
+ flex: 1;
598
+ border: 0;
599
+ outline: 0;
600
+ padding: 8px 0;
601
+ background: transparent;
602
+ color: var(--q-ink-1);
603
+ font: inherit;
604
+ font-size: 15px;
605
+ }
606
+
607
+ .lares-history__search button {
608
+ width: 32px;
609
+ height: 32px;
610
+ font-size: 20px;
611
+ line-height: 1;
612
+ }
613
+
614
+ .lares-history__sheet-label {
615
+ margin: 0;
616
+ padding: 8px 16px 4px;
617
+ color: var(--q-ink-3);
618
+ font-size: 14px;
619
+ font-weight: 500;
620
+ line-height: 18px;
128
621
  }
129
622
 
130
623
  .lares-history__list {
@@ -132,7 +625,7 @@ export default {
132
625
  flex: 1;
133
626
  min-height: 0;
134
627
  flex-direction: column;
135
- gap: 16px;
628
+ gap: 12px;
136
629
  overflow-x: hidden;
137
630
  overflow-y: auto;
138
631
  padding: 4px 12px 24px;
@@ -146,21 +639,189 @@ export default {
146
639
  gap: 4px;
147
640
  }
148
641
 
149
- .lares-history__label {
150
- margin: 0;
151
- padding: 8px 16px 4px;
152
- color: var(--q-ink-3);
153
- font-size: 12px;
642
+ .lares-history__group-head {
643
+ display: flex;
644
+ align-items: center;
645
+ gap: 4px;
646
+ padding: 0 4px;
647
+ }
648
+
649
+ .lares-history__group-toggle {
650
+ display: flex;
651
+ min-width: 0;
652
+ flex: 1;
653
+ align-items: center;
654
+ gap: 8px;
655
+ border: 0;
656
+ border-radius: 10px;
657
+ padding: 8px 6px;
658
+ background: transparent;
659
+ color: var(--q-ink-2);
660
+ font-size: 14px;
154
661
  font-weight: 500;
155
- line-height: 16px;
662
+ text-align: left;
663
+ }
664
+
665
+ .lares-history__group-toggle[data-active="true"] .lares-history__folder {
666
+ color: var(--q-blue-default);
667
+ }
668
+
669
+ .lares-history__group-icon {
670
+ display: grid;
671
+ width: 18px;
672
+ height: 18px;
673
+ flex: none;
674
+ place-items: center;
675
+ }
676
+
677
+ .lares-history__group-icon svg {
678
+ grid-area: 1 / 1;
679
+ }
680
+
681
+ .lares-history__folder {
682
+ fill: none;
683
+ stroke: var(--q-ink-3);
684
+ stroke-width: 1.7;
685
+ stroke-linecap: round;
686
+ stroke-linejoin: round;
687
+ }
688
+
689
+ .lares-history__caret {
690
+ fill: currentColor;
691
+ stroke: none;
692
+ color: var(--q-ink-3);
693
+ transform: rotate(0deg);
694
+ transition: transform 120ms ease;
695
+ }
696
+
697
+ .lares-history__group-icon[data-expanded="true"] .lares-history__caret {
698
+ transform: rotate(90deg);
699
+ }
700
+
701
+ .lares-history__group-toggle > span:last-child {
702
+ min-width: 0;
703
+ overflow: hidden;
704
+ text-overflow: ellipsis;
705
+ white-space: nowrap;
706
+ }
707
+
708
+ .lares-history__group-new {
709
+ display: grid;
710
+ width: 32px;
711
+ height: 32px;
712
+ flex: none;
713
+ place-items: center;
714
+ border: 0;
715
+ border-radius: 999px;
716
+ background: transparent;
717
+ color: var(--q-ink-3);
718
+ }
719
+
720
+ .lares-history__group-new svg {
721
+ width: 18px;
722
+ height: 18px;
723
+ fill: none;
724
+ stroke: currentColor;
725
+ stroke-width: 1.8;
726
+ stroke-linecap: round;
727
+ }
728
+
729
+ .lares-history__sessions {
730
+ display: flex;
731
+ flex-direction: column;
732
+ gap: 2px;
733
+ }
734
+
735
+ .lares-history__session-row {
736
+ display: flex;
737
+ align-items: center;
738
+ border-radius: 12px;
739
+ padding-right: 4px;
740
+ }
741
+
742
+ .lares-history__session-row[data-current="true"] {
743
+ background: var(--q-background-3);
744
+ }
745
+
746
+ .lares-history__item {
747
+ display: flex;
748
+ min-width: 0;
749
+ flex: 1;
750
+ align-items: center;
751
+ gap: 8px;
752
+ overflow: hidden;
753
+ border: 0;
754
+ border-radius: 12px;
755
+ padding: 12px 8px 12px 16px;
756
+ text-align: left;
757
+ background: transparent;
758
+ color: var(--q-ink-1);
759
+ text-overflow: ellipsis;
760
+ white-space: nowrap;
761
+ }
762
+
763
+ .lares-history__unseen {
764
+ width: 6px;
765
+ height: 6px;
766
+ flex: none;
767
+ border-radius: 50%;
768
+ background: transparent;
769
+ }
770
+
771
+ .lares-history__session-row[data-unseen="true"] .lares-history__unseen {
772
+ background: var(--q-positive, var(--q-green-default, #21c55d));
773
+ }
774
+
775
+ .lares-history__more {
776
+ display: grid;
777
+ width: 36px;
778
+ height: 36px;
779
+ flex: none;
780
+ place-items: center;
781
+ border: 0;
782
+ border-radius: 999px;
783
+ background: transparent;
784
+ color: var(--q-ink-3);
785
+ }
786
+
787
+ .lares-history__more svg {
788
+ width: 18px;
789
+ height: 18px;
790
+ fill: currentColor;
791
+ stroke: none;
792
+ }
793
+
794
+ .lares-history__more:active {
795
+ background: var(--q-background-hover);
796
+ color: var(--q-ink-2);
797
+ }
798
+
799
+ .lares-history__overflow {
800
+ width: 100%;
801
+ border: 0;
802
+ border-radius: 10px;
803
+ padding: 8px 8px 8px 24px;
804
+ background: transparent;
805
+ color: var(--q-ink-3);
806
+ font-size: 14px;
807
+ text-align: left;
156
808
  }
157
809
 
158
810
  .lares-history__empty {
159
811
  margin: 12px 8px;
160
- font-size: 13px;
812
+ font-size: 15px;
161
813
  color: var(--q-ink-3);
162
814
  }
163
815
 
816
+ .lares-history__empty button {
817
+ display: block;
818
+ margin-top: 8px;
819
+ border: 0;
820
+ background: transparent;
821
+ color: var(--q-blue-default);
822
+ font: inherit;
823
+ }
824
+
164
825
  .lares-history__skeleton {
165
826
  display: flex;
166
827
  flex-direction: column;
@@ -184,43 +845,74 @@ export default {
184
845
 
185
846
  .lares-history__section .lares-history__bone:nth-child(2) { width: 88%; }
186
847
  .lares-history__section .lares-history__bone:nth-child(3) { width: 72%; }
187
- .lares-history__section .lares-history__bone:nth-child(4) { width: 80%; }
188
- .lares-history__section .lares-history__bone:nth-child(5) { width: 64%; }
189
848
 
190
849
  @keyframes lares-history-pulse {
191
850
  50% { opacity: 0.45; }
192
851
  }
193
852
 
194
- @media (prefers-reduced-motion: reduce) {
195
- .lares-history__bone {
196
- animation: none;
197
- }
853
+ .lares-history__input {
854
+ box-sizing: border-box;
855
+ width: calc(100% - 40px);
856
+ height: 44px;
857
+ margin: 0 20px 12px;
858
+ border: 1px solid var(--q-separator);
859
+ border-radius: 12px;
860
+ padding: 0 12px;
861
+ outline: none;
862
+ background: var(--q-background-2, transparent);
863
+ color: var(--q-ink-1);
864
+ font: inherit;
865
+ font-size: 16px;
198
866
  }
199
867
 
200
- .lares-history__item {
201
- width: 100%;
202
- overflow: hidden;
203
- border: 0;
204
- border-radius: 12px;
205
- padding: 12px 16px;
206
- text-align: left;
868
+ .lares-history__sheet-actions {
869
+ display: flex;
870
+ justify-content: flex-end;
871
+ gap: 8px;
872
+ padding: 0 20px 12px;
873
+ }
874
+
875
+ .lares-history__cancel,
876
+ .lares-history__confirm {
877
+ min-height: 40px;
878
+ border-radius: 10px;
879
+ padding: 0 14px;
880
+ font: inherit;
881
+ }
882
+
883
+ .lares-history__cancel {
884
+ border: 1px solid var(--q-separator);
207
885
  background: transparent;
208
- color: var(--q-ink-1);
209
- text-overflow: ellipsis;
210
- white-space: nowrap;
886
+ color: var(--q-ink-2);
211
887
  }
212
888
 
213
- .lares-history__item[data-current="true"] {
214
- background: var(--q-background-3);
889
+ .lares-history__confirm {
890
+ border: 0;
891
+ background: var(--q-blue-default);
892
+ color: var(--q-ink-on-brand);
215
893
  }
216
894
 
217
- .lares-history__item:active {
218
- background: var(--q-background-hover);
895
+ .lares-history__confirm--danger {
896
+ background: var(--q-orange-default);
897
+ }
898
+
899
+ .lares-history__confirm:disabled {
900
+ opacity: 0.5;
901
+ }
902
+
903
+ .lares-history__confirm-copy {
904
+ margin: 0;
905
+ padding: 0 20px 16px;
906
+ color: var(--q-ink-2);
907
+ font-size: 15px;
908
+ line-height: 22px;
219
909
  }
220
910
 
221
911
  @media (prefers-reduced-motion: reduce) {
222
912
  .lares-history__backdrop,
223
- .lares-history__sheet {
913
+ .lares-history__sheet,
914
+ .lares-history__bone {
915
+ animation: none;
224
916
  transition: none;
225
917
  }
226
918
  }