@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
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
+ }
@@ -2,62 +2,50 @@
2
2
  <Teleport to="body">
3
3
  <div class="lares-preview" role="dialog" aria-modal="true" :aria-label="t('preview')">
4
4
  <header class="lares-preview__bar">
5
- <button type="button" class="lares-preview__back" @click="$emit('close')">{{ t("chat") }}</button>
6
- <strong class="lares-preview__name" :title="path">{{ name }}</strong>
5
+ <button
6
+ type="button"
7
+ class="lares-preview__icon-btn"
8
+ :aria-label="t('back')"
9
+ @click="$emit('close')"
10
+ >
11
+ <svg class="lares-preview__glyph" viewBox="0 0 24 24" aria-hidden="true">
12
+ <path d="M14.5 6 9 12l5.5 6" />
13
+ </svg>
14
+ </button>
15
+ <h1 class="lares-preview__name" :title="path">{{ name }}</h1>
7
16
  <a
8
17
  v-if="downloadHref"
9
- class="lares-preview__link"
18
+ class="lares-preview__download"
10
19
  :href="downloadHref"
11
20
  download
12
- >{{ t("download") }}</a>
21
+ >
22
+ {{ t("download") }}
23
+ </a>
24
+ <span v-else class="lares-preview__side-spacer" aria-hidden="true" />
13
25
  </header>
14
- <div v-if="status === 'loading'" class="lares-preview__hint">{{ t("loading") }}</div>
15
- <div v-else-if="status === 'error'" class="lares-preview__hint">
16
- <p>{{ failText }}</p>
17
- <button type="button" class="lares-preview__link" @click="$emit('retry')">{{ t("retry") }}</button>
18
- </div>
19
- <div v-else-if="data?.kind === 'image'" class="lares-preview__media">
20
- <img :src="mediaSrc" :alt="name" />
21
- </div>
22
- <div v-else-if="data?.kind === 'video'" class="lares-preview__media">
23
- <video :src="mediaSrc" controls playsinline />
24
- </div>
25
- <div v-else-if="data?.kind === 'audio'" class="lares-preview__media">
26
- <audio :src="mediaSrc" controls />
27
- </div>
28
- <iframe
29
- v-else-if="data?.kind === 'pdf'"
30
- class="lares-preview__pdf"
31
- :src="mediaSrc"
32
- :title="name"
26
+ <LaresPreviewBody
27
+ :path="path"
28
+ :session-id="sessionId"
29
+ :status="status"
30
+ :data="data"
31
+ :error="error"
32
+ :media-src="mediaSrc"
33
+ :href-for="hrefFor"
34
+ :t="t"
35
+ @retry="$emit('retry')"
36
+ @open="$emit('open', $event)"
33
37
  />
34
- <div
35
- v-else-if="data?.kind === 'markdown'"
36
- class="lares-preview__markdown"
37
- v-html="markdownHtml"
38
- @click="onMarkdownClick"
39
- />
40
- <pre v-else-if="data?.kind === 'text'" class="lares-preview__text">{{ data.text }}</pre>
41
- <div v-else-if="data?.kind === 'model3d'" class="lares-preview__hint">
42
- <p>{{ t("model3dHint") }}</p>
43
- </div>
44
- <div v-else class="lares-preview__hint">
45
- <p>{{ t("unsupportedTitle") }}</p>
46
- <p>{{ t("unsupported") }}</p>
47
- </div>
48
- <p v-if="data?.truncated" class="lares-preview__hint">{{ t("truncated") }}</p>
49
38
  </div>
50
39
  </Teleport>
51
40
  </template>
52
41
 
53
42
  <script>
54
- import { fileName, workspaceLinkClickPath } from "@olares/lares-core/files/preview-workspace";
55
- import { rewriteWorkspaceTargets } from "@olares/lares-core/files/markdown";
56
- import { messageFromCode } from "@olares/lares-core/i18n/t";
57
- import { renderMarkdown } from "../chat/markdown.js";
43
+ import { fileName } from "@olares/lares-core/files/filename";
44
+ import LaresPreviewBody from "./PreviewBody.vue";
58
45
 
59
46
  export default {
60
47
  name: "LaresPreview",
48
+ components: { LaresPreviewBody },
61
49
  props: {
62
50
  path: { type: String, required: true },
63
51
  sessionId: { type: String, default: "" },
@@ -74,25 +62,6 @@ export default {
74
62
  name() {
75
63
  return this.data?.name || fileName(this.path);
76
64
  },
77
- failText() {
78
- return messageFromCode(this.t, this.error, "failed");
79
- },
80
- markdownHtml() {
81
- const text = this.data?.text ?? "";
82
- const rewritten = this.hrefFor
83
- ? rewriteWorkspaceTargets(text, this.data?.path ?? this.path, this.hrefFor)
84
- : text;
85
- return renderMarkdown(rewritten);
86
- },
87
- },
88
- methods: {
89
- onMarkdownClick(event) {
90
- if (!this.sessionId) return;
91
- const path = workspaceLinkClickPath(this.sessionId, event);
92
- if (path === null) return;
93
- event.preventDefault();
94
- this.$emit("open", path);
95
- },
96
65
  },
97
66
  };
98
67
  </script>
@@ -100,12 +69,12 @@ export default {
100
69
  <style scoped>
101
70
  .lares-preview {
102
71
  position: fixed;
103
- inset: 0;
104
72
  z-index: 50;
105
73
  display: flex;
106
- flex-direction: column;
107
74
  min-width: 0;
108
75
  min-height: 0;
76
+ flex-direction: column;
77
+ inset: 0;
109
78
  padding-top: env(safe-area-inset-top, 0px);
110
79
  padding-bottom: env(safe-area-inset-bottom, 0px);
111
80
  background: var(--q-background-1);
@@ -113,111 +82,83 @@ export default {
113
82
  }
114
83
 
115
84
  .lares-preview__bar {
85
+ position: relative;
116
86
  display: flex;
117
- gap: 8px;
118
- align-items: center;
119
87
  flex-shrink: 0;
120
- height: 56px;
121
- padding: 0 12px;
88
+ align-items: center;
89
+ justify-content: space-between;
90
+ min-height: 56px;
91
+ padding: 6px 8px;
122
92
  }
123
93
 
124
- .lares-preview__name {
125
- flex: 1;
126
- min-width: 0;
127
- overflow: hidden;
128
- text-overflow: ellipsis;
129
- white-space: nowrap;
130
- font-size: 16px;
131
- font-weight: 500;
94
+ .lares-preview__icon-btn,
95
+ .lares-preview__side-spacer {
96
+ width: 40px;
97
+ height: 40px;
98
+ flex-shrink: 0;
132
99
  }
133
100
 
134
- .lares-preview__back,
135
- .lares-preview__link {
101
+ .lares-preview__icon-btn {
102
+ display: inline-flex;
103
+ align-items: center;
104
+ justify-content: center;
136
105
  border: 0;
137
- background: none;
138
- font: inherit;
139
- color: var(--q-blue-default);
140
- text-decoration: none;
141
- }
142
-
143
- .lares-preview__hint,
144
- .lares-preview__text,
145
- .lares-preview__markdown {
146
- margin: 0;
147
- padding: 12px 20px;
148
- font-size: 14px;
149
- color: var(--q-ink-2);
150
- }
151
-
152
- .lares-preview__text,
153
- .lares-preview__markdown {
154
- flex: 1;
155
- min-height: 0;
156
- overflow: auto;
106
+ border-radius: 999px;
107
+ padding: 0;
108
+ background: transparent;
157
109
  color: var(--q-ink-1);
158
110
  }
159
111
 
160
- .lares-preview__text {
161
- white-space: pre-wrap;
162
- word-break: break-word;
163
- }
164
-
165
- .lares-preview__markdown :deep(p),
166
- .lares-preview__markdown :deep(pre) {
167
- margin: 0 0 10px;
168
- }
169
-
170
- .lares-preview__markdown :deep(ul),
171
- .lares-preview__markdown :deep(ol) {
172
- margin: 4px 0 12px;
173
- padding: 0 0 0 1.35em;
174
- }
175
-
176
- .lares-preview__markdown :deep(ul) {
177
- list-style: disc outside;
178
- }
179
-
180
- .lares-preview__markdown :deep(ol) {
181
- list-style: decimal outside;
112
+ .lares-preview__icon-btn:active {
113
+ background: var(--q-btn-bg-pressed);
182
114
  }
183
115
 
184
- .lares-preview__markdown :deep(li + li) {
185
- margin-top: 6px;
116
+ .lares-preview__glyph {
117
+ width: 22px;
118
+ height: 22px;
119
+ fill: none;
120
+ stroke: currentColor;
121
+ stroke-width: 1.75;
122
+ stroke-linecap: round;
123
+ stroke-linejoin: round;
186
124
  }
187
125
 
188
- .lares-preview__markdown :deep(img) {
189
- max-width: 100%;
190
- height: auto;
191
- }
192
-
193
- .lares-preview__media {
194
- display: grid;
195
- flex: 1;
196
- min-width: 0;
197
- min-height: 0;
198
- place-items: center;
199
- overflow: auto;
200
- padding: 16px 20px;
126
+ .lares-preview__name {
127
+ position: absolute;
128
+ left: 50%;
129
+ max-width: calc(100% - 152px);
130
+ margin: 0;
131
+ overflow: hidden;
132
+ font-size: 18px;
133
+ font-weight: 600;
134
+ line-height: 24px;
135
+ text-align: center;
136
+ text-overflow: ellipsis;
137
+ white-space: nowrap;
138
+ transform: translateX(-50%);
139
+ pointer-events: none;
201
140
  }
202
141
 
203
- .lares-preview__media img,
204
- .lares-preview__media video {
205
- max-width: 100%;
206
- max-height: 100%;
207
- min-width: 0;
208
- min-height: 0;
142
+ .lares-preview__download {
143
+ display: inline-flex;
144
+ min-width: 40px;
145
+ height: 32px;
146
+ flex-shrink: 0;
147
+ align-items: center;
148
+ justify-content: center;
149
+ border: 1px solid var(--q-separator);
209
150
  border-radius: 10px;
210
- object-fit: contain;
211
- }
212
-
213
- .lares-preview__pdf {
214
- flex: 1;
215
- min-height: 0;
216
- width: 100%;
217
- border: 0;
151
+ padding: 0 12px;
152
+ background: var(--q-background-3);
153
+ color: var(--q-ink-1);
154
+ font: inherit;
155
+ font-size: 14px;
156
+ font-weight: 500;
157
+ line-height: 18px;
158
+ text-decoration: none;
218
159
  }
219
160
 
220
- .lares-preview__media audio {
221
- width: min(100%, 520px);
161
+ .lares-preview__download:active {
162
+ background: var(--q-btn-bg-pressed);
222
163
  }
223
164
  </style>
@@ -0,0 +1,185 @@
1
+ <template>
2
+ <div class="lares-preview-body">
3
+ <div v-if="status === 'loading'" class="lares-preview-body__hint">{{ t("loading") }}</div>
4
+ <div v-else-if="status === 'error'" class="lares-preview-body__hint">
5
+ <p>{{ failText }}</p>
6
+ <button type="button" class="lares-preview-body__retry" @click="$emit('retry')">{{ t("retry") }}</button>
7
+ </div>
8
+ <div v-else-if="data?.kind === 'image'" class="lares-preview-body__media">
9
+ <img :src="mediaSrc" :alt="name" />
10
+ </div>
11
+ <div v-else-if="data?.kind === 'video'" class="lares-preview-body__media">
12
+ <video :src="mediaSrc" controls playsinline />
13
+ </div>
14
+ <div v-else-if="data?.kind === 'audio'" class="lares-preview-body__media">
15
+ <audio :src="mediaSrc" controls />
16
+ </div>
17
+ <iframe
18
+ v-else-if="data?.kind === 'pdf'"
19
+ class="lares-preview-body__pdf"
20
+ :src="mediaSrc"
21
+ :title="name"
22
+ />
23
+ <div
24
+ v-else-if="data?.kind === 'markdown'"
25
+ class="lares-preview-body__markdown"
26
+ v-html="markdownHtml"
27
+ @click="onMarkdownClick"
28
+ />
29
+ <pre v-else-if="data?.kind === 'text'" class="lares-preview-body__text">{{ data.text }}</pre>
30
+ <div v-else-if="data?.kind === 'model3d'" class="lares-preview-body__hint">
31
+ <p>{{ t("model3dHint") }}</p>
32
+ </div>
33
+ <div v-else class="lares-preview-body__hint">
34
+ <p>{{ t("unsupportedTitle") }}</p>
35
+ <p>{{ t("unsupported") }}</p>
36
+ </div>
37
+ <p v-if="data?.truncated" class="lares-preview-body__hint">{{ t("truncated") }}</p>
38
+ </div>
39
+ </template>
40
+
41
+ <script>
42
+ import { fileName } from "@olares/lares-core/files/filename";
43
+ import { workspaceLinkClickPath } from "@olares/lares-core/files/preview-workspace";
44
+ import { rewriteWorkspaceTargets } from "@olares/lares-core/files/markdown";
45
+ import { messageFromCode } from "@olares/lares-core/i18n/t";
46
+ import { renderMarkdown } from "../chat/markdown.js";
47
+
48
+ export default {
49
+ name: "LaresPreviewBody",
50
+ props: {
51
+ path: { type: String, required: true },
52
+ sessionId: { type: String, default: "" },
53
+ status: { type: String, default: "loading" },
54
+ data: { type: Object, default: null },
55
+ error: { type: String, default: "" },
56
+ mediaSrc: { type: String, default: "" },
57
+ hrefFor: { type: Function, default: null },
58
+ t: { type: Function, required: true },
59
+ },
60
+ emits: ["retry", "open"],
61
+ computed: {
62
+ name() {
63
+ return this.data?.name || fileName(this.path);
64
+ },
65
+ failText() {
66
+ return messageFromCode(this.t, this.error, "failed");
67
+ },
68
+ markdownHtml() {
69
+ const text = this.data?.text ?? "";
70
+ const rewritten = this.hrefFor
71
+ ? rewriteWorkspaceTargets(text, this.data?.path ?? this.path, this.hrefFor)
72
+ : text;
73
+ return renderMarkdown(rewritten);
74
+ },
75
+ },
76
+ methods: {
77
+ onMarkdownClick(event) {
78
+ if (!this.sessionId) return;
79
+ const path = workspaceLinkClickPath(this.sessionId, event);
80
+ if (path === null) return;
81
+ event.preventDefault();
82
+ this.$emit("open", path);
83
+ },
84
+ },
85
+ };
86
+ </script>
87
+
88
+ <style scoped>
89
+ .lares-preview-body {
90
+ display: flex;
91
+ min-width: 0;
92
+ min-height: 0;
93
+ flex: 1;
94
+ flex-direction: column;
95
+ }
96
+
97
+ .lares-preview-body__hint,
98
+ .lares-preview-body__text,
99
+ .lares-preview-body__markdown {
100
+ margin: 0;
101
+ padding: 12px 20px;
102
+ color: var(--q-ink-2);
103
+ font-size: 16px;
104
+ }
105
+
106
+ .lares-preview-body__retry {
107
+ border: 0;
108
+ background: none;
109
+ color: var(--q-blue-default);
110
+ cursor: pointer;
111
+ font: inherit;
112
+ }
113
+
114
+ .lares-preview-body__text,
115
+ .lares-preview-body__markdown {
116
+ min-height: 0;
117
+ flex: 1;
118
+ overflow: auto;
119
+ color: var(--q-ink-1);
120
+ }
121
+
122
+ .lares-preview-body__text {
123
+ white-space: pre-wrap;
124
+ word-break: break-word;
125
+ }
126
+
127
+ .lares-preview-body__markdown :deep(p),
128
+ .lares-preview-body__markdown :deep(pre) {
129
+ margin: 0 0 10px;
130
+ }
131
+
132
+ .lares-preview-body__markdown :deep(ul),
133
+ .lares-preview-body__markdown :deep(ol) {
134
+ margin: 4px 0 12px;
135
+ padding: 0 0 0 1.35em;
136
+ }
137
+
138
+ .lares-preview-body__markdown :deep(ul) {
139
+ list-style: disc outside;
140
+ }
141
+
142
+ .lares-preview-body__markdown :deep(ol) {
143
+ list-style: decimal outside;
144
+ }
145
+
146
+ .lares-preview-body__markdown :deep(li + li) {
147
+ margin-top: 6px;
148
+ }
149
+
150
+ .lares-preview-body__markdown :deep(img) {
151
+ max-width: 100%;
152
+ height: auto;
153
+ }
154
+
155
+ .lares-preview-body__media {
156
+ display: grid;
157
+ min-width: 0;
158
+ min-height: 0;
159
+ flex: 1;
160
+ place-items: center;
161
+ overflow: auto;
162
+ padding: 16px 20px;
163
+ }
164
+
165
+ .lares-preview-body__media img,
166
+ .lares-preview-body__media video {
167
+ min-width: 0;
168
+ min-height: 0;
169
+ max-width: 100%;
170
+ max-height: 100%;
171
+ border-radius: 10px;
172
+ object-fit: contain;
173
+ }
174
+
175
+ .lares-preview-body__media audio {
176
+ width: min(100%, 520px);
177
+ }
178
+
179
+ .lares-preview-body__pdf {
180
+ min-height: 0;
181
+ flex: 1;
182
+ width: 100%;
183
+ border: 0;
184
+ }
185
+ </style>