diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-08-06 04:23:40 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-08-06 04:23:40 +0000 |
| commit | de2ac5a2860bc25180971e7a11f852d9d44675b7 (patch) | |
| tree | b931c363f2cb19e177a0a7b17190d5de2a82d709 /components/qna | |
| parent | 6c549b0f264e9be4d60af38f9efc05b189d6849f (diff) | |
(대표님) 정기평가, 법적검토, 정책, 가입관련 처리 및 관련 컴포넌트 추가, 메뉴 변경
Diffstat (limited to 'components/qna')
| -rw-r--r-- | components/qna/tiptap-editor.tsx | 98 |
1 files changed, 69 insertions, 29 deletions
diff --git a/components/qna/tiptap-editor.tsx b/components/qna/tiptap-editor.tsx index 5d0a84e9..b1cebf5a 100644 --- a/components/qna/tiptap-editor.tsx +++ b/components/qna/tiptap-editor.tsx @@ -1,4 +1,5 @@ import { useEditor, EditorContent } from '@tiptap/react' +import { useEffect } from 'react' // useEffect 추가 import StarterKit from '@tiptap/starter-kit' import Underline from '@tiptap/extension-underline' import { Image as TiptapImage } from '@tiptap/extension-image' @@ -26,6 +27,18 @@ interface TiptapEditorProps { height?: string; // 높이 prop 추가 } +// 이미지 크기 가져오기 헬퍼 함수 +function getImageDimensions(url: string): Promise<{ width: number; height: number }> { + return new Promise((resolve, reject) => { + const img = new Image() + img.onload = () => { + resolve({ width: img.width, height: img.height }) + } + img.onerror = reject + img.src = url + }) +} + export default function TiptapEditor({ content, setContent, disabled, height = "300px" }: TiptapEditorProps) { const editor = useEditor({ extensions: [ @@ -135,6 +148,21 @@ export default function TiptapEditor({ content, setContent, disabled, height = " }, }) + // ✅ 핵심 추가: content prop이 변경될 때 에디터 내용 동기화 + useEffect(() => { + if (editor && content !== editor.getHTML()) { + console.log('Updating editor content:', content) // 디버깅용 + editor.commands.setContent(content, false) // false: focus 유지하지 않음 + } + }, [content, editor]) + + // ✅ editable 상태 변경 처리 + useEffect(() => { + if (editor) { + editor.setEditable(!disabled) + } + }, [disabled, editor]) + async function uploadImageToServer(file: File): Promise<string> { const formData = new FormData(); formData.append('file', file); @@ -153,39 +181,51 @@ export default function TiptapEditor({ content, setContent, disabled, height = " return url; } -// Base64 → 서버 업로드 방식으로 교체 -const handleImageUpload = async (file: File) => { - try { - if (file.size > 3 * 1024 * 1024) { - alert('이미지 크기는 3 MB 이하만 지원됩니다.'); - return; - } - if (!file.type.startsWith('image/')) { - alert('이미지 파일만 업로드 가능합니다.'); - return; - } + // Base64 → 서버 업로드 방식으로 교체 + const handleImageUpload = async (file: File) => { + try { + if (file.size > 3 * 1024 * 1024) { + alert('이미지 크기는 3 MB 이하만 지원됩니다.'); + return; + } + if (!file.type.startsWith('image/')) { + alert('이미지 파일만 업로드 가능합니다.'); + return; + } - const url = await uploadImageToServer(file); // ← 업로드 & URL 획득 + const url = await uploadImageToServer(file); // ← 업로드 & URL 획득 - // 이미지 크기(너비)에 따라 style 조정 - const { width, height } = await getImageDimensions(url); - const maxWidth = 600; - const newW = width > maxWidth ? maxWidth : width; - const newH = width > maxWidth ? (height * maxWidth) / width : height; + // 이미지 크기(너비)에 따라 style 조정 + const { width, height } = await getImageDimensions(url); + const maxWidth = 600; + const newW = width > maxWidth ? maxWidth : width; + const newH = width > maxWidth ? (height * maxWidth) / width : height; + + editor + ?.chain() + .focus() + .setImage({ + src: url, + style: `width:${newW}px;height:${newH}px;max-width:100%;`, + }) + .run(); + } catch (e) { + console.error(e); + alert('이미지 업로드에 실패했습니다.'); + } + }; - editor - ?.chain() - .focus() - .setImage({ - src: url, - style: `width:${newW}px;height:${newH}px;max-width:100%;`, - }) - .run(); - } catch (e) { - console.error(e); - alert('이미지 업로드에 실패했습니다.'); + // ✅ 에디터가 준비되지 않았을 때 로딩 표시 + if (!editor) { + return ( + <div + className="border rounded-md bg-background flex items-center justify-center" + style={{ height }} + > + <div className="text-muted-foreground text-sm">에디터를 로딩 중...</div> + </div> + ) } -}; // 높이 계산 (100%인 경우 flex 사용, 아니면 구체적 높이) const containerStyle = height === "100%" |
