aboutsummaryrefslogtreecommitdiff
path: root/pages
diff options
context:
space:
mode:
authorFactiven <[email protected]>2023-05-01 01:09:33 +0700
committerFactiven <[email protected]>2023-05-01 01:09:33 +0700
commitc526d560a3e8ed9b2dc9a23825b8979c00a152ba (patch)
tree7fa872b8d6dd3cc3c93c7a53f4475ad7b9db7a0a /pages
parentEditor List v0.7 (diff)
downloadmoopa-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.js58
-rw-r--r--pages/anime/[...id].js78
-rw-r--r--pages/anime/watch/[...info].js98
-rw-r--r--pages/categories/[id].js125
-rw-r--r--pages/index.js8
-rw-r--r--pages/search/[param].js82
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>
))}