diff options
| author | Factiven <[email protected]> | 2023-05-01 01:09:33 +0700 |
|---|---|---|
| committer | Factiven <[email protected]> | 2023-05-01 01:09:33 +0700 |
| commit | c526d560a3e8ed9b2dc9a23825b8979c00a152ba (patch) | |
| tree | 7fa872b8d6dd3cc3c93c7a53f4475ad7b9db7a0a /pages | |
| parent | Editor List v0.7 (diff) | |
| download | moopa-c526d560a3e8ed9b2dc9a23825b8979c00a152ba.tar.xz moopa-c526d560a3e8ed9b2dc9a23825b8979c00a152ba.zip | |
Update v3.5
> Bug Fixes
> Editor List Update v0.8
> Display adjustment on search page
Diffstat (limited to 'pages')
| -rw-r--r-- | pages/about.js | 58 | ||||
| -rw-r--r-- | pages/anime/[...id].js | 78 | ||||
| -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/search/[param].js | 82 |
6 files changed, 278 insertions, 171 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 712197e..26c42cb 100644 --- a/pages/anime/[...id].js +++ b/pages/anime/[...id].js @@ -165,6 +165,7 @@ export default function Info() { ); // const [log, setLog] = useState(null); + // console.log(rec); useEffect(() => { const defaultState = { @@ -181,6 +182,7 @@ export default function Info() { // 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 @@ -341,7 +343,7 @@ export default function Info() { <Modal open={open} onClose={() => handleClose()}> <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> @@ -358,7 +360,7 @@ export default function Info() { </button> </div> )} - {session && loading && ( + {session && loading && info && ( <ListEditor animeId={info?.id} session={session} @@ -514,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} @@ -751,7 +763,7 @@ export default function Info() { )} </div> </div> - {rec && ( + {info && rec?.length !== 0 && ( <div className="w-screen md:w-[80%]"> <Content ids="recommendAnime" 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/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> ))} |