From a65d6d9127c3fa7f6a8ecaec5d1ffd1f47c2bc98 Mon Sep 17 00:00:00 2001 From: Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> Date: Tue, 3 Sep 2024 00:08:53 +0300 Subject: refactor: port to typescript --- frontend/src/components/Discussions.tsx | 151 ++ frontend/src/components/GameEntry.tsx | 49 + frontend/src/components/Leaderboards.tsx | 105 ++ frontend/src/components/Login.tsx | 1931 +++++++++++++++++++++ frontend/src/components/ModMenu.tsx | 324 ++++ frontend/src/components/Sidebar.tsx | 183 ++ frontend/src/components/Summary.tsx | 169 ++ frontend/src/components/login.css | 26 - frontend/src/components/login.js | 61 - frontend/src/components/main.css | 17 - frontend/src/components/main.js | 17 - frontend/src/components/news.css | 29 - frontend/src/components/news.js | 21 - frontend/src/components/pages/about.css | 17 - frontend/src/components/pages/about.js | 32 - frontend/src/components/pages/game.js | 46 - frontend/src/components/pages/games.css | 99 -- frontend/src/components/pages/games.js | 62 - frontend/src/components/pages/home.css | 92 - frontend/src/components/pages/home.js | 242 --- frontend/src/components/pages/maplist.css | 403 ----- frontend/src/components/pages/maplist.js | 890 ---------- frontend/src/components/pages/profile.css | 239 --- frontend/src/components/pages/profile.js | 382 ---- frontend/src/components/pages/summary.css | 720 -------- frontend/src/components/pages/summary.js | 650 ------- frontend/src/components/pages/summary_modview.css | 112 -- frontend/src/components/pages/summary_modview.js | 254 --- frontend/src/components/record.css | 15 - frontend/src/components/record.js | 56 - frontend/src/components/sidebar.css | 208 --- frontend/src/components/sidebar.js | 203 --- 32 files changed, 2912 insertions(+), 4893 deletions(-) create mode 100644 frontend/src/components/Discussions.tsx create mode 100644 frontend/src/components/GameEntry.tsx create mode 100644 frontend/src/components/Leaderboards.tsx create mode 100644 frontend/src/components/Login.tsx create mode 100644 frontend/src/components/ModMenu.tsx create mode 100644 frontend/src/components/Sidebar.tsx create mode 100644 frontend/src/components/Summary.tsx delete mode 100644 frontend/src/components/login.css delete mode 100644 frontend/src/components/login.js delete mode 100644 frontend/src/components/main.css delete mode 100644 frontend/src/components/main.js delete mode 100644 frontend/src/components/news.css delete mode 100644 frontend/src/components/news.js delete mode 100644 frontend/src/components/pages/about.css delete mode 100644 frontend/src/components/pages/about.js delete mode 100644 frontend/src/components/pages/game.js delete mode 100644 frontend/src/components/pages/games.css delete mode 100644 frontend/src/components/pages/games.js delete mode 100644 frontend/src/components/pages/home.css delete mode 100644 frontend/src/components/pages/home.js delete mode 100644 frontend/src/components/pages/maplist.css delete mode 100644 frontend/src/components/pages/maplist.js delete mode 100644 frontend/src/components/pages/profile.css delete mode 100644 frontend/src/components/pages/profile.js delete mode 100644 frontend/src/components/pages/summary.css delete mode 100644 frontend/src/components/pages/summary.js delete mode 100644 frontend/src/components/pages/summary_modview.css delete mode 100644 frontend/src/components/pages/summary_modview.js delete mode 100644 frontend/src/components/record.css delete mode 100644 frontend/src/components/record.js delete mode 100644 frontend/src/components/sidebar.css delete mode 100644 frontend/src/components/sidebar.js (limited to 'frontend/src/components') diff --git a/frontend/src/components/Discussions.tsx b/frontend/src/components/Discussions.tsx new file mode 100644 index 0000000..1cd3523 --- /dev/null +++ b/frontend/src/components/Discussions.tsx @@ -0,0 +1,151 @@ +import React from 'react'; + +import { MapDiscussion, MapDiscussions, MapDiscussionsDetail } from '../types/Map'; +import { MapDiscussionCommentContent, MapDiscussionContent } from '../types/Content'; +import { time_ago } from '../utils/Time'; +import { API } from '../api/Api'; +import "../css/Maps.css" + +interface DiscussionsProps { + data?: MapDiscussions; + isModerator: boolean; + mapID: string; + onRefresh: () => void; +} + +const Discussions: React.FC = ({ data, isModerator, mapID, onRefresh }) => { + + const [discussionThread, setDiscussionThread] = React.useState(undefined); + const [discussionSearch, setDiscussionSearch] = React.useState(""); + + const [createDiscussion, setCreateDiscussion] = React.useState(false); + const [createDiscussionContent, setCreateDiscussionContent] = React.useState({ + title: "", + content: "", + }); + const [createDiscussionCommentContent, setCreateDiscussionCommentContent] = React.useState({ + comment: "", + }); + + const _open_map_discussion = async (discussion_id: number) => { + const mapDiscussion = await API.get_map_discussion(mapID, discussion_id); + setDiscussionThread(mapDiscussion); + }; + + const _create_map_discussion = async () => { + await API.post_map_discussion(mapID, createDiscussionContent); + setCreateDiscussion(false); + onRefresh(); + }; + + const _create_map_discussion_comment = async (discussion_id: number) => { + await API.post_map_discussion_comment(mapID, discussion_id, createDiscussionCommentContent); + await _open_map_discussion(discussion_id); + }; + + const _delete_map_discussion = async (discussion: MapDiscussionsDetail) => { + if (window.confirm(`Are you sure you want to remove post: ${discussion.title}?`)) { + await API.delete_map_discussion(mapID, discussion.id); + onRefresh(); + } + }; + + return ( +
+ + + { // janky ternary operators here, could divide them to more components? + createDiscussion ? + ( +
+ Create Post + +
+ setCreateDiscussionContent({ + ...createDiscussionContent, + title: e.target.value, + })} /> + setCreateDiscussionContent({ + ...createDiscussionContent, + title: e.target.value, + })} /> +
+
+ +
+
+ ) + : + discussionThread ? + ( +
+
+ {discussionThread.discussion.title} + +
+ +
+ +
+ {discussionThread.discussion.creator.user_name} + {time_ago(new Date(discussionThread.discussion.created_at.replace("T", " ").replace("Z", "")))} + {discussionThread.discussion.content} +
+ {discussionThread.discussion.comments ? + discussionThread.discussion.comments.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()) + .map(e => ( + <> + +
+ {e.user.user_name} + {time_ago(new Date(e.date.replace("T", " ").replace("Z", "")))} + {e.comment} +
+ + )) : "" + } +
+
+ e.key === "Enter" && _create_map_discussion_comment(discussionThread.discussion.id)} onChange={(e) => setCreateDiscussionCommentContent({ + ...createDiscussionContent, + comment: e.target.value, + })} /> +
+
+ +
+ ) + : + ( + data ? + (<> + {data.discussions.filter(f => f.title.includes(discussionSearch)).sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()) + .map((e, i) => ( +
+ + : + } + {e.creator.user_name}: {e.content} + Last Updated: {time_ago(new Date(e.updated_at.replace("T", " ").replace("Z", "")))} + +
+ ))} + ) + : + (No Discussions...) + ) + } +
+ ); +}; + +export default Discussions; diff --git a/frontend/src/components/GameEntry.tsx b/frontend/src/components/GameEntry.tsx new file mode 100644 index 0000000..8e58ce9 --- /dev/null +++ b/frontend/src/components/GameEntry.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { Link } from "react-router-dom"; + +import { Game } from '../types/Game'; +import "../css/Games.css" + +interface GameEntryProps { + game: Game; +} + +const GameEntry: React.FC = ({ game }) => { + + React.useEffect(() => { + game.category_portals.forEach(catInfo => { + const itemBody = document.createElement("div"); + const itemTitle = document.createElement("span"); + const spacing = document.createElement("br"); + const itemNum = document.createElement("span"); + + itemTitle.innerText = catInfo.category.name; + itemNum.innerText = catInfo.portal_count as any as string; + itemTitle.classList.add("games-page-item-body-item-title"); + itemNum.classList.add("games-page-item-body-item-num"); + itemBody.appendChild(itemTitle); + itemBody.appendChild(spacing); + itemBody.appendChild(itemNum); + itemBody.className = "games-page-item-body-item"; + + // itemBody.innerHTML = ` + // ${catInfo.category.name}
+ // ${catInfo.portal_count}` + + document.getElementById(`${game.id}`)!.appendChild(itemBody); + }); + }, []); + + return ( +
+
+
+ {game.name} +
+
+
+
+ ); +}; + +export default GameEntry; diff --git a/frontend/src/components/Leaderboards.tsx b/frontend/src/components/Leaderboards.tsx new file mode 100644 index 0000000..badff37 --- /dev/null +++ b/frontend/src/components/Leaderboards.tsx @@ -0,0 +1,105 @@ +import React from 'react'; + +import { DownloadIcon, ThreedotIcon } from '../images/Images'; +import { MapLeaderboard } from '../types/Map'; +import { ticks_to_time, time_ago } from '../utils/Time'; +import "../css/Maps.css" + +interface LeaderboardsProps { + data?: MapLeaderboard; +} + +const Leaderboards: React.FC = ({ data }) => { + + const [pageNumber, setPageNumber] = React.useState(1); + + if (!data) { + return ( +
+

Map is not available for competitive boards.

+
+ ); + }; + + if (data.records.length === 0) { + return ( +
+

No records found.

+
+ ); + }; + + return ( +
+ +
+ Place + + {data.map.is_coop ? ( +
+ Host + Partner +
+ ) : ( + Runner + )} + + Portals + Time + Date +
+
+ + + {data.pagination.current_page}/{data.pagination.total_pages} + +
+
+
+
+
+ {data.records.map((r, index) => ( + + {r.placement} + + {r.kind === "multiplayer" ? ( +
+   {r.host.user_name} +   {r.partner.user_name} +
+ ) : ( +
  {r.user.user_name}
+ )} + + {r.score_count} + + {ticks_to_time(r.score_time)} + {time_ago(new Date(r.record_date.replace("T", " ").replace("Z", "")))} + + {r.kind === "multiplayer" ? ( + + + + + + ) : ( + + + + + + )} +
+ ))} +
+
+ ); +}; + +export default Leaderboards; diff --git a/frontend/src/components/Login.tsx b/frontend/src/components/Login.tsx new file mode 100644 index 0000000..adfa718 --- /dev/null +++ b/frontend/src/components/Login.tsx @@ -0,0 +1,1931 @@ +import React from 'react'; +import { Link, useNavigate } from 'react-router-dom'; + +import { ExitIcon, UserIcon, LoginIcon } from '../images/Images'; +import { UserProfile } from '../types/Profile'; +import { API } from '../api/Api'; +import "../css/Login.css"; + +interface LoginProps { + token?: string; + setToken: React.Dispatch>; + profile?: UserProfile; + setProfile: React.Dispatch>; +}; + +const Login: React.FC = ({ token, setToken, profile, setProfile }) => { + + const navigate = useNavigate(); + + const _logout = () => { + setProfile(undefined); + setToken(undefined); + API.user_logout(); + navigate("/"); + } + + return ( + <> + {profile + ? + ( + <> + + + + + + ) + : + ( + + + + )} + + ); +}; + +export default Login; diff --git a/frontend/src/components/ModMenu.tsx b/frontend/src/components/ModMenu.tsx new file mode 100644 index 0000000..1fe4239 --- /dev/null +++ b/frontend/src/components/ModMenu.tsx @@ -0,0 +1,324 @@ +import React from 'react'; +import ReactMarkdown from 'react-markdown'; + +import { MapSummary } from '../types/Map'; +import { ModMenuContent } from '../types/Content'; +import { API } from '../api/Api'; +import "../css/ModMenu.css" + +interface ModMenuProps { + data: MapSummary; + selectedRun: number; + mapID: string; +} + +const ModMenu: React.FC = ({ data, selectedRun, mapID }) => { + + const [menu, setMenu] = React.useState(0); + const [showButton, setShowButton] = React.useState(1) + + const [routeContent, setRouteContent] = React.useState({ + id: 0, + name: "", + score: 0, + date: "", + showcase: "", + description: "No description available.", + category_id: 1, + }); + + const [image, setImage] = React.useState(""); + const [md, setMd] = React.useState(""); + + function compressImage(file: File): Promise { + const reader = new FileReader(); + reader.readAsDataURL(file); + return new Promise(resolve => { + reader.onload = () => { + const img = new Image(); + if (typeof reader.result === "string") { + img.src = reader.result; + img.onload = () => { + let { width, height } = img; + if (width > 550) { + height *= 550 / width; + width = 550; + } + if (height > 320) { + width *= 320 / height; + height = 320; + } + const canvas = document.createElement('canvas'); + canvas.width = width; + canvas.height = height; + canvas.getContext('2d')!.drawImage(img, 0, 0, width, height); + resolve(canvas.toDataURL(file.type, 0.6)); + }; + } + }; + }); + }; + + const _edit_map_summary_image = async () => { + if (window.confirm("Are you sure you want to submit this to the database?")) { + await API.put_map_image(mapID, image); + } + }; + + const _edit_map_summary_route = async () => { + if (window.confirm("Are you sure you want to submit this to the database?")) { + await API.put_map_summary(mapID, routeContent); + } + }; + + const _create_map_summary_route = async () => { + if (window.confirm("Are you sure you want to submit this to the database?")) { + await API.post_map_summary(mapID, routeContent); + } + }; + + const _delete_map_summary_route = async () => { + if (window.confirm(`Are you sure you want to delete this run from the database? + ${data.summary.routes[selectedRun].category.name} ${data.summary.routes[selectedRun].history.score_count} portals ${data.summary.routes[selectedRun].history.runner_name}`)) { + await API.delete_map_summary(mapID, data.summary.routes[selectedRun].route_id); + } + }; + + React.useEffect(() => { + if (menu === 3) { // add route + setRouteContent({ + id: 0, + name: "", + score: 0, + date: "", + showcase: "", + description: "No description available.", + category_id: 1, + }); + setMd("No description available."); + } + if (menu === 2) { // edit route + setRouteContent({ + id: data.summary.routes[selectedRun].route_id, + name: data.summary.routes[selectedRun].history.runner_name, + score: data.summary.routes[selectedRun].history.score_count, + date: data.summary.routes[selectedRun].history.date.split("T")[0], + showcase: data.summary.routes[selectedRun].showcase, + description: data.summary.routes[selectedRun].description, + category_id: data.summary.routes[selectedRun].category.id, + }); + setMd(data.summary.routes[selectedRun].description); + } + }, [menu]); + + React.useEffect(() => { + const modview = document.querySelector("div#modview") as HTMLElement + if (modview) { + showButton ? modview.style.transform = "translateY(-68%)" + : modview.style.transform = "translateY(0%)" + } + + const modview_block = document.querySelector("#modview_block") as HTMLElement + if (modview_block) { + showButton === 1 ? modview_block.style.display = "none" : modview_block.style.display = "block"// eslint-disable-next-line + } + }, [showButton]) + + return ( +
+ +
+
+ + + + +
+
+ {showButton ? ( + + ) : ( + + )} +
+
+ +
+ { // Edit Image + menu === 1 && ( +
+
+ Current Image: + missing +
+ +
+ New Image: + { + if (e.target.files) { + compressImage(e.target.files[0]) + .then(d => setImage(d)) + } + } + } /> + {image ? () : } + + +
+
+ ) + } + + { // Edit Route + menu === 2 && ( +
+
+ Route ID: + +
+
+ Runner Name: + { + setRouteContent({ + ...routeContent, + name: e.target.value, + }); + }} /> +
+
+ Score: + { + setRouteContent({ + ...routeContent, + score: parseInt(e.target.value), + }); + }} /> +
+
+ Date: + { + setRouteContent({ + ...routeContent, + date: e.target.value, + }); + }} /> +
+
+ Showcase Video: + { + setRouteContent({ + ...routeContent, + showcase: e.target.value, + }); + }} /> +
+
+ Description: + -
- -
- ):menu===3?( - // add route -
-
- category: - -
-
- runner name: - -
-
- score: - -
-
- date: - -
-
- showcase video: - -
-
- description: - -
- -
- ):("error")} - - {menu!==1?( -
- Markdown preview - documentation - demo -

- {md} - -

-
- ):""} -
):""} - - -) -} - diff --git a/frontend/src/components/record.css b/frontend/src/components/record.css deleted file mode 100644 index 60d47ee..0000000 --- a/frontend/src/components/record.css +++ /dev/null @@ -1,15 +0,0 @@ -.record-container { - --padding: 20px; - width: calc(100% - calc(var(--padding * 2))); - height: 42px; - background-color: #2B2E46; - border-radius: 200px; - font-size: 18px; - display: grid; - grid-template-columns: 20% 25% 15% 15% 25%; - text-align: center; - padding: 0px var(--padding); - vertical-align: middle; - align-items: center; - margin-bottom: 6px; -} \ No newline at end of file diff --git a/frontend/src/components/record.js b/frontend/src/components/record.js deleted file mode 100644 index 80e084d..0000000 --- a/frontend/src/components/record.js +++ /dev/null @@ -1,56 +0,0 @@ -import React, { useEffect, useRef, useState } from 'react'; -import { useLocation, Link } from "react-router-dom"; - -import "./record.css" - -export default function Record({ name, place, portals, time, date }) { - // const {token} = prop; - const [record, setRecord] = useState(null); - const location = useLocation(); - - // useEffect(() => { - // console.log(name, place, portals, time, date); - // }) - - function timeSince() { - const now = new Date(); - const dateNew = new Date(date); - - const secondsPast = Math.floor((now - dateNew) / 1000); - - if (secondsPast < 60) { - return `${secondsPast} seconds ago`; - } - if (secondsPast < 3600) { - const minutes = Math.floor(secondsPast / 60); - return `${minutes} minutes ago`; - } - if (secondsPast < 86400) { - const hours = Math.floor(secondsPast / 3600); - return `${hours} hours ago`; - } - if (secondsPast < 2592000) { - const days = Math.floor(secondsPast / 86400); - return `${days} days ago`; - } - if (secondsPast < 31536000) { - const months = Math.floor(secondsPast / 2592000); - return `${months} months ago`; - } - const years = Math.floor(secondsPast / 31536000); - return `${years} years ago`; - } - - return( -
- {place} -
- - {name} -
- {portals} - {time} - {timeSince()} -
- ) -} diff --git a/frontend/src/components/sidebar.css b/frontend/src/components/sidebar.css deleted file mode 100644 index 34ede80..0000000 --- a/frontend/src/components/sidebar.css +++ /dev/null @@ -1,208 +0,0 @@ -#sidebar { - overflow: hidden; - position: absolute; - background-color: #2b2e46; - width: 320px; height: 100vh; - min-height: 670px; - -} - - /* logo */ -#logo{ - display: grid; - grid-template-columns: 60px 200px; - - - height: 80px; - padding: 20px 0 20px 30px; - cursor: pointer; - user-select: none; -} - -#logo-text{ - font-family: BarlowCondensed-Regular; - font-size: 42px; - color: #FFF; - line-height: 38px; -} -span>b{ - font-family: BarlowCondensed-Bold; - font-size: 56px; -} - - /* Sidelist */ -#sidebar-list{ - z-index: 2; - background-color: #2b2e46; - position: relative; - height: calc(100vh - 120px); - width: 320px; - /* min-height: 670px; */ - transition: width .3s; -} -#sidebar-toplist>button:nth-child(1){margin-top: 5px;} -#sidebar-toplist{ - display: grid; - - margin: 0 5px 0 5px; - justify-items: left; - height: 400px; - grid-template-rows: 45px 50px 50px 50px 50px 50px 50px 50px auto; -} - -#sidebar-bottomlist{ - display: grid; - - margin: 0 5px 0 5px; - justify-items: left; - grid-template-rows: calc(100vh - 670px) 50px 50px 50px; -} -.sidebar-button>span{ - font-family: BarlowSemiCondensed-Regular; - font-size: 18px; - color: #CDCFDF; - height: 32px; - line-height: 28px; - transition: opacity .1s; -} -.sidebar-button{ - display: grid; - grid-template-columns: 50px auto; - place-items: left; - text-align: left; - - background-color: inherit; - cursor: pointer; - border: none; - width: 310px; - height: 40px; - border-radius: 20px; - padding: 0.4em 0 0 11px; - - transition: - width .3s, - background-color .15s, - padding .3s; -} - -.sidebar-button-selected { - background-color: #202232; -} - -.sidebar-button-deselected { - background-color: #20223200; -} - -.sidebar-button-deselected:hover { - background-color: #202232aa; -} - -button>img { - scale: 1.1; - width: 20px; - padding: 5px; -} - - /* Maplist */ -#sidebar>div:nth-child(3){ - position: relative; - background-color: #202232; - color: #424562; - z-index: 1; - - left: 52px; - top: calc(-100vh + 120px); - width: 268px; height: calc(100vh - 120px); - min-height: 550px; -} -input#searchbar[type=text]{ - margin: 10px 0 0 6px; - padding: 1px 0px 1px 16px; - width: 240px; - height: 30px; - - font-family: BarlowSemiCondensed-Regular; - font-size: 20px; - - background-color: #161723; - color:#CDCFDF; - - border: 0; - border-radius: 20px; - -} -input[type=text]::placeholder{color:#2b2e46} -input[type=text]:focus{outline: inherit;} -a{text-decoration: none;height: 40px;} - - -#search-data{ - margin: 8px 0 8px 0; - overflow-y: auto; - max-height: calc(100vh - 172px); - scrollbar-width: thin; -} -#search-data::-webkit-scrollbar{display: none;} -.search-map{ - margin: 10px 6px 0 6px; - height: 80px; - - border-radius: 20px; - text-align: center; - - display: grid; - - border: 0; - transition: background-color .1s; - background-color: #2b2e46; - grid-template-rows: 20% 20% 60%; - width: calc(100% - 15px); -} -.search-map>span{ - color: #888; - font-size: 16px; - font-family: BarlowSemiCondensed-Regular; -} -.search-map>span:nth-child(3){ - font-size: 30px; - color: #CDCFDF; -} - -.search-player{ - overflow: hidden; - margin: 10px 6px 0 6px; - height: 80px; - - border-radius: 20px; - text-align: center; - color: #CDCFDF; - font-family: BarlowSemiCondensed-Regular; - - display: grid; - place-items: center; - grid-template-columns: 20% 80%; - padding: 0 16px 0 16px; - - border: 0; - transition: background-color .1s; - background-color: #2b2e46; -} -.search-player>img{ - height: 60px; - border-radius: 20px; -} -.search-player>span{ - width:154px; - font-size: 26px; -} - - - - - - - - - - - diff --git a/frontend/src/components/sidebar.js b/frontend/src/components/sidebar.js deleted file mode 100644 index 1ca17e6..0000000 --- a/frontend/src/components/sidebar.js +++ /dev/null @@ -1,203 +0,0 @@ -import React, { useEffect } from 'react'; -import { Link, useLocation } from "react-router-dom"; - -import "../App.css" -import "./sidebar.css"; -import logo from "../imgs/logo.png" -import img1 from "../imgs/1.png" -import img2 from "../imgs/2.png" -import img3 from "../imgs/3.png" -import img4 from "../imgs/4.png" -import img5 from "../imgs/5.png" -import img6 from "../imgs/6.png" -import img7 from "../imgs/7.png" -import img8 from "../imgs/8.png" -import img9 from "../imgs/9.png" -import Login from "./login.js" - -export default function Sidebar(prop) { -const {token,setToken} = prop -const [profile, setProfile] = React.useState(null); - -React.useEffect(() => { - fetch(`https://lp.ardapektezol.com/api/v1/profile`,{ - headers: { - 'Content-Type': 'application/json', - Authorization: token - }}) - .then(r => r.json()) - .then(d => setProfile(d.data)) - }, [token]); - -// Locks search button for 300ms before it can be clicked again, prevents spam -const [isLocked, setIsLocked] = React.useState(false); -function HandleLock(arg) { -if (!isLocked) { - setIsLocked(true); - setTimeout(() => setIsLocked(false), 300); - SidebarHide(arg) - } -} - - -// The menu button -const [sidebar, setSidebar] = React.useState(); - -// Clicked buttons -function SidebarClick(x){ -const btn = document.querySelectorAll("button.sidebar-button"); - -if(sidebar===1){setSidebar(0);SidebarHide()} - -// clusterfuck -btn.forEach((e,i) =>{ - btn[i].classList.remove("sidebar-button-selected") - btn[i].classList.add("sidebar-button-deselected") -}) -btn[x].classList.add("sidebar-button-selected") -btn[x].classList.remove("sidebar-button-deselected") - -} - -function SidebarHide(){ -const btn = document.querySelectorAll("button.sidebar-button") -const span = document.querySelectorAll("button.sidebar-button>span"); -const side = document.querySelector("#sidebar-list"); -const login = document.querySelectorAll(".login>button")[1]; -const searchbar = document.querySelector("#searchbar"); - -if(sidebar===1){ - setSidebar(0) - side.style.width="320px" - btn.forEach((e, i) =>{ - e.style.width="310px" - e.style.padding = "0.4em 0 0 11px" - setTimeout(() => { - span[i].style.opacity="1" - login.style.opacity="1" - - }, 100) - }) - side.style.zIndex="2" -} else { - side.style.width="40px"; - searchbar.focus(); - setSearch(searchbar.value) - setSidebar(1) - btn.forEach((e,i) =>{ - e.style.width="40px" - e.style.padding = "0.4em 0 0 5px" - span[i].style.opacity="0" - }) - login.style.opacity="0" - setTimeout(() => { - side.style.zIndex="0" - }, 300); - } -} -// Links -const location = useLocation() -React.useEffect(()=>{ - if(location.pathname==="/"){SidebarClick(1)} - if(location.pathname.includes("news")){SidebarClick(2)} - if(location.pathname.includes("games")){SidebarClick(3)} - if(location.pathname.includes("leaderboards")){SidebarClick(4)} - if(location.pathname.includes("scorelog")){SidebarClick(5)} - if(location.pathname.includes("profile")){SidebarClick(6)} - if(location.pathname.includes("rules")){SidebarClick(8)} - if(location.pathname.includes("about")){SidebarClick(9)} - - // eslint-disable-next-line react-hooks/exhaustive-deps -}, [location.pathname]) - -const [search,setSearch] = React.useState(null) -const [searchData,setSearchData] = React.useState(null) - -React.useEffect(()=>{ - fetch(`https://lp.ardapektezol.com/api/v1/search?q=${search}`) - .then(r=>r.json()) - .then(d=>setSearchData(d.data)) - -}, [search]) - - -return ( - - ) -} - - -- cgit v1.2.3