mirror of
https://github.com/p-stream/p-stream.git
synced 2026-04-21 18:42:18 +00:00
Refactor MediaCard for internal lazy loading and fix intersection logic
Moved intersection observer logic for lazy loading images from MediaCarousel into MediaCard, allowing each card to handle its own image loading. Simplified MediaCarousel by removing its intersection observer and related loading state, improving component separation and maintainability.
This commit is contained in:
parent
5e1bd09af5
commit
be6aec2c86
2 changed files with 152 additions and 200 deletions
|
|
@ -17,23 +17,19 @@ import { MediaBookmarkButton } from "./MediaBookmark";
|
|||
import { IconPatch } from "../buttons/IconPatch";
|
||||
import { Icon, Icons } from "../Icon";
|
||||
|
||||
// Intersection Observer Hook
|
||||
// Simple Intersection Observer Hook
|
||||
function useIntersectionObserver(options: IntersectionObserverInit = {}) {
|
||||
const [isIntersecting, setIsIntersecting] = useState(false);
|
||||
const [hasIntersected, setHasIntersected] = useState(false);
|
||||
const targetRef = useRef<Element | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const observer = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
setIsIntersecting(entry.isIntersecting);
|
||||
if (entry.isIntersecting) {
|
||||
setHasIntersected(true);
|
||||
}
|
||||
},
|
||||
{
|
||||
...options,
|
||||
rootMargin: options.rootMargin || "300px 0px",
|
||||
rootMargin: options.rootMargin || "300px",
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -49,7 +45,7 @@ function useIntersectionObserver(options: IntersectionObserverInit = {}) {
|
|||
};
|
||||
}, [options]);
|
||||
|
||||
return { targetRef, isIntersecting, hasIntersected };
|
||||
return { targetRef, isIntersecting };
|
||||
}
|
||||
|
||||
// Skeleton Component
|
||||
|
|
@ -135,8 +131,8 @@ function MediaCardContent({
|
|||
|
||||
const [searchQuery] = useSearchQuery();
|
||||
|
||||
// Intersection observer for lazy loading
|
||||
const { targetRef } = useIntersectionObserver({
|
||||
// Simple intersection observer for lazy loading images
|
||||
const { targetRef, isIntersecting } = useIntersectionObserver({
|
||||
rootMargin: "300px",
|
||||
});
|
||||
|
||||
|
|
@ -160,6 +156,7 @@ function MediaCardContent({
|
|||
}
|
||||
|
||||
return (
|
||||
<div ref={targetRef as React.RefObject<HTMLDivElement>}>
|
||||
<Flare.Base
|
||||
className={`group -m-[0.705em] rounded-xl bg-background-main transition-colors duration-300 focus:relative focus:z-10 ${
|
||||
canLink ? "hover:bg-mediaCard-hoverBackground tabbable" : ""
|
||||
|
|
@ -188,9 +185,11 @@ function MediaCardContent({
|
|||
},
|
||||
)}
|
||||
style={{
|
||||
backgroundImage: media.poster
|
||||
backgroundImage: isIntersecting
|
||||
? media.poster
|
||||
? `url(${media.poster})`
|
||||
: "url(/placeholder.png)",
|
||||
: "url(/placeholder.png)"
|
||||
: "",
|
||||
}}
|
||||
>
|
||||
{series ? (
|
||||
|
|
@ -312,6 +311,7 @@ function MediaCardContent({
|
|||
)}
|
||||
</Flare.Child>
|
||||
</Flare.Base>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import {
|
|||
useDiscoverMedia,
|
||||
useDiscoverOptions,
|
||||
} from "@/pages/discover/hooks/useDiscoverMedia";
|
||||
import { useIntersectionObserver } from "@/pages/discover/hooks/useIntersectionObserver";
|
||||
import { useDiscoverStore } from "@/stores/discover";
|
||||
import { useProgressStore } from "@/stores/progress";
|
||||
import { MediaItem } from "@/utils/mediaTypes";
|
||||
|
|
@ -114,13 +113,6 @@ export function MediaCarousel({
|
|||
title: item.title || "",
|
||||
}));
|
||||
|
||||
// Set up intersection observer for lazy loading
|
||||
const { targetRef, isIntersecting, hasIntersected } = useIntersectionObserver(
|
||||
{
|
||||
rootMargin: "300px",
|
||||
},
|
||||
);
|
||||
|
||||
// Handle provider/genre selection
|
||||
const handleProviderChange = React.useCallback((id: string, name: string) => {
|
||||
setSelectedProviderId(id);
|
||||
|
|
@ -197,7 +189,7 @@ export function MediaCarousel({
|
|||
content.type,
|
||||
]);
|
||||
|
||||
// Fetch media using our hook - only when carousel has been visible
|
||||
// Fetch media using our hook
|
||||
const { media, sectionTitle, actualContentType } = useDiscoverMedia({
|
||||
contentType,
|
||||
mediaType,
|
||||
|
|
@ -207,7 +199,6 @@ export function MediaCarousel({
|
|||
providerName: selectedProviderName,
|
||||
mediaTitle: selectedRecommendationTitle,
|
||||
isCarouselView: true,
|
||||
enabled: hasIntersected,
|
||||
});
|
||||
|
||||
// Find active button
|
||||
|
|
@ -311,47 +302,8 @@ export function MediaCarousel({
|
|||
actualContentType,
|
||||
]);
|
||||
|
||||
// Loading state
|
||||
if (!isIntersecting || !sectionTitle) {
|
||||
return (
|
||||
<div ref={targetRef as React.RefObject<HTMLDivElement>}>
|
||||
<div className="flex items-center justify-between ml-2 md:ml-8 mt-2">
|
||||
<div className="flex gap-4 items-center">
|
||||
<h2 className="text-2xl cursor-default font-bold text-white md:text-2xl pl-5 text-balance">
|
||||
{t("discover.carousel.title.loading")}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative overflow-hidden carousel-container md:pb-4">
|
||||
<div className="grid grid-flow-col auto-cols-max gap-4 pt-0 overflow-x-scroll scrollbar-none rounded-xl overflow-y-hidden md:pl-8 md:pr-8">
|
||||
<div className="md:w-12" />
|
||||
{Array(10)
|
||||
.fill(null)
|
||||
.map((_, index) => (
|
||||
<div
|
||||
key={`skeleton-loading-${Math.random().toString(36).substring(2)}`}
|
||||
className="relative mt-4 group cursor-default user-select-none rounded-xl p-2 bg-transparent transition-colors duration-300 w-[10rem] md:w-[11.5rem] h-auto"
|
||||
>
|
||||
<MediaCard
|
||||
media={{
|
||||
id: `skeleton-${index}`,
|
||||
title: "",
|
||||
poster: "",
|
||||
type: isTVShow ? "show" : "movie",
|
||||
}}
|
||||
forceSkeleton
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
<div className="md:w-12" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref={targetRef as React.RefObject<HTMLDivElement>}>
|
||||
<div>
|
||||
<div className="flex items-center justify-between ml-2 md:ml-8 mt-2">
|
||||
<div className="flex flex-col">
|
||||
<div className="flex items-center gap-4">
|
||||
|
|
|
|||
Loading…
Reference in a new issue