mirror of
https://github.com/p-stream/p-stream.git
synced 2026-04-13 19:20:22 +00:00
update media card skeleton and on recomented carousel
This commit is contained in:
parent
02291a3e37
commit
ac722880c4
2 changed files with 42 additions and 20 deletions
|
|
@ -49,10 +49,16 @@ function useIntersectionObserver(options: IntersectionObserverInit = {}) {
|
|||
}
|
||||
|
||||
// Skeleton Component
|
||||
function MediaCardSkeleton() {
|
||||
export function MediaCardSkeleton() {
|
||||
return (
|
||||
<div className="group -m-[0.705em] rounded-xl bg-background-main transition-colors duration-300">
|
||||
<div className="pointer-events-auto relative mb-2 p-[0.4em] transition-transform duration-300">
|
||||
<Flare.Base className="group -m-[0.705em] rounded-xl bg-background-main transition-colors duration-300">
|
||||
<Flare.Light
|
||||
flareSize={300}
|
||||
cssColorVar="--colors-mediaCard-hoverAccent"
|
||||
backgroundClass="bg-mediaCard-hoverBackground duration-100"
|
||||
className="rounded-xl bg-background-main group-hover:opacity-100"
|
||||
/>
|
||||
<Flare.Child className="pointer-events-auto relative mb-2 p-[0.4em] transition-transform duration-300 opacity-60">
|
||||
<div className="animate-pulse">
|
||||
{/* Poster skeleton - matches MediaCard poster dimensions exactly */}
|
||||
<div className="relative mb-4 pb-[150%] w-full overflow-hidden rounded-xl bg-mediaCard-hoverBackground" />
|
||||
|
|
@ -71,8 +77,8 @@ function MediaCardSkeleton() {
|
|||
<div className="h-3 bg-mediaCard-hoverBackground rounded w-8" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Flare.Child>
|
||||
</Flare.Base>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { useTranslation } from "react-i18next";
|
|||
|
||||
import { getMediaPoster, getRelatedMedia } from "@/backend/metadata/tmdb";
|
||||
import { TMDBContentTypes } from "@/backend/metadata/types/tmdb";
|
||||
import { MediaCard } from "@/components/media/MediaCard";
|
||||
import { MediaCard, MediaCardSkeleton } from "@/components/media/MediaCard";
|
||||
import { useIsMobile } from "@/hooks/useIsMobile";
|
||||
import { CarouselNavButtons } from "@/pages/discover/components/CarouselNavButtons";
|
||||
import { useOverlayStack } from "@/stores/interface/overlayStack";
|
||||
|
|
@ -22,6 +22,7 @@ export function SimilarMediaCarousel({
|
|||
const { isMobile } = useIsMobile();
|
||||
const { showModal } = useOverlayStack();
|
||||
const [similarMedia, setSimilarMedia] = useState<MediaItem[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const carouselRef = useRef<HTMLDivElement>(null);
|
||||
const carouselRefs = useRef<{ [key: string]: HTMLDivElement | null }>({
|
||||
similar: null,
|
||||
|
|
@ -29,6 +30,7 @@ export function SimilarMediaCarousel({
|
|||
|
||||
useEffect(() => {
|
||||
const loadSimilarMedia = async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const results = await getRelatedMedia(mediaId, mediaType, 12);
|
||||
const mediaItems: MediaItem[] = results.map((result) => {
|
||||
|
|
@ -57,6 +59,8 @@ export function SimilarMediaCarousel({
|
|||
setSimilarMedia(mediaItems);
|
||||
} catch (err) {
|
||||
console.error("Failed to load similar media:", err);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -76,7 +80,7 @@ export function SimilarMediaCarousel({
|
|||
});
|
||||
};
|
||||
|
||||
if (similarMedia.length === 0) return null;
|
||||
if (!isLoading && similarMedia.length === 0) return null;
|
||||
|
||||
return (
|
||||
<div className="space-y-4 pt-8">
|
||||
|
|
@ -96,19 +100,31 @@ export function SimilarMediaCarousel({
|
|||
>
|
||||
<div className="md:w-12" />
|
||||
|
||||
{similarMedia.map((media) => (
|
||||
<div
|
||||
key={media.id}
|
||||
className="relative mt-4 group cursor-pointer user-select-none rounded-xl p-2 bg-transparent transition-colors duration-300 w-[10rem] md:w-[11.5rem] h-auto"
|
||||
style={{ scrollSnapAlign: "start" }}
|
||||
>
|
||||
<MediaCard
|
||||
media={media}
|
||||
linkable
|
||||
onShowDetails={handleShowDetails}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
{isLoading
|
||||
? // Show skeleton cards while loading
|
||||
Array.from({ length: 12 }, (_, i) => (
|
||||
<div
|
||||
key={`skeleton-${i}`}
|
||||
className="relative mt-4 group cursor-pointer user-select-none rounded-xl p-2 bg-transparent transition-colors duration-300 w-[10rem] md:w-[11.5rem] h-auto"
|
||||
style={{ scrollSnapAlign: "start" }}
|
||||
>
|
||||
<MediaCardSkeleton />
|
||||
</div>
|
||||
))
|
||||
: // Show actual media cards when loaded
|
||||
similarMedia.map((media) => (
|
||||
<div
|
||||
key={media.id}
|
||||
className="relative mt-4 group cursor-pointer user-select-none rounded-xl p-2 bg-transparent transition-colors duration-300 w-[10rem] md:w-[11.5rem] h-auto"
|
||||
style={{ scrollSnapAlign: "start" }}
|
||||
>
|
||||
<MediaCard
|
||||
media={media}
|
||||
linkable
|
||||
onShowDetails={handleShowDetails}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<div className="md:w-12" />
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue