html to pdf page added

This commit is contained in:
shiva raj badu 2025-05-13 23:21:49 +05:45
parent abe4226147
commit 43062f7e6f
6 changed files with 278 additions and 71 deletions

View file

@ -26,7 +26,7 @@ const Type1Layout = ({
const { currentColors } = useSelector((state: RootState) => state.theme);
return (
<div
className="slide-container font-inter w-full rounded-sm max-w-[1280px] shadow-lg px-3 sm:px-12 lg:px-20 py-[10px] sm:py-[40px] lg:py-[86px] max-h-[720px] flex items-center aspect-video bg-white relative z-20"
className="slide-container w-full rounded-sm max-w-[1280px] shadow-lg px-3 sm:px-12 lg:px-20 py-[10px] sm:py-[40px] lg:py-[86px] max-h-[720px] flex items-center aspect-video bg-white relative z-20"
data-slide-element
data-slide-id={slideId}
data-slide-index={slideIndex}

View file

@ -46,7 +46,7 @@ const Type8Layout = ({
return (
<div
className="slide-container shadow-lg w-full rounded-sm font-inter px-3 sm:px-12 lg:px-20 py-[10px] sm:py-[40px] lg:py-[86px] flex items-center justify-center max-h-[720px] aspect-video bg-white relative z-20"
className="slide-container shadow-lg w-full max-w-[1280px] rounded-sm font-inter px-3 sm:px-12 lg:px-20 py-[10px] sm:py-[40px] lg:py-[86px] flex items-center justify-center max-h-[720px] aspect-video bg-white relative z-20"
data-slide-element
data-slide-index={slideIndex}
data-slide-id={slideId}
@ -89,29 +89,73 @@ const Type8Layout = ({
<div className="space-y-4 lg:space-y-8">
{body && body.length > 0 && body.length === 2
? body.map((item, index) => (
<div
data-slide-element
data-slide-index={slideIndex}
data-element-type="slide-box"
data-element-id={`slide-${slideIndex}-item-${index}-box`}
style={{
boxShadow: "0 2px 10px 0 rgba(43, 43, 43, 0.2)",
}}
key={`${body.length}-${index}`}
className="slide-box rounded-lg p-3 lg:p-6 relative group"
>
<ElementMenu index={index} handleDeleteItem={DeleteItem} />
<IconsEditor
icon={icons[index]}
index={index}
backgroundColor={currentColors.iconBg}
hasBg={true}
slideIndex={slideIndex}
elementId={`slide-${slideIndex}-icon-${index}`}
icon_prompt={icon_queries?.[index]?.queries || []}
/>
<div
data-slide-element
data-slide-index={slideIndex}
data-element-type="slide-box"
data-element-id={`slide-${slideIndex}-item-${index}-box`}
style={{
boxShadow: "0 2px 10px 0 rgba(43, 43, 43, 0.2)",
}}
key={`${body.length}-${index}`}
className="slide-box rounded-lg p-3 lg:p-6 relative group"
>
<ElementMenu index={index} handleDeleteItem={DeleteItem} />
<IconsEditor
icon={icons[index]}
index={index}
backgroundColor={currentColors.iconBg}
hasBg={true}
slideIndex={slideIndex}
elementId={`slide-${slideIndex}-icon-${index}`}
icon_prompt={icon_queries?.[index]?.queries || []}
/>
<div className="space-y-1 lg:space-y-3 lg:mt-3">
<div className="space-y-1 lg:space-y-3 lg:mt-3">
<EditableText
slideIndex={slideIndex}
elementId={`slide-${slideIndex}-item-${index}-heading`}
type="heading"
bodyIdx={index}
content={item.heading}
/>
<EditableText
slideIndex={slideIndex}
elementId={`slide-${slideIndex}-item-${index}-description`}
type="heading-description"
bodyIdx={index}
content={item.description}
/>
</div>
</div>
))
: body.map((item, index) => (
<div
data-slide-element
data-slide-index={slideIndex}
data-element-type="slide-box"
data-element-id={`slide-${slideIndex}-item-${index}-box`}
style={{
boxShadow: "0 2px 10px 0 rgba(43, 43, 43, 0.2)",
}}
key={`${body.length}-${index}`}
className="slide-box rounded-lg p-3 lg:p-6 relative group"
>
<ElementMenu index={index} handleDeleteItem={DeleteItem} />
<div className="flex items-start gap-4">
<div className="w-[32px] md:w-[64px] h-[32px] md:h-[64px]">
<IconsEditor
className="rounded-lg"
icon={icons[index]}
index={index}
backgroundColor={currentColors.iconBg}
hasBg={true}
slideIndex={slideIndex}
elementId={`slide-${slideIndex}-icon-${index}`}
icon_prompt={icon_queries?.[index]?.queries || []}
/>
</div>
<div className="lg:space-y-3 ">
<EditableText
slideIndex={slideIndex}
elementId={`slide-${slideIndex}-item-${index}-heading`}
@ -128,52 +172,8 @@ const Type8Layout = ({
/>
</div>
</div>
))
: body.map((item, index) => (
<div
data-slide-element
data-slide-index={slideIndex}
data-element-type="slide-box"
data-element-id={`slide-${slideIndex}-item-${index}-box`}
style={{
boxShadow: "0 2px 10px 0 rgba(43, 43, 43, 0.2)",
}}
key={`${body.length}-${index}`}
className="slide-box rounded-lg p-3 lg:p-6 relative group"
>
<ElementMenu index={index} handleDeleteItem={DeleteItem} />
<div className="flex items-start gap-4">
<div className="w-[32px] md:w-[64px] h-[32px] md:h-[64px]">
<IconsEditor
className="rounded-lg"
icon={icons[index]}
index={index}
backgroundColor={currentColors.iconBg}
hasBg={true}
slideIndex={slideIndex}
elementId={`slide-${slideIndex}-icon-${index}`}
icon_prompt={icon_queries?.[index]?.queries || []}
/>
</div>
<div className="lg:space-y-3 ">
<EditableText
slideIndex={slideIndex}
elementId={`slide-${slideIndex}-item-${index}-heading`}
type="heading"
bodyIdx={index}
content={item.heading}
/>
<EditableText
slideIndex={slideIndex}
elementId={`slide-${slideIndex}-item-${index}-description`}
type="heading-description"
bodyIdx={index}
content={item.description}
/>
</div>
</div>
</div>
))}
</div>
))}
</div>
</div>
</div>

View file

@ -0,0 +1,176 @@
"use client";
import React, { useEffect, useState, useCallback, useRef } from "react";
import { useDispatch, useSelector } from "react-redux";
import { RootState } from "@/store/store";
import { Skeleton } from "@/components/ui/skeleton";
import { DashboardApi } from "@/app/dashboard/api/dashboard";
import SlideContent from "../presentation/components/SlideContent";
import {
deletePresentationSlide,
setPresentationData,
} from "@/store/slices/presentationGeneration";
import { toast } from "@/hooks/use-toast";
import { Loader2 } from "lucide-react";
import { Button } from "@/components/ui/button";
import { AlertCircle } from "lucide-react";
import { setThemeColors, ThemeColors } from "../store/themeSlice";
import { ThemeType } from "../upload/type";
import { PresentationGenerationApi } from "../services/api/presentation-generation";
import { renderSlideContent } from "../components/slide_config";
// Custom debounce function
function useDebounce<T extends (...args: any[]) => void>(
callback: T,
delay: number
) {
const timeoutRef = useRef<NodeJS.Timeout>();
return useCallback(
(...args: Parameters<T>) => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
timeoutRef.current = setTimeout(() => {
callback(...args);
}, delay);
},
[callback, delay]
);
}
const PresentationPage = ({ presentation_id }: { presentation_id: string }) => {
const dispatch = useDispatch();
const [loading, setLoading] = useState(true);
const { currentTheme, currentColors } = useSelector(
(state: RootState) => state.theme
);
const { presentationData } = useSelector(
(state: RootState) => state.presentationGeneration
);
const [error, setError] = useState(false);
// Function to fetch the slides
useEffect(() => {
fetchUserSlides();
}, []);
// Function to fetch the user slides
const fetchUserSlides = async () => {
try {
const data = await DashboardApi.getPresentation(presentation_id);
if (data) {
if (data.presentation.theme) {
dispatch(
setThemeColors({
...data.presentation.theme.colors,
theme: data.presentation.theme.name as ThemeType,
})
);
setColorsVariables(
data.presentation.theme.colors,
data.presentation.theme.name as ThemeType
);
}
dispatch(setPresentationData(data));
setLoading(false);
}
} catch (error) {
setError(true);
toast({
title: "Error",
description: "Failed to load presentation",
variant: "destructive",
});
console.error("Error fetching user slides:", error);
setLoading(false);
}
};
const setColorsVariables = (colors: ThemeColors, theme: ThemeType) => {
const root = document.documentElement;
Object.entries(colors).forEach(([key, value]) => {
const cssKey = key.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
root.style.setProperty(`--${theme}-${cssKey}`, value);
});
};
const language = presentationData?.presentation?.language || "English";
// Regular view
return (
<div className="h-screen flex overflow-hidden flex-col">
{error ? (
<div className="flex flex-col items-center justify-center h-screen bg-gray-100">
<div
className="bg-white border border-red-300 text-red-700 px-6 py-8 rounded-lg shadow-lg flex flex-col items-center"
role="alert"
>
<AlertCircle className="w-16 h-16 mb-4 text-red-500" />
<strong className="font-bold text-4xl mb-2">Oops!</strong>
<p className="block text-2xl py-2">
We encountered an issue loading your presentation.
</p>
<p className="text-lg py-2">
Please check your internet connection or try again later.
</p>
<Button
className="mt-4 bg-red-500 text-white hover:bg-red-600 focus:ring-4 focus:ring-red-300"
onClick={() => window.location.reload()}
>
Retry
</Button>
</div>
</div>
) : (
<div style={{
background: currentColors.background,
}} className="flex-1 h-[calc(100vh-100px)] overflow-y-auto">
<div
className="mx-auto flex flex-col items-center overflow-hidden justify-center slide-theme"
data-theme={currentTheme}
>
{!presentationData ||
loading ||
!presentationData?.slides ||
presentationData?.slides.length === 0 ? (
<div className="relative w-full h-[calc(100vh-120px)] mx-auto ">
<div className=" ">
{Array.from({ length: 2 }).map((_, index) => (
<Skeleton
key={index}
className="aspect-video bg-gray-400 my-4 w-full mx-auto max-w-[1280px]"
/>
))}
</div>
</div>
) : (
<>
{presentationData &&
presentationData.slides &&
presentationData.slides.length > 0 &&
presentationData.slides.map((slide, index) => (
renderSlideContent(slide, language)
))}
</>
)}
</div>
</div>
)}
</div>
);
};
export default PresentationPage;

View file

@ -0,0 +1,28 @@
'use client'
import React from "react";
import { FooterProvider } from "../context/footerContext";
import { Button } from "@/components/ui/button";
import { useRouter, useSearchParams } from "next/navigation";
import PdfMakerPage from "./PdfMakerPage";
const page = () => {
const router = useRouter();
const params = useSearchParams();
const queryId = params.get("id");
if (!queryId) {
return (
<div className="flex flex-col items-center justify-center h-screen">
<h1 className="text-2xl font-bold">No presentation id found</h1>
<p className="text-gray-500 pb-4">Please try again</p>
<Button onClick={() => router.push("/dashboard")}>Go to home</Button>
</div>
);
}
return (
<FooterProvider>
<PdfMakerPage presentation_id={queryId} />
</FooterProvider>
);
};
export default page;

View file

@ -324,6 +324,9 @@ const Header = ({
{isStreaming && (
<Loader2 className="animate-spin text-white font-bold w-6 h-6" />
)}
<button onClick={() => router.push(`/pdf-maker?id=${presentation_id}`)}>
go there
</button>
<Select value={currentTheme} onValueChange={handleThemeSelect}>
<SelectTrigger className="w-[160px] bg-[#6358fd] text-white border-none hover:bg-[#5146E5] transition-colors">
<div className="flex items-center gap-2">

View file

@ -5,7 +5,7 @@ import PresentationPage from "./components/PresentationPage";
import { Button } from "@/components/ui/button";
import { useRouter, useSearchParams } from "next/navigation";
const page = () => {
console.log("presentation page", window.location.href);
const router = useRouter();
const params = useSearchParams();
const queryId = params.get("id");