import { useEditor, EditorContent } from '@tiptap/react'; import StarterKit from '@tiptap/starter-kit'; import Link from '@tiptap/extension-link'; import Image from '@tiptap/extension-image'; import Youtube from '@tiptap/extension-youtube'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { useState, useCallback } from 'react'; import { Bold, Italic, Strikethrough, Code, List, ListOrdered, Quote, Link as LinkIcon, Image as ImageIcon, Youtube as YoutubeIcon, Undo, Redo, Heading1, Heading2, Heading3, } from 'lucide-react'; import { Popover, PopoverContent, PopoverTrigger, } from '@/components/ui/popover'; interface RichTextEditorProps { content: string; onChange: (content: string) => void; placeholder?: string; className?: string; } export function RichTextEditor({ content, onChange, placeholder, className }: RichTextEditorProps) { const [linkUrl, setLinkUrl] = useState(''); const [imageUrl, setImageUrl] = useState(''); const [youtubeUrl, setYoutubeUrl] = useState(''); const [showLinkPopover, setShowLinkPopover] = useState(false); const [showImagePopover, setShowImagePopover] = useState(false); const [showYoutubePopover, setShowYoutubePopover] = useState(false); const editor = useEditor({ extensions: [ StarterKit.configure({ heading: { levels: [1, 2, 3], }, }), Link.configure({ openOnClick: true, HTMLAttributes: { class: 'text-primary underline cursor-pointer', }, }), Image.configure({ HTMLAttributes: { class: 'max-w-full h-auto rounded-lg my-2', }, }), Youtube.configure({ HTMLAttributes: { class: 'w-full aspect-video rounded-lg my-2', }, }), ], content, editorProps: { attributes: { class: 'prose prose-sm max-w-none focus:outline-none min-h-[150px] p-3', }, }, onUpdate: ({ editor }) => { onChange(editor.getHTML()); }, }); const addLink = useCallback(() => { if (linkUrl && editor) { editor.chain().focus().extendMarkRange('link').setLink({ href: linkUrl }).run(); setLinkUrl(''); setShowLinkPopover(false); } }, [editor, linkUrl]); const addImage = useCallback(() => { if (imageUrl && editor) { editor.chain().focus().setImage({ src: imageUrl }).run(); setImageUrl(''); setShowImagePopover(false); } }, [editor, imageUrl]); const addYoutubeVideo = useCallback(() => { if (youtubeUrl && editor) { editor.chain().focus().setYoutubeVideo({ src: youtubeUrl }).run(); setYoutubeUrl(''); setShowYoutubePopover(false); } }, [editor, youtubeUrl]); const handlePaste = useCallback((e: React.ClipboardEvent) => { const items = e.clipboardData?.items; if (!items || !editor) return; for (let i = 0; i < items.length; i++) { if (items[i].type.indexOf('image') !== -1) { e.preventDefault(); const blob = items[i].getAsFile(); if (blob) { const reader = new FileReader(); reader.onload = (event) => { const base64 = event.target?.result as string; editor.chain().focus().setImage({ src: base64 }).run(); }; reader.readAsDataURL(blob); } return; } } }, [editor]); if (!editor) return null; return (
Ou cole uma imagem diretamente (Ctrl+V)