fix homepage layout and carousels

This commit is contained in:
Pas 2025-06-01 19:04:14 -06:00
parent 3cc435332c
commit b8ca66b4cb
7 changed files with 60 additions and 177 deletions

View file

@ -70,7 +70,6 @@ export function HomePage() {
const enableCarouselView = usePreferencesStore( const enableCarouselView = usePreferencesStore(
(state) => state.enableCarouselView, (state) => state.enableCarouselView,
); );
const isMobile = window.innerWidth < 768;
const handleClick = (path: To) => { const handleClick = (path: To) => {
window.scrollTo(0, 0); window.scrollTo(0, 0);
@ -85,23 +84,8 @@ export function HomePage() {
detailsModal.show(); detailsModal.show();
}; };
// const { loggedIn } = useAuth(); // Adjust padding for popup show button based on logged in state
return ( return (
<HomeLayout showBg={showBg}> <HomeLayout showBg={showBg}>
{/* <a
onClick={() => modal.show()}
className={` text-white tabbable rounded-full z-50 fixed top-5 ${
loggedIn
? "right-[7.5rem] lg:right-[12.5rem] lg:text-2xl"
: "right-[7.5rem] text-xl lg:text-lg"
}`}
style={{ animation: "pulse 1s infinite" }}
>
<IconPill icon={Icons.WARNING}>
<span className="font-bold select-none">READ</span>
</IconPill>
</a> */}
<div className="mb-2"> <div className="mb-2">
<Helmet> <Helmet>
<style type="text/css">{` <style type="text/css">{`
@ -112,97 +96,7 @@ export function HomePage() {
<title>{t("global.name")}</title> <title>{t("global.name")}</title>
</Helmet> </Helmet>
{/* Popup {/* Page Header */}
<FancyModal
id="notice"
title="We're changing our backend server!"
oneTime
>
<div>
<p>
On <strong>January 8th</strong>, the backend server will change
from:
</p>
<p>
<strong>server.vidbinge.com</strong> {" "}
<strong>server.fifthwit.tech</strong>
</p>
<br />
<p>
You will need to <strong>migrate your account </strong> to the new
server or choose to continue using the old server by updating your
settings.
</p>
<br />
<p>
<strong>What You Need to Know:</strong>
</p>
<ul>
<li>
1. <strong>Migrating Your Account:</strong> Your data (e.g.,
bookmarks) will not be automatically transferred. You&apos;ll
need to migrate your account from the settings page. Or from
below.
</li>
<li>
2. <strong>Staying on the Old Server:</strong> If you don&apos;t
want to change to the new server, your data will remain safe on{" "}
<strong>server.vidbinge.com</strong>. You can change the Backend
URL in your settings to &quot;https://server.vidbinge.com&quot;.
</li>
</ul>
<br />
<p>
<strong>Steps to Move Your Data:</strong>
</p>
<ol>
<li>
1. Log into your account on <strong>server.vidbinge.com</strong>
.
</li>
<li>
(If you already are logged in, press here:{" "}
<a href="/migration" className="text-type-link">
Migrate my data.
</a>
)
</li>
<li>
2. Go to the <strong>Settings</strong> page.
</li>
<li>
3. Scroll down to{" "}
<strong>Connections &gt; Custom Server</strong>.
</li>
<li>
3. Press the &quot;Migrate my data to a new server.&quot;
button.
</li>
<li>
4. Enter the new server url:{" "}
<strong>https://server.fifthwit.tech</strong> and press
&quot;Migrate&quot;.
</li>
<li>5. Login to your account with the same passphrase!</li>
</ol>
<br />
<p>
Thank you for your understanding and support during this
transition! If you have questions or need help, feel free to reach
out on the{" "}
<a
href="https://discord.com/invite/7z6znYgrTG"
target="_blank"
rel="noopener noreferrer"
className="text-type-link"
>
P-Stream Discord
</a>
!
</p>
</div>
</FancyModal>
*/}
{enableFeatured ? ( {enableFeatured ? (
<FeaturedCarousel <FeaturedCarousel
forcedCategory="editorpicks" forcedCategory="editorpicks"
@ -223,59 +117,64 @@ export function HomePage() {
showTitle showTitle
/> />
)} )}
{conf().SHOW_AD ? <AdsPart /> : null} {conf().SHOW_AD ? <AdsPart /> : null}
</div> </div>
<WideContainer ultraWide={enableCarouselView}>
{s.loading ? ( {/* Search */}
<SearchLoadingPart /> {search && (
) : s.searching ? ( <WideContainer>
enableCarouselView ? ( {s.loading ? (
<WideContainer> <SearchLoadingPart />
) : (
s.searching && (
<SearchListPart <SearchListPart
searchQuery={search} searchQuery={search}
onShowDetails={handleShowDetails} onShowDetails={handleShowDetails}
/> />
</WideContainer> )
) : ( )}
<SearchListPart </WideContainer>
searchQuery={search} )}
{/* User Content */}
{!search &&
(enableCarouselView ? (
<WideContainer ultraWide>
<WatchingCarousel
carouselRefs={carouselRefs}
onShowDetails={handleShowDetails} onShowDetails={handleShowDetails}
/> />
) <BookmarksCarousel
carouselRefs={carouselRefs}
onShowDetails={handleShowDetails}
/>
</WideContainer>
) : ( ) : (
<div className="flex flex-col gap-8"> <WideContainer>
{enableCarouselView ? ( <div className="flex flex-col gap-8">
<> <WatchingPart
<WatchingCarousel onItemsChange={setShowWatching}
isMobile={isMobile} onShowDetails={handleShowDetails}
carouselRefs={carouselRefs} />
onShowDetails={handleShowDetails} <BookmarksPart
/> onItemsChange={setShowBookmarks}
<BookmarksCarousel onShowDetails={handleShowDetails}
isMobile={isMobile} />
carouselRefs={carouselRefs} </div>
onShowDetails={handleShowDetails} </WideContainer>
/> ))}
</>
) : ( {/* Under user content */}
<> <WideContainer ultraWide>
<WatchingPart {/* Empty text */}
onItemsChange={setShowWatching}
onShowDetails={handleShowDetails}
/>
<BookmarksPart
onItemsChange={setShowBookmarks}
onShowDetails={handleShowDetails}
/>
</>
)}
</div>
)}
{!(showBookmarks || showWatching) && !enableDiscover ? ( {!(showBookmarks || showWatching) && !enableDiscover ? (
<div className="flex flex-col translate-y-[-30px] items-center justify-center pt-20"> <div className="flex flex-col translate-y-[-30px] items-center justify-center pt-20">
<p className="text-[18.5px] pb-3">{emptyText}</p> <p className="text-[18.5px] pb-3">{emptyText}</p>
</div> </div>
) : null} ) : null}
{/* Discover Spacing */}
{enableDiscover && {enableDiscover &&
(enableFeatured ? ( (enableFeatured ? (
<div className="pb-4" /> <div className="pb-4" />
@ -285,6 +184,8 @@ export function HomePage() {
<div className="pb-20" /> <div className="pb-20" />
))} ))}
{/* there... perfect. */} {/* there... perfect. */}
{/* Discover section or discover button */}
{enableDiscover && !search ? ( {enableDiscover && !search ? (
<DiscoverContent /> <DiscoverContent />
) : ( ) : (

View file

@ -20,7 +20,6 @@ interface LazyMediaCarouselProps {
category?: Category; category?: Category;
genre?: Genre; genre?: Genre;
mediaType: "movie" | "tv"; mediaType: "movie" | "tv";
isMobile: boolean;
carouselRefs: React.MutableRefObject<{ carouselRefs: React.MutableRefObject<{
[key: string]: HTMLDivElement | null; [key: string]: HTMLDivElement | null;
}>; }>;
@ -37,7 +36,6 @@ export function LazyMediaCarousel({
category, category,
genre, genre,
mediaType, mediaType,
isMobile,
carouselRefs, carouselRefs,
onShowDetails, onShowDetails,
preloadedMedia, preloadedMedia,
@ -121,7 +119,6 @@ export function LazyMediaCarousel({
medias={medias} medias={medias}
category={categoryName} category={categoryName}
isTVShow={mediaType === "tv"} isTVShow={mediaType === "tv"}
isMobile={isMobile}
carouselRefs={carouselRefs} carouselRefs={carouselRefs}
onShowDetails={onShowDetails} onShowDetails={onShowDetails}
genreId={genreId} genreId={genreId}

View file

@ -8,6 +8,7 @@ import { Dropdown, OptionItem } from "@/components/form/Dropdown";
import { Icon, Icons } from "@/components/Icon"; import { Icon, Icons } from "@/components/Icon";
import { MediaCard } from "@/components/media/MediaCard"; import { MediaCard } from "@/components/media/MediaCard";
import { Flare } from "@/components/utils/Flare"; import { Flare } from "@/components/utils/Flare";
import { useIsMobile } from "@/hooks/useIsMobile";
import { Media } from "@/pages/discover/common"; import { Media } from "@/pages/discover/common";
import { useDiscoverStore } from "@/stores/discover"; import { useDiscoverStore } from "@/stores/discover";
import { MediaItem } from "@/utils/mediaTypes"; import { MediaItem } from "@/utils/mediaTypes";
@ -19,7 +20,6 @@ interface MediaCarouselProps {
medias: Media[]; medias: Media[];
category: string; category: string;
isTVShow: boolean; isTVShow: boolean;
isMobile: boolean;
carouselRefs: React.MutableRefObject<{ carouselRefs: React.MutableRefObject<{
[key: string]: HTMLDivElement | null; [key: string]: HTMLDivElement | null;
}>; }>;
@ -79,7 +79,6 @@ export function MediaCarousel({
medias, medias,
category, category,
isTVShow, isTVShow,
isMobile,
carouselRefs, carouselRefs,
onShowDetails, onShowDetails,
genreId, genreId,
@ -99,6 +98,8 @@ export function MediaCarousel({
); );
const categorySlug = `${category.toLowerCase().replace(/[^a-z0-9]+/g, "-")}-${isTVShow ? "tv" : "movie"}`; const categorySlug = `${category.toLowerCase().replace(/[^a-z0-9]+/g, "-")}-${isTVShow ? "tv" : "movie"}`;
const browser = !!window.chrome; const browser = !!window.chrome;
const { isMobile } = useIsMobile();
let isScrolling = false; let isScrolling = false;
const handleWheel = (e: React.WheelEvent) => { const handleWheel = (e: React.WheelEvent) => {

View file

@ -5,7 +5,6 @@ import { get } from "@/backend/metadata/tmdb";
import { WideContainer } from "@/components/layout/WideContainer"; import { WideContainer } from "@/components/layout/WideContainer";
import { DetailsModal } from "@/components/overlays/DetailsModal"; import { DetailsModal } from "@/components/overlays/DetailsModal";
import { useModal } from "@/components/overlays/Modal"; import { useModal } from "@/components/overlays/Modal";
import { useIsMobile } from "@/hooks/useIsMobile";
import { import {
Genre, Genre,
Movie, Movie,
@ -168,8 +167,6 @@ export function DiscoverContent() {
const carouselRefs = useRef<{ [key: string]: HTMLDivElement | null }>({}); const carouselRefs = useRef<{ [key: string]: HTMLDivElement | null }>({});
const { isMobile } = useIsMobile();
const userLanguage = useLanguageStore.getState().language; const userLanguage = useLanguageStore.getState().language;
const formattedLanguage = getTmdbLanguageCode(userLanguage); const formattedLanguage = getTmdbLanguageCode(userLanguage);
@ -505,7 +502,6 @@ export function DiscoverContent() {
preloadedMedia={filteredGenreMovies} preloadedMedia={filteredGenreMovies}
title="Editor Picks" title="Editor Picks"
mediaType="movie" mediaType="movie"
isMobile={isMobile}
carouselRefs={carouselRefs} carouselRefs={carouselRefs}
onShowDetails={handleShowDetails} onShowDetails={handleShowDetails}
moreContent moreContent
@ -514,7 +510,6 @@ export function DiscoverContent() {
preloadedMedia={filteredGenreTVShows} preloadedMedia={filteredGenreTVShows}
title="Editor Picks" title="Editor Picks"
mediaType="tv" mediaType="tv"
isMobile={isMobile}
carouselRefs={carouselRefs} carouselRefs={carouselRefs}
onShowDetails={handleShowDetails} onShowDetails={handleShowDetails}
moreContent moreContent
@ -533,7 +528,6 @@ export function DiscoverContent() {
medias={movieRecommendations} medias={movieRecommendations}
category={movieRecommendationTitle} category={movieRecommendationTitle}
isTVShow={false} isTVShow={false}
isMobile={isMobile}
carouselRefs={carouselRefs} carouselRefs={carouselRefs}
onShowDetails={handleShowDetails} onShowDetails={handleShowDetails}
moreLink={`/discover/more/recommendations/${movieRecommendationSourceId}/movie`} moreLink={`/discover/more/recommendations/${movieRecommendationSourceId}/movie`}
@ -548,7 +542,6 @@ export function DiscoverContent() {
<LazyMediaCarousel <LazyMediaCarousel
category={categories[0]} category={categories[0]}
mediaType="movie" mediaType="movie"
isMobile={isMobile}
carouselRefs={carouselRefs} carouselRefs={carouselRefs}
onShowDetails={handleShowDetails} onShowDetails={handleShowDetails}
moreContent moreContent
@ -558,7 +551,6 @@ export function DiscoverContent() {
<LazyMediaCarousel <LazyMediaCarousel
category={categories[1]} category={categories[1]}
mediaType="movie" mediaType="movie"
isMobile={isMobile}
carouselRefs={carouselRefs} carouselRefs={carouselRefs}
onShowDetails={handleShowDetails} onShowDetails={handleShowDetails}
moreContent moreContent
@ -568,7 +560,6 @@ export function DiscoverContent() {
<LazyMediaCarousel <LazyMediaCarousel
category={categories[2]} category={categories[2]}
mediaType="movie" mediaType="movie"
isMobile={isMobile}
carouselRefs={carouselRefs} carouselRefs={carouselRefs}
onShowDetails={handleShowDetails} onShowDetails={handleShowDetails}
moreContent moreContent
@ -579,7 +570,6 @@ export function DiscoverContent() {
medias={providerMovies} medias={providerMovies}
category={`Movies on ${selectedProvider.name || ""}`} category={`Movies on ${selectedProvider.name || ""}`}
isTVShow={false} isTVShow={false}
isMobile={isMobile}
carouselRefs={carouselRefs} carouselRefs={carouselRefs}
onShowDetails={handleShowDetails} onShowDetails={handleShowDetails}
relatedButtons={MOVIE_PROVIDERS.map((p) => ({ relatedButtons={MOVIE_PROVIDERS.map((p) => ({
@ -596,7 +586,6 @@ export function DiscoverContent() {
medias={filteredGenreMovies} medias={filteredGenreMovies}
category={`${selectedGenre.name || ""}`} category={`${selectedGenre.name || ""}`}
isTVShow={false} isTVShow={false}
isMobile={isMobile}
carouselRefs={carouselRefs} carouselRefs={carouselRefs}
onShowDetails={handleShowDetails} onShowDetails={handleShowDetails}
relatedButtons={genres.map((g) => ({ relatedButtons={genres.map((g) => ({
@ -621,7 +610,6 @@ export function DiscoverContent() {
medias={tvRecommendations} medias={tvRecommendations}
category={tvRecommendationTitle} category={tvRecommendationTitle}
isTVShow isTVShow
isMobile={isMobile}
carouselRefs={carouselRefs} carouselRefs={carouselRefs}
onShowDetails={handleShowDetails} onShowDetails={handleShowDetails}
moreLink={`/discover/more/recommendations/${tvRecommendationSourceId}/tv`} moreLink={`/discover/more/recommendations/${tvRecommendationSourceId}/tv`}
@ -636,7 +624,6 @@ export function DiscoverContent() {
<LazyMediaCarousel <LazyMediaCarousel
category={tvCategories[0]} category={tvCategories[0]}
mediaType="tv" mediaType="tv"
isMobile={isMobile}
carouselRefs={carouselRefs} carouselRefs={carouselRefs}
onShowDetails={handleShowDetails} onShowDetails={handleShowDetails}
moreContent moreContent
@ -646,7 +633,6 @@ export function DiscoverContent() {
<LazyMediaCarousel <LazyMediaCarousel
category={tvCategories[1]} category={tvCategories[1]}
mediaType="tv" mediaType="tv"
isMobile={isMobile}
carouselRefs={carouselRefs} carouselRefs={carouselRefs}
onShowDetails={handleShowDetails} onShowDetails={handleShowDetails}
moreContent moreContent
@ -656,7 +642,6 @@ export function DiscoverContent() {
<LazyMediaCarousel <LazyMediaCarousel
category={tvCategories[2]} category={tvCategories[2]}
mediaType="tv" mediaType="tv"
isMobile={isMobile}
carouselRefs={carouselRefs} carouselRefs={carouselRefs}
onShowDetails={handleShowDetails} onShowDetails={handleShowDetails}
moreContent moreContent
@ -667,7 +652,6 @@ export function DiscoverContent() {
medias={providerTVShows} medias={providerTVShows}
category={`Shows on ${selectedProvider.name || ""}`} category={`Shows on ${selectedProvider.name || ""}`}
isTVShow isTVShow
isMobile={isMobile}
carouselRefs={carouselRefs} carouselRefs={carouselRefs}
onShowDetails={handleShowDetails} onShowDetails={handleShowDetails}
relatedButtons={TV_PROVIDERS.map((p) => ({ relatedButtons={TV_PROVIDERS.map((p) => ({
@ -684,7 +668,6 @@ export function DiscoverContent() {
medias={filteredGenreTVShows} medias={filteredGenreTVShows}
category={`${selectedGenre.name || ""}`} category={`${selectedGenre.name || ""}`}
isTVShow isTVShow
isMobile={isMobile}
carouselRefs={carouselRefs} carouselRefs={carouselRefs}
onShowDetails={handleShowDetails} onShowDetails={handleShowDetails}
relatedButtons={tvGenres.map((g) => ({ relatedButtons={tvGenres.map((g) => ({

View file

@ -4,15 +4,14 @@ import { useTranslation } from "react-i18next";
import { EditButton } from "@/components/buttons/EditButton"; import { EditButton } from "@/components/buttons/EditButton";
import { Icons } from "@/components/Icon"; import { Icons } from "@/components/Icon";
import { SectionHeading } from "@/components/layout/SectionHeading"; import { SectionHeading } from "@/components/layout/SectionHeading";
import { MediaCard } from "@/components/media/MediaCard";
import { WatchedMediaCard } from "@/components/media/WatchedMediaCard"; import { WatchedMediaCard } from "@/components/media/WatchedMediaCard";
import { useIsMobile } from "@/hooks/useIsMobile";
import { CarouselNavButtons } from "@/pages/discover/components/CarouselNavButtons"; import { CarouselNavButtons } from "@/pages/discover/components/CarouselNavButtons";
import { useBookmarkStore } from "@/stores/bookmarks"; import { useBookmarkStore } from "@/stores/bookmarks";
import { useProgressStore } from "@/stores/progress"; import { useProgressStore } from "@/stores/progress";
import { MediaItem } from "@/utils/mediaTypes"; import { MediaItem } from "@/utils/mediaTypes";
interface BookmarksCarouselProps { interface BookmarksCarouselProps {
isMobile: boolean;
carouselRefs: React.MutableRefObject<{ carouselRefs: React.MutableRefObject<{
[key: string]: HTMLDivElement | null; [key: string]: HTMLDivElement | null;
}>; }>;
@ -33,7 +32,6 @@ function MediaCardSkeleton() {
} }
export function BookmarksCarousel({ export function BookmarksCarousel({
isMobile,
carouselRefs, carouselRefs,
onShowDetails, onShowDetails,
}: BookmarksCarouselProps) { }: BookmarksCarouselProps) {
@ -44,6 +42,8 @@ export function BookmarksCarousel({
const removeBookmark = useBookmarkStore((s) => s.removeBookmark); const removeBookmark = useBookmarkStore((s) => s.removeBookmark);
const pressTimerRef = useRef<NodeJS.Timeout | null>(null); const pressTimerRef = useRef<NodeJS.Timeout | null>(null);
const { isMobile } = useIsMobile();
const bookmarksLength = useBookmarkStore( const bookmarksLength = useBookmarkStore(
(state) => Object.keys(state.bookmarks).length, (state) => Object.keys(state.bookmarks).length,
); );
@ -133,7 +133,7 @@ export function BookmarksCarousel({
<SectionHeading <SectionHeading
title={t("home.bookmarks.sectionTitle") || "Bookmarks"} title={t("home.bookmarks.sectionTitle") || "Bookmarks"}
icon={Icons.BOOKMARK} icon={Icons.BOOKMARK}
className="ml-2 md:ml-8 mt-2 -mb-10" className="ml-2 md:ml-8 mt-2 -mb-5"
> >
<div className="mr-6"> <div className="mr-6">
<EditButton <EditButton

View file

@ -5,13 +5,13 @@ import { EditButton } from "@/components/buttons/EditButton";
import { Icons } from "@/components/Icon"; import { Icons } from "@/components/Icon";
import { SectionHeading } from "@/components/layout/SectionHeading"; import { SectionHeading } from "@/components/layout/SectionHeading";
import { WatchedMediaCard } from "@/components/media/WatchedMediaCard"; import { WatchedMediaCard } from "@/components/media/WatchedMediaCard";
import { useIsMobile } from "@/hooks/useIsMobile";
import { CarouselNavButtons } from "@/pages/discover/components/CarouselNavButtons"; import { CarouselNavButtons } from "@/pages/discover/components/CarouselNavButtons";
import { useProgressStore } from "@/stores/progress"; import { useProgressStore } from "@/stores/progress";
import { shouldShowProgress } from "@/stores/progress/utils"; import { shouldShowProgress } from "@/stores/progress/utils";
import { MediaItem } from "@/utils/mediaTypes"; import { MediaItem } from "@/utils/mediaTypes";
interface WatchingCarouselProps { interface WatchingCarouselProps {
isMobile: boolean;
carouselRefs: React.MutableRefObject<{ carouselRefs: React.MutableRefObject<{
[key: string]: HTMLDivElement | null; [key: string]: HTMLDivElement | null;
}>; }>;
@ -32,7 +32,6 @@ function MediaCardSkeleton() {
} }
export function WatchingCarousel({ export function WatchingCarousel({
isMobile,
carouselRefs, carouselRefs,
onShowDetails, onShowDetails,
}: WatchingCarouselProps) { }: WatchingCarouselProps) {
@ -43,6 +42,8 @@ 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);
const { isMobile } = useIsMobile();
const itemsLength = useProgressStore((state) => { const itemsLength = useProgressStore((state) => {
return Object.entries(state.items).filter( return Object.entries(state.items).filter(
(entry) => shouldShowProgress(entry[1]).show, (entry) => shouldShowProgress(entry[1]).show,
@ -125,7 +126,7 @@ export function WatchingCarousel({
<SectionHeading <SectionHeading
title={t("home.continueWatching.sectionTitle")} title={t("home.continueWatching.sectionTitle")}
icon={Icons.CLOCK} icon={Icons.CLOCK}
className="ml-2 md:ml-8 mt-2 -mb-10" className="ml-2 md:ml-8 mt-2 -mb-5"
> >
<div className="mr-6"> <div className="mr-6">
<EditButton <EditButton

View file

@ -20,7 +20,7 @@ function SearchSuffix(props: { failed?: boolean; results?: number }) {
const icon: Icons = props.failed ? Icons.WARNING : Icons.EYE_SLASH; const icon: Icons = props.failed ? Icons.WARNING : Icons.EYE_SLASH;
return ( return (
<div className="mb-24 mt-40 flex flex-col items-center justify-center space-y-3 text-center"> <div className="mt-40 flex flex-col items-center justify-center space-y-3 text-center">
<IconPatch <IconPatch
icon={icon} icon={icon}
className={`text-xl ${ className={`text-xl ${
@ -35,7 +35,7 @@ function SearchSuffix(props: { failed?: boolean; results?: number }) {
<> <>
<p>{t("home.search.allResults")}</p> <p>{t("home.search.allResults")}</p>
<Button <Button
className="px-py p-[0.3em] mt-3 rounded-xl text-type-dimmed box-content text-[17px] bg-largeCard-background text-buttons-secondaryText justify-center items-center" className="px-py p-[0.3em] mt-3 rounded-xl text-type-dimmed box-content text-[17px] bg-largeCard-background justify-center items-center"
onClick={() => navigate("/discover")} onClick={() => navigate("/discover")}
> >
{t("home.search.discoverMore")} {t("home.search.discoverMore")}