From b1fd0cdeff287e4cf0ec180ff9fee804cb2c8b8d Mon Sep 17 00:00:00 2001 From: Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> Date: Wed, 22 Oct 2025 01:52:05 +0400 Subject: feat/frontend: add general mobile support (#275) --- frontend/src/App.css | 53 ++- frontend/src/api/Api.ts | 6 +- frontend/src/components/Sidebar.tsx | 174 ++++++---- frontend/src/css/About.css | 23 +- frontend/src/css/Dialog.css | 37 +- frontend/src/css/Games.css | 48 +++ frontend/src/css/Login.css | 10 +- frontend/src/css/Maplist.css | 47 ++- frontend/src/css/Maps.css | 650 +++++++++++++++++++++++++---------- frontend/src/css/ModMenu.css | 148 ++++++-- frontend/src/css/Profile.css | 229 +++++++++--- frontend/src/css/Rankings.css | 33 +- frontend/src/css/Rules.css | 6 + frontend/src/css/Sidebar.css | 380 ++++++++++++++++---- frontend/src/css/UploadRunDialog.css | 124 +++++-- 15 files changed, 1495 insertions(+), 473 deletions(-) (limited to 'frontend') diff --git a/frontend/src/App.css b/frontend/src/App.css index 14a9972..eb39d85 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -2,17 +2,14 @@ main { overflow: auto; overflow-x: hidden; position: relative; - - width: calc(100% - 380px); + width: calc(100% - 23.75rem); height: 100vh; - left: 350px; - - padding-right: 30px; - - font-size: 40px; + left: 21.875rem; + padding-right: 1.875rem; + font-size: 2.5rem; font-family: BarlowSemiCondensed-Regular; color: #cdcfdf; - + transition: all 0.3s ease; } a { @@ -39,7 +36,7 @@ body { background-image: linear-gradient(-90deg, #202232 0%, #202232 25%, #2a2c41 50%, #202232 75%, #202232 100%); user-select: none; color: #00000000; - border-radius: 1000px; + border-radius: 62.5rem; } @keyframes loader { @@ -57,20 +54,21 @@ body { } .loader { - width: 48px; - height: 48px; - border: 5px solid #FFF; + width: 3rem; + height: 3rem; + border: 0.3125rem solid #FFF; border-bottom-color: transparent; border-radius: 50%; display: inline-block; box-sizing: border-box; animation: rotation 1s linear infinite; - } +} @keyframes rotation { 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } @@ -95,3 +93,32 @@ body { font-family: 'BarlowSemiCondensed-SemiBold'; src: local('BarlowSemiCondensed-Regular'), url(./fonts/BarlowSemiCondensed-SemiBold.ttf) format('truetype'); } + +@media screen and (max-width: 768px) { + * { + box-sizing: border-box; + } + + main { + width: 100%; + left: 0; + padding: 5rem 20px 1rem 20px; + height: auto; + min-height: 100vh; + font-size: 1.5rem; + } + + .loader { + width: 2.5rem; + height: 2.5rem; + border: 0.25rem solid #FFF; + } +} + +@media screen and (min-width: 1920px) { + main { + width: calc(100% - 25rem); + left: 23rem; + padding-right: 2rem; + } +} \ No newline at end of file diff --git a/frontend/src/api/Api.ts b/frontend/src/api/Api.ts index 862e688..c84714d 100644 --- a/frontend/src/api/Api.ts +++ b/frontend/src/api/Api.ts @@ -12,7 +12,7 @@ import { UploadRunContent } from '@customTypes/Content'; export const API = { // Auth get_token: () => get_token(), - + delete_token: () => delete_token(), // User get_user: (user_id: string) => get_user(user_id), @@ -42,10 +42,10 @@ export const API = { delete_map_record: (token: string, map_id: number, record_id: number) => delete_map_record(token, map_id, record_id), // Mod post_map_summary: (token: string, map_id: string, content: ModMenuContent) => post_map_summary(token, map_id, content), - + put_map_image: (token: string, map_id: string, image: string) => put_map_image(token, map_id, image), put_map_summary: (token: string, map_id: string, content: ModMenuContent) => put_map_summary(token, map_id, content), - + delete_map_summary: (token: string, map_id: string, route_id: number) => delete_map_summary(token, map_id, route_id), }; 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 = ({ setToken, profile, setProfile, onUplo const [searchData, setSearchData] = React.useState(undefined); const [isSidebarLocked, setIsSidebarLocked] = React.useState(false); - const [isSidebarOpen, setSidebarOpen] = React.useState(true); + const [isSidebarOpen, setSidebarOpen] = React.useState(false); + const [isMobileMenuOpen, setIsMobileMenuOpen] = React.useState(false); + const [isMobileSearchOpen, setIsMobileSearchOpen] = React.useState(false); const location = useLocation(); const path = location.pathname; @@ -88,18 +90,34 @@ const Sidebar: React.FC = ({ setToken, profile, setProfile, onUplo }; const _handle_sidebar_lock = () => { - if (!isSidebarLocked) { - _handle_sidebar_hide() - setIsSidebarLocked(true); - setTimeout(() => setIsSidebarLocked(false), 300); + if (window.innerWidth <= 768) { + setIsMobileSearchOpen(!isMobileSearchOpen); + } else { + if (!isSidebarLocked) { + _handle_sidebar_hide() + setIsSidebarLocked(true); + setTimeout(() => setIsSidebarLocked(false), 300); + } } }; + const _close_mobile_search = () => { + setIsMobileSearchOpen(false); + }; + const _handle_search_change = async (q: string) => { const searchResponse = await API.get_search(q); setSearchData(searchResponse); }; + const _toggle_mobile_menu = () => { + setIsMobileMenuOpen(!isMobileMenuOpen); + }; + + const _close_mobile_menu = () => { + setIsMobileMenuOpen(false); + }; + React.useEffect(() => { if (path === "/") { handle_sidebar_click(1) } else if (path.includes("games")) { handle_sidebar_click(2) } @@ -112,90 +130,110 @@ const Sidebar: React.FC = ({ setToken, profile, setProfile, onUplo }, [path]); return ( -