diff --git a/servers/nextjs/app/(presentation-generator)/(dashboard)/dashboard/components/PresentationCard.tsx b/servers/nextjs/app/(presentation-generator)/(dashboard)/dashboard/components/PresentationCard.tsx index c785ea51..8051258e 100644 --- a/servers/nextjs/app/(presentation-generator)/(dashboard)/dashboard/components/PresentationCard.tsx +++ b/servers/nextjs/app/(presentation-generator)/(dashboard)/dashboard/components/PresentationCard.tsx @@ -31,7 +31,7 @@ export const PresentationCard = ({ // useFontLoader(presentation.fonts || []); const handlePreview = (e: React.MouseEvent) => { e.preventDefault(); - router.push(`/presentation?id=${id}&type=${presentation.type}`); + router.push(`/presentation?id=${id}&type=standard`); }; const handleDelete = async (e: React.MouseEvent) => { diff --git a/servers/nextjs/app/(presentation-generator)/outline/hooks/usePresentationGeneration.ts b/servers/nextjs/app/(presentation-generator)/outline/hooks/usePresentationGeneration.ts index dbb15509..e990d6af 100644 --- a/servers/nextjs/app/(presentation-generator)/outline/hooks/usePresentationGeneration.ts +++ b/servers/nextjs/app/(presentation-generator)/outline/hooks/usePresentationGeneration.ts @@ -4,10 +4,9 @@ import { useRouter } from "next/navigation"; import { toast } from "sonner"; import { clearPresentationData } from "@/store/slices/presentationGeneration"; import { PresentationGenerationApi } from "../../services/api/presentation-generation"; -import { Template, LoadingState, TABS } from "../types/index"; -import { MixpanelEvent, trackEvent } from "@/utils/mixpanel"; -import { TemplateLayoutsWithSettings } from "@/app/presentation-templates"; +import { LoadingState, TABS } from "../types/index"; import { getCustomTemplateDetails } from "@/app/hooks/useCustomTemplates"; +import { TemplateLayoutsWithSettings } from "@/app/presentation-templates/utils"; const DEFAULT_LOADING_STATE: LoadingState = { message: "", @@ -129,7 +128,7 @@ export const usePresentationGeneration = ( layout = { name: selectedTemplate.id, ordered: false, - slides: selectedTemplate.layouts.map((layoutItem) => ({ + slides: selectedTemplate.layouts.map((layoutItem: any) => ({ id: layoutItem.layoutId, name: layoutItem.layoutName, description: layoutItem.layoutDescription, diff --git a/servers/nextjs/app/(presentation-generator)/presentation/components/Header.tsx b/servers/nextjs/app/(presentation-generator)/presentation/components/PresentationHeader.tsx similarity index 61% rename from servers/nextjs/app/(presentation-generator)/presentation/components/Header.tsx rename to servers/nextjs/app/(presentation-generator)/presentation/components/PresentationHeader.tsx index fc11296c..d7d387e9 100644 --- a/servers/nextjs/app/(presentation-generator)/presentation/components/Header.tsx +++ b/servers/nextjs/app/(presentation-generator)/presentation/components/PresentationHeader.tsx @@ -6,6 +6,8 @@ import { Loader2, Redo2, Undo2, + RotateCcw, + ArrowRightFromLine, } from "lucide-react"; import React, { useState } from "react"; @@ -37,17 +39,20 @@ import { usePresentationUndoRedo } from "../hooks/PresentationUndoRedo"; import ToolTip from "@/components/ToolTip"; import { clearPresentationData } from "@/store/slices/presentationGeneration"; import { clearHistory } from "@/store/slices/undoRedoSlice"; +import { Separator } from "@/components/ui/separator"; -const Header = ({ +const PresentationHeader = ({ presentation_id, + isPresentationSaving, currentSlide, }: { presentation_id: string; + isPresentationSaving: boolean; currentSlide?: number; }) => { const [open, setOpen] = useState(false); - const [showLoader, setShowLoader] = useState(false); const router = useRouter(); + const [isExporting, setIsExporting] = useState(false); const pathname = usePathname(); const dispatch = useDispatch(); @@ -68,8 +73,7 @@ const Header = ({ if (isStreaming) return; try { - setOpen(false); - setShowLoader(true); + setIsExporting(true); // Save the presentation data before exporting trackEvent(MixpanelEvent.Header_UpdatePresentationContent_API_Call); await PresentationGenerationApi.updatePresentationContent(presentationData); @@ -88,13 +92,12 @@ const Header = ({ } } catch (error) { console.error("Export failed:", error); - setShowLoader(false); toast.error("Having trouble exporting!", { description: "We are having trouble exporting your presentation. Please try again.", }); } finally { - setShowLoader(false); + setIsExporting(false); } }; @@ -102,8 +105,7 @@ const Header = ({ if (isStreaming) return; try { - setOpen(false); - setShowLoader(true); + setIsExporting(true); // Save the presentation data before exporting trackEvent(MixpanelEvent.Header_UpdatePresentationContent_API_Call); await PresentationGenerationApi.updatePresentationContent(presentationData); @@ -132,7 +134,7 @@ const Header = ({ "We are having trouble exporting your presentation. Please try again.", }); } finally { - setShowLoader(false); + setIsExporting(false); } }; const handleReGenerate = () => { @@ -182,117 +184,79 @@ const Header = ({ ); - const MenuItems = ({ mobile }: { mobile: boolean }) => ( -
- {/* undo redo */} - -
- - - - - - - - -
- - {/* Present Button */} - - - {/* Desktop Export Button with Popover */} - -
- - - - - - - - -
- - {/* Mobile Export Section */} -
- -
-
- ); return ( <> - -
+

{presentationData?.title || "Presentation"}

+
- className="bg-[#5146E5] w-full shadow-lg sticky top-0 "> + {isPresentationSaving &&
+ +
} - - - - Presentation logo - +
- {/* Desktop Menu */} -
- {isStreaming && ( - - )} + + + + + + + + + + + + + + + +
- {/* Mobile Menu */} -
- - -
- - + + + + + + + + +
); }; -export default Header; +export default PresentationHeader; diff --git a/servers/nextjs/app/(presentation-generator)/presentation/components/PresentationPage.tsx b/servers/nextjs/app/(presentation-generator)/presentation/components/PresentationPage.tsx index 3b32704c..9603141d 100644 --- a/servers/nextjs/app/(presentation-generator)/presentation/components/PresentationPage.tsx +++ b/servers/nextjs/app/(presentation-generator)/presentation/components/PresentationPage.tsx @@ -1,17 +1,15 @@ "use client"; -import React, { useEffect, useState } from "react"; +import React, { useState } from "react"; import { useSelector } from "react-redux"; import { RootState } from "@/store/store"; import { Skeleton } from "@/components/ui/skeleton"; import PresentationMode from "../../components/PresentationMode"; import SidePanel from "./SidePanel"; import SlideContent from "./SlideContent"; -import Header from "./Header"; import { Button } from "@/components/ui/button"; import { usePathname } from "next/navigation"; import { trackEvent, MixpanelEvent } from "@/utils/mixpanel"; import { AlertCircle, Loader2 } from "lucide-react"; -import Help from "./Help"; import { usePresentationStreaming, usePresentationData, @@ -21,8 +19,9 @@ import { import { PresentationPageProps } from "../types"; import LoadingState from "./LoadingState"; -import { useFontLoader } from "../../hooks/useFontLoader"; import { usePresentationUndoRedo } from "../hooks/PresentationUndoRedo"; +import PresentationHeader from "./PresentationHeader"; + const PresentationPage: React.FC = ({ presentation_id, }) => { @@ -32,7 +31,6 @@ const PresentationPage: React.FC = ({ const [selectedSlide, setSelectedSlide] = useState(0); const [isFullscreen, setIsFullscreen] = useState(false); const [error, setError] = useState(false); - const [isMobilePanelOpen, setIsMobilePanelOpen] = useState(false); const { presentationData, isStreaming } = useSelector( @@ -123,63 +121,64 @@ const PresentationPage: React.FC = ({ } return ( -
-
- {isSaving && } -
- -
- - +
- +
+ + /> +
+
+
- {!presentationData || - loading || - !presentationData?.slides || - presentationData?.slides.length === 0 ? ( -
-
- {Array.from({ length: 2 }).map((_, index) => ( - - ))} +
+ + {!presentationData || + loading || + !presentationData?.slides || + presentationData?.slides.length === 0 ? ( +
+
+ {Array.from({ length: 2 }).map((_, index) => ( + + ))} +
+ {stream && }
- {stream && } -
- ) : ( - <> - {presentationData && - presentationData.slides && - presentationData.slides.length > 0 && - presentationData.slides.map((slide: any, index: number) => ( - - ))} - - )} + ) : ( + <> + {presentationData && + presentationData.slides && + presentationData.slides.length > 0 && + presentationData.slides.map((slide: any, index: number) => ( + + ))} + + )} +
diff --git a/servers/nextjs/app/(presentation-generator)/presentation/components/SidePanel.tsx b/servers/nextjs/app/(presentation-generator)/presentation/components/SidePanel.tsx index b89879b4..301f2e41 100644 --- a/servers/nextjs/app/(presentation-generator)/presentation/components/SidePanel.tsx +++ b/servers/nextjs/app/(presentation-generator)/presentation/components/SidePanel.tsx @@ -1,8 +1,6 @@ "use client"; -import React, { useState, useEffect } from "react"; -import { LayoutList, ListTree, PanelRightOpen, X } from "lucide-react"; -import ToolTip from "@/components/ToolTip"; -import { Button } from "@/components/ui/button"; +import React, { } from "react"; +import { Plus } from "lucide-react"; import { useDispatch, useSelector } from "react-redux"; import { RootState } from "@/store/store"; import { @@ -21,26 +19,25 @@ import { } from "@dnd-kit/sortable"; import { setPresentationData } from "@/store/slices/presentationGeneration"; import { SortableSlide } from "./SortableSlide"; -import { SortableListItem } from "./SortableListItem"; import SlideScale from "../../components/PresentationRender"; +import { Separator } from "@/components/ui/separator"; +import { useRouter } from "next/navigation"; interface SidePanelProps { selectedSlide: number; onSlideClick: (index: number) => void; - isMobilePanelOpen: boolean; - setIsMobilePanelOpen: (value: boolean) => void; + loading: boolean; } const SidePanel = ({ selectedSlide, onSlideClick, - isMobilePanelOpen, - setIsMobilePanelOpen, + loading, }: SidePanelProps) => { - const [isOpen, setIsOpen] = useState(true); - const [active, setActive] = useState<"list" | "grid">("grid"); + + const router = useRouter(); const { presentationData, isStreaming } = useSelector( (state: RootState) => state.presentationGeneration @@ -50,11 +47,7 @@ const SidePanel = ({ - useEffect(() => { - if (window.innerWidth < 768) { - setIsOpen(isMobilePanelOpen); - } - }, [isMobilePanelOpen]); + const sensors = useSensors( useSensor(PointerSensor, { @@ -67,12 +60,7 @@ const SidePanel = ({ }) ); - const handleClose = () => { - setIsOpen(false); - if (window.innerWidth < 768) { - setIsMobilePanelOpen(false); - } - }; + const handleDragEnd = (event: any) => { const { active, over } = event; @@ -119,196 +107,80 @@ const SidePanel = ({ } return ( - <> - {/* Desktop Toggle Button - Always visible when panel is closed */} - {!isOpen && ( -
- - - -
- )} +
- {/* Mobile Toggle Button */} - {!isMobilePanelOpen && ( -
- - - -
- )} + { + router.push("/dashboard"); + }} src="/logo-with-bg.png" alt="" className="w-10 h-10 cursor-pointer object-contain" /> +
-
-
-
- - - - - - -
- -
-
+ +

Slides

- {/* List Preview */} - {active === "list" && ( -
- {isStreaming ? ( - presentationData && - presentationData?.slides.map((slide: any, index: number) => ( -
- - Slide {index + 1} - -

- {slide.content.title} -

-
- )) - ) : ( - slide.id!) || [] - } - strategy={verticalListSortingStrategy} +
+ {isStreaming ? ( + presentationData && + presentationData?.slides.map((slide: any, index: number) => ( +
onSlideClick(index)} + className={` cursor-pointer ring-2 rounded-[12px] transition-all duration-200 ${selectedSlide === index ? ' ring-[#5141e5]' : 'ring-gray-200' + }`} > -
- {presentationData && - presentationData?.slides.map((slide: any, index: number) => ( - - - ))} -
- - )} -
- )} - - {/* Grid Preview */} - {active === "grid" && ( -
- {isStreaming ? ( - presentationData && - presentationData?.slides.map((slide: any, index: number) => ( -
onSlideClick(index)} - className={` cursor-pointer ring-2 p-1 rounded-md transition-all duration-200 ${selectedSlide === index ? ' ring-[#5141e5]' : 'ring-gray-200' - }`} - > -
-
-
- -
+
+
+
+
- )) - ) : ( - slide.id || `${slide.index}`) || [] - } - strategy={verticalListSortingStrategy} - > - {presentationData && - presentationData?.slides.map((slide: any, index: number) => ( - + )) + ) : ( + slide.id || `${slide.index}`) || [] + } + strategy={verticalListSortingStrategy} + > + {presentationData && + presentationData?.slides.map((slide: any, index: number) => ( + + ))} + + )} +
- /> - ))} - - )} -
- )} + +
- +
); }; diff --git a/servers/nextjs/app/(presentation-generator)/presentation/components/SlideContent.tsx b/servers/nextjs/app/(presentation-generator)/presentation/components/SlideContent.tsx index 32e1fd6e..d694c594 100644 --- a/servers/nextjs/app/(presentation-generator)/presentation/components/SlideContent.tsx +++ b/servers/nextjs/app/(presentation-generator)/presentation/components/SlideContent.tsx @@ -132,7 +132,7 @@ const SlideContent = ({ slide, index, presentationId }: SlideContentProps) => { <>
{isStreaming && ( diff --git a/servers/nextjs/app/(presentation-generator)/presentation/components/SortableSlide.tsx b/servers/nextjs/app/(presentation-generator)/presentation/components/SortableSlide.tsx index 3356dd88..c6d55f3d 100644 --- a/servers/nextjs/app/(presentation-generator)/presentation/components/SortableSlide.tsx +++ b/servers/nextjs/app/(presentation-generator)/presentation/components/SortableSlide.tsx @@ -10,7 +10,7 @@ interface SortableSlideProps { selectedSlide: number; onSlideClick: (index: any) => void; } -const SCALE = 0.2; +const SCALE = 0.125; export function SortableSlide({ slide, index, selectedSlide, onSlideClick }: SortableSlideProps) { const searchParams = useSearchParams(); @@ -55,7 +55,7 @@ export function SortableSlide({ slide, index, selectedSlide, onSlideClick }: Sor {...attributes} {...listeners} onClick={handleClick} - className={` cursor-pointer border-[3px] relative p-1 shadow-lg rounded-md transition-all duration-200 ${selectedSlide === index ? ' border-[#5141e5]' : 'border-gray-300' + className={` cursor-pointer border relative p-1 rounded-[12px] transition-all duration-200 ${selectedSlide === index ? ' border-[#5141e5]' : 'border-[#EDEEEF]' }`} > diff --git a/servers/nextjs/app/(presentation-generator)/upload/components/UploadPage.tsx b/servers/nextjs/app/(presentation-generator)/upload/components/UploadPage.tsx index f44bf5f6..55248085 100644 --- a/servers/nextjs/app/(presentation-generator)/upload/components/UploadPage.tsx +++ b/servers/nextjs/app/(presentation-generator)/upload/components/UploadPage.tsx @@ -211,7 +211,7 @@ const UploadPage = () => { onConfigChange={handleConfigChange} />
*/} -
+