返回 presentation-ai
SlideItem.tsx
根目录 / src / components / presentation / slides / SlideItem.tsx
1 "use client";
2
3 import React from "react";
4
5 import { SlideGenerationProvider } from "@/components/notebook/presentation/editor/context/SlideGenerationContext";
6 import PresentationEditor from "@/components/notebook/presentation/editor/presentation-editor";
7 import StaticPresentationEditor from "@/components/notebook/presentation/editor/presentation-editor-static";
8 import { SlideWrapper } from "@/components/presentation/slides/SlideWrapper";
9 import { cn } from "@/lib/utils";
10 import { usePresentationState } from "@/states/presentation-state";
11
12 interface SlideItemProps {
13 slideId: string;
14 isGeneratingPresentation: boolean;
15 slidesCount: number;
16 isReadOnly?: boolean;
17 }
18
19 /**
20 * SlideItem fetches its own slide data from the store.
21 * This isolates re-renders: only this component re-renders when its slide changes.
22 */
23 export const SlideItem = React.memo(function SlideItem({
24 slideId,
25 isGeneratingPresentation,
26 slidesCount,
27 isReadOnly = false,
28 }: SlideItemProps) {
29 // Each slide item fetches its own data - stable reference unless THIS slide changes
30 const slide = usePresentationState((s) =>
31 s.slides.find((slide) => slide.id === slideId),
32 );
33 const isPresenting = usePresentationState((s) => s.isPresenting);
34 const currentSlideId = usePresentationState((s) => s.currentSlideId);
35 const setCurrentSlideId = usePresentationState((s) => s.setCurrentSlideId);
36
37 if (!slide) return null;
38
39 return (
40 <div className={`slide-wrapper slide-wrapper-${slide.id} w-full`}>
41 <SlideGenerationProvider>
42 <SlideWrapper
43 id={slide.id}
44 slideWidth={slide.width}
45 slidesCount={slidesCount}
46 isReadOnly={isReadOnly}
47 >
48 <div
49 className={cn(`slide-container-${slide.id}`)}
50 onClickCapture={() => setCurrentSlideId(slide.id)}
51 >
52 {isGeneratingPresentation ? (
53 <StaticPresentationEditor
54 initialContent={slide}
55 className={cn(
56 "min-h-75 rounded-md border",
57 !isPresenting &&
58 slide.id === currentSlideId &&
59 "border-primary ring-4! ring-primary ring-offset-2!",
60 )}
61 id={slide.id}
62 />
63 ) : (
64 <PresentationEditor
65 initialContent={slide}
66 className={cn(
67 "min-h-75 rounded-md border",
68 !isPresenting &&
69 slide.id === currentSlideId &&
70 "border-primary ring-2! ring-primary",
71 )}
72 id={slide.id}
73 isGenerating={isGeneratingPresentation}
74 readOnly={isReadOnly || isPresenting}
75 />
76 )}
77 </div>
78 </SlideWrapper>
79 </SlideGenerationProvider>
80 </div>
81 );
82 });
83
83 lines Plain Text