aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/components/Sidebar.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/components/Sidebar.tsx')
-rw-r--r--frontend/src/components/Sidebar.tsx174
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&nbsp;Page</span></button> 167 <button className='sidebar-button'><img src={HomeIcon} alt="homepage" /><span>Home&nbsp;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&nbsp;Logs</span></button> 183 <button className='sidebar-button'><img src={TableIcon} alt="scorelogs" /><span>Score&nbsp;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&nbsp;Record</span></button> 191 <button id='upload-run' className='submit-run-button' onClick={() => onUploadRun()}><img src={UploadIcon} alt="upload" /><span>Upload&nbsp;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&nbsp;Rules</span></button> 199 <button className='sidebar-button'><img src={BookIcon} alt="rules" /><span>Leaderboard&nbsp;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&nbsp;LPHUB</span></button> 203 <button className='sidebar-button'><img src={HelpIcon} alt="about" /><span>About&nbsp;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