"use client"; import Image from "@tiptap/extension-image"; import { Placeholder } from "@tiptap/extension-placeholder"; import { TableKit } from "@tiptap/extension-table"; import type { Editor } from "@tiptap/react"; import { EditorContent, useEditor, useEditorState } from "@tiptap/react"; import StarterKit from "@tiptap/starter-kit"; import { useEffect, useId, useRef, useState } from "react"; import { MarkdownInputRules } from "@/components/admin/markdown-input-rules"; import { ErrorText, Label, cx } from "@/components/ui"; import { renderMarkdown } from "@/lib/markdown"; import { uploadImageFile } from "@/lib/upload-client"; /** * WordPress-style WYSIWYG editor (Tiptap/ProseMirror). * * - Emits HTML into a hidden field so the surrounding server-action form * submits it like any other input (sanitized server-side on save). * - Images are uploaded via /api/admin/uploads — from the toolbar button, * by dropping files onto the editor, or by pasting from the clipboard — * and inserted inline as /uploads/... URLs. * - Pasting plain text that looks like Markdown converts it through the * same remark pipeline used everywhere else; pasting rich HTML uses * ProseMirror's native handling. */ // Cheap markdown sniff: headings, lists, quotes, fences, emphasis, // links, or inline code. Plain prose without these pastes untouched. const MARKDOWN_PATTERN = /(^|\n)\s{0,3}(#{1,6}\s|[-*+]\s|\d+\.\s|>\s?|```)|\*\*[^*\n]+\*\*|__[^_\n]+__|\[[^\]\n]+\]\([^)\n]+\)|`[^`\n]+`/; function looksLikeMarkdown(text: string): boolean { return MARKDOWN_PATTERN.test(text); } function ToolButton({ label, active = false, disabled = false, onClick, children, className, }: { label: string; active?: boolean; disabled?: boolean; onClick: () => void; children: React.ReactNode; className?: string; }) { return ( ); } function ToolDivider() { return