import { useCallback, useEffect, useLayoutEffect, useRef, useState, type CSSProperties, type ReactNode } from "react"; import { createPortal } from "react-dom"; import { artifactsApi, type EditSlide, type GenerateBody } from "../api/endpoints"; import { addActions, convert, type DeckFmt, LAYOUTS, MAX_SLIDES, newSlide, problem, removable, removeField, setText } from "./slideDeckEdit"; import type { Artifact, ChatSummary } from "../api/types"; import { Dropdown } from "./Dropdown"; import { useJob } from "../hooks/useJob"; import { CheckIcon, CollapseIcon, DownloadIcon, ExpandIcon, MoreIcon, PdfIcon, PlayIcon, PptxIcon, SlidesIcon, TrashIcon } from "./icons/Icons"; import { LANGUAGES, Pills, SourceFocusFields, sourceSummary, type SourceSelection } from "./SourceFocusFields"; import { ConfirmDeleteModal, errorMessage, formatDate, JobProgress, Modal } from "./ui"; /** Bumped when the thumbnails are drawn again (backend/scripts/render_slide_thumbnails.py), so browsers fetch the new * images instead of the ones they cached. */ const THUMBS_VERSION = 2; /** The two deck themes. Their slides are laid out on the server (backend/app/slides); the thumbnails are rendered from * them (backend/scripts/render_slide_thumbnails.py). */ export const SLIDE_THEMES = [ { id: "dark-space", name: "Night stellar", blurb: "Night sky, planets and a blue glow" }, { id: "light-space", name: "Moon light", blurb: "Moonlit sky, orbits and constellations" }, ] as const; const FORMATS = [ { id: "detailed", label: "Detailed deck", blurb: "Full text and details, perfect for emailing or reading on its own." }, { id: "presenter", label: "Presenter slides", blurb: "Clean slides with key talking points to support you while you speak." }, ] as const; const LENGTHS = [ { id: "short", label: "Short", range: "6 to 8 slides" }, { id: "default", label: "Default", range: "9 to 11 slides" }, { id: "long", label: "Long", range: "12 to 16 slides" }, ] as const; const SLIDE_W = 1920; const SLIDE_H = 1080; export type SlideDeckRequest = Omit; type DeckFormat = "detailed" | "presenter"; type DeckLength = "short" | "default" | "long"; /** The slide deck settings: a visual style on top, then the format, language, length, sources and what it should say. */ export function SlideDeckDialog({ notebookId, notebookTitle, chats, currentChatId, onClose, onCreate }: { notebookId: string; notebookTitle?: string; chats: ChatSummary[]; currentChatId?: string | null; onClose: () => void; onCreate: (body: SlideDeckRequest) => void; }) { const [sel, setSel] = useState(null); const [theme, setTheme] = useState("dark-space"); const [format, setFormat] = useState("detailed"); const [length, setLength] = useState("default"); const [language, setLanguage] = useState("English"); const [prompt, setPrompt] = useState(""); return (
Visual style
{SLIDE_THEMES.map((t) => ( ))}
Format label="Format" value={format} onChange={setFormat} options={FORMATS} /> {FORMATS.find((f) => f.id === format)?.blurb}
Length label="Length" value={length} onChange={setLength} options={LENGTHS.map((l) => ({ value: l.id, label: l.label, hint: l.range }))} />
Language label="Language" value={language} onChange={setLanguage} options={LANGUAGES.map((l) => ({ value: l, label: l }))} />