mirror of
https://github.com/JustAnimeCore/JustAnime.git
synced 2026-04-17 22:01:45 +00:00
sidebar DONE
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
||||
faBars,
|
||||
faRandom,
|
||||
faMagnifyingGlass,
|
||||
faXmark,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { useLanguage } from "@/src/context/LanguageContext";
|
||||
import { Link, useLocation } from "react-router-dom";
|
||||
@@ -109,10 +110,14 @@ function Navbar() {
|
||||
<div className="md:hidden flex items-center">
|
||||
<button
|
||||
onClick={() => setIsMobileSearchOpen(!isMobileSearchOpen)}
|
||||
className="p-[10px] aspect-square bg-[#2a2a2a]/75 text-white/50 hover:text-white rounded-lg transition-colors flex items-center justify-center"
|
||||
title="Search Anime"
|
||||
className="p-[10px] aspect-square bg-[#2a2a2a]/75 text-white/50 hover:text-white rounded-lg transition-colors flex items-center justify-center w-[38px] h-[38px]"
|
||||
title={isMobileSearchOpen ? "Close Search" : "Search Anime"}
|
||||
>
|
||||
<FontAwesomeIcon icon={faMagnifyingGlass} className="text-lg" />
|
||||
<FontAwesomeIcon
|
||||
icon={isMobileSearchOpen ? faXmark : faMagnifyingGlass}
|
||||
className="w-[18px] h-[18px] transition-transform duration-200"
|
||||
style={{ transform: isMobileSearchOpen ? 'rotate(90deg)' : 'rotate(0deg)' }}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
33
src/components/sidebar/Sidebar.css
Normal file
33
src/components/sidebar/Sidebar.css
Normal file
@@ -0,0 +1,33 @@
|
||||
.sidebar {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(255, 255, 255, 0.2) transparent;
|
||||
}
|
||||
|
||||
.sidebar::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
}
|
||||
|
||||
.sidebar::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.sidebar::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
body.sidebar-open {
|
||||
overflow: hidden;
|
||||
padding-right: 5px; /* Prevent layout shift when scrollbar disappears */
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Wrapper to maintain scroll position when sidebar is opened */
|
||||
.sidebar-scroll-wrapper {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
@@ -1,22 +1,42 @@
|
||||
import { FaChevronLeft } from "react-icons/fa";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faFilm, faRandom } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faFilm, faRandom, faHome, faClock, faFire, faTv, faPlay, faCirclePlay, faFilePen, faPaperPlane } from "@fortawesome/free-solid-svg-icons";
|
||||
import { useLanguage } from "@/src/context/LanguageContext";
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { Link, useLocation } from "react-router-dom";
|
||||
import {
|
||||
cleanupScrollbar,
|
||||
toggleScrollbar,
|
||||
} from "@/src/helper/toggleScrollbar";
|
||||
import "./Sidebar.css";
|
||||
|
||||
const MENU_ITEMS = [
|
||||
{ name: "Home", path: "/home", icon: faHome },
|
||||
{ name: "Subbed Anime", path: "/subbed-anime", icon: faFilePen },
|
||||
{ name: "Dubbed Anime", path: "/dubbed-anime", icon: faPlay },
|
||||
{ name: "Most Popular", path: "/most-popular", icon: faFire },
|
||||
{ name: "Movies", path: "/movie", icon: faFilm },
|
||||
{ name: "TV Series", path: "/tv", icon: faTv },
|
||||
{ name: "OVAs", path: "/ova", icon: faCirclePlay },
|
||||
{ name: "ONAs", path: "/ona", icon: faPlay },
|
||||
{ name: "Specials", path: "/special", icon: faClock },
|
||||
{ name: "Join Telegram", path: "https://t.me/zenime_discussion", icon: faPaperPlane },
|
||||
];
|
||||
|
||||
const Sidebar = ({ isOpen, onClose }) => {
|
||||
const { language, toggleLanguage } = useLanguage();
|
||||
const location = useLocation();
|
||||
const scrollPosition = useRef(0);
|
||||
|
||||
useEffect(() => {
|
||||
toggleScrollbar(isOpen);
|
||||
if (isOpen) {
|
||||
scrollPosition.current = window.pageYOffset;
|
||||
document.body.classList.add('sidebar-open');
|
||||
document.body.style.top = `-${scrollPosition.current}px`;
|
||||
} else {
|
||||
document.body.classList.remove('sidebar-open');
|
||||
document.body.style.top = '';
|
||||
window.scrollTo(0, scrollPosition.current);
|
||||
}
|
||||
return () => {
|
||||
cleanupScrollbar();
|
||||
document.body.classList.remove('sidebar-open');
|
||||
document.body.style.top = '';
|
||||
};
|
||||
}, [isOpen]);
|
||||
|
||||
@@ -28,110 +48,83 @@ const Sidebar = ({ isOpen, onClose }) => {
|
||||
<>
|
||||
{isOpen && (
|
||||
<div
|
||||
className={`fixed top-0 left-0 bottom-0 right-0 w-screen h-screen transform transition-all duration-400 ease-in-out ${
|
||||
isOpen ? "backdrop-blur-lg" : "backdrop-blur-none"
|
||||
}`}
|
||||
className="fixed inset-0 transform transition-all duration-400 ease-in-out backdrop-blur-lg bg-black/50"
|
||||
onClick={onClose}
|
||||
style={{ zIndex: 1000000, background: "rgba(32, 31, 49, .8)" }}
|
||||
style={{ zIndex: 1000000 }}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div
|
||||
className={`fixed h-full top-0 left-0 z-50 flex transition-transform duration-300 ease-in-out ${
|
||||
className={`fixed h-[100dvh] w-[280px] max-[575px]:w-[260px] top-0 left-0 transform transition-transform duration-300 ease-in-out ${
|
||||
isOpen ? "translate-x-0" : "-translate-x-full"
|
||||
}`}
|
||||
style={{ zIndex: 1000200 }}
|
||||
>
|
||||
<div
|
||||
className="bg-white/10 w-[260px] py-8 h-full flex flex-col items-start max-[575px]:w-56 overflow-y-auto sidebar"
|
||||
style={{
|
||||
zIndex: 300,
|
||||
borderRight: "1px solid rgba(0, 0, 0, .1)",
|
||||
}}
|
||||
className="bg-[#0a0a0a] w-full h-full flex flex-col items-start overflow-y-auto sidebar"
|
||||
>
|
||||
<div className="px-4 w-full">
|
||||
{/* Header */}
|
||||
<div className="w-full p-6 border-b border-white/5">
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="w-full text-white flex items-baseline h-fit gap-x-1 z-[100] px-3 py-2 bg-[#4f4d6e] rounded-3xl"
|
||||
className="w-full flex items-center justify-center gap-2 py-2.5 px-4 bg-white/10 hover:bg-white/15 rounded-lg transition-colors"
|
||||
>
|
||||
<FaChevronLeft className="text-sm font-bold" />
|
||||
<p>Close menu</p>
|
||||
<FaChevronLeft className="text-sm" />
|
||||
<span className="text-sm font-medium">Close Menu</span>
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex gap-x-7 w-full py-3 justify-center px-auto mt-8 bg-black/10 max-[575px]:gap-x-4 lg:hidden">
|
||||
{[
|
||||
{ icon: faRandom, label: "Random" },
|
||||
{ icon: faFilm, label: "Movie" },
|
||||
].map((item, index) => (
|
||||
|
||||
{/* Quick Actions */}
|
||||
<div className="w-full p-4 border-b border-white/5 lg:hidden">
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
<Link
|
||||
to={`/${item.label}`}
|
||||
key={index}
|
||||
className="flex flex-col gap-y-1 items-center"
|
||||
to="/random"
|
||||
className="flex flex-col items-center gap-2 p-3 rounded-lg bg-white/5 hover:bg-white/10 transition-colors"
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={item.icon}
|
||||
className="text-[#ffbade] text-xl font-bold max-[575px]:text-[15px]"
|
||||
/>
|
||||
<p className="text-[15px] max-[575px]:text-[13px]">
|
||||
{item.label}
|
||||
</p>
|
||||
<FontAwesomeIcon icon={faRandom} className="text-lg" />
|
||||
<span className="text-xs font-medium">Random</span>
|
||||
</Link>
|
||||
))}
|
||||
<div className="flex flex-col gap-y-1 items-center w-auto justify-center">
|
||||
<div className="flex">
|
||||
{["EN", "JP"].map((lang, index) => (
|
||||
<button
|
||||
key={lang}
|
||||
onClick={() => toggleLanguage(lang)}
|
||||
className={`px-1 py-[1px] text-xs font-bold ${
|
||||
index === 0 ? "rounded-l-[3px]" : "rounded-r-[3px]"
|
||||
} ${
|
||||
language === lang
|
||||
? "bg-[#ffbade] text-black"
|
||||
: "bg-gray-600 text-white"
|
||||
} max-[575px]:text-[9px] max-[575px]:py-0`}
|
||||
>
|
||||
{lang}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<p className="whitespace-nowrap text-[15px] max-[575px]:text-[13px]">
|
||||
Anime name
|
||||
</p>
|
||||
<Link
|
||||
to="/movie"
|
||||
className="flex flex-col items-center gap-2 p-3 rounded-lg bg-white/5 hover:bg-white/10 transition-colors"
|
||||
>
|
||||
<FontAwesomeIcon icon={faFilm} className="text-lg" />
|
||||
<span className="text-xs font-medium">Movie</span>
|
||||
</Link>
|
||||
<div className="flex flex-col items-center gap-2 p-3 rounded-lg bg-white/5">
|
||||
<div className="flex bg-white/10 rounded">
|
||||
{["EN", "JP"].map((lang, index) => (
|
||||
<button
|
||||
key={lang}
|
||||
onClick={() => toggleLanguage(lang)}
|
||||
className={`px-2 py-1 text-xs font-medium transition-colors ${
|
||||
language === lang
|
||||
? "bg-white/15 text-white"
|
||||
: "text-white/60 hover:text-white"
|
||||
}`}
|
||||
>
|
||||
{lang}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<span className="text-xs font-medium text-white/60">Language</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul className="text-white mt-8 w-full">
|
||||
{[
|
||||
{ name: "Home", path: "/home" },
|
||||
{ name: "Subbed Anime", path: "/subbed-anime" },
|
||||
{ name: "Dubbed Anime", path: "/dubbed-anime" },
|
||||
{ name: "Most Popular", path: "/most-popular" },
|
||||
{ name: "Movies", path: "/movie" },
|
||||
{ name: "TV Series", path: "/tv" },
|
||||
{ name: "OVAs", path: "/ova" },
|
||||
{ name: "ONAs", path: "/ona" },
|
||||
{ name: "Specials", path: "/special" },
|
||||
{
|
||||
name: "Join Telegram",
|
||||
path: "https://t.me/zenime_discussion",
|
||||
},
|
||||
].map((item, index) => (
|
||||
<li
|
||||
|
||||
{/* Menu Items */}
|
||||
<div className="w-full p-2">
|
||||
{MENU_ITEMS.map((item, index) => (
|
||||
<Link
|
||||
key={index}
|
||||
className="py-4 w-full font-semibold"
|
||||
style={{ borderBottom: "1px solid rgba(255, 255, 255, .08)" }}
|
||||
to={item.path}
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-lg text-white/60 hover:text-white hover:bg-white/5 transition-colors"
|
||||
>
|
||||
<Link
|
||||
to={item.path}
|
||||
className="px-4 hover:text-[#ffbade] hover:cursor-pointer w-fit line-clamp-1"
|
||||
>
|
||||
{item.name}
|
||||
</Link>
|
||||
</li>
|
||||
<FontAwesomeIcon icon={item.icon} className="text-lg w-5" />
|
||||
<span className="font-medium">{item.name}</span>
|
||||
</Link>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user