From 180c9577f8337991ca71470816333fe8430cd3ca Mon Sep 17 00:00:00 2001 From: real-zephex Date: Fri, 24 May 2024 22:51:36 +0530 Subject: =?UTF-8?q?=E2=9C=A8=20feat(ui):=20=F0=9F=8E=A8=20migrate=20from?= =?UTF-8?q?=20vanilla=20css=20to=20tailwind=20css,=20adopted=20next=20ui?= =?UTF-8?q?=20and=20restructured?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/anime/[id]/page.jsx | 103 +++++-------- src/app/anime/components/cacher.js | 4 +- src/app/anime/components/episode_buttons.jsx | 2 +- src/app/anime/components/infoTabs.jsx | 46 ++++++ src/app/anime/components/popularAnimes.jsx | 53 ------- src/app/anime/components/recentEpisodes.jsx | 54 ------- src/app/anime/components/saveToLocalStorage.js | 29 ++++ src/app/anime/components/search.jsx | 55 +++---- src/app/anime/components/search_results.jsx | 51 ++++--- src/app/anime/components/topAiring.jsx | 56 ------- src/app/anime/components/vidButtonContainer.jsx | 133 +++++++++++++++++ src/app/anime/continueWatching/page.jsx | 1 - src/app/anime/loading.jsx | 11 -- src/app/anime/page.jsx | 105 +++++++++++-- src/app/anime/styles/anime.module.css | 4 - src/app/anime/styles/buttons.module.css | 98 ------------ src/app/anime/styles/cw.module.css | 59 -------- src/app/anime/styles/info.module.css | 69 --------- src/app/anime/styles/loading.module.css | 12 -- src/app/anime/styles/pop_recent_top.module.css | 95 ------------ src/app/anime/styles/search.module.css | 116 --------------- src/app/components/header/header.jsx | 53 ++++--- src/app/components/moonIcon.jsx | 17 +++ src/app/components/sunIcon.jsx | 17 +++ src/app/components/themeSwitcher.jsx | 43 ++++++ src/app/components/workInProgress/page.jsx | 12 ++ src/app/error.jsx | 13 +- src/app/globals.css | 10 +- src/app/kdrama/[id]/buttons.jsx | 86 ----------- src/app/kdrama/[id]/page.jsx | 92 +++++------- src/app/kdrama/components/cacher.js | 17 +-- src/app/kdrama/components/episodesContainer.jsx | 83 +++++++++++ src/app/kdrama/components/infoTabs.jsx | 51 +++++++ src/app/kdrama/components/popular.jsx | 47 ------ src/app/kdrama/components/recent.jsx | 46 ------ src/app/kdrama/components/requests.js | 44 ++++++ src/app/kdrama/components/search.jsx | 65 -------- src/app/kdrama/components/searchBar.jsx | 57 +++++++ src/app/kdrama/components/searchFormatter.jsx | 46 ++++++ src/app/kdrama/components/searchQuery.js | 10 -- src/app/kdrama/components/videoLink.js | 11 -- src/app/kdrama/loading.jsx | 9 -- src/app/kdrama/page.jsx | 104 +++++++++++-- src/app/kdrama/styles/info.module.css | 173 ---------------------- src/app/kdrama/styles/kdrama.module.css | 4 - src/app/kdrama/styles/loading.module.css | 21 --- src/app/kdrama/styles/popular.module.css | 73 --------- src/app/kdrama/styles/search.module.css | 84 ----------- src/app/layout.jsx | 31 +++- src/app/movies/components/popular.jsx | 17 +-- src/app/movies/components/search.jsx | 2 +- src/app/movies/components/trending.jsx | 17 +-- src/app/movies/styles/pop_trend.module.css | 26 ++-- src/app/movies/styles/search.module.css | 7 +- src/app/page.jsx | 96 ++++++------ src/app/page.module.css | 156 +------------------ src/app/web-series/[id]/page.jsx | 2 +- src/app/web-series/components/HomePageModules.jsx | 4 +- src/app/web-series/components/searchBar.jsx | 2 +- src/app/web-series/styles/info.module.css | 1 - src/app/web-series/styles/pages.module.css | 9 +- src/app/web-series/styles/search.module.css | 4 +- 62 files changed, 1058 insertions(+), 1760 deletions(-) create mode 100644 src/app/anime/components/infoTabs.jsx delete mode 100644 src/app/anime/components/popularAnimes.jsx delete mode 100644 src/app/anime/components/recentEpisodes.jsx create mode 100644 src/app/anime/components/saveToLocalStorage.js delete mode 100644 src/app/anime/components/topAiring.jsx create mode 100644 src/app/anime/components/vidButtonContainer.jsx delete mode 100644 src/app/anime/loading.jsx delete mode 100644 src/app/anime/styles/anime.module.css delete mode 100644 src/app/anime/styles/buttons.module.css delete mode 100644 src/app/anime/styles/cw.module.css delete mode 100644 src/app/anime/styles/info.module.css delete mode 100644 src/app/anime/styles/loading.module.css delete mode 100644 src/app/anime/styles/pop_recent_top.module.css delete mode 100644 src/app/anime/styles/search.module.css create mode 100644 src/app/components/moonIcon.jsx create mode 100644 src/app/components/sunIcon.jsx create mode 100644 src/app/components/themeSwitcher.jsx create mode 100644 src/app/components/workInProgress/page.jsx delete mode 100644 src/app/kdrama/[id]/buttons.jsx create mode 100644 src/app/kdrama/components/episodesContainer.jsx create mode 100644 src/app/kdrama/components/infoTabs.jsx delete mode 100644 src/app/kdrama/components/popular.jsx delete mode 100644 src/app/kdrama/components/recent.jsx create mode 100644 src/app/kdrama/components/requests.js delete mode 100644 src/app/kdrama/components/search.jsx create mode 100644 src/app/kdrama/components/searchBar.jsx create mode 100644 src/app/kdrama/components/searchFormatter.jsx delete mode 100644 src/app/kdrama/components/searchQuery.js delete mode 100644 src/app/kdrama/components/videoLink.js delete mode 100644 src/app/kdrama/loading.jsx delete mode 100644 src/app/kdrama/styles/info.module.css delete mode 100644 src/app/kdrama/styles/kdrama.module.css delete mode 100644 src/app/kdrama/styles/loading.module.css delete mode 100644 src/app/kdrama/styles/popular.module.css delete mode 100644 src/app/kdrama/styles/search.module.css (limited to 'src') diff --git a/src/app/anime/[id]/page.jsx b/src/app/anime/[id]/page.jsx index d338417..f8cbe0c 100644 --- a/src/app/anime/[id]/page.jsx +++ b/src/app/anime/[id]/page.jsx @@ -1,80 +1,49 @@ -import Image from "next/image"; +import { Chip, Image } from "@nextui-org/react"; import { anime_info } from "../data-fetch/request"; -import styles from "../styles/info.module.css"; -import EpisodesButtons from "../components/episode_buttons"; +import DescriptionTabs from "../components/infoTabs"; -import { preFetchVideoLinks } from "../components/cacher"; +import EpisodesContainer from "../components/vidButtonContainer"; const AnimeInfoHomepage = async ({ params }) => { const id = params.id; const data = await anime_info(id); - const sliceLength = Math.min(data.episodes.length, 49); - preFetchVideoLinks(data.episodes.slice(0, sliceLength)); - return ( -
-
- {data && ( -
-
- Anime Poster -
-

- {data.title || "Not Found"} -

-

- Description: - {data.description || "Not Found"} -

-
- - - Genres: - - {data.genres && - data.genres.map((item, index) => ( - - {item} - {index !== - data.genres.length - 1 && - ", "} - - ))} - -

- Episodes:{" "} - {data.totalEpisodes || "Not Found"} -

-

- Release year:{" "} - {data.releaseDate || "Not Found"} -

-

- Status:{" "} - {data.status || "Not Found"} -

-

- Type:{" "} - {data.type || "Not Found"} -

-
-
-
- )} +
+
+ Anime Title Poster +
+

+ {data.title} +

+
+ {data.genres && + data.genres.map((item, index) => ( + +

{item}

+
+ ))} +
+
- -
+ + +
+
+
+ ); }; diff --git a/src/app/anime/components/cacher.js b/src/app/anime/components/cacher.js index d3008fa..164dafd 100644 --- a/src/app/anime/components/cacher.js +++ b/src/app/anime/components/cacher.js @@ -1,11 +1,11 @@ "use server"; -import { info_url, watch_url } from "../../../../utils/anime_urls"; +import { anime_info } from "../data-fetch/request"; export async function preFetchAnimeInfo(data) { try { const fetchPromises = data.results.map(async (element) => { - await fetch(info_url(element.id), { next: { revalidate: 21600 } }); + await anime_info(element.id); }); await Promise.all(fetchPromises); diff --git a/src/app/anime/components/episode_buttons.jsx b/src/app/anime/components/episode_buttons.jsx index 013dee1..71f338f 100644 --- a/src/app/anime/components/episode_buttons.jsx +++ b/src/app/anime/components/episode_buttons.jsx @@ -202,4 +202,4 @@ function store_to_local(name, image, episode, id) { } } -export default EpisodesButtons; \ No newline at end of file +export default EpisodesButtons; diff --git a/src/app/anime/components/infoTabs.jsx b/src/app/anime/components/infoTabs.jsx new file mode 100644 index 0000000..68a1da1 --- /dev/null +++ b/src/app/anime/components/infoTabs.jsx @@ -0,0 +1,46 @@ +"use client"; + +import { Tabs, Tab, Card, CardBody } from "@nextui-org/react"; + +import { lexend, atkinson } from "../../../../config/fonts"; + +export default function DescriptionTabs({ data: data }) { + return ( +
+ + + + + {data.description || "No description found"} + + + + + + +

+ Episodes:{" "} + {data.totalEpisodes} +

+

+ Type: {data.type} +

+

+ SUB/DUB:{" "} + {data.subOrDub.toUpperCase()} +

+

+ Status:{" "} + {data.status} +

+

+ Release Year:{" "} + {data.releaseDate} +

+
+
+
+
+
+ ); +} diff --git a/src/app/anime/components/popularAnimes.jsx b/src/app/anime/components/popularAnimes.jsx deleted file mode 100644 index e62f70f..0000000 --- a/src/app/anime/components/popularAnimes.jsx +++ /dev/null @@ -1,53 +0,0 @@ -import Link from "next/link"; -import Image from "next/image"; -import { Lexend_Deca } from "next/font/google"; - -import styles from "../styles/pop_recent_top.module.css"; -import { popular } from "../data-fetch/request"; -import { preFetchAnimeInfo } from "./cacher"; - -const lexend = Lexend_Deca({ subsets: ["latin"], weight: "400" }); - -const PopularAnimes = async () => { - const data = await popular(); - - preFetchAnimeInfo(data); - - return ( -
-
-

Popular Animes

-
- {data && - data.results.map((item, index) => ( - -
- Anime Poster Image -

- {item.title} -

-
- - ))} -
-
-
- ); -}; - -export default PopularAnimes; diff --git a/src/app/anime/components/recentEpisodes.jsx b/src/app/anime/components/recentEpisodes.jsx deleted file mode 100644 index 9e7899f..0000000 --- a/src/app/anime/components/recentEpisodes.jsx +++ /dev/null @@ -1,54 +0,0 @@ -import Link from "next/link"; -import Image from "next/image"; -import { Lexend_Deca } from "next/font/google"; - -import styles from "../styles/pop_recent_top.module.css"; -import { recent } from "../data-fetch/request"; -import { preFetchAnimeInfo } from "./cacher"; - -const lexend = Lexend_Deca({ subsets: ["latin"], weight: "400" }); - -const RecentAnimes = async () => { - const data = await recent(); - - preFetchAnimeInfo(data); - - return ( -
-
-

Recent Releases

-
- {data && - data.results.map((item, index) => ( - -
- Anime Poster Image -

- {item.title} -

-

{item.episodeNumber}

-
- - ))} -
-
-
- ); -}; - -export default RecentAnimes; diff --git a/src/app/anime/components/saveToLocalStorage.js b/src/app/anime/components/saveToLocalStorage.js new file mode 100644 index 0000000..313b157 --- /dev/null +++ b/src/app/anime/components/saveToLocalStorage.js @@ -0,0 +1,29 @@ +"use client"; + +import { storeLocal } from "./storeHistory"; + +export default function store_to_local(name, image, episode, id) { + const currentDate = new Date(); + + try { + let newData = { + name: name, + image: image, + episode: episode, + id: id, + type: "anime", + date: `${currentDate.getDate()}-${String( + currentDate.getMonth() + 1 + ).padStart(2, "0")}`, + time: `${currentDate.getHours()}:${String( + currentDate.getMinutes() + ).padStart(2, "0")}`, + }; + storeLocal(newData); + } catch (error) { + console.error( + "Some error occurred during the process of saving your watch history to local storage. Please try again or contact us on GitHub if this issue persists.", + error.message + ); + } +} diff --git a/src/app/anime/components/search.jsx b/src/app/anime/components/search.jsx index 0a780f8..0fe883b 100644 --- a/src/app/anime/components/search.jsx +++ b/src/app/anime/components/search.jsx @@ -2,37 +2,37 @@ import { FaSearch } from "react-icons/fa"; import { useState } from "react"; -import Link from "next/link"; +import { Input, Link, Button, Progress } from "@nextui-org/react"; -import styles from "../styles/search.module.css"; import SearchResults from "./search_results"; -const SearcBar = () => { +const SearchBar = () => { const [title, setTitle] = useState(""); const [searchResults, setSearchResults] = useState(null); const [loading, setLoading] = useState(false); const handleSearchInput = async (title) => { setSearchResults(null); - setLoading(true); + setLoading( + + ); setSearchResults(await SearchResults(title)); setLoading(false); }; return (
-
-
- - +
+ { - if (event.target.value.trim() != "") { - setTitle(event.target.value); - } - }} + label="Search for anime" + placeholder="Enter anime title here" autoComplete="off" onKeyDown={async (event) => { if ( @@ -43,22 +43,23 @@ const SearcBar = () => { await handleSearchInput(title); } }} - > - - + onChange={(event) => { + if (event.target.value.trim() != "") { + setTitle(event.target.value); + } + }} + startContent={} + /> + + +
+ {loading}
- {loading && ( -

- Please wait while we crunch up all the data..... -

- )} - {searchResults} +
{searchResults}
); }; -export default SearcBar; +export default SearchBar; diff --git a/src/app/anime/components/search_results.jsx b/src/app/anime/components/search_results.jsx index 051124d..3097a96 100644 --- a/src/app/anime/components/search_results.jsx +++ b/src/app/anime/components/search_results.jsx @@ -1,12 +1,9 @@ -import { Lexend_Deca } from "next/font/google"; -import Link from "next/link"; -import Image from "next/image"; - -import styles from "../styles/search.module.css"; import { search_results } from "../data-fetch/request"; import { preFetchAnimeInfo } from "./cacher"; +import styles from "../../page.module.css"; -const lexend = Lexend_Deca({ subsets: ["latin"], weight: "400" }); +import { Card, CardHeader, CardBody, Image, Link } from "@nextui-org/react"; +import NextImage from "next/image"; const SearchResults = async (title) => { const data = await search_results(title); @@ -14,25 +11,39 @@ const SearchResults = async (title) => { preFetchAnimeInfo(data); return ( -
+
{data && data.results.map((item, index) => ( -
- Anime Poster -

{item.title}

-
+ + + Anime Poster + + +

+ {item.title} +

+
+
))}
diff --git a/src/app/anime/components/topAiring.jsx b/src/app/anime/components/topAiring.jsx deleted file mode 100644 index 22e8c3b..0000000 --- a/src/app/anime/components/topAiring.jsx +++ /dev/null @@ -1,56 +0,0 @@ -import Link from "next/link"; -import Image from "next/image"; -import { Lexend_Deca } from "next/font/google"; - -import styles from "../styles/pop_recent_top.module.css"; -import { top_airing } from "../data-fetch/request"; -import { preFetchAnimeInfo } from "./cacher"; - -const lexend = Lexend_Deca({ subsets: ["latin"], weight: "400" }); - -const TopAiringAnimes = async () => { - const data = await top_airing(); - - preFetchAnimeInfo(data); - - return ( -
-
-

Top Airing Animes

-
- {data && - data.results.map((item, index) => ( - -
- Anime Poster Image -

- {item.title} -

-

- {item.episodeNumber} -

-
- - ))} -
-
-
- ); -}; - -export default TopAiringAnimes; diff --git a/src/app/anime/components/vidButtonContainer.jsx b/src/app/anime/components/vidButtonContainer.jsx new file mode 100644 index 0000000..6b872d8 --- /dev/null +++ b/src/app/anime/components/vidButtonContainer.jsx @@ -0,0 +1,133 @@ +"use client"; + +import { MediaPlayer, MediaProvider } from "@vidstack/react"; +import "@vidstack/react/player/styles/default/theme.css"; +import "@vidstack/react/player/styles/default/layouts/video.css"; +import { + defaultLayoutIcons, + DefaultVideoLayout, +} from "@vidstack/react/player/layouts/default"; +import { Select, SelectItem, Button, Skeleton } from "@nextui-org/react"; +import { useState, useEffect } from "react"; + +import { lexend } from "../../../../config/fonts"; +import { video_url } from "../data-fetch/request"; +import store_to_local from "./saveToLocalStorage"; + +const EpisodesContainer = ({ data: data }) => { + const [videoLink, setVideoLink] = useState(""); + const [buttonGroups, setButtonGroups] = useState(<>); + const [videoLoading, setVideoLoading] = useState(<>); + + useEffect(() => { + setButtonGroups(createButtonGroups(0, 50)); + }, []); + + const groups = createGroups(data.episodes, 50); + + function createButtonGroups(start, end) { + setButtonGroups(<>); + return ( +
+ {data.episodes && + data.episodes.slice(start, end).map((item, index) => ( + + ))} +
+ ); + } + + function handleSelectChange(item) { + // console.log(item[item.length - 1].number); + const start_index = item[0].number; + const end_index = item[item.length - 1].number; + setButtonGroups(createButtonGroups(start_index - 1, end_index)); + } + + async function changeVideoLink(id) { + setVideoLink(""); + setVideoLoading( +
+
+ +
+
+ ); + const videoURL = await video_url(id); + setVideoLoading(<>); + setVideoLink(videoURL.sources[videoURL.sources.length - 2].url); + } + + return ( +
+ {videoLoading} + {videoLink && ( +
+ + + + +
+ )} + {data.episodes && ( +
+ +
+ )} + {buttonGroups} +
+ ); +}; + +function createGroups(array, size) { + const groups = []; + for (let i = 0; i < array.length; i += size) { + groups.push(array.slice(i, i + size)); + } + return groups; +} + +export default EpisodesContainer; diff --git a/src/app/anime/continueWatching/page.jsx b/src/app/anime/continueWatching/page.jsx index eb28a2f..69d06de 100644 --- a/src/app/anime/continueWatching/page.jsx +++ b/src/app/anime/continueWatching/page.jsx @@ -2,7 +2,6 @@ import React, { useState, useEffect } from "react"; import Image from "next/image"; -import styles from "../styles/cw.module.css"; import Link from "next/link"; const ContinueWatching = () => { diff --git a/src/app/anime/loading.jsx b/src/app/anime/loading.jsx deleted file mode 100644 index 00ce39c..0000000 --- a/src/app/anime/loading.jsx +++ /dev/null @@ -1,11 +0,0 @@ -import styles from "./styles/loading.module.css"; - -const Loading = async () => { - return ( -
- Loading... -
- ); -}; - -export default Loading; diff --git a/src/app/anime/page.jsx b/src/app/anime/page.jsx index 7143740..a2d5777 100644 --- a/src/app/anime/page.jsx +++ b/src/app/anime/page.jsx @@ -1,18 +1,101 @@ -import styles from "./styles/anime.module.css"; -import PopularAnimes from "./components/popularAnimes"; -import RecentAnimes from "./components/recentEpisodes"; -import TopAiringAnimes from "./components/topAiring"; -import SearcBar from "./components/search"; +import { Card, CardHeader, CardBody, Image, Link } from "@nextui-org/react"; +import NextImage from "next/image"; +import styles from "../page.module.css"; + +import { top_airing, recent, popular } from "./data-fetch/request"; +import SearchBar from "./components/search"; +import { preFetchAnimeInfo } from "./components/cacher"; + const AnimeHomepage = async () => { + const popular_data = await popular(); + const recent_data = await recent(); + const airing_data = await top_airing(); + + const dataToBeLoaded = [popular_data, recent_data, airing_data]; + + for (let item of dataToBeLoaded) { + preFetchAnimeInfo(item); + } + + const header = (title) => ( + <> +

+ {title} +

+ + ); + + const format = (data) => ( + <> + {data && + data.results.map((item, index) => ( + + + + Anime Poster + + +

+ {item.title} +

+
+
+ + ))} + + ); + return ( -
- - +
+
+ +
+ +
+ {header("Popular Animes")} +
+ {format(popular_data)} +
+
+ +
+ {header("Recent Animes")} +
+ {format(recent_data)} +
+
+
+ {header("Top Airing Animes")} +
+ {format(airing_data)} +
+

-
- -
+
); }; diff --git a/src/app/anime/styles/anime.module.css b/src/app/anime/styles/anime.module.css deleted file mode 100644 index e5d402a..0000000 --- a/src/app/anime/styles/anime.module.css +++ /dev/null @@ -1,4 +0,0 @@ -.Main { - max-width: 99%; - margin: 65px auto; -} \ No newline at end of file diff --git a/src/app/anime/styles/buttons.module.css b/src/app/anime/styles/buttons.module.css deleted file mode 100644 index d0b8e78..0000000 --- a/src/app/anime/styles/buttons.module.css +++ /dev/null @@ -1,98 +0,0 @@ -.animeButtonContainer { - margin-top: 1rem; -} - -.dramaButton { - background-color: #1f1f1fd2; - outline: none; - border: none; - color: white; - font-family: "Atkinson Hyperlegible", serif; - width: 50px; - padding: 0.5rem; - margin: 0 0.2rem 0.2rem 0; - border-radius: 0.5rem; - cursor: pointer; - transition: background-color 200ms ease, scale 200ms ease; -} - -.dramaButton:hover { - background-color: #121212; - scale: 0.95; -} - -.dramaButton:focus { - background-color: var(--soft-purple); - scale: 0.95; -} - -.Main { - display: flex; - align-items: center; - flex-direction: column; - text-align: center; -} - -.SelectClass { - text-align: center; - outline: none; - border: none; - padding: 0.4rem; - font-family: "Lexend Deca", serif; - background-color: #1f1f1fd2; - color: white; - border-radius: 0.5rem; -} - -.SelectClass::-webkit-scrollbar { - width: 0; -} - -/* Video Player */ - -.videoPopUp { - height: 100dvh; - width: 100dvw; - background-color: #141414ee; - position: fixed; - bottom: 0; - left: 0; - right: 0; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - z-index: 1; - overflow-y: auto; -} - -.closeButton { - font-family: "Lexend Deca", serif; - font-size: 16px; - background-color: var(--pastel-red); - padding: 0.5rem 1.5rem; - border: 0; - outline: 0; - border-radius: 0.5rem; - cursor: pointer; - margin: 5px; -} - -.video { - width: 60vw; -} - -.VideoPlayer { - width: 100%; -} - -@media screen and (max-width: 1024px) { - - .dramaButton { - font-size: 14px; - } - - .video { - width: 100%; - } -} \ No newline at end of file diff --git a/src/app/anime/styles/cw.module.css b/src/app/anime/styles/cw.module.css deleted file mode 100644 index cb579c7..0000000 --- a/src/app/anime/styles/cw.module.css +++ /dev/null @@ -1,59 +0,0 @@ -.main { - width: 99%; - margin: 60px auto; -} - -.mainText { - color: white; - font-size: 24px; - margin: 0.2rem 0 0.2rem 0; -} - -.animeContainer { - font-size: 18px; - margin: 0px; -} - -.animeEntry { - display: flex; - align-items: center; - justify-content: space-between; - padding: 5px; - margin-bottom: 0.5rem; - border-radius: 0.4rem; - background-color: #1f1f1f; -} - -.animeEntry img { - border-radius: 0.4rem; - margin-left: 0.2rem; -} - -.titleContainer { - color: white; - margin-left: 0.2rem; -} - -.titleContainer h3 { - margin: 0px; -} - -.EpisodeCount { - color: var(--soft-purple); - margin: 0px; -} - -.date { - color: var(--neon-yellow); - margin: 0px; -} - -@media screen and (max-width: 768px) { - .animeContainer { - font-size: 14px; - } - - .animeEntry img { - width: 35%; - } -} \ No newline at end of file diff --git a/src/app/anime/styles/info.module.css b/src/app/anime/styles/info.module.css deleted file mode 100644 index afdc08f..0000000 --- a/src/app/anime/styles/info.module.css +++ /dev/null @@ -1,69 +0,0 @@ -.main { - width: 50%; - margin: 60px auto; - color: white; -} - -.AnimeHeroSection { - display: flex; - align-items: center; -} - -.AnimeHeroSection strong { - color: #38bdf8; -} - -.AnimeHeroSection img { - /* width: auto; - height: auto; */ - padding: 0.5rem 0.7rem 0.5rem 0.7rem; -} - -.animeDescription { - max-height: 100px; - overflow: auto; -} - -.animeDescription::-webkit-scrollbar { - width: 0px; -} - -.AnimeHeroSection p { - margin: 0; - color: #a3a3a3; -} - -.animeTitle { - font-size: 26px; - text-transform: uppercase; -} - -@media screen and (max-width: 1024px) { - .main { - width: 100%; - } - - .AnimeHeroSection { - font-size: 14px; - } - - .animeTitle { - font-size: 24px; - } - - .AnimeHeroSection img { - padding: 0.4rem 0.4rem 0.4rem 0.4rem; - } -} - -@media screen and (max-width: 425px) { - .AnimeHeroSection { - display: flex; - align-items: center; - flex-direction: column; - } - - .animeTitle { - text-align: center; - } -} \ No newline at end of file diff --git a/src/app/anime/styles/loading.module.css b/src/app/anime/styles/loading.module.css deleted file mode 100644 index f0d0606..0000000 --- a/src/app/anime/styles/loading.module.css +++ /dev/null @@ -1,12 +0,0 @@ -.LoadingContainer { - height: 100vh; - width: 100vw; - display: flex; - align-items: center; - justify-content: center; -} - -.LoadingContainer strong { - color: white; - font-size: 20px; -} \ No newline at end of file diff --git a/src/app/anime/styles/pop_recent_top.module.css b/src/app/anime/styles/pop_recent_top.module.css deleted file mode 100644 index 253f60f..0000000 --- a/src/app/anime/styles/pop_recent_top.module.css +++ /dev/null @@ -1,95 +0,0 @@ -.AnimeHeaderText { - color: white; - margin: 0.4rem 0 0 0; - text-transform: uppercase; - font-size: 30px; -} - -.AnimeContainer { - margin: 0.2rem 0 0 0; - display: grid; - grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); - grid-gap: 0.5rem; -} - -/* .AnimeEntry { - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; - text-align: center; - padding: 0.8rem; - border-radius: 0.4rem; - background-color: #1a1a1a; - transition: opacity 200ms ease; -} */ - -.AnimeEntry { - position: relative; - display: inline-block; - overflow: hidden; - border-radius: 0.5rem; - transition: opacity 200ms ease; - -} - -.AnimeContainer:hover .AnimeEntry { - opacity: 0.5; -} - -.AnimeContainer:hover .AnimeEntry:hover { - opacity: 1; -} - -.AnimeEntry img { - display: block; - transition: transform 200ms ease; -} - -.AnimeEntry img:hover { - transform: translateY(-5px) scale(1.04); -} - - -.AnimeTitle { - position: absolute; - bottom: 0; - /* Adjust the value as needed */ - left: 50%; - transform: translateX(-50%); - margin: 0; - color: white; - padding: 5px; - text-align: center; - background-color: #121212ab; - backdrop-filter: blur(10px); - text-transform: uppercase; - width: 100%; - max-width: 170px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.AnimeReleasedEpisode { - position: absolute; - top: 0; - margin: 0.2rem; - padding: 0.5rem; - background-color: #121212b2; - border-radius: 0.4rem; - backdrop-filter: blur(10px); -} - -.AnimeContainer::-webkit-scrollbar { - height: 0rem; -} - - -@media screen and (max-width: 768px) { - .AnimeContainer { - display: flex; - overflow: auto; - align-items: center; - } -} \ No newline at end of file diff --git a/src/app/anime/styles/search.module.css b/src/app/anime/styles/search.module.css deleted file mode 100644 index abed86c..0000000 --- a/src/app/anime/styles/search.module.css +++ /dev/null @@ -1,116 +0,0 @@ -.SearchBarContainer { - padding: 1rem 0 0.8rem 0; - display: flex; - align-items: center; - width: 100%; -} - -.SearchInputContainer { - display: flex; - align-items: center; - background-color: #1f1f1f; - padding: 0.4rem; - border-radius: 0.5rem; - width: 40%; -} - -.animeHistoryButton { - font-family: "Lexend Deca", serif; - outline: none; - border: none; - background-color: #121212; - color: white; - margin: 0 0.1rem 0 0.2rem; - padding: 0.6rem; - cursor: pointer; - border-radius: 0.5rem; -} - -.SearchInputContainer input { - background-color: transparent; - border: none; - outline: none; - color: white; - margin-left: 0.5rem; - font-size: 20px; - font-family: "Atkinson Hyperlegible", serif; - width: 100%; -} - -.SearchLoading { - color: white; - text-align: center; -} - -/* Search Results */ - -.SearchResultsContainer { - display: flex; - align-items: center; - overflow-x: auto; - padding-bottom: 0.5rem; -} - -.AnimeEntry { - position: relative; - display: inline-block; - overflow: hidden; - border-radius: 0.5rem; - transition: opacity 200ms ease; - margin: 0.4rem; -} - -.SearchResultsContainer:hover .AnimeEntry { - opacity: 0.5; -} - -.SearchResultsContainer:hover .AnimeEntry:hover { - opacity: 1; -} - -.AnimeEntry p { - position: absolute; - bottom: 0; - /* Adjust the value as needed */ - left: 50%; - transform: translateX(-50%); - margin: 0; - color: white; - padding: 5px; - text-align: center; - background-color: #121212ab; - backdrop-filter: blur(10px); - text-transform: uppercase; - width: 100%; - max-width: 170px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.AnimeEntry img { - display: block; - transition: transform 200ms ease; -} - -.AnimeEntry img:hover { - transform: translateY(-5px) scale(1.04); -} - - -.SearchResultsContainer::-webkit-scrollbar { - height: 0.5rem; -} - -.SearchResultsContainer::-webkit-scrollbar-thumb { - background: rgb(83, 83, 83); - border-radius: 1rem; -} - -@media screen and (max-width: 768px) { - .SearchInputContainer { - width: 100%; - } - - -} \ No newline at end of file diff --git a/src/app/components/header/header.jsx b/src/app/components/header/header.jsx index 9e5fc69..3c7db2e 100644 --- a/src/app/components/header/header.jsx +++ b/src/app/components/header/header.jsx @@ -1,26 +1,43 @@ import Link from "next/link"; import styles from "../../page.module.css"; +import { ThemeSwitcher } from "../themeSwitcher"; export default async function Header() { return ( -
-
-
- -

Dramalama

- -
-
- Anime - Kdrama - Manga - Movies - Series -
+
+

+ Dramalama +

+
+ + + +

Anime

+ + +

Kdrama

+ + +

Manga

+ + +

Series

+ + +

Movies

+
-
+ ); } diff --git a/src/app/components/moonIcon.jsx b/src/app/components/moonIcon.jsx new file mode 100644 index 0000000..6f20a38 --- /dev/null +++ b/src/app/components/moonIcon.jsx @@ -0,0 +1,17 @@ +import React from "react"; +export const MoonIcon = (props) => ( + +); diff --git a/src/app/components/sunIcon.jsx b/src/app/components/sunIcon.jsx new file mode 100644 index 0000000..cc47cfa --- /dev/null +++ b/src/app/components/sunIcon.jsx @@ -0,0 +1,17 @@ +import React from "react"; +export const SunIcon = (props) => ( + +); diff --git a/src/app/components/themeSwitcher.jsx b/src/app/components/themeSwitcher.jsx new file mode 100644 index 0000000..995dbbf --- /dev/null +++ b/src/app/components/themeSwitcher.jsx @@ -0,0 +1,43 @@ +// app/components/ThemeSwitcher.tsx +"use client"; + +import { useTheme } from "next-themes"; +import { useEffect, useState } from "react"; + +import React from "react"; +import { Switch } from "@nextui-org/react"; +import { SunIcon } from "./sunIcon"; +import { MoonIcon } from "./moonIcon"; + +export function ThemeSwitcher() { + const [mounted, setMounted] = useState(false); + const { theme, setTheme } = useTheme(); + + useEffect(() => { + setMounted(true); + }, []); + + if (!mounted) return null; + + return ( + + isSelected ? ( + + ) : ( + + ) + } + onClick={() => { + if (theme === "light") { + setTheme("dark"); + } else { + setTheme("light"); + } + }} + > + ); +} diff --git a/src/app/components/workInProgress/page.jsx b/src/app/components/workInProgress/page.jsx new file mode 100644 index 0000000..0af0a98 --- /dev/null +++ b/src/app/components/workInProgress/page.jsx @@ -0,0 +1,12 @@ +const WorkInProgress = async () => { + return ( +
+

+ This section is undergoing a complete overhaul. Sorry for the + inconvenience. +

+
+ ); +}; + +export default WorkInProgress; diff --git a/src/app/error.jsx b/src/app/error.jsx index 7549925..348050b 100644 --- a/src/app/error.jsx +++ b/src/app/error.jsx @@ -1,7 +1,7 @@ "use client"; // Error components must be Client Components import { useEffect } from "react"; -import styles from "./globals.module.css"; +import { Button } from "@nextui-org/react"; export default function Error({ error, reset }) { useEffect(() => { @@ -9,16 +9,11 @@ export default function Error({ error, reset }) { }, [error]); return ( -
+

Something went wrong!

- +
); } diff --git a/src/app/globals.css b/src/app/globals.css index bcf2a8b..c414701 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,3 +1,7 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + @import url("https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible:ital,wght@0,400;0,700;1,400;1,700&family=Lexend+Deca&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"); :root { @@ -23,12 +27,6 @@ --light-sky: #CAF4FF; } -body { - margin: 0; - padding: 0; - background-color: #121212; -} - body::-webkit-scrollbar { width: 0; } \ No newline at end of file diff --git a/src/app/kdrama/[id]/buttons.jsx b/src/app/kdrama/[id]/buttons.jsx deleted file mode 100644 index 66292e7..0000000 --- a/src/app/kdrama/[id]/buttons.jsx +++ /dev/null @@ -1,86 +0,0 @@ -"use client"; -import styles from "../styles/info.module.css"; -import getVideoLink from "../components/videoLink"; -import React, { useState } from "react"; -import { MediaPlayer, MediaProvider } from "@vidstack/react"; -import "@vidstack/react/player/styles/default/theme.css"; -import "@vidstack/react/player/styles/default/layouts/video.css"; -import { - defaultLayoutIcons, - DefaultVideoLayout, -} from "@vidstack/react/player/layouts/default"; - -export default function EpisodesButtons({ data: episodeData, id: dramaId }) { - const [videoLink, setVideoLink] = useState(null); - - async function test(a, b) { - let link = await getVideoLink(a, b); - setVideoLink(link); - } - - return ( -
-
-

Episodes

-
- {episodeData && episodeData.length > 0 ? ( - episodeData.map((item, index) => ( - - )) - ) : ( -

- No episodes are available at the moment but they - will be made available soon. Thank you for your - patience. -

- )} -
-
- - {videoLink && ( - - )} -
- ); -} diff --git a/src/app/kdrama/[id]/page.jsx b/src/app/kdrama/[id]/page.jsx index 9cb3cd8..d94810e 100644 --- a/src/app/kdrama/[id]/page.jsx +++ b/src/app/kdrama/[id]/page.jsx @@ -1,66 +1,46 @@ -import styles from "../styles/info.module.css"; -import Image from "next/image"; -import EpisodesButtons from "./buttons"; -import { PreFetchVideoLinks } from "../components/cacher"; +import { Chip, Image } from "@nextui-org/react"; +import DescriptionTabs from "../components/infoTabs"; +import { dramaInfo } from "../components/requests"; +import EpisodesContainer from "../components/episodesContainer"; export default async function DramaInfo({ params }) { const id = decodeURIComponent(params.id); - const info = await getDramaInfo(id); - - PreFetchVideoLinks(info.episodes, id); + const data = await dramaInfo(id); return ( -
- {info && ( -
-
-

{info.title}

- Drama Poster -
- - {/* Drama description */} -
-

Description

-

{info.description}

-
- - {/* Genres */} -
- Genres: - {info.genres && - info.genres.map((item, index) => ( -

{item}

- ))} -
- - {/* Other names */} -
- AKA: - {info.otherNames && - info.otherNames.map((item, index) => ( -

{item}

+
+
+ Anime Title Poster +
+

+ {data.title} +

+
+ {data.genres && + data.genres.map((item, index) => ( + +

{item}

+
))}
- - {/* Episodes Buttons */} -
- )} -
- ); -} - -async function getDramaInfo(id) { - const res = await fetch( - `https://consumet-jade.vercel.app/movies/dramacool/info?id=${id}`, - { next: { revalidate: 21600 } } +
+ + +
+
+
+ ); - const data = await res.json(); - return data; } diff --git a/src/app/kdrama/components/cacher.js b/src/app/kdrama/components/cacher.js index 860cdca..fdfa272 100644 --- a/src/app/kdrama/components/cacher.js +++ b/src/app/kdrama/components/cacher.js @@ -1,21 +1,6 @@ -// This function pre-fetches all the video links for a drama in the background "use server"; -export async function PreFetchVideoLinks(data, dramaId) { - try { - const fetchPromises = data.map(async (element) => { - const link = `https://consumet-jade.vercel.app/movies/dramacool/watch?episodeId=${element.id}&mediaId=${dramaId}`; - await fetch(link, { cache: "force-cache" }); - }); - - await Promise.all(fetchPromises); - console.log("Video links pre-fetched successfully!"); - } catch (error) { - console.error("Error occurred while pre-fetching video links:", error); - } -} - -export async function PreFetchAnimeInfo(data) { +export async function PreFetchKdramaInfo(data) { try { const fetchPromises = data.results.map(async (element) => { const link = `https://consumet-jade.vercel.app/movies/dramacool/info?id=${element.id}`; diff --git a/src/app/kdrama/components/episodesContainer.jsx b/src/app/kdrama/components/episodesContainer.jsx new file mode 100644 index 0000000..984ece5 --- /dev/null +++ b/src/app/kdrama/components/episodesContainer.jsx @@ -0,0 +1,83 @@ +"use client"; + +import { MediaPlayer, MediaProvider } from "@vidstack/react"; +import "@vidstack/react/player/styles/default/theme.css"; +import "@vidstack/react/player/styles/default/layouts/video.css"; +import { + defaultLayoutIcons, + DefaultVideoLayout, +} from "@vidstack/react/player/layouts/default"; +import { Select, SelectItem, Button, Skeleton } from "@nextui-org/react"; +import { useState, useEffect } from "react"; + +import { lexend } from "../../../../config/fonts"; +import { videoLink } from "./requests"; + +const EpisodesContainer = ({ data: data }) => { + const [videolink, setVideoLink] = useState(""); + const [loading, setLoading] = useState(<>); + + async function handleSelectChange(episodeId) { + setVideoLink(""); + setLoading( +
+
+ +
+
+ ); + const videoURL = await videoLink(episodeId, data.id); + setLoading(<>); + setVideoLink(videoURL); + } + + return ( +
+
+ +
+ + {loading} + {videolink && ( +
+ + + + +
+ )} +
+ ); +}; + +export default EpisodesContainer; diff --git a/src/app/kdrama/components/infoTabs.jsx b/src/app/kdrama/components/infoTabs.jsx new file mode 100644 index 0000000..54c05ba --- /dev/null +++ b/src/app/kdrama/components/infoTabs.jsx @@ -0,0 +1,51 @@ +"use client"; + +import { Tabs, Tab, Card, CardBody } from "@nextui-org/react"; + +import { lexend, atkinson } from "../../../../config/fonts"; + +export default function DescriptionTabs({ data: data }) { + return ( +
+ + + + + {data.description || "No description found"} + + + + + + +

+ Episodes:{" "} + {data.episodes.length} +

+

+ Duration:{" "} + {data.duration || "not found"} +

+

+ Release Year:{" "} + {data.releaseDate} +

+

+ Other Names:{" "} + {data.otherNames && + data.otherNames.map((item, index) => ( + + {item} + {index < + data.otherNames.length - 1 && + ", "} + + ))} +

+
+
+
+
+
+ ); +} diff --git a/src/app/kdrama/components/popular.jsx b/src/app/kdrama/components/popular.jsx deleted file mode 100644 index 21d8cc3..0000000 --- a/src/app/kdrama/components/popular.jsx +++ /dev/null @@ -1,47 +0,0 @@ -import styles from "../styles/popular.module.css"; -import Image from "next/image"; -import Link from "next/link"; -import { PreFetchAnimeInfo } from "./cacher"; - -export default async function PopularDramas() { - const popular = await getPopular(); - PreFetchAnimeInfo(popular); - - return ( -
-

Trending Dramas

- -
- {popular && - popular.results.slice(0, 24).map((item, index) => ( - -
- Drama Poster -

{item.title}

-
- - ))} -
-
- ); -} - -async function getPopular() { - const res = await fetch("https://dramacool-scraper.vercel.app/popular", { - next: { revalidate: 21600 }, - }); - const data = await res.json(); - return data; -} diff --git a/src/app/kdrama/components/recent.jsx b/src/app/kdrama/components/recent.jsx deleted file mode 100644 index 2b883d6..0000000 --- a/src/app/kdrama/components/recent.jsx +++ /dev/null @@ -1,46 +0,0 @@ -import styles from "../styles/popular.module.css"; -import Image from "next/image"; -import Link from "next/link"; -import { PreFetchAnimeInfo } from "./cacher"; - -export default async function RecentDramas() { - const popular = await getPopular(); - PreFetchAnimeInfo(popular); - return ( -
-

Recent Releases

- -
- {popular && - popular.results.slice(0, 24).map((item, index) => ( - -
- Drama Poster -

{item.title}

-
- - ))} -
-
- ); -} - -async function getPopular() { - const res = await fetch("https://dramacool-scraper.vercel.app/recent", { - next: { revalidate: 21600 }, - }); - const data = await res.json(); - return data; -} diff --git a/src/app/kdrama/components/requests.js b/src/app/kdrama/components/requests.js new file mode 100644 index 0000000..5609d79 --- /dev/null +++ b/src/app/kdrama/components/requests.js @@ -0,0 +1,44 @@ +"use server"; + +import { + popular_dramas_url, + recent_drama_url, + search_drama_url, + drama_info_url, + videoURL, +} from "../../../../utils/kdrama_urls"; + +export const DramaDataFetcher = async (type) => { + const options = { + popular: popular_dramas_url, + recent: recent_drama_url, + }; + const res = await fetch(options[type], { next: { revalidate: 21600 } }); + const data = await res.json(); + return data; +}; + +export const SearchedDramaData = async (title) => { + const res = await fetch(search_drama_url(title), { + next: { revalidate: 21600 }, + }); + const data = await res.json(); + return data; +}; + +export const dramaInfo = async (id) => { + const res = await fetch(drama_info_url(id), { + next: { revalidate: 21600 }, + }); + const data = await res.json(); + return data; +}; + +export const videoLink = async (epiId, mediaId) => { + const res = await fetch(videoURL(epiId, mediaId), { + next: { revalidate: 21600 }, + }); + const data = await res.json(); + const videoLink = data.sources[0].url; + return videoLink; +}; diff --git a/src/app/kdrama/components/search.jsx b/src/app/kdrama/components/search.jsx deleted file mode 100644 index f44e4bb..0000000 --- a/src/app/kdrama/components/search.jsx +++ /dev/null @@ -1,65 +0,0 @@ -"use client"; - -import styles from "../styles/search.module.css"; -import { useState } from "react"; -import { FaSearch } from "react-icons/fa"; -import FetchSearchTitle from "./searchQuery"; -import Image from "next/image"; -import Link from "next/link"; -import { PreFetchAnimeInfo } from "./cacher"; - -export default function DramaSearch() { - const [title, setTitle] = useState(""); - const [infoTitle, setInfoTitle] = useState(null); - const [loadingText, setLoadingText] = useState(null); - - const handleSearch = async (title) => { - setLoadingText(true); - const data = await FetchSearchTitle(title); - PreFetchAnimeInfo(data); - setLoadingText(false); - setInfoTitle(data); - }; - - return ( -
-
- - setTitle(event.target.value)} - onKeyDown={async (e) => { - if ((e.key === "Enter" || e.code === 13) && title) { - await handleSearch(e.target.value); - } - }} - > -
- - {loadingText && ( -

Wait a moment...

- )} - -
- {infoTitle && - infoTitle.results.map((item, index) => ( - -
-

{item.title}

- Drama Poster -
- - ))} -
-
- ); -} diff --git a/src/app/kdrama/components/searchBar.jsx b/src/app/kdrama/components/searchBar.jsx new file mode 100644 index 0000000..5f5d89e --- /dev/null +++ b/src/app/kdrama/components/searchBar.jsx @@ -0,0 +1,57 @@ +"use client"; + +import React from "react"; +import { useState } from "react"; +import { Input, Progress } from "@nextui-org/react"; + +import { SearchedDramaData } from "./requests"; +import SearchedDataFormatter from "./searchFormatter"; +import { PreFetchKdramaInfo } from "./cacher"; + +export const Searchbar = () => { + const [loading, setLoading] = useState(<>); + const [searchData, setSearchData] = useState(null); + const [searchTitle, setSearchTitle] = useState(""); + + async function handleSearchInput() { + setSearchData(null); + setLoading( + + ); + const data = await SearchedDramaData(searchTitle); + PreFetchKdramaInfo(data); + const format = await SearchedDataFormatter(data); + setSearchData(format); + setLoading(<>); + } + + return ( +
+
+ { + if (event.target.value.trim() !== "") { + setSearchTitle(event.target.value); + } + }} + onKeyDown={async (event) => { + if (event.key === "Enter" || event.code === "Enter") { + await handleSearchInput(); + } + }} + /> + {loading} +
+
{searchData}
+
+ ); +}; diff --git a/src/app/kdrama/components/searchFormatter.jsx b/src/app/kdrama/components/searchFormatter.jsx new file mode 100644 index 0000000..bac2549 --- /dev/null +++ b/src/app/kdrama/components/searchFormatter.jsx @@ -0,0 +1,46 @@ +import { Card, CardHeader, CardBody, Image, Link } from "@nextui-org/react"; +import NextImage from "next/image"; + +import styles from "../../page.module.css"; + +const SearchedDataFormatter = async (data) => { + return ( +
+ {data && + data.results.length > 0 && + data.results.map((item, index) => ( + + + + Anime Poster + + +

+ {item.title} +

+
+
+ + ))} +
+ ); +}; + +export default SearchedDataFormatter; diff --git a/src/app/kdrama/components/searchQuery.js b/src/app/kdrama/components/searchQuery.js deleted file mode 100644 index 18c06a9..0000000 --- a/src/app/kdrama/components/searchQuery.js +++ /dev/null @@ -1,10 +0,0 @@ -"use server"; - -export default async function FetchSearchTitle(title) { - const res = await fetch( - `https://consumet-jade.vercel.app/movies/dramacool/${title}`, - { cache: "force-cache" } - ); - const data = await res.json(); - return data; -} diff --git a/src/app/kdrama/components/videoLink.js b/src/app/kdrama/components/videoLink.js deleted file mode 100644 index e49ca18..0000000 --- a/src/app/kdrama/components/videoLink.js +++ /dev/null @@ -1,11 +0,0 @@ -"use server"; -export default async function getVideoLink(epiId, mediaId) { - let videoLink; - const res = await fetch( - `https://consumet-jade.vercel.app/movies/dramacool/watch?episodeId=${epiId}&mediaId=${mediaId}`, - { cache: "force-cache" } - ); - const data = await res.json(); - videoLink = data.sources[0].url; - return videoLink; -} diff --git a/src/app/kdrama/loading.jsx b/src/app/kdrama/loading.jsx deleted file mode 100644 index 4d5e9bd..0000000 --- a/src/app/kdrama/loading.jsx +++ /dev/null @@ -1,9 +0,0 @@ -import styles from "./styles/loading.module.css"; - -export default async function Loading() { - return ( -
-
-
- ); -} diff --git a/src/app/kdrama/page.jsx b/src/app/kdrama/page.jsx index b9cdb69..d5e2855 100644 --- a/src/app/kdrama/page.jsx +++ b/src/app/kdrama/page.jsx @@ -1,15 +1,95 @@ -import styles from "./styles/kdrama.module.css"; -import PopularDramas from "./components/popular"; -import RecentDramas from "./components/recent"; -import DramaSearch from "./components/search"; +import { Card, CardHeader, CardBody, Image, Link } from "@nextui-org/react"; +import NextImage from "next/image"; + +import { DramaDataFetcher } from "./components/requests"; +import styles from "../page.module.css"; +import { Searchbar } from "./components/searchBar"; +import { PreFetchKdramaInfo } from "./components/cacher"; + +const KdramaHomepage = async () => { + const recent_data = await DramaDataFetcher("recent"); + const popular_data = await DramaDataFetcher("popular"); + + const dataToBeLoaded = [recent_data, popular_data]; + + for (let item of dataToBeLoaded) { + PreFetchKdramaInfo(item); + } + + const header = (title) => ( + <> +

+ {title} +

+ + ); + + const format = (data) => ( + <> + {data && + data.results.map((item, index) => ( + + + + Anime Poster + + +

+ {item.title} +

+
+
+ + ))} + + ); -export default async function Kdrama() { return ( -
- - -
- -
+
+
+ +
+
+ {header("Popular K-dramas")} +
+ {format(popular_data)} +
+
+
+ {header("Recent Releases")} +
+ {format(recent_data)} +
+
+ +
+
+
+
+
+
); -} +}; + +export default KdramaHomepage; diff --git a/src/app/kdrama/styles/info.module.css b/src/app/kdrama/styles/info.module.css deleted file mode 100644 index 3b60fd2..0000000 --- a/src/app/kdrama/styles/info.module.css +++ /dev/null @@ -1,173 +0,0 @@ -.Main { - max-width: 98%; - margin: 60px auto; -} - -.TitleContainer { - display: flex; - align-items: center; - justify-content: space-between; -} - -.TitleContainer p { - color: white; - font-size: 34px; - font-weight: 500; - color: var(--neon-green); - margin: 0; -} - -.TitleContainer img { - border-radius: 0.4rem; -} - -.DramaDescription h2 { - color: gray; -} - -.DramaDescription p { - color: white; - margin-top: -10px; - color: rgba(255, 255, 255, 0.637); -} - -.DramaGenre { - display: flex; - align-items: center; - overflow-x: auto; - color: white; - margin-top: 1rem; -} -.DramaGenre p { - background-color: #1f1f1f; - margin: 0rem 0rem 0rem 0.4rem; - padding: 0.4rem; - border-radius: 0.2rem; -} - -.DramaGenre::-webkit-scrollbar { - height: 2px; -} - -.DramaGenre::-webkit-scrollbar-thumb { - background-color: var(--light-green); - border-radius: 1rem; -} - -.genreMain { - color: var(--neon-green); - font-size: 18px; -} - -.EpisodesContainer { - margin-top: -10px; -} - -.EpisodesContainer h2 { - color: gray; -} - -.EpisodeButtons { - margin: -10px 5px; -} - -.EpisodeButtons button { - margin: 3px; - padding: 5px; - border: none; - outline: none; - border-radius: 5px; - background-color: #3d3d3d; - transition: background-color 0.2s linear; - color: white; - cursor: pointer; - width: 100px; -} - -.EpisodeButtons button p { - text-align: center; - font-family: "Lexend Deca", serif; - margin: 0; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -.EpisodeButtons button:hover { - background-color: #1f1f1f; - transition: background-color 0.2s linear; -} - -.videoPopUp { - height: 100dvh; - width: 100dvw; - background-color: #141414ea; - position: fixed; - bottom: 0; - left: 0; - right: 0; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - z-index: 1; - overflow-y: auto; -} - -.closeButton { - font-family: "Lexend Deca", serif; - font-size: 16px; - background-color: var(--pastel-red); - padding: 0.5rem 1.5rem; - border: 0; - outline: 0; - border-radius: 0.5rem; - cursor: pointer; - margin: 5px; -} - -.video { - width: 60vw; -} - -.VideoPlayer { - width: 100%; - height: auto; -} - -@media screen and (max-width: 768px) { - .video { - width: 100%; - } - - .EpisodeButtons button { - font-size: 14px; - width: 80px; - } - - .TitleContainer { - flex-direction: column; - } - - .TitleContainer img { - width: auto; - height: auto; - border-radius: 0.2rem; - background-color: #121212; - padding: 0.2rem; - } - - .TitleContainer p { - font-size: 30px; - font-weight: 400; - margin: 0 0 0.25rem 0 - } - - .EpisodesContainer { - text-align: center; - } - - .EpisodeButtons button { - width: 90px; - } -} diff --git a/src/app/kdrama/styles/kdrama.module.css b/src/app/kdrama/styles/kdrama.module.css deleted file mode 100644 index deb3860..0000000 --- a/src/app/kdrama/styles/kdrama.module.css +++ /dev/null @@ -1,4 +0,0 @@ -.Main { - margin: 80px auto; - width: 99%; -} diff --git a/src/app/kdrama/styles/loading.module.css b/src/app/kdrama/styles/loading.module.css deleted file mode 100644 index 825c247..0000000 --- a/src/app/kdrama/styles/loading.module.css +++ /dev/null @@ -1,21 +0,0 @@ -.Main { - height: 100dvh; - display: flex; - justify-content: center; - align-items: center; -} - -.LoadingContainer { - width: 50px; - height: 50px; - border-radius: 50%; - border: 8px solid; - border-color: #f4f4f4 #0000; - animation: s1 1s infinite; -} - -@keyframes s1 { - to { - transform: rotate(0.5turn); - } -} diff --git a/src/app/kdrama/styles/popular.module.css b/src/app/kdrama/styles/popular.module.css deleted file mode 100644 index ec76fb3..0000000 --- a/src/app/kdrama/styles/popular.module.css +++ /dev/null @@ -1,73 +0,0 @@ -.popDramasText { - color: white; - margin: 0 0 0.2rem 0; -} - -.AnimeContainer { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - grid-gap: 0.7rem; - align-items: center; -} - -.AnimeContainer::-webkit-scrollbar { - height: 0px; -} - -.AnimeContainer:hover .AnimeEntry { - opacity: 0.5; -} - -.AnimeContainer:hover .AnimeEntry:hover { - opacity: 1; - transform: scale(1.018); - background-color: #272727; -} - -.AnimeEntry { - display: flex; - flex-direction: column; - align-items: center; - background-color: #1f1f1fbb; - padding: 0.5rem; - transition: opacity 200ms ease, transform 200ms ease, - background-color 200ms ease; - cursor: grab; - border-radius: 0.4rem; - overflow: hidden; -} - -.AnimeEntry img { - border-radius: 0.4rem; - box-shadow: 0 0 10px 5px rgba(18, 18, 18, 0.863); -} - -.AnimeEntry p { - text-align: center; - color: white; - width: auto; - max-width: 160px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - margin: 0.5rem 0rem 0rem 0rem; -} - -@media screen and (max-width: 768px) { - .popDramasText { - text-align: start; - font-size: 26px; - margin: 1rem 0 1rem 0; - } - - .AnimeContainer { - display: flex; - overflow-x: auto; - overflow-y: hidden; - margin-top: -8px; - } - - .AnimeEntry img { - width: auto; - } -} diff --git a/src/app/kdrama/styles/search.module.css b/src/app/kdrama/styles/search.module.css deleted file mode 100644 index d7d28b2..0000000 --- a/src/app/kdrama/styles/search.module.css +++ /dev/null @@ -1,84 +0,0 @@ - -.LoadingText { - color: white; - text-align: center; - font-size: 18px; -} - -.Search { - padding: 5px; - background-color: #121212; - display: flex; - align-items: center; - max-width: 30%; - border-radius: 0.5rem; -} - -.SearchContainer input { - margin-left: 5px; - padding: 5px; - border: none; - outline: none; - background-color: #121212; - font-size: 16px; - color: white; - width: 100%; - font-family: "Lexend Deca"; -} - -.SearchResults { - display: flex; - margin: 10px 0 10px 0; - overflow-x: auto; -} - -.SearchResults::-webkit-scrollbar { - height: 5px; -} - -.SearchResults::-webkit-scrollbar-track { - background-color: #3333339d; - border-radius: 5px; -} - -.SearchResults::-webkit-scrollbar-thumb { - background-color: rgb(68, 68, 68); - border-radius: 5px; -} - -.SearchEntry { - display: flex; - align-items: center; - justify-content: space-between; - margin: 5px; - padding: 6px; - background-color: #2e2e2eab; - border-radius: 0.5rem; - cursor: pointer; - transition: opacity 200ms linear, background-color 200ms linear; -} - -.SearchResults .SearchEntry { - opacity: 0.5; -} - -.SearchResults .SearchEntry:hover { - opacity: 1; - background-color: #333333c9; -} - -.SearchEntry p { - color: white; - font-size: 18px; - width: 45vh; -} - -.SearchEntry img { - border-radius: 0.5rem; -} - -@media screen and (max-width: 768px) { - .Search { - max-width: 100%; - } -} diff --git a/src/app/layout.jsx b/src/app/layout.jsx index f16ed98..9673001 100644 --- a/src/app/layout.jsx +++ b/src/app/layout.jsx @@ -1,11 +1,11 @@ -import { Lexend_Deca } from "next/font/google"; import "./globals.css"; import Header from "./components/header/header"; import Footer from "./components/footer/page"; import { SpeedInsights } from "@vercel/speed-insights/next"; import { Analytics } from "@vercel/analytics/react"; - -const lexend = Lexend_Deca({ subsets: ["latin"] }); +import { NextUIProvider } from "@nextui-org/react"; +import { ThemeProvider as NextThemesProvider } from "next-themes"; +import { lexend } from "../../config/fonts"; export const metadata = { title: "Dramalama", @@ -15,7 +15,21 @@ export const metadata = { applicationName: "Dramalama", authors: [{ name: "zephex", url: "https://github.com/real-zephex" }], creator: "Zephex", - keywords: ["Kdrama", "Anime", "Manga", "Watch Online"], + keywords: [ + "Kdrama", + "Anime", + "Manga", + "Watch Online", + "watch kdrama free", + "watch anime free online", + "kdrama for free", + "watch online", + "read mangas for free", + "mangas online", + "movies online", + "free movies online", + "watch series for free", + ], robots: { index: true, follow: true, @@ -45,9 +59,12 @@ export default function RootLayout({ children }) { -
- {children} -