mirror of
https://github.com/JustAnimeCore/JustAnime.git
synced 2026-04-17 22:01:45 +00:00
watch page progress
This commit is contained in:
@@ -137,9 +137,9 @@ function Episodelist({
|
||||
}, [activeEpisodeId, episodes]);
|
||||
|
||||
return (
|
||||
<div className="relative flex flex-col w-full h-full max-[1200px]:max-h-[500px]">
|
||||
<div className="sticky top-0 z-10 flex flex-col gap-y-[5px] justify-start px-4 py-5 bg-[#1a1a1a] border-b border-[#2a2a2a]">
|
||||
<h1 className="text-[14px] font-semibold text-white mb-2">Episodes</h1>
|
||||
<div className="flex flex-col w-full h-full">
|
||||
<div className="sticky top-0 z-10 flex flex-col gap-y-[5px] justify-start px-4 py-3 bg-[#1a1a1a] border-b border-[#2a2a2a]">
|
||||
<h1 className="text-[14px] font-semibold text-white mb-1">Episodes</h1>
|
||||
{totalEpisodes > 100 && (
|
||||
<div className="w-full flex gap-x-4 items-center max-[1200px]:justify-between">
|
||||
<div className="min-w-fit flex text-[13px]">
|
||||
@@ -198,7 +198,7 @@ function Episodelist({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div ref={listContainerRef} className="w-full h-full overflow-y-auto bg-[#1a1a1a]">
|
||||
<div ref={listContainerRef} className="w-full flex-1 overflow-y-auto bg-[#1a1a1a]">
|
||||
<div
|
||||
className={`${
|
||||
totalEpisodes > 30
|
||||
|
||||
@@ -9,10 +9,9 @@ import { Link, useNavigate } from "react-router-dom";
|
||||
import useToolTipPosition from "@/src/hooks/useToolTipPosition";
|
||||
import Qtip from "../qtip/Qtip";
|
||||
|
||||
function Sidecard({ data, label, className, limit }) {
|
||||
function Sidecard({ data, label, className }) {
|
||||
const { language } = useLanguage();
|
||||
const navigate = useNavigate();
|
||||
const [showAll, setShowAll] = useState(false);
|
||||
const [hoverTimeout, setHoverTimeout] = useState(null);
|
||||
const handleMouseEnter = (item, index) => {
|
||||
const timeout = setTimeout(() => {
|
||||
@@ -24,116 +23,86 @@ function Sidecard({ data, label, className, limit }) {
|
||||
clearTimeout(hoverTimeout);
|
||||
setHoveredItem(null);
|
||||
};
|
||||
const toggleShowAll = () => {
|
||||
setShowAll((prev) => !prev);
|
||||
};
|
||||
|
||||
const displayedData = limit
|
||||
? data.slice(0, limit)
|
||||
: showAll
|
||||
? data
|
||||
: data.slice(0, 6);
|
||||
const [hoveredItem, setHoveredItem] = useState(null);
|
||||
const { tooltipPosition, tooltipHorizontalPosition, cardRefs } =
|
||||
useToolTipPosition(hoveredItem, data);
|
||||
|
||||
return (
|
||||
<div className={`flex flex-col space-y-6 ${className}`}>
|
||||
<h1 className="font-bold text-2xl text-[#ffbade]">{label}</h1>
|
||||
<div className="flex flex-col space-y-4 bg-[#2B2A3C] p-4 pt-8">
|
||||
<div className={`flex flex-col ${className}`}>
|
||||
<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">
|
||||
{data &&
|
||||
displayedData.map((item, index) => (
|
||||
data.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center gap-x-4"
|
||||
className="group"
|
||||
ref={(el) => (cardRefs.current[index] = el)}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
borderBottom:
|
||||
index + 1 < displayedData.length
|
||||
? "1px solid rgba(255, 255, 255, .075)"
|
||||
: "none",
|
||||
}}
|
||||
className="flex pb-4 relative container items-center"
|
||||
>
|
||||
{hoveredItem === item.id + index &&
|
||||
window.innerWidth > 1024 && (
|
||||
<div
|
||||
className={`absolute ${tooltipPosition} ${tooltipHorizontalPosition} ${
|
||||
tooltipPosition === "top-1/2"
|
||||
? "translate-y-[50px]"
|
||||
: "translate-y-[-50px]"
|
||||
} z-[100000] transform transition-all duration-300 ease-in-out ${
|
||||
hoveredItem === item.id + index
|
||||
? "opacity-100 translate-y-0"
|
||||
: "opacity-0 translate-y-2"
|
||||
}`}
|
||||
>
|
||||
<Qtip id={item.id} />
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-start gap-3 p-2 rounded-lg transition-colors hover:bg-[#1f1f1f]">
|
||||
{hoveredItem === item.id + index && window.innerWidth > 1024 && (
|
||||
<div
|
||||
className={`absolute ${tooltipPosition} ${tooltipHorizontalPosition} ${
|
||||
tooltipPosition === "top-1/2"
|
||||
? "translate-y-[50px]"
|
||||
: "translate-y-[-50px]"
|
||||
} z-[100000] transform transition-all duration-300 ease-in-out ${
|
||||
hoveredItem === item.id + index
|
||||
? "opacity-100 translate-y-0"
|
||||
: "opacity-0 translate-y-2"
|
||||
}`}
|
||||
>
|
||||
<Qtip id={item.id} />
|
||||
</div>
|
||||
)}
|
||||
<img
|
||||
src={`${item.poster}`}
|
||||
alt={item.title}
|
||||
className="flex-shrink-0 w-[60px] h-[75px] rounded-md object-cover cursor-pointer"
|
||||
className="w-[50px] h-[70px] rounded object-cover cursor-pointer transition-transform group-hover:scale-105"
|
||||
onClick={() => navigate(`/watch/${item.id}`)}
|
||||
onMouseEnter={() => handleMouseEnter(item, index)}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
/>
|
||||
<div className="flex flex-col ml-4 space-y-2">
|
||||
<div className="flex flex-col gap-1.5 flex-1 min-w-0">
|
||||
<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]"
|
||||
onClick={() =>
|
||||
window.scrollTo({ top: 0, behavior: "smooth" })
|
||||
}
|
||||
className="text-sm font-medium text-gray-200 hover:text-white transition-colors line-clamp-1"
|
||||
onClick={() => window.scrollTo({ top: 0, behavior: "smooth" })}
|
||||
>
|
||||
{language === "EN" ? item.title : item.japanese_title}
|
||||
</Link>
|
||||
<div className="flex flex-wrap items-center w-fit space-x-1 max-[320px]:gap-y-2">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{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 items-center gap-1 px-1.5 py-0.5 bg-[#2a2a2a] rounded text-gray-300">
|
||||
<FontAwesomeIcon
|
||||
icon={faClosedCaptioning}
|
||||
className="text-[12px]"
|
||||
className="text-[10px]"
|
||||
/>
|
||||
<p className="text-[12px] font-bold">
|
||||
<span className="text-[10px] font-medium">
|
||||
{item.tvInfo.sub}
|
||||
</p>
|
||||
</span>
|
||||
</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 items-center gap-1 px-1.5 py-0.5 bg-[#2a2a2a] rounded text-gray-300">
|
||||
<FontAwesomeIcon
|
||||
icon={faMicrophone}
|
||||
className="text-[12px]"
|
||||
className="text-[10px]"
|
||||
/>
|
||||
<p className="text-[12px] font-bold">
|
||||
<span className="text-[10px] font-medium">
|
||||
{item.tvInfo.dub}
|
||||
</p>
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{item.tvInfo?.showType && (
|
||||
<div className="flex items-center gap-x-2">
|
||||
<div className="dot ml-[4px]"></div>
|
||||
<p className="text-[15px] font-light">
|
||||
{item.tvInfo.showType}
|
||||
</p>
|
||||
</div>
|
||||
<span className="text-xs text-gray-400">
|
||||
{item.tvInfo.showType}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{!limit && data.length > 6 && (
|
||||
<button
|
||||
className="w-full bg-[#555462d3] py-3 mt-4 hover:bg-[#555462] rounded-md font-bold transform transition-all ease-out"
|
||||
onClick={toggleShowAll}
|
||||
>
|
||||
{showAll ? "Show less" : "Show more"}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -3,14 +3,17 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
const ToggleButton = ({ label, isActive, onClick }) => (
|
||||
<button className="flex gap-x-2" onClick={onClick}>
|
||||
<h1 className="capitalize text-[13px]">{label}</h1>
|
||||
<button
|
||||
className="flex items-center text-xs px-2 py-0.5 rounded transition-colors hover:bg-[#2a2a2a]"
|
||||
onClick={onClick}
|
||||
>
|
||||
<span className="text-gray-300">{label}</span>
|
||||
<span
|
||||
className={`capitalize text-[13px] ${
|
||||
isActive ? "text-[#ffbade]" : "text-red-500"
|
||||
className={`ml-1.5 ${
|
||||
isActive ? "text-white" : "text-gray-500"
|
||||
}`}
|
||||
>
|
||||
{isActive ? "on" : "off"}
|
||||
{isActive ? "ON" : "OFF"}
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
@@ -42,25 +45,25 @@ export default function WatchControls({
|
||||
}, [episodeId, episodes]);
|
||||
|
||||
return (
|
||||
<div className="bg-[#11101A] w-full flex justify-between flex-wrap px-4 pt-4 max-[1200px]:bg-[#14151A] max-[375px]:flex-col max-[375px]:gap-y-2">
|
||||
<div className="flex gap-x-4 flex-wrap">
|
||||
<div className="w-full flex justify-between items-center px-3 py-2 border-b border-gray-800">
|
||||
<div className="flex gap-x-2">
|
||||
<ToggleButton
|
||||
label="auto play"
|
||||
label="Auto Play"
|
||||
isActive={autoPlay}
|
||||
onClick={() => setAutoPlay((prev) => !prev)}
|
||||
/>
|
||||
<ToggleButton
|
||||
label="auto skip intro"
|
||||
<ToggleButton
|
||||
label="Skip Intro"
|
||||
isActive={autoSkipIntro}
|
||||
onClick={() => setAutoSkipIntro((prev) => !prev)}
|
||||
/>
|
||||
/>
|
||||
<ToggleButton
|
||||
label="auto next"
|
||||
label="Auto Next"
|
||||
isActive={autoNext}
|
||||
onClick={() => setAutoNext((prev) => !prev)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-x-6 max-[575px]:gap-x-4 max-[375px]:justify-end">
|
||||
<div className="flex items-center gap-x-2">
|
||||
<button
|
||||
onClick={() => {
|
||||
if (currentEpisodeIndex > 0) {
|
||||
@@ -70,11 +73,13 @@ export default function WatchControls({
|
||||
}
|
||||
}}
|
||||
disabled={currentEpisodeIndex <= 0}
|
||||
className={`w-7 h-7 flex items-center justify-center rounded transition-colors ${
|
||||
currentEpisodeIndex <= 0
|
||||
? "text-gray-600 cursor-not-allowed"
|
||||
: "text-gray-300 hover:text-white"
|
||||
}`}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faBackward}
|
||||
className="text-[20px] max-[575px]:text-[16px] text-white"
|
||||
/>
|
||||
<FontAwesomeIcon icon={faBackward} className="text-[14px]" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
@@ -85,11 +90,13 @@ export default function WatchControls({
|
||||
}
|
||||
}}
|
||||
disabled={currentEpisodeIndex >= episodes?.length - 1}
|
||||
className={`w-7 h-7 flex items-center justify-center rounded transition-colors ${
|
||||
currentEpisodeIndex >= episodes?.length - 1
|
||||
? "text-gray-600 cursor-not-allowed"
|
||||
: "text-gray-300 hover:text-white"
|
||||
}`}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faForward}
|
||||
className="text-[20px] max-[575px]:text-[16px] text-white"
|
||||
/>
|
||||
<FontAwesomeIcon icon={faForward} className="text-[14px]" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user