From 2e2c784f4c6ee83d96164b0d0192da4fd5ca26a2 Mon Sep 17 00:00:00 2001 From: ByungCheol Date: Sun, 7 Jun 2026 20:16:14 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EC=97=90=EB=94=94=ED=84=B0=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EB=B2=84=ED=8A=BC=20=3D=20=EB=B0=94?= =?UTF-8?q?=EB=A1=9C=20=EC=97=85=EB=A1=9C=EB=93=9C(=ED=8C=9D=EC=97=85=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0)=20=E2=80=94=20=EB=8C=93=EA=B8=80=EC=B0=BD?= =?UTF-8?q?=20OK=20=EC=9E=98=EB=A6=BC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Toast UI 기본 이미지 팝업(File/URL/Description/OK)이 작은 댓글창/하단 위치에서 잘려 OK 를 못 누르던 문제 → 커스텀 툴바 이미지 버튼으로 교체(클릭 시 바로 파일선택→업로드→삽입) - 서버 업로드(URL) 그대로 Co-Authored-By: Claude Opus 4.8 --- src/components/editor/MarkdownEditor.vue | 54 ++++++++++++++++++------ 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/src/components/editor/MarkdownEditor.vue b/src/components/editor/MarkdownEditor.vue index 1c2981c..902d02e 100644 --- a/src/components/editor/MarkdownEditor.vue +++ b/src/components/editor/MarkdownEditor.vue @@ -17,6 +17,7 @@ const props = defineProps({ const emit = defineEmits(['update:modelValue']) const el = ref(null) +const imgInput = ref(null) let editor = null // 에디터가 마지막으로 emit 한 값. 부모가 되돌려준 echo 를 구분해 입력 중 setMarkdown 으로 끊기지 않게. let lastEmitted = props.modelValue || '' @@ -28,6 +29,34 @@ async function uploadCompressed(fileOrBlob) { return url } +// 커스텀 이미지 버튼 클릭 → 파일 선택 → 업로드 → 에디터에 삽입 +// (Toast UI 기본 이미지 팝업이 작은 댓글창에서 잘려 OK 를 못 누르는 문제 회피) +async function onImagePick(e) { + const file = e.target.files?.[0] + e.target.value = '' + if (!file || !editor) return + try { + const url = await uploadCompressed(file) + const alt = file.name.replace(/\.[^.]+$/, '') + editor.exec('addImage', { imageUrl: url, altText: alt }) + } catch { + /* 업로드 실패 시 미삽입 */ + } +} + +function makeImageButton() { + const btn = document.createElement('button') + btn.type = 'button' + btn.className = 'toastui-editor-toolbar-icons image' + btn.style.margin = '0' + btn.setAttribute('aria-label', '이미지') + btn.addEventListener('click', (ev) => { + ev.preventDefault() + imgInput.value?.click() + }) + return btn +} + onMounted(() => { editor = new Editor({ el: el.value, @@ -39,24 +68,20 @@ onMounted(() => { placeholder: props.placeholder, usageStatistics: false, autofocus: false, + // 기본 이미지 버튼(팝업)을 커스텀(바로 업로드)으로 교체 + toolbarItems: [ + ['heading', 'bold', 'italic', 'strike'], + ['hr', 'quote'], + ['ul', 'ol', 'task', 'indent', 'outdent'], + ['table', { name: 'image', tooltip: '이미지', el: makeImageButton() }, 'link'], + ['code', 'codeblock'], + ], events: { change: () => { lastEmitted = editor.getMarkdown() emit('update:modelValue', lastEmitted) }, }, - hooks: { - // 이미지 추가 시 base64 대신 서버 업로드 → URL 삽입 - addImageBlobHook: async (blob, callback) => { - try { - const url = await uploadCompressed(blob) - callback(url, '') - } catch { - /* 업로드 실패 시 미삽입 */ - } - return false - }, - }, }) }) @@ -80,5 +105,8 @@ onBeforeUnmount(() => {