mirror of
https://github.com/JustAnimeCore/JustAnime.git
synced 2026-04-17 22:01:45 +00:00
home page improved
This commit is contained in:
@@ -16,6 +16,8 @@
|
|||||||
"@fortawesome/free-solid-svg-icons": "^6.6.0",
|
"@fortawesome/free-solid-svg-icons": "^6.6.0",
|
||||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||||
"@radix-ui/react-icons": "^1.3.0",
|
"@radix-ui/react-icons": "^1.3.0",
|
||||||
|
"@vercel/analytics": "^1.5.0",
|
||||||
|
"@vercel/speed-insights": "^1.2.0",
|
||||||
"artplayer": "^5.2.3",
|
"artplayer": "^5.2.3",
|
||||||
"artplayer-plugin-chapter": "^1.0.0",
|
"artplayer-plugin-chapter": "^1.0.0",
|
||||||
"artplayer-plugin-hls-control": "^1.0.1",
|
"artplayer-plugin-hls-control": "^1.0.1",
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { Routes, Route } from "react-router-dom";
|
import { Routes, Route } from "react-router-dom";
|
||||||
|
import { Analytics } from '@vercel/analytics/react';
|
||||||
|
import { SpeedInsights } from '@vercel/speed-insights/react';
|
||||||
import { HomeInfoProvider } from "./context/HomeInfoContext";
|
import { HomeInfoProvider } from "./context/HomeInfoContext";
|
||||||
import Home from "./pages/Home/Home";
|
import Home from "./pages/Home/Home";
|
||||||
import AnimeInfo from "./pages/animeInfo/AnimeInfo";
|
import AnimeInfo from "./pages/animeInfo/AnimeInfo";
|
||||||
@@ -71,6 +73,8 @@ function App() {
|
|||||||
</Routes>
|
</Routes>
|
||||||
{!isSplashScreen && <Footer />}
|
{!isSplashScreen && <Footer />}
|
||||||
</main>
|
</main>
|
||||||
|
<Analytics />
|
||||||
|
<SpeedInsights />
|
||||||
</div>
|
</div>
|
||||||
</HomeInfoProvider>
|
</HomeInfoProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,79 +7,132 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
to top,
|
180deg,
|
||||||
rgba(18, 18, 18, 1) 0%,
|
rgba(0, 0, 0, 0) 0%,
|
||||||
rgba(18, 18, 18, 0.7) 20%,
|
rgba(0, 0, 0, 0.4) 50%,
|
||||||
rgba(18, 18, 18, 0) 60%,
|
rgba(0, 0, 0, 0.95) 100%
|
||||||
rgba(18, 18, 18, 0.2) 100%
|
|
||||||
);
|
);
|
||||||
z-index: 50;
|
z-index: 50;
|
||||||
transition: all 0.3s ease-in-out;
|
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
border-radius: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group:hover .overlay {
|
.group:hover .overlay {
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
to top,
|
180deg,
|
||||||
rgba(18, 18, 18, 0.95) 0%,
|
rgba(0, 0, 0, 0.2) 0%,
|
||||||
rgba(18, 18, 18, 0.8) 50%,
|
rgba(0, 0, 0, 0.6) 50%,
|
||||||
rgba(18, 18, 18, 0.6) 100%
|
rgba(0, 0, 0, 0.98) 100%
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dot {
|
.dot {
|
||||||
width: 3px;
|
width: 2px;
|
||||||
height: 3px;
|
height: 2px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: rgba(255, 255, 255, 0.4);
|
background: rgba(255, 255, 255, 0.4);
|
||||||
margin: 0 4px;
|
margin: 0 6px;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: -1px;
|
top: -1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Modern Card Styles */
|
/* Modern Card Styles */
|
||||||
.category-card-container {
|
.category-card-container {
|
||||||
transition: transform 0.3s ease-in-out;
|
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
position: relative;
|
||||||
|
border-radius: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #1a1a1a;
|
||||||
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
.category-card-container:hover {
|
.category-card-container:hover {
|
||||||
transform: translateY(-4px);
|
transform: translateY(-4px);
|
||||||
|
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-card-container img {
|
||||||
|
border-radius: 16px;
|
||||||
|
transform: scale(1.01);
|
||||||
|
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
filter: brightness(0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-card-container:hover img {
|
||||||
|
transform: scale(1.05);
|
||||||
|
filter: brightness(1.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.category-badge {
|
.category-badge {
|
||||||
backdrop-filter: blur(8px);
|
backdrop-filter: blur(8px);
|
||||||
-webkit-backdrop-filter: blur(8px);
|
-webkit-backdrop-filter: blur(8px);
|
||||||
background: rgba(255, 255, 255, 0.1);
|
background: rgba(255, 255, 255, 0.1);
|
||||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-weight: 600;
|
font-weight: 500;
|
||||||
letter-spacing: 0.02em;
|
letter-spacing: 0.02em;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.category-badge:hover {
|
.category-badge:hover {
|
||||||
background: rgba(255, 255, 255, 0.15);
|
background: rgba(255, 255, 255, 0.15);
|
||||||
|
border-color: rgba(255, 255, 255, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-title {
|
.item-title {
|
||||||
font-weight: 500;
|
font-weight: 600;
|
||||||
letter-spacing: 0.01em;
|
letter-spacing: 0.01em;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.3s ease;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 1.4;
|
||||||
|
color: rgba(255, 255, 255, 0.95);
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-title:hover {
|
.item-title:hover {
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
text-shadow: 0 0 20px rgba(255, 255, 255, 0.2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.play-icon {
|
.play-icon {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translate(-50%, -50%) scale(0.8);
|
transform: translate(-50%, -50%) scale(0.9);
|
||||||
transition: all 0.3s ease;
|
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.4));
|
||||||
}
|
}
|
||||||
|
|
||||||
.group:hover .play-icon {
|
.group:hover .play-icon {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translate(-50%, -50%) scale(1);
|
transform: translate(-50%, -50%) scale(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.info-container {
|
||||||
|
padding: 12px 16px 16px;
|
||||||
|
background: linear-gradient(
|
||||||
|
to top,
|
||||||
|
rgba(0, 0, 0, 0.95) 0%,
|
||||||
|
rgba(0, 0, 0, 0.8) 50%,
|
||||||
|
rgba(0, 0, 0, 0) 100%
|
||||||
|
);
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group:hover .info-container {
|
||||||
|
padding-bottom: 20px;
|
||||||
|
background: linear-gradient(
|
||||||
|
to top,
|
||||||
|
rgba(0, 0, 0, 0.98) 0%,
|
||||||
|
rgba(0, 0, 0, 0.85) 50%,
|
||||||
|
rgba(0, 0, 0, 0) 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-info {
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|||||||
@@ -87,19 +87,20 @@ const CategoryCard = React.memo(
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className={`w-full ${className}`}>
|
<div className={`w-full ${className}`}>
|
||||||
<div className="flex items-center justify-between mb-6">
|
<div className="flex items-center justify-between mb-8">
|
||||||
<h1 className="font-bold text-2xl text-white max-[478px]:text-[18px] capitalize tracking-wide">
|
<h1 className="font-semibold text-2xl text-white max-[478px]:text-[18px] capitalize tracking-wide">
|
||||||
{label}
|
{label}
|
||||||
</h1>
|
</h1>
|
||||||
{showViewMore && (
|
{showViewMore && (
|
||||||
<Link
|
<Link
|
||||||
to={`/${path}`}
|
to={`/${path}`}
|
||||||
className="flex w-fit items-baseline h-fit rounded-3xl gap-x-1 group"
|
className="flex items-center gap-x-1 py-1 px-2 -mr-2 rounded-md
|
||||||
|
text-[13px] font-medium text-[#ffffff80] hover:text-white
|
||||||
|
transition-all duration-300 group"
|
||||||
>
|
>
|
||||||
<p className="text-gray-300 text-[12px] font-medium h-fit leading-0 group-hover:text-white transition-all ease-out">
|
View all
|
||||||
View more
|
<FaChevronRight className="text-[10px] transform transition-transform duration-300
|
||||||
</p>
|
group-hover:translate-x-0.5" />
|
||||||
<FaChevronRight className="text-gray-300 text-[10px] group-hover:text-white transition-all ease-out" />
|
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -115,12 +116,12 @@ const CategoryCard = React.memo(
|
|||||||
{itemsToRender.firstRow.map((item, index) => (
|
{itemsToRender.firstRow.map((item, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className="flex flex-col transition-transform duration-300 ease-in-out category-card-container"
|
className="flex flex-col category-card-container"
|
||||||
style={{ height: "fit-content" }}
|
style={{ height: "fit-content" }}
|
||||||
ref={(el) => (cardRefs.current[index] = el)}
|
ref={(el) => (cardRefs.current[index] = el)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="w-full relative group hover:cursor-pointer"
|
className="w-full relative group hover:cursor-pointer overflow-hidden rounded-xl"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
navigate(
|
navigate(
|
||||||
`${
|
`${
|
||||||
@@ -139,51 +140,72 @@ const CategoryCard = React.memo(
|
|||||||
className="text-[40px] text-white absolute top-1/2 left-1/2 play-icon z-[10000]"
|
className="text-[40px] text-white absolute top-1/2 left-1/2 play-icon z-[10000]"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="overlay"></div>
|
<div className="overlay"></div>
|
||||||
<div className="overflow-hidden">
|
<div className="overflow-hidden rounded-xl">
|
||||||
<img
|
<img
|
||||||
src={`${item.poster}`}
|
src={`${item.poster}`}
|
||||||
alt={item.title}
|
alt={item.title}
|
||||||
className={`w-full h-[320px] object-cover max-[1200px]:h-[35vw] max-[758px]:h-[45vw] max-[478px]:h-[60vw] group-hover:blur-[7px] transform transition-all duration-300 ease-in-out ultra-wide:h-[400px] ${cardStyle}`}
|
className={`w-full h-[320px] object-cover max-[1200px]:h-[35vw] max-[758px]:h-[45vw] max-[478px]:h-[60vw] transform transition-all duration-300 ease-in-out ultra-wide:h-[400px] ${cardStyle}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{(item.tvInfo?.rating === "18+" ||
|
{(item.tvInfo?.rating === "18+" ||
|
||||||
item?.adultContent === true) && (
|
item?.adultContent === true) && (
|
||||||
<div className="text-white px-2 py-1 rounded-md bg-black/50 backdrop-blur-sm border border-white/10 absolute top-2 left-2 flex items-center justify-center text-[12px] font-medium">
|
<div className="text-white px-3 py-1 rounded-lg bg-black/40 backdrop-blur-md border border-white/10 absolute top-3 left-3 flex items-center justify-center text-[12px] font-medium">
|
||||||
18+
|
18+
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="absolute left-2 bottom-3 flex items-center justify-center w-fit space-x-2 z-[100] max-[270px]:flex-col max-[270px]:gap-y-[3px]">
|
<div className="info-container">
|
||||||
{item.tvInfo?.sub && (
|
<div className="flex items-center justify-start w-fit space-x-2 z-[100] max-[270px]:flex-col max-[270px]:gap-y-[3px]">
|
||||||
<div className="category-badge flex space-x-1 justify-center items-center">
|
{item.tvInfo?.sub && (
|
||||||
<FontAwesomeIcon
|
<div className="category-badge flex space-x-1 justify-center items-center">
|
||||||
icon={faClosedCaptioning}
|
<FontAwesomeIcon
|
||||||
className="text-[12px] text-white/90"
|
icon={faClosedCaptioning}
|
||||||
/>
|
className="text-[12px] text-white/90"
|
||||||
<p className="text-[12px] text-white/90">
|
/>
|
||||||
{item.tvInfo.sub}
|
<p className="text-[12px] text-white/90">
|
||||||
</p>
|
{item.tvInfo.sub}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{item.tvInfo?.dub && (
|
||||||
|
<div className="category-badge flex space-x-1 justify-center items-center">
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faMicrophone}
|
||||||
|
className="text-[12px] text-white/90"
|
||||||
|
/>
|
||||||
|
<p className="text-[12px] text-white/90">
|
||||||
|
{item.tvInfo.dub}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{item.tvInfo?.eps && (
|
||||||
|
<div className="category-badge flex space-x-1 justify-center items-center">
|
||||||
|
<p className="text-[12px] text-white/90">
|
||||||
|
{item.tvInfo.eps}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<Link
|
||||||
|
to={`/${item.id}`}
|
||||||
|
className="text-white font-medium mt-3 item-title hover:text-white hover:cursor-pointer line-clamp-1 block"
|
||||||
|
>
|
||||||
|
{language === "EN" ? item.title : item.japanese_title}
|
||||||
|
</Link>
|
||||||
|
<div className="flex items-center gap-x-2 w-full mt-2 overflow-hidden">
|
||||||
|
<div className="text-gray-300 text-[13px] text-nowrap overflow-hidden text-ellipsis font-medium">
|
||||||
|
{item.tvInfo.showType.split(" ").shift()}
|
||||||
</div>
|
</div>
|
||||||
)}
|
<div className="dot"></div>
|
||||||
{item.tvInfo?.dub && (
|
<div className="text-gray-300 text-[13px] text-nowrap overflow-hidden text-ellipsis font-medium">
|
||||||
<div className="category-badge flex space-x-1 justify-center items-center">
|
{item.tvInfo?.duration === "m" ||
|
||||||
<FontAwesomeIcon
|
item.tvInfo?.duration === "?" ||
|
||||||
icon={faMicrophone}
|
item.duration === "m" ||
|
||||||
className="text-[12px] text-white/90"
|
item.duration === "?"
|
||||||
/>
|
? "N/A"
|
||||||
<p className="text-[12px] text-white/90">
|
: item.tvInfo?.duration || item.duration || "N/A"}
|
||||||
{item.tvInfo.dub}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
{item.tvInfo?.eps && (
|
|
||||||
<div className="category-badge flex space-x-1 justify-center items-center">
|
|
||||||
<p className="text-[12px] text-white/90">
|
|
||||||
{item.tvInfo.eps}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
{hoveredItem === item.id + index &&
|
{hoveredItem === item.id + index &&
|
||||||
window.innerWidth > 1024 && (
|
window.innerWidth > 1024 && (
|
||||||
@@ -198,31 +220,11 @@ const CategoryCard = React.memo(
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Link
|
|
||||||
to={`/${item.id}`}
|
|
||||||
className="text-gray-100 font-medium mt-2 item-title hover:text-white hover:cursor-pointer line-clamp-1"
|
|
||||||
>
|
|
||||||
{language === "EN" ? item.title : item.japanese_title}
|
|
||||||
</Link>
|
|
||||||
{item.description && (
|
{item.description && (
|
||||||
<div className="line-clamp-3 text-[13px] font-light text-gray-400 mt-1 max-[1200px]:hidden">
|
<div className="line-clamp-3 text-[13px] font-light text-gray-400 mt-3 max-[1200px]:hidden">
|
||||||
{item.description}
|
{item.description}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="flex items-center gap-x-2 w-full mt-2 overflow-hidden">
|
|
||||||
<div className="text-gray-500 text-[13px] text-nowrap overflow-hidden text-ellipsis font-medium">
|
|
||||||
{item.tvInfo.showType.split(" ").shift()}
|
|
||||||
</div>
|
|
||||||
<div className="dot"></div>
|
|
||||||
<div className="text-gray-500 text-[13px] text-nowrap overflow-hidden text-ellipsis font-medium">
|
|
||||||
{item.tvInfo?.duration === "m" ||
|
|
||||||
item.tvInfo?.duration === "?" ||
|
|
||||||
item.duration === "m" ||
|
|
||||||
item.duration === "?"
|
|
||||||
? "N/A"
|
|
||||||
: item.tvInfo?.duration || item.duration || "N/A"}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -46,10 +46,10 @@ const ContinueWatching = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-x-2 pr-2 max-[350px]:hidden">
|
<div className="flex gap-x-2 pr-2 max-[350px]:hidden">
|
||||||
<button className="btn-prev bg-gray-700 text-white p-3 rounded-full hover:bg-gray-500 transition max-[768px]:p-2">
|
<button className="continue-btn-prev bg-gray-700 text-white p-3 rounded-full hover:bg-gray-500 transition max-[768px]:p-2">
|
||||||
<FaChevronLeft className="text-xs" />
|
<FaChevronLeft className="text-xs" />
|
||||||
</button>
|
</button>
|
||||||
<button className="btn-next bg-gray-700 text-white p-3 rounded-full hover:bg-gray-500 transition max-[768px]:p-2">
|
<button className="continue-btn-next bg-gray-700 text-white p-3 rounded-full hover:bg-gray-500 transition max-[768px]:p-2">
|
||||||
<FaChevronRight className="text-xs" />
|
<FaChevronRight className="text-xs" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -70,11 +70,11 @@ const ContinueWatching = () => {
|
|||||||
}}
|
}}
|
||||||
modules={[Navigation]}
|
modules={[Navigation]}
|
||||||
navigation={{
|
navigation={{
|
||||||
nextEl: ".btn-next",
|
nextEl: ".continue-btn-next",
|
||||||
prevEl: ".btn-prev",
|
prevEl: ".continue-btn-prev",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{memoizedWatchList.map((item, index) => (
|
{memoizedWatchList.slice().reverse().map((item, index) => (
|
||||||
<SwiperSlide
|
<SwiperSlide
|
||||||
key={index}
|
key={index}
|
||||||
className="text-center flex justify-center items-center"
|
className="text-center flex justify-center items-center"
|
||||||
|
|||||||
@@ -114,28 +114,28 @@ const Schedule = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="w-full mt-[60px] max-[480px]:mt-[40px]">
|
<div className="w-full mt-8 max-[480px]:mt-6">
|
||||||
<div className="flex items-center justify-between max-[570px]:flex-col max-[570px]:items-start max-[570px]:gap-y-2">
|
<div className="flex items-center justify-between max-[570px]:flex-col max-[570px]:items-start max-[570px]:gap-y-2">
|
||||||
<div className="font-bold text-2xl text-[#ffbade] max-[478px]:text-[18px]">
|
<div className="font-bold text-2xl text-white max-[478px]:text-[18px]">
|
||||||
Estimated Schedule
|
Estimated Schedule
|
||||||
</div>
|
</div>
|
||||||
<p className="leading-[28px] px-[10px] bg-white text-black rounded-full my-[6px] text-[16px] font-bold max-[478px]:text-[12px] max-[275px]:text-[10px]">
|
<p className="leading-[28px] px-3 bg-zinc-800 text-white rounded-md text-[14px] font-medium max-[478px]:text-[12px] max-[275px]:text-[10px]">
|
||||||
({GMTOffset}) {currentTime.toLocaleDateString()}{" "}
|
({GMTOffset}) {currentTime.toLocaleDateString()}{" "}
|
||||||
{currentTime.toLocaleTimeString()}
|
{currentTime.toLocaleTimeString()}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full overflow-x-scroll space-x-4 scrollbar-hide pt-10 px-6 max-[480px]:px-4 max-[478px]:pt-4">
|
<div className="w-full overflow-x-scroll space-x-4 scrollbar-hide pt-6 px-4 max-[480px]:px-2 max-[478px]:pt-4">
|
||||||
<div className="relative w-full">
|
<div className="relative w-full">
|
||||||
<Swiper
|
<Swiper
|
||||||
slidesPerView={3}
|
slidesPerView={3}
|
||||||
spaceBetween={2}
|
spaceBetween={2}
|
||||||
breakpoints={{
|
breakpoints={{
|
||||||
250: { slidesPerView: 3, spaceBetween: 10 },
|
250: { slidesPerView: 3, spaceBetween: 8 },
|
||||||
640: { slidesPerView: 4, spaceBetween: 10 },
|
640: { slidesPerView: 4, spaceBetween: 8 },
|
||||||
768: { slidesPerView: 5, spaceBetween: 10 },
|
768: { slidesPerView: 5, spaceBetween: 8 },
|
||||||
1024: { slidesPerView: 7, spaceBetween: 10 },
|
1024: { slidesPerView: 7, spaceBetween: 8 },
|
||||||
1300: { slidesPerView: 7, spaceBetween: 15 },
|
1300: { slidesPerView: 7, spaceBetween: 8 },
|
||||||
}}
|
}}
|
||||||
modules={[Pagination, Navigation]}
|
modules={[Pagination, Navigation]}
|
||||||
navigation={{
|
navigation={{
|
||||||
@@ -150,20 +150,20 @@ const Schedule = () => {
|
|||||||
<div
|
<div
|
||||||
ref={(el) => (cardRefs.current[index] = el)}
|
ref={(el) => (cardRefs.current[index] = el)}
|
||||||
onClick={() => toggleActive(index)}
|
onClick={() => toggleActive(index)}
|
||||||
className={`h-[70px] flex flex-col justify-center items-center w-full text-center rounded-xl shadow-lg cursor-pointer ${
|
className={`h-[60px] flex flex-col justify-center items-center w-full text-center rounded-lg cursor-pointer transition-all duration-200 ${
|
||||||
currentActiveIndex === index
|
currentActiveIndex === index
|
||||||
? "bg-[#ffbade] text-black"
|
? "bg-white text-black"
|
||||||
: "bg-white bg-opacity-5 text-[#ffffff] hover:bg-[#373646] transition-all duration-300 ease-in-out"
|
: "bg-zinc-800 text-white hover:bg-zinc-700"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="text-[18px] font-bold max-[400px]:text-[14px] max-[350px]:text-[12px]">
|
<div className="text-[16px] font-bold max-[400px]:text-[14px] max-[350px]:text-[12px]">
|
||||||
{date.dayname}
|
{date.dayname}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`text-[14px] max-[400px]:text-[12px] ${
|
className={`text-[13px] max-[400px]:text-[11px] ${
|
||||||
currentActiveIndex === index
|
currentActiveIndex === index
|
||||||
? "text-black"
|
? "text-zinc-800"
|
||||||
: "text-gray-400"
|
: "text-zinc-400"
|
||||||
} max-[350px]:text-[10px]`}
|
} max-[350px]:text-[10px]`}
|
||||||
>
|
>
|
||||||
{date.monthName} {date.day}
|
{date.monthName} {date.day}
|
||||||
@@ -172,28 +172,28 @@ const Schedule = () => {
|
|||||||
</SwiperSlide>
|
</SwiperSlide>
|
||||||
))}
|
))}
|
||||||
</Swiper>
|
</Swiper>
|
||||||
<button className="next absolute top-1/2 right-[-15px] transform -translate-y-1/2 flex justify-center items-center cursor-pointer">
|
<button className="next absolute top-1/2 right-[-12px] transform -translate-y-1/2 flex justify-center items-center cursor-pointer">
|
||||||
<FaChevronRight className="text-[12px]" />
|
<FaChevronRight className="text-[12px]" />
|
||||||
</button>
|
</button>
|
||||||
<button className="prev absolute top-1/2 left-[-15px] transform -translate-y-1/2 flex justify-center items-center cursor-pointer">
|
<button className="prev absolute top-1/2 left-[-12px] transform -translate-y-1/2 flex justify-center items-center cursor-pointer">
|
||||||
<FaChevronLeft className="text-[12px]" />
|
<FaChevronLeft className="text-[12px]" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="w-full h-[70px] flex justify-center items-center">
|
<div className="w-full h-[60px] flex justify-center items-center">
|
||||||
<BouncingLoader />
|
<BouncingLoader />
|
||||||
</div>
|
</div>
|
||||||
) : !scheduleData || scheduleData.length === 0 ? (
|
) : !scheduleData || scheduleData.length === 0 ? (
|
||||||
<div className="w-full h-[70px] flex justify-center items-center mt-5 text-xl">
|
<div className="w-full h-[60px] flex justify-center items-center mt-4 text-lg text-zinc-400">
|
||||||
No data to display
|
No data to display
|
||||||
</div>
|
</div>
|
||||||
) : error ? (
|
) : error ? (
|
||||||
<div className="w-full h-[70px] flex justify-center items-center mt-5 text-xl">
|
<div className="w-full h-[60px] flex justify-center items-center mt-4 text-lg text-zinc-400">
|
||||||
Something went wrong
|
Something went wrong
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col mt-5 items-start">
|
<div className="flex flex-col mt-4 items-start">
|
||||||
{(showAll
|
{(showAll
|
||||||
? scheduleData
|
? scheduleData
|
||||||
: Array.isArray(scheduleData)
|
: Array.isArray(scheduleData)
|
||||||
@@ -203,31 +203,31 @@ const Schedule = () => {
|
|||||||
<Link
|
<Link
|
||||||
to={`/${item.id}`}
|
to={`/${item.id}`}
|
||||||
key={idx}
|
key={idx}
|
||||||
className="w-full flex justify-between py-4 border-[#FFFFFF0D] border-b-[1px] group cursor-pointer max-[325px]:py-2"
|
className="w-full flex justify-between py-3 border-zinc-800 border-b-[1px] group cursor-pointer hover:bg-zinc-900/50 px-2 transition-all duration-200 max-[325px]:py-2"
|
||||||
>
|
>
|
||||||
<div className="flex items-center max-w-[500px] gap-x-7 max-[400px]:gap-x-2">
|
<div className="flex items-center max-w-[500px] gap-x-4 max-[400px]:gap-x-2">
|
||||||
<div className="text-lg font-semibold text-[#ffffff59] group-hover:text-[#ffbade] transition-all duration-300 ease-in-out max-[600px]:text-[14px] max-[275px]:text-[12px]">
|
<div className="text-base font-medium text-zinc-500 group-hover:text-white transition-all duration-200 max-[600px]:text-[14px] max-[275px]:text-[12px]">
|
||||||
{item.time || "N/A"}
|
{item.time || "N/A"}
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-[17px] font-semibold line-clamp-1 group-hover:text-[#ffbade] transition-all duration-300 ease-in-out max-[600px]:text-[14px] max-[275px]:text-[12px]">
|
<h3 className="text-[16px] font-medium line-clamp-1 group-hover:text-white transition-all duration-200 max-[600px]:text-[14px] max-[275px]:text-[12px]">
|
||||||
{item.title || "N/A"}
|
{item.title || "N/A"}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<button className="max-w-[150px] flex items-center py-1 px-4 rounded-lg gap-x-2 group-hover:bg-[#ffbade] transition-all duration-300 ease-in-out">
|
<div className="flex items-center gap-x-2 py-1 px-3 rounded-md bg-zinc-800 group-hover:bg-white transition-all duration-200">
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faPlay}
|
icon={faPlay}
|
||||||
className="mt-[1px] text-[10px] max-[320px]:text-[8px] group-hover:text-black transition-all duration-300 ease-in-out"
|
className="mt-[1px] text-[10px] max-[320px]:text-[8px] text-zinc-400 group-hover:text-black"
|
||||||
/>
|
/>
|
||||||
<p className="text-[14px] text-white group-hover:text-black transition-all duration-300 ease-in-out max-[275px]:text-[12px]">
|
<p className="text-[13px] text-zinc-400 group-hover:text-black max-[275px]:text-[12px]">
|
||||||
Episode {item.episode_no || "N/A"}
|
EP {item.episode_no || "N/A"}
|
||||||
</p>
|
</p>
|
||||||
</button>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
{scheduleData.length > 7 && (
|
{scheduleData.length > 7 && (
|
||||||
<button
|
<button
|
||||||
onClick={toggleShowAll}
|
onClick={toggleShowAll}
|
||||||
className="text-white py-4 hover:text-[#ffbade] font-semibold transition-all duration-300 ease-in-out max-sm:text-[13px]"
|
className="text-zinc-400 py-3 hover:text-white font-medium transition-all duration-200 max-sm:text-[13px]"
|
||||||
>
|
>
|
||||||
{showAll ? "Show Less" : "Show More"}
|
{showAll ? "Show Less" : "Show More"}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,11 +1,18 @@
|
|||||||
.next,
|
.next,
|
||||||
.prev {
|
.prev {
|
||||||
width: 30px;
|
width: 24px;
|
||||||
height: 30px;
|
height: 24px;
|
||||||
border-radius: 100%;
|
border-radius: 6px;
|
||||||
background-color: white;
|
background-color: rgb(39 39 42);
|
||||||
color: black;
|
color: rgb(161 161 170);
|
||||||
font-size: 13px;
|
font-size: 12px;
|
||||||
padding: 10px;
|
padding: 6px;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.next:hover,
|
||||||
|
.prev:hover {
|
||||||
|
background-color: rgb(63 63 70);
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import "./Sidebar.css";
|
|||||||
|
|
||||||
const MENU_ITEMS = [
|
const MENU_ITEMS = [
|
||||||
{ name: "Home", path: "/home", icon: faHome },
|
{ name: "Home", path: "/home", icon: faHome },
|
||||||
|
{ name: "Recently Added", path: "/recently-added", icon: faCirclePlay },
|
||||||
|
{ name: "Top Upcoming", path: "/top-upcoming", icon: faFilePen },
|
||||||
{ name: "Subbed Anime", path: "/subbed-anime", icon: faFilePen },
|
{ name: "Subbed Anime", path: "/subbed-anime", icon: faFilePen },
|
||||||
{ name: "Dubbed Anime", path: "/dubbed-anime", icon: faPlay },
|
{ name: "Dubbed Anime", path: "/dubbed-anime", icon: faPlay },
|
||||||
{ name: "Most Popular", path: "/most-popular", icon: faFire },
|
{ name: "Most Popular", path: "/most-popular", icon: faFire },
|
||||||
|
|||||||
72
src/components/tabbed-anime/TabbedAnimeSection.jsx
Normal file
72
src/components/tabbed-anime/TabbedAnimeSection.jsx
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import CategoryCard from "@/src/components/categorycard/CategoryCard.jsx";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import { FaChevronRight } from "react-icons/fa";
|
||||||
|
|
||||||
|
function TabbedAnimeSection({ topAiring, mostFavorite, latestCompleted, className = "" }) {
|
||||||
|
const [activeTab, setActiveTab] = useState("airing");
|
||||||
|
|
||||||
|
const tabs = [
|
||||||
|
{ id: "airing", label: "Top Airing", data: topAiring, path: "top-airing" },
|
||||||
|
{ id: "favorite", label: "Most Favorite", data: mostFavorite, path: "most-favorite" },
|
||||||
|
{ id: "completed", label: "Latest Completed", data: latestCompleted, path: "completed" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const activeTabData = tabs.find((tab) => tab.id === activeTab);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`w-full ${className}`}>
|
||||||
|
<div className="flex justify-between items-center border-b border-[#ffffff1a] relative">
|
||||||
|
<div className="flex">
|
||||||
|
{tabs.map((tab) => (
|
||||||
|
<button
|
||||||
|
key={tab.id}
|
||||||
|
onClick={() => setActiveTab(tab.id)}
|
||||||
|
className={`relative px-6 py-4 text-[15px] font-medium transition-all duration-300
|
||||||
|
${activeTab === tab.id
|
||||||
|
? "text-white after:absolute after:bottom-0 after:left-0 after:w-full after:h-[2px] after:bg-primary after:rounded-t-full"
|
||||||
|
: "text-[#ffffff80] hover:text-white"
|
||||||
|
}
|
||||||
|
before:absolute before:bottom-0 before:left-1/2 before:w-0 before:h-[2px] before:bg-[#ffffff40]
|
||||||
|
before:transition-all before:duration-300 before:-translate-x-1/2
|
||||||
|
hover:before:w-full
|
||||||
|
group
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<span className="relative z-10 transition-transform duration-300 group-hover:transform group-hover:translate-y-[-1px]">
|
||||||
|
{tab.label}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<Link
|
||||||
|
to={`/${activeTabData.path}`}
|
||||||
|
className="flex items-center gap-x-1 py-1 px-2 -mr-2 rounded-md
|
||||||
|
text-[13px] font-medium text-[#ffffff80] hover:text-white
|
||||||
|
transition-all duration-300 group"
|
||||||
|
>
|
||||||
|
View all
|
||||||
|
<FaChevronRight className="text-[10px] transform transition-transform duration-300
|
||||||
|
group-hover:translate-x-0.5" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<CategoryCard
|
||||||
|
data={activeTabData.data}
|
||||||
|
path={activeTabData.path}
|
||||||
|
limit={12}
|
||||||
|
showViewMore={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TabbedAnimeSection.propTypes = {
|
||||||
|
topAiring: PropTypes.array.isRequired,
|
||||||
|
mostFavorite: PropTypes.array.isRequired,
|
||||||
|
latestCompleted: PropTypes.array.isRequired,
|
||||||
|
className: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TabbedAnimeSection;
|
||||||
@@ -49,19 +49,17 @@ function Topten({ data, className }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`flex flex-col space-y-6 ${className}`}>
|
<div className={`flex flex-col space-y-4 ${className}`}>
|
||||||
<div className="flex justify-between items-center max-[350px]:flex-col max-[350px]:gap-y-2 max-[350px]:items-start">
|
<div className="flex justify-between items-center max-[350px]:flex-col max-[350px]:gap-y-2 max-[350px]:items-start">
|
||||||
<h1 className="font-bold text-2xl text-[#ffbade]">Top 10</h1>
|
<h1 className="font-bold text-2xl text-white tracking-tight">Top 10</h1>
|
||||||
<ul className="flex justify-between w-fit bg-[#373646] rounded-[4px] text-sm font-bold">
|
<ul className="flex justify-between w-fit bg-[#1a1a1a] rounded-lg overflow-hidden shadow-lg">
|
||||||
{["today", "week", "month"].map((period) => (
|
{["today", "week", "month"].map((period) => (
|
||||||
<li
|
<li
|
||||||
key={period}
|
key={period}
|
||||||
className={`cursor-pointer p-2 px-3 ${
|
className={`cursor-pointer p-1.5 px-4 transition-all duration-200 ${
|
||||||
activePeriod === period
|
activePeriod === period
|
||||||
? "bg-[#ffbade] text-[#555462]"
|
? "bg-white text-black font-medium"
|
||||||
: "text-white hover:text-[#ffbade]"
|
: "text-gray-400 hover:text-white hover:bg-[#2a2a2a]"
|
||||||
} ${period === "today" ? "rounded-l-[4px]" : ""} ${
|
|
||||||
period === "month" ? "rounded-r-[4px]" : ""
|
|
||||||
}`}
|
}`}
|
||||||
onClick={() => handlePeriodChange(period)}
|
onClick={() => handlePeriodChange(period)}
|
||||||
>
|
>
|
||||||
@@ -71,19 +69,19 @@ function Topten({ data, className }) {
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col space-y-4 bg-[#2B2A3C] p-4 pt-8">
|
<div className="flex flex-col space-y-3 bg-[#1a1a1a] p-3 pt-6 rounded-lg shadow-lg">
|
||||||
{currentData &&
|
{currentData &&
|
||||||
currentData.map((item, index) => (
|
currentData.map((item, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className="flex items-center gap-x-4"
|
className="flex items-center gap-x-3 group"
|
||||||
ref={(el) => (cardRefs.current[index] = el)}
|
ref={(el) => (cardRefs.current[index] = el)}
|
||||||
>
|
>
|
||||||
<h1
|
<h1
|
||||||
className={`font-bold text-2xl ${
|
className={`font-bold text-2xl transition-colors ${
|
||||||
index < 3
|
index < 3
|
||||||
? "pb-1 text-white border-b-[3px] border-[#ffbade]"
|
? "text-white border-b-2 border-white pb-0.5"
|
||||||
: "text-[#777682]"
|
: "text-gray-600"
|
||||||
} max-[350px]:hidden`}
|
} max-[350px]:hidden`}
|
||||||
>
|
>
|
||||||
{`${index + 1 < 10 ? "0" : ""}${index + 1}`}
|
{`${index + 1 < 10 ? "0" : ""}${index + 1}`}
|
||||||
@@ -92,16 +90,15 @@ function Topten({ data, className }) {
|
|||||||
style={{
|
style={{
|
||||||
borderBottom:
|
borderBottom:
|
||||||
index + 1 < 10
|
index + 1 < 10
|
||||||
? "1px solid rgba(255, 255, 255, .075)"
|
? "1px solid rgba(255, 255, 255, .1)"
|
||||||
: "none",
|
: "none",
|
||||||
}}
|
}}
|
||||||
className="flex pb-4 relative container items-center"
|
className="flex pb-3 relative container items-center group-hover:bg-[#2a2a2a] transition-colors duration-200 rounded-lg p-1.5"
|
||||||
>
|
>
|
||||||
{/* Image with tooltip behavior */}
|
|
||||||
<img
|
<img
|
||||||
src={`${item.poster}`}
|
src={`${item.poster}`}
|
||||||
alt={item.title}
|
alt={item.title}
|
||||||
className="w-[60px] h-[75px] rounded-md object-cover flex-shrink-0 cursor-pointer"
|
className="w-[55px] h-[70px] rounded-lg object-cover flex-shrink-0 cursor-pointer shadow-md transition-transform duration-200 group-hover:scale-[1.02]"
|
||||||
onClick={() => navigate(`/watch/${item.id}`)}
|
onClick={() => navigate(`/watch/${item.id}`)}
|
||||||
onMouseEnter={() => handleMouseEnter(item, index)}
|
onMouseEnter={() => handleMouseEnter(item, index)}
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
@@ -132,33 +129,33 @@ function Topten({ data, className }) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex flex-col ml-4 space-y-2">
|
<div className="flex flex-col ml-3 space-y-1.5">
|
||||||
<Link
|
<Link
|
||||||
to={`/${item.id}`}
|
to={`/${item.id}`}
|
||||||
className="text-[1em] font-[500] hover:cursor-pointer hover:text-[#ffbade] transform transition-all ease-out line-clamp-1 max-[478px]:line-clamp-2 max-[478px]:text-[14px]"
|
className="text-[0.95em] font-medium text-gray-200 hover:text-white transform transition-all ease-out line-clamp-1 max-[478px]:line-clamp-2 max-[478px]:text-[14px]"
|
||||||
onClick={() => handleNavigate(item.id)}
|
onClick={() => handleNavigate(item.id)}
|
||||||
>
|
>
|
||||||
{language === "EN" ? item.title : item.japanese_title}
|
{language === "EN" ? item.title : item.japanese_title}
|
||||||
</Link>
|
</Link>
|
||||||
<div className="flex flex-wrap items-center w-fit space-x-1 max-[350px]:gap-y-[3px]">
|
<div className="flex flex-wrap items-center w-fit space-x-2 max-[350px]:gap-y-[3px]">
|
||||||
{item.tvInfo?.sub && (
|
{item.tvInfo?.sub && (
|
||||||
<div className="flex space-x-1 justify-center items-center bg-[#B0E3AF] rounded-[4px] px-[4px] text-black py-[2px]">
|
<div className="flex space-x-1 justify-center items-center bg-white bg-opacity-10 backdrop-blur-sm rounded-md px-1.5 py-0.5 transition-colors duration-200 hover:bg-opacity-20">
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faClosedCaptioning}
|
icon={faClosedCaptioning}
|
||||||
className="text-[12px]"
|
className="text-[11px] text-gray-300"
|
||||||
/>
|
/>
|
||||||
<p className="text-[12px] font-bold">
|
<p className="text-[11px] font-medium text-gray-300">
|
||||||
{item.tvInfo.sub}
|
{item.tvInfo.sub}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{item.tvInfo?.dub && (
|
{item.tvInfo?.dub && (
|
||||||
<div className="flex space-x-1 justify-center items-center bg-[#B9E7FF] rounded-[4px] px-[8px] text-black py-[2px]">
|
<div className="flex space-x-1 justify-center items-center bg-white bg-opacity-10 backdrop-blur-sm rounded-md px-1.5 py-0.5 transition-colors duration-200 hover:bg-opacity-20">
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faMicrophone}
|
icon={faMicrophone}
|
||||||
className="text-[12px]"
|
className="text-[11px] text-gray-300"
|
||||||
/>
|
/>
|
||||||
<p className="text-[12px] font-bold">
|
<p className="text-[11px] font-medium text-gray-300">
|
||||||
{item.tvInfo.dub}
|
{item.tvInfo.dub}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,74 +1,79 @@
|
|||||||
import { Pagination, Navigation } from "swiper/modules";
|
|
||||||
import { Swiper, SwiperSlide } from "swiper/react";
|
|
||||||
import { FaChevronLeft, FaChevronRight } from "react-icons/fa";
|
|
||||||
import { useLanguage } from "@/src/context/LanguageContext";
|
import { useLanguage } from "@/src/context/LanguageContext";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
import {
|
||||||
|
faClosedCaptioning,
|
||||||
|
faMicrophone,
|
||||||
|
faFire
|
||||||
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
const Trending = ({ trending }) => {
|
const Trending = ({ trending, className }) => {
|
||||||
const { language } = useLanguage();
|
const { language } = useLanguage();
|
||||||
const navigate = useNavigate();
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-6 max-[1200px]:px-4 max-md:px-0">
|
<div className={`bg-[#141414] rounded-lg p-6 ${className}`}>
|
||||||
<h1 className="text-[#ffbade] text-2xl font-bold max-md:pl-4">
|
<div className="flex items-center gap-2 mb-4">
|
||||||
Trending
|
<FontAwesomeIcon icon={faFire} className="text-white/90" />
|
||||||
</h1>
|
<h2 className="text-xl font-semibold text-white">Trending Now</h2>
|
||||||
<div className="pr-[60px] relative mx-auto overflow-hidden z-[1] mt-6 max-[759px]:pr-0">
|
</div>
|
||||||
<Swiper
|
<div className="flex flex-col space-y-2 max-h-[600px] overflow-y-auto pr-2 scrollbar-thin scrollbar-track-[#1a1a1a] scrollbar-thumb-[#2a2a2a] hover:scrollbar-thumb-[#333] scrollbar-thumb-rounded">
|
||||||
className="w-full h-full"
|
{trending &&
|
||||||
slidesPerView={3}
|
trending.map((item, index) => (
|
||||||
spaceBetween={2}
|
<div key={index} className="group">
|
||||||
breakpoints={{
|
<Link
|
||||||
479: { spaceBetween: 15 },
|
to={`/${item.id}`}
|
||||||
575: { spaceBetween: 15 },
|
onClick={() => window.scrollTo({ top: 0, behavior: "smooth" })}
|
||||||
640: { slidesPerView: 3, spaceBetween: 15 },
|
className="block"
|
||||||
900: { slidesPerView: 4, spaceBetween: 15 },
|
|
||||||
1300: { slidesPerView: 6, spaceBetween: 15 },
|
|
||||||
}}
|
|
||||||
modules={[Pagination, Navigation]}
|
|
||||||
navigation={{
|
|
||||||
nextEl: ".btn-next",
|
|
||||||
prevEl: ".btn-prev",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{trending &&
|
|
||||||
trending.map((item, idx) => (
|
|
||||||
<SwiperSlide
|
|
||||||
key={idx}
|
|
||||||
className="text-center flex text-[18px] justify-center items-center"
|
|
||||||
onClick={() => navigate(`/watch/${item.id}`)}
|
|
||||||
>
|
>
|
||||||
<div className="w-full h-auto pb-[115%] relative inline-block overflow-hidden max-[575px]:pb-[150%]">
|
<div className="flex items-start gap-3 p-2 rounded-lg transition-colors hover:bg-[#1a1a1a]">
|
||||||
<div className="absolute left-0 top-0 bottom-0 overflow-hidden w-[40px] text-center font-semibold bg-[#201F31] max-[575px]:top-0 max-[575px]:h-[30px] max-[575px]:z-[9] max-[575px]:bg-white">
|
<div className="relative">
|
||||||
<span className="absolute left-0 right-0 bottom-0 text-[24px] leading-[1.1em] text-center z-[9] transform -rotate-90 max-[575px]:transform max-[575px]:rotate-0 max-[575px]:text-[#111] max-[575px]:text-[18px] max-[575px]:leading-[30px]">
|
<img
|
||||||
{item.number}
|
src={item.poster}
|
||||||
</span>
|
alt={item.title}
|
||||||
<div className="w-[150px] h-fit text-left transform -rotate-90 absolute bottom-[100px] left-[-55px] leading-[40px] text-ellipsis whitespace-nowrap overflow-hidden text-white text-[16px] font-medium">
|
className="w-[50px] h-[70px] rounded object-cover"
|
||||||
{language === "EN" ? item.title : item.japanese_title}
|
/>
|
||||||
|
<div className="absolute top-0 left-0 bg-white/90 text-black text-xs font-bold px-1.5 rounded-br">
|
||||||
|
#{index + 1}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-1.5 flex-1 min-w-0">
|
||||||
|
<span className="text-sm font-medium text-gray-200 group-hover:text-white transition-colors line-clamp-2">
|
||||||
|
{language === "EN" ? item.title : item.japanese_title}
|
||||||
|
</span>
|
||||||
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
|
{item.tvInfo?.sub && (
|
||||||
|
<div className="flex items-center gap-1 px-1.5 py-0.5 bg-[#2a2a2a] rounded text-gray-300">
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faClosedCaptioning}
|
||||||
|
className="text-[10px]"
|
||||||
|
/>
|
||||||
|
<span className="text-[10px] font-medium">
|
||||||
|
{item.tvInfo.sub}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{item.tvInfo?.dub && (
|
||||||
|
<div className="flex items-center gap-1 px-1.5 py-0.5 bg-[#2a2a2a] rounded text-gray-300">
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faMicrophone}
|
||||||
|
className="text-[10px]"
|
||||||
|
/>
|
||||||
|
<span className="text-[10px] font-medium">
|
||||||
|
{item.tvInfo.dub}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{item.tvInfo?.showType && (
|
||||||
|
<span className="text-xs text-gray-400">
|
||||||
|
{item.tvInfo.showType}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Link
|
|
||||||
to={`/${item.id}`}
|
|
||||||
className="inline-block bg-[#2a2c31] absolute w-auto left-[40px] right-0 top-0 bottom-0 max-[575px]:left-0 max-[575px]:top-0 max-[575px]:bottom-0"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src={`${item.poster}`}
|
|
||||||
alt={item.title}
|
|
||||||
className="block w-full h-full object-cover hover:cursor-pointer"
|
|
||||||
title={item.title}
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
</div>
|
</div>
|
||||||
</SwiperSlide>
|
</Link>
|
||||||
))}
|
</div>
|
||||||
</Swiper>
|
))}
|
||||||
<div className="absolute top-0 right-0 bottom-0 w-[45px] flex flex-col space-y-2 max-[759px]:hidden">
|
|
||||||
<div className="btn-next bg-[#383747] h-[50%] flex justify-center items-center rounded-[8px] cursor-pointer transition-all duration-300 ease-out hover:bg-[#ffbade] hover:text-[#383747]">
|
|
||||||
<FaChevronRight />
|
|
||||||
</div>
|
|
||||||
<div className="btn-prev bg-[#383747] h-[50%] flex justify-center items-center rounded-[8px] cursor-pointer transition-all duration-300 ease-out hover:bg-[#ffbade] hover:text-[#383747]">
|
|
||||||
<FaChevronLeft />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import website_name from "@/src/config/website.js";
|
import website_name from "@/src/config/website.js";
|
||||||
import Spotlight from "@/src/components/spotlight/Spotlight.jsx";
|
import Spotlight from "@/src/components/spotlight/Spotlight.jsx";
|
||||||
import Trending from "@/src/components/trending/Trending.jsx";
|
import Trending from "@/src/components/trending/Trending.jsx";
|
||||||
import Cart from "@/src/components/cart/Cart.jsx";
|
|
||||||
import CategoryCard from "@/src/components/categorycard/CategoryCard.jsx";
|
import CategoryCard from "@/src/components/categorycard/CategoryCard.jsx";
|
||||||
import Genre from "@/src/components/genres/Genre.jsx";
|
import Genre from "@/src/components/genres/Genre.jsx";
|
||||||
import Topten from "@/src/components/topten/Topten.jsx";
|
import Topten from "@/src/components/topten/Topten.jsx";
|
||||||
@@ -10,6 +9,7 @@ import Error from "@/src/components/error/Error.jsx";
|
|||||||
import { useHomeInfo } from "@/src/context/HomeInfoContext.jsx";
|
import { useHomeInfo } from "@/src/context/HomeInfoContext.jsx";
|
||||||
import Schedule from "@/src/components/schedule/Schedule";
|
import Schedule from "@/src/components/schedule/Schedule";
|
||||||
import ContinueWatching from "@/src/components/continue/ContinueWatching";
|
import ContinueWatching from "@/src/components/continue/ContinueWatching";
|
||||||
|
import TabbedAnimeSection from "@/src/components/tabbed-anime/TabbedAnimeSection";
|
||||||
|
|
||||||
function Home() {
|
function Home() {
|
||||||
const { homeInfo, homeInfoLoading, error } = useHomeInfo();
|
const { homeInfo, homeInfoLoading, error } = useHomeInfo();
|
||||||
@@ -24,56 +24,27 @@ function Home() {
|
|||||||
<Genre data={homeInfo.genres} />
|
<Genre data={homeInfo.genres} />
|
||||||
</div>
|
</div>
|
||||||
<ContinueWatching />
|
<ContinueWatching />
|
||||||
<Trending trending={homeInfo.trending} />
|
|
||||||
<div className="mt-10 flex gap-6 max-[1200px]:px-4 max-[1200px]:grid max-[1200px]:grid-cols-2 max-[1200px]:mt-12 max-[1200px]:gap-y-10 max-[680px]:grid-cols-1">
|
|
||||||
<Cart
|
|
||||||
label="Top Airing"
|
|
||||||
data={homeInfo.top_airing}
|
|
||||||
path="top-airing"
|
|
||||||
/>
|
|
||||||
<Cart
|
|
||||||
label="Most Popular"
|
|
||||||
data={homeInfo.most_popular}
|
|
||||||
path="most-popular"
|
|
||||||
/>
|
|
||||||
<Cart
|
|
||||||
label="Most Favorite"
|
|
||||||
data={homeInfo.most_favorite}
|
|
||||||
path="most-favorite"
|
|
||||||
/>
|
|
||||||
<Cart
|
|
||||||
label="Latest Completed"
|
|
||||||
data={homeInfo.latest_completed}
|
|
||||||
path="completed"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="w-full grid grid-cols-[minmax(0,75%),minmax(0,25%)] gap-x-6 max-[1200px]:flex flex-col max-[1200px]:px-4">
|
<div className="w-full grid grid-cols-[minmax(0,75%),minmax(0,25%)] gap-x-6 max-[1200px]:flex flex-col max-[1200px]:px-4">
|
||||||
<div>
|
<div>
|
||||||
<CategoryCard
|
<CategoryCard
|
||||||
label="Latest Episode"
|
label="Latest Episode"
|
||||||
data={homeInfo.latest_episode}
|
data={homeInfo.latest_episode}
|
||||||
className={"mt-[60px]"}
|
className="mt-[60px]"
|
||||||
path="recently-updated"
|
path="recently-updated"
|
||||||
limit={12}
|
limit={12}
|
||||||
/>
|
/>
|
||||||
<CategoryCard
|
<Schedule className="mt-8" />
|
||||||
label={`New On ${website_name}`}
|
<TabbedAnimeSection
|
||||||
data={homeInfo.recently_added}
|
topAiring={homeInfo.top_airing}
|
||||||
className={"mt-[60px]"}
|
mostFavorite={homeInfo.most_favorite}
|
||||||
path="recently-added"
|
latestCompleted={homeInfo.latest_completed}
|
||||||
limit={12}
|
className="mt-8"
|
||||||
/>
|
|
||||||
<Schedule />
|
|
||||||
<CategoryCard
|
|
||||||
label="Top Upcoming"
|
|
||||||
data={homeInfo.top_upcoming}
|
|
||||||
className={"mt-[30px]"}
|
|
||||||
path="top-upcoming"
|
|
||||||
limit={12}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full mt-[60px]">
|
<div className="w-full mt-[60px]">
|
||||||
<Topten data={homeInfo.topten} className={"mt-12"} />
|
<Trending trending={homeInfo.trending} />
|
||||||
|
<Topten data={homeInfo.topten} className="mt-12" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -51,17 +51,6 @@ function Category({ path, label }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full flex flex-col gap-y-4 mt-[64px] max-md:mt-[50px]">
|
<div className="w-full flex flex-col gap-y-4 mt-[64px] max-md:mt-[50px]">
|
||||||
<div className="w-full flex gap-x-4 items-center bg-[#191826] p-5 max-[575px]:px-3 max-[320px]:hidden">
|
|
||||||
<img
|
|
||||||
src="https://media.tenor.com/hJfxLKzDUFcAAAAM/bleach-best-anime.gif"
|
|
||||||
alt="Share Anime"
|
|
||||||
className="w-[60px] h-auto rounded-full max-[1024px]:w-[40px] max-[575px]:hidden"
|
|
||||||
/>
|
|
||||||
<div className="flex flex-col w-fit">
|
|
||||||
<p className="text-[15px] font-bold text-[#FFBADE]">Share Anime</p>
|
|
||||||
<p className="text-[16px] text-white">to your friends</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{categoryInfo ? (
|
{categoryInfo ? (
|
||||||
<div className="w-full px-4 grid grid-cols-[minmax(0,75%),minmax(0,25%)] gap-x-6 max-[1200px]:flex max-[1200px]:flex-col max-[1200px]:gap-y-10">
|
<div className="w-full px-4 grid grid-cols-[minmax(0,75%),minmax(0,25%)] gap-x-6 max-[1200px]:flex max-[1200px]:flex-col max-[1200px]:gap-y-10">
|
||||||
{page > totalPages ? (
|
{page > totalPages ? (
|
||||||
|
|||||||
@@ -9,17 +9,14 @@ import IframePlayer from "@/src/components/player/IframePlayer";
|
|||||||
import Episodelist from "@/src/components/episodelist/Episodelist";
|
import Episodelist from "@/src/components/episodelist/Episodelist";
|
||||||
import website_name from "@/src/config/website";
|
import website_name from "@/src/config/website";
|
||||||
import Sidecard from "@/src/components/sidecard/Sidecard";
|
import Sidecard from "@/src/components/sidecard/Sidecard";
|
||||||
import CategoryCard from "@/src/components/categorycard/CategoryCard";
|
|
||||||
import {
|
import {
|
||||||
faClosedCaptioning,
|
faClosedCaptioning,
|
||||||
faMicrophone,
|
faMicrophone,
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import Servers from "@/src/components/servers/Servers";
|
import Servers from "@/src/components/servers/Servers";
|
||||||
import CategoryCardLoader from "@/src/components/Loader/CategoryCard.loader";
|
|
||||||
import { Skeleton } from "@/src/components/ui/Skeleton/Skeleton";
|
import { Skeleton } from "@/src/components/ui/Skeleton/Skeleton";
|
||||||
import SidecardLoader from "@/src/components/Loader/Sidecard.loader";
|
import SidecardLoader from "@/src/components/Loader/Sidecard.loader";
|
||||||
import Voiceactor from "@/src/components/voiceactor/Voiceactor";
|
|
||||||
import Watchcontrols from "@/src/components/watchcontrols/Watchcontrols";
|
import Watchcontrols from "@/src/components/watchcontrols/Watchcontrols";
|
||||||
import useWatchControl from "@/src/hooks/useWatchControl";
|
import useWatchControl from "@/src/hooks/useWatchControl";
|
||||||
import Player from "@/src/components/player/Player";
|
import Player from "@/src/components/player/Player";
|
||||||
|
|||||||
Reference in New Issue
Block a user