aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFactiven <[email protected]>2023-05-16 22:40:02 +0700
committerGitHub <[email protected]>2023-05-16 22:40:02 +0700
commit9a5754fdba9d778f820fe89b44d1e21ca9f0bb4d (patch)
tree8bd574163e760216bc91f7b3c164232b6982efe8
parentUpdate v3.5.6 (diff)
downloadmoopa-9a5754fdba9d778f820fe89b44d1e21ca9f0bb4d.tar.xz
moopa-9a5754fdba9d778f820fe89b44d1e21ca9f0bb4d.zip
Update v3.5.7 (#12)
* Merge request (#11) * Update v3.5.5 > Now Skip button will hide if player is not in focused state. > Added some options to player. > Manga images should be displayed now. * Update videoPlayer.js * Revamp hero section #1 * UI Improvement > Updating main page > Updated Genres selection using params method > Added search bar v1.0 on main page ( [ctrl + space] to access search bar ) * update meta * Update [...id].js * Update [...id].js > Back to ssr I guess * update episode selector * Update [...info].js * Update UI > Added On-Going section for AniList user * Update content.js * added dynamic og * Update og.jsx * Update og * Update og.jsx * update og and id fallback > Added fallback for anime info if it's not found * Update v3.5.7 > Added On-Going section for AniList user > Added Genre section > Added dynamic Open Graph when sharing anime > Added Episode Selector above information
-rw-r--r--assets/Karla-MediumItalic.ttfbin0 -> 42252 bytes
-rw-r--r--assets/Outfit-Regular.ttfbin0 -> 47848 bytes
-rw-r--r--components/hero/content.js182
-rw-r--r--components/hero/genres.js69
-rw-r--r--components/searchBar.js144
-rw-r--r--components/videoPlayer.js2
-rw-r--r--lib/useAnilist.js33
-rw-r--r--package-lock.json175
-rw-r--r--package.json3
-rw-r--r--pages/anime/[...id].js129
-rw-r--r--pages/api/og.jsx103
-rw-r--r--pages/index.js60
-rw-r--r--pages/search/[param].js44
13 files changed, 841 insertions, 103 deletions
diff --git a/assets/Karla-MediumItalic.ttf b/assets/Karla-MediumItalic.ttf
new file mode 100644
index 0000000..608d425
--- /dev/null
+++ b/assets/Karla-MediumItalic.ttf
Binary files differ
diff --git a/assets/Outfit-Regular.ttf b/assets/Outfit-Regular.ttf
new file mode 100644
index 0000000..3fe424f
--- /dev/null
+++ b/assets/Outfit-Regular.ttf
Binary files differ
diff --git a/components/hero/content.js b/components/hero/content.js
index 7e2d9ab..24ee942 100644
--- a/components/hero/content.js
+++ b/components/hero/content.js
@@ -1,9 +1,54 @@
import Link from "next/link";
-import React, { useState } from "react";
+import React, { useState, useRef, useEffect } from "react";
import Image from "next/image";
-import { MdChevronLeft, MdChevronRight } from "react-icons/md";
+import { MdChevronRight } from "react-icons/md";
+import {
+ ChevronRightIcon,
+ ArrowRightCircleIcon,
+} from "@heroicons/react/24/outline";
+
+import { ChevronLeftIcon } from "@heroicons/react/20/solid";
+import { ExclamationCircleIcon } from "@heroicons/react/24/solid";
+
+export default function Content({ ids, section, data, og }) {
+ const [startX, setStartX] = useState(null);
+ const [scrollLefts, setScrollLefts] = useState(null);
+ const containerRef = useRef(null);
+
+ const [isDragging, setIsDragging] = useState(false);
+ const [clicked, setClicked] = useState(false);
+
+ useEffect(() => {
+ const click = localStorage.getItem("clicked");
+ if (click) {
+ setClicked(JSON.parse(click));
+ }
+ }, []);
+
+ const handleMouseDown = (e) => {
+ setIsDragging(true);
+ setStartX(e.pageX - containerRef.current.offsetLeft);
+ setScrollLefts(containerRef.current.scrollLeft);
+ };
+
+ const handleMouseUp = () => {
+ setIsDragging(false);
+ };
+
+ const handleMouseMove = (e) => {
+ if (!isDragging) return;
+ e.preventDefault();
+ const x = e.pageX - containerRef.current.offsetLeft;
+ const walk = (x - startX) * 3;
+ containerRef.current.scrollLeft = scrollLeft - walk;
+ };
+
+ const handleClick = (e) => {
+ if (isDragging) {
+ e.preventDefault();
+ }
+ };
-export default function Content({ ids, section, data }) {
const [scrollLeft, setScrollLeft] = useState(false);
const [scrollRight, setScrollRight] = useState(true);
@@ -24,27 +69,59 @@ export default function Content({ ids, section, data }) {
setScrollRight(scrollRight);
};
- // console.log({ left: scrollLeft, right: scrollRight });
+ function handleAlert(e) {
+ if (localStorage.getItem("clicked")) {
+ const existingDataString = localStorage.getItem("clicked");
+ const existingData = JSON.parse(existingDataString);
+
+ existingData[e] = true;
+
+ const updatedDataString = JSON.stringify(existingData);
+
+ localStorage.setItem("clicked", updatedDataString);
+ } else {
+ const newData = {
+ [e]: true,
+ };
+
+ const newDataString = JSON.stringify(newData);
+
+ localStorage.setItem("clicked", newDataString);
+ }
+ }
const array = data;
let filteredData = array?.filter((item) => item !== null);
+ const slicedData =
+ filteredData?.length > 15 ? filteredData?.slice(0, 15) : filteredData;
+
return (
<div>
- <h1 className="px-5 font-karla text-[20px] font-bold">{section}</h1>
+ <div className="flex items-center justify-between lg:justify-normal lg:gap-3 px-5">
+ <h1 className="font-karla text-[20px] font-bold">{section}</h1>
+ <ChevronRightIcon className="w-5 h-5" />
+ </div>
<div className="relative flex items-center lg:gap-2">
- <MdChevronLeft
+ <div
onClick={slideLeft}
- size={35}
- className={`mb-5 cursor-pointer hover:text-action absolute left-0 bg-gradient-to-r from-[#141519] z-40 h-full hover:opacity-100 ${
- scrollLeft ? "visible" : "hidden"
+ className={`flex items-center mb-5 cursor-pointer hover:text-action absolute left-0 bg-gradient-to-r from-[#141519] z-40 h-full hover:opacity-100 ${
+ scrollLeft ? "lg:visible" : "invisible"
}`}
- />
+ >
+ <ChevronLeftIcon className="w-7 h-7 stroke-2" />
+ </div>
<div
id={ids}
- className="scroll flex h-full w-full items-center select-none overflow-x-scroll scroll-smooth whitespace-nowrap overflow-y-hidden scrollbar-hide lg:gap-8 gap-5 p-10 z-30 "
+ className="scroll flex h-full w-full items-center select-none overflow-x-scroll whitespace-nowrap overflow-y-hidden scrollbar-hide lg:gap-8 gap-3 lg:p-10 py-8 px-5 z-30 scroll-smooth"
onScroll={handleScroll}
+ onMouseDown={handleMouseDown}
+ onMouseUp={handleMouseUp}
+ onMouseMove={handleMouseMove}
+ onClick={handleClick}
+ ref={containerRef}
>
- {filteredData?.map((anime) => {
+ {slicedData?.map((anime) => {
+ const progress = og?.find((i) => i.mediaId === anime.id);
return (
<div
key={anime.id}
@@ -52,8 +129,39 @@ export default function Content({ ids, section, data }) {
>
<Link
href={`/anime/${anime.id}`}
- className="hover:scale-105 group relative duration-300 ease-in-out"
+ className="hover:scale-105 hover:shadow-lg group relative duration-300 ease-out"
>
+ {ids === "onGoing" && (
+ <div className="h-[190px] w-[135px] lg:h-[265px] lg:w-[185px] bg-gradient-to-b from-transparent to-black absolute z-40 rounded-md whitespace-normal font-karla group">
+ <div className="flex flex-col items-center h-full justify-end text-center pb-5">
+ <h1 className="line-clamp-1 w-[70%] text-[10px]">
+ {anime.title.romaji || anime.title.english}
+ </h1>
+ {checkProgress(progress) &&
+ !clicked?.hasOwnProperty(anime.id) && (
+ <ExclamationCircleIcon className="w-7 h-7 absolute z-40 -top-3 -right-3" />
+ )}
+ {checkProgress(progress) && (
+ <div
+ onClick={() => handleAlert(anime.id)}
+ className="group-hover:visible invisible absolute top-0 bg-black bg-opacity-20 w-full h-full z-20 text-center"
+ >
+ <h1 className="text-[12px] lg:text-sm pt-28 lg:pt-44 font-bold opacity-100">
+ {checkProgress(progress)}
+ </h1>
+ </div>
+ )}
+ <div className="flex gap-1 text-[13px] lg:text-base">
+ <h1>Episode {anime.nextAiringEpisode.episode} in</h1>
+ <h1 className="font-bold">
+ {convertSecondsToTime(
+ anime?.nextAiringEpisode?.timeUntilAiring
+ )}
+ </h1>
+ </div>
+ </div>
+ </div>
+ )}
<Image
draggable={false}
src={
@@ -72,17 +180,27 @@ export default function Content({ ids, section, data }) {
anime.coverImage?.large ||
"https://cdn.discordapp.com/attachments/986579286397964290/1058415946945003611/gray_pfp.png"
}
- className="z-20 h-[192px] w-[135px] lg:h-[265px] lg:w-[185px] object-cover rounded-md"
+ className="z-20 h-[190px] w-[135px] lg:h-[265px] lg:w-[185px] object-cover rounded-md brightness-90"
/>
</Link>
</div>
);
})}
+ {filteredData.length >= 10 && section !== "Recommendations" && (
+ <div key={section} className="flex ">
+ <div className="h-[190px] w-[135px] lg:h-[265px] lg:w-[185px] object-cover rounded-md border-secondary border-2 flex flex-col gap-2 items-center text-center justify-center text-[#6a6a6a]">
+ <h1 className="whitespace-pre-wrap text-sm">
+ More on {section}
+ </h1>
+ <ArrowRightCircleIcon className="w-5 h-5" />
+ </div>
+ </div>
+ )}
</div>
<MdChevronRight
onClick={slideRight}
size={30}
- className={`mb-5 cursor-pointer hover:text-action absolute right-0 bg-gradient-to-l from-[#141519] z-40 h-full hover:opacity-100 hover:bg-gradient-to-l ${
+ className={`hidden md:block mb-5 cursor-pointer hover:text-action absolute right-0 bg-gradient-to-l from-[#141519] z-40 h-full hover:opacity-100 hover:bg-gradient-to-l ${
scrollRight ? "visible" : "hidden"
}`}
/>
@@ -90,3 +208,37 @@ export default function Content({ ids, section, data }) {
</div>
);
}
+
+function convertSecondsToTime(sec) {
+ let days = Math.floor(sec / (3600 * 24));
+ let hours = Math.floor((sec % (3600 * 24)) / 3600);
+ let minutes = Math.floor((sec % 3600) / 60);
+
+ let time = "";
+
+ if (days > 0) {
+ time += `${days}d `;
+ time += `${hours}h`;
+ } else {
+ time += `${hours}h `;
+ time += `${minutes}m`;
+ }
+
+ return time.trim();
+}
+
+function checkProgress(entry) {
+ const { progress, media } = entry;
+ const { episodes, nextAiringEpisode } = media;
+
+ if (nextAiringEpisode !== null) {
+ const { episode } = nextAiringEpisode;
+
+ if (episode - progress > 1) {
+ const missedEpisodes = episode - progress - 1;
+ return `${missedEpisodes} episode${missedEpisodes > 1 ? "s" : ""} behind`;
+ }
+ }
+
+ return;
+}
diff --git a/components/hero/genres.js b/components/hero/genres.js
new file mode 100644
index 0000000..1c8a475
--- /dev/null
+++ b/components/hero/genres.js
@@ -0,0 +1,69 @@
+import Image from "next/image";
+import { ChevronRightIcon } from "@heroicons/react/24/outline";
+import Link from "next/link";
+
+const g = [
+ {
+ name: "Action",
+ img: "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx20958-HuFJyr54Mmir.jpg",
+ },
+ {
+ name: "Comedy",
+ img: "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx21202-TfzXuWQf2oLQ.png",
+ },
+ {
+ name: "Horror",
+ img: "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx127230-FlochcFsyoF4.png",
+ },
+ {
+ name: "Romance",
+ img: "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx124080-h8EPH92nyRfS.jpg",
+ },
+ {
+ name: "Music",
+ img: "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx130003-5Y8rYzg982sq.png",
+ },
+ {
+ name: "Sports",
+ img: "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx20464-eW7ZDBOcn74a.png",
+ },
+];
+
+export default function Genres() {
+ return (
+ <div className="antialiased">
+ <div className="flex items-center justify-between lg:justify-normal lg:gap-3 px-5">
+ <h1 className="font-karla text-[20px] font-bold">Top Genres</h1>
+ <ChevronRightIcon className="w-5 h-5" />
+ </div>
+ <div className="flex xl:justify-center items-center relative">
+ <div className="bg-gradient-to-r from-primary to-transparent z-40 absolute w-7 h-[300px] left-0" />
+ <div className="flex lg:gap-8 gap-3 lg:p-10 py-8 px-5 z-30 overflow-y-hidden overflow-x-scroll snap-x snap-proximity scrollbar-none relative">
+ <div className="flex lg:gap-10 gap-3">
+ {g.map((a, index) => (
+ <Link
+ href={`/search/anime/?genres=${a.name}`}
+ key={index}
+ className="relative hover:shadow-lg hover:scale-105 duration-200 cursor-pointer ease-out h-[190px] w-[135px] lg:h-[265px] lg:w-[230px] rounded-md shrink-0"
+ >
+ <div className="bg-gradient-to-b from-transparent to-[#0c0d10] h-[190px] w-[135px] lg:h-[265px] lg:w-[230px] rounded-md absolute flex justify-center items-end">
+ <h1 className="pb-7 lg:text-xl font-karla font-semibold">
+ {a.name}
+ </h1>
+ </div>
+ <Image
+ src={a.img}
+ alt="genres images"
+ width={1000}
+ height={1000}
+ className="object-cover shrink-0 h-[190px] w-[135px] lg:h-[265px] lg:w-[230px] rounded-md"
+ />
+ </Link>
+ ))}
+ </div>
+ </div>
+ <div className="bg-gradient-to-l from-primary to-transparent z-40 absolute w-7 h-[300px] right-0" />
+ </div>
+ </div>
+ );
+}
diff --git a/components/searchBar.js b/components/searchBar.js
new file mode 100644
index 0000000..35e9b45
--- /dev/null
+++ b/components/searchBar.js
@@ -0,0 +1,144 @@
+import { useState, useEffect, useRef } from "react";
+import { motion as m, AnimatePresence } from "framer-motion";
+import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
+import { useAniList } from "../lib/useAnilist";
+import Image from "next/image";
+import Link from "next/link";
+import { useRouter } from "next/router";
+
+const SearchBar = () => {
+ const [isOpen, setIsOpen] = useState(false);
+ const searchBoxRef = useRef(null);
+
+ const router = useRouter();
+
+ const { aniAdvanceSearch } = useAniList();
+ const [data, setData] = useState(null);
+ const [query, setQuery] = useState("");
+
+ useEffect(() => {
+ if (isOpen) {
+ searchBoxRef.current.querySelector("input").focus();
+ }
+ const handleKeyDown = (e) => {
+ if (e.ctrlKey && e.code === "Space") {
+ setIsOpen((prev) => !prev);
+ setData(null);
+ setQuery("");
+ }
+ };
+
+ document.addEventListener("keydown", handleKeyDown);
+
+ const handleClick = (e) => {
+ if (searchBoxRef.current && !searchBoxRef.current.contains(e.target)) {
+ setIsOpen(false);
+ }
+ };
+ document.addEventListener("click", handleClick);
+
+ return () => {
+ document.removeEventListener("keydown", handleKeyDown);
+ document.removeEventListener("click", handleClick);
+ };
+ }, [isOpen]);
+
+ async function search() {
+ const data = await aniAdvanceSearch({
+ search: query,
+ type: "ANIME",
+ perPage: 10,
+ });
+ setData(data);
+ }
+
+ useEffect(() => {
+ if (query) {
+ search();
+ }
+ }, [query]);
+
+ function handleSubmit(e) {
+ e.preventDefault();
+ if (data?.media.length) {
+ router.push(`/anime/${data?.media[0].id}`);
+ }
+ }
+
+ return (
+ <AnimatePresence>
+ {isOpen && (
+ <m.div
+ initial={{ opacity: 0, y: -100 }}
+ animate={{ opacity: 1, y: 0 }}
+ exit={{ opacity: 0, y: -100 }}
+ className="fixed top-0 w-screen flex justify-center z-50"
+ >
+ <div
+ ref={searchBoxRef}
+ className={` bg-[#1c1c1fef] text-white p-4 ${
+ isOpen ? "flex" : "hidden"
+ } flex-col w-[80%] backdrop-blur-sm rounded-b-lg`}
+ >
+ <form onSubmit={handleSubmit}>
+ <input
+ type="text"
+ className="w-full rounded-lg px-4 py-2 mb-2 bg-[#474747]"
+ placeholder="Search..."
+ onChange={(e) => setQuery(e.target.value)}
+ />
+ </form>
+ <div className="flex flex-col gap-2 p-2 font-karla">
+ {data?.media.map((i) => (
+ <Link
+ key={i.id}
+ href={i.type === "ANIME" ? `/anime/${i.id}` : `/`}
+ className="flex hover:bg-[#3e3e3e] rounded-md"
+ >
+ <Image
+ src={i.coverImage.extraLarge}
+ alt="search results"
+ width={500}
+ height={500}
+ className="object-cover w-14 h-14 rounded-md"
+ />
+ <div className="flex items-center justify-between w-full px-5">
+ <div>
+ <h1>{i.title.userPreferred}</h1>
+ <h5 className="text-sm font-light text-[#878787] flex gap-2">
+ {i.status
+ ?.toLowerCase()
+ .replace(/^\w/, (c) => c.toUpperCase())}{" "}
+ {i.status && i.season && <>&#183;</>}{" "}
+ {i.season
+ ?.toLowerCase()
+ .replace(/^\w/, (c) => c.toUpperCase())}{" "}
+ {(i.status || i.season) && i.episodes && <>&#183;</>}{" "}
+ {i.episodes || 0} Episodes
+ </h5>
+ </div>
+ <div className="text-sm text-[#b5b5b5] ">
+ <h1>
+ {i.type
+ ?.toLowerCase()
+ .replace(/^\w/, (c) => c.toUpperCase())}
+ </h1>
+ </div>
+ </div>
+ </Link>
+ ))}
+ </div>
+ {query && (
+ <button className="flex items-center gap-2 justify-center">
+ <MagnifyingGlassIcon className="h-5 w-5" />
+ <Link href={`/search/${query}`}>More Results...</Link>
+ </button>
+ )}
+ </div>
+ </m.div>
+ )}
+ </AnimatePresence>
+ );
+};
+
+export default SearchBar;
diff --git a/components/videoPlayer.js b/components/videoPlayer.js
index c441acc..8594645 100644
--- a/components/videoPlayer.js
+++ b/components/videoPlayer.js
@@ -16,7 +16,6 @@ export default function VideoPlayer({
}) {
const [url, setUrl] = useState();
const [source, setSource] = useState([]);
- const [loading, setLoading] = useState(true);
const { markProgress } = useAniList(session);
useEffect(() => {
@@ -52,7 +51,6 @@ export default function VideoPlayer({
setUrl(defUrl);
setSource(source);
- setLoading(false);
} catch (error) {
console.error(error);
}
diff --git a/lib/useAnilist.js b/lib/useAnilist.js
index 6a0a986..fc25902 100644
--- a/lib/useAnilist.js
+++ b/lib/useAnilist.js
@@ -20,6 +20,10 @@ export function useAniList(session, stats) {
score
media {
id
+ nextAiringEpisode {
+ timeUntilAiring
+ episode
+ }
title {
english
romaji
@@ -104,34 +108,7 @@ export function useAniList(session, stats) {
"Content-Type": "application/json",
},
body: JSON.stringify({
- query: `
- query ($username: String, $status: MediaListStatus) {
- MediaListCollection(userName: $username, type: ANIME, status: $status) {
- lists {
- status
- name
- entries {
- id
- mediaId
- status
- progress
- score
- media {
- id
- title {
- english
- romaji
- }
- episodes
- coverImage {
- large
- }
- }
- }
- }
- }
- }
- `,
+ query: queryMedia,
variables: {
username: username,
status: statuss?.stats,
diff --git a/package-lock.json b/package-lock.json
index 5ecc78b..bdb2ab2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,16 +1,17 @@
{
"name": "moopa",
- "version": "3.5.0",
+ "version": "3.5.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "moopa",
- "version": "3.5.0",
+ "version": "3.5.7",
"dependencies": {
"@apollo/client": "^3.7.3",
"@heroicons/react": "^2.0.17",
"@next/font": "13.0.7",
+ "@vercel/og": "^0.5.4",
"artplayer": "latest",
"axios": "^1.2.2",
"closest-match": "^1.3.3",
@@ -3259,6 +3260,14 @@
"url": "https://github.com/sponsors/panva"
}
},
+ "node_modules/@resvg/resvg-wasm": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/@resvg/resvg-wasm/-/resvg-wasm-2.4.1.tgz",
+ "integrity": "sha512-yi6R0HyHtsoWTRA06Col4WoDs7SvlXU3DLMNP2bdAgs7HK18dTEVl1weXgxRzi8gwLteGUbIg29zulxIB3GSdg==",
+ "engines": {
+ "node": ">= 10"
+ }
+ },
"node_modules/@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -3339,6 +3348,21 @@
"integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==",
"dev": true
},
+ "node_modules/@shuding/opentype.js": {
+ "version": "1.4.0-beta.0",
+ "resolved": "https://registry.npmjs.org/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz",
+ "integrity": "sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==",
+ "dependencies": {
+ "fflate": "^0.7.3",
+ "string.prototype.codepointat": "^0.2.1"
+ },
+ "bin": {
+ "ot": "bin/ot"
+ },
+ "engines": {
+ "node": ">= 8.0.0"
+ }
+ },
"node_modules/@surma/rollup-plugin-off-main-thread": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
@@ -3547,6 +3571,19 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
+ "node_modules/@vercel/og": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/@vercel/og/-/og-0.5.4.tgz",
+ "integrity": "sha512-o4Zjgw66HPtfGFYG4CFcKfnCcK6qCY+3FC6g22Z1SdAN5jN8XjbHCh3hRVHH5IGBQp8mxH941EcH53KimAm+wg==",
+ "dependencies": {
+ "@resvg/resvg-wasm": "2.4.1",
+ "satori": "0.7.2",
+ "yoga-wasm-web": "0.3.3"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
"node_modules/@webassemblyjs/ast": {
"version": "1.11.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.5.tgz",
@@ -4289,6 +4326,14 @@
"node": ">= 6"
}
},
+ "node_modules/camelize": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
+ "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/caniuse-lite": {
"version": "1.0.30001481",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz",
@@ -4496,6 +4541,34 @@
"node": ">=8"
}
},
+ "node_modules/css-background-parser": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/css-background-parser/-/css-background-parser-0.1.0.tgz",
+ "integrity": "sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA=="
+ },
+ "node_modules/css-box-shadow": {
+ "version": "1.0.0-3",
+ "resolved": "https://registry.npmjs.org/css-box-shadow/-/css-box-shadow-1.0.0-3.tgz",
+ "integrity": "sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg=="
+ },
+ "node_modules/css-color-keywords": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
+ "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/css-to-react-native": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
+ "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==",
+ "dependencies": {
+ "camelize": "^1.0.0",
+ "css-color-keywords": "^1.0.0",
+ "postcss-value-parser": "^4.0.2"
+ }
+ },
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@@ -5381,6 +5454,11 @@
"reusify": "^1.0.4"
}
},
+ "node_modules/fflate": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz",
+ "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw=="
+ },
"node_modules/file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -5866,6 +5944,17 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/hex-rgb": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/hex-rgb/-/hex-rgb-4.3.0.tgz",
+ "integrity": "sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/hey-listen": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
@@ -6551,6 +6640,23 @@
"node": ">=10"
}
},
+ "node_modules/linebreak": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz",
+ "integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==",
+ "dependencies": {
+ "base64-js": "0.0.8",
+ "unicode-trie": "^2.0.0"
+ }
+ },
+ "node_modules/linebreak/node_modules/base64-js": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
+ "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@@ -7231,6 +7337,11 @@
"node": ">=6"
}
},
+ "node_modules/pako": {
+ "version": "0.2.9",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
+ "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="
+ },
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -7243,6 +7354,15 @@
"node": ">=6"
}
},
+ "node_modules/parse-css-color": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/parse-css-color/-/parse-css-color-0.2.1.tgz",
+ "integrity": "sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==",
+ "dependencies": {
+ "color-name": "^1.1.4",
+ "hex-rgb": "^4.1.0"
+ }
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -7496,8 +7616,7 @@
"node_modules/postcss-value-parser": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
- "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
- "dev": true
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
},
"node_modules/preact": {
"version": "10.13.2",
@@ -7944,6 +8063,30 @@
"node": ">=6"
}
},
+ "node_modules/satori": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/satori/-/satori-0.7.2.tgz",
+ "integrity": "sha512-Eltg0/i3OEbBLaveCnYi2j+p0J9Bb5rmDMXddq4Zy0/NYHbpTkPIlPYGgb+DKamhmvXhiGvWGiFdqHVjJCaCpA==",
+ "dependencies": {
+ "@shuding/opentype.js": "1.4.0-beta.0",
+ "css-background-parser": "^0.1.0",
+ "css-box-shadow": "1.0.0-3",
+ "css-to-react-native": "^3.0.0",
+ "emoji-regex": "^10.2.1",
+ "linebreak": "^1.1.0",
+ "parse-css-color": "^0.2.1",
+ "postcss-value-parser": "^4.2.0",
+ "yoga-wasm-web": "^0.3.3"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/satori/node_modules/emoji-regex": {
+ "version": "10.2.1",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.2.1.tgz",
+ "integrity": "sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA=="
+ },
"node_modules/scheduler": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
@@ -8131,6 +8274,11 @@
"node": ">= 0.4"
}
},
+ "node_modules/string.prototype.codepointat": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz",
+ "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg=="
+ },
"node_modules/string.prototype.matchall": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz",
@@ -8582,6 +8730,11 @@
"node": ">=0.8"
}
},
+ "node_modules/tiny-inflate": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
+ "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="
+ },
"node_modules/to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@@ -8780,6 +8933,15 @@
"node": ">=4"
}
},
+ "node_modules/unicode-trie": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz",
+ "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==",
+ "dependencies": {
+ "pako": "^0.2.5",
+ "tiny-inflate": "^1.0.0"
+ }
+ },
"node_modules/unique-string": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz",
@@ -9364,6 +9526,11 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/yoga-wasm-web": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/yoga-wasm-web/-/yoga-wasm-web-0.3.3.tgz",
+ "integrity": "sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA=="
+ },
"node_modules/zen-observable": {
"version": "0.8.15",
"resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz",
diff --git a/package.json b/package.json
index 4c718b2..1106b7e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "moopa",
- "version": "3.5.5",
+ "version": "3.5.7",
"private": true,
"scripts": {
"dev": "next dev",
@@ -13,6 +13,7 @@
"@apollo/client": "^3.7.3",
"@heroicons/react": "^2.0.17",
"@next/font": "13.0.7",
+ "@vercel/og": "^0.5.4",
"artplayer": "latest",
"axios": "^1.2.2",
"closest-match": "^1.3.3",
diff --git a/pages/anime/[...id].js b/pages/anime/[...id].js
index ae6ac34..dc385f9 100644
--- a/pages/anime/[...id].js
+++ b/pages/anime/[...id].js
@@ -140,16 +140,18 @@ const infoQuery = `query ($id: Int) {
}
}`;
-export default function Info() {
- const { data: session, status } = useSession();
+export default function Info({ info, color }) {
+ const { data: session } = useSession();
const [data, setData] = useState(null);
- const [info, setInfo] = useState(null);
+ // const [infos, setInfo] = useState(null);
const [episode, setEpisode] = useState(null);
const [loading, setLoading] = useState(false);
const [progress, setProgress] = useState(0);
const [statuses, setStatuses] = useState(null);
const [stall, setStall] = useState(false);
- const [color, setColor] = useState(null);
+ const [domainUrl, setDomainUrl] = useState("");
+
+ // console.log(info);
const [showAll, setShowAll] = useState(false);
const [open, setOpen] = useState(false);
@@ -164,13 +166,15 @@ export default function Info() {
(data) => data.mediaRecommendation
);
- // const [log, setLog] = useState(null);
- // console.log(rec);
-
useEffect(() => {
+ const { protocol, host } = window.location;
+ const url = `${protocol}//${host}`;
+
+ setDomainUrl(url);
+
const defaultState = {
data: null,
- info: null,
+ // info: null,
episode: null,
loading: true,
statuses: null,
@@ -204,23 +208,23 @@ export default function Info() {
if (id) {
setLoading(false);
try {
- const [res, info] = await Promise.all([
+ const [res] = await Promise.all([
fetch(`https://api.moopa.my.id/meta/anilist/info/${id?.[0]}`),
- fetch("https://graphql.anilist.co/", {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({
- query: infoQuery,
- variables: {
- id: id?.[0],
- },
- }),
- }),
+ // fetch("https://graphql.anilist.co/", {
+ // method: "POST",
+ // headers: {
+ // "Content-Type": "application/json",
+ // },
+ // body: JSON.stringify({
+ // query: infoQuery,
+ // variables: {
+ // id: id?.[0],
+ // },
+ // }),
+ // }),
]);
const data = await res.json();
- const infos = await info.json();
+ // const infos = await info.json();
if (res.status === 500) {
setEpisode(null);
@@ -229,10 +233,10 @@ export default function Info() {
} else if (res.status === 404) {
window.location.href("/404");
}
- setInfo(infos.data.Media);
+ // setInfo(infos.data.Media);
// setLog(data);
- const textColor = setTxtColor(infos.data.Media.coverImage?.color);
+ // const textColor = setTxtColor(infos.data.Media.coverImage?.color);
if (!data || data?.episodes?.length === 0) {
const res = await fetch(
@@ -246,19 +250,19 @@ export default function Info() {
} else {
setEpisode(datas.episodes);
}
- setColor({
- backgroundColor: `${data?.color || "#ffff"}`,
- color: textColor,
- });
+ // setColor({
+ // backgroundColor: `${data?.color || "#ffff"}`,
+ // color: textColor,
+ // });
setStall(true);
} else {
setEpisode(data.episodes);
}
- setColor({
- backgroundColor: `${data?.color || "#ffff"}`,
- color: textColor,
- });
+ // setColor({
+ // backgroundColor: `${data?.color || "#ffff"}`,
+ // color: textColor,
+ // });
if (session?.user?.name) {
const response = await fetch("https://graphql.anilist.co/", {
@@ -339,6 +343,21 @@ export default function Info() {
? info?.title?.romaji || info?.title?.english
: "Retrieving Data..."}
</title>
+ <meta name="twitter:card" content="summary_large_image" />
+ <meta
+ name="twitter:title"
+ content={`Moopa - ${info.title.romaji || info.title.english}`}
+ />
+ <meta
+ name="twitter:description"
+ content={`${info.description?.slice(0, 180)}...`}
+ />
+ <meta
+ name="twitter:image"
+ content={`${domainUrl}/api/og?title=${
+ info.title.romaji || info.title.english
+ }&image=${info.bannerImage || info.coverImage.extraLarge}`}
+ />
</Head>
<Modal open={open} onClose={() => handleClose()}>
<div>
@@ -743,13 +762,15 @@ export default function Info() {
// Something went wrong, can't retrieve any episodes :/
// </p>
<div className="flex flex-col">
- <h1>{epiStatus} while retrieving data</h1>
+ {/* <h1>{epiStatus} while retrieving data</h1> */}
<pre
className={`rounded-md ${getLanguageClassName(
"bash"
)}`}
>
- <code>{error}</code>
+ <code>
+ Something went wrong while retrieving data :/
+ </code>
</pre>
</div>
)}
@@ -785,6 +806,46 @@ export default function Info() {
);
}
+export async function getServerSideProps(context) {
+ const { id } = context.query;
+
+ const res = await fetch("https://graphql.anilist.co/", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ query: infoQuery,
+ variables: {
+ id: id?.[0],
+ },
+ }),
+ });
+
+ const json = await res.json();
+ const data = json?.data?.Media;
+
+ if (!data) {
+ return {
+ notFound: true,
+ };
+ }
+
+ const textColor = setTxtColor(data?.coverImage?.color);
+
+ const color = {
+ backgroundColor: `${data?.coverImage?.color || "#ffff"}`,
+ color: textColor,
+ };
+
+ return {
+ props: {
+ info: data,
+ color: color,
+ },
+ };
+}
+
function convertSecondsToTime(sec) {
let days = Math.floor(sec / (3600 * 24));
let hours = Math.floor((sec % (3600 * 24)) / 3600);
diff --git a/pages/api/og.jsx b/pages/api/og.jsx
new file mode 100644
index 0000000..b1cf238
--- /dev/null
+++ b/pages/api/og.jsx
@@ -0,0 +1,103 @@
+import { ImageResponse } from "@vercel/og";
+
+export const config = {
+ runtime: "edge",
+};
+
+const karla = fetch(
+ new URL("../../assets/Karla-MediumItalic.ttf", import.meta.url)
+).then((res) => res.arrayBuffer());
+const outfit = fetch(
+ new URL("../../assets/Outfit-Regular.ttf", import.meta.url)
+).then((res) => res.arrayBuffer());
+
+export default async function handler(request) {
+ const Karla = await karla;
+ const Outfit = await outfit;
+
+ const { searchParams } = request.nextUrl;
+ const hasTitle = searchParams.has("title");
+ const title = hasTitle
+ ? searchParams.get("title").length > 64
+ ? searchParams.get("title").slice(0, 64) + "..."
+ : searchParams.get("title")
+ : "Watch Now";
+ const image = searchParams.get("image");
+ if (!title) {
+ return new ImageResponse(<>Visit with &quot;?username=vercel&quot;</>, {
+ width: 1200,
+ height: 630,
+ });
+ }
+
+ return new ImageResponse(
+ (
+ <div
+ style={{
+ display: "flex",
+ fontSize: 60,
+ color: "black",
+ background: "#f6f6f6",
+ width: "100%",
+ height: "100%",
+ backgroundImage: `url(${image})`,
+ }}
+ className="relative w-[1900px] h-[400px] text-[10px]"
+ >
+ <div
+ className="w-[1900px] h-[400px]"
+ style={{
+ display: "flex",
+ width: "100%",
+ paddingLeft: 100,
+ alignItems: "center",
+ color: "white",
+ position: "relative",
+ backgroundImage: `linear-gradient(to right, rgba(0,0,0,0.93), rgba(0,0,0,0.8) , rgba(0,0,0,0.2))`,
+ filter: "brightness(20%)",
+ }}
+ >
+ <span
+ style={{
+ display: "flex",
+ position: "absolute",
+ top: 10,
+ left: 25,
+ fontSize: "40",
+ color: "#FF7F57",
+ fontFamily: "Outfit",
+ filter: "brightness(100%)",
+ }}
+ >
+ moopa
+ </span>
+ <h1
+ style={{
+ width: "70%",
+ fontSize: "70px",
+ filter: "brightness(100%)",
+ }}
+ >
+ {title}
+ </h1>
+ </div>
+ </div>
+ ),
+ {
+ width: 1900,
+ height: 400,
+ fonts: [
+ {
+ name: "Karla",
+ data: Karla,
+ style: "normal",
+ },
+ {
+ name: "Outfit",
+ data: Outfit,
+ style: "normal",
+ },
+ ],
+ }
+ );
+}
diff --git a/pages/index.js b/pages/index.js
index 88687d7..abe5df3 100644
--- a/pages/index.js
+++ b/pages/index.js
@@ -13,6 +13,8 @@ import { useSession, signIn, signOut } from "next-auth/react";
import { useAniList } from "../lib/useAnilist";
import { getServerSession } from "next-auth/next";
import { authOptions } from "./api/auth/[...nextauth]";
+import SearchBar from "../components/searchBar";
+import Genres from "../components/hero/genres";
export function Navigasi() {
const { data: sessions, status } = useSession();
@@ -38,7 +40,7 @@ export function Navigasi() {
<div className="flex items-center lg:gap-16 lg:pt-7">
<Link
href="/"
- className=" font-outfit text-[40px] font-bold text-[#FF7F57]"
+ className=" font-outfit lg:text-[40px] text-[30px] font-bold text-[#FF7F57]"
>
moopa
</Link>
@@ -78,7 +80,7 @@ export function Navigasi() {
)}
</ul>
</div>
- <div className="relative flex scale-75 items-center mb-7 lg:mb-0">
+ <div className="relative flex lg:scale-75 scale-[65%] items-center mb-7 lg:mb-0">
<div className="search-box ">
<input
className="search-text"
@@ -105,6 +107,10 @@ export default function Home({ detail, populars, sessions }) {
const [list, setList] = useState(null);
const [planned, setPlanned] = useState(null);
const [greeting, setGreeting] = useState("");
+ const [onGoing, setOnGoing] = useState(null);
+
+ const [prog, setProg] = useState(null);
+
const popular = populars?.data;
const data = detail.data[0];
@@ -140,10 +146,19 @@ export default function Home({ detail, populars, sessions }) {
.map(({ media }) => media)
.filter((media) => media);
+ const prog = getMedia?.entries.filter(
+ (item) => item.media.nextAiringEpisode !== null
+ );
+
+ setProg(prog);
+
const planned = plan?.[0]?.entries
.map(({ media }) => media)
.filter((media) => media);
+ const onGoing = list?.filter((item) => item.nextAiringEpisode !== null);
+ setOnGoing(onGoing);
+
if (list) {
setList(list.reverse());
}
@@ -154,6 +169,8 @@ export default function Home({ detail, populars, sessions }) {
userData();
}, [sessions, current, plan]);
+ // console.log(log);
+
return (
<>
<Head>
@@ -361,6 +378,7 @@ export default function Home({ detail, populars, sessions }) {
<div className="h-auto w-screen bg-[#141519] text-[#dbdcdd] ">
<Navigasi />
+ <SearchBar />
{/* PC / TABLET */}
<div className=" hidden justify-center lg:flex my-16">
<div className="relative grid grid-rows-2 items-center lg:flex lg:h-[467px] lg:w-[80%] lg:justify-between">
@@ -402,9 +420,14 @@ export default function Home({ detail, populars, sessions }) {
</div>
</div>
</div>
+ {/* {!sessions && (
+ <h1 className="font-bold font-karla mx-5 text-[32px] mt-2 lg:mx-24 xl:mx-36">
+ {greeting}!
+ </h1>
+ )} */}
{sessions && (
- <div className="flex items-center mx-3 lg:mx-0 mt-10 lg:mt-0">
- <div className="lg:text-4xl lg:mx-32 flex items-center gap-3 text-2xl font-bold font-karla">
+ <div className="flex items-center justify-center lg:bg-none mt-4 lg:mt-0 w-screen">
+ <div className="lg:w-[85%] w-screen px-5 lg:px-0 lg:text-4xl flex items-center gap-3 text-2xl font-bold font-karla">
{greeting},<h1 className="lg:hidden">{sessions?.user.name}</h1>
<button
onClick={() => signOut()}
@@ -419,13 +442,30 @@ export default function Home({ detail, populars, sessions }) {
</div>
)}
- <div className="lg:mt-16 mt-12 flex flex-col items-center">
+ <div className="lg:mt-16 mt-5 flex flex-col items-center">
<motion.div
className="w-screen flex-none lg:w-[87%]"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5, staggerChildren: 0.2 }} // Add staggerChildren prop
>
+ {sessions && onGoing && (
+ <motion.div // Add motion.div to each child component
+ key="onGoing"
+ initial={{ y: 20, opacity: 0 }}
+ whileInView={{ y: 0, opacity: 1 }}
+ transition={{ duration: 0.5 }}
+ viewport={{ once: true }}
+ >
+ <Content
+ ids="onGoing"
+ section="On-Going Anime"
+ data={onGoing}
+ og={prog}
+ />
+ </motion.div>
+ )}
+
{sessions && list && (
<motion.div // Add motion.div to each child component
key="listAnime"
@@ -492,6 +532,16 @@ export default function Home({ detail, populars, sessions }) {
/>
</motion.div>
)}
+
+ <motion.div // Add motion.div to each child component
+ key="Genres"
+ initial={{ y: 20, opacity: 0 }}
+ whileInView={{ y: 0, opacity: 1 }}
+ transition={{ duration: 0.5 }}
+ viewport={{ once: true }}
+ >
+ <Genres />
+ </motion.div>
</motion.div>
</div>
</div>
diff --git a/pages/search/[param].js b/pages/search/[param].js
index 9fc2b17..96d6671 100644
--- a/pages/search/[param].js
+++ b/pages/search/[param].js
@@ -56,8 +56,11 @@ export default function Card() {
let tipe = "ANIME";
let s = undefined;
let y = NaN;
+ let gr = undefined;
const query = router.query;
+ gr = query.genres;
+
if (query.param !== "anime" && query.param !== "manga") {
hasil = query.param;
} else if (query.param === "anime") {
@@ -96,9 +99,8 @@ export default function Card() {
const [search, setQuery] = useState(hasil);
const [type, setSelectedType] = useState(tipe);
- const [genres, setSelectedGenre] = useState();
+ // const [genres, setSelectedGenre] = useState();
const [sort, setSelectedSort] = useState();
- // console.log(data);
const [isVisible, setIsVisible] = useState(false);
@@ -112,7 +114,7 @@ export default function Card() {
const data = await aniAdvanceSearch({
search: search,
type: type,
- genres: genres,
+ genres: gr,
page: page,
sort: sort,
season: s,
@@ -137,7 +139,7 @@ export default function Card() {
setPage(1);
setNextPage(true);
advance();
- }, [search, type, genres, sort, s, y]);
+ }, [search, type, sort, s, y, gr]);
useEffect(() => {
advance();
@@ -178,8 +180,9 @@ export default function Card() {
function trash() {
setQuery(null);
inputRef.current.value = "";
- setSelectedGenre(null);
+ // setSelectedGenre(null);
setSelectedSort(["POPULARITY_DESC"]);
+ router.push(`/search/${tipe.toLocaleLowerCase()}`);
}
function handleVisible() {
@@ -202,7 +205,7 @@ export default function Card() {
<div className="bg-primary">
<Navbar />
<div className="min-h-screen mt-10 mb-14 text-white items-center gap-5 xl:gap-0 flex flex-col">
- <div className="w-screen px-10 xl:w-[80%] xl:h-[10rem] flex text-center xl:items-end xl:pb-16 justify-center lg:gap-7 xl:gap-10 gap-3 font-karla font-light">
+ <div className="w-screen px-10 xl:w-[80%] xl:h-[10rem] flex text-center xl:items-end xl:pb-10 justify-center lg:gap-7 xl:gap-10 gap-3 font-karla font-light">
<div className="text-start">
<h1 className="font-bold xl:pb-5 pb-3 hidden lg:block text-md pl-1 font-outfit">
TITLE
@@ -299,6 +302,7 @@ export default function Card() {
</div>
</div>
</div>
+
<div className="w-screen xl:w-[64%] flex xl:justify-end xl:pl-0">
<AnimatePresence>
{isVisible && (
@@ -309,19 +313,24 @@ export default function Card() {
exit={{ opacity: 0, y: -10 }}
className="xl:pb-16"
>
- <div className="text-start items-center xl:items-start flex w-screen xl:w-auto px-8 xl:px-0 flex-row justify-between xl:flex-col pb-5 ">
+ <div className="text-start items-center xl:items-start flex w-screen xl:w-auto px-8 xl:px-0 flex-row justify-between xl:flex-col pb-5 lg:pb-0 ">
<h1 className="font-bold xl:pb-5 text-md pl-1 font-outfit">
GENRE
</h1>
<select
className="w-[195px] xl:w-[297px] xl:h-[46px] h-[35px] bg-secondary rounded-[10px] flex items-center text-center cursor-pointer hover:bg-[#272b35] transition-all duration-300"
- onChange={(e) =>
- setSelectedGenre(
- e.target.value === "undefined"
- ? undefined
- : e.target.value
- )
- }
+ onChange={(e) => {
+ // setSelectedGenre(
+ // e.target.value === "undefined"
+ // ? undefined
+ // : e.target.value
+ // );
+ router.push(
+ `/search/${tipe.toLocaleLowerCase()}/?genres=${
+ e.target.value
+ }`
+ );
+ }}
>
<option value="undefined">Select a Genre</option>
{genre.map((option) => {
@@ -372,6 +381,13 @@ export default function Card() {
)}
</AnimatePresence>
</div>
+ {gr && (
+ <div className="lg:w-[70%] px-5 lg:px-4 w-screen lg:mb-6">
+ <h1 className="font-bold text-[25px] font-karla">
+ Looking for : {gr}
+ </h1>
+ </div>
+ )}
<div className="flex flex-col gap-14 items-center">
<AnimatePresence>
<div