diff --git a/servers/nextjs/app/(presentation-generator)/outline/components/GroupLayouts.tsx b/servers/nextjs/app/(presentation-generator)/outline/components/GroupLayouts.tsx new file mode 100644 index 00000000..99c95d9e --- /dev/null +++ b/servers/nextjs/app/(presentation-generator)/outline/components/GroupLayouts.tsx @@ -0,0 +1,65 @@ +import { useGroupLayoutLoader } from '@/app/layout-preview/hooks/useGroupLayoutLoader'; +import { CheckCircle } from 'lucide-react'; +import React from 'react'; +import { LayoutGroup } from "../types/index"; + +interface GroupLayoutsProps { + group: LayoutGroup; + onSelectLayoutGroup: (group: LayoutGroup) => void; + selectedLayoutGroup: LayoutGroup | null; +} + +const GroupLayouts: React.FC = ({ group, onSelectLayoutGroup, selectedLayoutGroup }) => { + const { layoutGroup } = useGroupLayoutLoader(group.id); + return ( +
onSelectLayoutGroup(group)} + className={`relative p-4 rounded-lg border cursor-pointer transition-all duration-200 ${selectedLayoutGroup?.id === group.id + ? 'border-blue-500 bg-blue-50 shadow-md' + : 'border-gray-200 bg-white hover:border-gray-300 hover:shadow-sm' + }`} + > + {selectedLayoutGroup?.id === group.id && ( +
+ +
+ )} + +
+
+ {group.name} +
+

+ {group.description} +

+
+ + {/* Layout previews */} +
+ {layoutGroup && layoutGroup?.layouts.slice(0, 4).map((layout: any, index: number) => { + const { component: LayoutComponent, sampleData, layoutId } = layout + return ( +
+
+
+ +
+
+ ) + })} +
+ +
+ {layoutGroup?.layouts.length} layouts + + {group.ordered ? 'Structured' : 'Flexible'} + +
+
+ ); +}; + +export default GroupLayouts; diff --git a/servers/nextjs/app/(presentation-generator)/outline/components/LayoutSelection.tsx b/servers/nextjs/app/(presentation-generator)/outline/components/LayoutSelection.tsx index 1c2b4bd5..04db37d3 100644 --- a/servers/nextjs/app/(presentation-generator)/outline/components/LayoutSelection.tsx +++ b/servers/nextjs/app/(presentation-generator)/outline/components/LayoutSelection.tsx @@ -1,17 +1,9 @@ "use client"; import React, { useEffect } from "react"; import { useLayout } from "../../context/LayoutContext"; -import { CheckCircle } from "lucide-react"; - -interface LayoutGroup { - id: string; - name: string; - description: string; - ordered: boolean; - isDefault?: boolean; - slides: string[]; -} +import GroupLayouts from "./GroupLayouts"; +import { LayoutGroup } from "../types/index"; interface LayoutSelectionProps { selectedLayoutGroup: LayoutGroup | null; onSelectLayoutGroup: (group: LayoutGroup) => void; @@ -25,17 +17,15 @@ const LayoutSelection: React.FC = ({ getLayoutsByGroup, getGroupSetting, getAllGroups, - getLayout, loading } = useLayout(); const layoutGroups: LayoutGroup[] = React.useMemo(() => { const groups = getAllGroups(); - if (groups.length === 0) return []; const Groups: LayoutGroup[] = groups.map(groupName => { - const layouts = getLayoutsByGroup(groupName); + const settings = getGroupSetting(groupName); return { id: groupName, @@ -43,7 +33,6 @@ const LayoutSelection: React.FC = ({ description: settings?.description || `${groupName} presentation layouts`, ordered: settings?.ordered || false, isDefault: settings?.isDefault || false, - slides: layouts.map(layout => layout.id) }; }); @@ -63,32 +52,6 @@ const LayoutSelection: React.FC = ({ } }, [layoutGroups, selectedLayoutGroup, onSelectLayoutGroup]); - const renderLayoutPreview = (layoutId: string) => { - const Layout = getLayout(layoutId); - if (!Layout) { - return ( -
- Preview unavailable -
- ); - } - - // Sample data for preview - const sampleData = { - title: "Sample Title", - description: "This is a preview of the layout", - subtitle: "Sample subtitle", - }; - - return ( -
-
- -
-
- ); - }; - if (loading) { return (
@@ -124,52 +87,24 @@ const LayoutSelection: React.FC = ({ ); } + const handleLayoutGroupSelection = (group: LayoutGroup) => { + const slides = getLayoutsByGroup(group.id); + onSelectLayoutGroup({ + ...group, + slides: slides, + }); + } + return (
{layoutGroups.map((group) => ( -
onSelectLayoutGroup(group)} - className={`relative p-4 rounded-lg border cursor-pointer transition-all duration-200 ${selectedLayoutGroup?.id === group.id - ? 'border-blue-500 bg-blue-50 shadow-md' - : 'border-gray-200 bg-white hover:border-gray-300 hover:shadow-sm' - }`} - > - {selectedLayoutGroup?.id === group.id && ( -
- -
- )} - -
-
- {group.name} -
-

- {group.description} -

-
- - {/* Layout previews */} -
- {group.slides.slice(0, 6).map((layoutId, index) => ( -
- {renderLayoutPreview(layoutId)} -
- ))} -
- -
- {group.slides.length} layouts - - {group.ordered ? 'Structured' : 'Flexible'} - -
-
+ group={group} + onSelectLayoutGroup={handleLayoutGroupSelection} + selectedLayoutGroup={selectedLayoutGroup} + /> ))}
diff --git a/servers/nextjs/app/(presentation-generator)/outline/components/OutlinePage.tsx b/servers/nextjs/app/(presentation-generator)/outline/components/OutlinePage.tsx index 9c615eda..fa9c0ee4 100644 --- a/servers/nextjs/app/(presentation-generator)/outline/components/OutlinePage.tsx +++ b/servers/nextjs/app/(presentation-generator)/outline/components/OutlinePage.tsx @@ -24,7 +24,6 @@ const OutlinePage: React.FC = () => { const [activeTab, setActiveTab] = useState(TABS.OUTLINE); const [selectedLayoutGroup, setSelectedLayoutGroup] = useState(null); - // Custom hooks const streamState = useOutlineStreaming(presentation_id); const { handleDragEnd, handleAddSlide } = useOutlineManagement(outlines); @@ -39,6 +38,7 @@ const OutlinePage: React.FC = () => { return ; } + return ( { if (!selectedLayoutGroup) return null; - const groupLayoutSchemas = selectedLayoutGroup.slides - .map(slideId => { - const layout = getLayoutById(slideId); - return layout ? { - id: layout.id, - name: layout.name, - description: layout.description, - json_schema: layout.json_schema - } : null; - }) - .filter(schema => schema !== null); + return { name: selectedLayoutGroup.name, ordered: selectedLayoutGroup.ordered, - slides: groupLayoutSchemas + slides: selectedLayoutGroup.slides }; }, [selectedLayoutGroup, getLayoutById]); @@ -84,7 +74,6 @@ export const usePresentationGeneration = ( try { const layoutData = prepareLayoutData(); if (!layoutData) return; - const response = await PresentationGenerationApi.presentationPrepare({ presentation_id: presentationId, outlines: outlines, diff --git a/servers/nextjs/app/(presentation-generator)/outline/types/index.ts b/servers/nextjs/app/(presentation-generator)/outline/types/index.ts index 9965d2f4..a311f447 100644 --- a/servers/nextjs/app/(presentation-generator)/outline/types/index.ts +++ b/servers/nextjs/app/(presentation-generator)/outline/types/index.ts @@ -4,7 +4,7 @@ export interface LayoutGroup { description: string; ordered: boolean; isDefault?: boolean; - slides: string[]; + slides?: any } export interface LoadingState { diff --git a/servers/nextjs/app/layout-preview/hooks/useGroupLayoutLoader.ts b/servers/nextjs/app/layout-preview/hooks/useGroupLayoutLoader.ts index 00a14e2a..278607f5 100644 --- a/servers/nextjs/app/layout-preview/hooks/useGroupLayoutLoader.ts +++ b/servers/nextjs/app/layout-preview/hooks/useGroupLayoutLoader.ts @@ -67,7 +67,6 @@ export const useGroupLayoutLoader = (groupSlug: string): UseGroupLayoutLoaderRet ordered: false, isDefault: false } - for (const fileName of targetGroupData.files) { try { const layoutName = fileName.replace('.tsx', '').replace('.ts', '') @@ -163,8 +162,7 @@ export const useGroupLayoutLoader = (groupSlug: string): UseGroupLayoutLoaderRet } const retry = () => { - // Clear cache for this group to force reload - layoutGroupCache.delete(groupSlug) + hasMountedRef.current = false loadGroupLayouts() } @@ -179,6 +177,6 @@ export const useGroupLayoutLoader = (groupSlug: string): UseGroupLayoutLoaderRet layoutGroup, loading, error, - retry + retry, } } \ No newline at end of file diff --git a/servers/nextjs/package.json b/servers/nextjs/package.json index 109e3de8..5c769cc1 100644 --- a/servers/nextjs/package.json +++ b/servers/nextjs/package.json @@ -37,11 +37,9 @@ "@tiptap/extension-underline": "^2.0.0", "@tiptap/react": "^2.11.5", "@tiptap/starter-kit": "^2.11.5", - "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cmdk": "^1.0.0", - "jsonrepair": "^3.12.0", "lucide-react": "^0.447.0", "marked": "^15.0.11", @@ -57,7 +55,6 @@ "tailwind-scrollbar-hide": "^2.0.0", "tailwindcss-animate": "^1.0.7", "tiptap-markdown": "^0.8.10", - "ws": "^8.18.0", "uuid": "^11.1.0", "zod": "^4.0.5" },