From 45185fb1252f64a1d5cc1d252ceeb71fda413950 Mon Sep 17 00:00:00 2001 From: shiva raj badu Date: Sat, 21 Feb 2026 14:44:34 +0545 Subject: [PATCH] feat: Upload page redesigns --- .../dashboard/components/Header.tsx | 2 +- .../components/MarkdownEditor.tsx | 15 +- .../outline/components/OutlineContent.tsx | 28 +- .../outline/components/OutlineItem.tsx | 38 +- .../outline/components/OutlinePage.tsx | 20 +- .../outline/hooks/useOutlineManagement.ts | 16 +- .../upload/components/AdvanceSettings.tsx | 172 +++++++++ .../components/ConfigurationSelects.tsx | 364 ------------------ .../upload/components/LanguageSelector.tsx | 69 ++++ .../upload/components/NumberOfSlide.tsx | 90 +++++ .../upload/components/PromptInput.tsx | 48 +-- .../upload/components/SupportingDoc.tsx | 47 +-- .../upload/components/UploadPage.tsx | 115 ++++-- .../(presentation-generator)/upload/page.tsx | 6 +- .../app/presentation-templates/index.tsx | 3 + servers/nextjs/components/AnthropicConfig.tsx | 309 +++++++-------- servers/nextjs/components/GoogleConfig.tsx | 282 +++++++------- servers/nextjs/components/ToolTip.tsx | 4 +- 18 files changed, 844 insertions(+), 784 deletions(-) create mode 100644 servers/nextjs/app/(presentation-generator)/upload/components/AdvanceSettings.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/upload/components/ConfigurationSelects.tsx create mode 100644 servers/nextjs/app/(presentation-generator)/upload/components/LanguageSelector.tsx create mode 100644 servers/nextjs/app/(presentation-generator)/upload/components/NumberOfSlide.tsx diff --git a/servers/nextjs/app/(presentation-generator)/(dashboard)/dashboard/components/Header.tsx b/servers/nextjs/app/(presentation-generator)/(dashboard)/dashboard/components/Header.tsx index 4e8895a1..4b763c3d 100644 --- a/servers/nextjs/app/(presentation-generator)/(dashboard)/dashboard/components/Header.tsx +++ b/servers/nextjs/app/(presentation-generator)/(dashboard)/dashboard/components/Header.tsx @@ -11,7 +11,7 @@ import { trackEvent, MixpanelEvent } from "@/utils/mixpanel"; const Header = () => { const pathname = usePathname(); return ( -
+
diff --git a/servers/nextjs/app/(presentation-generator)/components/MarkdownEditor.tsx b/servers/nextjs/app/(presentation-generator)/components/MarkdownEditor.tsx index 0d464476..7a8631ff 100644 --- a/servers/nextjs/app/(presentation-generator)/components/MarkdownEditor.tsx +++ b/servers/nextjs/app/(presentation-generator)/components/MarkdownEditor.tsx @@ -1,3 +1,4 @@ +import { useEffect } from "react" import { useEditor, EditorContent } from "@tiptap/react" import StarterKit from "@tiptap/starter-kit" import { Markdown } from "tiptap-markdown" @@ -19,12 +20,14 @@ export default function MarkdownEditor({ content, onChange }: { content: string; immediatelyRender: false, }); - // Update editor content when the content prop changes (for streaming) - // useEffect(() => { - // if (editor && content !== editor.storage.markdown.getMarkdown()) { - // editor.commands.setContent(content); - // } - // }, [content, editor]); + // Keep editor state in sync when parent changes content (e.g. reorder) + useEffect(() => { + if (!editor) return; + const currentMarkdown = editor.storage.markdown.getMarkdown(); + if (content !== currentMarkdown) { + editor.commands.setContent(content, false); + } + }, [content, editor]); return (
diff --git a/servers/nextjs/app/(presentation-generator)/outline/components/OutlineContent.tsx b/servers/nextjs/app/(presentation-generator)/outline/components/OutlineContent.tsx index 2d3c5d4f..35544dd4 100644 --- a/servers/nextjs/app/(presentation-generator)/outline/components/OutlineContent.tsx +++ b/servers/nextjs/app/(presentation-generator)/outline/components/OutlineContent.tsx @@ -92,40 +92,28 @@ const OutlineContent: React.FC = ({ {/* Outlines content */} {outlines && outlines.length > 0 && ( -
+
- {isStreaming ? ( - - outlines.map((item, index) => ( - = 0 && index < highestActiveIndex} - /> - )) - ) : - ({ id: `slide-${index}` })) || []} + `slide-${index}`)} strategy={verticalListSortingStrategy} > - {outlines?.map((item, index) => ( + {outlines.map((item, index) => ( = 0 && index < highestActiveIndex} /> ))} - } +
diff --git a/servers/nextjs/app/(presentation-generator)/outline/components/OutlinePage.tsx b/servers/nextjs/app/(presentation-generator)/outline/components/OutlinePage.tsx index de5d6f46..808b8fac 100644 --- a/servers/nextjs/app/(presentation-generator)/outline/components/OutlinePage.tsx +++ b/servers/nextjs/app/(presentation-generator)/outline/components/OutlinePage.tsx @@ -15,7 +15,7 @@ import { useOutlineStreaming } from "../hooks/useOutlineStreaming"; import { useOutlineManagement } from "../hooks/useOutlineManagement"; import { usePresentationGeneration } from "../hooks/usePresentationGeneration"; import TemplateSelection from "./TemplateSelection"; -import { TemplateLayoutsWithSettings } from "@/app/presentation-templates"; +import { TemplateLayoutsWithSettings } from "@/app/presentation-templates/utils"; const OutlinePage: React.FC = () => { const { presentation_id, outlines } = useSelector( @@ -48,11 +48,21 @@ const OutlinePage: React.FC = () => { /> -
+
- - Outline & Content - Select Template + + + Outline & Content + + + Select Template +
diff --git a/servers/nextjs/app/(presentation-generator)/outline/hooks/useOutlineManagement.ts b/servers/nextjs/app/(presentation-generator)/outline/hooks/useOutlineManagement.ts index 774b459e..b91c3d6e 100644 --- a/servers/nextjs/app/(presentation-generator)/outline/hooks/useOutlineManagement.ts +++ b/servers/nextjs/app/(presentation-generator)/outline/hooks/useOutlineManagement.ts @@ -11,12 +11,16 @@ export const useOutlineManagement = (outlines: { content: string }[] | null) => if (!active || !over || !outlines) return; - if (active.id !== over.id) { - const oldIndex = outlines.findIndex((item) => item.content === active.id); - const newIndex = outlines.findIndex((item) => item.content === over.id); - const reorderedArray = arrayMove(outlines, oldIndex, newIndex); - dispatch(setOutlines(reorderedArray)); - } + if (active.id === over.id) return; + + const oldIndex = Number(String(active.id).replace("slide-", "")); + const newIndex = Number(String(over.id).replace("slide-", "")); + + if (Number.isNaN(oldIndex) || Number.isNaN(newIndex)) return; + if (oldIndex < 0 || newIndex < 0 || oldIndex >= outlines.length || newIndex >= outlines.length) return; + + const reorderedArray = arrayMove(outlines, oldIndex, newIndex); + dispatch(setOutlines(reorderedArray)); }, [outlines, dispatch]); const handleAddSlide = useCallback(() => { diff --git a/servers/nextjs/app/(presentation-generator)/upload/components/AdvanceSettings.tsx b/servers/nextjs/app/(presentation-generator)/upload/components/AdvanceSettings.tsx new file mode 100644 index 00000000..bd709a5c --- /dev/null +++ b/servers/nextjs/app/(presentation-generator)/upload/components/AdvanceSettings.tsx @@ -0,0 +1,172 @@ +import ToolTip from '@/components/ToolTip' +import { Button } from '@/components/ui/button' +import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog' +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' +import { Switch } from '@/components/ui/switch' +import { Textarea } from '@/components/ui/textarea' +import { SlidersHorizontal } from 'lucide-react' +import React, { useState } from 'react' +import { PresentationConfig, ToneType, VerbosityType } from '../type' + + +interface ConfigurationSelectsProps { + config: PresentationConfig; + onConfigChange: (key: keyof PresentationConfig, value: any) => void; +} +const AdvanceSettings = ({ config, onConfigChange }: ConfigurationSelectsProps) => { + + const [openAdvanced, setOpenAdvanced] = useState(false); + + const [advancedDraft, setAdvancedDraft] = useState({ + tone: config.tone, + verbosity: config.verbosity, + instructions: config.instructions, + includeTableOfContents: config.includeTableOfContents, + includeTitleSlide: config.includeTitleSlide, + webSearch: config.webSearch, + }); + + const handleOpenAdvancedChange = (open: boolean) => { + if (open) { + setAdvancedDraft({ + tone: config.tone, + verbosity: config.verbosity, + instructions: config.instructions, + includeTableOfContents: config.includeTableOfContents, + includeTitleSlide: config.includeTitleSlide, + webSearch: config.webSearch, + }); + } + setOpenAdvanced(open); + }; + + const handleSaveAdvanced = () => { + onConfigChange("tone", advancedDraft.tone); + onConfigChange("verbosity", advancedDraft.verbosity); + onConfigChange("instructions", advancedDraft.instructions); + onConfigChange("includeTableOfContents", advancedDraft.includeTableOfContents); + onConfigChange("includeTitleSlide", advancedDraft.includeTitleSlide); + onConfigChange("webSearch", advancedDraft.webSearch); + setOpenAdvanced(false); + }; + return ( +
+ + + + + + + Advanced settings + + +
+ {/* Tone */} +
+ +

Controls the writing style (e.g., casual, professional, funny).

+ +
+ + {/* Verbosity */} +
+ +

Controls how detailed slide descriptions are: concise, standard, or text-heavy.

+ +
+ + + + {/* Toggles */} +
+
+ + setAdvancedDraft((prev) => ({ ...prev, includeTableOfContents: checked }))} + /> +
+

Add an index slide summarizing sections (requires 3+ slides).

+
+
+
+ + setAdvancedDraft((prev) => ({ ...prev, includeTitleSlide: checked }))} + /> +
+

Include a title slide as the first slide.

+
+
+
+ + setAdvancedDraft((prev) => ({ ...prev, webSearch: checked }))} + /> +
+

Allow the model to consult the web for fresher facts.

+
+ + {/* Instructions */} +
+ +

Optional guidance for the AI. These override defaults except format constraints.

+