home page improved

This commit is contained in:
Tejas Panchal
2025-07-31 22:28:03 +05:30
parent 18e36d8b63
commit 8ee1ff1754
14 changed files with 371 additions and 270 deletions

View File

@@ -1,6 +1,8 @@
import { useLocation } from "react-router-dom";
import { useEffect } from "react";
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 Home from "./pages/Home/Home";
import AnimeInfo from "./pages/animeInfo/AnimeInfo";
@@ -71,6 +73,8 @@ function App() {
</Routes>
{!isSplashScreen && <Footer />}
</main>
<Analytics />
<SpeedInsights />
</div>
</HomeInfoProvider>
);

View File

@@ -7,79 +7,132 @@
right: 0;
bottom: 0;
background: linear-gradient(
to top,
rgba(18, 18, 18, 1) 0%,
rgba(18, 18, 18, 0.7) 20%,
rgba(18, 18, 18, 0) 60%,
rgba(18, 18, 18, 0.2) 100%
180deg,
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 0.4) 50%,
rgba(0, 0, 0, 0.95) 100%
);
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 {
background: linear-gradient(
to top,
rgba(18, 18, 18, 0.95) 0%,
rgba(18, 18, 18, 0.8) 50%,
rgba(18, 18, 18, 0.6) 100%
180deg,
rgba(0, 0, 0, 0.2) 0%,
rgba(0, 0, 0, 0.6) 50%,
rgba(0, 0, 0, 0.98) 100%
);
}
.dot {
width: 3px;
height: 3px;
width: 2px;
height: 2px;
display: inline-block;
border-radius: 50%;
background: rgba(255, 255, 255, 0.4);
margin: 0 4px;
margin: 0 6px;
position: relative;
top: -1px;
}
/* Modern Card Styles */
.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 {
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 {
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
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;
border-radius: 4px;
font-weight: 600;
font-weight: 500;
letter-spacing: 0.02em;
transition: all 0.3s ease;
}
.category-badge:hover {
background: rgba(255, 255, 255, 0.15);
border-color: rgba(255, 255, 255, 0.2);
}
.item-title {
font-weight: 500;
font-weight: 600;
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 {
color: #ffffff;
text-shadow: 0 0 20px rgba(255, 255, 255, 0.2);
}
.play-icon {
opacity: 0;
transform: translate(-50%, -50%) scale(0.8);
transition: all 0.3s ease;
transform: translate(-50%, -50%) scale(0.9);
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 {
opacity: 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;
}

View File

@@ -87,19 +87,20 @@ const CategoryCard = React.memo(
};
return (
<div className={`w-full ${className}`}>
<div className="flex items-center justify-between mb-6">
<h1 className="font-bold text-2xl text-white max-[478px]:text-[18px] capitalize tracking-wide">
<div className="flex items-center justify-between mb-8">
<h1 className="font-semibold text-2xl text-white max-[478px]:text-[18px] capitalize tracking-wide">
{label}
</h1>
{showViewMore && (
<Link
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 more
</p>
<FaChevronRight className="text-gray-300 text-[10px] group-hover:text-white transition-all ease-out" />
View all
<FaChevronRight className="text-[10px] transform transition-transform duration-300
group-hover:translate-x-0.5" />
</Link>
)}
</div>
@@ -115,12 +116,12 @@ const CategoryCard = React.memo(
{itemsToRender.firstRow.map((item, index) => (
<div
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" }}
ref={(el) => (cardRefs.current[index] = el)}
>
<div
className="w-full relative group hover:cursor-pointer"
className="w-full relative group hover:cursor-pointer overflow-hidden rounded-xl"
onClick={() =>
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]"
/>
)}
<div className="overlay"></div>
<div className="overflow-hidden">
<div className="overflow-hidden rounded-xl">
<img
src={`${item.poster}`}
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>
{(item.tvInfo?.rating === "18+" ||
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+
</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]">
{item.tvInfo?.sub && (
<div className="category-badge flex space-x-1 justify-center items-center">
<FontAwesomeIcon
icon={faClosedCaptioning}
className="text-[12px] text-white/90"
/>
<p className="text-[12px] text-white/90">
{item.tvInfo.sub}
</p>
<div className="info-container">
<div className="flex items-center justify-start w-fit space-x-2 z-[100] max-[270px]:flex-col max-[270px]:gap-y-[3px]">
{item.tvInfo?.sub && (
<div className="category-badge flex space-x-1 justify-center items-center">
<FontAwesomeIcon
icon={faClosedCaptioning}
className="text-[12px] text-white/90"
/>
<p className="text-[12px] text-white/90">
{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>
)}
{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 className="dot"></div>
<div className="text-gray-300 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>
)}
{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 &&
window.innerWidth > 1024 && (
@@ -198,31 +220,11 @@ const CategoryCard = React.memo(
</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 && (
<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}
</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>

View File

@@ -46,10 +46,10 @@ const ContinueWatching = () => {
</div>
<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" />
</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" />
</button>
</div>
@@ -70,11 +70,11 @@ const ContinueWatching = () => {
}}
modules={[Navigation]}
navigation={{
nextEl: ".btn-next",
prevEl: ".btn-prev",
nextEl: ".continue-btn-next",
prevEl: ".continue-btn-prev",
}}
>
{memoizedWatchList.map((item, index) => (
{memoizedWatchList.slice().reverse().map((item, index) => (
<SwiperSlide
key={index}
className="text-center flex justify-center items-center"

View File

@@ -114,28 +114,28 @@ const Schedule = () => {
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="font-bold text-2xl text-[#ffbade] max-[478px]:text-[18px]">
<div className="font-bold text-2xl text-white max-[478px]:text-[18px]">
Estimated Schedule
</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()}{" "}
{currentTime.toLocaleTimeString()}
</p>
</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">
<Swiper
slidesPerView={3}
spaceBetween={2}
breakpoints={{
250: { slidesPerView: 3, spaceBetween: 10 },
640: { slidesPerView: 4, spaceBetween: 10 },
768: { slidesPerView: 5, spaceBetween: 10 },
1024: { slidesPerView: 7, spaceBetween: 10 },
1300: { slidesPerView: 7, spaceBetween: 15 },
250: { slidesPerView: 3, spaceBetween: 8 },
640: { slidesPerView: 4, spaceBetween: 8 },
768: { slidesPerView: 5, spaceBetween: 8 },
1024: { slidesPerView: 7, spaceBetween: 8 },
1300: { slidesPerView: 7, spaceBetween: 8 },
}}
modules={[Pagination, Navigation]}
navigation={{
@@ -150,20 +150,20 @@ const Schedule = () => {
<div
ref={(el) => (cardRefs.current[index] = el)}
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
? "bg-[#ffbade] text-black"
: "bg-white bg-opacity-5 text-[#ffffff] hover:bg-[#373646] transition-all duration-300 ease-in-out"
? "bg-white text-black"
: "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}
</div>
<div
className={`text-[14px] max-[400px]:text-[12px] ${
className={`text-[13px] max-[400px]:text-[11px] ${
currentActiveIndex === index
? "text-black"
: "text-gray-400"
? "text-zinc-800"
: "text-zinc-400"
} max-[350px]:text-[10px]`}
>
{date.monthName} {date.day}
@@ -172,28 +172,28 @@ const Schedule = () => {
</SwiperSlide>
))}
</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]" />
</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]" />
</button>
</div>
</div>
{loading ? (
<div className="w-full h-[70px] flex justify-center items-center">
<div className="w-full h-[60px] flex justify-center items-center">
<BouncingLoader />
</div>
) : !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
</div>
) : 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
</div>
) : (
<div className="flex flex-col mt-5 items-start">
<div className="flex flex-col mt-4 items-start">
{(showAll
? scheduleData
: Array.isArray(scheduleData)
@@ -203,31 +203,31 @@ const Schedule = () => {
<Link
to={`/${item.id}`}
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="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="flex items-center max-w-[500px] gap-x-4 max-[400px]:gap-x-2">
<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"}
</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"}
</h3>
</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
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]">
Episode {item.episode_no || "N/A"}
<p className="text-[13px] text-zinc-400 group-hover:text-black max-[275px]:text-[12px]">
EP {item.episode_no || "N/A"}
</p>
</button>
</div>
</Link>
))}
{scheduleData.length > 7 && (
<button
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"}
</button>

View File

@@ -1,11 +1,18 @@
.next,
.prev {
width: 30px;
height: 30px;
border-radius: 100%;
background-color: white;
color: black;
font-size: 13px;
padding: 10px;
width: 24px;
height: 24px;
border-radius: 6px;
background-color: rgb(39 39 42);
color: rgb(161 161 170);
font-size: 12px;
padding: 6px;
z-index: 10;
transition: all 0.2s;
}
.next:hover,
.prev:hover {
background-color: rgb(63 63 70);
color: white;
}

View File

@@ -8,6 +8,8 @@ import "./Sidebar.css";
const MENU_ITEMS = [
{ 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: "Dubbed Anime", path: "/dubbed-anime", icon: faPlay },
{ name: "Most Popular", path: "/most-popular", icon: faFire },

View 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;

View File

@@ -49,19 +49,17 @@ function Topten({ data, className }) {
};
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">
<h1 className="font-bold text-2xl text-[#ffbade]">Top 10</h1>
<ul className="flex justify-between w-fit bg-[#373646] rounded-[4px] text-sm font-bold">
<h1 className="font-bold text-2xl text-white tracking-tight">Top 10</h1>
<ul className="flex justify-between w-fit bg-[#1a1a1a] rounded-lg overflow-hidden shadow-lg">
{["today", "week", "month"].map((period) => (
<li
key={period}
className={`cursor-pointer p-2 px-3 ${
className={`cursor-pointer p-1.5 px-4 transition-all duration-200 ${
activePeriod === period
? "bg-[#ffbade] text-[#555462]"
: "text-white hover:text-[#ffbade]"
} ${period === "today" ? "rounded-l-[4px]" : ""} ${
period === "month" ? "rounded-r-[4px]" : ""
? "bg-white text-black font-medium"
: "text-gray-400 hover:text-white hover:bg-[#2a2a2a]"
}`}
onClick={() => handlePeriodChange(period)}
>
@@ -71,19 +69,19 @@ function Topten({ data, className }) {
</ul>
</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.map((item, index) => (
<div
key={index}
className="flex items-center gap-x-4"
className="flex items-center gap-x-3 group"
ref={(el) => (cardRefs.current[index] = el)}
>
<h1
className={`font-bold text-2xl ${
className={`font-bold text-2xl transition-colors ${
index < 3
? "pb-1 text-white border-b-[3px] border-[#ffbade]"
: "text-[#777682]"
? "text-white border-b-2 border-white pb-0.5"
: "text-gray-600"
} max-[350px]:hidden`}
>
{`${index + 1 < 10 ? "0" : ""}${index + 1}`}
@@ -92,16 +90,15 @@ function Topten({ data, className }) {
style={{
borderBottom:
index + 1 < 10
? "1px solid rgba(255, 255, 255, .075)"
? "1px solid rgba(255, 255, 255, .1)"
: "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
src={`${item.poster}`}
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}`)}
onMouseEnter={() => handleMouseEnter(item, index)}
onMouseLeave={handleMouseLeave}
@@ -132,33 +129,33 @@ function Topten({ data, className }) {
</div>
)}
<div className="flex flex-col ml-4 space-y-2">
<div className="flex flex-col ml-3 space-y-1.5">
<Link
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)}
>
{language === "EN" ? item.title : item.japanese_title}
</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 && (
<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
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}
</p>
</div>
)}
{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
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}
</p>
</div>

View File

@@ -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 { 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 navigate = useNavigate();
return (
<div className="mt-6 max-[1200px]:px-4 max-md:px-0">
<h1 className="text-[#ffbade] text-2xl font-bold max-md:pl-4">
Trending
</h1>
<div className="pr-[60px] relative mx-auto overflow-hidden z-[1] mt-6 max-[759px]:pr-0">
<Swiper
className="w-full h-full"
slidesPerView={3}
spaceBetween={2}
breakpoints={{
479: { spaceBetween: 15 },
575: { spaceBetween: 15 },
640: { slidesPerView: 3, spaceBetween: 15 },
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={`bg-[#141414] rounded-lg p-6 ${className}`}>
<div className="flex items-center gap-2 mb-4">
<FontAwesomeIcon icon={faFire} className="text-white/90" />
<h2 className="text-xl font-semibold text-white">Trending Now</h2>
</div>
<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">
{trending &&
trending.map((item, index) => (
<div key={index} className="group">
<Link
to={`/${item.id}`}
onClick={() => window.scrollTo({ top: 0, behavior: "smooth" })}
className="block"
>
<div className="w-full h-auto pb-[115%] relative inline-block overflow-hidden max-[575px]:pb-[150%]">
<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">
<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]">
{item.number}
</span>
<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">
{language === "EN" ? item.title : item.japanese_title}
<div className="flex items-start gap-3 p-2 rounded-lg transition-colors hover:bg-[#1a1a1a]">
<div className="relative">
<img
src={item.poster}
alt={item.title}
className="w-[50px] h-[70px] rounded object-cover"
/>
<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>
<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>
</SwiperSlide>
))}
</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>
</Link>
</div>
))}
</div>
</div>
);

View File

@@ -1,7 +1,6 @@
import website_name from "@/src/config/website.js";
import Spotlight from "@/src/components/spotlight/Spotlight.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 Genre from "@/src/components/genres/Genre.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 Schedule from "@/src/components/schedule/Schedule";
import ContinueWatching from "@/src/components/continue/ContinueWatching";
import TabbedAnimeSection from "@/src/components/tabbed-anime/TabbedAnimeSection";
function Home() {
const { homeInfo, homeInfoLoading, error } = useHomeInfo();
@@ -24,56 +24,27 @@ function Home() {
<Genre data={homeInfo.genres} />
</div>
<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>
<CategoryCard
label="Latest Episode"
data={homeInfo.latest_episode}
className={"mt-[60px]"}
className="mt-[60px]"
path="recently-updated"
limit={12}
/>
<CategoryCard
label={`New On ${website_name}`}
data={homeInfo.recently_added}
className={"mt-[60px]"}
path="recently-added"
limit={12}
/>
<Schedule />
<CategoryCard
label="Top Upcoming"
data={homeInfo.top_upcoming}
className={"mt-[30px]"}
path="top-upcoming"
limit={12}
<Schedule className="mt-8" />
<TabbedAnimeSection
topAiring={homeInfo.top_airing}
mostFavorite={homeInfo.most_favorite}
latestCompleted={homeInfo.latest_completed}
className="mt-8"
/>
</div>
<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>

View File

@@ -51,17 +51,6 @@ function Category({ path, label }) {
return (
<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 ? (
<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 ? (

View File

@@ -9,17 +9,14 @@ import IframePlayer from "@/src/components/player/IframePlayer";
import Episodelist from "@/src/components/episodelist/Episodelist";
import website_name from "@/src/config/website";
import Sidecard from "@/src/components/sidecard/Sidecard";
import CategoryCard from "@/src/components/categorycard/CategoryCard";
import {
faClosedCaptioning,
faMicrophone,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import Servers from "@/src/components/servers/Servers";
import CategoryCardLoader from "@/src/components/Loader/CategoryCard.loader";
import { Skeleton } from "@/src/components/ui/Skeleton/Skeleton";
import SidecardLoader from "@/src/components/Loader/Sidecard.loader";
import Voiceactor from "@/src/components/voiceactor/Voiceactor";
import Watchcontrols from "@/src/components/watchcontrols/Watchcontrols";
import useWatchControl from "@/src/hooks/useWatchControl";
import Player from "@/src/components/player/Player";