UNPKG

@asgerami/zemenay-blog

Version:

Plug-and-play blog system for Next.js - Get a fully functional blog running in minutes with zero configuration

67 lines (66 loc) 7 kB
"use strict"; "use client"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.RichTextEditor = RichTextEditor; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("@tiptap/react"); const starter_kit_1 = __importDefault(require("@tiptap/starter-kit")); const extension_placeholder_1 = __importDefault(require("@tiptap/extension-placeholder")); const extension_image_1 = __importDefault(require("@tiptap/extension-image")); const react_2 = require("react"); const ImageUpload_1 = require("./ImageUpload"); function RichTextEditor({ content, onChange, placeholder = "Start writing your blog post...", className = "", }) { const [showImageUpload, setShowImageUpload] = (0, react_2.useState)(false); const [uploadedImages, setUploadedImages] = (0, react_2.useState)([]); const handleImageUploaded = (image, publicUrl) => { setUploadedImages((prev) => [...prev, { image, publicUrl }]); }; const handleImageInsert = (publicUrl, altText) => { if (editor) { editor.chain().focus().setImage({ src: publicUrl, alt: altText }).run(); setShowImageUpload(false); } }; const handleImageError = (error) => { alert(`Image upload error: ${error}`); }; const editor = (0, react_1.useEditor)({ extensions: [ starter_kit_1.default, extension_placeholder_1.default.configure({ placeholder, }), extension_image_1.default.configure({ inline: true, allowBase64: false, HTMLAttributes: { class: "editor-image", }, }), ], content, onUpdate: ({ editor }) => { onChange(editor.getHTML()); }, editorProps: { attributes: { class: "prose prose-sm sm:prose lg:prose-lg xl:prose-2xl mx-auto focus:outline-none min-h-[200px] p-4", }, }, }); // Update editor content when prop changes (0, react_2.useEffect)(() => { if (editor && content !== editor.getHTML()) { editor.commands.setContent(content); } }, [content, editor]); if (!editor) { return (0, jsx_runtime_1.jsx)("div", { className: "animate-pulse bg-gray-200 h-48 rounded" }); } return ((0, jsx_runtime_1.jsxs)("div", { className: `rich-text-editor ${className}`, children: [(0, jsx_runtime_1.jsxs)("div", { className: "editor-toolbar", children: [(0, jsx_runtime_1.jsxs)("div", { className: "toolbar-group", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => editor.chain().focus().toggleBold().run(), className: editor.isActive("bold") ? "active" : "", title: "Bold", children: (0, jsx_runtime_1.jsx)("strong", { children: "B" }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => editor.chain().focus().toggleItalic().run(), className: editor.isActive("italic") ? "active" : "", title: "Italic", children: (0, jsx_runtime_1.jsx)("em", { children: "I" }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => editor.chain().focus().toggleStrike().run(), className: editor.isActive("strike") ? "active" : "", title: "Strikethrough", children: (0, jsx_runtime_1.jsx)("s", { children: "S" }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "toolbar-group", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => editor.chain().focus().toggleHeading({ level: 1 }).run(), className: editor.isActive("heading", { level: 1 }) ? "active" : "", title: "Heading 1", children: "H1" }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => editor.chain().focus().toggleHeading({ level: 2 }).run(), className: editor.isActive("heading", { level: 2 }) ? "active" : "", title: "Heading 2", children: "H2" }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => editor.chain().focus().toggleHeading({ level: 3 }).run(), className: editor.isActive("heading", { level: 3 }) ? "active" : "", title: "Heading 3", children: "H3" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "toolbar-group", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => editor.chain().focus().toggleBulletList().run(), className: editor.isActive("bulletList") ? "active" : "", title: "Bullet List", children: "\u2022 List" }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => editor.chain().focus().toggleOrderedList().run(), className: editor.isActive("orderedList") ? "active" : "", title: "Numbered List", children: "1. List" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "toolbar-group", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => editor.chain().focus().toggleBlockquote().run(), className: editor.isActive("blockquote") ? "active" : "", title: "Quote", children: "\" Quote" }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => editor.chain().focus().toggleCodeBlock().run(), className: editor.isActive("codeBlock") ? "active" : "", title: "Code Block", children: "</>" })] }), (0, jsx_runtime_1.jsx)("div", { className: "toolbar-group", children: (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setShowImageUpload(!showImageUpload), className: showImageUpload ? "active" : "", title: "Insert Image", children: "\uD83D\uDDBC\uFE0F" }) }), (0, jsx_runtime_1.jsxs)("div", { className: "toolbar-group", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => editor.chain().focus().undo().run(), disabled: !editor.can().undo(), title: "Undo", children: "\u21B6" }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => editor.chain().focus().redo().run(), disabled: !editor.can().redo(), title: "Redo", children: "\u21B7" })] })] }), showImageUpload && ((0, jsx_runtime_1.jsxs)("div", { className: "image-upload-panel", children: [(0, jsx_runtime_1.jsx)("h4", { children: "Upload Image" }), (0, jsx_runtime_1.jsx)(ImageUpload_1.ImageUpload, { onImageUploaded: handleImageUploaded, onError: handleImageError }), uploadedImages.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "uploaded-images", children: [(0, jsx_runtime_1.jsx)("h5", { children: "Recently Uploaded" }), uploadedImages.map(({ image, publicUrl }, index) => ((0, jsx_runtime_1.jsx)(ImageUpload_1.ImagePreview, { image: image, publicUrl: publicUrl, onInsert: () => handleImageInsert(publicUrl, image.alt_text || image.original_name), onRemove: () => { setUploadedImages((prev) => prev.filter((_, i) => i !== index)); } }, `${image.id}-${index}`)))] }))] })), (0, jsx_runtime_1.jsx)("div", { className: "editor-content", children: (0, jsx_runtime_1.jsx)(react_1.EditorContent, { editor: editor }) })] })); }