diff options
| author | FifthWit <fifthwitbusiness@gmail.com> | 2025-01-30 10:44:30 -0600 |
|---|---|---|
| committer | FifthWit <fifthwitbusiness@gmail.com> | 2025-01-30 10:44:30 -0600 |
| commit | e40f07211f5f15dcb138e2520a76d13afd3c0cfd (patch) | |
| tree | 46bad6a17e66d55a4a65088c0b6eb8c48641615a /frontend/src/components/Sidebar.tsx | |
| parent | added prettier for more consistency (diff) | |
| download | lphub-e40f07211f5f15dcb138e2520a76d13afd3c0cfd.tar.gz lphub-e40f07211f5f15dcb138e2520a76d13afd3c0cfd.tar.bz2 lphub-e40f07211f5f15dcb138e2520a76d13afd3c0cfd.zip | |
formatted with prettier
Diffstat (limited to 'frontend/src/components/Sidebar.tsx')
| -rw-r--r-- | frontend/src/components/Sidebar.tsx | 262 |
1 files changed, 171 insertions, 91 deletions
diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index 67f7f3d..71b79be 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx | |||
| @@ -1,23 +1,38 @@ | |||
| 1 | import React from 'react'; | 1 | import React from 'react'; |
| 2 | import { Link, useLocation } from 'react-router-dom'; | 2 | import { Link, useLocation } from 'react-router-dom'; |
| 3 | 3 | ||
| 4 | import { BookIcon, FlagIcon, HelpIcon, HomeIcon, LogoIcon, PortalIcon, SearchIcon, UploadIcon } from '@images/Images'; | 4 | import { |
| 5 | BookIcon, | ||
| 6 | FlagIcon, | ||
| 7 | HelpIcon, | ||
| 8 | HomeIcon, | ||
| 9 | LogoIcon, | ||
| 10 | PortalIcon, | ||
| 11 | SearchIcon, | ||
| 12 | UploadIcon, | ||
| 13 | } from '@images/Images'; | ||
| 5 | import Login from '@components/Login'; | 14 | import Login from '@components/Login'; |
| 6 | import { UserProfile } from '@customTypes/Profile'; | 15 | import { UserProfile } from '@customTypes/Profile'; |
| 7 | import { Search } from '@customTypes/Search'; | 16 | import { Search } from '@customTypes/Search'; |
| 8 | import { API } from '@api/Api'; | 17 | import { API } from '@api/Api'; |
| 9 | import "@css/Sidebar.css"; | 18 | import '@css/Sidebar.css'; |
| 10 | 19 | ||
| 11 | interface SidebarProps { | 20 | interface SidebarProps { |
| 12 | setToken: React.Dispatch<React.SetStateAction<string | undefined>>; | 21 | setToken: React.Dispatch<React.SetStateAction<string | undefined>>; |
| 13 | profile?: UserProfile; | 22 | profile?: UserProfile; |
| 14 | setProfile: React.Dispatch<React.SetStateAction<UserProfile | undefined>>; | 23 | setProfile: React.Dispatch<React.SetStateAction<UserProfile | undefined>>; |
| 15 | onUploadRun: () => void; | 24 | onUploadRun: () => void; |
| 16 | }; | 25 | } |
| 17 | |||
| 18 | const Sidebar: React.FC<SidebarProps> = ({ setToken, profile, setProfile, onUploadRun }) => { | ||
| 19 | 26 | ||
| 20 | const [searchData, setSearchData] = React.useState<Search | undefined>(undefined); | 27 | const Sidebar: React.FC<SidebarProps> = ({ |
| 28 | setToken, | ||
| 29 | profile, | ||
| 30 | setProfile, | ||
| 31 | onUploadRun, | ||
| 32 | }) => { | ||
| 33 | const [searchData, setSearchData] = React.useState<Search | undefined>( | ||
| 34 | undefined | ||
| 35 | ); | ||
| 21 | const [isSidebarLocked, setIsSidebarLocked] = React.useState<boolean>(false); | 36 | const [isSidebarLocked, setIsSidebarLocked] = React.useState<boolean>(false); |
| 22 | const [isSidebarOpen, setSidebarOpen] = React.useState<boolean>(true); | 37 | const [isSidebarOpen, setSidebarOpen] = React.useState<boolean>(true); |
| 23 | 38 | ||
| @@ -25,71 +40,86 @@ const Sidebar: React.FC<SidebarProps> = ({ setToken, profile, setProfile, onUplo | |||
| 25 | const path = location.pathname; | 40 | const path = location.pathname; |
| 26 | 41 | ||
| 27 | const handle_sidebar_click = (clicked_sidebar_idx: number) => { | 42 | const handle_sidebar_click = (clicked_sidebar_idx: number) => { |
| 28 | const btn = document.querySelectorAll("button.sidebar-button"); | 43 | const btn = document.querySelectorAll('button.sidebar-button'); |
| 29 | if (isSidebarOpen) { setSidebarOpen(false); _handle_sidebar_hide() } | 44 | if (isSidebarOpen) { |
| 45 | setSidebarOpen(false); | ||
| 46 | _handle_sidebar_hide(); | ||
| 47 | } | ||
| 30 | // clusterfuck | 48 | // clusterfuck |
| 31 | btn.forEach((e, i) => { | 49 | btn.forEach((e, i) => { |
| 32 | btn[i].classList.remove("sidebar-button-selected") | 50 | btn[i].classList.remove('sidebar-button-selected'); |
| 33 | btn[i].classList.add("sidebar-button-deselected") | 51 | btn[i].classList.add('sidebar-button-deselected'); |
| 34 | }) | 52 | }); |
| 35 | btn[clicked_sidebar_idx].classList.add("sidebar-button-selected") | 53 | btn[clicked_sidebar_idx].classList.add('sidebar-button-selected'); |
| 36 | btn[clicked_sidebar_idx].classList.remove("sidebar-button-deselected") | 54 | btn[clicked_sidebar_idx].classList.remove('sidebar-button-deselected'); |
| 37 | }; | 55 | }; |
| 38 | 56 | ||
| 39 | const _handle_sidebar_hide = () => { | 57 | const _handle_sidebar_hide = () => { |
| 40 | var btn = document.querySelectorAll("button.sidebar-button") as NodeListOf<HTMLElement> | 58 | var btn = document.querySelectorAll( |
| 41 | const span = document.querySelectorAll("button.sidebar-button>span") as NodeListOf<HTMLElement> | 59 | 'button.sidebar-button' |
| 42 | const side = document.querySelector("#sidebar-list") as HTMLElement; | 60 | ) as NodeListOf<HTMLElement>; |
| 43 | const searchbar = document.querySelector("#searchbar") as HTMLInputElement; | 61 | const span = document.querySelectorAll( |
| 44 | const uploadRunBtn = document.querySelector("#upload-run") as HTMLInputElement; | 62 | 'button.sidebar-button>span' |
| 45 | const uploadRunSpan = document.querySelector("#upload-run>span") as HTMLInputElement; | 63 | ) as NodeListOf<HTMLElement>; |
| 64 | const side = document.querySelector('#sidebar-list') as HTMLElement; | ||
| 65 | const searchbar = document.querySelector('#searchbar') as HTMLInputElement; | ||
| 66 | const uploadRunBtn = document.querySelector( | ||
| 67 | '#upload-run' | ||
| 68 | ) as HTMLInputElement; | ||
| 69 | const uploadRunSpan = document.querySelector( | ||
| 70 | '#upload-run>span' | ||
| 71 | ) as HTMLInputElement; | ||
| 46 | 72 | ||
| 47 | if (isSidebarOpen) { | 73 | if (isSidebarOpen) { |
| 48 | if (profile) { | 74 | if (profile) { |
| 49 | const login = document.querySelectorAll(".login>button")[1] as HTMLElement; | 75 | const login = document.querySelectorAll( |
| 50 | login.style.opacity = "1" | 76 | '.login>button' |
| 51 | uploadRunBtn.style.width = "310px" | 77 | )[1] as HTMLElement; |
| 52 | uploadRunBtn.style.padding = "0.4em 0 0 11px" | 78 | login.style.opacity = '1'; |
| 53 | uploadRunSpan.style.opacity = "0" | 79 | uploadRunBtn.style.width = '310px'; |
| 80 | uploadRunBtn.style.padding = '0.4em 0 0 11px'; | ||
| 81 | uploadRunSpan.style.opacity = '0'; | ||
| 54 | setTimeout(() => { | 82 | setTimeout(() => { |
| 55 | uploadRunSpan.style.opacity = "1" | 83 | uploadRunSpan.style.opacity = '1'; |
| 56 | }, 100) | 84 | }, 100); |
| 57 | } | 85 | } |
| 58 | setSidebarOpen(false); | 86 | setSidebarOpen(false); |
| 59 | side.style.width = "320px" | 87 | side.style.width = '320px'; |
| 60 | btn.forEach((e, i) => { | 88 | btn.forEach((e, i) => { |
| 61 | e.style.width = "310px" | 89 | e.style.width = '310px'; |
| 62 | e.style.padding = "0.4em 0 0 11px" | 90 | e.style.padding = '0.4em 0 0 11px'; |
| 63 | setTimeout(() => { | 91 | setTimeout(() => { |
| 64 | span[i].style.opacity = "1" | 92 | span[i].style.opacity = '1'; |
| 65 | }, 100) | 93 | }, 100); |
| 66 | }); | 94 | }); |
| 67 | side.style.zIndex = "2" | 95 | side.style.zIndex = '2'; |
| 68 | } else { | 96 | } else { |
| 69 | if (profile) { | 97 | if (profile) { |
| 70 | const login = document.querySelectorAll(".login>button")[1] as HTMLElement; | 98 | const login = document.querySelectorAll( |
| 71 | login.style.opacity = "0" | 99 | '.login>button' |
| 72 | uploadRunBtn.style.width = "40px" | 100 | )[1] as HTMLElement; |
| 73 | uploadRunBtn.style.padding = "0.4em 0 0 5px" | 101 | login.style.opacity = '0'; |
| 74 | uploadRunSpan.style.opacity = "0" | 102 | uploadRunBtn.style.width = '40px'; |
| 103 | uploadRunBtn.style.padding = '0.4em 0 0 5px'; | ||
| 104 | uploadRunSpan.style.opacity = '0'; | ||
| 75 | } | 105 | } |
| 76 | setSidebarOpen(true); | 106 | setSidebarOpen(true); |
| 77 | side.style.width = "40px"; | 107 | side.style.width = '40px'; |
| 78 | searchbar.focus(); | 108 | searchbar.focus(); |
| 79 | btn.forEach((e, i) => { | 109 | btn.forEach((e, i) => { |
| 80 | e.style.width = "40px" | 110 | e.style.width = '40px'; |
| 81 | e.style.padding = "0.4em 0 0 5px" | 111 | e.style.padding = '0.4em 0 0 5px'; |
| 82 | span[i].style.opacity = "0" | 112 | span[i].style.opacity = '0'; |
| 83 | }) | 113 | }); |
| 84 | setTimeout(() => { | 114 | setTimeout(() => { |
| 85 | side.style.zIndex = "0" | 115 | side.style.zIndex = '0'; |
| 86 | }, 300); | 116 | }, 300); |
| 87 | } | 117 | } |
| 88 | }; | 118 | }; |
| 89 | 119 | ||
| 90 | const _handle_sidebar_lock = () => { | 120 | const _handle_sidebar_lock = () => { |
| 91 | if (!isSidebarLocked) { | 121 | if (!isSidebarLocked) { |
| 92 | _handle_sidebar_hide() | 122 | _handle_sidebar_hide(); |
| 93 | setIsSidebarLocked(true); | 123 | setIsSidebarLocked(true); |
| 94 | setTimeout(() => setIsSidebarLocked(false), 300); | 124 | setTimeout(() => setIsSidebarLocked(false), 300); |
| 95 | } | 125 | } |
| @@ -101,98 +131,148 @@ const Sidebar: React.FC<SidebarProps> = ({ setToken, profile, setProfile, onUplo | |||
| 101 | }; | 131 | }; |
| 102 | 132 | ||
| 103 | React.useEffect(() => { | 133 | React.useEffect(() => { |
| 104 | if (path === "/") { handle_sidebar_click(1) } | 134 | if (path === '/') { |
| 105 | else if (path.includes("games")) { handle_sidebar_click(2) } | 135 | handle_sidebar_click(1); |
| 106 | else if (path.includes("rankings")) { handle_sidebar_click(3) } | 136 | } else if (path.includes('games')) { |
| 137 | handle_sidebar_click(2); | ||
| 138 | } else if (path.includes('rankings')) { | ||
| 139 | handle_sidebar_click(3); | ||
| 140 | } | ||
| 107 | // else if (path.includes("news")) { handle_sidebar_click(4) } | 141 | // else if (path.includes("news")) { handle_sidebar_click(4) } |
| 108 | // else if (path.includes("scorelog")) { handle_sidebar_click(5) } | 142 | // else if (path.includes("scorelog")) { handle_sidebar_click(5) } |
| 109 | else if (path.includes("profile")) { handle_sidebar_click(4) } | 143 | else if (path.includes('profile')) { |
| 110 | else if (path.includes("rules")) { handle_sidebar_click(5) } | 144 | handle_sidebar_click(4); |
| 111 | else if (path.includes("about")) { handle_sidebar_click(6) } | 145 | } else if (path.includes('rules')) { |
| 146 | handle_sidebar_click(5); | ||
| 147 | } else if (path.includes('about')) { | ||
| 148 | handle_sidebar_click(6); | ||
| 149 | } | ||
| 112 | }, [path]); | 150 | }, [path]); |
| 113 | 151 | ||
| 114 | return ( | 152 | return ( |
| 115 | <div id='sidebar'> | 153 | <div id="sidebar"> |
| 116 | <Link to="/" tabIndex={-1}> | 154 | <Link to="/" tabIndex={-1}> |
| 117 | <div id='logo'> {/* logo */} | 155 | <div id="logo"> |
| 118 | <img src={LogoIcon} alt="" height={"80px"} /> | 156 | {' '} |
| 119 | <div id='logo-text'> | 157 | {/* logo */} |
| 120 | <span><b>PORTAL 2</b></span><br /> | 158 | <img src={LogoIcon} alt="" height={'80px'} /> |
| 159 | <div id="logo-text"> | ||
| 160 | <span> | ||
| 161 | <b>PORTAL 2</b> | ||
| 162 | </span> | ||
| 163 | <br /> | ||
| 121 | <span>Least Portals Hub</span> | 164 | <span>Least Portals Hub</span> |
| 122 | </div> | 165 | </div> |
| 123 | </div> | 166 | </div> |
| 124 | </Link> | 167 | </Link> |
| 125 | <div id='sidebar-list'> {/* List */} | 168 | <div id="sidebar-list"> |
| 126 | <div id='sidebar-toplist'> {/* Top */} | 169 | {' '} |
| 127 | 170 | {/* List */} | |
| 128 | <button className='sidebar-button' onClick={() => _handle_sidebar_lock()}><img src={SearchIcon} alt="" /><span>Search</span></button> | 171 | <div id="sidebar-toplist"> |
| 129 | 172 | {' '} | |
| 173 | {/* Top */} | ||
| 174 | <button | ||
| 175 | className="sidebar-button" | ||
| 176 | onClick={() => _handle_sidebar_lock()} | ||
| 177 | > | ||
| 178 | <img src={SearchIcon} alt="" /> | ||
| 179 | <span>Search</span> | ||
| 180 | </button> | ||
| 130 | <span></span> | 181 | <span></span> |
| 131 | |||
| 132 | <Link to="/" tabIndex={-1}> | 182 | <Link to="/" tabIndex={-1}> |
| 133 | <button className='sidebar-button'><img src={HomeIcon} alt="homepage" /><span>Home Page</span></button> | 183 | <button className="sidebar-button"> |
| 184 | <img src={HomeIcon} alt="homepage" /> | ||
| 185 | <span>Home Page</span> | ||
| 186 | </button> | ||
| 134 | </Link> | 187 | </Link> |
| 135 | |||
| 136 | <Link to="/games" tabIndex={-1}> | 188 | <Link to="/games" tabIndex={-1}> |
| 137 | <button className='sidebar-button'><img src={PortalIcon} alt="games" /><span>Games</span></button> | 189 | <button className="sidebar-button"> |
| 190 | <img src={PortalIcon} alt="games" /> | ||
| 191 | <span>Games</span> | ||
| 192 | </button> | ||
| 138 | </Link> | 193 | </Link> |
| 139 | |||
| 140 | <Link to="/rankings" tabIndex={-1}> | 194 | <Link to="/rankings" tabIndex={-1}> |
| 141 | <button className='sidebar-button'><img src={FlagIcon} alt="rankings" /><span>Rankings</span></button> | 195 | <button className="sidebar-button"> |
| 196 | <img src={FlagIcon} alt="rankings" /> | ||
| 197 | <span>Rankings</span> | ||
| 198 | </button> | ||
| 142 | </Link> | 199 | </Link> |
| 143 | |||
| 144 | {/* <Link to="/news" tabIndex={-1}> | 200 | {/* <Link to="/news" tabIndex={-1}> |
| 145 | <button className='sidebar-button'><img src={NewsIcon} alt="news" /><span>News</span></button> | 201 | <button className='sidebar-button'><img src={NewsIcon} alt="news" /><span>News</span></button> |
| 146 | </Link> */} | 202 | </Link> */} |
| 147 | |||
| 148 | {/* <Link to="/scorelog" tabIndex={-1}> | 203 | {/* <Link to="/scorelog" tabIndex={-1}> |
| 149 | <button className='sidebar-button'><img src={TableIcon} alt="scorelogs" /><span>Score Logs</span></button> | 204 | <button className='sidebar-button'><img src={TableIcon} alt="scorelogs" /><span>Score Logs</span></button> |
| 150 | </Link> */} | 205 | </Link> */} |
| 151 | </div> | 206 | </div> |
| 152 | <div id='sidebar-bottomlist'> | 207 | <div id="sidebar-bottomlist"> |
| 153 | <span></span> | 208 | <span></span> |
| 154 | 209 | ||
| 155 | { | 210 | {profile && profile.profile ? ( |
| 156 | profile && profile.profile ? | 211 | <button |
| 157 | <button id='upload-run' className='submit-run-button' onClick={() => onUploadRun()}><img src={UploadIcon} alt="upload" /><span>Upload Record</span></button> | 212 | id="upload-run" |
| 158 | : | 213 | className="submit-run-button" |
| 159 | <span></span> | 214 | onClick={() => onUploadRun()} |
| 160 | } | 215 | > |
| 216 | <img src={UploadIcon} alt="upload" /> | ||
| 217 | <span>Upload Record</span> | ||
| 218 | </button> | ||
| 219 | ) : ( | ||
| 220 | <span></span> | ||
| 221 | )} | ||
| 161 | 222 | ||
| 162 | <Login setToken={setToken} profile={profile} setProfile={setProfile} /> | 223 | <Login |
| 224 | setToken={setToken} | ||
| 225 | profile={profile} | ||
| 226 | setProfile={setProfile} | ||
| 227 | /> | ||
| 163 | 228 | ||
| 164 | <Link to="/rules" tabIndex={-1}> | 229 | <Link to="/rules" tabIndex={-1}> |
| 165 | <button className='sidebar-button'><img src={BookIcon} alt="rules" /><span>Leaderboard Rules</span></button> | 230 | <button className="sidebar-button"> |
| 231 | <img src={BookIcon} alt="rules" /> | ||
| 232 | <span>Leaderboard Rules</span> | ||
| 233 | </button> | ||
| 166 | </Link> | 234 | </Link> |
| 167 | 235 | ||
| 168 | <Link to="/about" tabIndex={-1}> | 236 | <Link to="/about" tabIndex={-1}> |
| 169 | <button className='sidebar-button'><img src={HelpIcon} alt="about" /><span>About LPHUB</span></button> | 237 | <button className="sidebar-button"> |
| 238 | <img src={HelpIcon} alt="about" /> | ||
| 239 | <span>About LPHUB</span> | ||
| 240 | </button> | ||
| 170 | </Link> | 241 | </Link> |
| 171 | </div> | 242 | </div> |
| 172 | </div> | 243 | </div> |
| 173 | <div> | 244 | <div> |
| 174 | <input type="text" id='searchbar' placeholder='Search for map or a player...' onChange={(e) => _handle_search_change(e.target.value)} /> | 245 | <input |
| 175 | 246 | type="text" | |
| 176 | <div id='search-data'> | 247 | id="searchbar" |
| 248 | placeholder="Search for map or a player..." | ||
| 249 | onChange={e => _handle_search_change(e.target.value)} | ||
| 250 | /> | ||
| 177 | 251 | ||
| 252 | <div id="search-data"> | ||
| 178 | {searchData?.maps.map((q, index) => ( | 253 | {searchData?.maps.map((q, index) => ( |
| 179 | <Link to={`/maps/${q.id}`} className='search-map' key={index}> | 254 | <Link to={`/maps/${q.id}`} className="search-map" key={index}> |
| 180 | <span>{q.game}</span> | 255 | <span>{q.game}</span> |
| 181 | <span>{q.chapter}</span> | 256 | <span>{q.chapter}</span> |
| 182 | <span>{q.map}</span> | 257 | <span>{q.map}</span> |
| 183 | </Link> | 258 | </Link> |
| 184 | ))} | 259 | ))} |
| 185 | {searchData?.players.map((q, index) => | 260 | {searchData?.players.map((q, index) => ( |
| 186 | ( | 261 | <Link |
| 187 | <Link to={ | 262 | to={ |
| 188 | profile && q.steam_id === profile.steam_id ? `/profile` : | 263 | profile && q.steam_id === profile.steam_id |
| 189 | `/users/${q.steam_id}` | 264 | ? `/profile` |
| 190 | } className='search-player' key={index}> | 265 | : `/users/${q.steam_id}` |
| 191 | <img src={q.avatar_link} alt='pfp'></img> | 266 | } |
| 192 | <span style={{ fontSize: `${36 - q.user_name.length * 0.8}px` }}>{q.user_name}</span> | 267 | className="search-player" |
| 268 | key={index} | ||
| 269 | > | ||
| 270 | <img src={q.avatar_link} alt="pfp"></img> | ||
| 271 | <span style={{ fontSize: `${36 - q.user_name.length * 0.8}px` }}> | ||
| 272 | {q.user_name} | ||
| 273 | </span> | ||
| 193 | </Link> | 274 | </Link> |
| 194 | ))} | 275 | ))} |
| 195 | |||
| 196 | </div> | 276 | </div> |
| 197 | </div> | 277 | </div> |
| 198 | </div> | 278 | </div> |