"use client"; import { type ChangeEvent, useEffect, useRef, useState } from "react"; import { EditorContent, useEditor } from "@tiptap/react"; import StarterKit from "@tiptap/starter-kit"; import Underline from "@tiptap/extension-underline"; import Link from "@tiptap/extension-link"; import Placeholder from "@tiptap/extension-placeholder"; import Image from "@tiptap/extension-image"; type TiptapHtmlEditorProps = { value: string; onChange: (html: string) => void; placeholder?: string; onUploadImage?: (file: File) => Promise; }; type ToolbarButtonProps = { active?: boolean; disabled?: boolean; label: string; onClick: () => void; }; function ToolbarButton({ active = false, disabled = false, label, onClick }: ToolbarButtonProps) { return ( ); } export default function TiptapHtmlEditor({ value, onChange, placeholder = "Skriv artikkelen her...", onUploadImage, }: TiptapHtmlEditorProps) { const fileInputRef = useRef(null); const [isUploading, setIsUploading] = useState(false); const editor = useEditor({ extensions: [ StarterKit.configure({ heading: { levels: [2, 3], }, }), Underline, Link.configure({ autolink: true, openOnClick: false, protocols: ["http", "https", "mailto"], }), Image, Placeholder.configure({ placeholder, }), ], content: value || "

", immediatelyRender: false, editorProps: { attributes: { class: "min-h-[28rem] rounded-[1.5rem] border border-[#112015]/10 bg-white px-5 py-5 text-base leading-8 text-[#112015] outline-none focus:border-[#8BC34A]", }, }, onUpdate: ({ editor: currentEditor }) => { onChange(currentEditor.getHTML()); }, }); useEffect(() => { if (!editor) return; const currentHtml = editor.getHTML(); if (value !== currentHtml) { editor.commands.setContent(value || "

", { emitUpdate: false }); } }, [editor, value]); if (!editor) { return (
Laster editor...
); } const setLink = () => { const previousUrl = editor.getAttributes("link").href as string | undefined; const url = window.prompt("Lenke-URL", previousUrl || "https://"); if (url === null) return; if (url.trim() === "") { editor.chain().focus().extendMarkRange("link").unsetLink().run(); return; } editor.chain().focus().extendMarkRange("link").setLink({ href: url.trim() }).run(); }; const insertImage = () => { const url = window.prompt("Bilde-URL", "https://"); if (!url || !url.trim()) return; editor.chain().focus().setImage({ src: url.trim() }).run(); }; const triggerImageUpload = () => { fileInputRef.current?.click(); }; const handleImageUpload = async (event: ChangeEvent) => { const file = event.target.files?.[0]; event.target.value = ""; if (!file || !onUploadImage) return; setIsUploading(true); try { const url = await onUploadImage(file); editor.chain().focus().setImage({ src: url, alt: file.name }).run(); } catch (error) { window.alert(error instanceof Error ? error.message : "Kunne ikke laste opp bildet."); } finally { setIsUploading(false); } }; return (
editor.chain().focus().setParagraph().run()} /> editor.chain().focus().toggleHeading({ level: 2 }).run()} /> editor.chain().focus().toggleHeading({ level: 3 }).run()} /> editor.chain().focus().toggleBold().run()} /> editor.chain().focus().toggleItalic().run()} /> editor.chain().focus().toggleUnderline().run()} /> editor.chain().focus().toggleBulletList().run()} /> editor.chain().focus().toggleOrderedList().run()} /> editor.chain().focus().toggleBlockquote().run()} /> editor.chain().focus().undo().run()} /> editor.chain().focus().redo().run()} />
); }