@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.
- package/README.md +6 -2
- package/package.json +2 -2
- package/src/App.vue +924 -184
- package/src/chat/ChatBar.vue +2 -2
- package/src/chat/Composer.vue +467 -16
- package/src/chat/Deliverables.vue +22 -10
- package/src/chat/HistoryPanel.vue +747 -55
- package/src/chat/MessageActions.vue +88 -34
- package/src/chat/QuestionCard.vue +5 -5
- package/src/chat/StageRow.vue +8 -5
- package/src/chat/Transcript.vue +20 -6
- package/src/chat/composer-tokens.js +32 -0
- package/src/chat/format.js +37 -0
- package/src/desktop/DesktopComposer.vue +871 -0
- package/src/desktop/DesktopContextMeter.vue +81 -0
- package/src/desktop/DesktopGoal.vue +88 -0
- package/src/desktop/DesktopPreview.vue +58 -0
- package/src/desktop/DesktopPreviewTabs.vue +82 -0
- package/src/desktop/DesktopQuestions.vue +118 -0
- package/src/desktop/DesktopQueue.vue +203 -0
- package/src/desktop/DesktopShell.vue +203 -0
- package/src/desktop/DesktopSidebar.vue +645 -0
- package/src/desktop/DesktopTodos.vue +52 -0
- package/src/desktop/DirectoryBrowser.vue +170 -0
- package/src/desktop/DirectoryNewFolder.vue +124 -0
- package/src/desktop/ui/PcDialog.vue +85 -0
- package/src/desktop/ui/PcPopover.vue +110 -0
- package/src/desktop/ui/PcTooltip.vue +95 -0
- package/src/desktop/ui/place.js +24 -0
- package/src/desktop/workspace-view.js +121 -0
- package/src/host.js +20 -2
- package/src/index.d.ts +2 -0
- package/src/mobile/MobileDirectoryNewFolder.vue +121 -0
- package/src/mobile/MobileDirectorySheet.vue +162 -0
- package/src/mobile/MobileNewSession.vue +217 -0
- package/src/mobile/MobileShell.vue +367 -0
- package/src/motion.css +166 -0
- package/src/preview/Preview.vue +91 -150
- package/src/preview/PreviewBody.vue +185 -0
- package/src/settings/AgentSettings.vue +126 -36
- package/src/settings/Select.vue +183 -0
- package/src/settings/SettingRow.vue +5 -4
- package/src/settings/Sheet.vue +4 -4
- package/src/styles.css +9 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="lares-mobile-shell">
|
|
3
|
+
<LaresChatBar
|
|
4
|
+
:t="t"
|
|
5
|
+
:title="barTitle"
|
|
6
|
+
:starting="state.starting"
|
|
7
|
+
@history="$emit('history')"
|
|
8
|
+
@create="$emit('create', state.currentWorkspaceId || null)"
|
|
9
|
+
/>
|
|
10
|
+
<LaresHistoryPanel
|
|
11
|
+
:open="state.panel === 'history'"
|
|
12
|
+
:sessions="state.sessions"
|
|
13
|
+
:workspaces="state.workspaces"
|
|
14
|
+
:workspaces-ready="state.workspacesReady"
|
|
15
|
+
:workspace-error="state.workspaceError"
|
|
16
|
+
:archived-session-ids="state.archivedSessionIds"
|
|
17
|
+
:session-id="state.sessionId"
|
|
18
|
+
:ready="state.sessionsReady"
|
|
19
|
+
:unseen="state.unseen"
|
|
20
|
+
:t="t"
|
|
21
|
+
@close="$emit('close-history')"
|
|
22
|
+
@pick="$emit('pick-session', $event)"
|
|
23
|
+
@create="$emit('create', $event)"
|
|
24
|
+
@browse-workspaces="$emit('browse-workspaces')"
|
|
25
|
+
@refresh-workspaces="$emit('refresh-workspaces')"
|
|
26
|
+
@rename-session="(id, title) => $emit('rename-session', id, title)"
|
|
27
|
+
@archive-session="$emit('archive-session', $event)"
|
|
28
|
+
@move-session="(workspaceId, sessionId, before) => $emit('move-session', workspaceId, sessionId, before)"
|
|
29
|
+
/>
|
|
30
|
+
<LaresMobileDirectorySheet
|
|
31
|
+
:open="state.directory.open"
|
|
32
|
+
:state="state.directory"
|
|
33
|
+
:t="t"
|
|
34
|
+
@close="$emit('close-directory')"
|
|
35
|
+
@browse="$emit('browse-directory', $event)"
|
|
36
|
+
@choose="$emit('choose-directory', $event)"
|
|
37
|
+
@create-folder="$emit('create-folder', $event)"
|
|
38
|
+
@toggle-hidden="$emit('toggle-hidden', $event)"
|
|
39
|
+
/>
|
|
40
|
+
<div class="lares-shell__conversation" :data-hero="newSessionHero ? 'true' : 'false'">
|
|
41
|
+
<p v-if="state.failed" class="lares-shell__status">{{ state.failText }}</p>
|
|
42
|
+
<button
|
|
43
|
+
v-if="state.failed"
|
|
44
|
+
type="button"
|
|
45
|
+
class="lares-shell__retry"
|
|
46
|
+
:disabled="state.starting"
|
|
47
|
+
@click="$emit('retry')"
|
|
48
|
+
>
|
|
49
|
+
{{ t("probe.retry") }}
|
|
50
|
+
</button>
|
|
51
|
+
|
|
52
|
+
<Transition name="lares-view" mode="out-in">
|
|
53
|
+
<LaresMobileNewSession
|
|
54
|
+
v-if="newSessionHero"
|
|
55
|
+
key="hero"
|
|
56
|
+
:t="t"
|
|
57
|
+
:workspace-label="workspaceLabel"
|
|
58
|
+
:workspace-busy="!state.workspacesReady && !state.workspaceError"
|
|
59
|
+
:model-label="state.modelLabel"
|
|
60
|
+
:model-busy="state.modelBusy"
|
|
61
|
+
@workspace="workspaceSheet = true"
|
|
62
|
+
@model="$emit('open-model')"
|
|
63
|
+
>
|
|
64
|
+
<LaresComposer
|
|
65
|
+
ref="composer"
|
|
66
|
+
hero
|
|
67
|
+
:draft="state.draft"
|
|
68
|
+
:sending="state.sending"
|
|
69
|
+
:can-send="state.canSend"
|
|
70
|
+
:model-label="state.modelLabel"
|
|
71
|
+
:model-busy="state.modelBusy"
|
|
72
|
+
:effort-label="state.effortLabel"
|
|
73
|
+
:effort-disabled="state.effortDisabled"
|
|
74
|
+
:attach-pending="state.upload.pending > 0"
|
|
75
|
+
:attach-disabled="!state.sessionId || state.historyLoading || state.starting"
|
|
76
|
+
:voice-phase="state.voicePhase"
|
|
77
|
+
:voice-elapsed="state.voiceElapsed"
|
|
78
|
+
:voice-error="state.voiceErrorText"
|
|
79
|
+
:failures="state.upload.failures"
|
|
80
|
+
:draft-images="state.draftImages"
|
|
81
|
+
:references="state.references"
|
|
82
|
+
:references-loading="state.referencesLoading"
|
|
83
|
+
:references-error="state.referencesError"
|
|
84
|
+
:commands="state.commands"
|
|
85
|
+
:commands-error="state.commandsError"
|
|
86
|
+
:t="t"
|
|
87
|
+
@update:draft="$emit('update-draft', $event)"
|
|
88
|
+
@send="$emit('send')"
|
|
89
|
+
@model="$emit('open-model')"
|
|
90
|
+
@effort="$emit('open-effort')"
|
|
91
|
+
@files="$emit('files', $event)"
|
|
92
|
+
@voice="$emit('voice')"
|
|
93
|
+
@hold-start="$emit('hold-start')"
|
|
94
|
+
@hold-end="$emit('hold-end')"
|
|
95
|
+
@open-commands="$emit('open-commands')"
|
|
96
|
+
@open-references="$emit('open-references', $event)"
|
|
97
|
+
@pick-command="$emit('pick-command', $event)"
|
|
98
|
+
@remove-image="$emit('remove-image', $event)"
|
|
99
|
+
/>
|
|
100
|
+
</LaresMobileNewSession>
|
|
101
|
+
|
|
102
|
+
<div v-else key="chat" class="lares-shell__chat">
|
|
103
|
+
<LaresTranscript
|
|
104
|
+
ref="transcript"
|
|
105
|
+
:items="state.viewItems"
|
|
106
|
+
:running="state.running"
|
|
107
|
+
:loading="state.historyLoading || state.starting"
|
|
108
|
+
:previews="state.previews"
|
|
109
|
+
:media-url="mediaUrl"
|
|
110
|
+
:scroll-top="scrollTop"
|
|
111
|
+
:remember-scroll="rememberScroll"
|
|
112
|
+
:sticking="sticking"
|
|
113
|
+
:session-id="state.sessionId"
|
|
114
|
+
:question="state.question"
|
|
115
|
+
:question-busy="state.questionBusy"
|
|
116
|
+
:t="t"
|
|
117
|
+
@open="$emit('open-file', $event)"
|
|
118
|
+
@media="pinLog"
|
|
119
|
+
@answer="forwardAnswer"
|
|
120
|
+
/>
|
|
121
|
+
<LaresComposer
|
|
122
|
+
ref="composer"
|
|
123
|
+
:draft="state.draft"
|
|
124
|
+
:sending="state.sending"
|
|
125
|
+
:can-send="state.canSend"
|
|
126
|
+
:model-label="state.modelLabel"
|
|
127
|
+
:model-busy="state.modelBusy"
|
|
128
|
+
:effort-label="state.effortLabel"
|
|
129
|
+
:effort-disabled="state.effortDisabled"
|
|
130
|
+
:attach-pending="state.upload.pending > 0"
|
|
131
|
+
:attach-disabled="!state.sessionId || state.historyLoading || state.starting"
|
|
132
|
+
:voice-phase="state.voicePhase"
|
|
133
|
+
:voice-elapsed="state.voiceElapsed"
|
|
134
|
+
:voice-error="state.voiceErrorText"
|
|
135
|
+
:failures="state.upload.failures"
|
|
136
|
+
:draft-images="state.draftImages"
|
|
137
|
+
:references="state.references"
|
|
138
|
+
:references-loading="state.referencesLoading"
|
|
139
|
+
:references-error="state.referencesError"
|
|
140
|
+
:commands="state.commands"
|
|
141
|
+
:commands-error="state.commandsError"
|
|
142
|
+
:t="t"
|
|
143
|
+
@update:draft="$emit('update-draft', $event)"
|
|
144
|
+
@send="$emit('send')"
|
|
145
|
+
@model="$emit('open-model')"
|
|
146
|
+
@effort="$emit('open-effort')"
|
|
147
|
+
@files="$emit('files', $event)"
|
|
148
|
+
@voice="$emit('voice')"
|
|
149
|
+
@hold-start="$emit('hold-start')"
|
|
150
|
+
@hold-end="$emit('hold-end')"
|
|
151
|
+
@open-commands="$emit('open-commands')"
|
|
152
|
+
@open-references="$emit('open-references', $event)"
|
|
153
|
+
@pick-command="$emit('pick-command', $event)"
|
|
154
|
+
@remove-image="$emit('remove-image', $event)"
|
|
155
|
+
/>
|
|
156
|
+
</div>
|
|
157
|
+
</Transition>
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
<LaresSheet :open="workspaceSheet" :title="t('desktop.workspaces')" @close="workspaceSheet = false">
|
|
161
|
+
<p v-if="state.workspaceError" class="lares-shell__status">{{ state.workspaceError }}</p>
|
|
162
|
+
<p v-else-if="!state.workspacesReady" class="lares-shell__hint">{{ t("agent.loading") }}</p>
|
|
163
|
+
<p v-else-if="!state.workspaces.length" class="lares-shell__hint">{{ t("desktop.noFolders") }}</p>
|
|
164
|
+
<LaresSettingRow
|
|
165
|
+
v-for="workspace in state.workspaces"
|
|
166
|
+
:key="workspace.workspaceId"
|
|
167
|
+
:label="workspace.title"
|
|
168
|
+
:checked="workspace.workspaceId === state.currentWorkspaceId"
|
|
169
|
+
@click="pickWorkspace(workspace.workspaceId)"
|
|
170
|
+
/>
|
|
171
|
+
</LaresSheet>
|
|
172
|
+
<LaresSheet :open="state.modelSheet" :title="t('model.menuAria')" @close="$emit('close-model')">
|
|
173
|
+
<p v-if="state.modelError" class="lares-shell__status">{{ state.modelError }}</p>
|
|
174
|
+
<p v-else-if="!state.models" class="lares-shell__hint">{{ t("agent.loading") }}</p>
|
|
175
|
+
<p v-else-if="!state.modelGroups.length" class="lares-shell__hint">{{ t("model.empty") }}</p>
|
|
176
|
+
<template v-for="section in state.modelGroups" :key="section.provider">
|
|
177
|
+
<p class="lares-shell__heading">{{ section.provider }}</p>
|
|
178
|
+
<LaresSettingRow
|
|
179
|
+
v-for="item in section.models"
|
|
180
|
+
:key="modelKey(item)"
|
|
181
|
+
:label="item.name"
|
|
182
|
+
:checked="modelKey(item) === state.modelCurrent"
|
|
183
|
+
:disabled="state.modelBusy"
|
|
184
|
+
@click="$emit('choose-model', item)"
|
|
185
|
+
/>
|
|
186
|
+
</template>
|
|
187
|
+
</LaresSheet>
|
|
188
|
+
<LaresSheet :open="state.effortSheet" :title="t('reasoning.title')" @close="$emit('close-effort')">
|
|
189
|
+
<p v-if="!state.effortRows.length" class="lares-shell__hint">{{ t("reasoning.default") }}</p>
|
|
190
|
+
<LaresSettingRow
|
|
191
|
+
v-for="row in state.effortRows"
|
|
192
|
+
:key="row.key"
|
|
193
|
+
:label="effortName(row)"
|
|
194
|
+
:checked="row.id === state.effortId"
|
|
195
|
+
:disabled="state.modelBusy"
|
|
196
|
+
@click="$emit('choose-effort', row.id)"
|
|
197
|
+
/>
|
|
198
|
+
</LaresSheet>
|
|
199
|
+
<Transition name="lares-preview">
|
|
200
|
+
<LaresPreview
|
|
201
|
+
v-if="state.previewMode === 'preview' && state.preview.path"
|
|
202
|
+
:path="state.preview.path"
|
|
203
|
+
:session-id="state.sessionId"
|
|
204
|
+
:status="state.preview.status"
|
|
205
|
+
:data="state.preview.data"
|
|
206
|
+
:error="state.preview.error"
|
|
207
|
+
:media-src="state.previewMediaSrc"
|
|
208
|
+
:download-href="state.previewDownloadHref"
|
|
209
|
+
:href-for="previewHref"
|
|
210
|
+
:t="t"
|
|
211
|
+
@close="$emit('close-preview')"
|
|
212
|
+
@retry="$emit('open-file', state.preview.path)"
|
|
213
|
+
@open="$emit('open-file', $event)"
|
|
214
|
+
/>
|
|
215
|
+
</Transition>
|
|
216
|
+
</div>
|
|
217
|
+
</template>
|
|
218
|
+
|
|
219
|
+
<script>
|
|
220
|
+
import LaresChatBar from "../chat/ChatBar.vue";
|
|
221
|
+
import LaresHistoryPanel from "../chat/HistoryPanel.vue";
|
|
222
|
+
import LaresTranscript from "../chat/Transcript.vue";
|
|
223
|
+
import LaresComposer from "../chat/Composer.vue";
|
|
224
|
+
import LaresPreview from "../preview/Preview.vue";
|
|
225
|
+
import LaresSheet from "../settings/Sheet.vue";
|
|
226
|
+
import LaresSettingRow from "../settings/SettingRow.vue";
|
|
227
|
+
import LaresMobileDirectorySheet from "./MobileDirectorySheet.vue";
|
|
228
|
+
import LaresMobileNewSession from "./MobileNewSession.vue";
|
|
229
|
+
import { DEFAULT_WORKSPACE_TITLE } from "@olares/lares-core/workspace/constants";
|
|
230
|
+
|
|
231
|
+
export default {
|
|
232
|
+
name: "LaresMobileShell",
|
|
233
|
+
components: {
|
|
234
|
+
LaresChatBar,
|
|
235
|
+
LaresHistoryPanel,
|
|
236
|
+
LaresTranscript,
|
|
237
|
+
LaresComposer,
|
|
238
|
+
LaresPreview,
|
|
239
|
+
LaresSheet,
|
|
240
|
+
LaresSettingRow,
|
|
241
|
+
LaresMobileDirectorySheet,
|
|
242
|
+
LaresMobileNewSession,
|
|
243
|
+
},
|
|
244
|
+
props: {
|
|
245
|
+
state: { type: Object, required: true },
|
|
246
|
+
t: { type: Function, required: true },
|
|
247
|
+
mediaUrl: { type: Function, required: true },
|
|
248
|
+
scrollTop: { type: Function, required: true },
|
|
249
|
+
rememberScroll: { type: Function, required: true },
|
|
250
|
+
sticking: { type: Function, required: true },
|
|
251
|
+
previewHref: { type: Function, required: true },
|
|
252
|
+
modelKey: { type: Function, required: true },
|
|
253
|
+
effortName: { type: Function, required: true },
|
|
254
|
+
},
|
|
255
|
+
emits: [
|
|
256
|
+
"history", "create", "close-history", "pick-session", "retry", "open-file",
|
|
257
|
+
"answer", "update-draft", "send", "open-model", "open-effort", "files",
|
|
258
|
+
"voice", "hold-start", "hold-end", "close-model", "choose-model",
|
|
259
|
+
"close-effort", "choose-effort", "close-preview",
|
|
260
|
+
"open-commands", "open-references", "pick-command", "remove-image",
|
|
261
|
+
"refresh-workspaces", "browse-workspaces", "browse-directory",
|
|
262
|
+
"close-directory", "choose-directory", "create-folder", "toggle-hidden",
|
|
263
|
+
"rename-session", "archive-session",
|
|
264
|
+
"move-session", "pick-workspace",
|
|
265
|
+
],
|
|
266
|
+
data() {
|
|
267
|
+
return { workspaceSheet: false };
|
|
268
|
+
},
|
|
269
|
+
computed: {
|
|
270
|
+
newSessionHero() {
|
|
271
|
+
if (this.state.previewMode === "preview" && this.state.preview.path) return false;
|
|
272
|
+
return (
|
|
273
|
+
this.state.viewItems.length === 0
|
|
274
|
+
&& !this.state.running
|
|
275
|
+
&& !this.state.historyLoading
|
|
276
|
+
&& !this.state.starting
|
|
277
|
+
);
|
|
278
|
+
},
|
|
279
|
+
barTitle() {
|
|
280
|
+
return this.newSessionHero ? this.t("desktop.newSession") : this.state.sessionTitle;
|
|
281
|
+
},
|
|
282
|
+
workspaceLabel() {
|
|
283
|
+
if (!this.state.workspacesReady) return this.t("agent.loading");
|
|
284
|
+
const current = this.state.workspaces.find(
|
|
285
|
+
(row) => row.workspaceId === this.state.currentWorkspaceId,
|
|
286
|
+
);
|
|
287
|
+
if (current?.title) return current.title;
|
|
288
|
+
if (this.state.workspaces[0]?.title) return this.state.workspaces[0].title;
|
|
289
|
+
return DEFAULT_WORKSPACE_TITLE;
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
methods: {
|
|
293
|
+
pickWorkspace(workspaceId) {
|
|
294
|
+
this.workspaceSheet = false;
|
|
295
|
+
if (!workspaceId || workspaceId === this.state.currentWorkspaceId) return;
|
|
296
|
+
this.$emit("pick-workspace", workspaceId);
|
|
297
|
+
},
|
|
298
|
+
forwardAnswer(label, row) {
|
|
299
|
+
this.$emit("answer", label, row);
|
|
300
|
+
},
|
|
301
|
+
restoreLog() {
|
|
302
|
+
this.$refs.transcript?.restoreLog?.();
|
|
303
|
+
},
|
|
304
|
+
captureLog() {
|
|
305
|
+
this.$refs.transcript?.captureLog?.();
|
|
306
|
+
},
|
|
307
|
+
pinLog() {
|
|
308
|
+
this.$refs.transcript?.scheduleLogPin?.();
|
|
309
|
+
},
|
|
310
|
+
focusComposer() {
|
|
311
|
+
this.$refs.composer?.focus?.();
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
};
|
|
315
|
+
</script>
|
|
316
|
+
|
|
317
|
+
<style scoped>
|
|
318
|
+
.lares-mobile-shell {
|
|
319
|
+
position: relative;
|
|
320
|
+
display: flex;
|
|
321
|
+
flex: 1;
|
|
322
|
+
min-height: 0;
|
|
323
|
+
flex-direction: column;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.lares-shell__conversation[data-hero="true"] {
|
|
327
|
+
justify-content: center;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.lares-shell__chat {
|
|
331
|
+
display: flex;
|
|
332
|
+
min-width: 0;
|
|
333
|
+
min-height: 0;
|
|
334
|
+
flex: 1;
|
|
335
|
+
flex-direction: column;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.lares-shell__status,
|
|
339
|
+
.lares-shell__hint {
|
|
340
|
+
margin: 0 20px;
|
|
341
|
+
font-size: 15px;
|
|
342
|
+
color: var(--q-ink-3);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.lares-shell__status {
|
|
346
|
+
color: var(--q-orange-default);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.lares-shell__retry {
|
|
350
|
+
align-self: flex-start;
|
|
351
|
+
margin: 0 20px;
|
|
352
|
+
border: 0;
|
|
353
|
+
border-radius: 8px;
|
|
354
|
+
padding: 8px 12px;
|
|
355
|
+
background: var(--q-blue-alpha);
|
|
356
|
+
color: var(--q-blue-default);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.lares-shell__heading {
|
|
360
|
+
margin: 0;
|
|
361
|
+
padding: 12px 16px 4px;
|
|
362
|
+
color: var(--q-ink-3);
|
|
363
|
+
font-size: 14px;
|
|
364
|
+
font-weight: 500;
|
|
365
|
+
line-height: 18px;
|
|
366
|
+
}
|
|
367
|
+
</style>
|
package/src/motion.css
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/* Shared motion tokens — align with Sheet / HistoryPanel easing. */
|
|
2
|
+
.lares-shell {
|
|
3
|
+
--lares-ease-out: cubic-bezier(0.32, 0.72, 0, 1);
|
|
4
|
+
--lares-ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
|
|
5
|
+
--lares-duration-fast: 120ms;
|
|
6
|
+
--lares-duration-normal: 220ms;
|
|
7
|
+
--lares-duration-sheet: 280ms;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@media (prefers-reduced-motion: reduce) {
|
|
11
|
+
.lares-shell {
|
|
12
|
+
--lares-duration-fast: 0ms;
|
|
13
|
+
--lares-duration-normal: 0ms;
|
|
14
|
+
--lares-duration-sheet: 0ms;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* Mobile full-screen preview — push from the right. */
|
|
19
|
+
.lares-preview-enter-active,
|
|
20
|
+
.lares-preview-leave-active {
|
|
21
|
+
transition: transform var(--lares-duration-sheet) var(--lares-ease-out);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.lares-preview-enter-from,
|
|
25
|
+
.lares-preview-leave-to {
|
|
26
|
+
transform: translateX(100%);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Desktop preview overlay — fade over the conversation. */
|
|
30
|
+
.lares-desk-preview-enter-active,
|
|
31
|
+
.lares-desk-preview-leave-active {
|
|
32
|
+
transition: opacity var(--lares-duration-normal) var(--lares-ease-out);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.lares-desk-preview-enter-from,
|
|
36
|
+
.lares-desk-preview-leave-to {
|
|
37
|
+
opacity: 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* Modal dialog — backdrop fade + surface scale. */
|
|
41
|
+
.lares-dialog-enter-active,
|
|
42
|
+
.lares-dialog-leave-active {
|
|
43
|
+
transition: opacity var(--lares-duration-normal) var(--lares-ease-out);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.lares-dialog-enter-active .lares-pc-dialog__surface,
|
|
47
|
+
.lares-dialog-leave-active .lares-pc-dialog__surface {
|
|
48
|
+
transition: transform var(--lares-duration-normal) var(--lares-ease-out),
|
|
49
|
+
opacity var(--lares-duration-normal) var(--lares-ease-out);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.lares-dialog-enter-from,
|
|
53
|
+
.lares-dialog-leave-to {
|
|
54
|
+
opacity: 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.lares-dialog-enter-from .lares-pc-dialog__surface,
|
|
58
|
+
.lares-dialog-leave-to .lares-pc-dialog__surface {
|
|
59
|
+
opacity: 0;
|
|
60
|
+
transform: scale(0.96) translateY(8px);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* Popover menu — subtle rise. */
|
|
64
|
+
.lares-popover-enter-active,
|
|
65
|
+
.lares-popover-leave-active {
|
|
66
|
+
transition: opacity var(--lares-duration-fast) var(--lares-ease-out),
|
|
67
|
+
transform var(--lares-duration-fast) var(--lares-ease-out);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.lares-popover-enter-from,
|
|
71
|
+
.lares-popover-leave-to {
|
|
72
|
+
opacity: 0;
|
|
73
|
+
transform: translateY(-4px) scale(0.98);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* Mobile hero ↔ chat crossfade. */
|
|
77
|
+
.lares-view-enter-active,
|
|
78
|
+
.lares-view-leave-active {
|
|
79
|
+
transition: opacity var(--lares-duration-normal) var(--lares-ease-out),
|
|
80
|
+
transform var(--lares-duration-normal) var(--lares-ease-out);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.lares-view-enter-from {
|
|
84
|
+
opacity: 0;
|
|
85
|
+
transform: translateY(12px);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.lares-view-leave-to {
|
|
89
|
+
opacity: 0;
|
|
90
|
+
transform: translateY(-8px);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* Composer panels (queue, questions, approval). */
|
|
94
|
+
.lares-panel-enter-active,
|
|
95
|
+
.lares-panel-leave-active {
|
|
96
|
+
transition: opacity var(--lares-duration-normal) var(--lares-ease-out),
|
|
97
|
+
transform var(--lares-duration-normal) var(--lares-ease-out);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.lares-panel-enter-from,
|
|
101
|
+
.lares-panel-leave-to {
|
|
102
|
+
opacity: 0;
|
|
103
|
+
transform: translateY(8px);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* Preview tab strip — slide in from the header edge. */
|
|
107
|
+
.lares-tabs-enter-active {
|
|
108
|
+
transition: opacity var(--lares-duration-normal) var(--lares-ease-out),
|
|
109
|
+
transform var(--lares-duration-normal) var(--lares-ease-out);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.lares-tabs-enter-from {
|
|
113
|
+
opacity: 0;
|
|
114
|
+
transform: translateX(12px);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.lares-tab-enter-active,
|
|
118
|
+
.lares-tab-leave-active {
|
|
119
|
+
transition: opacity var(--lares-duration-fast) var(--lares-ease-out),
|
|
120
|
+
transform var(--lares-duration-fast) var(--lares-ease-out);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.lares-tab-enter-from,
|
|
124
|
+
.lares-tab-leave-to {
|
|
125
|
+
opacity: 0;
|
|
126
|
+
transform: scale(0.92);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.lares-tab-leave-active {
|
|
130
|
+
position: absolute;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
@media (prefers-reduced-motion: reduce) {
|
|
134
|
+
.lares-preview-enter-active,
|
|
135
|
+
.lares-preview-leave-active,
|
|
136
|
+
.lares-desk-preview-enter-active,
|
|
137
|
+
.lares-desk-preview-leave-active,
|
|
138
|
+
.lares-dialog-enter-active,
|
|
139
|
+
.lares-dialog-leave-active,
|
|
140
|
+
.lares-dialog-enter-active .lares-pc-dialog__surface,
|
|
141
|
+
.lares-dialog-leave-active .lares-pc-dialog__surface,
|
|
142
|
+
.lares-popover-enter-active,
|
|
143
|
+
.lares-popover-leave-active,
|
|
144
|
+
.lares-view-enter-active,
|
|
145
|
+
.lares-view-leave-active,
|
|
146
|
+
.lares-panel-enter-active,
|
|
147
|
+
.lares-panel-leave-active,
|
|
148
|
+
.lares-tabs-enter-active,
|
|
149
|
+
.lares-tab-enter-active,
|
|
150
|
+
.lares-tab-leave-active {
|
|
151
|
+
transition: none;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.lares-preview-enter-from,
|
|
155
|
+
.lares-preview-leave-to,
|
|
156
|
+
.lares-view-enter-from,
|
|
157
|
+
.lares-view-leave-to,
|
|
158
|
+
.lares-panel-enter-from,
|
|
159
|
+
.lares-panel-leave-to,
|
|
160
|
+
.lares-dialog-enter-from .lares-pc-dialog__surface,
|
|
161
|
+
.lares-dialog-leave-to .lares-pc-dialog__surface,
|
|
162
|
+
.lares-popover-enter-from,
|
|
163
|
+
.lares-popover-leave-to {
|
|
164
|
+
transform: none;
|
|
165
|
+
}
|
|
166
|
+
}
|