mirror of
https://github.com/p-stream/p-stream.git
synced 2026-04-20 20:12:04 +00:00
Add Featured Modal Removed Individual Carousels for each genre Recommended Carousel View More page for viewing all Improve several minor visuals Update search and navigation Full Commit Log: add more carousel skeleton dots bug fix and languages remove provider translations Add change button for recommended more content add buttons to moreContent page dropdown for changing recommended Increase genres and providers add home/search button to discover Update FeaturedCarousel.tsx fix recommended load more pages increase number of featured items clean up featured image fetch maybe fix ff bug? add dynamic blur to header Update Dropdown.tsx fix dropdown add recommended carousel animate dropdown fix some visuals random button fix padding reset timer when manually switching slides fix editor picks more titles add store for discover fix editor picks Update FeaturedCarousel.tsx add view more card move view more link update carousel buttons and dropdown finish 5 carousels use 5 carousels init carousel nav buttons update dropdown update featured sizing update blurs add clear blur to navigation update padding and sizing Update FeaturedCarousel.tsx add loading skeleton update discover navigation again simplify featured media Update SearchBar.tsx tweak some minor visual stuff fix button sizes update carousel gradient fix sticky fix safari overlay bug make search transparent use secondary buttons on featured fix up negative margins fix searching classes fix buttons because of the overlay make it shorter add featured section to home page add toggle for image logos fix details modal title overlay position clean up some buttons improve fed setup status check update grid Update FeaturedCarousel.tsx dont show more content for providers more stuff clean and bugfix update editor picks more content page Update DetailsModal.tsx more more more! shuffle editor picks discover update part 2 fix more info button init discover v3
153 lines
4.5 KiB
TypeScript
153 lines
4.5 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
|
|
import { get } from "@/backend/metadata/tmdb";
|
|
import { useIntersectionObserver } from "@/pages/discover/hooks/useIntersectionObserver";
|
|
import { useLazyTMDBData } from "@/pages/discover/hooks/useTMDBData";
|
|
import { MediaItem } from "@/utils/mediaTypes";
|
|
|
|
import { MediaCarousel } from "./MediaCarousel";
|
|
import {
|
|
Category,
|
|
Genre,
|
|
Media,
|
|
Movie,
|
|
TVShow,
|
|
categories,
|
|
tvCategories,
|
|
} from "../common";
|
|
|
|
interface LazyMediaCarouselProps {
|
|
category?: Category;
|
|
genre?: Genre;
|
|
mediaType: "movie" | "tv";
|
|
isMobile: boolean;
|
|
carouselRefs: React.MutableRefObject<{
|
|
[key: string]: HTMLDivElement | null;
|
|
}>;
|
|
onShowDetails?: (media: MediaItem) => void;
|
|
preloadedMedia?: Movie[] | TVShow[];
|
|
genreId?: number;
|
|
title?: string;
|
|
relatedButtons?: Array<{ name: string; id: string }>;
|
|
onButtonClick?: (id: string, name: string) => void;
|
|
moreContent?: boolean;
|
|
}
|
|
|
|
export function LazyMediaCarousel({
|
|
category,
|
|
genre,
|
|
mediaType,
|
|
isMobile,
|
|
carouselRefs,
|
|
onShowDetails,
|
|
preloadedMedia,
|
|
genreId,
|
|
title,
|
|
relatedButtons,
|
|
onButtonClick,
|
|
moreContent,
|
|
}: LazyMediaCarouselProps) {
|
|
const [medias, setMedias] = useState<Media[]>([]);
|
|
const [loading, setLoading] = useState(!preloadedMedia);
|
|
|
|
const categoryData = (mediaType === "movie" ? categories : tvCategories).find(
|
|
(c: Category) => c.name === (category?.name || genre?.name || title || ""),
|
|
);
|
|
|
|
// Use intersection observer to detect when this component is visible
|
|
const { targetRef, isIntersecting } = useIntersectionObserver(
|
|
{ rootMargin: "200px" }, // Load when within 200px of viewport
|
|
);
|
|
|
|
// Use the lazy loading hook only if we don't have preloaded media
|
|
const { media } = useLazyTMDBData(
|
|
!preloadedMedia ? genre || null : null,
|
|
!preloadedMedia ? category || null : null,
|
|
mediaType,
|
|
isIntersecting,
|
|
);
|
|
|
|
// Update medias when data is loaded or preloaded
|
|
useEffect(() => {
|
|
if (preloadedMedia) {
|
|
setMedias(preloadedMedia);
|
|
setLoading(false);
|
|
} else if (media.length > 0) {
|
|
setMedias(media);
|
|
setLoading(false);
|
|
}
|
|
}, [media, preloadedMedia]);
|
|
|
|
// Only fetch category content if we don't have preloaded media
|
|
useEffect(() => {
|
|
if (preloadedMedia || !categoryData) return;
|
|
|
|
const fetchContent = async () => {
|
|
try {
|
|
const data = await get<any>(categoryData.endpoint, {
|
|
api_key: process.env.TMDB_READ_API_KEY,
|
|
language: "en-US",
|
|
});
|
|
setMedias(data.results);
|
|
} catch (error) {
|
|
console.error("Error fetching content:", error);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
fetchContent();
|
|
}, [categoryData, preloadedMedia]);
|
|
|
|
const categoryName = category?.name || genre?.name || title || "";
|
|
const categorySlug = `${categoryName.toLowerCase().replace(/[^a-z0-9]+/g, "-")}-${mediaType}`;
|
|
|
|
if (loading) {
|
|
return (
|
|
<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">
|
|
{categoryName}
|
|
</h2>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div ref={targetRef as React.RefObject<HTMLDivElement>}>
|
|
{isIntersecting ? (
|
|
<MediaCarousel
|
|
medias={medias}
|
|
category={categoryName}
|
|
isTVShow={mediaType === "tv"}
|
|
isMobile={isMobile}
|
|
carouselRefs={carouselRefs}
|
|
onShowDetails={onShowDetails}
|
|
genreId={genreId}
|
|
relatedButtons={relatedButtons}
|
|
onButtonClick={onButtonClick}
|
|
moreContent={moreContent}
|
|
moreLink={
|
|
categoryData
|
|
? `/discover/more/category/${categoryData.urlPath}/${categoryData.mediaType}`
|
|
: undefined
|
|
}
|
|
/>
|
|
) : (
|
|
<div className="relative overflow-hidden carousel-container">
|
|
<div id={`carousel-${categorySlug}`}>
|
|
<h2 className="ml-2 md:ml-8 mt-2 text-2xl cursor-default font-bold text-white md:text-2xl mx-auto pl-5 text-balance">
|
|
{categoryName} {mediaType === "tv" ? "Shows" : "Movies"}
|
|
</h2>
|
|
<div className="flex whitespace-nowrap pt-0 pb-4 overflow-auto scrollbar rounded-xl overflow-y-hidden h-[300px] animate-pulse bg-background-secondary/20">
|
|
<div className="w-full text-center flex items-center justify-center">
|
|
Loading...
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|