diff --git a/app/web/components/PreviewPanel.tsx b/app/web/components/PreviewPanel.tsx index 83ae353..da89d40 100644 --- a/app/web/components/PreviewPanel.tsx +++ b/app/web/components/PreviewPanel.tsx @@ -3,12 +3,13 @@ import ReactMarkdown from "react-markdown"; import remarkBreaks from "remark-breaks"; import remarkGfm from "remark-gfm"; import rehypeSanitize from "rehype-sanitize"; +import { GENRES } from "../../../lib/genres"; interface PreviewPanelProps { storyName: string | null; fileName: string | null; authFetch: (url: string, opts?: RequestInit) => Promise; - onPublish?: (storyName: string, fileName: string) => void; + onPublish?: (storyName: string, fileName: string, genre: string) => void; publishingFile?: string | null; } @@ -34,6 +35,7 @@ export function PreviewPanel({ storyName, fileName, authFetch, onPublish, publis const [dirty, setDirty] = useState(false); const [retrying, setRetrying] = useState(false); const [indexTimeLeft, setIndexTimeLeft] = useState(null); + const [selectedGenre, setSelectedGenre] = useState(GENRES[0]); const textareaRef = useRef(null); const dirtyRef = useRef(false); @@ -75,6 +77,25 @@ export function PreviewPanel({ storyName, fileName, authFetch, onPublish, publis return () => clearInterval(interval); }, [storyName, fileName, loadFile, activeTab, dirty]); + // Auto-detect genre from structure.md when story changes + useEffect(() => { + if (!storyName) return; + let cancelled = false; + authFetch(`/api/stories/${storyName}/structure.md`) + .then((res) => res.ok ? res.json() : null) + .then((data) => { + if (cancelled || !data?.content) return; + const match = data.content.match(/\*{0,2}genre\*{0,2}[:\s]+(.+)/i); + if (match) { + const detected = match[1].replace(/\*+/g, "").trim(); + const found = GENRES.find((g) => g.toLowerCase() === detected.toLowerCase()); + if (found) setSelectedGenre(found); + } + }) + .catch(() => {}); + return () => { cancelled = true; }; + }, [storyName, authFetch]); + const handleSave = useCallback(async () => { if (!storyName || !fileName) return; setSaving(true); @@ -303,7 +324,7 @@ export function PreviewPanel({ storyName, fileName, authFetch, onPublish, publis )} {isPlot && (