From d4813b02a643a0c3330963a36944b398f0d47f59 Mon Sep 17 00:00:00 2001 From: shiva raj badu Date: Sat, 19 Jul 2025 22:59:02 +0545 Subject: [PATCH] refactor (Nextjs): Unused files and function removed --- .../components/CustomThemeSettings.tsx | 291 -------------- .../components/EditableText.tsx | 111 ------ .../components/ElementMenu.tsx | 43 --- .../{UserAccount.tsx => HeaderNab.tsx} | 4 +- .../{slide_layouts => }/NewSlide.tsx | 0 .../components/PresentationMode.tsx | 7 +- .../{slide_layouts => }/SlideFooter.tsx | 0 .../components/Tiptap.tsx | 91 ----- .../components/TypeWriter.tsx | 14 - .../components/slide_layouts/AllChart.tsx | 104 ----- .../components/slide_layouts/Type1Layout.tsx | 82 ---- .../components/slide_layouts/Type2Layout.tsx | 358 ------------------ .../components/slide_layouts/Type4Layout.tsx | 147 ------- .../components/slide_layouts/Type5Layout.tsx | 73 ---- .../components/slide_layouts/Type6Layout.tsx | 139 ------- .../components/slide_layouts/Type7Layout.tsx | 209 ---------- .../components/slide_layouts/Type8Layout.tsx | 185 --------- .../components/slide_layouts/Type9Layout.tsx | 139 ------- .../components/DocumentPreviewPage.tsx | 8 +- .../documents-preview/styles/main.module.css | 39 -- .../hooks/use-slide-operations.ts | 56 --- .../presentation/components/Header.tsx | 152 +------- .../components/LoadingState.tsx | 0 .../components/PresentationPage.tsx | 11 +- .../presentation/components/SidePanel.tsx | 14 +- .../presentation/components/SlideContent.tsx | 2 +- .../presentation/components/ThemeSelector.tsx | 155 -------- .../store/themeSlice.ts | 164 -------- .../styles/themes.css | 148 -------- .../theme/ThemePage.tsx | 184 --------- .../theme/loading.tsx | 24 -- .../(presentation-generator)/theme/page.tsx | 16 - .../utils/NewSlideContent.ts | 151 -------- .../(presentation-generator)/utils/chart.tsx | 46 --- .../utils/chartDataTransforms.ts | 18 - .../utils/layoutsExtractor.ts | 285 -------------- .../app/dashboard/components/Header.tsx | 4 +- servers/nextjs/app/globals.css | 1 - servers/nextjs/app/layout-preview/README.md | 137 ------- servers/nextjs/data/presenton-settings.db | Bin 12288 -> 0 bytes servers/nextjs/hooks/useTypeWriter.ts | 39 -- servers/nextjs/lib/utils.ts | 63 --- servers/nextjs/store/store.ts | 2 - servers/nextjs/utils/helpers.ts | 122 ------ 44 files changed, 28 insertions(+), 3810 deletions(-) delete mode 100644 servers/nextjs/app/(presentation-generator)/components/CustomThemeSettings.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/components/EditableText.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/components/ElementMenu.tsx rename servers/nextjs/app/(presentation-generator)/components/{UserAccount.tsx => HeaderNab.tsx} (95%) rename servers/nextjs/app/(presentation-generator)/components/{slide_layouts => }/NewSlide.tsx (100%) rename servers/nextjs/app/(presentation-generator)/components/{slide_layouts => }/SlideFooter.tsx (100%) delete mode 100644 servers/nextjs/app/(presentation-generator)/components/Tiptap.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/components/TypeWriter.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/components/slide_layouts/AllChart.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type1Layout.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type2Layout.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type4Layout.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type5Layout.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type6Layout.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type7Layout.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type8Layout.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type9Layout.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/documents-preview/styles/main.module.css delete mode 100644 servers/nextjs/app/(presentation-generator)/hooks/use-slide-operations.ts rename servers/nextjs/app/(presentation-generator)/{ => presentation}/components/LoadingState.tsx (100%) delete mode 100644 servers/nextjs/app/(presentation-generator)/presentation/components/ThemeSelector.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/store/themeSlice.ts delete mode 100644 servers/nextjs/app/(presentation-generator)/styles/themes.css delete mode 100644 servers/nextjs/app/(presentation-generator)/theme/ThemePage.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/theme/loading.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/theme/page.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/utils/NewSlideContent.ts delete mode 100644 servers/nextjs/app/(presentation-generator)/utils/chart.tsx delete mode 100644 servers/nextjs/app/(presentation-generator)/utils/chartDataTransforms.ts delete mode 100644 servers/nextjs/app/(presentation-generator)/utils/layoutsExtractor.ts delete mode 100644 servers/nextjs/app/layout-preview/README.md delete mode 100644 servers/nextjs/data/presenton-settings.db delete mode 100644 servers/nextjs/hooks/useTypeWriter.ts delete mode 100644 servers/nextjs/utils/helpers.ts diff --git a/servers/nextjs/app/(presentation-generator)/components/CustomThemeSettings.tsx b/servers/nextjs/app/(presentation-generator)/components/CustomThemeSettings.tsx deleted file mode 100644 index 02cd1e66..00000000 --- a/servers/nextjs/app/(presentation-generator)/components/CustomThemeSettings.tsx +++ /dev/null @@ -1,291 +0,0 @@ -import React, { useState, useRef } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import { RootState } from "@/store/store"; -import { Label } from "@/components/ui/label"; -import { Input } from "@/components/ui/input"; -import { Button } from "@/components/ui/button"; -import { - setThemeColors, - setTheme, - setLoadingState, -} from "../store/themeSlice"; -import { ThemeType } from "../upload/type"; - -import { useThemeService, ThemeColors } from "../services/themeService"; -import { PresentationGenerationApi } from "../services/api/presentation-generation"; - -interface CustomThemeSettingsProps { - onClose?: () => void; - presentationId: string; -} - -const CustomThemeSettings = ({ - onClose, - presentationId, -}: CustomThemeSettingsProps) => { - const dispatch = useDispatch(); - const [draftColors, setDraftColors] = useState({ - background: "#63ceff", - slideBg: "#F4F4F4", - slideTitle: "#1A1A1A", - slideHeading: "#2D2D2D", - slideDescription: "#4A4A4A", - slideBox: "#d8c6c6", - iconBg: "#281810", - chartColors: ["#281810", "#4A3728", "#665E57", "#665E57", "#665E57"], - fontFamily: "var(--font-inter)", - }); - - const themeService = useThemeService(); - - // Refs for tracking drag state and RAF - const isDragging = useRef(false); - const rafId = useRef(); - const currentKey = useRef(); - const currentValue = useRef(); - - const updateDraftColor = (key: string, value: string) => { - if (rafId.current) { - cancelAnimationFrame(rafId.current); - } - - rafId.current = requestAnimationFrame(() => { - setDraftColors((prev) => ({ - ...prev, - [key]: value, - })); - }); - }; - - const handleColorPickerChange = (key: string, value: string) => { - if (isDragging.current) { - // Update refs for current values - currentKey.current = key; - currentValue.current = value; - // Update preview immediately - const previewElement = document.getElementById(`preview-${key}`); - if (previewElement) { - previewElement.style.backgroundColor = value; - } - } else { - // For non-drag changes (like text input), update immediately - updateDraftColor(key, value); - } - }; - - const handleColorPickerMouseDown = () => { - isDragging.current = true; - }; - - const handleColorPickerMouseUp = () => { - isDragging.current = false; - // Apply the final color value - if (currentKey.current && currentValue.current) { - updateDraftColor(currentKey.current, currentValue.current); - } - }; - - const handleTextInputChange = (key: string, value: string) => { - updateDraftColor(key, value); - }; - - const handleSave = async () => { - try { - // Update UI immediately - const themeType = "custom" as ThemeType; - dispatch(setTheme(themeType)); - dispatch( - setThemeColors({ - ...draftColors, - theme: themeType, - }) - ); - - // Set CSS variables - const root = document.documentElement; - root.style.setProperty("--custom-slide-bg", draftColors.slideBg); - root.style.setProperty("--custom-slide-title", draftColors.slideTitle); - root.style.setProperty( - "--custom-slide-heading", - draftColors.slideHeading - ); - root.style.setProperty( - "--custom-slide-description", - draftColors.slideDescription - ); - root.style.setProperty("--custom-slide-box", draftColors.slideBox); - root.style.setProperty("--custom-icon-bg", draftColors.iconBg); - - // Save to file and API - await Promise.all([ - PresentationGenerationApi.setThemeColors(presentationId, { - name: themeType, - colors: { - ...draftColors, - }, - }), - themeService.saveTheme({ - name: "custom", - colors: { - ...draftColors, - theme: themeType, - }, - }), - ]); - - onClose?.(); - } catch (error) { - console.error("Failed to save custom theme:", error); - } - }; - - // Load saved theme - React.useEffect(() => { - const loadSavedCustomTheme = async () => { - try { - dispatch(setLoadingState(true)); - const savedTheme = await themeService.getTheme(); - if (savedTheme) { - setDraftColors(savedTheme.colors); - } - } catch (error) { - console.error("Failed to load theme preferences:", error); - } finally { - dispatch(setLoadingState(false)); - } - }; - - loadSavedCustomTheme(); - }, []); - - // Cleanup RAF on unmount - React.useEffect(() => { - return () => { - if (rafId.current) { - cancelAnimationFrame(rafId.current); - } - }; - }, []); - - const colorInputs = [ - { key: "background", label: "Background Color", icon: "🎨" }, - { key: "slideBg", label: "Slide Background Color", icon: "🎨" }, - { key: "slideTitle", label: "Title Color", icon: "📝" }, - { key: "slideHeading", label: "Heading Color", icon: "🔤" }, - { key: "slideDescription", label: "Description Color", icon: "📄" }, - { key: "slideBox", label: "Box Color", icon: "📦" }, - { key: "iconBg", label: "Icon Background Color", icon: "📦" }, - ]; - - return ( -
-
- {/* Live Preview */} -
-

Live Preview

-
-
-
- Sample Title -
-
- Heading -
-
- Description text -
-
-
-
-
-
- {colorInputs.map(({ key, label, icon }) => ( -
-
- handleColorPickerChange(key, e.target.value)} - onMouseDown={() => handleColorPickerMouseDown()} - onMouseUp={() => handleColorPickerMouseUp()} - onTouchStart={() => handleColorPickerMouseDown()} - onTouchEnd={() => handleColorPickerMouseUp()} - className="w-12 h-12 p-1 cursor-pointer border rounded-lg transition-all hover:border-[#5146E5] focus:border-[#5146E5]" - /> -
-
-
- - handleTextInputChange(key, e.target.value)} - className="h-8 font-mono text-sm" - placeholder="#000000" - /> -
-
- ))} -
-
-
- - -
-
- ); -}; - -export default CustomThemeSettings; diff --git a/servers/nextjs/app/(presentation-generator)/components/EditableText.tsx b/servers/nextjs/app/(presentation-generator)/components/EditableText.tsx deleted file mode 100644 index b2702807..00000000 --- a/servers/nextjs/app/(presentation-generator)/components/EditableText.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import React, { useEffect, useRef } from "react"; -import { useSelector } from "react-redux"; -import TipTapEditor from "./Tiptap"; -import { RootState } from "@/store/store"; -import Typewriter from "./TypeWriter"; - -interface EditableTextProps { - slideIndex: number; - bodyIdx?: number; - elementId: string; - type: - | "title" - | "heading" - | "description-body" - | "description" - | "heading-description" - | "info-heading" - | "info-description"; - content: string; - isAlingCenter?: boolean; -} - -const EditableText = ({ - slideIndex, - elementId, - type, - content, - bodyIdx = 0, - isAlingCenter = false, -}: EditableTextProps) => { - const { isStreaming } = useSelector( - (state: RootState) => state.presentationGeneration - ); - - const elementRef = useRef(null); - - // Add useEffect to initialize content - useEffect(() => { - if (elementRef.current) { - const displayContent = content || getPlaceholder(); - elementRef.current.textContent = displayContent; - - // Add placeholder styling if needed - if (!content) { - elementRef.current.classList.add("text-gray-400"); - } - } - }, [content]); - - const getPlaceholder = () => { - switch (type) { - case "title": - return "Enter title"; - case "heading": - return "Enter heading"; - case "description-body": - return "Enter description"; - case "description": - return "Enter description"; - case "heading-description": - return "Enter description"; - case "info-heading": - return "Enter heading"; - case "info-description": - return "Enter description"; - default: - return "Enter text"; - } - }; - - const getTextStyle = () => { - const baseStyle = "outline-none transition-all duration-200"; - switch (type) { - case "title": - return `${baseStyle} text-[40px] slide-title leading-[48px] font-bold`; - case "heading": - return `${baseStyle} text-[24px] slide-heading leading-[32px] font-bold`; - case "description": - case "description-body": - case "heading-description": - return `${baseStyle} text-[20px] slide-description leading-[24px] font-normal`; - default: - return `${baseStyle} text-[20px] slide-description leading-[24px] font-normal`; - } - }; - - return ( - <> - {isStreaming ? ( -
- -
- ) : ( - - )} - - ); -}; - -export default React.memo(EditableText); diff --git a/servers/nextjs/app/(presentation-generator)/components/ElementMenu.tsx b/servers/nextjs/app/(presentation-generator)/components/ElementMenu.tsx deleted file mode 100644 index 7c7697ec..00000000 --- a/servers/nextjs/app/(presentation-generator)/components/ElementMenu.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { MoreHorizontal } from "lucide-react"; -import React from "react"; - -interface ElementMenuProps { - index: number; - handleDeleteItem: (index: number) => void; -} - -const ElementMenu = ({ index, handleDeleteItem }: ElementMenuProps) => { - return ( - - - - - - handleDeleteItem(index)} - className="px-3 py-2 cursor-pointer" - > - Delete Item {index + 1} - - - - ); -}; - -// Prevent unnecessary re-renders -export default React.memo(ElementMenu, (prevProps, nextProps) => { - return ( - prevProps.index === nextProps.index && prevProps.index === nextProps.index - ); -}); diff --git a/servers/nextjs/app/(presentation-generator)/components/UserAccount.tsx b/servers/nextjs/app/(presentation-generator)/components/HeaderNab.tsx similarity index 95% rename from servers/nextjs/app/(presentation-generator)/components/UserAccount.tsx rename to servers/nextjs/app/(presentation-generator)/components/HeaderNab.tsx index 9d213c1a..5f0fbe2e 100644 --- a/servers/nextjs/app/(presentation-generator)/components/UserAccount.tsx +++ b/servers/nextjs/app/(presentation-generator)/components/HeaderNab.tsx @@ -5,7 +5,7 @@ import Link from "next/link"; import { RootState } from "@/store/store"; import { useSelector } from "react-redux"; -const UserAccount = () => { +const HeaderNav = () => { const canChangeKeys = useSelector((state: RootState) => state.userConfig.can_change_keys); @@ -39,4 +39,4 @@ const UserAccount = () => { ); }; -export default UserAccount; +export default HeaderNav; diff --git a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/NewSlide.tsx b/servers/nextjs/app/(presentation-generator)/components/NewSlide.tsx similarity index 100% rename from servers/nextjs/app/(presentation-generator)/components/slide_layouts/NewSlide.tsx rename to servers/nextjs/app/(presentation-generator)/components/NewSlide.tsx diff --git a/servers/nextjs/app/(presentation-generator)/components/PresentationMode.tsx b/servers/nextjs/app/(presentation-generator)/components/PresentationMode.tsx index 4ceec318..e466711a 100644 --- a/servers/nextjs/app/(presentation-generator)/components/PresentationMode.tsx +++ b/servers/nextjs/app/(presentation-generator)/components/PresentationMode.tsx @@ -15,7 +15,7 @@ import { useGroupLayouts } from "../hooks/useGroupLayouts"; interface PresentationModeProps { slides: Slide[]; currentSlide: number; - currentTheme: string; + isFullscreen: boolean; onFullscreenToggle: () => void; onExit: () => void; @@ -26,7 +26,7 @@ const PresentationMode: React.FC = ({ slides, currentSlide, - currentTheme, + isFullscreen, onFullscreenToggle, onExit, @@ -190,10 +190,9 @@ const PresentationMode: React.FC = ({
{slides[currentSlide] && - renderSlideContent(slides[currentSlide])} + renderSlideContent(slides[currentSlide], false)}
diff --git a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/SlideFooter.tsx b/servers/nextjs/app/(presentation-generator)/components/SlideFooter.tsx similarity index 100% rename from servers/nextjs/app/(presentation-generator)/components/slide_layouts/SlideFooter.tsx rename to servers/nextjs/app/(presentation-generator)/components/SlideFooter.tsx diff --git a/servers/nextjs/app/(presentation-generator)/components/Tiptap.tsx b/servers/nextjs/app/(presentation-generator)/components/Tiptap.tsx deleted file mode 100644 index 33e11dfb..00000000 --- a/servers/nextjs/app/(presentation-generator)/components/Tiptap.tsx +++ /dev/null @@ -1,91 +0,0 @@ -"use client"; - -import { useEditor, EditorContent, BubbleMenu } from "@tiptap/react"; -import StarterKit from "@tiptap/starter-kit"; -import { Markdown } from "tiptap-markdown"; -import Underline from "@tiptap/extension-underline"; -import { - Bold, - Italic, - Underline as UnderlinedIcon, - Strikethrough, - Code, -} from "lucide-react"; - - - -const TipTapEditor = ({ - content, -}: { - content: string; - -}) => { - - const editor = useEditor({ - extensions: [StarterKit, Markdown, Underline], - content: content, - editorProps: { - attributes: { - class: "outline-none transition-all duration-200", - }, - }, - immediatelyRender: false, - }); - - return ( -
- -
- - - - - -
-
- - { - const markdown = editor?.storage.markdown.getMarkdown(); - console.log("🔍 markdown", markdown); - }} - - editor={editor} - /> -
- ); -}; - -export default TipTapEditor; diff --git a/servers/nextjs/app/(presentation-generator)/components/TypeWriter.tsx b/servers/nextjs/app/(presentation-generator)/components/TypeWriter.tsx deleted file mode 100644 index a9b8acd9..00000000 --- a/servers/nextjs/app/(presentation-generator)/components/TypeWriter.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { useTypewriter } from "@/hooks/useTypeWriter"; - -const Typewriter = ({ text, speed }: { text: string; speed: number }) => { - const { displayText, isCursorVisible } = useTypewriter(text, speed, true); - - return ( -

- {displayText} - {isCursorVisible && |} -

- ); -}; - -export default Typewriter; diff --git a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/AllChart.tsx b/servers/nextjs/app/(presentation-generator)/components/slide_layouts/AllChart.tsx deleted file mode 100644 index 687b6306..00000000 --- a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/AllChart.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import React, { useState, useEffect } from "react"; -import ChartEditor from "../ChartEditor"; -import { StoreChartData } from "../../utils/chartDataTransforms"; -import { useDispatch, useSelector } from "react-redux"; -import { - ChartSettings, - updateSlideChart, - updateSlideChartSettings, -} from "@/store/slices/presentationGeneration"; -import { renderChart } from "../slide_config"; -import { RootState } from "@/store/store"; - -interface AllChartProps { - chartData: StoreChartData; - slideIndex: number; -} - -const AllChart = ({ - chartData: initialChartData, - slideIndex, -}: AllChartProps) => { - const dispatch = useDispatch(); - const [localChartData, setLocalChartData] = - useState(initialChartData); - const [isEditorOpen, setIsEditorOpen] = useState(false); - const { currentColors } = useSelector((state: RootState) => state.theme); - - // Use chart settings from the Redux store - const chartSettings = useSelector((state: RootState) => { - const slide = - state.presentationGeneration?.presentationData?.slides[slideIndex]; - - - const style = slide?.content.graph.style || {}; - return Object.keys( - style === null || style === undefined ? {} : (style as ChartSettings) - ).length > 0 - ? (style as ChartSettings) - : { - showLegend: false, - showGrid: false, - showAxisLabel: true, - showDataLabel: true, - dataLabel: { - dataLabelPosition: - slide?.content.graph.type === "pie" - ? ("Outside" as const) - : ("Inside" as const), - dataLabelAlignment: "Center" as const, - }, - }; - }); - - useEffect(() => { - setLocalChartData(initialChartData); - }, [initialChartData]); - - const handleChartClick = () => { - setIsEditorOpen(true); - }; - - const onChartDataChange = (newData: StoreChartData) => { - dispatch(updateSlideChart({ index: slideIndex, chart: newData })); - setLocalChartData(newData); - }; - - const onChartSettingsChange = (newSettings: ChartSettings) => { - dispatch( - updateSlideChartSettings({ - index: slideIndex, - chartSettings: newSettings, - }) - ); - }; - - return ( - <> -
- {renderChart(localChartData, false, currentColors ?? [], chartSettings)} - {/* {localChartData.type} */} -
- - {localChartData && ( - setIsEditorOpen(false)} - chartData={localChartData} - onChartDataChange={onChartDataChange} - /> - )} - - ); -}; - -export default AllChart; diff --git a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type1Layout.tsx b/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type1Layout.tsx deleted file mode 100644 index 9570dbe5..00000000 --- a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type1Layout.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import React from "react"; -import EditableText from "../EditableText"; -import ImageEditor from "../ImageEditor"; -import { useSelector } from "react-redux"; -import { RootState } from "@/store/store"; -import SlideFooter from "./SlideFooter"; - -interface Type1LayoutProps { - title: string; - description: string; - slideId: string | null; - images: string[]; - slideIndex: number; - image_prompts?: string[] | null; - properties?: null | any; -} -const Type1Layout = ({ - title, - description, - images, - slideId, - slideIndex, - image_prompts, - properties, -}: Type1LayoutProps) => { - const { currentColors } = useSelector((state: RootState) => state.theme); - return ( -
-
-
- - -
- - - - {/* {imagePosition === 'left' ? ( - <> - - - - ) : ( - <> - - - - )} */} -
- -
- ); -}; - -export default Type1Layout; diff --git a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type2Layout.tsx b/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type2Layout.tsx deleted file mode 100644 index aba6a0db..00000000 --- a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type2Layout.tsx +++ /dev/null @@ -1,358 +0,0 @@ -import React from "react"; -import EditableText from "../EditableText"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { MoreVertical, Plus } from "lucide-react"; -import ElementMenu from "../ElementMenu"; -import { useSelector } from "react-redux"; -import { numberTranslations } from "../../utils/others"; -import { RootState } from "@/store/store"; -import { useSlideOperations } from "../../hooks/use-slide-operations"; -import SlideFooter from "./SlideFooter"; - -interface Type2LayoutProps { - title: string; - body: Array<{ - heading: string; - description: string; - }>; - slideId: string | null; - - slideIndex: number; - language: string; - design_index: number; -} - -const Type2Layout = ({ - title, - body, - slideId, - slideIndex, - design_index, - language, -}: Type2LayoutProps) => { - const { currentColors } = useSelector( - (state: RootState) => state.theme - ); - const { handleAddItem, handleDeleteItem, handleVariantChange } = - useSlideOperations(slideIndex); - - const onAddItem = () => { - if (body.length < 4) { - handleAddItem({ item: { heading: "", description: "" } }); - } - }; - - const onDeleteItem = (index: number) => { - if (body.length > 2) { - handleDeleteItem({ itemIndex: index }); - } - }; - - const VariantMenu = () => ( - - - - - - handleVariantChange({ variant: 1 })} - className={`px-3 py-2 cursor-pointer ${design_index === 1 ? "bg-blue-50" : "" - }`} - > - Default Layout - - handleVariantChange({ variant: 2 })} - className={`px-3 py-2 cursor-pointer ${design_index === 2 ? "bg-blue-50" : "" - }`} - > - Numbered Layout - - handleVariantChange({ variant: 3 })} - className={`px-3 py-2 cursor-pointer ${design_index === 3 ? "bg-blue-50" : "" - }`} - > - Timeline Layout - - - - ); - - const isGridLayout = body.length >= 4; - - const renderContent = () => { - if (design_index === 3) { - return ( -
-
- - {/* Three Dots Icon */} - - - {/* Plus Icon */} - - {/* Timeline Header with Numbers and Line */} -
- {/* Horizontal Line */} -
- - {/* Timeline Numbers */} - {body.map((_, index) => ( -
- - {numberTranslations[language][index || 0]} - -
- ))} -
- - {/* Timeline Content */} -
- {body.map((item, index) => ( -
- -
- - -
-
- ))} -
-
- ); - } - if (isGridLayout) { - return ( -
- {/* Hover Border and Icons for entire layout */} -
- - {/* Three Dots Icon */} - - - {body.map((item, index) => ( -
-
- {design_index === 2 && ( -
- { - numberTranslations[ - language as keyof typeof numberTranslations - ][index] - } -
- )} - -
- - - -
-
-
- ))} -
- ); - } - - // Horizontal layout for 2-3 items - return ( -
- {/* Hover Border and Icons for entire layout */} -
- - {/* Three Dots Icon */} - - - {/* Plus Icon */} - {body.length < 4 && ( - - )} - {body.map((item, index) => ( -
- - - {design_index === 2 && ( -
- { - numberTranslations[ - language as keyof typeof numberTranslations - ][index] - } -
- )} -
- - - -
-
- ))} -
- ); - }; - - return ( -
-
- -
- - {renderContent()} - -
- ); -}; - -export default Type2Layout; diff --git a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type4Layout.tsx b/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type4Layout.tsx deleted file mode 100644 index 8fa91f26..00000000 --- a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type4Layout.tsx +++ /dev/null @@ -1,147 +0,0 @@ -import React from "react"; -import EditableText from "../EditableText"; -import ImageEditor from "../ImageEditor"; -import { useDispatch, useSelector } from "react-redux"; -import { RootState } from "@/store/store"; -import ElementMenu from "../ElementMenu"; -import { Plus } from "lucide-react"; -import { useSlideOperations } from "../../hooks/use-slide-operations"; -import SlideFooter from "./SlideFooter"; - -interface Type4LayoutProps { - title: string; - body: Array<{ - heading: string; - description: string; - }>; - slideId: string | null; - images: string[]; - slideIndex: number; - image_prompts?: string[] | null; - properties?: null | any; -} - -const Type4Layout = ({ - title, - body, - slideId, - images, - slideIndex, - image_prompts, - properties, -}: Type4LayoutProps) => { - const { currentColors } = useSelector((state: RootState) => state.theme); - const { - handleAddItem, - handleDeleteItem, - handleImageChange, - handleDeleteImage, - } = useSlideOperations(slideIndex); - - const AddItem = () => { - if (body.length < 3) { - handleImageChange({ imageUrl: "", imageIndex: slideIndex }); - handleAddItem({ - item: { heading: "Enter Heading", description: "Enter Description" }, - }); - } - }; - const DeleteItem = (index: number) => { - if (body.length > 2) { - handleDeleteItem({ itemIndex: index }); - handleDeleteImage({ imageIndex: index }); - } - }; - const getGridCols = (length: number) => { - switch (length) { - case 1: return 'lg:grid-cols-1'; - case 2: return 'lg:grid-cols-2'; - case 3: return 'lg:grid-cols-3'; - case 4: return 'lg:grid-cols-4'; - // Add more cases as needed - default: return 'lg:grid-cols-1'; - } - } - - return ( -
-
- -
- -
-
- - {body.map((item, index) => ( -
- - - -
- - -
-
- ))} -
- -
- ); -}; - -export default Type4Layout; diff --git a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type5Layout.tsx b/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type5Layout.tsx deleted file mode 100644 index 6d2b2b49..00000000 --- a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type5Layout.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import React from "react"; -import EditableText from "../EditableText"; -import { RootState } from "@/store/store"; -import { useSelector } from "react-redux"; -import AllChart from "./AllChart"; -import SlideFooter from "./SlideFooter"; - -interface Type5LayoutProps { - title: string; - description: string; - slideId: string | null; - chartComponent?: React.ReactNode; - graphData?: any; - slideIndex: number; - isFullSizeGraph?: boolean; -} - -const Type5Layout = ({ - title, - description, - slideId, - chartComponent, - graphData, - slideIndex, - isFullSizeGraph = false, -}: Type5LayoutProps) => { - const { currentColors } = useSelector((state: RootState) => state.theme); - - return ( -
- -
-
- -
-
- -
-
- -
- ); -}; - -export default Type5Layout; diff --git a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type6Layout.tsx b/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type6Layout.tsx deleted file mode 100644 index c5f6dc01..00000000 --- a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type6Layout.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import React from "react"; -import EditableText from "../EditableText"; -import { Plus } from "lucide-react"; -import ElementMenu from "../ElementMenu"; -import { useDispatch, useSelector } from "react-redux"; -import { numberTranslations } from "../../utils/others"; -import { RootState } from "@/store/store"; -import { useSlideOperations } from "../../hooks/use-slide-operations"; -import SlideFooter from "./SlideFooter"; - -interface Type6LayoutProps { - title: string; - description: string; - body: Array<{ - heading: string; - description: string; - }>; - slideId: string | null; - slideIndex: number; - language: string; -} - -const Type6Layout = ({ - title, - description, - body, - slideId, - slideIndex, - language, -}: Type6LayoutProps) => { - const dispatch = useDispatch(); - const { currentColors } = useSelector((state: RootState) => state.theme); - const { handleAddItem, handleDeleteItem } = useSlideOperations(slideIndex); - - const AddItem = () => { - if (body.length < 3) { - handleAddItem({ item: { heading: "", description: "" } }); - } - }; - const DeleteItem = (index: number) => { - if (body.length > 2) { - handleDeleteItem({ itemIndex: index }); - } - }; - return ( -
-
- {/* Left section - Description */} -
- - - -
- - {/* Right section - Numbered items */} -
-
- -
- {body.map((item, index) => ( -
- -
-
- {numberTranslations[language][index || 0]} -
-
- - -
-
-
- ))} -
-
-
- -
- ); -}; - -export default Type6Layout; diff --git a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type7Layout.tsx b/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type7Layout.tsx deleted file mode 100644 index f1831be6..00000000 --- a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type7Layout.tsx +++ /dev/null @@ -1,209 +0,0 @@ -import React from "react"; -import EditableText from "../EditableText"; -import IconsEditor from "../IconsEditor"; -import { Plus } from "lucide-react"; -import ElementMenu from "../ElementMenu"; -import { useSelector } from "react-redux"; -import { RootState } from "@/store/store"; -import { useSlideOperations } from "../../hooks/use-slide-operations"; -import SlideFooter from "./SlideFooter"; - -interface Type2LayoutProps { - title: string; - body: Array<{ - heading: string; - description: string; - }>; - icons: string[]; - slideIndex: number; - slideId: string | null; - icon_queries?: Array<{ queries: string[] }> | null; -} - -const Type7Layout = ({ - title, - body, - icons, - slideIndex, - slideId, - icon_queries, -}: Type2LayoutProps) => { - const { currentColors } = useSelector((state: RootState) => state.theme); - const { handleAddItem, handleDeleteItem } = useSlideOperations(slideIndex); - - const AddItem = () => { - if (body.length < 4) { - handleAddItem({ item: { heading: "", description: "" } }); - } - }; - const DeleteItem = (index: number) => { - if (body.length > 2) { - handleDeleteItem({ itemIndex: index }); - } - }; - const getGridCols = (length: number) => { - switch (length) { - case 1: return 'lg:grid-cols-1'; - case 2: return 'lg:grid-cols-2'; - case 3: return 'lg:grid-cols-3'; - case 4: return 'lg:grid-cols-4'; - case 5: return 'lg:grid-cols-5'; - case 6: return 'lg:grid-cols-6'; - case 7: return 'lg:grid-cols-7'; - // Add more cases as needed - default: return 'lg:grid-cols-1'; - } - } - - const isGridLayout = body.length >= 4; - - const renderContent = () => { - if (isGridLayout) { - return ( -
4 ? 'md:grid-cols-3' : 'md:grid-cols-2'} gap-4 sm:gap-6 lg:gap-8 mt-4 lg:mt-12 w-full relative group`} - > -
- - - {body.map((item, index) => ( -
- -
-
- -
-
- - -
-
-
- ))} -
- ); - } - - - // Horizontal layout for 2-3 items - return ( -
-
- - - - {body.map((item, index) => ( -
- - -
- - -
-
- ))} -
- ); - }; - - return ( -
-
- -
- {renderContent()} - -
- ); -}; - -export default Type7Layout; diff --git a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type8Layout.tsx b/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type8Layout.tsx deleted file mode 100644 index b1af87b3..00000000 --- a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type8Layout.tsx +++ /dev/null @@ -1,185 +0,0 @@ -import React from "react"; -import EditableText from "../EditableText"; -import IconsEditor from "../IconsEditor"; -import { Plus } from "lucide-react"; -import ElementMenu from "../ElementMenu"; -import { useSelector } from "react-redux"; -import { RootState } from "@/store/store"; -import { useSlideOperations } from "../../hooks/use-slide-operations"; -import SlideFooter from "./SlideFooter"; - -interface Type6LayoutProps { - title: string; - description: string; - body: Array<{ - heading: string; - description: string; - }>; - icons: string[]; - slideId: string | null; - slideIndex: number; - icon_queries?: Array<{ queries: string[] }> | null; -} - -const Type8Layout = ({ - title, - description, - body, - icons, - slideIndex, - slideId, - icon_queries, -}: Type6LayoutProps) => { - const { currentColors } = useSelector((state: RootState) => state.theme); - const { handleAddItem, handleDeleteItem } = useSlideOperations(slideIndex); - - const AddItem = () => { - if (body.length < 3) { - handleAddItem({ item: { heading: "", description: "" } }); - } - }; - const DeleteItem = (index: number) => { - if (body.length > 2) { - handleDeleteItem({ itemIndex: index }); - } - }; - - return ( -
-
- {/* Left section - Description */} -
- - - -
- - {/* Right section - Numbered items */} -
-
- - - -
- {body && body.length > 0 && body.length === 2 - ? body.map((item, index) => ( -
- - - -
- - -
-
- )) - : body.map((item, index) => ( -
- -
-
- -
-
- - -
-
-
- ))} -
-
-
- -
- ); -}; - -export default Type8Layout; diff --git a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type9Layout.tsx b/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type9Layout.tsx deleted file mode 100644 index b42706ef..00000000 --- a/servers/nextjs/app/(presentation-generator)/components/slide_layouts/Type9Layout.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import React from "react"; -import EditableText from "../EditableText"; -import { Plus } from "lucide-react"; -import ElementMenu from "../ElementMenu"; -import { useSelector } from "react-redux"; -import { numberTranslations } from "../../utils/others"; -import { RootState } from "@/store/store"; -import AllChart from "./AllChart"; -import { useSlideOperations } from "../../hooks/use-slide-operations"; -import SlideFooter from "./SlideFooter"; - -interface Type9LayoutProps { - title: string; - body: Array<{ - heading: string; - description: string; - }>; - graphData?: any; - slideId: string | null; - language: string; - slideIndex: number; -} - -const Type9Layout = ({ - title, - body, - graphData, - slideId, - slideIndex, - language, -}: Type9LayoutProps) => { - const { currentColors } = useSelector((state: RootState) => state.theme); - const { handleAddItem, handleDeleteItem } = useSlideOperations(slideIndex); - const AddItem = () => { - if (body.length < 3) { - handleAddItem({ item: { heading: "", description: "" } }); - } - }; - const DeleteItem = (index: number) => { - if (body.length > 2) { - handleDeleteItem({ itemIndex: index }); - } - }; - return ( -
-
- {/* Left section - Chart */} -
- -
-
- -
-
-
- - {/* Right section - Numbered items */} - -
-
- -
- {body.length > 0 && - body.map((item, index) => ( -
- -
-
- {numberTranslations[language][index || 0]} -
- -
- - -
-
-
- ))} -
-
-
- -
- ); -}; - -export default Type9Layout; diff --git a/servers/nextjs/app/(presentation-generator)/documents-preview/components/DocumentPreviewPage.tsx b/servers/nextjs/app/(presentation-generator)/documents-preview/components/DocumentPreviewPage.tsx index 0480be69..8357ea4f 100644 --- a/servers/nextjs/app/(presentation-generator)/documents-preview/components/DocumentPreviewPage.tsx +++ b/servers/nextjs/app/(presentation-generator)/documents-preview/components/DocumentPreviewPage.tsx @@ -13,7 +13,6 @@ "use client"; -import styles from "../styles/main.module.css"; import { useEffect, useState, useRef, useMemo } from "react"; import { Skeleton } from "@/components/ui/skeleton"; import { OverlayLoader } from "@/components/ui/overlay-loader"; @@ -29,7 +28,6 @@ import { getIconFromFile } from "../../utils/others"; import { ChevronRight, PanelRightOpen, X } from "lucide-react"; import ToolTip from "@/components/ToolTip"; import Header from "@/app/dashboard/components/Header"; -import { useLayout } from "../../context/LayoutContext"; // Types interface LoadingState { @@ -214,7 +212,7 @@ const DocumentsPreviewPage: React.FC = () => { if (!isOpen) return null; return ( -
setIsOpen(false)} @@ -230,7 +228,7 @@ const DocumentsPreviewPage: React.FC = () => {
updateSelectedDocument(key)} - className={`${selectedDocument === key ? styles.selected_border : "" + className={`${selectedDocument === key ? 'border border-blue-500' : "" } flex p-2 rounded-sm gap-2 items-center cursor-pointer`} > { }; return ( -
+
{ - const dispatch = useDispatch(); - - const handleAddItem = ({ item }: { item: any }) => { - dispatch(addSlideBodyItem({ index: slideIndex, item })); - }; - - const handleDeleteItem = ({ itemIndex }: { itemIndex: number }) => { - dispatch(deleteSlideBodyItem({ index: slideIndex, itemIdx: itemIndex })); - }; - - const handleVariantChange = ({ variant }: { variant: number }) => { - dispatch(updateSlideVariant({ index: slideIndex, variant })); - }; - - const handleImageChange = ({ - imageUrl, - imageIndex, - }: { - imageUrl: string; - imageIndex: number; - }) => { - dispatch( - updateSlideImage({ - index: slideIndex, - imageIdx: imageIndex, - image: imageUrl, - }) - ); - }; - const handleDeleteImage = ({ imageIndex }: { imageIndex: number }) => { - dispatch(deleteSlideImage({ index: slideIndex, imageIdx: imageIndex })); - }; - - // Add other common slide operations here - - return { - handleAddItem, - handleDeleteItem, - handleVariantChange, - handleImageChange, - handleDeleteImage, - }; -}; diff --git a/servers/nextjs/app/(presentation-generator)/presentation/components/Header.tsx b/servers/nextjs/app/(presentation-generator)/presentation/components/Header.tsx index 2518f450..64d3a9b7 100644 --- a/servers/nextjs/app/(presentation-generator)/presentation/components/Header.tsx +++ b/servers/nextjs/app/(presentation-generator)/presentation/components/Header.tsx @@ -1,12 +1,9 @@ "use client"; import { Button } from "@/components/ui/button"; import { - Menu, - Palette, SquareArrowOutUpRight, Play, Loader2, - ExternalLink, } from "lucide-react"; import React, { useState } from "react"; import Wrapper from "@/components/Wrapper"; @@ -16,38 +13,21 @@ import { PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; -import UserAccount from "../../components/UserAccount"; import { PresentationGenerationApi } from "../../services/api/presentation-generation"; import { OverlayLoader } from "@/components/ui/overlay-loader"; -import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"; import { useDispatch, useSelector } from "react-redux"; import Link from "next/link"; -import { ThemeType } from "@/app/(presentation-generator)/upload/type"; -import { - setTheme, - setThemeColors, - defaultColors, - serverColors, -} from "../../store/themeSlice"; -import CustomThemeSettings from "../../components/CustomThemeSettings"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; import { RootState } from "@/store/store"; import { toast } from "@/hooks/use-toast"; -import ThemeSelector from "./ThemeSelector"; import Modal from "./Modal"; import Announcement from "@/components/Announcement"; -import { getFontLink, getStaticFileUrl } from "../../utils/others"; +import { getStaticFileUrl } from "../../utils/others"; import { PptxPresentationModel } from "@/types/pptx_models"; +import HeaderNav from "../../components/HeaderNab"; const Header = ({ @@ -61,66 +41,13 @@ const Header = ({ const [showLoader, setShowLoader] = useState(false); const router = useRouter(); - const [showCustomThemeModal, setShowCustomThemeModal] = useState(false); const [showDownloadModal, setShowDownloadModal] = useState(false); const [downloadPath, setDownloadPath] = useState(""); - const { currentTheme, currentColors } = useSelector( - (state: RootState) => state.theme - ); + const { presentationData, isStreaming } = useSelector( (state: RootState) => state.presentationGeneration ); const dispatch = useDispatch(); - const handleThemeSelect = async (value: string) => { - if (isStreaming) return; - if (value === "custom") { - setShowCustomThemeModal(true); - return; - } else { - const themeType = value as ThemeType; - const themeColors = serverColors[themeType] || defaultColors[themeType]; - - if (themeColors) { - try { - // Update UI - dispatch(setTheme(themeType)); - dispatch(setThemeColors({ ...themeColors, theme: themeType })); - // Set CSS variables - const root = document.documentElement; - root.style.setProperty( - `--${themeType}-slide-bg`, - themeColors.slideBg - ); - root.style.setProperty( - `--${themeType}-slide-title`, - themeColors.slideTitle - ); - root.style.setProperty( - `--${themeType}-slide-heading`, - themeColors.slideHeading - ); - root.style.setProperty( - `--${themeType}-slide-description`, - themeColors.slideDescription - ); - root.style.setProperty( - `--${themeType}-slide-box`, - themeColors.slideBox - ); - - - } catch (error) { - console.error("Failed to update theme:", error); - toast({ - title: "Error updating theme", - description: - "Failed to update the presentation theme. Please try again.", - variant: "destructive", - }); - } - } - } - }; const get_presentation_pptx_model = async (id: string): Promise => { const response = await fetch(`/api/presentation_to_pptx_model?id=${id}`); @@ -212,15 +139,8 @@ const Header = ({ pptx export Export as PPTX - {/*
- -
*/} -

- Font Used: - - {getFontLink(currentColors.fontFamily).name || ''} - -

+ +
); @@ -282,68 +202,16 @@ const Header = ({ {isStreaming && ( )} - - {/* Custom Theme Modal */} - setShowCustomThemeModal(false)} - title="Custom Theme Colors" - > - setShowCustomThemeModal(false)} - presentationId={presentation_id} - /> - + + - +
{/* Mobile Menu */}
- - - - - - -
- - -
-
-
+ +
{/* Download Modal */} diff --git a/servers/nextjs/app/(presentation-generator)/components/LoadingState.tsx b/servers/nextjs/app/(presentation-generator)/presentation/components/LoadingState.tsx similarity index 100% rename from servers/nextjs/app/(presentation-generator)/components/LoadingState.tsx rename to servers/nextjs/app/(presentation-generator)/presentation/components/LoadingState.tsx diff --git a/servers/nextjs/app/(presentation-generator)/presentation/components/PresentationPage.tsx b/servers/nextjs/app/(presentation-generator)/presentation/components/PresentationPage.tsx index f5d5ec36..dfff071b 100644 --- a/servers/nextjs/app/(presentation-generator)/presentation/components/PresentationPage.tsx +++ b/servers/nextjs/app/(presentation-generator)/presentation/components/PresentationPage.tsx @@ -6,7 +6,6 @@ import { Skeleton } from "@/components/ui/skeleton"; import PresentationMode from "../../components/PresentationMode"; import SidePanel from "../components/SidePanel"; import SlideContent from "../components/SlideContent"; -import LoadingState from "../../components/LoadingState"; import Header from "../components/Header"; import { Button } from "@/components/ui/button"; import { AlertCircle, Loader2 } from "lucide-react"; @@ -18,6 +17,7 @@ import { useAutoSave } from "../hooks"; import { PresentationPageProps } from "../types"; +import LoadingState from "./LoadingState"; const PresentationPage: React.FC = ({ presentation_id }) => { // State management @@ -27,10 +27,7 @@ const PresentationPage: React.FC = ({ presentation_id }) const [error, setError] = useState(false); const [isMobilePanelOpen, setIsMobilePanelOpen] = useState(false); - // Redux state - const { currentTheme, currentColors } = useSelector( - (state: RootState) => state.theme - ); + const { presentationData, isStreaming } = useSelector( (state: RootState) => state.presentationGeneration ); @@ -84,7 +81,7 @@ const PresentationPage: React.FC = ({ presentation_id }) = ({ presentation_id })
diff --git a/servers/nextjs/app/(presentation-generator)/presentation/components/SidePanel.tsx b/servers/nextjs/app/(presentation-generator)/presentation/components/SidePanel.tsx index 16c57120..f14364ab 100644 --- a/servers/nextjs/app/(presentation-generator)/presentation/components/SidePanel.tsx +++ b/servers/nextjs/app/(presentation-generator)/presentation/components/SidePanel.tsx @@ -45,9 +45,7 @@ const SidePanel = ({ const { presentationData, isStreaming } = useSelector( (state: RootState) => state.presentationGeneration ); - const { currentTheme, currentColors } = useSelector( - (state: RootState) => state.theme - ); + const dispatch = useDispatch(); // Use the centralized group layouts hook @@ -159,16 +157,10 @@ const SidePanel = ({ `} >
diff --git a/servers/nextjs/app/(presentation-generator)/presentation/components/SlideContent.tsx b/servers/nextjs/app/(presentation-generator)/presentation/components/SlideContent.tsx index 9fdb7dec..a260734a 100644 --- a/servers/nextjs/app/(presentation-generator)/presentation/components/SlideContent.tsx +++ b/servers/nextjs/app/(presentation-generator)/presentation/components/SlideContent.tsx @@ -14,8 +14,8 @@ import ToolTip from "@/components/ToolTip"; import { RootState } from "@/store/store"; import { useDispatch, useSelector } from "react-redux"; import { deletePresentationSlide, updateSlide } from "@/store/slices/presentationGeneration"; -import NewSlide from "../../components/slide_layouts/NewSlide"; import { useGroupLayouts } from "../../hooks/useGroupLayouts"; +import NewSlide from "../../components/NewSlide"; interface SlideContentProps { slide: any; diff --git a/servers/nextjs/app/(presentation-generator)/presentation/components/ThemeSelector.tsx b/servers/nextjs/app/(presentation-generator)/presentation/components/ThemeSelector.tsx deleted file mode 100644 index fcbdb4f3..00000000 --- a/servers/nextjs/app/(presentation-generator)/presentation/components/ThemeSelector.tsx +++ /dev/null @@ -1,155 +0,0 @@ -import React from "react"; - -const ThemeSelector = ({ - onSelect, - selectedTheme, -}: { - onSelect: (theme: string) => void; - selectedTheme: string; -}) => { - return ( -
- - - - - - - - - -
- ); -}; - -export default ThemeSelector; - -const ThemePreview = ({ - theme, - color, - isSelected, -}: { - theme: string; - color: string; - isSelected: boolean; -}) => ( -
-
-
-
-
-
-
-
- - {theme} - -
-); diff --git a/servers/nextjs/app/(presentation-generator)/store/themeSlice.ts b/servers/nextjs/app/(presentation-generator)/store/themeSlice.ts deleted file mode 100644 index d848cf05..00000000 --- a/servers/nextjs/app/(presentation-generator)/store/themeSlice.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { ThemeType } from "@/app/(presentation-generator)/upload/type"; -import { createSlice, PayloadAction } from "@reduxjs/toolkit"; - -export const defaultColors = { - light: { - background: "#c8c7c9", - slideBg: "#F2F2F2", - slideTitle: "#000000", - slideHeading: "#1a1a1a", - slideDescription: "#333333", - slideBox: "#ffffff", - iconBg: "#1F1F2D", - chartColors: ["#1F1F2D", "#3F3F5D", "#62628E", "#8F8FB2", "#C0C0D3"], - fontFamily: "var(--font-inter)", - }, - dark: { - background: "#000000", - slideBg: "#1E1E1E", - slideTitle: "#ffffff", - slideHeading: "#f5f5f5", - slideDescription: "#e0e0e0", - slideBox: "#2d2d2d", - iconBg: "#5E8CF0", - chartColors: ["#5E8CF0", "#8800ff", "#b200ff", "#d700ff", "#ef00ff"], - fontFamily: "var(--font-inter)", - }, - faint_yellow: { - background: "#d9cebc", - slideBg: "#F8F4E8", - slideTitle: "#2C1810", - slideHeading: "#4A3728", - slideDescription: "#665E57", - slideBox: "#FFFFFF", - iconBg: "#281810", - chartColors: ["#281810", "#4A3728", "#665E57", "#665E57", "#665E57"], - fontFamily: "var(--font-inter)", - }, - custom: { - background: "#63ceff", - slideBg: "#F4F4F4", - slideTitle: "#1A1A1A", - slideHeading: "#2D2D2D", - slideDescription: "#4A4A4A", - slideBox: "#d8c6c6", - iconBg: "#281810", - chartColors: ["#281810", "#4A3728", "#665E57", "#665E57", "#665E57"], - fontFamily: "var(--font-inter)", - }, - cream: { - background: "#DDCFBB", - slideBg: "#F9F6F0", - slideTitle: "#484237", - slideHeading: "#484237", - slideDescription: "#595F6C", - slideBox: "#EEE9DD", - iconBg: "#A6825B", - chartColors: ["#765939", "#A6825B", "#B89B7C", "#CAB49D", "#DBCDBD"], - fontFamily: "var(--font-fraunces)", - }, - royal_blue: { - background: "#010103", - slideBg: "#091433", - slideTitle: "#ffffff", - slideHeading: "#ffffff", - slideDescription: "#E6E6E6", - slideBox: "#29136C", - iconBg: "#5E8CF0", - chartColors: ["#5E8CF0", "#496CEB", "#f051b5", "#F7A8FF", "#FCD8FF"], - fontFamily: "var(--font-instrument-sans)", - }, - light_red: { - background: "#F8E9E8", - slideBg: "#FFFAFA", - slideTitle: "#181D27", - slideHeading: "#252B37", - slideDescription: "#595F6C", - slideBox: "#F3E8E8", - iconBg: "#F0695F", - chartColors: [ - "#F0695F", - "#450808", - "#8F1010", - "#C1392F", - "#EC5555", - "#F49E9E", - ], - fontFamily: "var(--font-montserrat)", - }, - dark_pink: { - background: "#F3AEED", - slideBg: "#F9E8FF", - slideTitle: "#261827", - slideHeading: "#252B37", - slideDescription: "#6A596C", - slideBox: "#F0D4F7", - iconBg: "#D02CE5", - chartColors: ["#D02CE5", "#B414C9", "#6E1886", "#A724CC", "#C65FE3"], - fontFamily: "var(--font-inria-serif)", - }, -}; - -// Store the server-provided colors -export const serverColors: { [key in ThemeType]?: ThemeColors } = {}; - -export interface ThemeColors { - background: string; - slideBg: string; - slideTitle: string; - slideHeading: string; - slideDescription: string; - slideBox: string; - iconBg: string; - chartColors: string[]; - fontFamily: string; -} - -interface ThemeState { - currentTheme: ThemeType; - currentColors: ThemeColors; - isLoading: boolean; -} - -const initialState: ThemeState = { - currentTheme: ThemeType.Light, - currentColors: defaultColors.light, - isLoading: false, -}; - -const themeSlice = createSlice({ - name: "theme", - initialState, - reducers: { - setTheme: (state, action: PayloadAction) => { - state.currentTheme = action.payload; - // Use server colors if available, otherwise fall back to default - state.currentColors = - serverColors[action.payload] || defaultColors[action.payload]; - }, - setThemeColors: ( - state, - action: PayloadAction & { theme: ThemeType }> - ) => { - const newColors = { ...state.currentColors, ...action.payload }; - state.currentColors = newColors; - state.currentTheme = action.payload.theme; - // Store the colors for this theme - serverColors[action.payload.theme] = newColors; - }, - setLoadingState: (state, action: PayloadAction) => { - state.isLoading = action.payload; - }, - loadSavedTheme: (state, action: PayloadAction) => { - if (action.payload.name === "custom") { - state.currentTheme = ThemeType.Custom; - state.currentColors = action.payload.colors; - serverColors.custom = action.payload.colors; - } - }, - }, -}); - -export const { setTheme, setThemeColors, setLoadingState, loadSavedTheme } = - themeSlice.actions; -export default themeSlice.reducer; diff --git a/servers/nextjs/app/(presentation-generator)/styles/themes.css b/servers/nextjs/app/(presentation-generator)/styles/themes.css deleted file mode 100644 index 0063ee06..00000000 --- a/servers/nextjs/app/(presentation-generator)/styles/themes.css +++ /dev/null @@ -1,148 +0,0 @@ -/* Light Theme */ -.slide-theme[data-theme="light"] { - --slide-bg: var(--light-slide-bg); - --slide-title: var(--light-slide-title); - --slide-heading: var(--light-slide-heading); - --slide-description: var(--light-slide-description); - --slide-box: var(--light-slide-box); -} - -/* Dark Theme */ -.slide-theme[data-theme="dark"] { - --slide-bg: var(--dark-slide-bg); - --slide-title: var(--dark-slide-title); - --slide-heading: var(--dark-slide-heading); - --slide-description: var(--dark-slide-description); - --slide-box: var(--dark-slide-box); -} - -/* Classic Theme */ -.slide-theme[data-theme="faint_yellow"] { - --slide-bg: var(--faint_yellow-slide-bg); - --slide-title: var(--faint_yellow-slide-title); - --slide-heading: var(--faint_yellow-slide-heading); - --slide-description: var(--faint_yellow-slide-description); - --slide-box: var(--faint_yellow-slide-box); -} - -/* Custom Theme */ -.slide-theme[data-theme="custom"] { - --slide-bg: var(--custom-slide-bg); - --slide-title: var(--custom-slide-title); - --slide-heading: var(--custom-slide-heading); - --slide-description: var(--custom-slide-description); - --slide-box: var(--custom-slide-box); -} - -/* Royal Blue Theme */ -.slide-theme[data-theme="royal_blue"] { - --slide-bg: var(--royal_blue-slide-bg); - --slide-title: var(--royal_blue-slide-title); - --slide-heading: var(--royal_blue-slide-heading); - --slide-description: var(--royal_blue-slide-description); - --slide-box: var(--royal_blue-slide-box); -} - -/* Light Red Theme */ -.slide-theme[data-theme="light_red"] { - --slide-bg: var(--light_red-slide-bg); - --slide-title: var(--light_red-slide-title); - --slide-heading: var(--light_red-slide-heading); - --slide-description: var(--light_red-slide-description); - --slide-box: var(--light_red-slide-box); -} - -/* Dark Pink Theme */ -.slide-theme[data-theme="dark_pink"] { - --slide-bg: var(--dark_pink-slide-bg); - --slide-title: var(--dark_pink-slide-title); - --slide-heading: var(--dark_pink-slide-heading); - --slide-description: var(--dark_pink-slide-description); - --slide-box: var(--dark_pink-slide-box); -} - -/* Cream Theme */ -.slide-theme[data-theme="cream"] { - --slide-bg: var(--cream-slide-bg); - --slide-title: var(--cream-slide-title); - --slide-heading: var(--cream-slide-heading); - --slide-description: var(--cream-slide-description); - --slide-box: var(--cream-slide-box); -} - - -/* Apply theme styles - Make sure these selectors are more specific */ -.slide-theme .slide-container { - background-color: var(--slide-bg); - -} - - -.slide-theme .slide-title { - color: var(--slide-title); -} - -.slide-theme .slide-heading { - color: var(--slide-heading); -} - -.slide-theme .slide-description { - color: var(--slide-description); -} - -.slide-theme .slide-box { - background-color: var(--slide-box); -} - -/* Add to your existing CSS */ -.slide-theme { - transition: background-color 0.3s ease, color 0.3s ease; -} - -.slide-theme .border-color{ - border-color: var(--slide-box); -} - - -@keyframes progress { - 0% { width: 5%; } - 20% { width: 25%; } - 50% { width: 45%; } - 75% { width: 75%; } - 90% { width: 85%; } - 100% { width: 90%; } -} - -@keyframes fade-in { - 0% { opacity: 0; transform: translateY(10px); } - 100% { opacity: 1; transform: translateY(0); } -} - -.animate-progress { - animation: progress 20s ease-out forwards; -} - -.animate-fade-in { - animation: fade-in 0.5s ease-out forwards; -} - -@keyframes border-dance { - 0% { - background-position: 0 0, 100% 0, 100% 100%, 0 100%; - } - 100% { - background-position: 100% 0, 100% 100%, 0 100%, 0 0; - } -} - -.animate-border { - background-image: - linear-gradient(90deg, #5141e5 50%, transparent 50%), /* top */ - linear-gradient(90deg, #5141e5 50%, transparent 50%), /* right */ - linear-gradient(90deg, #5141e5 50%, transparent 50%), /* bottom */ - linear-gradient(90deg, #5141e5 50%, transparent 50%); /* left */ - background-repeat: repeat-x, repeat-y, repeat-x, repeat-y; - background-size: 15px 2px, 2px 15px, 15px 2px, 2px 15px; - background-position: 0 0, 100% 0, 100% 100%, 0 100%; - animation: border-dance 6s infinite linear; -} \ No newline at end of file diff --git a/servers/nextjs/app/(presentation-generator)/theme/ThemePage.tsx b/servers/nextjs/app/(presentation-generator)/theme/ThemePage.tsx deleted file mode 100644 index fb03d405..00000000 --- a/servers/nextjs/app/(presentation-generator)/theme/ThemePage.tsx +++ /dev/null @@ -1,184 +0,0 @@ -"use client"; -import React, { useEffect, useState } from "react"; -import { Card } from "@/components/ui/card"; -import { defaultColors, setTheme, ThemeColors } from "../store/themeSlice"; -import Header from "@/app/dashboard/components/Header"; -import Wrapper from "@/components/Wrapper"; -import { useDispatch } from "react-redux"; -import { useRouter } from "next/navigation"; -import { ThemeType } from "../upload/type"; -import { Button } from "@/components/ui/button"; - -import { toast } from "@/hooks/use-toast"; - -interface ThemeCardProps { - name: string; - font: string; - colors: ThemeColors; - selected: boolean; - onClick: () => void; -} - -const ThemeCard = ({ - name, - font, - colors, - selected, - onClick, -}: ThemeCardProps) => { - return ( -
- -
-
-
-

- {name} -

-

- This is the body paragraph -

-
-
-
-
-
- ); -}; - -const ThemePage = () => { - const themes = [ - { - name: "Dark Theme", - colors: defaultColors.dark, - type: "dark", - font: "var(--font-inter)", - }, - - { - name: "Royal Blue Theme", - colors: defaultColors.royal_blue, - type: "royal_blue", - font: "var(--font-instrument-sans)", - }, - { - name: "Creme Theme", - colors: defaultColors.cream, - type: "cream", - font: "var(--font-fraunces)", - }, - { - name: "Light Red Theme", - colors: defaultColors.light_red, - type: "light_red", - font: "var(--font-montserrat)", - }, - { - name: "Dark Pink Theme", - colors: defaultColors.dark_pink, - type: "dark_pink", - font: "var(--font-inria-serif)", - }, - { - name: "Light Theme", - colors: defaultColors.light, - type: "light", - font: "var(--font-inter)", - }, - - { - name: "Faint Yellow Theme", - colors: defaultColors.faint_yellow, - type: "faint_yellow", - font: "var(--font-inter)", - }, - ]; - const dispatch = useDispatch(); - const router = useRouter(); - const [selectedTheme, setSelectedTheme] = useState(null); - const handleThemeClick = async (theme: ThemeColors, type: string) => { - setSelectedTheme(type as ThemeType); - }; - const handleSubmit = () => { - if (!selectedTheme) { - toast({ - title: "Please select a theme", - variant: "destructive", - }); - return; - } - dispatch(setTheme(selectedTheme as ThemeType)); - - router.push("/outline"); - }; - - return ( -
-
- -

Select a Theme

-
- {themes.map((theme, index) => ( - handleThemeClick(theme.colors, theme.type)} - /> - ))} -
- -
-
- ); -}; - -export default ThemePage; diff --git a/servers/nextjs/app/(presentation-generator)/theme/loading.tsx b/servers/nextjs/app/(presentation-generator)/theme/loading.tsx deleted file mode 100644 index 3a4314c1..00000000 --- a/servers/nextjs/app/(presentation-generator)/theme/loading.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { Skeleton } from '@/components/ui/skeleton' -import React from 'react' - -const loading = () => { - return ( -
- -
- - -
- { - Array.from({ length: 6 }).map((_, index) => ( - - )) - } -
-
-
- - ) -} - -export default loading \ No newline at end of file diff --git a/servers/nextjs/app/(presentation-generator)/theme/page.tsx b/servers/nextjs/app/(presentation-generator)/theme/page.tsx deleted file mode 100644 index 0437a922..00000000 --- a/servers/nextjs/app/(presentation-generator)/theme/page.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react' -import ThemePage from './ThemePage' -import { Metadata } from 'next' - -export const metadata: Metadata = { - title: "Theme Selection | Presenton.ai", - description: "Select a Presenton theme which will be suitable for your presentation", -} - -const page = () => { - return ( - - ) -} - -export default page diff --git a/servers/nextjs/app/(presentation-generator)/utils/NewSlideContent.ts b/servers/nextjs/app/(presentation-generator)/utils/NewSlideContent.ts deleted file mode 100644 index 115dcd71..00000000 --- a/servers/nextjs/app/(presentation-generator)/utils/NewSlideContent.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { randomChartGenerator } from "@/lib/utils"; -import { Slide } from "../types/slide"; -import { generateRandomId } from "./others"; - -const randomGraph = (presentation_id: string) => { - const randomData = randomChartGenerator(); - - return { - id: generateRandomId(), - name: "Sales Performance", - type: "bar", - presentation: presentation_id, - postfix: "", - data: randomData, - }; -}; - -export const getEmptySlideContent = ( - type: number, - index: number, - presentation_id: string -): Slide => { - const baseSlide: Slide = { - id: generateRandomId(), - type, - index, - design_index: 1, - properties: null, - images: [], - icons: [], - graph_id: null, - presentation: presentation_id, - content: { - title: "", - body: "", - infographics: [], - }, - }; - const graph = randomGraph(presentation_id); - - switch (type) { - case 1: - return { - ...baseSlide, - images: [""], - content: { - title: "New Title", - body: "Add your description here", - image_prompts: [""], - }, - }; - case 2: - return { - ...baseSlide, - content: { - title: "New Title", - body: [ - { heading: "First Point", description: "Add description" }, - { heading: "Second Point", description: "Add description" }, - ], - }, - }; - case 4: - return { - ...baseSlide, - images: ["", "", ""], - content: { - title: "New Title", - body: [ - { heading: "First Item", description: "Add description" }, - { heading: "Second Item", description: "Add description" }, - { heading: "Third Item", description: "Add description" }, - ], - image_prompts: ["", "", ""], - }, - }; - case 5: - return { - ...baseSlide, - graph_id: graph.id, - content: { - graph: graph, - title: "New Title", - body: "Add your description here", - }, - }; - case 6: - return { - ...baseSlide, - content: { - title: "New Title", - description: "Add your description here", - body: [ - { heading: "First Point", description: "Add description" }, - { heading: "Second Point", description: "Add description" }, - ], - }, - }; - case 7: - return { - ...baseSlide, - icons: ["", "", ""], - content: { - title: "New Title", - body: [ - { heading: "First Point", description: "Add description" }, - { heading: "Second Point", description: "Add description" }, - ], - icon_queries: [ - { - queries: [""], - }, - ], - }, - }; - case 8: - return { - ...baseSlide, - icons: ["", "", ""], - content: { - title: "New Title", - description: "Add your description here", - body: [ - { heading: "First Point", description: "Add description" }, - { heading: "Second Point", description: "Add description" }, - ], - icon_queries: [ - { - queries: [""], - }, - ], - }, - }; - case 9: - return { - ...baseSlide, - graph_id: graph.id, - content: { - graph: graph, - title: "New Subheading", - body: [ - { heading: "First Point", description: "Add description" }, - { heading: "Second Point", description: "Add description" }, - ], - }, - }; - - default: - return baseSlide; - } -}; diff --git a/servers/nextjs/app/(presentation-generator)/utils/chart.tsx b/servers/nextjs/app/(presentation-generator)/utils/chart.tsx deleted file mode 100644 index daced823..00000000 --- a/servers/nextjs/app/(presentation-generator)/utils/chart.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { formatLargeNumber } from "@/lib/utils"; -import { Chart } from "@/store/slices/presentationGeneration"; - -export const formatTooltipValue = (localChartData: Chart, value: number) => { - const formattedValue = formatLargeNumber(value); - if (localChartData.postfix) { - return `${formattedValue}${localChartData.postfix}`; - } - return formattedValue; -}; -export const transformedData = (localChartData: Chart) => { - if (!localChartData) return []; - if (!localChartData.data || localChartData.data.categories.length === 0) - return []; - if (localChartData && localChartData.type === "pie") { - return localChartData.data.categories.map((category, index) => ({ - name: category, - value: localChartData.data.series[0].data[index], - actualValue: localChartData.data.series[0].data[index], - seriesName: localChartData.data.series[0].name || "Series 1", - })); - } else { - return localChartData.data.categories.map((category, index) => { - const dataPoint: any = { name: category }; - localChartData.data.series.forEach((serie) => { - const seriesName = serie.name || "Series"; - dataPoint[seriesName] = serie.data[index]; - dataPoint[`${seriesName}Value`] = serie.data[index]; - }); - return dataPoint; - }); - } -}; - -export const formatYAxisTick = (value: number) => { - if (value >= 1_000_000_000_000) { - return `${(value / 1_000_000_000_000).toFixed(0)}T`; - } else if (value >= 1_000_000_000) { - return `${(value / 1_000_000_000).toFixed(0)}B`; - } else if (value >= 1_000_000) { - return `${(value / 1_000_000).toFixed(0)}M`; - } else if (value >= 1_000) { - return `${(value / 1_000).toFixed(0)}k`; - } - return value.toString(); -}; diff --git a/servers/nextjs/app/(presentation-generator)/utils/chartDataTransforms.ts b/servers/nextjs/app/(presentation-generator)/utils/chartDataTransforms.ts deleted file mode 100644 index fb07825f..00000000 --- a/servers/nextjs/app/(presentation-generator)/utils/chartDataTransforms.ts +++ /dev/null @@ -1,18 +0,0 @@ -// Store Chart Data Type -export interface StoreChartData { - id: string; - name: string; - type: 'bar' | 'line' | 'pie'; - style: { - - }; - presentation: string; - postfix: string; - data: { - categories: string[]; - series: Array<{ - name?: string; - data: number[]; - }>; - }; -} diff --git a/servers/nextjs/app/(presentation-generator)/utils/layoutsExtractor.ts b/servers/nextjs/app/(presentation-generator)/utils/layoutsExtractor.ts deleted file mode 100644 index c76facc4..00000000 --- a/servers/nextjs/app/(presentation-generator)/utils/layoutsExtractor.ts +++ /dev/null @@ -1,285 +0,0 @@ -import * as z from 'zod'; -import fs from 'fs'; -import * as path from 'path'; - -interface LayoutInfo { - id: string; - name: string; - description: string; - json_schema: Record; - group: string; -} - -interface LayoutGroup { - id: string; - ordered: boolean; - slides: string[]; -} - -interface LayoutStructure { - name: string; - ordered: boolean; - slides: LayoutInfo[]; -} - -interface GroupedLayoutsResponse { - group: string; - files: string[]; -} - -// Cache for layouts to avoid repeated file system operations -let layoutsCache: LayoutStructure[] | null = null; - -/** - * Dynamically imports a layout file and extracts its schema and metadata - */ -async function extractLayoutFromFile(filePath: string, fileName: string, groupName: string): Promise { - try { - // Import the layout module dynamically - const module = await import(filePath); - - // Check if the module has a Schema export - if (!module.Schema) { - console.warn(`No Schema export found in ${fileName}`); - return null; - } - - // Extract layout metadata (optional) - const layoutId = module.layoutId || fileName.replace(/\.tsx?$/, '').toLowerCase().replace(/layout$/, ''); - const layoutName = module.layoutName || fileName.replace(/\.tsx?$/, '').replace(/([A-Z])/g, ' $1').trim(); - const layoutDescription = module.layoutDescription || `${layoutName} layout for presentations`; - - // Convert Zod schema to JSON schema - const jsonSchema = z.toJSONSchema(module.Schema, { - override: (ctx) => { - delete ctx.jsonSchema.default; - }, - }); - - return { - id: layoutId, - name: layoutName, - description: layoutDescription, - json_schema: jsonSchema, - group: groupName - }; - } catch (error: unknown) { - console.error(`Error extracting layout from ${fileName}:`, error); - const errorMessage = error instanceof Error ? error.message : 'Unknown error'; - throw new Error(`Failed to extract schema from ${fileName}: ${errorMessage}`); - } -} - -/** - * Gets all layout files from the grouped presentation-layouts directory - */ -async function getGroupedLayoutFiles(): Promise { - const layoutsDirectory = path.join(process.cwd(), 'presentation-layouts'); - - if (!fs.existsSync(layoutsDirectory)) { - throw new Error(`Layouts directory not found at ${layoutsDirectory}`); - } - - const items = fs.readdirSync(layoutsDirectory, { withFileTypes: true }); - const groupDirectories = items - .filter(item => item.isDirectory()) - .map(dir => dir.name); - - const allLayouts: GroupedLayoutsResponse[] = []; - - for (const groupName of groupDirectories) { - try { - const groupPath = path.join(layoutsDirectory, groupName); - const groupFiles = fs.readdirSync(groupPath); - - // Filter for TypeScript/TSX files, excluding setting.json and other non-layout files - const layoutFiles = groupFiles.filter(file => - (file.endsWith('.ts') || file.endsWith('.tsx')) && - file !== 'setting.json' && - !file.startsWith('.') && - !file.includes('.test.') && - !file.includes('.spec.') - ); - - if (layoutFiles.length > 0) { - allLayouts.push({ - group: groupName, - files: layoutFiles - }); - } - } catch (error) { - console.error(`Error reading group directory ${groupName}:`, error); - // Continue with other groups even if one fails - } - } - - return allLayouts; -} - -/** - * Extracts layout groups from layoutGroup.ts file in presentation-layouts directory - */ -async function extractLayoutGroups(): Promise { - try { - const layoutGroupPath = path.join(process.cwd(), 'presentation-layouts', 'layoutGroup.ts'); - - if (!fs.existsSync(layoutGroupPath)) { - throw new Error('layoutGroup.ts file not found in presentation-layouts directory'); - } - - const module = await import(layoutGroupPath); - - // Extract all exported layout groups - const layoutGroups: LayoutGroup[] = []; - - Object.keys(module).forEach(key => { - const exportedItem = module[key]; - - // Check if it's a layout group object - if (exportedItem && - typeof exportedItem === 'object' && - exportedItem.id && - Array.isArray(exportedItem.slides)) { - - layoutGroups.push({ - id: exportedItem.id, - ordered: exportedItem.ordered || false, - slides: exportedItem.slides - }); - } - }); - - if (layoutGroups.length === 0) { - throw new Error('No valid layout groups found in layoutGroup.ts'); - } - - return layoutGroups; - } catch (error) { - console.error('Error extracting layout groups:', error); - throw error; - } -} - -/** - * Maps layout information to layout groups - */ -function mapLayoutsToGroups( - layoutInfos: LayoutInfo[], - layoutGroups: LayoutGroup[] -): LayoutStructure[] { - return layoutGroups.map(group => { - const groupSlides: LayoutInfo[] = []; - - // Map slides in the group to their layout info - group.slides.forEach(slideId => { - const layoutInfo = layoutInfos.find(layout => - layout.id === slideId || - layout.id.replace('-', '') === slideId.replace('-', '') || - layout.id.toLowerCase() === slideId.toLowerCase() - ); - - if (layoutInfo) { - groupSlides.push(layoutInfo); - } else { - console.warn(`Layout info not found for slide ID: ${slideId}`); - } - }); - - return { - name: group.id, - ordered: group.ordered, - slides: groupSlides - }; - }); -} - -/** - * Main function to extract all layouts dynamically from grouped structure - */ -export async function extractLayouts(): Promise { - // Return cached layouts if available - if (layoutsCache) { - return layoutsCache; - } - - try { - // Get all grouped layout files - const groupedLayoutFiles = await getGroupedLayoutFiles(); - - if (groupedLayoutFiles.length === 0) { - throw new Error('No layout files found in the presentation-layouts directory'); - } - - // Extract layout information from each file in each group - const allLayoutPromises: Promise[] = []; - - for (const groupData of groupedLayoutFiles) { - for (const fileName of groupData.files) { - const filePath = path.join(process.cwd(), 'presentation-layouts', groupData.group, fileName); - allLayoutPromises.push(extractLayoutFromFile(filePath, fileName, groupData.group)); - } - } - - const layoutResults = await Promise.all(allLayoutPromises); - - // Filter out null results (files without valid schemas) - const validLayouts = layoutResults.filter((layout): layout is LayoutInfo => layout !== null); - - if (validLayouts.length === 0) { - throw new Error('No valid schemas found in any layout files'); - } - - // Extract layout groups - const layoutGroups = await extractLayoutGroups(); - - // Map layouts to groups - const mappedLayouts = mapLayoutsToGroups(validLayouts, layoutGroups); - - // Cache the results - layoutsCache = mappedLayouts; - - return mappedLayouts; - } catch (error) { - console.error('Error extracting layouts:', error); - throw error; - } -} - -/** - * Clears the layout cache (useful for development/testing) - */ -export function clearLayoutCache(): void { - layoutsCache = null; -} - -/** - * Gets a specific layout by ID - */ -export async function getLayoutById(layoutId: string): Promise { - const layouts = await extractLayouts(); - - for (const group of layouts) { - const layout = group.slides.find(slide => slide.id === layoutId); - if (layout) { - return layout; - } - } - - return null; -} - -/** - * Gets all available layout IDs - */ -export async function getAllLayoutIds(): Promise { - const layouts = await extractLayouts(); - const ids: string[] = []; - - layouts.forEach(group => { - group.slides.forEach(slide => { - ids.push(slide.id); - }); - }); - - return ids; -} \ No newline at end of file diff --git a/servers/nextjs/app/dashboard/components/Header.tsx b/servers/nextjs/app/dashboard/components/Header.tsx index 6ca4c67e..6063e8e1 100644 --- a/servers/nextjs/app/dashboard/components/Header.tsx +++ b/servers/nextjs/app/dashboard/components/Header.tsx @@ -3,9 +3,9 @@ import Wrapper from "@/components/Wrapper"; import React from "react"; import Link from "next/link"; -import UserAccount from "@/app/(presentation-generator)/components/UserAccount"; import BackBtn from "@/components/BackBtn"; import { usePathname } from "next/navigation"; +import HeaderNav from "@/app/(presentation-generator)/components/HeaderNab"; const Header = () => { const pathname = usePathname(); return ( @@ -23,7 +23,7 @@ const Header = () => {
- +
diff --git a/servers/nextjs/app/globals.css b/servers/nextjs/app/globals.css index 6c02fcac..49e38ed9 100644 --- a/servers/nextjs/app/globals.css +++ b/servers/nextjs/app/globals.css @@ -2,7 +2,6 @@ @tailwind components; @tailwind utilities; -@import '../app/(presentation-generator)/styles/themes.css'; body { font-family: Arial, Helvetica, sans-serif; diff --git a/servers/nextjs/app/layout-preview/README.md b/servers/nextjs/app/layout-preview/README.md deleted file mode 100644 index 75ab0824..00000000 --- a/servers/nextjs/app/layout-preview/README.md +++ /dev/null @@ -1,137 +0,0 @@ -# Layout Preview Studio - -A modular, responsive layout preview system for viewing and testing presentation layout components with realistic sample data. - -## ✨ Features - -- **Dynamic Layout Discovery**: Automatically discovers and loads layout components -- **Interactive Navigation**: Easy navigation with quick select grid -- **Beautiful Presentation Display**: Mock browser frame with professional styling -- **Detailed Information Panel**: Layout metadata and sample data inspection -- **Responsive Design**: Mobile-friendly with collapsible sidebar -- **Professional Loading States**: Skeleton loaders and error handling -- **Type Safety**: Full TypeScript support with shared types - -## 🏗️ Architecture - -The system is built with a modular architecture for maintainability and reusability: - -``` -layout-preview/ -├── components/ # Modular UI components -│ ├── LayoutNavigation.tsx # Navigation controls & layout selector -│ ├── LayoutDisplay.tsx # Main layout preview area -│ ├── LayoutInfoPanel.tsx # Information and data structure display -│ └── LoadingStates.tsx # Loading, error, and empty states -├── hooks/ # Custom React hooks -│ └── useLayoutLoader.ts # Layout loading logic and state management -├── utils/ # Utility functions -│ └── sampleDataGenerator.ts # Realistic sample data generation -├── types/ # Shared TypeScript types -│ └── index.ts # Common interfaces and types -├── page.tsx # Main page component -└── README.md # This file -``` - -## 🧩 Components - -### LayoutNavigation -- Previous/Next navigation buttons -- Layout counter and current layout info -- Quick select grid for fast switching -- Responsive design with mobile optimization - -### LayoutDisplay -- Mock browser frame presentation -- Layout rendering with sample data -- Professional shadow and styling effects -- Empty state with helpful messaging - -### LayoutInfoPanel -- Layout metadata display -- Collapsible sample data viewer -- Copy to clipboard functionality -- Position tracking in collection - -### LoadingStates -- Loading spinner with animated dots -- Error state with retry functionality -- Empty state with helpful instructions -- Skeleton loading animations - -## 🎯 Custom Hooks - -### useLayoutLoader -Handles all layout loading logic: -- Fetches layout files from API -- Imports and validates components -- Generates realistic sample data -- Provides retry functionality -- Manages loading and error states - -## 🛠️ Utilities - -### sampleDataGenerator -Intelligent sample data generation: -- Context-aware field value generation -- Support for images, emails, phones, URLs -- Realistic business content -- Zod schema parsing and validation -- Array and object handling - -## 📱 Responsive Design - -The layout preview system is fully responsive: -- **Desktop**: Sidebar navigation with main preview area -- **Tablet**: Collapsible navigation panels -- **Mobile**: Stacked layout with touch-friendly controls - -## 🎨 Styling - -Built with: -- **Tailwind CSS**: Utility-first styling -- **shadcn/ui**: Consistent component library -- **Gradient Backgrounds**: Modern visual appeal -- **Glass Morphism**: Backdrop blur effects -- **Smooth Animations**: Hover and transition effects - -## 🔧 Usage - -The system automatically discovers layout components that export: -```typescript -// Layout component -export default function MyLayout({ data }: { data: any }) { - return
{/* Your layout */}
-} - -// Zod schema for type safety and sample data generation -export const Schema = z.object({ - title: z.string(), - description: z.string(), - // ... other fields -}) -``` - -## 🚀 Getting Started - -1. **Add Layout Components**: Place your layout files in the appropriate directory -2. **Export Requirements**: Ensure each layout exports both a default component and Schema -3. **Navigate**: Use the navigation controls or quick select grid -4. **Inspect**: View layout information and sample data structure -5. **Test**: See how your layouts render with realistic data - -## 🎯 Benefits - -- **Modular Architecture**: Easy to maintain and extend -- **Type Safety**: Full TypeScript support prevents runtime errors -- **Beautiful UI**: Professional design that's pleasant to use -- **Developer Experience**: Quick feedback loop for layout development -- **Responsive**: Works on all device sizes -- **Accessible**: Keyboard navigation and screen reader support - -## 📈 Performance - -- **Lazy Loading**: Components are imported only when needed -- **Optimized Rendering**: Efficient re-renders with React best practices -- **Minimal Bundle**: Modular structure enables tree shaking -- **Caching**: Sample data generation is memoized \ No newline at end of file diff --git a/servers/nextjs/data/presenton-settings.db b/servers/nextjs/data/presenton-settings.db deleted file mode 100644 index 39a091a560437e81a23f718a8112b8430543656d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI$Pj3=I6aesr8ml$5-bfEkw!@`OpzgAzY)MR{utXyLBW$CMX~=YUmTtN*xI1WT z(}QjNBHsKOUOe^#_z^stc=Qd+5>1-4@n-TS?6ULT{CWJ~GIUZzbd0gIRr{-75n@9A3Gs@j%nSGQW0nncx=Id$Al z*qLfuuWfa&-Q2FW57ZadL4J}OMJ#N(ae8OhR(JMWtt97CL2u4DA)|u1T{v6UVPm_w zZK-vuQQdFZYHh#Wws!2U40i15_Fl5wXb215b<()J)hFru+1gS{@dqwDjot=urti{` z;NyNb`Ji1rd6MV)2huYGS2}a3WDe)Q%RV*~Kmim$0Te(16hHwKKmim$fqxLVJg?7Y zmp?r+3~|i*EZ`0e3i2R%P6o8kNQF3~Nbo+%6Nd*pj7a6298u?_7xK}-g?!F6D5Yf> z5Cy)=wt6z=c~04x#%x~%a;cnd>h|C-jHH=Y#Pqsvqgz zbOU}G?_heS4Ehcq#G5v>jm=U+R(ecBQJa+ehUBJ++$=HrKsN!x+K=@;_}ri!|*s4Ec}x{;61(<@*xX_&&KT0F@N8JD5;2W#PVc3 zf=B+uDPW#}QuvTMzJO}AH8UR5?9(3bpA(mcCr~80xQG)S__86P$Gu(8gR{3B2f$jM z$R%K4T-i2@qRA? { - const [displayText, setDisplayText] = useState(""); - const [isCursorVisible, setIsCursorVisible] = useState(true); - const [index, setIndex] = useState(0); - - // Reset when text changes or enabled status changes - useEffect(() => { - if (enabled) { - setDisplayText(""); - setIndex(0); - setIsCursorVisible(true); - } else { - // When disabled, immediately show full text and hide cursor - setDisplayText(text); - setIsCursorVisible(false); - } - }, [text, enabled]); - - // Only run the typing effect when enabled - useEffect(() => { - if (!enabled) return; - - if (index >= text.length) { - setIsCursorVisible(false); - return; - } - - const timeout = setTimeout(() => { - setDisplayText((prev) => prev + text.charAt(index)); - setIndex((prev) => prev + 1); - }, speed); - - return () => clearTimeout(timeout); - }, [index, text, speed, enabled]); - - return { displayText, isCursorVisible }; -}; diff --git a/servers/nextjs/lib/utils.ts b/servers/nextjs/lib/utils.ts index 97033366..ccd54c72 100644 --- a/servers/nextjs/lib/utils.ts +++ b/servers/nextjs/lib/utils.ts @@ -4,66 +4,3 @@ import { twMerge } from 'tailwind-merge' export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) } - -interface ChartData { - categories: string[]; - series: { - name: string; - data: number[]; - }[]; -} - -export function randomChartGenerator(): ChartData { - const templates = [ - { - categories: ["first Q", "second Q", "third Q", "fourth Q"], - series: [ - { - name: "Revenue 2023", - data: [32500, 47800, 41500, 59000] - }, - { - name: "Revenue 2022", - data: [28000, 35000, 37500, 41000] - } - ] - }, - { - categories: ["Mobile", "Desktop", "Tablet", "Other"], - series: [ - { - name: "Active Users", - data: [85000, 65000, 22000, 95000] - }, - { - name: "Last Month", - data: [72000, 58000, 18000, 85000] - } - ] - }, - { - categories: ["Product A", "Product B", "Product C", "Product D"], - series: [ - { - name: "Sales Volume", - data: [1200, 980, 850, 674] - }, - { - name: "Target", - data: [1000, 800, 900, 700] - } - ] - } - ]; - - return templates[Math.floor(Math.random() * templates.length)]; -} - -export function formatLargeNumber(num: number): string { - if (num >= 1000000) { - return (num / 1000000).toFixed(1) + 'M'; - } else if (num >= 1000) { - return (num / 1000).toFixed(1) + 'K'; - } - return num.toString(); -} \ No newline at end of file diff --git a/servers/nextjs/store/store.ts b/servers/nextjs/store/store.ts index 8a104c3d..680ed2b7 100644 --- a/servers/nextjs/store/store.ts +++ b/servers/nextjs/store/store.ts @@ -1,13 +1,11 @@ import { configureStore } from "@reduxjs/toolkit"; import presentationGenerationReducer from "./slices/presentationGeneration"; -import themeReducer from "@/app/(presentation-generator)/store/themeSlice"; import pptGenUploadReducer from "./slices/presentationGenUpload"; import userConfigReducer from "./slices/userConfig"; export const store = configureStore({ reducer: { presentationGeneration: presentationGenerationReducer, - theme: themeReducer, pptGenUpload: pptGenUploadReducer, userConfig: userConfigReducer, }, diff --git a/servers/nextjs/utils/helpers.ts b/servers/nextjs/utils/helpers.ts deleted file mode 100644 index d103906b..00000000 --- a/servers/nextjs/utils/helpers.ts +++ /dev/null @@ -1,122 +0,0 @@ -export const toDateTime = (secs: number) => { - var t = new Date('1970-01-01T00:30:00Z'); - t.setSeconds(secs); - return t; -}; - -export const calculateTrialEndUnixTimestamp = ( - trialPeriodDays: number | null | undefined -) => { - // Check if trialPeriodDays is null, undefined, or less than 2 days - if ( - trialPeriodDays === null || - trialPeriodDays === undefined || - trialPeriodDays < 2 - ) { - return undefined; - } - - const currentDate = new Date(); // Current date and time - const trialEnd = new Date( - currentDate.getTime() + (trialPeriodDays + 1) * 24 * 60 * 60 * 1000 - ); // Add trial days - return Math.floor(trialEnd.getTime() / 1000); // Convert to Unix timestamp in seconds -}; - -const toastKeyMap: { [key: string]: string[] } = { - status: ['status', 'status_description'], - error: ['error', 'error_description'] -}; - -const getToastRedirect = ( - path: string, - toastType: string, - toastName: string, - toastDescription: string = '', - disableButton: boolean = false, - arbitraryParams: string = '' -): string => { - const [nameKey, descriptionKey] = toastKeyMap[toastType]; - - let redirectPath = `${path}?${nameKey}=${encodeURIComponent(toastName)}`; - - if (toastDescription) { - redirectPath += `&${descriptionKey}=${encodeURIComponent(toastDescription)}`; - } - - if (disableButton) { - redirectPath += `&disable_button=true`; - } - - if (arbitraryParams) { - redirectPath += `&${arbitraryParams}`; - } - - return redirectPath; -}; - -export const getStatusRedirect = ( - path: string, - statusName: string, - statusDescription: string = '', - disableButton: boolean = false, - arbitraryParams: string = '' -) => - getToastRedirect( - path, - 'status', - statusName, - statusDescription, - disableButton, - arbitraryParams - ); - -export const getErrorRedirect = ( - path: string, - errorName: string, - errorDescription: string = '', - disableButton: boolean = false, - arbitraryParams: string = '' -) => - getToastRedirect( - path, - 'error', - errorName, - errorDescription, - disableButton, - arbitraryParams - ); - -export const getMaxLimits = (tier: 'free' | 'standard' | 'premium') => { - const limits = { - free: { - exports: 5, - slides: 8, - aiVideos: 5, - fileSize: 6 * 1024 * 1024, // 6MB in bytes - videoDuration: 5 * 60, // 5 minutes in seconds - hasWatermark: true, - hasAvatar: false - }, - standard: { - exports: 10, - slides: 15, - aiVideos: 10, - fileSize: 10 * 1024 * 1024, // 10MB - videoDuration: 10 * 60, // 10 minutes - hasWatermark: false, - hasAvatar: true - }, - premium: { - exports: 25, - slides: 25, - aiVideos: 25, - fileSize: 25 * 1024 * 1024, // 25MB - videoDuration: 25 * 60, // 25 minutes - hasWatermark: false, - hasAvatar: true - } - }; - - return limits[tier]; -};