diff options
| author | Factiven <[email protected]> | 2023-05-01 01:24:24 +0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-05-01 01:24:24 +0700 |
| commit | f026ac4ffc988c6de085a14e0eb0dc28fffe5482 (patch) | |
| tree | 7fa872b8d6dd3cc3c93c7a53f4475ad7b9db7a0a /pages | |
| parent | Merge branch 'pre-production' into main (diff) | |
| parent | Update v3.5 (diff) | |
| download | moopa-f026ac4ffc988c6de085a14e0eb0dc28fffe5482.tar.xz moopa-f026ac4ffc988c6de085a14e0eb0dc28fffe5482.zip | |
Update v3.5
Diffstat (limited to 'pages')
| -rw-r--r-- | pages/about.js | 58 | ||||
| -rw-r--r-- | pages/anime/[...id].js | 298 | ||||
| -rw-r--r-- | pages/anime/watch/[...info].js | 98 | ||||
| -rw-r--r-- | pages/categories/[id].js | 125 | ||||
| -rw-r--r-- | pages/index.js | 8 | ||||
| -rw-r--r-- | pages/profile/[user].js | 140 | ||||
| -rw-r--r-- | pages/search/[param].js | 82 |
7 files changed, 474 insertions, 335 deletions
diff --git a/pages/about.js b/pages/about.js index 7255401..42690e0 100644 --- a/pages/about.js +++ b/pages/about.js @@ -1,5 +1,7 @@ import Head from "next/head"; import Layout from "../components/layout"; +import { motion } from "framer-motion"; +import Link from "next/link"; export default function About() { return ( @@ -11,7 +13,7 @@ export default function About() { <link rel="icon" href="/c.svg" /> </Head> <Layout> - <div className="mb-[6rem] bg-[#121212] text-white flex min-h-screen w-screen flex-col justify-center gap-8 px-6 pt-nav lg:items-center lg:gap-14"> + {/* <div className="mb-[6rem] bg-[#121212] text-white flex min-h-screen w-screen flex-col justify-center gap-8 px-6 pt-nav lg:items-center lg:gap-14"> <h1 className="place-items-start font-karla text-[3rem] font-bold"> Hi ! </h1> @@ -20,22 +22,13 @@ export default function About() { <p className="inline-block font-extrabold text-[#ffffff]"> Welcome to our website! </p>{" "} - Moopa is a platform where you can watch and stream anime or read - manga for free, without any ads or VPNs. Our mission is to provide - a convenient and enjoyable experience for anime and manga - enthusiasts all around the world. + </div> <p> - At our site, you will find a vast collection of anime and manga - titles from different genres, including action, adventure, comedy, - romance, and more. We take pride in our fast and reliable servers, - which ensure smooth streaming and reading for all our users. + </p> <p> - It is important to note that we do not store any files on our - servers. Instead, we only link to media hosted on third-party - services. This is to ensure that we comply with copyright laws and - respect the intellectual property rights of content creators. + </p> <p> We are committed to providing a safe and secure environment for @@ -44,12 +37,49 @@ export default function About() { safety of our community. </p> <p> + + </p> + </div> + </div> */} + + <motion.div + initial={{ opacity: 0 }} + animate={{ opacity: 1 }} + exit={{ opacity: 0 }} + className="flex flex-col justify-center items-center min-h-screen md:py-0 py-16" + > + <div className="max-w-screen-lg w-full px-4 py-10"> + <h1 className="text-4xl font-bold mb-6">About Us</h1> + <p className="text-lg mb-8"> + Moopa is a platform where you can watch and stream anime or read + manga for free, without any ads or VPNs. Our mission is to provide + a convenient and enjoyable experience for anime and manga + enthusiasts all around the world. + </p> + <p className="text-lg mb-8"> + At our site, you will find a vast collection of anime and manga + titles from different genres, including action, adventure, comedy, + romance, and more. We take pride in our fast and reliable servers, + which ensure smooth streaming and reading for all our users. + </p> + <p className="text-lg mb-8"> + We believe that anime and manga have the power to inspire and + entertain people of all ages and backgrounds. Our service is + designed to make it easy for fans to access the content they love, + whether they are casual viewers or die-hard fans. + </p> + <p className="text-lg mb-8"> Thank you for choosing our website as your go-to platform for anime and manga. We hope you enjoy your stay here, and feel free to contact us if you have any feedback or suggestions. </p> + <Link href="/contact"> + <div className="bg-[#ffffff] text-black font-medium py-3 px-6 rounded-lg hover:bg-action transition duration-300 ease-in-out"> + Contact Us + </div> + </Link> </div> - </div> + </motion.div> </Layout> </> ); diff --git a/pages/anime/[...id].js b/pages/anime/[...id].js index f26c70d..26c42cb 100644 --- a/pages/anime/[...id].js +++ b/pages/anime/[...id].js @@ -140,15 +140,6 @@ const infoQuery = `query ($id: Int) { } }`; -const stats = [ - "Watching", - "Plan to Watch", - "Completed", - "Dropped", - "Paused", - "Rewatching", -]; - export default function Info() { const { data: session, status } = useSession(); const [data, setData] = useState(null); @@ -166,13 +157,16 @@ export default function Info() { const [time, setTime] = useState(0); const { id } = useRouter().query; - const [aniStatus, setAniStatus] = useState(statuses); - const [aniProgress, setAniProgress] = useState(0); + const [epiStatus, setEpiStatus] = useState("ok"); + const [error, setError] = useState(null); const rec = info?.recommendations?.nodes.map( (data) => data.mediaRecommendation ); + // const [log, setLog] = useState(null); + // console.log(rec); + useEffect(() => { const defaultState = { data: null, @@ -181,10 +175,14 @@ export default function Info() { loading: true, statuses: null, progress: null, + stall: false, + EpiStatus: "ok", + error: null, }; // Reset all state variables to their default values Object.keys(defaultState).forEach((key) => { + document.body.style.overflow = "auto"; const value = defaultState[key]; if (Array.isArray(value)) { value.length @@ -223,21 +221,36 @@ export default function Info() { ]); const data = await res.json(); const infos = await info.json(); + + if (res.status === 500) { + setEpisode(null); + setEpiStatus("error"); + setError(data.message); + } else if (res.status === 404) { + window.location.href("/404"); + } setInfo(infos.data.Media); + // setLog(data); const textColor = setTxtColor(infos.data.Media.coverImage?.color); - if (!data || data.episodes.length === 0) { + if (!data || data?.episodes?.length === 0) { const res = await fetch( `https://api.consumet.org/meta/anilist/info/${id[0]}?provider=9anime` ); const datas = await res.json(); + if (res.status === 500) { + setEpisode(null); + setEpiStatus("error"); + setError(datas.message); + } else { + setEpisode(datas.episodes); + } setColor({ backgroundColor: `${data?.color || "#ffff"}`, color: textColor, }); setStall(true); - setEpisode(datas.episodes); } else { setEpisode(data.episodes); } @@ -267,33 +280,24 @@ export default function Info() { const gat = prog.lists.map((item) => item.entries); const git = gat.map((item) => - item.find((item) => item.media.id === parseInt(data?.id)) - ); - const gut = git?.find( - (item) => item?.media.id === parseInt(data?.id) + item.find((item) => item.mediaId === parseInt(id[0])) ); + const gut = git?.find((item) => item?.mediaId === parseInt(id[0])); if (gut) { setProgress(gut?.progress); - setAniProgress(parseInt(gut?.progress)); if (gut.status === "CURRENT") { - setStatuses("Watching"); - setAniStatus("Watching"); + setStatuses({ name: "Watching", value: "CURRENT" }); } else if (gut.status === "PLANNING") { - setStatuses("Planned to watch"); - setAniStatus("Planned to watch"); + setStatuses({ name: "Plan to watch", value: "PLANNING" }); } else if (gut.status === "COMPLETED") { - setStatuses("Completed"); - setAniStatus("Completed"); + setStatuses({ name: "Completed", value: "COMPLETED" }); } else if (gut.status === "DROPPED") { - setStatuses("Dropped"); - setAniStatus("Dropped"); + setStatuses({ name: "Dropped", value: "DROPPED" }); } else if (gut.status === "PAUSED") { - setStatuses("Paused"); - setAniStatus("Paused"); + setStatuses({ name: "Paused", value: "PAUSED" }); } else if (gut.status === "REPEATING") { - setStatuses("Rewatching"); - setAniStatus("Rewatching"); + setStatuses({ name: "Rewatching", value: "REPEATING" }); } } } @@ -327,18 +331,6 @@ export default function Info() { document.body.style.overflow = "auto"; } - function handleSubmit(e) { - e.preventDefault(); - const formData = { status: aniStatus, progress: aniProgress }; - console.log(formData); - } - - function handleProgress(e) { - setAniProgress(e.target.value); - } - - // console.log(progress); - return ( <> <Head> @@ -349,14 +341,14 @@ export default function Info() { </title> </Head> <Modal open={open} onClose={() => handleClose()}> - <div className="bg-[#202020] rounded-lg text-center"> + <div> {!session && ( - <div className="flex-center flex-col gap-5 px-10 py-5"> + <div className="flex-center flex-col gap-5 px-10 py-5 bg-secondary rounded-md"> <h1 className="text-md font-extrabold font-karla"> Edit your list </h1> <button - className="flex items-center bg-[#3a3a3a] rounded-md text-white p-1" + className="flex items-center bg-[#363642] rounded-md text-white p-1" onClick={() => signIn("AniListProvider")} > <h1 className="px-1 font-bold font-karla"> @@ -368,13 +360,14 @@ export default function Info() { </button> </div> )} - {session && info && progress && ( + {session && loading && info && ( <ListEditor animeId={info?.id} session={session} stats={statuses} prg={progress} max={info?.episodes} + image={info} /> )} </div> @@ -391,6 +384,7 @@ export default function Info() { info?.coverImage?.extraLarge || info?.coverImage.large } + priority={true} alt="banner anime" height={1000} width={1000} @@ -435,12 +429,17 @@ export default function Info() { {info && ( <div className="flex items-center gap-5 pt-3 text-center"> <div className="flex items-center gap-2 text-center"> - <div - className="bg-action px-10 rounded-sm font-karla font-bold cursor-pointer" + <button + type="button" + className="bg-action px-10 rounded-sm font-karla font-bold" onClick={() => handleOpen()} > - {statuses ? statuses : "Add to List"} - </div> + {loading + ? statuses + ? statuses.name + : "Add to List" + : "Loading..."} + </button> <div className="h-6 w-6"> <HeartIcon /> </div> @@ -477,16 +476,28 @@ export default function Info() { <div className="shrink-0 md:h-[250px] md:w-[180px] w-[115px] h-[164px] relative"> {info ? ( <> - <div className="bg-image md:h-[250px] md:w-[180px] w-[115px] h-[164px] bg-opacity-30 absolute backdrop-blur-lg z-10" /> + <div className="bg-image md:h-[250px] md:w-[180px] w-[115px] h-[164px] bg-opacity-30 absolute backdrop-blur-lg z-10 -top-7" /> <Image src={ info.coverImage.extraLarge || info.coverImage.large } + priority={true} alt="poster anime" height={700} width={700} - className="object-cover md:h-[250px] md:w-[180px] w-[115px] h-[164px] z-20 absolute" + className="object-cover md:h-[250px] md:w-[180px] w-[115px] h-[164px] z-20 absolute rounded-md -top-7" /> + <button + type="button" + className="bg-action flex-center z-20 h-[20px] w-[180px] absolute bottom-0 rounded-sm font-karla font-bold" + onClick={() => handleOpen()} + > + {loading + ? statuses + ? statuses.name + : "Add to List" + : "Loading..."} + </button> </> ) : ( <Skeleton className="h-[250px] w-[180px]" /> @@ -505,36 +516,46 @@ export default function Info() { </h1> {info ? ( <div className="flex gap-6"> - <div - className={`dynamic-text rounded-md px-2 font-karla font-bold`} - style={color} - > - {info?.episodes} Episodes - </div> - <div - className={`dynamic-text rounded-md px-2 font-karla font-bold`} - style={color} - > - {info?.startDate?.year} - </div> - <div - className={`dynamic-text rounded-md px-2 font-karla font-bold`} - style={color} - > - {info?.averageScore}% - </div> - <div - className={`dynamic-text rounded-md px-2 font-karla font-bold`} - style={color} - > - {info?.type} - </div> - <div - className={`dynamic-text rounded-md px-2 font-karla font-bold`} - style={color} - > - {info?.status} - </div> + {info?.episodes && ( + <div + className={`dynamic-text rounded-md px-2 font-karla font-bold`} + style={color} + > + {info?.episodes} Episodes + </div> + )} + {info?.startDate?.year && ( + <div + className={`dynamic-text rounded-md px-2 font-karla font-bold`} + style={color} + > + {info?.startDate?.year} + </div> + )} + {info?.averageScore && ( + <div + className={`dynamic-text rounded-md px-2 font-karla font-bold`} + style={color} + > + {info?.averageScore}% + </div> + )} + {info?.type && ( + <div + className={`dynamic-text rounded-md px-2 font-karla font-bold`} + style={color} + > + {info?.type} + </div> + )} + {info?.status && ( + <div + className={`dynamic-text rounded-md px-2 font-karla font-bold`} + style={color} + > + {info?.status} + </div> + )} <div className={`dynamic-text rounded-md px-2 font-karla font-bold`} style={color} @@ -554,7 +575,6 @@ export default function Info() { ) : ( <Skeleton className="h-[130px]" /> )} - {/* <p>{data.description}</p> */} </div> </div> @@ -670,58 +690,64 @@ export default function Info() { </div> </div> )} - {statuses && ( - <> - <div className="hidden font-karla relative group md:flex justify-center"> - {statuses} - <span className="absolute bottom-8 shadow-lg invisible group-hover:visible transition-all opacity-0 group-hover:opacity-100 font-karla font-light bg-secondary p-1 px-2 rounded-lg"> - status - </span> - </div> - </> - )} </div> {loading ? ( data && ( <div className="flex h-[640px] flex-col gap-5 scrollbar-thin scrollbar-thumb-[#1b1c21] scrollbar-thumb-rounded-full overflow-y-scroll hover:scrollbar-thumb-[#2e2f37]"> - {episode?.length !== 0 ? ( - episode?.map((epi, index) => { - return ( - <div - key={index} - className="flex flex-col gap-3 px-2" - > - <Link - href={`/anime/watch/${epi.id}/${data.id}/${ - stall ? `9anime` : "" - }`} - className={`text-start text-sm md:text-lg ${ - progress && epi.number <= progress - ? "text-[#5f5f5f]" - : "text-white" - }`} + {epiStatus === "ok" ? ( + episode?.length !== 0 ? ( + episode?.map((epi, index) => { + return ( + <div + key={index} + className="flex flex-col gap-3 px-2" > - <p>Episode {epi.number}</p> - {epi.title && ( - <p - className={`text-xs md:text-sm ${ - progress && epi.number <= progress - ? "text-[#5f5f5f]" - : "text-[#b1b1b1]" - } italic`} - > - "{epi.title}" - </p> + <Link + href={`/anime/watch/${epi.id}/${data.id}/${ + stall ? `9anime` : "" + }`} + className={`text-start text-sm md:text-lg ${ + progress && epi.number <= progress + ? "text-[#5f5f5f]" + : "text-white" + }`} + > + <p>Episode {epi.number}</p> + {epi.title && ( + <p + className={`text-xs md:text-sm ${ + progress && epi.number <= progress + ? "text-[#5f5f5f]" + : "text-[#b1b1b1]" + } italic`} + > + "{epi.title}" + </p> + )} + </Link> + {index !== episode?.length - 1 && ( + <span className="h-[1px] bg-white" /> )} - </Link> - {index !== episode?.length - 1 && ( - <span className="h-[1px] bg-white" /> - )} - </div> - ); - }) + </div> + ); + }) + ) : ( + <p>No Episodes Available</p> + ) ) : ( - <p>No Episodes Available</p> + // <p className="flex-center"> + // Something went wrong, can't retrieve any episodes :/ + // </p> + <div className="flex flex-col"> + <h1>{epiStatus} while retrieving data</h1> + <pre + className={`rounded-md overflow-hidden ${getLanguageClassName( + "bash" + )}`} + > + <code>{error}</code> + </pre> + </div> )} </div> ) @@ -737,7 +763,7 @@ export default function Info() { )} </div> </div> - {rec && ( + {info && rec?.length !== 0 && ( <div className="w-screen md:w-[80%]"> <Content ids="recommendAnime" @@ -792,3 +818,17 @@ function setTxtColor(hexColor) { const brightness = getBrightness(hexColor); return brightness < 150 ? "#fff" : "#000"; } + +const getLanguageClassName = (language) => { + switch (language) { + case "javascript": + return "language-javascript"; + case "html": + return "language-html"; + case "bash": + return "language-bash"; + // add more languages here as needed + default: + return ""; + } +}; diff --git a/pages/anime/watch/[...info].js b/pages/anime/watch/[...info].js index 0face64..0d11684 100644 --- a/pages/anime/watch/[...info].js +++ b/pages/anime/watch/[...info].js @@ -32,8 +32,7 @@ export default function Info({ sessions, id, aniId, provider }) { const [playingEpisode, setPlayingEpisode] = useState(null); const [loading, setLoading] = useState(false); const [playingTitle, setPlayingTitle] = useState(null); - - // console.log(epiData); + const [poster, setPoster] = useState(null); useEffect(() => { const defaultState = { @@ -137,6 +136,11 @@ export default function Info({ sessions, id, aniId, provider }) { setPlayingEpisode(playingEpisode); + const playing = aniData.episodes.filter((item) => item.id == id); + // .map((item) => item.); + + setPoster(playing); + const title = aniData.episodes .filter((item) => item.id == id) .find((item) => item.title !== null); @@ -255,12 +259,8 @@ export default function Info({ sessions, id, aniId, provider }) { fetchData(); }, [id, aniId, provider, sessions]); - // console.log(fallback); - const { Notification: NotificationComponent } = useNotification(); - // console.log(); - const [open, setOpen] = useState(false); const [aniStatus, setAniStatus] = useState(""); const [aniProgress, setAniProgress] = useState(parseInt(playingEpisode)); @@ -282,97 +282,12 @@ export default function Info({ sessions, id, aniId, provider }) { console.log(formData); }; - // console.log(playingTitle.title); - return ( <> <Head> <title>{playingTitle}</title> </Head> - {/* <NotificationComponent /> */} - - {/* <Modal open={open} onClose={() => setOpen(false)}> - <div className="bg-[#202020] rounded-lg text-center"> - <div className="p-5 grid gap-2 justify-center place-items-center"> - <h1 className="text-md font-extrabold font-karla"> - Save this Anime to Your List - </h1> - {!sessions && ( - <button - className="flex items-center bg-[#3a3a3a] mt-4 rounded-md text-white p-1" - onClick={() => signIn("AniListProvider")} - > - <h1 className="px-1 font-bold font-karla"> - Login with AniList - </h1> - <div className="scale-[60%] pb-[1px]"> - <AniList /> - </div> - </button> - )} - {sessions && ( - <> - <form - onSubmit={handleSubmit} - className="grid grid-cols-2 gap-5 max-w-sm mx-auto mt-5 items-center" - > - <div className="mb-4"> - <label - htmlFor="option" - className="block font-bold mb-2 text-sm" - > - Select an option - </label> - <select - id="option" - value={aniStatus} - onChange={handleStatus} - className="form-select block w-full px-2 py-1 rounded-lg shadow-sm focus:outline-none focus:shadow-outline-blue focus:border-blue-300" - > - {aniStatus === "" && ( - <option value="" hidden> - Select an option - </option> - )} - <option value="option1">Option 1</option> - <option value="option2">Option 2</option> - <option value="option3">Option 3</option> - </select> - </div> - <div className="mb-4"> - <label - htmlFor="number" - className="block text-sm font-bold mb-2" - > - Episode Progress - </label> - <input - id="number" - type="number" - step="1" - min="0" - max={data.totalEpisodes} - className="form-input block w-full px-2 py-1 rounded-lg shadow-sm focus:outline-none focus:shadow-outline-blue focus:border-blue-300" - value={aniProgress} - onChange={handleProgress} - /> - </div> - <div className="col-start-2 row-start-2 w-full justify-items-end text-center"> - <button - type="submit" - className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" - onClick={() => setOpen(false)} - > - Submit - </button> - </div> - </form> - </> - )} - </div> - </div> - </Modal> */} <SkeletonTheme baseColor="#232329" highlightColor="#2a2a32"> <div className="bg-primary"> <Navigasi /> @@ -391,6 +306,7 @@ export default function Info({ sessions, id, aniId, provider }) { op={skip.op} ed={skip.ed} title={playingTitle} + poster={poster[0]?.image} /> </div> ) : ( diff --git a/pages/categories/[id].js b/pages/categories/[id].js new file mode 100644 index 0000000..1395a33 --- /dev/null +++ b/pages/categories/[id].js @@ -0,0 +1,125 @@ +import Head from "next/head"; +import Footer from "../../components/footer"; +import { useRouter } from "next/router"; +import { useEffect, useState } from "react"; +import { useAniList } from "../../lib/useAnilist"; +import Image from "next/image"; + +export default function Categories() { + const router = useRouter(); + const { id } = router.query; + const tags = id?.replace(/-/g, " "); + const { aniAdvanceSearch } = useAniList(); + + const [data, setData] = useState(); + + const [season, setSeason] = useState(""); + const [loading, setLoading] = useState(false); + + useEffect(() => { + setLoading(true); + if (tags === "This Season") { + seasonNow(); + setLoading(false); + } else if (tags === "Popular Anime") { + PopularAnime(); + setLoading(false); + } else if (tags === "Popular Manga") { + PopularManga(); + setLoading(false); + } else { + setData(null); + setLoading(false); + } + }, [id]); + + async function seasonNow() { + const data = await aniAdvanceSearch({ + perPage: 25, + seasonYear: 2023, + season: getCurrentSeason(), + // type: "MANGA", + }); + setData(data); + } + + async function PopularAnime() { + const data = await aniAdvanceSearch({ + perPage: 25, + sort: ["POPULARITY_DESC"], + }); + setData(data); + } + + async function PopularManga() { + const data = await aniAdvanceSearch({ + perPage: 25, + sort: ["POPULARITY_DESC"], + type: "MANGA", + }); + setData(data); + } + + console.log(data); + return ( + <> + <Head> + <title>Categories - {tags}</title> + </Head> + <div className="flex-center min-h-screen w-screen"> + <div className="grid-container bg-white"> + {loading ? ( + <p>Loading...</p> + ) : ( + data && + data?.media.map((m) => { + return ( + <div key={m.id} className="grid-item h-[265px] w-[185px]"> + <Image + src={m.coverImage.extraLarge} + alt="image" + width={500} + height={500} + className="object-cover h-[265px] w-[185px]" + /> + </div> + ); + }) + )} + </div> + </div> + <Footer /> + </> + ); +} + +function getYear() { + const now = new Date(); + return now.getFullYear(); +} + +function getCurrentSeason() { + const now = new Date(); + const month = now.getMonth() + 1; // getMonth() returns 0-based index + + switch (month) { + case 12: + case 1: + case 2: + return "WINTER"; + case 3: + case 4: + case 5: + return "SPRING"; + case 6: + case 7: + case 8: + return "SUMMER"; + case 9: + case 10: + case 11: + return "FALL"; + default: + return "UNKNOWN SEASON"; + } +} diff --git a/pages/index.js b/pages/index.js index e2bdb65..6295dee 100644 --- a/pages/index.js +++ b/pages/index.js @@ -1,6 +1,5 @@ import { aniListData } from "../lib/AniList"; import React, { useState, useEffect } from "react"; -import ReactHtmlParser from "kt-react-html-parser"; import Head from "next/head"; import Link from "next/link"; import Footer from "../components/footer"; @@ -369,9 +368,10 @@ export default function Home({ detail, populars, sessions }) { <h1 className="w-[85%] font-outfit font-extrabold md:text-[34px] line-clamp-2"> {data.title.english || data.title.romaji || data.title.native} </h1> - <div className="font-roboto font-light md:text-[18px] line-clamp-5"> - {ReactHtmlParser(data.description)} - </div> + <p + className="font-roboto font-light md:text-[18px] line-clamp-5" + dangerouslySetInnerHTML={{ __html: data?.description }} + /> <div className="md:pt-5"> <Link diff --git a/pages/profile/[user].js b/pages/profile/[user].js index a27d5b9..e28e1cb 100644 --- a/pages/profile/[user].js +++ b/pages/profile/[user].js @@ -185,75 +185,79 @@ export default function MyList({ media, sessions, user, time }) { <div className="lg:w-[75%] grid gap-10 my-12 lg:pt-16"> {media.length !== 0 ? ( - filterMedia(listFilter).map((item, index) => ( - <div key={index} className="flex flex-col gap-5 mx-3"> - <h1 className="font-karla font-bold text-xl">{item.name}</h1> - <table className="bg-secondary rounded-lg"> - <thead> - <tr> - <th className="font-bold text-xs py-3 text-start pl-10 lg:w-[75%] w-[65%]"> - Title - </th> - <th className="font-bold text-xs py-3">Score</th> - <th className="font-bold text-xs py-3">Progress</th> - </tr> - </thead> - <tbody className=""> - {item.entries.map((item, index) => ( - <tr - key={index + 1} - className="hover:bg-orange-400 duration-150 ease-in-out group relative" - > - <td className="font-medium py-2 pl-2 rounded-l-lg"> - <div className="flex items-center gap-2"> - {item.media.status === "RELEASING" ? ( - <span className="dot group-hover:invisible bg-green-500 shrink-0" /> - ) : item.media.status === "NOT_YET_RELEASED" ? ( - <span className="dot group-hover:invisible bg-red-500 shrink-0" /> - ) : ( - <span className="dot group-hover:invisible shrink-0" /> - )} - <Image - src={item.media.coverImage.large} - alt="Cover Image" - width={500} - height={500} - className="object-cover rounded-md w-10 h-10 shrink-0" - /> - <div className="absolute -top-10 -left-40 invisible lg:group-hover:visible"> - <Image - src={item.media.coverImage.large} - alt={item.media.id} - width={1000} - height={1000} - className="object-cover h-[186px] w-[140px] shrink-0 rounded-md" - /> - </div> - <Link - href={`/anime/${item.media.id}`} - className="font-semibold font-karla pl-2 text-sm line-clamp-1" - title={item.media.title.romaji} - > - {item.media.title.romaji} - </Link> - </div> - </td> - <td className="text-center text-xs text-txt"> - {item.score === 0 ? null : item.score} - </td> - <td className="text-center text-xs text-txt rounded-r-lg"> - {item.progress === item.media.episodes - ? item.progress - : item.media.episodes === null - ? item.progress - : `${item.progress}/${item.media.episodes}`} - </td> + filterMedia(listFilter).map((item, index) => { + return ( + <div key={index} className="flex flex-col gap-5 mx-3"> + <h1 className="font-karla font-bold text-xl">{item.name}</h1> + <table className="bg-secondary rounded-lg"> + <thead> + <tr> + <th className="font-bold text-xs py-3 text-start pl-10 lg:w-[75%] w-[65%]"> + Title + </th> + <th className="font-bold text-xs py-3">Score</th> + <th className="font-bold text-xs py-3">Progress</th> </tr> - ))} - </tbody> - </table> - </div> - )) + </thead> + <tbody className=""> + {item.entries.map((item) => { + return ( + <tr + key={item.mediaId} + className="hover:bg-orange-400 duration-150 ease-in-out group relative" + > + <td className="font-medium py-2 pl-2 rounded-l-lg"> + <div className="flex items-center gap-2"> + {item.media.status === "RELEASING" ? ( + <span className="dot group-hover:invisible bg-green-500 shrink-0" /> + ) : item.media.status === "NOT_YET_RELEASED" ? ( + <span className="dot group-hover:invisible bg-red-500 shrink-0" /> + ) : ( + <span className="dot group-hover:invisible shrink-0" /> + )} + <Image + src={item.media.coverImage.large} + alt="Cover Image" + width={500} + height={500} + className="object-cover rounded-md w-10 h-10 shrink-0" + /> + <div className="absolute -top-10 -left-40 invisible lg:group-hover:visible"> + <Image + src={item.media.coverImage.large} + alt={item.media.id} + width={1000} + height={1000} + className="object-cover h-[186px] w-[140px] shrink-0 rounded-md" + /> + </div> + <Link + href={`/anime/${item.media.id}`} + className="font-semibold font-karla pl-2 text-sm line-clamp-1" + title={item.media.title.romaji} + > + {item.media.title.romaji} + </Link> + </div> + </td> + <td className="text-center text-xs text-txt"> + {item.score === 0 ? null : item.score} + </td> + <td className="text-center text-xs text-txt rounded-r-lg"> + {item.progress === item.media.episodes + ? item.progress + : item.media.episodes === null + ? item.progress + : `${item.progress}/${item.media.episodes}`} + </td> + </tr> + ); + })} + </tbody> + </table> + </div> + ); + }) ) : ( <div className="w-screen lg:w-full flex-center flex-col gap-5"> {user.name === sessions?.user.name ? ( diff --git a/pages/search/[param].js b/pages/search/[param].js index 31760c4..f38ba76 100644 --- a/pages/search/[param].js +++ b/pages/search/[param].js @@ -9,6 +9,7 @@ import Head from "next/head"; import Footer from "../../components/footer"; import { useAniList } from "../../lib/useAnilist"; +import Image from "next/image"; const genre = [ "Action", @@ -53,6 +54,8 @@ export default function Card() { let hasil = null; let tipe = "ANIME"; + let s = undefined; + let y = NaN; const query = router.query; if (query.param !== "anime" && query.param !== "manga") { @@ -60,19 +63,42 @@ export default function Card() { } else if (query.param === "anime") { hasil = null; tipe = "ANIME"; + if ( + query.season !== "WINTER" && + query.season !== "SPRING" && + query.season !== "SUMMER" && + query.season !== "FALL" + ) { + s = undefined; + y = NaN; + } else { + s = query.season; + y = parseInt(query.seasonYear); + } } else if (query.param === "manga") { hasil = null; tipe = "MANGA"; + if ( + query.season !== "WINTER" && + query.season !== "SPRING" && + query.season !== "SUMMER" && + query.season !== "FALL" + ) { + s = undefined; + y = NaN; + } else { + s = query.season; + y = parseInt(query.seasonYear); + } } - // ; + + // console.log(tags); const [search, setQuery] = useState(hasil); const [type, setSelectedType] = useState(tipe); - const [seasonYear, setSeasonYear] = useState(); - const [season, setSeason] = useState(); const [genres, setSelectedGenre] = useState(); - const [perPage, setPerPage] = useState(10); - const [sort, setSelectedSort] = useState(["POPULARITY_DESC"]); + const [sort, setSelectedSort] = useState(); + // console.log(data); const [isVisible, setIsVisible] = useState(false); @@ -83,16 +109,15 @@ export default function Card() { async function advance() { setLoading(true); - const data = await aniAdvanceSearch( - search, - type, - seasonYear, - season, - genres, - page, - perPage, - sort - ); + const data = await aniAdvanceSearch({ + search: search, + type: type, + genres: genres, + page: page, + sort: sort, + season: s, + seasonYear: y, + }); if (data.media.length === 0) { setNextPage(false); } else if (data !== null && page > 1) { @@ -112,7 +137,7 @@ export default function Card() { setPage(1); setNextPage(true); advance(); - }, [search, type, seasonYear, season, genres, perPage, sort]); + }, [search, type, genres, sort, s, y]); useEffect(() => { advance(); @@ -183,7 +208,7 @@ export default function Card() { TITLE </h1> <input - className="lg:w-[297px] lg:h-[46px] h-[35px] w-[230px] xs:w-[280px] bg-secondary rounded-[10px] font-karla font-light text-[#ffffff89] text-center" + className="lg:w-[297px] lg:h-[46px] h-[35px] xxs:w-[230px] xs:w-[280px] bg-secondary rounded-[10px] font-karla font-light text-[#ffffff89] text-center" placeholder="search here..." type="text" onKeyDown={handleKeyDown} @@ -347,7 +372,7 @@ export default function Card() { <AnimatePresence> <div key="card-keys" - className="grid pt-3 lg:grid-cols-5 justify-items-center grid-cols-3 w-screen px-2 lg:w-auto lg:gap-10 gap-2 lg:gap-y-24 gap-y-12 overflow-hidden" + className="grid pt-3 lg:grid-cols-6 justify-items-center grid-cols-2 xxs:grid-cols-3 w-screen px-2 lg:w-auto lg:gap-10 gap-2 lg:gap-y-24 gap-y-12 overflow-hidden" > {loading ? "" @@ -362,7 +387,7 @@ export default function Card() { <m.div initial={{ scale: 0.9 }} animate={{ scale: 1, transition: { duration: 0.35 } }} - className="w-[115px] xs:w-[140px] lg:w-[228px]" + className="w-[146px] xxs:w-[115px] xs:w-[135px] md:w-[185px]" key={index} > <Link @@ -373,17 +398,16 @@ export default function Card() { } className="" > - <div - className=" bg-[#3B3C41] lg:h-[313px] xs:h-[215px] h-[175px] hover:scale-105 scale-100 transition-all cursor-pointer duration-200 ease-out rounded-[10px]" - style={{ - backgroundImage: `url(${anime.coverImage.extraLarge})`, - backgroundSize: "cover", - backgroundPosition: "center", - }} + <Image + className="object-cover bg-[#3B3C41] w-[146px] h-[208px] xxs:w-[115px] xxs:h-[163px] xs:w-[135px] xs:h-[192px] md:w-[185px] md:h-[265px] hover:scale-105 scale-100 transition-all cursor-pointer duration-200 ease-out rounded-[10px]" + src={anime.coverImage.extraLarge} + alt={anime.title.userPreferred} + width={500} + height={500} /> </Link> <Link href={`/anime/${anime.id}`}> - <h1 className="font-outfit font-bold lg:text-[20px] pt-4 line-clamp-2"> + <h1 className="font-outfit font-bold md:text-base text-[15px] pt-4 line-clamp-2"> {anime.status === "RELEASING" ? ( <span className="dots bg-green-500" /> ) : anime.status === "NOT_YET_RELEASED" ? ( @@ -407,10 +431,10 @@ export default function Card() { {[1, 2, 4, 5, 6, 7, 8].map((item) => ( <div key={item} - className="flex flex-col w-[115px] xs:w-[140px] lg:w-[228px] gap-5" + className="flex flex-col w-[135px] lg:w-[185px] gap-5" style={{ scale: 0.98 }} > - <Skeleton className="lg:h-[313px] xs:h-[215px] h-[175px]" /> + <Skeleton className="h-[192px] w-[135px] lg:h-[265px] lg:w-[185px]" /> <Skeleton width={110} height={30} /> </div> ))} |