"use client"; import { useState, useMemo, useEffect } from "react"; import { useStore, selectActiveTask, usePersistHydrated } from "@/lib/store"; import { detectFormat } from "@/lib/parsers/auto"; import { useAutosave, relativeTime } from "@/lib/use-autosave"; import { downloadMarkdown } from "@/lib/export/download"; import { useUploadFile } from "@/lib/use-upload"; import { useT, type DictKey } from "@/lib/i18n"; import { DraftsMenu } from "./drafts-menu"; import { SamplesGallery } from "./samples-gallery"; import { FormatsGallery } from "./formats-gallery"; import { AiPromptBar } from "./ai-prompt-bar"; const TAB_KEY: Record<"text" | "formats" | "samples", DictKey> = { text: "editor.tab.text", formats: "editor.tab.formats", samples: "editor.tab.samples", }; export function EditorPane() { const [tab, setTab] = useState<"text" | "formats" | "samples">("text"); const [dragActive, setDragActive] = useState(false); const hydrated = usePersistHydrated(); const content = useStore((s) => selectActiveTask(s)?.content ?? ""); const setContent = useStore((s) => s.setContent); const format = useStore((s) => selectActiveTask(s)?.format ?? "text"); const setFormat = useStore((s) => s.setFormat); const setFilename = useStore((s) => s.setFilename); const { status: saveStatus, savedAt } = useAutosave(); const { ingest } = useUploadFile(); const t = useT(); const detected = useMemo(() => detectFormat(content), [content]); const hasContent = content.length > 0; return (
{(["text", "formats", "samples"] as const).map((id) => ( ))}
{hasContent && ( )}
{hasContent && (
| {format || detected} · {t("editor.chars", { n: content.length.toLocaleString() })}
)}
{tab === "text" && (
{ if (e.dataTransfer?.types?.includes("Files")) { e.preventDefault(); setDragActive(true); } }} onDragOver={(e) => { if (e.dataTransfer?.types?.includes("Files")) { e.preventDefault(); } }} onDragLeave={(e) => { // Only deactivate when leaving the outer container, not when // crossing into a child element inside it. if (e.currentTarget === e.target || !e.currentTarget.contains(e.relatedTarget as Node)) { setDragActive(false); } }} onDrop={(e) => { e.preventDefault(); setDragActive(false); ingest(e.dataTransfer?.files ?? null); }} >
{!hydrated && (
{t("editor.restoring")}
)}