"use client"; import type { PlaitElement } from "@plait/core"; import { ExternalLink, FileDown, Link2, StickyNote, Tag, X, } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { getSafeTopicHref, getTopicDetails, getTopicTitle, type TopicDetails, type TopicEntry, } from "@/lib/flow-board/topic-details"; import { getNoteDocument } from "@/lib/flow-board/topic-notes"; import { XmindNotesEditor } from "./xmind-notes-editor"; export type TopicDetailSection = "notes" | "links" | "labels"; export function XmindTopicPanel({ topic, topics, section, onPatch, onJump, onClose, }: { topic: PlaitElement | null; topics: TopicEntry[]; section: TopicDetailSection; onPatch: (patch: Partial) => void; onJump: (id: string) => void; onClose: () => void; }) { const details = getTopicDetails(topic); const [labelDraft, setLabelDraft] = useState(""); const [linkDraft, setLinkDraft] = useState(details.href); const [attachmentError, setAttachmentError] = useState(""); const [isReadingAttachment, setIsReadingAttachment] = useState(false); const attachmentRef = useRef(null); const linkRef = useRef(null); const labelRef = useRef(null); useEffect(() => { setLinkDraft(details.href); }, [topic?.id, details.href]); useEffect(() => { setLabelDraft(""); setAttachmentError(""); }, [topic?.id]); useEffect(() => { if (section === "links") linkRef.current?.focus(); if (section === "labels") labelRef.current?.focus(); }, [section]); const safeHref = getSafeTopicHref(linkDraft); const invalidHref = Boolean(linkDraft.trim()) && !safeHref; const addLabel = () => { const value = labelDraft.trim(); if (value && !details.labels.includes(value)) onPatch({ labels: [...details.labels, value] }); setLabelDraft(""); }; const addAttachment = async (file: File) => { setAttachmentError(""); if (file.size > 8 * 1024 * 1024) { setAttachmentError("附件不能超过 8 MB。"); return; } setIsReadingAttachment(true); try { const url = await new Promise((resolve, reject) => { const reader = new FileReader(); reader.onerror = () => reject(new Error("读取失败")); reader.onload = () => resolve(String(reader.result)); // Always download attachments as files, independent of their source type. reader.readAsDataURL( new Blob([file], { type: "application/octet-stream" }) ); }); onPatch({ attachment: { name: file.name, url, mimeType: "application/octet-stream", }, }); } catch { setAttachmentError("无法读取附件,请重新选择。"); } finally { setIsReadingAttachment(false); } }; return ( ); }