diff --git a/package.json b/package.json
index 0abc694..3e6c4ea 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,8 @@
"@fortawesome/free-solid-svg-icons": "^6.6.0",
"@fortawesome/react-fontawesome": "^0.2.2",
"@radix-ui/react-icons": "^1.3.0",
+ "@vercel/analytics": "^1.5.0",
+ "@vercel/speed-insights": "^1.2.0",
"artplayer": "^5.2.3",
"artplayer-plugin-chapter": "^1.0.0",
"artplayer-plugin-hls-control": "^1.0.1",
diff --git a/src/App.jsx b/src/App.jsx
index fffc4a2..072492c 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -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() {
{!isSplashScreen && }
+
+
);
diff --git a/src/components/categorycard/CategoryCard.css b/src/components/categorycard/CategoryCard.css
index 7766feb..91b2dc0 100644
--- a/src/components/categorycard/CategoryCard.css
+++ b/src/components/categorycard/CategoryCard.css
@@ -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;
+}
diff --git a/src/components/categorycard/CategoryCard.jsx b/src/components/categorycard/CategoryCard.jsx
index d3a20a8..72f6668 100644
--- a/src/components/categorycard/CategoryCard.jsx
+++ b/src/components/categorycard/CategoryCard.jsx
@@ -87,19 +87,20 @@ const CategoryCard = React.memo(
};
return (
-
-
+
+
{label}
{showViewMore && (
-
- View more
-
-
+ View all
+
)}
@@ -115,12 +116,12 @@ const CategoryCard = React.memo(
{itemsToRender.firstRow.map((item, index) => (
(cardRefs.current[index] = el)}
>
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]"
/>
)}
-
-
+
{(item.tvInfo?.rating === "18+" ||
item?.adultContent === true) && (
-
+
18+
)}
-
- {item.tvInfo?.sub && (
-
-
-
- {item.tvInfo.sub}
-
+
+
+ {item.tvInfo?.sub && (
+
+
+
+ {item.tvInfo.sub}
+
+
+ )}
+ {item.tvInfo?.dub && (
+
+
+
+ {item.tvInfo.dub}
+
+
+ )}
+ {item.tvInfo?.eps && (
+
+
+ {item.tvInfo.eps}
+
+
+ )}
+
+
+ {language === "EN" ? item.title : item.japanese_title}
+
+
+
+ {item.tvInfo.showType.split(" ").shift()}
- )}
- {item.tvInfo?.dub && (
-
-
-
- {item.tvInfo.dub}
-
+
+
+ {item.tvInfo?.duration === "m" ||
+ item.tvInfo?.duration === "?" ||
+ item.duration === "m" ||
+ item.duration === "?"
+ ? "N/A"
+ : item.tvInfo?.duration || item.duration || "N/A"}
- )}
- {item.tvInfo?.eps && (
-
-
- {item.tvInfo.eps}
-
-
- )}
+
{hoveredItem === item.id + index &&
window.innerWidth > 1024 && (
@@ -198,31 +220,11 @@ const CategoryCard = React.memo(
)}
-
- {language === "EN" ? item.title : item.japanese_title}
-
{item.description && (
-
+
{item.description}
)}
-
-
- {item.tvInfo.showType.split(" ").shift()}
-
-
-
- {item.tvInfo?.duration === "m" ||
- item.tvInfo?.duration === "?" ||
- item.duration === "m" ||
- item.duration === "?"
- ? "N/A"
- : item.tvInfo?.duration || item.duration || "N/A"}
-
-
))}
diff --git a/src/components/continue/ContinueWatching.jsx b/src/components/continue/ContinueWatching.jsx
index 530dbef..3d18696 100644
--- a/src/components/continue/ContinueWatching.jsx
+++ b/src/components/continue/ContinueWatching.jsx
@@ -46,10 +46,10 @@ const ContinueWatching = () => {
-
@@ -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) => (
{
return (
<>
-
+
-
+
Estimated Schedule
-
+
({GMTOffset}) {currentTime.toLocaleDateString()}{" "}
{currentTime.toLocaleTimeString()}
-
+
{
(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"
}`}
>
-
+
{date.dayname}
{date.monthName} {date.day}
@@ -172,28 +172,28 @@ const Schedule = () => {
))}
-
+
-
+
{loading ? (
-
+
) : !scheduleData || scheduleData.length === 0 ? (
-
+
No data to display
) : error ? (
-
+
Something went wrong
) : (
-
+
{(showAll
? scheduleData
: Array.isArray(scheduleData)
@@ -203,31 +203,31 @@ const Schedule = () => {
-
-
+
+
{item.time || "N/A"}
-
+
{item.title || "N/A"}
-
+
-
- Episode {item.episode_no || "N/A"}
+
+ EP {item.episode_no || "N/A"}
-
+
))}
{scheduleData.length > 7 && (
{showAll ? "Show Less" : "Show More"}
diff --git a/src/components/schedule/schedule.css b/src/components/schedule/schedule.css
index 440906f..14612f2 100644
--- a/src/components/schedule/schedule.css
+++ b/src/components/schedule/schedule.css
@@ -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;
}
diff --git a/src/components/sidebar/Sidebar.jsx b/src/components/sidebar/Sidebar.jsx
index 37e7b5c..b463124 100644
--- a/src/components/sidebar/Sidebar.jsx
+++ b/src/components/sidebar/Sidebar.jsx
@@ -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 },
diff --git a/src/components/tabbed-anime/TabbedAnimeSection.jsx b/src/components/tabbed-anime/TabbedAnimeSection.jsx
new file mode 100644
index 0000000..e1c8416
--- /dev/null
+++ b/src/components/tabbed-anime/TabbedAnimeSection.jsx
@@ -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 (
+
+
+
+ {tabs.map((tab) => (
+ 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
+ `}
+ >
+
+ {tab.label}
+
+
+ ))}
+
+
+ View all
+
+
+
+
+
+
+ );
+}
+
+TabbedAnimeSection.propTypes = {
+ topAiring: PropTypes.array.isRequired,
+ mostFavorite: PropTypes.array.isRequired,
+ latestCompleted: PropTypes.array.isRequired,
+ className: PropTypes.string,
+};
+
+export default TabbedAnimeSection;
\ No newline at end of file
diff --git a/src/components/topten/Topten.jsx b/src/components/topten/Topten.jsx
index 6b54316..169fb0e 100644
--- a/src/components/topten/Topten.jsx
+++ b/src/components/topten/Topten.jsx
@@ -49,19 +49,17 @@ function Topten({ data, className }) {
};
return (
-
+
-
Top 10
-
+ Top 10
+
{["today", "week", "month"].map((period) => (
- handlePeriodChange(period)}
>
@@ -71,19 +69,19 @@ function Topten({ data, className }) {
-
+
{currentData &&
currentData.map((item, index) => (
(cardRefs.current[index] = el)}
>
{`${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 */}
navigate(`/watch/${item.id}`)}
onMouseEnter={() => handleMouseEnter(item, index)}
onMouseLeave={handleMouseLeave}
@@ -132,33 +129,33 @@ function Topten({ data, className }) {
)}
-
+
handleNavigate(item.id)}
>
{language === "EN" ? item.title : item.japanese_title}
-
+
{item.tvInfo?.sub && (
-
+
)}
{item.tvInfo?.dub && (
-
+
diff --git a/src/components/trending/Trending.jsx b/src/components/trending/Trending.jsx
index dd9ea4f..b70e866 100644
--- a/src/components/trending/Trending.jsx
+++ b/src/components/trending/Trending.jsx
@@ -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 (
-
-
- Trending
-
-
-
- {trending &&
- trending.map((item, idx) => (
- navigate(`/watch/${item.id}`)}
+
+
+
+
Trending Now
+
+
+ {trending &&
+ trending.map((item, index) => (
+
+
window.scrollTo({ top: 0, behavior: "smooth" })}
+ className="block"
>
-
-
-
- {item.number}
-
-
- {language === "EN" ? item.title : item.japanese_title}
+
+
+

+
+ #{index + 1}
+
+
+
+
+ {language === "EN" ? item.title : item.japanese_title}
+
+
+ {item.tvInfo?.sub && (
+
+
+
+ {item.tvInfo.sub}
+
+
+ )}
+ {item.tvInfo?.dub && (
+
+
+
+ {item.tvInfo.dub}
+
+
+ )}
+ {item.tvInfo?.showType && (
+
+ {item.tvInfo.showType}
+
+ )}
-
-

-
-
- ))}
-
-
+
+
+ ))}
);
diff --git a/src/pages/Home/Home.jsx b/src/pages/Home/Home.jsx
index 0557494..e6af014 100644
--- a/src/pages/Home/Home.jsx
+++ b/src/pages/Home/Home.jsx
@@ -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() {
-
-
-
-
-
-
-
+
diff --git a/src/pages/category/Category.jsx b/src/pages/category/Category.jsx
index acaca32..2ee67fb 100644
--- a/src/pages/category/Category.jsx
+++ b/src/pages/category/Category.jsx
@@ -51,17 +51,6 @@ function Category({ path, label }) {
return (
-
-

-
-
Share Anime
-
to your friends
-
-
{categoryInfo ? (
{page > totalPages ? (
diff --git a/src/pages/watch/Watch.jsx b/src/pages/watch/Watch.jsx
index dccb864..c5b88cc 100644
--- a/src/pages/watch/Watch.jsx
+++ b/src/pages/watch/Watch.jsx
@@ -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";