From cfac59282da55f4791d6352f15887a15e9ff6ec5 Mon Sep 17 00:00:00 2001 From: Wolfboy248 <121288977+Wolfboy248@users.noreply.github.com> Date: Wed, 10 Jul 2024 21:51:25 +0200 Subject: Games page, maplist page (#153) Co-authored-by: Wolfboy248 <105884620+Wolfboy248@users.noreply.github.com> --- frontend/src/components/pages/maplist.js | 844 +++++++++++++++++++++++++++++++ 1 file changed, 844 insertions(+) create mode 100644 frontend/src/components/pages/maplist.js (limited to 'frontend/src/components/pages/maplist.js') diff --git a/frontend/src/components/pages/maplist.js b/frontend/src/components/pages/maplist.js new file mode 100644 index 0000000..dca76d6 --- /dev/null +++ b/frontend/src/components/pages/maplist.js @@ -0,0 +1,844 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { useLocation, Link } from "react-router-dom"; +import { BrowserRouter as Router, Route, Routes, useNavigate } from 'react-router-dom'; + +import "./maplist.css" +import img5 from "../../imgs/5.png" +import img6 from "../../imgs/6.png" + +export default function Maplist(prop) { + const {token,setToken} = prop + const scrollRef = useRef(null) + const [games, setGames] = React.useState(null); + const location = useLocation(); + + let gameTitle; + let minPage; + let maxPage; + let currentPage; + let add = 0; + let gameState; + let catState = 0; + async function detectGame() { + const response = await fetch("https://lp.ardapektezol.com/api/v1/games", { + headers: { + 'Authorization': token + } + }); + + const data = await response.json(); + + const url = new URL(window.location.href) + + const params = new URLSearchParams(url.search) + gameState = parseFloat(params.get("game")) + + document.querySelector("#catPortalCount").innerText = data.data[gameState - 1].category_portals[0].portal_count; + + if (gameState == 1){ + gameTitle = data.data[0].name; + + maxPage = 9; + minPage = 1; + createCategories(1); + } else if (gameState == 2){ + gameTitle = data.data[1].name; + + maxPage = 16; + minPage = 10; + add = 10 + createCategories(2); + } + + let chapterParam = params.get("chapter") + + currentPage = minPage; + + if (chapterParam) { + currentPage = +chapterParam + add + } + + changePage(currentPage); + + // if (chapterParam) { + // document.querySelector("#pageNumbers").innerText = `${chapterParam - minPage + 1}/${maxPage - minPage + 1}` + // } + } + + function changeMaplistOrStatistics(index, name) { + const maplistBtns = document.querySelectorAll("#maplistBtn"); + maplistBtns.forEach((btn, i) => { + if (i == index) { + btn.className = "game-nav-btn selected" + + if (name == "maplist") { + document.querySelector(".stats").style.display = "none"; + document.querySelector(".maplist").style.display = "block"; + document.querySelector(".maplist").setAttribute("currentTab", "maplist"); + } else { + document.querySelector(".stats").style.display = "block"; + document.querySelector(".maplist").style.display = "none"; + + document.querySelector(".maplist-page").scrollTo({ top: 372, behavior: "smooth" }) + document.querySelector(".maplist").setAttribute("currentTab", "stats"); + } + } else { + btn.className = "game-nav-btn"; + } + }); + } + + async function createCategories(gameID) { + const response = await fetch("https://lp.ardapektezol.com/api/v1/games", { + headers: { + 'Authorization': token + } + }); + + const data = await response.json(); + let categoriesArr = data.data[gameID - 1].category_portals; + + const gameNav = document.querySelector(".game-nav"); + gameNav.innerHTML = ""; + categoriesArr.forEach((category) => { + createCategory(category); + }); + } + + let categoryNum = 0; + function createCategory(category) { + const gameNav = document.querySelector(".game-nav"); + + categoryNum++; + const gameNavBtn = document.createElement("button"); + if (categoryNum == 1) { + gameNavBtn.className = "game-nav-btn selected"; + } else { + gameNavBtn.className = "game-nav-btn"; + } + gameNavBtn.id = "catBtn" + gameNavBtn.innerText = category.category.name; + + gameNavBtn.addEventListener("click", (e) => { + changeCategory(category, e); + changePage(currentPage); + }) + + gameNav.appendChild(gameNavBtn); + } + + async function changeCategory(category, btn) { + const response = await fetch("https://lp.ardapektezol.com/api/v1/games", { + headers: { + 'Authorization': token + } + }); + + const data = await response.json(); + catState = category.category.id - 1; + console.log(catState) + const navBtns = document.querySelectorAll("#catBtn"); + navBtns.forEach((btns) => { + btns.classList.remove("selected"); + }); + + btn.srcElement.classList.add("selected"); + document.querySelector("#catPortalCount").innerText = category.portal_count; + } + + async function changePage(page) { + + const pageNumbers = document.querySelector("#pageNumbers"); + + pageNumbers.innerText = `${currentPage - minPage + 1}/${maxPage - minPage + 1}`; + + const maplistMaps = document.querySelector(".maplist-maps"); + maplistMaps.innerHTML = ""; + for (let index = 0; index < 8; index++) { + const loadingAnimation = document.createElement("div"); + loadingAnimation.classList.add("loader"); + loadingAnimation.classList.add("loader-map") + maplistMaps.appendChild(loadingAnimation); + } + const data = await fetchMaps(page); + const maps = data.data.maps; + const name = data.data.chapter.name; + + let chapterName = "Chapter"; + const chapterNumberOld = name.split(" - ")[0]; + let chapterNumber1 = chapterNumberOld.split("Chapter ")[1]; + if (chapterNumber1 == undefined) { + chapterName = "Course" + chapterNumber1 = chapterNumberOld.split("Course ")[1]; + } + const chapterNumber = chapterNumber1.toString().padStart(2, "0"); + const chapterTitle = name.split(" - ")[1]; + + const chapterNumberElement = document.querySelector(".chapter-num") + const chapterTitleElement = document.querySelector(".chapter-name") + chapterNumberElement.innerText = chapterName + " " + chapterNumber; + chapterTitleElement.innerText = chapterTitle; + + maplistMaps.innerHTML = ""; + maps.forEach(map => { + let portalCount; + if (map.category_portals[catState] != undefined) { + portalCount = map.category_portals[catState].portal_count; + } else { + portalCount = map.category_portals[0].portal_count; + } + addMap(map.name, portalCount, map.image, map.difficulty + 1, map.id); + }); + + const gameTitleElement = document.querySelector("#gameTitle"); + gameTitleElement.innerText = gameTitle; + + const url = new URL(window.location.href) + + const params = new URLSearchParams(url.search) + + let chapterParam = params.get("chapter") + + try { + const response = await fetch("https://lp.ardapektezol.com/api/v1/games", { + headers: { + 'Authorization': token + } + }); + + const data = await response.json(); + + const gameImg = document.querySelector(".game-img"); + + gameImg.style.backgroundImage = `url(${data.data[0].image})`; + + // const mapImg = document.querySelectorAll(".maplist-img"); + // mapImg.forEach((map) => { + // map.style.backgroundImage = `url(${data.data[0].image})`; + // }); + + } catch (error) { + console.log("error fetching games:", error); + } + + asignDifficulties(); + } + + async function addMap(mapName, mapPortalCount, mapImage, difficulty, mapID) { + // jesus christ + const maplistItem = document.createElement("div"); + const maplistTitle = document.createElement("span"); + const maplistImgDiv = document.createElement("div"); + const maplistImg = document.createElement("div"); + const maplistPortalcountDiv = document.createElement("div"); + const maplistPortalcount = document.createElement("span"); + const b = document.createElement("b"); + const maplistPortalcountPortals = document.createElement("span"); + const difficultyDiv = document.createElement("div"); + const difficultyLabel = document.createElement("span"); + const difficultyBar = document.createElement("div"); + const difficultyPoint1 = document.createElement("div"); + const difficultyPoint2 = document.createElement("div"); + const difficultyPoint3 = document.createElement("div"); + const difficultyPoint4 = document.createElement("div"); + const difficultyPoint5 = document.createElement("div"); + + maplistItem.className = "maplist-item"; + maplistTitle.className = "maplist-title"; + maplistImgDiv.className = "maplist-img-div"; + maplistImg.className = "maplist-img"; + maplistPortalcountDiv.className = "maplist-portalcount-div"; + maplistPortalcount.className = "maplist-portalcount"; + maplistPortalcountPortals.className = "maplist-portals"; + difficultyDiv.className = "difficulty-div"; + difficultyLabel.className = "difficulty-label"; + difficultyBar.className = "difficulty-bar"; + difficultyPoint1.className = "difficulty-point"; + difficultyPoint2.className = "difficulty-point"; + difficultyPoint3.className = "difficulty-point"; + difficultyPoint4.className = "difficulty-point"; + difficultyPoint5.className = "difficulty-point"; + + + maplistTitle.innerText = mapName; + difficultyLabel.innerText = "Difficulty: " + maplistPortalcountPortals.innerText = "portals" + b.innerText = mapPortalCount; + maplistImg.style.backgroundImage = `url(${mapImage})`; + difficultyBar.setAttribute("difficulty", difficulty) + maplistItem.setAttribute("id", mapID) + maplistItem.addEventListener("click", () => { + console.log(mapID) + window.location.href = "/maps/" + mapID + }) + + // appends + // maplist item + maplistItem.appendChild(maplistTitle); + maplistImgDiv.appendChild(maplistImg); + maplistImgDiv.appendChild(maplistPortalcountDiv); + maplistPortalcountDiv.appendChild(maplistPortalcount); + maplistPortalcount.appendChild(b); + maplistPortalcountDiv.appendChild(maplistPortalcountPortals); + maplistItem.appendChild(maplistImgDiv); + maplistItem.appendChild(difficultyDiv); + difficultyDiv.appendChild(difficultyLabel); + difficultyDiv.appendChild(difficultyBar); + difficultyBar.appendChild(difficultyPoint1); + difficultyBar.appendChild(difficultyPoint2); + difficultyBar.appendChild(difficultyPoint3); + difficultyBar.appendChild(difficultyPoint4); + difficultyBar.appendChild(difficultyPoint5); + + // display in place + const maplistMaps = document.querySelector(".maplist-maps"); + maplistMaps.appendChild(maplistItem); + } + + async function fetchMaps(chapterID) { + try{ + const response = await fetch(`https://lp.ardapektezol.com/api/v1/chapters/${chapterID}`, { + headers: { + 'Authorization': token + } + }); + + const data = await response.json(); + return data; + } catch (err) { + console.log(err) + } + } + + // difficulty stuff + function asignDifficulties() { + const difficulties = document.querySelectorAll(".difficulty-bar"); + difficulties.forEach((difficultyElement) => { + let difficulty = difficultyElement.getAttribute("difficulty"); + if (difficulty == "1") { + difficultyElement.childNodes[0].style.backgroundColor = "#51C355"; + } else if (difficulty == "2") { + difficultyElement.childNodes[0].style.backgroundColor = "#8AC93A"; + difficultyElement.childNodes[1].style.backgroundColor = "#8AC93A"; + } else if (difficulty == "3") { + difficultyElement.childNodes[0].style.backgroundColor = "#8AC93A"; + difficultyElement.childNodes[1].style.backgroundColor = "#8AC93A"; + difficultyElement.childNodes[2].style.backgroundColor = "#8AC93A"; + } else if (difficulty == "4") { + difficultyElement.childNodes[0].style.backgroundColor = "#C35F51"; + difficultyElement.childNodes[1].style.backgroundColor = "#C35F51"; + difficultyElement.childNodes[2].style.backgroundColor = "#C35F51"; + difficultyElement.childNodes[3].style.backgroundColor = "#C35F51"; + } else if (difficulty == "5") { + difficultyElement.childNodes[0].style.backgroundColor = "#C35F51"; + difficultyElement.childNodes[1].style.backgroundColor = "#C35F51"; + difficultyElement.childNodes[2].style.backgroundColor = "#C35F51"; + difficultyElement.childNodes[3].style.backgroundColor = "#C35F51"; + difficultyElement.childNodes[4].style.backgroundColor = "#C35F51"; + } + }); + } + + const divRef = useRef(null); + + React.useEffect(() => { + + const lineChart = document.querySelector(".line-chart") + function createGraph() { + // max + let items = [ + { + record: "100", + date: new Date(2011, 4, 4), + map: "Container Ride", + first: "tiny zach" + }, + { + record: "98", + date: new Date(2012, 6, 4), + map: "Container Ride", + first: "tiny zach" + }, + { + record: "94", + date: new Date(2013, 0, 1), + map: "Container Ride", + first: "tiny zach" + }, + { + record: "90", + date: new Date(2014, 0, 1), + map: "Container Ride", + first: "tiny zach" + }, + { + record: "88", + date: new Date(2015, 6, 14), + map: "Container Ride", + first: "tiny zach" + }, + { + record: "84", + date: new Date(2016, 8, 19), + map: "Container Ride", + first: "tiny zach" + }, + { + record: "82", + date: new Date(2017, 3, 20), + map: "Container Ride", + first: "tiny zach" + }, + { + record: "81", + date: new Date(2018, 2, 25), + map: "Container Ride", + first: "tiny zach" + }, + { + record: "80", + date: new Date(2019, 3, 4), + map: "Container Ride", + first: "tiny zach" + }, + { + record: "78", + date: new Date(2020, 11, 21), + map: "Container Ride", + first: "tiny zach" + }, + { + record: "77", + date: new Date(2021, 10, 25), + map: "Container Ride", + first: "tiny zach" + }, + { + record: "76", + date: new Date(2022, 4, 17), + map: "Container Ride", + first: "tiny zach" + }, + { + record: "75", + date: new Date(2023, 9, 31), + map: "Container Ride", + first: "tiny zach" + }, + { + record: "74", + date: new Date(2024, 4, 4), + map: "Container Ride", + first: "tiny zach" + }, + ] + + function calculatePosition(date, startDate, endDate, maxWidth) { + const totalMilliseconds = endDate - startDate + 10000000000; + const millisecondsFromStart = date - startDate + 5000000000; + return (millisecondsFromStart / totalMilliseconds) * maxWidth + } + + const minDate = items.reduce((min, dp) => dp.date < min ? dp.date : min, items[0].date) + const maxDate = items.reduce((max, dp) => dp.date > max ? dp.date : max, items[0].date) + + const graph_width = document.querySelector(".portalcount-over-time-div").clientWidth + // console.log(graph_width) + + const uniqueYears = new Set() + items.forEach(dp => uniqueYears.add(dp.date.getFullYear())) + let minYear = Infinity; + let maxYear = -Infinity; + + items.forEach(dp => { + const year = dp.date.getFullYear(); + minYear = Math.min(minYear, year); + maxYear = Math.max(maxYear, year); + }); + + // Add missing years to the set + for (let year = minYear; year <= maxYear; year++) { + uniqueYears.add(year); + } + const uniqueYearsArr = Array.from(uniqueYears) + + items = items.map(dp => ({ + record: dp.record, + date: dp.date, + x: calculatePosition(dp.date, minDate, maxDate, lineChart.clientWidth), + map: dp.map, + first: dp.first + })) + + const yearInterval = lineChart.clientWidth / uniqueYears.size + for (let index = 1; index < (uniqueYears.size); index++) { + const placeholderlmao = document.createElement("div") + const yearSpan = document.createElement("span") + yearSpan.style.position = "absolute" + placeholderlmao.style.height = "100%" + placeholderlmao.style.width = "2px" + placeholderlmao.style.backgroundColor = "#00000080" + placeholderlmao.style.position = `absolute` + const thing = calculatePosition(new Date(uniqueYearsArr[index], 0, 0), minDate, maxDate, lineChart.clientWidth) + placeholderlmao.style.left = `${thing}px` + yearSpan.style.left = `${thing}px` + yearSpan.style.bottom = "-34px" + yearSpan.innerText = uniqueYearsArr[index] + yearSpan.style.fontFamily = "BarlowSemiCondensed-Regular" + yearSpan.style.fontSize = "22px" + yearSpan.style.opacity = "0.8" + lineChart.appendChild(yearSpan) + + } + + let maxPortals; + let minPortals; + let precision; + let multiplier = 1; + for (let index = 0; index < items.length; index++) { + precision = Math.floor((items[0].record - items[items.length - 1].record)) + if (precision > 20) { + precision = 20 + } + minPortals = Math.floor((items[items.length - 1].record) / 10) * 10 + if (index == 0) { + maxPortals = items[index].record - minPortals + } + } + function calculateMultiplier(value) { + while (value > precision) { + multiplier += 1; + value -= precision; + } + } + calculateMultiplier(items[0].record); + // if (items[0].record > 10) { + // multiplier = 2; + // } + + // Original cubic bezier control points + const P0 = { x: 0, y: 0 }; + const P1 = { x: 0.26, y: 1 }; + const P2 = { x: 0.74, y: 1 }; + const P3 = { x: 1, y: 0 }; + + function calculateIntermediateControlPoints(t, P0, P1, P2, P3) { + const x = (1 - t) ** 3 * P0.x + + 3 * (1 - t) ** 2 * t * P1.x + + 3 * (1 - t) * t ** 2 * P2.x + + t ** 3 * P3.x; + + const y = (1 - t) ** 3 * P0.y + + 3 * (1 - t) ** 2 * t * P1.y + + 3 * (1 - t) * t ** 2 * P2.y + + t ** 3 * P3.y; + + return { x, y }; + } + + + let delay = 0; + for (let index = 0; index < items.length; index++) { + let chart_height = 340; + const item = items[index]; + delay += 0.05; + // console.log(lineChart.clientWidth) + + // maxPortals++; + // maxPortals++; + + let point_height = (chart_height / maxPortals) + + for (let index = 0; index < (maxPortals / multiplier); index++) { + // console.log((index + 1) * multiplier) + let current_portal_count = (index + 1); + + const placeholderDiv = document.createElement("div") + const numPortalsText = document.createElement("span") + const numPortalsTextBottom = document.createElement("span") + numPortalsText.innerText = (current_portal_count * multiplier) + minPortals + numPortalsTextBottom.innerText = minPortals + placeholderDiv.style.position = "absolute" + numPortalsText.style.position = "absolute" + numPortalsTextBottom.style.position = "absolute" + numPortalsText.style.left = "-37px" + numPortalsText.style.opacity = "0.2" + numPortalsTextBottom.style.opacity = "0.2" + numPortalsText.style.fontFamily = "BarlowSemiCondensed-Regular" + numPortalsTextBottom.style.fontFamily = "BarlowSemiCondensed-Regular" + numPortalsText.style.fontSize = "22px" + numPortalsTextBottom.style.left = "-37px" + numPortalsTextBottom.style.fontSize = "22px" + numPortalsTextBottom.style.fontWeight = "400" + numPortalsText.style.color = "#CDCFDF" + numPortalsTextBottom.style.color = "#CDCFDF" + numPortalsText.style.fontFamily = "inherit" + numPortalsTextBottom.style.fontFamily = "inherit" + numPortalsText.style.textAlign = "right" + numPortalsTextBottom.style.textAlign = "right" + numPortalsText.style.width = "30px" + numPortalsTextBottom.style.width = "30px" + placeholderDiv.style.bottom = `${(point_height * current_portal_count * multiplier) - 2}px` + numPortalsText.style.bottom = `${(point_height * current_portal_count * multiplier) - 2 - 9}px` + numPortalsTextBottom.style.bottom = `${0 - 2 - 8}px` + placeholderDiv.id = placeholderDiv.style.bottom + placeholderDiv.style.width = "100%" + placeholderDiv.style.height = "2px" + placeholderDiv.style.backgroundColor = "#2B2E46" + placeholderDiv.style.zIndex = "0" + + if (index == 0) { + lineChart.appendChild(numPortalsTextBottom) + } + lineChart.appendChild(numPortalsText) + lineChart.appendChild(placeholderDiv) + } + + const li = document.createElement("li"); + const lineSeg = document.createElement("div"); + const dataPoint = document.createElement("div"); + + li.style = `--y: ${point_height * (item.record - minPortals) - 3}px; --x: ${item.x}px`; + lineSeg.className = "line-segment"; + dataPoint.className = "data-point"; + + if (items[index + 1] !== undefined) { + const hypotenuse = Math.sqrt( + Math.pow(items[index + 1].x - items[index].x, 2) + + Math.pow((point_height * items[index + 1].record) - point_height * item.record, 2) + ); + const angle = Math.asin( + ((point_height * item.record) - (point_height * items[index + 1].record)) / hypotenuse + ); + + lineSeg.style = `--hypotenuse: ${hypotenuse}; --angle: ${angle * (-180 / Math.PI)}`; + const t0 = index / items.length; + const t1 = (index + 1) / items.length + + const P0t0 = calculateIntermediateControlPoints(t0, P0, P1, P2, P3); + const P1t1 = calculateIntermediateControlPoints(t1, P0, P1, P2, P3); + const bezierStyle = `cubic-bezier(${P0t0.x.toFixed(3)}, ${P0t0.y.toFixed(3)}, ${P1t1.x.toFixed(3)}, ${P1t1.y.toFixed(3)})` + lineSeg.style.animationTimingFunction = bezierStyle + lineSeg.style.animationDelay = delay + "s" + } + dataPoint.style.animationDelay = delay + "s" + + let isHoveringOverData = false; + let isDataActive = false; + document.querySelector("#dataPointInfo").style.left = item.x + "px"; + document.querySelector("#dataPointInfo").style.bottom = (point_height * item.record -3) + "px"; + dataPoint.addEventListener("mouseenter", (e) => { + isDataActive = true; + isHoveringOverData = true; + const dataPoints = document.querySelectorAll(".data-point") + dataPoints.forEach(point => { + point.classList.remove("data-point-active") + }); + dataPoint.classList.add("data-point-active") + document.querySelector("#dataPointRecord").innerText = item.record; + document.querySelector("#dataPointMap").innerText = item.map; + document.querySelector("#dataPointDate").innerText = item.date.toLocaleDateString("en-GB"); + document.querySelector("#dataPointFirst").innerText = item.first; + if ((lineChart.clientWidth - 400) < item.x) { + document.querySelector("#dataPointInfo").style.left = item.x - 400 + "px"; + } else { + document.querySelector("#dataPointInfo").style.left = item.x + "px"; + } + if ((lineChart.clientHeight - 115) < (point_height * (item.record - minPortals) -3)) { + document.querySelector("#dataPointInfo").style.bottom = (point_height * (item.record - minPortals) -3) - 115 + "px"; + } else { + document.querySelector("#dataPointInfo").style.bottom = (point_height * (item.record - minPortals) -3) + "px"; + } + document.querySelector("#dataPointInfo").style.opacity = "1"; + document.querySelector("#dataPointInfo").style.zIndex = "10"; + }); + document.querySelector("#dataPointInfo").addEventListener("mouseenter", (e) => { + isHoveringOverData = true; + }) + document.querySelector("#dataPointInfo").addEventListener("mouseleave", (e) => { + isHoveringOverData = false; + }) + document.addEventListener("mousedown", () => { + if (!isHoveringOverData) { + isDataActive = false + dataPoint.classList.remove("data-point-active") + document.querySelector("#dataPointInfo").style.opacity = "0"; + document.querySelector("#dataPointInfo").style.zIndex = "0"; + } + }) + dataPoint.addEventListener("mouseenter", (e) => { + isHoveringOverData = false; + }) + document.querySelector(".chart").addEventListener("mouseleave", () => { + isDataActive = false + dataPoint.classList.remove("data-point-active") + document.querySelector("#dataPointInfo").style.opacity = "0"; + document.querySelector("#dataPointInfo").style.zIndex = "0"; + }) + + li.appendChild(lineSeg); + li.appendChild(dataPoint); + lineChart.appendChild(li); + } + } + + createGraph() + + async function fetchGames() { + try { + const response = await fetch("https://lp.ardapektezol.com/api/v1/games", { + headers: { + 'Authorization': token + } + }); + + const data = await response.json(); + + const gameImg = document.querySelector(".game-img"); + + gameImg.style.backgroundImage = `url(${data.data[0].image})`; + + // const mapImg = document.querySelectorAll(".maplist-img"); + // mapImg.forEach((map) => { + // map.style.backgroundImage = `url(${data.data[0].image})`; + // }); + + } catch (error) { + console.log("error fetching games:", error); + } + } + + detectGame(); + + const maplistImg = document.querySelector("#maplistImg"); + maplistImg.src = img5; + const statisticsImg = document.querySelector("#statisticsImg"); + statisticsImg.src = img6; + + fetchGames(); + + const handleResize = (entries) => { + for (let entry of entries) { + lineChart.innerHTML = "" + createGraph() + if (document.querySelector(".maplist").getAttribute("currentTab") == "stats") { + document.querySelector(".stats").style.display = "block" + } else { + document.querySelector(".stats").style.display = "none" + } + } + }; + + const resizeObserver = new ResizeObserver(handleResize); + + // if (scrollRef.current) { + // //hi + // if (new URLSearchParams(new URL(window.location.href).search).get("chapter")) { + // setTimeout(() => { + // scrollRef.current.scrollIntoView({ behavior: "smooth", block: "start" }) + // }, 200); + // } + + // } + + if (divRef.current) { + resizeObserver.observe(divRef.current); + } + + return () => { + if (divRef.current) { + resizeObserver.unobserve(divRef.current); + } + resizeObserver.disconnect(); + }; + + + }) + return ( +
+
+
+ +   +
+ +
+
+
+
+ 0 + portals +
+
+ +
+
+
+ +
+ + +
+ +
+
+ undefined
+ undefined + +
+ + 0/0 + +
+ +
+
+
+
+ +
+
+ Portal count over time
+ +
+
+
+
+
+ Date + Map + Record + First completion +
+
+
+ + + + Hello +
+
+
    + +
+
+
+
+
+
+
+ ) +} \ No newline at end of file -- cgit v1.2.3