"use client"; import { useCallback, useEffect, useId, useRef, useState } from "react"; import dynamic from "next/dynamic"; import Link from "next/link"; import { useRouter } from "next/navigation"; import type { EditorView } from "@uiw/react-codemirror"; import { api, ApiError } from "@/lib/client"; import { categoryLabel, slugify, todayIso, validatePost } from "@/lib/validate"; import type { BlogPost, GalleryImage, ImageFile, PostInput } from "@/lib/types"; import TagInput from "./TagInput"; import PreviewFrame from "./PreviewFrame"; import ImagePanel from "./ImagePanel"; import { insertText } from "./MarkdownEditor"; // CodeMirror touches the DOM on load; render it client-side only. const MarkdownEditor = dynamic(() => import("./MarkdownEditor"), { ssr: false, loading: () =>
, }); type Props = { /** Absent for a new post. */ post?: BlogPost; revision: string; files?: ImageFile[]; categories: string[]; tags: string[]; }; type Form = PostInput & { images: GalleryImage[] }; function toForm(post?: BlogPost): Form { return { slug: post?.slug ?? "", title: post?.title ?? "", description: post?.description ?? "", date: post?.date ?? todayIso(), category: post?.category ?? "", tags: post?.tags ?? [], images: post?.images ?? [], details: post?.details ?? "", }; } export default function PostEditor({ post, revision: initialRevision, files: initialFiles, categories, tags }: Props) { const router = useRouter(); const categoryListId = useId(); const viewRef = useRef