diff --git a/frontend/src/components/MdEditor.vue b/frontend/src/components/MdEditor.vue
index 1abd502..2d13382 100644
--- a/frontend/src/components/MdEditor.vue
+++ b/frontend/src/components/MdEditor.vue
@@ -1,22 +1,28 @@
-
+
{{ captionText }}
@@ -111,6 +162,7 @@
size="sm"
@click="preview = !preview"
/>
+ {{ t('stack.uploading') }}
-
+
+
+
+
+
+
@@ -138,6 +209,11 @@
.md-toggle {
margin-left: auto;
}
+.md-uploading {
+ font-size: 0.85em;
+ color: var(--text-muted, #888);
+ align-self: center;
+}
.md-editor :deep(textarea.input) {
height: auto;
min-height: 9rem;
@@ -147,4 +223,31 @@
.md-preview {
min-height: 9rem;
}
+/* миниатюры вставленных картинок */
+.md-pasted {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.4rem;
+ margin-top: 0.5rem;
+}
+.md-thumb {
+ padding: 0;
+ border: 1px solid var(--border, #2a2e42);
+ background: none;
+ cursor: zoom-in;
+ line-height: 0;
+}
+.md-thumb img {
+ width: 72px;
+ height: 54px;
+ object-fit: cover;
+ display: block;
+}
+.md-thumb:hover {
+ border-color: var(--accent, #7aa2f7);
+}
+/* кликабельные картинки в предпросмотре */
+.md-preview :deep(img) {
+ cursor: zoom-in;
+}
\ No newline at end of file
diff --git a/frontend/src/components/MdLightbox.vue b/frontend/src/components/MdLightbox.vue
new file mode 100644
index 0000000..0340c10
--- /dev/null
+++ b/frontend/src/components/MdLightbox.vue
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
![]()
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/components/TaskForm.vue b/frontend/src/components/TaskForm.vue
index 4234543..54b0cf9 100644
--- a/frontend/src/components/TaskForm.vue
+++ b/frontend/src/components/TaskForm.vue
@@ -209,20 +209,19 @@
}
}
-// Вставка изображений из буфера обмена — только для существующей задачи
-async function onPaste(event: ClipboardEvent) {
- if (!props.task) return
- const files = Array.from(event.clipboardData?.files ?? []).filter((f) =>
- f.type.startsWith('image/'),
- )
- if (!files.length) return
- event.preventDefault()
+// Вставка изображений из буфера — только для существующей задачи.
+// MdEditor сам вставляет markdown-ссылку в позицию курсора и показывает
+// миниатюру; здесь только загрузка на сервер.
+async function uploadImages(files: File[]): Promise
{
+ if (!props.task) return []
uploading.value = true
try {
const saved = await api.uploadAttachments(props.task.id, files)
attachments.value.push(...saved)
+ return saved
} catch (e) {
toast.error({ title: t('common.error'), text: String(e) })
+ return []
} finally {
uploading.value = false
}
@@ -258,7 +257,7 @@
]"
/>
-
+
(project.value ? renderMarkdown(project.value.note) : ''))
+// Клик по картинке в заметке → просмотр на весь экран
+const noteImage = ref<{ url: string; name: string } | null>(null)
+
+function onNoteClick(e: MouseEvent) {
+ const target = e.target as HTMLElement
+ if (target.tagName === 'IMG') {
+ const img = target as HTMLImageElement
+ noteImage.value = { url: img.getAttribute('src') ?? '', name: img.alt }
+ }
+}
+
async function load() {
loading.value = true
notFound.value = false
@@ -384,13 +396,24 @@
-
+
{{ t('projectPage.noteEmpty') }}
+
(null)
+
+function onDescClick(e: MouseEvent) {
+ const target = e.target as HTMLElement
+ if (target.tagName === 'IMG') {
+ const img = target as HTMLImageElement
+ descImage.value = { url: img.getAttribute('src') ?? '', name: img.alt }
+ }
+}
+
async function savePriority() {
await patchTask({
priority: draftPriority.value === '' ? null : gradeToPriority(draftPriority.value),
@@ -574,7 +600,7 @@
/>
-
+
-
+
{{ t('task.descriptionEmpty') }}
+