mirror of
https://github.com/p-stream/p-stream.git
synced 2026-04-21 01:22:23 +00:00
Revert "feat: hide the arrow buttons on scroll lists when at either end of the list"
This reverts commit 4f781f9736.
This commit is contained in:
parent
2084033b13
commit
8d8a5bdb66
5 changed files with 74 additions and 248 deletions
|
|
@ -45,39 +45,6 @@ export function EpisodeCarousel({
|
||||||
const updateItem = useProgressStore((s) => s.updateItem);
|
const updateItem = useProgressStore((s) => s.updateItem);
|
||||||
const confirmModal = useModal("season-watch-confirm");
|
const confirmModal = useModal("season-watch-confirm");
|
||||||
|
|
||||||
const [canScrollLeft, setCanScrollLeft] = useState(false);
|
|
||||||
const [canScrollRight, setCanScrollRight] = useState(false);
|
|
||||||
|
|
||||||
const updateScrollState = () => {
|
|
||||||
if (!carouselRef.current) {
|
|
||||||
setCanScrollLeft(false);
|
|
||||||
setCanScrollRight(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { scrollLeft, scrollWidth, clientWidth } = carouselRef.current;
|
|
||||||
const isAtStart = scrollLeft <= 1;
|
|
||||||
const isAtEnd = scrollLeft + clientWidth >= scrollWidth - 1;
|
|
||||||
|
|
||||||
setCanScrollLeft(!isAtStart);
|
|
||||||
setCanScrollRight(!isAtEnd);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const carousel = carouselRef.current;
|
|
||||||
if (!carousel) return;
|
|
||||||
|
|
||||||
updateScrollState();
|
|
||||||
|
|
||||||
carousel.addEventListener("scroll", updateScrollState);
|
|
||||||
window.addEventListener("resize", updateScrollState);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
carousel.removeEventListener("scroll", updateScrollState);
|
|
||||||
window.removeEventListener("resize", updateScrollState);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleScroll = (direction: "left" | "right") => {
|
const handleScroll = (direction: "left" | "right") => {
|
||||||
if (!carouselRef.current) return;
|
if (!carouselRef.current) return;
|
||||||
|
|
||||||
|
|
@ -563,17 +530,15 @@ export function EpisodeCarousel({
|
||||||
{/* Episodes Carousel */}
|
{/* Episodes Carousel */}
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
{/* Left scroll button */}
|
{/* Left scroll button */}
|
||||||
{canScrollLeft && (
|
<div className="absolute left-0 top-1/2 transform -translate-y-1/2 z-10 px-4 hidden lg:block">
|
||||||
<div className="absolute left-0 top-1/2 transform -translate-y-1/2 z-10 px-4 hidden lg:block">
|
<button
|
||||||
<button
|
type="button"
|
||||||
type="button"
|
className="p-2 bg-black/80 hover:bg-video-context-hoverColor transition-colors rounded-full border border-video-context-border backdrop-blur-sm"
|
||||||
className="p-2 bg-black/80 hover:bg-video-context-hoverColor transition-colors rounded-full border border-video-context-border backdrop-blur-sm"
|
onClick={() => handleScroll("left")}
|
||||||
onClick={() => handleScroll("left")}
|
>
|
||||||
>
|
<Icon icon={Icons.CHEVRON_LEFT} className="text-white/80" />
|
||||||
<Icon icon={Icons.CHEVRON_LEFT} className="text-white/80" />
|
</button>
|
||||||
</button>
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
ref={carouselRef}
|
ref={carouselRef}
|
||||||
|
|
@ -818,17 +783,15 @@ export function EpisodeCarousel({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right scroll button */}
|
{/* Right scroll button */}
|
||||||
{canScrollRight && (
|
<div className="absolute right-0 top-1/2 transform -translate-y-1/2 z-10 px-4 hidden lg:block">
|
||||||
<div className="absolute right-0 top-1/2 transform -translate-y-1/2 z-10 px-4 hidden lg:block">
|
<button
|
||||||
<button
|
type="button"
|
||||||
type="button"
|
className="p-2 bg-black/80 hover:bg-video-context-hoverColor transition-colors rounded-full border border-video-context-border backdrop-blur-sm"
|
||||||
className="p-2 bg-black/80 hover:bg-video-context-hoverColor transition-colors rounded-full border border-video-context-border backdrop-blur-sm"
|
onClick={() => handleScroll("right")}
|
||||||
onClick={() => handleScroll("right")}
|
>
|
||||||
>
|
<Icon icon={Icons.CHEVRON_RIGHT} className="text-white/80" />
|
||||||
<Icon icon={Icons.CHEVRON_RIGHT} className="text-white/80" />
|
</button>
|
||||||
</button>
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -766,39 +766,6 @@ export function EpisodesView({
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
const [canScrollLeft, setCanScrollLeft] = useState(false);
|
|
||||||
const [canScrollRight, setCanScrollRight] = useState(false);
|
|
||||||
|
|
||||||
const updateScrollState = () => {
|
|
||||||
if (!carouselRef.current) {
|
|
||||||
setCanScrollLeft(false);
|
|
||||||
setCanScrollRight(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { scrollLeft, scrollWidth, clientWidth } = carouselRef.current;
|
|
||||||
const isAtStart = scrollLeft <= 1;
|
|
||||||
const isAtEnd = scrollLeft + clientWidth >= scrollWidth - 1;
|
|
||||||
|
|
||||||
setCanScrollLeft(!isAtStart);
|
|
||||||
setCanScrollRight(!isAtEnd);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const carousel = carouselRef.current;
|
|
||||||
if (!carousel) return;
|
|
||||||
|
|
||||||
updateScrollState();
|
|
||||||
|
|
||||||
carousel.addEventListener("scroll", updateScrollState);
|
|
||||||
window.addEventListener("resize", updateScrollState);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
carousel.removeEventListener("scroll", updateScrollState);
|
|
||||||
window.removeEventListener("resize", updateScrollState);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleScroll = (direction: "left" | "right") => {
|
const handleScroll = (direction: "left" | "right") => {
|
||||||
if (!carouselRef.current) return;
|
if (!carouselRef.current) return;
|
||||||
|
|
||||||
|
|
@ -949,22 +916,20 @@ export function EpisodesView({
|
||||||
content = (
|
content = (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
{/* Horizontal scroll buttons */}
|
{/* Horizontal scroll buttons */}
|
||||||
{canScrollLeft && (
|
<div
|
||||||
<div
|
className={classNames(
|
||||||
className={classNames(
|
"absolute left-0 top-1/2 transform -translate-y-1/2 z-10 px-4",
|
||||||
"absolute left-0 top-1/2 transform -translate-y-1/2 z-10 px-4",
|
forceCompactEpisodeView ? "hidden" : "hidden lg:block",
|
||||||
forceCompactEpisodeView ? "hidden" : "hidden lg:block",
|
)}
|
||||||
)}
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="p-2 bg-black/80 hover:bg-video-context-hoverColor transition-colors rounded-full border border-video-context-border backdrop-blur-sm"
|
||||||
|
onClick={() => handleScroll("left")}
|
||||||
>
|
>
|
||||||
<button
|
<Icon icon={Icons.CHEVRON_LEFT} className="text-white/80" />
|
||||||
type="button"
|
</button>
|
||||||
className="p-2 bg-black/80 hover:bg-video-context-hoverColor transition-colors rounded-full border border-video-context-border backdrop-blur-sm"
|
</div>
|
||||||
onClick={() => handleScroll("left")}
|
|
||||||
>
|
|
||||||
<Icon icon={Icons.CHEVRON_LEFT} className="text-white/80" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
ref={carouselRef}
|
ref={carouselRef}
|
||||||
|
|
@ -1031,22 +996,20 @@ export function EpisodesView({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right scroll button */}
|
{/* Right scroll button */}
|
||||||
{canScrollRight && (
|
<div
|
||||||
<div
|
className={classNames(
|
||||||
className={classNames(
|
"absolute right-0 top-1/2 transform -translate-y-1/2 z-10 px-4",
|
||||||
"absolute right-0 top-1/2 transform -translate-y-1/2 z-10 px-4",
|
forceCompactEpisodeView ? "hidden" : "hidden lg:block",
|
||||||
forceCompactEpisodeView ? "hidden" : "hidden lg:block",
|
)}
|
||||||
)}
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="p-2 bg-black/80 hover:bg-video-context-hoverColor transition-colors rounded-full border border-video-context-border backdrop-blur-sm"
|
||||||
|
onClick={() => handleScroll("right")}
|
||||||
>
|
>
|
||||||
<button
|
<Icon icon={Icons.CHEVRON_RIGHT} className="text-white/80" />
|
||||||
type="button"
|
</button>
|
||||||
className="p-2 bg-black/80 hover:bg-video-context-hoverColor transition-colors rounded-full border border-video-context-border backdrop-blur-sm"
|
</div>
|
||||||
onClick={() => handleScroll("right")}
|
|
||||||
>
|
|
||||||
<Icon icon={Icons.CHEVRON_RIGHT} className="text-white/80" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
import { useCallback, useEffect, useState } from "react";
|
|
||||||
|
|
||||||
import { Icon, Icons } from "@/components/Icon";
|
import { Icon, Icons } from "@/components/Icon";
|
||||||
import { Flare } from "@/components/utils/Flare";
|
import { Flare } from "@/components/utils/Flare";
|
||||||
|
|
||||||
|
|
@ -13,12 +11,9 @@ interface CarouselNavButtonsProps {
|
||||||
interface NavButtonProps {
|
interface NavButtonProps {
|
||||||
direction: "left" | "right";
|
direction: "left" | "right";
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
visible: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function NavButton({ direction, onClick, visible }: NavButtonProps) {
|
function NavButton({ direction, onClick }: NavButtonProps) {
|
||||||
if (!visible) return null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|
@ -48,40 +43,6 @@ export function CarouselNavButtons({
|
||||||
categorySlug,
|
categorySlug,
|
||||||
carouselRefs,
|
carouselRefs,
|
||||||
}: CarouselNavButtonsProps) {
|
}: CarouselNavButtonsProps) {
|
||||||
const [canScrollLeft, setCanScrollLeft] = useState(false);
|
|
||||||
const [canScrollRight, setCanScrollRight] = useState(false);
|
|
||||||
|
|
||||||
const updateScrollState = useCallback(() => {
|
|
||||||
const carousel = carouselRefs.current[categorySlug];
|
|
||||||
if (!carousel) {
|
|
||||||
setCanScrollLeft(false);
|
|
||||||
setCanScrollRight(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { scrollLeft, scrollWidth, clientWidth } = carousel;
|
|
||||||
const isAtStart = scrollLeft <= 1;
|
|
||||||
const isAtEnd = scrollLeft + clientWidth >= scrollWidth - 1;
|
|
||||||
|
|
||||||
setCanScrollLeft(!isAtStart);
|
|
||||||
setCanScrollRight(!isAtEnd);
|
|
||||||
}, [categorySlug, carouselRefs]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const carousel = carouselRefs.current[categorySlug];
|
|
||||||
if (!carousel) return;
|
|
||||||
|
|
||||||
updateScrollState();
|
|
||||||
|
|
||||||
carousel.addEventListener("scroll", updateScrollState);
|
|
||||||
window.addEventListener("resize", updateScrollState);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
carousel.removeEventListener("scroll", updateScrollState);
|
|
||||||
window.removeEventListener("resize", updateScrollState);
|
|
||||||
};
|
|
||||||
}, [categorySlug, carouselRefs, updateScrollState]);
|
|
||||||
|
|
||||||
const handleScroll = (direction: "left" | "right") => {
|
const handleScroll = (direction: "left" | "right") => {
|
||||||
const carousel = carouselRefs.current[categorySlug];
|
const carousel = carouselRefs.current[categorySlug];
|
||||||
if (!carousel) return;
|
if (!carousel) return;
|
||||||
|
|
@ -115,16 +76,8 @@ export function CarouselNavButtons({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NavButton
|
<NavButton direction="left" onClick={() => handleScroll("left")} />
|
||||||
direction="left"
|
<NavButton direction="right" onClick={() => handleScroll("right")} />
|
||||||
onClick={() => handleScroll("left")}
|
|
||||||
visible={canScrollLeft}
|
|
||||||
/>
|
|
||||||
<NavButton
|
|
||||||
direction="right"
|
|
||||||
onClick={() => handleScroll("right")}
|
|
||||||
visible={canScrollRight}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
import { useCallback, useEffect, useState } from "react";
|
|
||||||
|
|
||||||
import { Icon, Icons } from "@/components/Icon";
|
import { Icon, Icons } from "@/components/Icon";
|
||||||
|
|
||||||
interface CategoryButtonsProps {
|
interface CategoryButtonsProps {
|
||||||
|
|
@ -17,84 +15,34 @@ export function CategoryButtons({
|
||||||
isMobile,
|
isMobile,
|
||||||
showAlwaysScroll,
|
showAlwaysScroll,
|
||||||
}: CategoryButtonsProps) {
|
}: CategoryButtonsProps) {
|
||||||
const [canScrollLeft, setCanScrollLeft] = useState(false);
|
const renderScrollButton = (direction: "left" | "right") => (
|
||||||
const [canScrollRight, setCanScrollRight] = useState(false);
|
<div>
|
||||||
|
<button
|
||||||
const updateScrollState = useCallback(() => {
|
type="button"
|
||||||
const element = document.getElementById(`button-carousel-${categoryType}`);
|
className="flex items-center rounded-full px-4 text-white py-3"
|
||||||
if (!element) {
|
onClick={() => {
|
||||||
setCanScrollLeft(false);
|
const element = document.getElementById(
|
||||||
setCanScrollRight(false);
|
`button-carousel-${categoryType}`,
|
||||||
return;
|
);
|
||||||
}
|
if (element) {
|
||||||
|
element.scrollBy({
|
||||||
const { scrollLeft, scrollWidth, clientWidth } = element;
|
left: direction === "left" ? -200 : 200,
|
||||||
const isAtStart = scrollLeft <= 1;
|
behavior: "smooth",
|
||||||
const isAtEnd = scrollLeft + clientWidth >= scrollWidth - 1;
|
});
|
||||||
|
}
|
||||||
setCanScrollLeft(!isAtStart);
|
}}
|
||||||
setCanScrollRight(!isAtEnd);
|
>
|
||||||
}, [categoryType]);
|
<Icon
|
||||||
|
icon={direction === "left" ? Icons.CHEVRON_LEFT : Icons.CHEVRON_RIGHT}
|
||||||
useEffect(() => {
|
className="text-2xl rtl:-scale-x-100"
|
||||||
const element = document.getElementById(`button-carousel-${categoryType}`);
|
/>
|
||||||
if (!element) return;
|
</button>
|
||||||
|
</div>
|
||||||
updateScrollState();
|
);
|
||||||
|
|
||||||
element.addEventListener("scroll", updateScrollState);
|
|
||||||
window.addEventListener("resize", updateScrollState);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
element.removeEventListener("scroll", updateScrollState);
|
|
||||||
window.removeEventListener("resize", updateScrollState);
|
|
||||||
};
|
|
||||||
}, [categoryType, updateScrollState]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const timeoutId = setTimeout(() => {
|
|
||||||
updateScrollState();
|
|
||||||
}, 0);
|
|
||||||
return () => clearTimeout(timeoutId);
|
|
||||||
}, [categories, categoryType, updateScrollState]);
|
|
||||||
|
|
||||||
const renderScrollButton = (direction: "left" | "right") => {
|
|
||||||
const shouldShow = direction === "left" ? canScrollLeft : canScrollRight;
|
|
||||||
|
|
||||||
if (!shouldShow && !showAlwaysScroll && !isMobile) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="flex items-center rounded-full px-4 text-white py-3"
|
|
||||||
onClick={() => {
|
|
||||||
const element = document.getElementById(
|
|
||||||
`button-carousel-${categoryType}`,
|
|
||||||
);
|
|
||||||
if (element) {
|
|
||||||
element.scrollBy({
|
|
||||||
left: direction === "left" ? -200 : 200,
|
|
||||||
behavior: "smooth",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
icon={
|
|
||||||
direction === "left" ? Icons.CHEVRON_LEFT : Icons.CHEVRON_RIGHT
|
|
||||||
}
|
|
||||||
className="text-2xl rtl:-scale-x-100"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex overflow-x-auto">
|
<div className="flex overflow-x-auto">
|
||||||
{(showAlwaysScroll || isMobile || canScrollLeft) &&
|
{(showAlwaysScroll || isMobile) && renderScrollButton("left")}
|
||||||
renderScrollButton("left")}
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
id={`button-carousel-${categoryType}`}
|
id={`button-carousel-${categoryType}`}
|
||||||
|
|
@ -114,8 +62,7 @@ export function CategoryButtons({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{(showAlwaysScroll || isMobile || canScrollRight) &&
|
{(showAlwaysScroll || isMobile) && renderScrollButton("right")}
|
||||||
renderScrollButton("right")}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import { useProgressStore } from "@/stores/progress";
|
import { useProgressStore } from "@/stores/progress";
|
||||||
|
|
||||||
import { createVersionedStore } from "../migrations";
|
|
||||||
import { OldData, migrateV2Videos } from "./migrations/v2";
|
import { OldData, migrateV2Videos } from "./migrations/v2";
|
||||||
import { migrateV3Videos } from "./migrations/v3";
|
import { migrateV3Videos } from "./migrations/v3";
|
||||||
import { migrateV4Videos } from "./migrations/v4";
|
import { migrateV4Videos } from "./migrations/v4";
|
||||||
import { WatchedStoreData } from "./types";
|
import { WatchedStoreData } from "./types";
|
||||||
|
import { createVersionedStore } from "../migrations";
|
||||||
|
|
||||||
export const VideoProgressStore = createVersionedStore<WatchedStoreData>()
|
export const VideoProgressStore = createVersionedStore<WatchedStoreData>()
|
||||||
.setKey("video-progress")
|
.setKey("video-progress")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue