import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react' import { EditorContent, useEditor, useEditorState } from '@tiptap/react' import StarterKit from '@tiptap/starter-kit' import Placeholder from '@tiptap/extension-placeholder' import { docToMarkdown, markdownToDoc, unplacedMedia } from '../journal/document.js' import { JournalMediaContext, KanshoMedia } from '../journal/KanshoMedia.jsx' function ToolbarButton({ active, children, disabled, onClick }) { return ( ) } const JournalDocumentEditor = forwardRef(function JournalDocumentEditor( { body, contentKey, onChange, media, previews, onUpload, onPlaced, onRemoveMedia, disabled }, ref ) { const imageInput = useRef(null) const videoInput = useRef(null) const editorRef = useRef(null) const editor = useEditor({ immediatelyRender: false, shouldRerenderOnTransaction: true, editable: !disabled, extensions: [ StarterKit.configure({ code: false, codeBlock: false, blockquote: false, link: false, horizontalRule: false, heading: { levels: [2, 3] } }), Placeholder.configure({ placeholder: 'Schreiben …' }), KanshoMedia ], content: '', onUpdate: ({ editor: instance }) => { onChange(docToMarkdown(instance.getJSON())) } }) editorRef.current = editor useImperativeHandle(ref, () => ({ getMarkdown: () => { const instance = editorRef.current if (!instance) return body || '' return docToMarkdown(instance.getJSON()) } }), [body]) useEffect(() => { if (!editor) return editor.setEditable(!disabled) }, [editor, disabled]) useEffect(() => { if (!editor) return editor.commands.setContent(markdownToDoc(body || ''), { emitUpdate: false }) }, [editor, contentKey]) const marks = useEditorState({ editor, selector: ({ editor: instance }) => instance ? { paragraph: instance.isActive('paragraph'), heading: instance.isActive('heading', { level: 2 }), subheading: instance.isActive('heading', { level: 3 }), bold: instance.isActive('bold'), italic: instance.isActive('italic'), underline: instance.isActive('underline'), bullet: instance.isActive('bulletList'), ordered: instance.isActive('orderedList') } : {} }) const insertFile = async (event) => { const file = event.target.files?.[0] event.target.value = '' if (!file || !editor) return const asset = await onUpload(file) if (!asset?.id) return editor.chain().focus().insertKanshoMedia({ id: asset.id, caption: '', kind: asset.kind || (file.type.startsWith('video/') ? 'video' : 'image') }).run() await onPlaced?.() } const insertExisting = async (item) => { if (!editor) return editor.chain().focus().insertKanshoMedia({ id: item.id, caption: '', kind: item.kind || 'image' }).run() await onPlaced?.() } const unused = unplacedMedia(editor ? docToMarkdown(editor.getJSON()) : body, media) return (
editor.chain().focus().setParagraph().run()} > Absatz editor.chain().focus().toggleHeading({ level: 2 }).run()} > Überschrift editor.chain().focus().toggleHeading({ level: 3 }).run()} > Zwischenüberschrift editor.chain().focus().toggleBold().run()} > Fett editor.chain().focus().toggleItalic().run()} > Kursiv editor.chain().focus().toggleUnderline().run()} > Unterstrichen editor.chain().focus().toggleBulletList().run()} > Liste editor.chain().focus().toggleOrderedList().run()} > Nummerierung imageInput.current?.click()}> Bild videoInput.current?.click()}> Video
{unused.length > 0 && (

Hochgeladen, aber nicht im Text. Dieselbe Datei mehrfach zu wählen erzeugt mehrere Uploads — im Text duplizieren, statt erneut hochzuladen.

    {unused.map((item) => (
  • {item.filename || item.kind} · {String(item.id).slice(0, 8)}
  • ))}
)}
) }) export default JournalDocumentEditor