'use client'; /** * TipTap 에디터 툴바 */ import { useCallback, useRef } from 'react'; import { Editor } from '@tiptap/react'; import { Button } from '@/components/ui/button'; import { Bold, Italic, Underline, Strikethrough, AlignLeft, AlignCenter, AlignRight, List, ListOrdered, Link as LinkIcon, Image as ImageIcon, Undo, Redo, } from 'lucide-react'; import { Popover, PopoverContent, PopoverTrigger, } from '@/components/ui/popover'; import { Input } from '@/components/ui/input'; import { useState } from 'react'; interface MenuBarProps { editor: Editor | null; onImageUpload?: (file: File) => Promise; } export function MenuBar({ editor, onImageUpload }: MenuBarProps) { const [linkUrl, setLinkUrl] = useState(''); const [isLinkPopoverOpen, setIsLinkPopoverOpen] = useState(false); const fileInputRef = useRef(null); // 링크 추가 (hooks는 조건문 전에 선언해야 함) const handleAddLink = useCallback(() => { if (!editor) return; if (linkUrl) { editor .chain() .focus() .extendMarkRange('link') .setLink({ href: linkUrl }) .run(); setLinkUrl(''); setIsLinkPopoverOpen(false); } }, [editor, linkUrl]); // 링크 제거 const handleRemoveLink = useCallback(() => { if (!editor) return; editor.chain().focus().unsetLink().run(); setIsLinkPopoverOpen(false); }, [editor]); // 이미지 업로드 const handleImageUpload = useCallback(async (e: React.ChangeEvent) => { if (!editor) return; const file = e.target.files?.[0]; if (!file) return; if (onImageUpload) { try { const url = await onImageUpload(file); editor.chain().focus().setImage({ src: url }).run(); } catch (error) { console.error('Image upload failed:', error); } } else { // 기본: Base64로 삽입 (개발용) const reader = new FileReader(); reader.onload = () => { const base64 = reader.result as string; editor.chain().focus().setImage({ src: base64 }).run(); }; reader.readAsDataURL(file); } // 파일 input 초기화 if (fileInputRef.current) { fileInputRef.current.value = ''; } }, [editor, onImageUpload]); // editor가 없으면 렌더링 안 함 (hooks 이후에 체크) if (!editor) { return null; } const buttonClass = 'h-8 w-8 p-0'; const activeClass = 'bg-gray-200'; return (
{/* Undo/Redo */}
{/* 텍스트 스타일 */}
{/* 정렬 */}
{/* 목록 */}
{/* 링크 */}
setLinkUrl(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && handleAddLink()} />
{editor.isActive('link') && ( )}
{/* 이미지 */}
); }