diff options
Diffstat (limited to 'frontend/src/components')
| -rw-r--r-- | frontend/src/components/Sidebar.tsx | 174 |
1 files changed, 106 insertions, 68 deletions
diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index 67f7f3d..f972c6f 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx | |||
| @@ -19,7 +19,9 @@ const Sidebar: React.FC<SidebarProps> = ({ setToken, profile, setProfile, onUplo | |||
| 19 | 19 | ||
| 20 | const [searchData, setSearchData] = React.useState<Search | undefined>(undefined); | 20 | const [searchData, setSearchData] = React.useState<Search | undefined>(undefined); |
| 21 | const [isSidebarLocked, setIsSidebarLocked] = React.useState<boolean>(false); | 21 | const [isSidebarLocked, setIsSidebarLocked] = React.useState<boolean>(false); |
| 22 | const [isSidebarOpen, setSidebarOpen] = React.useState<boolean>(true); | 22 | const [isSidebarOpen, setSidebarOpen] = React.useState<boolean>(false); |
| 23 | const [isMobileMenuOpen, setIsMobileMenuOpen] = React.useState<boolean>(false); | ||
| 24 | const [isMobileSearchOpen, setIsMobileSearchOpen] = React.useState<boolean>(false); | ||
| 23 | 25 | ||
| 24 | const location = useLocation(); | 26 | const location = useLocation(); |
| 25 | const path = location.pathname; | 27 | const path = location.pathname; |
| @@ -88,18 +90,34 @@ const Sidebar: React.FC<SidebarProps> = ({ setToken, profile, setProfile, onUplo | |||
| 88 | }; | 90 | }; |
| 89 | 91 | ||
| 90 | const _handle_sidebar_lock = () => { | 92 | const _handle_sidebar_lock = () => { |
| 91 | if (!isSidebarLocked) { | 93 | if (window.innerWidth <= 768) { |
| 92 | _handle_sidebar_hide() | 94 | setIsMobileSearchOpen(!isMobileSearchOpen); |
| 93 | setIsSidebarLocked(true); | 95 | } else { |
| 94 | setTimeout(() => setIsSidebarLocked(false), 300); | 96 | if (!isSidebarLocked) { |
| 97 | _handle_sidebar_hide() | ||
| 98 | setIsSidebarLocked(true); | ||
| 99 | setTimeout(() => setIsSidebarLocked(false), 300); | ||
| 100 | } | ||
| 95 | } | 101 | } |
| 96 | }; | 102 | }; |
| 97 | 103 | ||
| 104 | const _close_mobile_search = () => { | ||
| 105 | setIsMobileSearchOpen(false); | ||
| 106 | }; | ||
| 107 | |||
| 98 | const _handle_search_change = async (q: string) => { | 108 | const _handle_search_change = async (q: string) => { |
| 99 | const searchResponse = await API.get_search(q); | 109 | const searchResponse = await API.get_search(q); |
| 100 | setSearchData(searchResponse); | 110 | setSearchData(searchResponse); |
| 101 | }; | 111 | }; |
| 102 | 112 | ||
| 113 | const _toggle_mobile_menu = () => { | ||
| 114 | setIsMobileMenuOpen(!isMobileMenuOpen); | ||
| 115 | }; | ||
| 116 | |||
| 117 | const _close_mobile_menu = () => { | ||
| 118 | setIsMobileMenuOpen(false); | ||
| 119 | }; | ||
| 120 | |||
| 103 | React.useEffect(() => { | 121 | React.useEffect(() => { |
| 104 | if (path === "/") { handle_sidebar_click(1) } | 122 | if (path === "/") { handle_sidebar_click(1) } |
| 105 | else if (path.includes("games")) { handle_sidebar_click(2) } | 123 | else if (path.includes("games")) { handle_sidebar_click(2) } |
| @@ -112,90 +130,110 @@ const Sidebar: React.FC<SidebarProps> = ({ setToken, profile, setProfile, onUplo | |||
| 112 | }, [path]); | 130 | }, [path]); |
| 113 | 131 | ||
| 114 | return ( | 132 | return ( |
| 115 | <div id='sidebar'> | 133 | <> |
| 116 | <Link to="/" tabIndex={-1}> | 134 | <div id='mobile-topbar'> |
| 117 | <div id='logo'> {/* logo */} | 135 | <Link to="/" tabIndex={-1}> |
| 118 | <img src={LogoIcon} alt="" height={"80px"} /> | 136 | <div id='mobile-logo'> |
| 119 | <div id='logo-text'> | 137 | <img src={LogoIcon} alt="" height={"50px"} /> |
| 120 | <span><b>PORTAL 2</b></span><br /> | 138 | <div id='mobile-logo-text'> |
| 121 | <span>Least Portals Hub</span> | 139 | <span><b>LPHUB</b></span> |
| 140 | </div> | ||
| 122 | </div> | 141 | </div> |
| 123 | </div> | 142 | </Link> |
| 124 | </Link> | 143 | <button id='hamburger-menu' onClick={_toggle_mobile_menu} className={isMobileMenuOpen ? 'open' : ''}> |
| 125 | <div id='sidebar-list'> {/* List */} | 144 | <span></span> |
| 126 | <div id='sidebar-toplist'> {/* Top */} | 145 | <span></span> |
| 146 | <span></span> | ||
| 147 | </button> | ||
| 148 | </div> | ||
| 149 | <div id='sidebar' className={isMobileMenuOpen ? 'mobile-open' : ''}> | ||
| 150 | <Link to="/" tabIndex={-1}> | ||
| 151 | <div id='logo'> {/* logo */} | ||
| 152 | <img src={LogoIcon} alt="" height={"80px"} /> | ||
| 153 | <div id='logo-text'> | ||
| 154 | <span><b>PORTAL 2</b></span><br /> | ||
| 155 | <span>Least Portals Hub</span> | ||
| 156 | </div> | ||
| 157 | </div> | ||
| 158 | </Link> | ||
| 159 | <div id='sidebar-list'> {/* List */} | ||
| 160 | <div id='sidebar-toplist'> {/* Top */} | ||
| 127 | 161 | ||
| 128 | <button className='sidebar-button' onClick={() => _handle_sidebar_lock()}><img src={SearchIcon} alt="" /><span>Search</span></button> | 162 | <button className='sidebar-button' onClick={() => _handle_sidebar_lock()}><img src={SearchIcon} alt="" /><span>Search</span></button> |
| 129 | 163 | ||
| 130 | <span></span> | 164 | <span></span> |
| 131 | 165 | ||
| 132 | <Link to="/" tabIndex={-1}> | 166 | <Link to="/" tabIndex={-1} onClick={_close_mobile_menu}> |
| 133 | <button className='sidebar-button'><img src={HomeIcon} alt="homepage" /><span>Home Page</span></button> | 167 | <button className='sidebar-button'><img src={HomeIcon} alt="homepage" /><span>Home Page</span></button> |
| 134 | </Link> | 168 | </Link> |
| 135 | 169 | ||
| 136 | <Link to="/games" tabIndex={-1}> | 170 | <Link to="/games" tabIndex={-1} onClick={_close_mobile_menu}> |
| 137 | <button className='sidebar-button'><img src={PortalIcon} alt="games" /><span>Games</span></button> | 171 | <button className='sidebar-button'><img src={PortalIcon} alt="games" /><span>Games</span></button> |
| 138 | </Link> | 172 | </Link> |
| 139 | 173 | ||
| 140 | <Link to="/rankings" tabIndex={-1}> | 174 | <Link to="/rankings" tabIndex={-1} onClick={_close_mobile_menu}> |
| 141 | <button className='sidebar-button'><img src={FlagIcon} alt="rankings" /><span>Rankings</span></button> | 175 | <button className='sidebar-button'><img src={FlagIcon} alt="rankings" /><span>Rankings</span></button> |
| 142 | </Link> | 176 | </Link> |
| 143 | 177 | ||
| 144 | {/* <Link to="/news" tabIndex={-1}> | 178 | {/* <Link to="/news" tabIndex={-1}> |
| 145 | <button className='sidebar-button'><img src={NewsIcon} alt="news" /><span>News</span></button> | 179 | <button className='sidebar-button'><img src={NewsIcon} alt="news" /><span>News</span></button> |
| 146 | </Link> */} | 180 | </Link> */} |
| 147 | 181 | ||
| 148 | {/* <Link to="/scorelog" tabIndex={-1}> | 182 | {/* <Link to="/scorelog" tabIndex={-1}> |
| 149 | <button className='sidebar-button'><img src={TableIcon} alt="scorelogs" /><span>Score Logs</span></button> | 183 | <button className='sidebar-button'><img src={TableIcon} alt="scorelogs" /><span>Score Logs</span></button> |
| 150 | </Link> */} | 184 | </Link> */} |
| 151 | </div> | 185 | </div> |
| 152 | <div id='sidebar-bottomlist'> | 186 | <div id='sidebar-bottomlist'> |
| 153 | <span></span> | 187 | <span></span> |
| 154 | 188 | ||
| 155 | { | 189 | { |
| 156 | profile && profile.profile ? | 190 | profile && profile.profile ? |
| 157 | <button id='upload-run' className='submit-run-button' onClick={() => onUploadRun()}><img src={UploadIcon} alt="upload" /><span>Upload Record</span></button> | 191 | <button id='upload-run' className='submit-run-button' onClick={() => onUploadRun()}><img src={UploadIcon} alt="upload" /><span>Upload Record</span></button> |
| 158 | : | 192 | : |
| 159 | <span></span> | 193 | <span></span> |
| 160 | } | 194 | } |
| 161 | 195 | ||
| 162 | <Login setToken={setToken} profile={profile} setProfile={setProfile} /> | 196 | <Login setToken={setToken} profile={profile} setProfile={setProfile} /> |
| 163 | 197 | ||
| 164 | <Link to="/rules" tabIndex={-1}> | 198 | <Link to="/rules" tabIndex={-1} onClick={_close_mobile_menu}> |
| 165 | <button className='sidebar-button'><img src={BookIcon} alt="rules" /><span>Leaderboard Rules</span></button> | 199 | <button className='sidebar-button'><img src={BookIcon} alt="rules" /><span>Leaderboard Rules</span></button> |
| 166 | </Link> | 200 | </Link> |
| 167 | 201 | ||
| 168 | <Link to="/about" tabIndex={-1}> | 202 | <Link to="/about" tabIndex={-1} onClick={_close_mobile_menu}> |
| 169 | <button className='sidebar-button'><img src={HelpIcon} alt="about" /><span>About LPHUB</span></button> | 203 | <button className='sidebar-button'><img src={HelpIcon} alt="about" /><span>About LPHUB</span></button> |
| 170 | </Link> | 204 | </Link> |
| 205 | </div> | ||
| 171 | </div> | 206 | </div> |
| 172 | </div> | 207 | <div id='search-panel' className={isMobileSearchOpen ? 'mobile-search-open' : ''}> |
| 173 | <div> | 208 | <input type="text" id='searchbar' placeholder='Search for map or a player...' onChange={(e) => _handle_search_change(e.target.value)} /> |
| 174 | <input type="text" id='searchbar' placeholder='Search for map or a player...' onChange={(e) => _handle_search_change(e.target.value)} /> | 209 | <div className='mobile-search-header'> |
| 210 | <button className='mobile-search-close' onClick={_close_mobile_search}>✕</button> | ||
| 211 | </div> | ||
| 175 | 212 | ||
| 176 | <div id='search-data'> | 213 | <div id='search-data'> |
| 177 | 214 | ||
| 178 | {searchData?.maps.map((q, index) => ( | 215 | {searchData?.maps.map((q, index) => ( |
| 179 | <Link to={`/maps/${q.id}`} className='search-map' key={index}> | 216 | <Link to={`/maps/${q.id}`} className='search-map' key={index} onClick={_close_mobile_search}> |
| 180 | <span>{q.game}</span> | 217 | <span>{q.game}</span> |
| 181 | <span>{q.chapter}</span> | 218 | <span>{q.chapter}</span> |
| 182 | <span>{q.map}</span> | 219 | <span>{q.map}</span> |
| 183 | </Link> | 220 | </Link> |
| 184 | ))} | 221 | ))} |
| 185 | {searchData?.players.map((q, index) => | 222 | {searchData?.players.map((q, index) => |
| 186 | ( | 223 | ( |
| 187 | <Link to={ | 224 | <Link to={ |
| 188 | profile && q.steam_id === profile.steam_id ? `/profile` : | 225 | profile && q.steam_id === profile.steam_id ? `/profile` : |
| 189 | `/users/${q.steam_id}` | 226 | `/users/${q.steam_id}` |
| 190 | } className='search-player' key={index}> | 227 | } className='search-player' key={index} onClick={_close_mobile_search}> |
| 191 | <img src={q.avatar_link} alt='pfp'></img> | 228 | <img src={q.avatar_link} alt='pfp'></img> |
| 192 | <span style={{ fontSize: `${36 - q.user_name.length * 0.8}px` }}>{q.user_name}</span> | 229 | <span style={{ fontSize: `${36 - q.user_name.length * 0.8}px` }}>{q.user_name}</span> |
| 193 | </Link> | 230 | </Link> |
| 194 | ))} | 231 | ))} |
| 195 | 232 | ||
| 233 | </div> | ||
| 196 | </div> | 234 | </div> |
| 197 | </div> | 235 | </div> |
| 198 | </div> | 236 | </> |
| 199 | ); | 237 | ); |
| 200 | }; | 238 | }; |
| 201 | 239 | ||