mirror of
https://github.com/p-stream/p-stream.git
synced 2026-05-11 07:30:53 +00:00
Revert hide/show carousel buttons based on carousel length
This commit is contained in:
parent
b1b2539814
commit
e79a04c204
5 changed files with 20 additions and 191 deletions
|
|
@ -34,11 +34,6 @@ export function DiscoverMore() {
|
||||||
const { lastView } = useDiscoverStore();
|
const { lastView } = useDiscoverStore();
|
||||||
const { isMobile } = useIsMobile();
|
const { isMobile } = useIsMobile();
|
||||||
|
|
||||||
// Track overflow states for curated lists
|
|
||||||
const [overflowStates, setOverflowStates] = useState<{
|
|
||||||
[key: string]: boolean;
|
|
||||||
}>({});
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchCuratedLists = async () => {
|
const fetchCuratedLists = async () => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -93,41 +88,6 @@ export function DiscoverMore() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to check overflow for a carousel
|
|
||||||
const checkOverflow = (element: HTMLDivElement | null, key: string) => {
|
|
||||||
if (!element) {
|
|
||||||
setOverflowStates((prev) => ({ ...prev, [key]: false }));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasOverflow = element.scrollWidth > element.clientWidth;
|
|
||||||
setOverflowStates((prev) => ({ ...prev, [key]: hasOverflow }));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function to set carousel ref and check overflow
|
|
||||||
const setCarouselRef = (element: HTMLDivElement | null, key: string) => {
|
|
||||||
carouselRefs.current[key] = element;
|
|
||||||
|
|
||||||
// Check overflow after a short delay to ensure content is rendered
|
|
||||||
setTimeout(() => checkOverflow(element, key), 100);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Effect to recheck overflow on window resize
|
|
||||||
useEffect(() => {
|
|
||||||
const handleResize = () => {
|
|
||||||
// Recheck overflow for all carousels
|
|
||||||
Object.keys(carouselRefs.current).forEach((key) => {
|
|
||||||
const element = carouselRefs.current[key];
|
|
||||||
if (element) {
|
|
||||||
checkOverflow(element, key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener("resize", handleResize);
|
|
||||||
return () => window.removeEventListener("resize", handleResize);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SubPageLayout>
|
<SubPageLayout>
|
||||||
<WideContainer>
|
<WideContainer>
|
||||||
|
|
@ -183,7 +143,9 @@ export function DiscoverMore() {
|
||||||
<div className="relative overflow-hidden carousel-container md:pb-4">
|
<div className="relative overflow-hidden carousel-container md:pb-4">
|
||||||
<div
|
<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"
|
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"
|
||||||
ref={(el) => setCarouselRef(el, list.listSlug)}
|
ref={(el) => {
|
||||||
|
carouselRefs.current[list.listSlug] = el;
|
||||||
|
}}
|
||||||
onWheel={handleWheel}
|
onWheel={handleWheel}
|
||||||
>
|
>
|
||||||
<div className="md:w-12" />
|
<div className="md:w-12" />
|
||||||
|
|
@ -215,7 +177,6 @@ export function DiscoverMore() {
|
||||||
<CarouselNavButtons
|
<CarouselNavButtons
|
||||||
categorySlug={list.listSlug}
|
categorySlug={list.listSlug}
|
||||||
carouselRefs={carouselRefs}
|
carouselRefs={carouselRefs}
|
||||||
hasOverflow={overflowStates[list.listSlug]}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ interface CarouselNavButtonsProps {
|
||||||
carouselRefs: React.MutableRefObject<{
|
carouselRefs: React.MutableRefObject<{
|
||||||
[key: string]: HTMLDivElement | null;
|
[key: string]: HTMLDivElement | null;
|
||||||
}>;
|
}>;
|
||||||
hasOverflow?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NavButtonProps {
|
interface NavButtonProps {
|
||||||
|
|
@ -43,7 +42,6 @@ function NavButton({ direction, onClick }: NavButtonProps) {
|
||||||
export function CarouselNavButtons({
|
export function CarouselNavButtons({
|
||||||
categorySlug,
|
categorySlug,
|
||||||
carouselRefs,
|
carouselRefs,
|
||||||
hasOverflow = true,
|
|
||||||
}: CarouselNavButtonsProps) {
|
}: CarouselNavButtonsProps) {
|
||||||
const handleScroll = (direction: "left" | "right") => {
|
const handleScroll = (direction: "left" | "right") => {
|
||||||
const carousel = carouselRefs.current[categorySlug];
|
const carousel = carouselRefs.current[categorySlug];
|
||||||
|
|
@ -76,11 +74,6 @@ export function CarouselNavButtons({
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Don't render buttons if there's no overflow
|
|
||||||
if (!hasOverflow) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NavButton direction="left" onClick={() => handleScroll("left")} />
|
<NavButton direction="left" onClick={() => handleScroll("left")} />
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Listbox } from "@headlessui/react";
|
import { Listbox } from "@headlessui/react";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { useWindowSize } from "react-use";
|
import { useWindowSize } from "react-use";
|
||||||
|
|
@ -110,9 +110,6 @@ export function MediaCarousel({
|
||||||
const { isMobile } = useIsMobile();
|
const { isMobile } = useIsMobile();
|
||||||
const browser = !!window.chrome;
|
const browser = !!window.chrome;
|
||||||
|
|
||||||
// Track overflow state
|
|
||||||
const [hasOverflow, setHasOverflow] = useState(false);
|
|
||||||
|
|
||||||
// State for selected options
|
// State for selected options
|
||||||
const [selectedProviderId, setSelectedProviderId] = useState<string>("");
|
const [selectedProviderId, setSelectedProviderId] = useState<string>("");
|
||||||
const [selectedProviderName, setSelectedProviderName] = useState<string>("");
|
const [selectedProviderName, setSelectedProviderName] = useState<string>("");
|
||||||
|
|
@ -275,45 +272,8 @@ export function MediaCarousel({
|
||||||
}
|
}
|
||||||
}, [showRecommendations, recommendationSources, selectedRecommendationId]);
|
}, [showRecommendations, recommendationSources, selectedRecommendationId]);
|
||||||
|
|
||||||
const categorySlug = React.useMemo(() => {
|
const categorySlug = `${sectionTitle.toLowerCase().replace(/[^a-z0-9]+/g, "-")}-${isTVShow ? "tv" : "movie"}`;
|
||||||
return `${sectionTitle.toLowerCase().replace(/[^a-z0-9]+/g, "-")}-${isTVShow ? "tv" : "movie"}`;
|
const isScrollingRef = useRef(false);
|
||||||
}, [sectionTitle, isTVShow]);
|
|
||||||
|
|
||||||
// Function to check overflow for the carousel
|
|
||||||
const checkOverflow = React.useCallback((element: HTMLDivElement | null) => {
|
|
||||||
if (!element) {
|
|
||||||
setHasOverflow(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasHorizontalOverflow = element.scrollWidth > element.clientWidth;
|
|
||||||
setHasOverflow(hasHorizontalOverflow);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Function to set carousel ref and check overflow
|
|
||||||
const setCarouselRef = React.useCallback(
|
|
||||||
(element: HTMLDivElement | null) => {
|
|
||||||
carouselRefs.current[categorySlug] = element;
|
|
||||||
|
|
||||||
// Check overflow after a short delay to ensure content is rendered
|
|
||||||
setTimeout(() => checkOverflow(element), 100);
|
|
||||||
},
|
|
||||||
[carouselRefs, categorySlug, checkOverflow],
|
|
||||||
);
|
|
||||||
|
|
||||||
// Effect to recheck overflow on window resize
|
|
||||||
useEffect(() => {
|
|
||||||
const handleResize = () => {
|
|
||||||
const element = carouselRefs.current[categorySlug];
|
|
||||||
if (element) {
|
|
||||||
checkOverflow(element);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener("resize", handleResize);
|
|
||||||
return () => window.removeEventListener("resize", handleResize);
|
|
||||||
}, [carouselRefs, categorySlug, checkOverflow]);
|
|
||||||
const isScrollingRef = React.useRef(false);
|
|
||||||
|
|
||||||
const handleWheel = React.useCallback(
|
const handleWheel = React.useCallback(
|
||||||
(e: React.WheelEvent) => {
|
(e: React.WheelEvent) => {
|
||||||
|
|
@ -568,7 +528,9 @@ export function MediaCarousel({
|
||||||
<div
|
<div
|
||||||
id={`carousel-${categorySlug}`}
|
id={`carousel-${categorySlug}`}
|
||||||
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"
|
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"
|
||||||
ref={setCarouselRef}
|
ref={(el) => {
|
||||||
|
carouselRefs.current[categorySlug] = el;
|
||||||
|
}}
|
||||||
onWheel={handleWheel}
|
onWheel={handleWheel}
|
||||||
>
|
>
|
||||||
<div className="md:w-12" />
|
<div className="md:w-12" />
|
||||||
|
|
@ -623,7 +585,6 @@ export function MediaCarousel({
|
||||||
<CarouselNavButtons
|
<CarouselNavButtons
|
||||||
categorySlug={categorySlug}
|
categorySlug={categorySlug}
|
||||||
carouselRefs={carouselRefs}
|
carouselRefs={carouselRefs}
|
||||||
hasOverflow={hasOverflow}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useEffect, useMemo, useRef, useState } from "react";
|
import React, { useMemo, useRef, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
|
|
@ -96,17 +96,6 @@ export function BookmarksCarousel({
|
||||||
const backendUrl = useBackendUrl();
|
const backendUrl = useBackendUrl();
|
||||||
const account = useAuthStore((s) => s.account);
|
const account = useAuthStore((s) => s.account);
|
||||||
|
|
||||||
// Create refs for overflow detection
|
|
||||||
const groupedCarouselRefs = useRef<{
|
|
||||||
[key: string]: HTMLDivElement | null;
|
|
||||||
}>({});
|
|
||||||
const regularCarouselRef = useRef<HTMLDivElement | null>(null);
|
|
||||||
|
|
||||||
// Track overflow state for each section
|
|
||||||
const [overflowStates, setOverflowStates] = useState<{
|
|
||||||
[key: string]: boolean;
|
|
||||||
}>({});
|
|
||||||
|
|
||||||
// Group order editing state
|
// Group order editing state
|
||||||
const groupOrder = useGroupOrderStore((s) => s.groupOrder);
|
const groupOrder = useGroupOrderStore((s) => s.groupOrder);
|
||||||
const setGroupOrder = useGroupOrderStore((s) => s.setGroupOrder);
|
const setGroupOrder = useGroupOrderStore((s) => s.setGroupOrder);
|
||||||
|
|
@ -376,49 +365,6 @@ export function BookmarksCarousel({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to check overflow for a carousel
|
|
||||||
const checkOverflow = (element: HTMLDivElement | null, key: string) => {
|
|
||||||
if (!element) {
|
|
||||||
setOverflowStates((prev) => ({ ...prev, [key]: false }));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasOverflow = element.scrollWidth > element.clientWidth;
|
|
||||||
setOverflowStates((prev) => ({ ...prev, [key]: hasOverflow }));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function to set carousel ref and check overflow
|
|
||||||
const setCarouselRef = (element: HTMLDivElement | null, key: string) => {
|
|
||||||
// Set the ref for the main carousel refs
|
|
||||||
carouselRefs.current[key] = element;
|
|
||||||
|
|
||||||
// Set the ref for overflow detection
|
|
||||||
if (key === "bookmarks") {
|
|
||||||
regularCarouselRef.current = element;
|
|
||||||
} else {
|
|
||||||
groupedCarouselRefs.current[key] = element;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check overflow after a short delay to ensure content is rendered
|
|
||||||
setTimeout(() => checkOverflow(element, key), 100);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Effect to recheck overflow on window resize
|
|
||||||
useEffect(() => {
|
|
||||||
const handleResize = () => {
|
|
||||||
// Recheck overflow for all carousels
|
|
||||||
Object.keys(carouselRefs.current).forEach((key) => {
|
|
||||||
const element = carouselRefs.current[key];
|
|
||||||
if (element) {
|
|
||||||
checkOverflow(element, key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener("resize", handleResize);
|
|
||||||
return () => window.removeEventListener("resize", handleResize);
|
|
||||||
}, [carouselRefs]);
|
|
||||||
|
|
||||||
const categorySlug = "bookmarks";
|
const categorySlug = "bookmarks";
|
||||||
const SKELETON_COUNT = 10;
|
const SKELETON_COUNT = 10;
|
||||||
|
|
||||||
|
|
@ -462,7 +408,9 @@ export function BookmarksCarousel({
|
||||||
<div
|
<div
|
||||||
id={`carousel-${section.group}`}
|
id={`carousel-${section.group}`}
|
||||||
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"
|
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"
|
||||||
ref={(el) => setCarouselRef(el, section.group || "bookmarks")}
|
ref={(el) => {
|
||||||
|
carouselRefs.current[section.group || "bookmarks"] = el;
|
||||||
|
}}
|
||||||
onWheel={handleWheel}
|
onWheel={handleWheel}
|
||||||
>
|
>
|
||||||
<div className="md:w-12" />
|
<div className="md:w-12" />
|
||||||
|
|
@ -503,7 +451,6 @@ export function BookmarksCarousel({
|
||||||
<CarouselNavButtons
|
<CarouselNavButtons
|
||||||
categorySlug={section.group || "bookmarks"}
|
categorySlug={section.group || "bookmarks"}
|
||||||
carouselRefs={carouselRefs}
|
carouselRefs={carouselRefs}
|
||||||
hasOverflow={overflowStates[section.group || "bookmarks"]}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -538,7 +485,9 @@ export function BookmarksCarousel({
|
||||||
<div
|
<div
|
||||||
id={`carousel-${categorySlug}`}
|
id={`carousel-${categorySlug}`}
|
||||||
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"
|
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"
|
||||||
ref={(el) => setCarouselRef(el, categorySlug)}
|
ref={(el) => {
|
||||||
|
carouselRefs.current[categorySlug] = el;
|
||||||
|
}}
|
||||||
onWheel={handleWheel}
|
onWheel={handleWheel}
|
||||||
>
|
>
|
||||||
<div className="md:w-12" />
|
<div className="md:w-12" />
|
||||||
|
|
@ -585,7 +534,6 @@ export function BookmarksCarousel({
|
||||||
<CarouselNavButtons
|
<CarouselNavButtons
|
||||||
categorySlug={categorySlug}
|
categorySlug={categorySlug}
|
||||||
carouselRefs={carouselRefs}
|
carouselRefs={carouselRefs}
|
||||||
hasOverflow={overflowStates[categorySlug]}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useEffect, useMemo, useRef, useState } from "react";
|
import React, { useMemo, useRef, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { EditButton } from "@/components/buttons/EditButton";
|
import { EditButton } from "@/components/buttons/EditButton";
|
||||||
|
|
@ -42,9 +42,6 @@ export function WatchingCarousel({
|
||||||
const removeItem = useProgressStore((s) => s.removeItem);
|
const removeItem = useProgressStore((s) => s.removeItem);
|
||||||
const pressTimerRef = useRef<NodeJS.Timeout | null>(null);
|
const pressTimerRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
|
||||||
// Track overflow state
|
|
||||||
const [hasOverflow, setHasOverflow] = useState(false);
|
|
||||||
|
|
||||||
const { isMobile } = useIsMobile();
|
const { isMobile } = useIsMobile();
|
||||||
|
|
||||||
const itemsLength = useProgressStore((state) => {
|
const itemsLength = useProgressStore((state) => {
|
||||||
|
|
@ -125,38 +122,6 @@ export function WatchingCarousel({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to check overflow for the carousel
|
|
||||||
const checkOverflow = (element: HTMLDivElement | null) => {
|
|
||||||
if (!element) {
|
|
||||||
setHasOverflow(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasHorizontalOverflow = element.scrollWidth > element.clientWidth;
|
|
||||||
setHasOverflow(hasHorizontalOverflow);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function to set carousel ref and check overflow
|
|
||||||
const setCarouselRef = (element: HTMLDivElement | null) => {
|
|
||||||
carouselRefs.current[categorySlug] = element;
|
|
||||||
|
|
||||||
// Check overflow after a short delay to ensure content is rendered
|
|
||||||
setTimeout(() => checkOverflow(element), 100);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Effect to recheck overflow on window resize
|
|
||||||
useEffect(() => {
|
|
||||||
const handleResize = () => {
|
|
||||||
const element = carouselRefs.current[categorySlug];
|
|
||||||
if (element) {
|
|
||||||
checkOverflow(element);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener("resize", handleResize);
|
|
||||||
return () => window.removeEventListener("resize", handleResize);
|
|
||||||
}, [carouselRefs, categorySlug]);
|
|
||||||
|
|
||||||
if (itemsLength === 0) return null;
|
if (itemsLength === 0) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -178,7 +143,9 @@ export function WatchingCarousel({
|
||||||
<div
|
<div
|
||||||
id={`carousel-${categorySlug}`}
|
id={`carousel-${categorySlug}`}
|
||||||
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"
|
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"
|
||||||
ref={setCarouselRef}
|
ref={(el) => {
|
||||||
|
carouselRefs.current[categorySlug] = el;
|
||||||
|
}}
|
||||||
onWheel={handleWheel}
|
onWheel={handleWheel}
|
||||||
>
|
>
|
||||||
<div className="md:w-12" />
|
<div className="md:w-12" />
|
||||||
|
|
@ -219,7 +186,6 @@ export function WatchingCarousel({
|
||||||
<CarouselNavButtons
|
<CarouselNavButtons
|
||||||
categorySlug={categorySlug}
|
categorySlug={categorySlug}
|
||||||
carouselRefs={carouselRefs}
|
carouselRefs={carouselRefs}
|
||||||
hasOverflow={hasOverflow}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue