mirror of https://github.com/sussy-code/smov.git
add that skids improvments for discover page
This commit is contained in:
parent
495c52ed76
commit
525b30012d
9444
pnpm-lock.yaml
9444
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
||||||
// Based mfs only use only one 500 line file instead of ten 50 line files.
|
// Based mfs only use only one 500 line file instead of ten 50 line files.
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { Helmet } from "react-helmet-async";
|
import { Helmet } from "react-helmet-async";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
@ -21,7 +21,6 @@ import {
|
||||||
|
|
||||||
import { SubPageLayout } from "./layouts/SubPageLayout";
|
import { SubPageLayout } from "./layouts/SubPageLayout";
|
||||||
import { PageTitle } from "./parts/util/PageTitle";
|
import { PageTitle } from "./parts/util/PageTitle";
|
||||||
import placeholderImageLogo from "../../public/placeholder.png";
|
|
||||||
import { Icon, Icons } from "../components/Icon";
|
import { Icon, Icons } from "../components/Icon";
|
||||||
|
|
||||||
export function Discover() {
|
export function Discover() {
|
||||||
|
@ -167,6 +166,66 @@ export function Discover() {
|
||||||
tvGenres.forEach((genre) => fetchTVShowsForGenre(genre.id));
|
tvGenres.forEach((genre) => fetchTVShowsForGenre(genre.id));
|
||||||
}, [tvGenres]);
|
}, [tvGenres]);
|
||||||
|
|
||||||
|
// Fetch Movie genres
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchGenres = async () => {
|
||||||
|
try {
|
||||||
|
const data = await get<any>("/genre/movie/list", {
|
||||||
|
api_key: conf().TMDB_READ_API_KEY,
|
||||||
|
language: "en-US",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Shuffle the array of genres
|
||||||
|
for (let i = data.genres.length - 1; i > 0; i -= 1) {
|
||||||
|
const j = Math.floor(Math.random() * (i + 1));
|
||||||
|
[data.genres[i], data.genres[j]] = [data.genres[j], data.genres[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch only the first 4 genres
|
||||||
|
setGenres(data.genres.slice(0, 4));
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching genres:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchGenres();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Fetch movies for each genre
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchMoviesForGenre = async (genreId: number) => {
|
||||||
|
try {
|
||||||
|
const movies: any[] = [];
|
||||||
|
for (let page = 1; page <= 6; page += 1) {
|
||||||
|
// Fetch only 6 pages
|
||||||
|
const data = await get<any>("/discover/movie", {
|
||||||
|
api_key: conf().TMDB_READ_API_KEY,
|
||||||
|
with_genres: genreId.toString(),
|
||||||
|
language: "en-US",
|
||||||
|
page: page.toString(),
|
||||||
|
});
|
||||||
|
|
||||||
|
movies.push(...data.results);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shuffle the movies
|
||||||
|
for (let i = movies.length - 1; i > 0; i -= 1) {
|
||||||
|
const j = Math.floor(Math.random() * (i + 1));
|
||||||
|
[movies[i], movies[j]] = [movies[j], movies[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
setGenreMovies((prevGenreMovies) => ({
|
||||||
|
...prevGenreMovies,
|
||||||
|
[genreId]: movies,
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error fetching movies for genre ${genreId}:`, error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
genres.forEach((genre) => fetchMoviesForGenre(genre.id));
|
||||||
|
}, [genres]);
|
||||||
|
|
||||||
// Update the scrollCarousel function to use the new ref map
|
// Update the scrollCarousel function to use the new ref map
|
||||||
function scrollCarousel(categorySlug: string, direction: string) {
|
function scrollCarousel(categorySlug: string, direction: string) {
|
||||||
const carousel = carouselRefs.current[categorySlug];
|
const carousel = carouselRefs.current[categorySlug];
|
||||||
|
@ -176,6 +235,7 @@ export function Discover() {
|
||||||
const movieWidth = movieElements[0].offsetWidth;
|
const movieWidth = movieElements[0].offsetWidth;
|
||||||
const visibleMovies = Math.floor(carousel.offsetWidth / movieWidth);
|
const visibleMovies = Math.floor(carousel.offsetWidth / movieWidth);
|
||||||
const scrollAmount = movieWidth * visibleMovies * 0.69; // Silly number :3
|
const scrollAmount = movieWidth * visibleMovies * 0.69; // Silly number :3
|
||||||
|
|
||||||
if (direction === "left") {
|
if (direction === "left") {
|
||||||
if (carousel.scrollLeft <= 5) {
|
if (carousel.scrollLeft <= 5) {
|
||||||
carousel.scrollBy({
|
carousel.scrollBy({
|
||||||
|
@ -254,23 +314,21 @@ export function Discover() {
|
||||||
|
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isHovered) {
|
||||||
|
document.body.style.overflow = "auto";
|
||||||
|
}
|
||||||
|
}, [isHovered]);
|
||||||
|
|
||||||
const handleMouseEnter = () => {
|
const handleMouseEnter = () => {
|
||||||
document.body.style.overflow = "hidden";
|
document.body.style.overflow = "hidden";
|
||||||
setIsHovered(true);
|
setIsHovered(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseLeave = () => {
|
const handleMouseLeave = () => {
|
||||||
document.body.style.overflow = "auto";
|
|
||||||
setIsHovered(false);
|
setIsHovered(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
window.addEventListener("mouseleave", handleMouseLeave);
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener("mouseleave", handleMouseLeave);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
function renderMovies(medias: Media[], category: string, isTVShow = false) {
|
function renderMovies(medias: Media[], category: string, isTVShow = false) {
|
||||||
const categorySlug = `${category.toLowerCase().replace(/ /g, "-")}${Math.random()}`; // Convert the category to a slug
|
const categorySlug = `${category.toLowerCase().replace(/ /g, "-")}${Math.random()}`; // Convert the category to a slug
|
||||||
const displayCategory =
|
const displayCategory =
|
||||||
|
@ -281,6 +339,7 @@ export function Discover() {
|
||||||
: isTVShow
|
: isTVShow
|
||||||
? `${category} Shows`
|
? `${category} Shows`
|
||||||
: `${category} Movies`;
|
: `${category} Movies`;
|
||||||
|
|
||||||
// https://tailwindcss.com/docs/border-style
|
// https://tailwindcss.com/docs/border-style
|
||||||
return (
|
return (
|
||||||
<div className="relative overflow-hidden mt-2">
|
<div className="relative overflow-hidden mt-2">
|
||||||
|
@ -302,48 +361,58 @@ export function Discover() {
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
onWheel={(e) => handleWheel(e, categorySlug)}
|
onWheel={(e) => handleWheel(e, categorySlug)}
|
||||||
>
|
>
|
||||||
{medias.slice(0, 20).map((media) => (
|
{medias
|
||||||
<a
|
.filter((media, index, self) => {
|
||||||
key={media.id}
|
return (
|
||||||
onClick={() =>
|
index ===
|
||||||
navigate(
|
self.findIndex(
|
||||||
`/media/tmdb-${isTVShow ? "tv" : "movie"}-${media.id}-${
|
(m) => m.id === media.id && m.title === media.title,
|
||||||
isTVShow ? media.name : media.title
|
|
||||||
}`,
|
|
||||||
)
|
)
|
||||||
}
|
);
|
||||||
className="text-center relative mt-3 mx-[0.285em] mb-3 transition-transform hover:scale-105 duration-[0.45s]"
|
})
|
||||||
style={{ flex: `0 0 ${movieWidth}` }} // Set a fixed width for each movie
|
.slice(0, 20)
|
||||||
>
|
.map((media) => (
|
||||||
<Flare.Base className="group cursor-pointer rounded-xl relative p-[0.65em] bg-background-main transition-colors duration-300 bg-transparent">
|
<a
|
||||||
<Flare.Light
|
key={media.id}
|
||||||
flareSize={300}
|
onClick={() =>
|
||||||
cssColorVar="--colors-mediaCard-hoverAccent"
|
navigate(
|
||||||
backgroundClass="bg-mediaCard-hoverBackground duration-200"
|
`/media/tmdb-${isTVShow ? "tv" : "movie"}-${media.id}-${
|
||||||
className="rounded-xl bg-background-main group-hover:opacity-100"
|
isTVShow ? media.name : media.title
|
||||||
/>
|
}`,
|
||||||
<img
|
)
|
||||||
src={
|
}
|
||||||
media.poster_path
|
className="text-center relative mt-3 mx-[0.285em] mb-3 transition-transform hover:scale-105 duration-[0.45s]"
|
||||||
? `https://image.tmdb.org/t/p/w500${media.poster_path}`
|
style={{ flex: `0 0 ${movieWidth}` }} // Set a fixed width for each movie
|
||||||
: placeholderImageLogo
|
>
|
||||||
}
|
<Flare.Base className="group cursor-pointer rounded-xl relative p-[0.65em] bg-background-main transition-colors duration-300 bg-transparent">
|
||||||
alt={media.poster_path ? "" : "failed to fetch :("}
|
<Flare.Light
|
||||||
loading="lazy"
|
flareSize={300}
|
||||||
className="rounded-xl relative"
|
cssColorVar="--colors-mediaCard-hoverAccent"
|
||||||
/>
|
backgroundClass="bg-mediaCard-hoverBackground duration-200"
|
||||||
<h1 className="group relative pt-2 text-[13.5px] whitespace-normal duration-[0.35s] font-semibold text-white opacity-0 group-hover:opacity-100">
|
className="rounded-xl bg-background-main group-hover:opacity-100"
|
||||||
{isTVShow
|
/>
|
||||||
? (media.name?.length ?? 0) > 32
|
<img
|
||||||
? `${media.name?.slice(0, 32)}...`
|
src={
|
||||||
: media.name
|
media.poster_path
|
||||||
: (media.title?.length ?? 0) > 32
|
? `https://image.tmdb.org/t/p/w500${media.poster_path}`
|
||||||
? `${media.title?.slice(0, 32)}...`
|
: "/placeholder.png"
|
||||||
: media.title}
|
}
|
||||||
</h1>
|
alt={media.poster_path ? "" : "failed to fetch :("}
|
||||||
</Flare.Base>
|
loading="lazy"
|
||||||
</a>
|
className="rounded-xl relative"
|
||||||
))}
|
/>
|
||||||
|
<h1 className="group relative pt-2 text-[13.5px] whitespace-normal duration-[0.35s] font-semibold text-white opacity-0 group-hover:opacity-100">
|
||||||
|
{isTVShow
|
||||||
|
? (media.name?.length ?? 0) > 32
|
||||||
|
? `${media.name?.slice(0, 32)}...`
|
||||||
|
: media.name
|
||||||
|
: (media.title?.length ?? 0) > 32
|
||||||
|
? `${media.title?.slice(0, 32)}...`
|
||||||
|
: media.title}
|
||||||
|
</h1>
|
||||||
|
</Flare.Base>
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center justify-center">
|
<div className="flex items-center justify-center">
|
||||||
|
@ -407,66 +476,6 @@ export function Discover() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fetch Movie genres
|
|
||||||
useEffect(() => {
|
|
||||||
const fetchGenres = async () => {
|
|
||||||
try {
|
|
||||||
const data = await get<any>("/genre/movie/list", {
|
|
||||||
api_key: conf().TMDB_READ_API_KEY,
|
|
||||||
language: "en-US",
|
|
||||||
});
|
|
||||||
|
|
||||||
// Shuffle the array of genres
|
|
||||||
for (let i = data.genres.length - 1; i > 0; i -= 1) {
|
|
||||||
const j = Math.floor(Math.random() * (i + 1));
|
|
||||||
[data.genres[i], data.genres[j]] = [data.genres[j], data.genres[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch only the first 4 genres
|
|
||||||
setGenres(data.genres.slice(0, 4));
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error fetching genres:", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchGenres();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Fetch movies for each genre
|
|
||||||
useEffect(() => {
|
|
||||||
const fetchMoviesForGenre = async (genreId: number) => {
|
|
||||||
try {
|
|
||||||
const movies: any[] = [];
|
|
||||||
for (let page = 1; page <= 6; page += 1) {
|
|
||||||
// Fetch only 6 pages
|
|
||||||
const data = await get<any>("/discover/movie", {
|
|
||||||
api_key: conf().TMDB_READ_API_KEY,
|
|
||||||
with_genres: genreId.toString(),
|
|
||||||
language: "en-US",
|
|
||||||
page: page.toString(),
|
|
||||||
});
|
|
||||||
|
|
||||||
movies.push(...data.results);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shuffle the movies
|
|
||||||
for (let i = movies.length - 1; i > 0; i -= 1) {
|
|
||||||
const j = Math.floor(Math.random() * (i + 1));
|
|
||||||
[movies[i], movies[j]] = [movies[j], movies[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
setGenreMovies((prevGenreMovies) => ({
|
|
||||||
...prevGenreMovies,
|
|
||||||
[genreId]: movies,
|
|
||||||
}));
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error fetching movies for genre ${genreId}:`, error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
genres.forEach((genre) => fetchMoviesForGenre(genre.id));
|
|
||||||
}, [genres]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let countdownInterval: NodeJS.Timeout;
|
let countdownInterval: NodeJS.Timeout;
|
||||||
if (countdown !== null && countdown > 0) {
|
if (countdown !== null && countdown > 0) {
|
||||||
|
@ -554,7 +563,7 @@ export function Discover() {
|
||||||
))}
|
))}
|
||||||
{genres.map((genre) => (
|
{genres.map((genre) => (
|
||||||
<div
|
<div
|
||||||
key={genre.id}
|
key={`${genre.id}|${genre.name}`}
|
||||||
id={`carousel-${genre.name.toLowerCase().replace(/ /g, "-")}`}
|
id={`carousel-${genre.name.toLowerCase().replace(/ /g, "-")}`}
|
||||||
className="mt-8"
|
className="mt-8"
|
||||||
>
|
>
|
||||||
|
@ -581,7 +590,7 @@ export function Discover() {
|
||||||
))}
|
))}
|
||||||
{tvGenres.map((genre) => (
|
{tvGenres.map((genre) => (
|
||||||
<div
|
<div
|
||||||
key={genre.id}
|
key={`${genre.id}|${genre.name}`}
|
||||||
id={`carousel-${genre.name.toLowerCase().replace(/ /g, "-")}`}
|
id={`carousel-${genre.name.toLowerCase().replace(/ /g, "-")}`}
|
||||||
className="mt-8"
|
className="mt-8"
|
||||||
>
|
>
|
||||||
|
|
Loading…
Reference in New Issue