"use client" import * as React from "react" import { Button } from "@/components/ui/button" import { Textarea } from "@/components/ui/textarea" import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog" import { Upload, X, Image as ImageIcon, Eye, EyeOff } from "lucide-react" import { toast } from "sonner" import { cn } from "@/lib/utils" interface ClauseImage { id: string url: string fileName: string size: number } interface MarkdownImageEditorProps { content: string images: ClauseImage[] onChange: (content: string, images: ClauseImage[]) => void placeholder?: string rows?: number className?: string } export function MarkdownImageEditor({ content, images, onChange, placeholder = "텍스트를 입력하고, 이미지를 삽입하려면 '이미지 추가' 버튼을 클릭하세요.", rows = 6, className }: MarkdownImageEditorProps) { const [imageUploadOpen, setImageUploadOpen] = React.useState(false) const [showPreview, setShowPreview] = React.useState(false) const [uploading, setUploading] = React.useState(false) const textareaRef = React.useRef(null) // 이미지 업로드 핸들러 const handleImageUpload = async (file: File) => { if (!file.type.startsWith('image/')) { toast.error('이미지 파일만 업로드 가능합니다.') return } if (file.size > 5 * 1024 * 1024) { // 5MB 제한 toast.error('파일 크기는 5MB 이하여야 합니다.') return } setUploading(true) try { // 실제 구현에서는 서버로 업로드 const uploadedUrl = await uploadImage(file) const imageId = `image${Date.now()}` // 이미지 배열에 추가 const newImages = [...images, { id: imageId, url: uploadedUrl, fileName: file.name, size: file.size, }] // 커서 위치에 이미지 참조 삽입 const imageRef = `![${imageId}]` const textarea = textareaRef.current if (textarea) { const start = textarea.selectionStart const end = textarea.selectionEnd const newContent = content.substring(0, start) + imageRef + content.substring(end) onChange(newContent, newImages) // 커서 위치를 이미지 참조 뒤로 이동 setTimeout(() => { textarea.focus() textarea.setSelectionRange(start + imageRef.length, start + imageRef.length) }, 0) } else { // 텍스트 끝에 추가 const newContent = content + (content ? '\n\n' : '') + imageRef onChange(newContent, newImages) } toast.success('이미지가 추가되었습니다.') setImageUploadOpen(false) } catch (error) { toast.error('이미지 업로드에 실패했습니다.') console.error('Image upload error:', error) } finally { setUploading(false) } } // 이미지 제거 const removeImage = (imageId: string) => { // 이미지 배열에서 제거 const newImages = images.filter(img => img.id !== imageId) // 텍스트에서 이미지 참조 제거 const imageRef = `![${imageId}]` const newContent = content.replace(new RegExp(`\\!\\[${imageId}\\]`, 'g'), '') onChange(newContent, newImages) toast.success('이미지가 제거되었습니다.') } // 커서 위치에 텍스트 삽입 const insertAtCursor = (text: string) => { const textarea = textareaRef.current if (!textarea) return const start = textarea.selectionStart const end = textarea.selectionEnd const newContent = content.substring(0, start) + text + content.substring(end) onChange(newContent, images) // 커서 위치 조정 setTimeout(() => { textarea.focus() textarea.setSelectionRange(start + text.length, start + text.length) }, 0) } return (
{/* 에디터 툴바 */}
{images.length > 0 && ( {images.length}개 이미지 첨부됨 )}
{/* 에디터 영역 */} {showPreview ? ( /* 미리보기 모드 */
{renderMarkdownPreview(content, images)}
) : ( /* 편집 모드 */