From 9444f1162ff40842afe1c2a01cf0a32db19a6376 Mon Sep 17 00:00:00 2001 From: real-zephex Date: Sat, 13 Apr 2024 09:42:25 +0530 Subject: feature added: anime history is now stored locally on the device. --- src/app/anime/[id]/buttons.jsx | 26 ++++++++- .../anime/history/continueWatching/cw.module.css | 59 ++++++++++++++++++++ src/app/anime/history/continueWatching/page.jsx | 65 ++++++++++++++++++++++ src/app/anime/history/storeData.js | 26 +++++++++ src/app/anime/search/page.jsx | 6 ++ src/app/anime/search/search.module.css | 23 +++++++- src/app/layout.jsx | 1 - src/app/page.jsx | 1 + 8 files changed, 204 insertions(+), 3 deletions(-) create mode 100644 src/app/anime/history/continueWatching/cw.module.css create mode 100644 src/app/anime/history/continueWatching/page.jsx create mode 100644 src/app/anime/history/storeData.js (limited to 'src') diff --git a/src/app/anime/[id]/buttons.jsx b/src/app/anime/[id]/buttons.jsx index eac1884..dd49d6e 100644 --- a/src/app/anime/[id]/buttons.jsx +++ b/src/app/anime/[id]/buttons.jsx @@ -10,8 +10,10 @@ import { PlyrLayout, plyrLayoutIcons, } from "@vidstack/react/player/layouts/plyr"; +import { storeLocal } from "../history/storeData"; export default function Button({ data2: info }) { + const currentDate = new Date(); const [videoLink, setVideoLink] = useState(null); async function video(id) { @@ -20,10 +22,26 @@ export default function Button({ data2: info }) { alert("Sorry, but not links were found"); } else { setVideoLink(link); - console.log(videoLink); } } + function store_to_local(name, image, episode, id) { + 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); + } + return (

Episodes:

@@ -38,6 +56,12 @@ export default function Button({ data2: info }) { event.target.style.backgroundColor = "var(--soft-purple)"; video(item.id); + store_to_local( + info.title, + info.image, + item.number, + info.id + ); }} > {item.number} diff --git a/src/app/anime/history/continueWatching/cw.module.css b/src/app/anime/history/continueWatching/cw.module.css new file mode 100644 index 0000000..d8062ac --- /dev/null +++ b/src/app/anime/history/continueWatching/cw.module.css @@ -0,0 +1,59 @@ +.main { + width: 99%; + margin: 80px auto; +} + +.mainText { + color: var(--light-green); + font-family: "Poppins", serif; + font-size: 24px; +} + +.animeContainer { + font-family: "Poppins", serif; + font-size: 18px; + margin: 0px; +} + +.animeEntry { + display: flex; + align-items: center; + justify-content: space-between; + padding: 5px; + margin-bottom: 0.5rem; + border-radius: 1rem; + background-color: #1f1f1f; +} + +.animeEntry img { + width: auto; + height: auto; + max-height: 40dvh; + border-radius: 0.8rem; +} + +.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; + + } +} \ No newline at end of file diff --git a/src/app/anime/history/continueWatching/page.jsx b/src/app/anime/history/continueWatching/page.jsx new file mode 100644 index 0000000..cab834c --- /dev/null +++ b/src/app/anime/history/continueWatching/page.jsx @@ -0,0 +1,65 @@ +"use client"; + +import React, { useState, useEffect } from "react"; +import Image from "next/image"; +import styles from "./cw.module.css"; +import Link from "next/link"; + +const ContinueWatching = () => { + const [localItems, setLocalItems] = useState(null); + + useEffect(() => { + const newData = get_local(); + setLocalItems(newData); + }, []); // Empty dependency array means this effect runs only once after the initial render + + function get_local() { + try { + const data = localStorage.getItem("data"); + return JSON.parse(data); + } catch (error) { + console.log("error", error); + return false; + } + } + + return ( +
+

Continue Watching

+ {localItems && ( +
+ {localItems.watchHis && + localItems.watchHis.map((item, index) => ( + +
+
+

{item.name}

+

+ Episode watching: {item.episode} +

+

+ Last watched on: {item.date} at{" "} + {item.time} +

+
+ Continue anime poster +
+ + ))} +
+ )} +
+ ); +}; + +export default ContinueWatching; diff --git a/src/app/anime/history/storeData.js b/src/app/anime/history/storeData.js new file mode 100644 index 0000000..ae5f9d4 --- /dev/null +++ b/src/app/anime/history/storeData.js @@ -0,0 +1,26 @@ +"use client"; + +export function storeLocal(watchData) { + const jsonData = localStorage.getItem("data"); + const dataObject = jsonData ? JSON.parse(jsonData) : {}; + + if (!dataObject.watchHis) { + dataObject.watchHis = []; + } + + let found = false; + dataObject.watchHis.forEach((element) => { + if (element.name === watchData.name) { + let episode = watchData.episode; + element.episode = episode; + found = true; + } + }); + + if (!found) { + dataObject.watchHis.push(watchData); + } + + let updatedData = JSON.stringify(dataObject); + localStorage.setItem("data", updatedData); +} diff --git a/src/app/anime/search/page.jsx b/src/app/anime/search/page.jsx index ce037cb..43b5cd7 100644 --- a/src/app/anime/search/page.jsx +++ b/src/app/anime/search/page.jsx @@ -5,6 +5,7 @@ import { FaSearch } from "react-icons/fa"; // Import the search icon from react- import { useState } from "react"; import Results from "./components/fetchInfo"; import fetchedInfo from "./components/fetchedInfo"; +import Link from "next/link"; export default function Input() { const [searchedAnime, setSearchedAnime] = useState(null); @@ -47,6 +48,11 @@ export default function Input() { className={styles.SearchInput} > + {loading && ( diff --git a/src/app/anime/search/search.module.css b/src/app/anime/search/search.module.css index feff8bc..e91133f 100644 --- a/src/app/anime/search/search.module.css +++ b/src/app/anime/search/search.module.css @@ -5,6 +5,27 @@ color: white; } +.inputContainer { + display: flex; + align-items: center; +} + +.inputContainer button { + margin: 5px; + background-color: #121212; + padding: 10px; + border-radius: 10px; + outline: none; + border: none; + color: white; + font-family: "Atkinson Hyperlegible"; +} + +.inputContainer button a { + text-decoration: none; + color: white; +} + .searchContainer input { border: none; border-radius: 5px; @@ -77,7 +98,7 @@ .anime p { color: white; width: 20dvw; - font-family: "Atkinson"; + font-family: "Atkinson Hyperlegible"; font-size: 18px; } diff --git a/src/app/layout.jsx b/src/app/layout.jsx index 6cb8c6a..a2fc5ae 100644 --- a/src/app/layout.jsx +++ b/src/app/layout.jsx @@ -1,5 +1,4 @@ import { Inter } from "next/font/google"; -import styles from "./globals.module.css"; import "./globals.css"; import Header from "./components/header/header"; import Footer from "./components/footer/page"; diff --git a/src/app/page.jsx b/src/app/page.jsx index fff492b..47f30b0 100644 --- a/src/app/page.jsx +++ b/src/app/page.jsx @@ -27,6 +27,7 @@ export default function Home() { +