/** * `TemplateEditor` — a fullscreen overlay for creating or editing agent * templates (L7). Rendered on top of the rest of the UI (`fixed inset-0`). * * Provides: * - Name field and default-profile selector * - Two tabs: "Edit" (textarea) and "Preview" (react-markdown) * - Save (create/update) and Cancel/Close buttons * * Pure presentation: all mutations are delegated to the callbacks supplied by * the parent (`TemplatesPanel`). Styled with `@/shared`; no inline styles. */ import { useState } from "react"; import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import type { AgentProfile, Template } from "@/domain"; import { Button, Input, SmallDropdown, cn } from "@/shared"; export interface TemplateEditorProps { /** * When set, the editor is in edit-mode for the given template; otherwise it * is in create-mode (all fields start empty). */ template?: Template | null; /** Available profiles for the default-profile selector. */ profiles: AgentProfile[]; /** Called when the user submits the form. */ onSave: (name: string, content: string, defaultProfileId: string) => Promise; /** Called when the user cancels / closes the overlay. */ onClose: () => void; /** Whether a save operation is in flight. */ busy?: boolean; } type EditorTab = "edit" | "preview"; export function TemplateEditor({ template, profiles, onSave, onClose, busy = false, }: TemplateEditorProps) { const [name, setName] = useState(template?.name ?? ""); const [content, setContent] = useState(template?.contentMd ?? ""); const [defaultProfileId, setDefaultProfileId] = useState( template?.defaultProfileId ?? "", ); const [tab, setTab] = useState("edit"); const canSave = name.trim().length > 0 && !busy; async function handleSubmit(e: React.FormEvent) { e.preventDefault(); if (!canSave) return; await onSave(name.trim(), content, defaultProfileId); } return (
{/* ── Header bar ── */}

{template ? `Edit template — ${template.name}` : "New template"}

{/* ── Form body ── */}
void handleSubmit(e)} className="flex flex-1 flex-col gap-0 overflow-hidden" > {/* ── Meta fields ── */}
setName(e.target.value)} disabled={busy} className="min-w-48" />
{profiles.length > 0 ? ( ({ value: p.id, label: p.name })), ]} /> ) : ( setDefaultProfileId(e.target.value)} disabled={busy} className="min-w-48" /> )}
{/* ── Tab strip ── */}
{(["edit", "preview"] as EditorTab[]).map((t) => ( ))}
{/* ── Edit / Preview pane ── */}
{tab === "edit" ? (