aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/components/Sidebar
diff options
context:
space:
mode:
authorWolfboy248 <georgejvindkarlsen@gmail.com>2025-08-25 09:36:51 +0200
committerWolfboy248 <georgejvindkarlsen@gmail.com>2025-08-25 09:36:51 +0200
commit246eabe4a46d2585d653738e46089ed2bfada8bd (patch)
treec86dd05119b0aa086a5d5401dd6a48d90a6f3bbd /frontend/src/components/Sidebar
parentReorganised Maplist and Sidebar (diff)
downloadlphub-246eabe4a46d2585d653738e46089ed2bfada8bd.tar.gz
lphub-246eabe4a46d2585d653738e46089ed2bfada8bd.tar.bz2
lphub-246eabe4a46d2585d653738e46089ed2bfada8bd.zip
Restructured sidebar and implemented links var
Diffstat (limited to '')
-rw-r--r--frontend/src/components/Sidebar/Content.tsx117
-rw-r--r--frontend/src/components/Sidebar/Footer.tsx56
-rw-r--r--frontend/src/components/Sidebar/Header.tsx6
-rw-r--r--frontend/src/components/Sidebar/Links.ts53
-rw-r--r--frontend/src/components/Sidebar/Search.tsx66
-rw-r--r--frontend/src/components/Sidebar/Sidebar.module.css16
-rw-r--r--frontend/src/components/Sidebar/Sidebar.tsx82
7 files changed, 211 insertions, 185 deletions
diff --git a/frontend/src/components/Sidebar/Content.tsx b/frontend/src/components/Sidebar/Content.tsx
index 4051b08..3d9533a 100644
--- a/frontend/src/components/Sidebar/Content.tsx
+++ b/frontend/src/components/Sidebar/Content.tsx
@@ -1,124 +1,45 @@
1import React, { useRef } from "react"; 1import React, { useRef } from "react";
2import { Link } from "react-router-dom"; 2import { Link, useLocation } from "react-router-dom";
3import { UserProfile } from "@customTypes/Profile"; 3import { UserProfile } from "@customTypes/Profile";
4import { Search } from "@customTypes/Search";
5import { API } from "@api/Api";
6 4
7import styles from "./Sidebar.module.css"; 5import styles from "./Sidebar.module.css";
8 6
9import { 7import {
10 FlagIcon,
11 HomeIcon,
12 PortalIcon,
13 SearchIcon, 8 SearchIcon,
14} from "../../images/Images"; 9} from "../../images/Images";
15 10
11import links from "./Links";
12
16interface ContentProps { 13interface ContentProps {
17 profile?: UserProfile; 14 profile?: UserProfile;
15 isSearching: boolean;
16 selectedButtonIndex: number
18 isSidebarOpen: boolean; 17 isSidebarOpen: boolean;
19 sidebarButtonRefs: React.RefObject<(HTMLButtonElement | null)[]>;
20 getButtonClasses: (buttonIndex: number) => string;
21 handle_sidebar_click: (clicked_sidebar_idx: number) => void; 18 handle_sidebar_click: (clicked_sidebar_idx: number) => void;
22}; 19};
23 20
24const Content: React.FC<ContentProps> = ({ profile, isSidebarOpen, sidebarButtonRefs, getButtonClasses, handle_sidebar_click }) => { 21const _Content: React.FC<ContentProps> = ({ profile, isSearching, selectedButtonIndex, isSidebarOpen, handle_sidebar_click }) => {
25 const [searchData, setSearchData] = React.useState<Search | undefined>(
26 undefined
27 );
28
29 const searchbarRef = useRef<HTMLInputElement>(null);
30
31 const _handle_search_change = async (q: string) => {
32 const searchResponse = await API.get_search(q);
33 setSearchData(searchResponse);
34 };
35
36 const iconClasses = "";
37 22
38 return ( 23 return (
39 <div className="h-full"> 24 <div className="h-full">
40 25
41 <div className="px-2"> 26 <div className="px-2 my-2.5">
42 <div className={`${styles.button}`}> 27 <button onClick={() => handle_sidebar_click(0)} className={`${styles.button} ${selectedButtonIndex == 0 ? styles["button-selected"] : ""} ${isSearching ? styles["button-hidden"] : ""}`}>
43 <img src={SearchIcon} alt="Search" className={iconClasses} /> 28 <img src={SearchIcon} alt="Search" />
44 <span className="text-white font-[--font-barlow-semicondensed-regular] truncate">Search</span> 29 <span>Search</span>
45 </div> 30 </button>
46
47 <div className="min-w-0">
48 <input
49 ref={searchbarRef}
50 type="text"
51 id="searchbar"
52 placeholder="Search for map or a player..."
53 onChange={e => _handle_search_change(e.target.value)}
54 className="w-full p-2 bg-input text-foreground border border-border rounded-lg text-sm min-w-0"
55 />
56
57 {searchData && (
58 <div className="mt-2 max-h-40 overflow-y-auto min-w-0">
59 {searchData?.maps.map((q, index) => (
60 <Link to={`/maps/${q.id}`} className="block p-2 mb-1 bg-surface1 rounded hover:bg-surface2 transition-colors min-w-0" key={index}>
61 <span className="block text-xs text-subtext1 truncate">{q.game}</span>
62 <span className="block text-xs text-subtext1 truncate">{q.chapter}</span>
63 <span className="block text-sm text-foreground truncate">{q.map}</span>
64 </Link>
65 ))}
66 {searchData?.players.map((q, index) => (
67 <Link
68 to={
69 profile && q.steam_id === profile.steam_id
70 ? `/profile`
71 : `/users/${q.steam_id}`
72 }
73 className="flex items-center p-2 mb-1 bg-surface1 rounded hover:bg-surface2 transition-colors min-w-0"
74 key={index}
75 >
76 <img src={q.avatar_link} alt="pfp" className="w-6 h-6 rounded-full mr-2 flex-shrink-0" />
77 <span className="text-sm text-foreground truncate">
78 {q.user_name}
79 </span>
80 </Link>
81 ))}
82 </div>
83 )}
84 </div>
85 </div> 31 </div>
86 32
87 <div className="flex-1 min-w-0"> 33 <div className="flex-1 min-w-0 mt-12">
88 <nav className="px-2 flex flex-col gap-2"> 34 <nav className="px-2 flex flex-col gap-2">
89 {[ 35 {links.content.map(({ to, icon, label }, i) => (
90 { 36 <Link to={to} tabIndex={-1} key={i + 1}>
91 to: "/",
92 refIndex: 1,
93 icon: HomeIcon,
94 alt: "Home",
95 label: "Home Page",
96 },
97 {
98 to: "/games",
99 refIndex: 2,
100 icon: PortalIcon,
101 alt: "Games",
102 label: "Games",
103 },
104 {
105 to: "/rankings",
106 refIndex: 3,
107 icon: FlagIcon,
108 alt: "Rankings",
109 label: "Rankings",
110 },
111 ].map(({ to, refIndex, icon, alt, label }) => (
112 <Link to={to} tabIndex={-1} key={refIndex}>
113 <button 37 <button
114 ref={el => { 38 className={`${styles.button} ${selectedButtonIndex == i + 1 ? styles["button-selected"] : ""} ${isSearching ? styles["button-hidden"] : ""}`}
115 sidebarButtonRefs.current[refIndex] = el 39 onClick={() => handle_sidebar_click(i + 1)}
116 }}
117 className={`${styles.button}`}
118 onClick={() => handle_sidebar_click(refIndex)}
119 > 40 >
120 <img src={icon} alt={alt} className={iconClasses} /> 41 <img src={icon} />
121 <span className=""> 42 <span>
122 {label} 43 {label}
123 </span> 44 </span>
124 </button> 45 </button>
@@ -130,4 +51,4 @@ const Content: React.FC<ContentProps> = ({ profile, isSidebarOpen, sidebarButton
130 ); 51 );
131} 52}
132 53
133export default Content; 54export default _Content;
diff --git a/frontend/src/components/Sidebar/Footer.tsx b/frontend/src/components/Sidebar/Footer.tsx
index 070301a..8e910b3 100644
--- a/frontend/src/components/Sidebar/Footer.tsx
+++ b/frontend/src/components/Sidebar/Footer.tsx
@@ -12,26 +12,28 @@ import {
12 HelpIcon, 12 HelpIcon,
13} from "../../images/Images"; 13} from "../../images/Images";
14 14
15import links from "./Links";
16
15interface FooterProps { 17interface FooterProps {
16 profile?: UserProfile; 18 profile?: UserProfile;
19 isSearching: boolean;
20 selectedButtonIndex: number;
17 onUploadRun: () => void; 21 onUploadRun: () => void;
18 setProfile: React.Dispatch<React.SetStateAction<UserProfile | undefined>>; 22 setProfile: React.Dispatch<React.SetStateAction<UserProfile | undefined>>;
19 setToken: React.Dispatch<React.SetStateAction<string | undefined>>; 23 setToken: React.Dispatch<React.SetStateAction<string | undefined>>;
20 sidebarButtonRefs: React.RefObject<(HTMLButtonElement | null)[]>;
21 getButtonClasses: (buttonIndex: number) => string;
22 handle_sidebar_click: (clicked_sidebar_idx: number) => void; 24 handle_sidebar_click: (clicked_sidebar_idx: number) => void;
23}; 25};
24 26
25const Footer: React.FC<FooterProps> = ({ profile, onUploadRun, setToken, setProfile, sidebarButtonRefs, getButtonClasses, handle_sidebar_click }) => { 27const _Footer: React.FC<FooterProps> = ({ profile, isSearching, selectedButtonIndex, onUploadRun, setToken, setProfile, handle_sidebar_click }) => {
26 const uploadRunRef = useRef<HTMLButtonElement>(null); 28 const uploadRunRef = useRef<HTMLButtonElement>(null);
27 29
28 return ( 30 return (
29 <div className=""> 31 <div className="px-2 gap-2 flex flex-col mb-2">
30 {profile && profile.profile && ( 32 {profile && profile.profile && (
31 <button 33 <button
32 ref={uploadRunRef} 34 ref={uploadRunRef}
33 id="upload-run" 35 id="upload-run"
34 className={getButtonClasses(-1)} 36 className={``}
35 onClick={() => onUploadRun()} 37 onClick={() => onUploadRun()}
36 > 38 >
37 <img src={UploadIcon} alt="Upload" className={``} /> 39 <img src={UploadIcon} alt="Upload" className={``} />
@@ -39,42 +41,30 @@ const Footer: React.FC<FooterProps> = ({ profile, onUploadRun, setToken, setProf
39 </button> 41 </button>
40 )} 42 )}
41 43
42 <div className={true ? 'min-w-0' : 'flex justify-center'}> 44 {/* <div className={true ? 'min-w-0' : 'flex justify-center'}>
43 <Login 45 <Login
44 setToken={setToken} 46 setToken={setToken}
45 profile={profile} 47 profile={profile}
46 setProfile={setProfile} 48 setProfile={setProfile}
47 isOpen={true} 49 isOpen={true}
48 /> 50 />
49 </div> 51 </div> */}
50
51 <Link to="/rules" tabIndex={-1}>
52 <button
53 ref={el => {
54 sidebarButtonRefs.current[5] = el
55 }}
56 className={`${styles.button}`}
57 onClick={() => handle_sidebar_click(5)}
58 >
59 <img src={BookIcon} alt="Rules" />
60 {true && <span className="font-[--font-barlow-semicondensed-regular] truncate">Leaderboard Rules</span>}
61 </button>
62 </Link>
63 52
64 <Link to="/about" tabIndex={-1}> 53 {links.footer.map(({ to, icon, label }, i) => (
65 <button 54 <Link to={to} tabIndex={-1} key={i}>
66 ref={el => { 55 <button
67 sidebarButtonRefs.current[6] = el 56 className={`${styles.button} ${selectedButtonIndex == links.content.length + i + 1 ? styles["button-selected"] : ""} ${isSearching ? styles["button-hidden"] : ""}`}
68 }} 57 onClick={() => handle_sidebar_click(links.content.length + i + 1)}
69 className={`${styles.button}`} 58 >
70 onClick={() => handle_sidebar_click(6)} 59 <img src={icon} />
71 > 60 <span className="">
72 <img src={HelpIcon} alt="About" /> 61 {label}
73 {true && <span className="font-[--font-barlow-semicondensed-regular] truncate">About LPHUB</span>} 62 </span>
74 </button> 63 </button>
75 </Link> 64 </Link>
65 ))}
76 </div> 66 </div>
77 ); 67 );
78} 68}
79 69
80export default Footer; 70export default _Footer;
diff --git a/frontend/src/components/Sidebar/Header.tsx b/frontend/src/components/Sidebar/Header.tsx
index e990060..c317d38 100644
--- a/frontend/src/components/Sidebar/Header.tsx
+++ b/frontend/src/components/Sidebar/Header.tsx
@@ -5,9 +5,9 @@ import {
5 LogoIcon, 5 LogoIcon,
6} from "../../images/Images"; 6} from "../../images/Images";
7 7
8const Header: React.FC = () => { 8const _Header: React.FC = () => {
9 return ( 9 return (
10 <div className="flex justify-center px-4 py-3 bg-gradient-to-t from-block to-bright"> 10 <div className="flex justify-center px-4 py-3 bg-gradient-to-t from-block to-bright md:w-80">
11 <Link to="/" tabIndex={-1} className="flex gap-4"> 11 <Link to="/" tabIndex={-1} className="flex gap-4">
12 <img src={LogoIcon} alt="Logo" className="h-18 translate-y-0.5" /> 12 <img src={LogoIcon} alt="Logo" className="h-18 translate-y-0.5" />
13 <div className="text-[#fff] flex flex-col justify-center not-md:hidden"> 13 <div className="text-[#fff] flex flex-col justify-center not-md:hidden">
@@ -23,4 +23,4 @@ const Header: React.FC = () => {
23 ) 23 )
24} 24}
25 25
26export default Header; 26export default _Header;
diff --git a/frontend/src/components/Sidebar/Links.ts b/frontend/src/components/Sidebar/Links.ts
new file mode 100644
index 0000000..dfb621d
--- /dev/null
+++ b/frontend/src/components/Sidebar/Links.ts
@@ -0,0 +1,53 @@
1import {
2 FlagIcon,
3 HomeIcon,
4 PortalIcon,
5 BookIcon,
6 HelpIcon,
7} from "../../images/Images";
8
9export interface SidebarLink {
10 to: string;
11 icon: any;
12 label: string;
13};
14
15export interface SidebarLinks {
16 content: SidebarLink[];
17 footer: SidebarLink[];
18}
19
20const links: SidebarLinks = {
21 content: [
22 {
23 to: "/",
24 icon: HomeIcon,
25 label: "Home Page"
26 },
27 {
28 to: "/games",
29 icon: PortalIcon,
30 label: "Games"
31 },
32 {
33 to: "/rankings",
34 icon: FlagIcon,
35 label: "Rankings"
36 },
37 ],
38
39 footer: [
40 {
41 to: "/rules",
42 icon: BookIcon,
43 label: "Leaderboard Rules"
44 },
45 {
46 to: "/about",
47 icon: HelpIcon,
48 label: "About"
49 },
50 ]
51}
52
53export default links;
diff --git a/frontend/src/components/Sidebar/Search.tsx b/frontend/src/components/Sidebar/Search.tsx
new file mode 100644
index 0000000..0c6b868
--- /dev/null
+++ b/frontend/src/components/Sidebar/Search.tsx
@@ -0,0 +1,66 @@
1import React, { useRef } from "react";
2import { Link } from "react-router-dom";
3
4import { Search } from "@customTypes/Search";
5import { API } from "@api/Api";
6import { UserProfile } from "@customTypes/Profile";
7
8interface SearchProps {
9 profile?: UserProfile;
10 isSearching: boolean;
11};
12
13const _Search: React.FC<SearchProps> = ({ profile, isSearching }) => {
14 const [searchData, setSearchData] = React.useState<Search | undefined>(
15 undefined
16 );
17
18 const searchbarRef = useRef<HTMLInputElement>(null);
19
20 const _handle_search_change = async (q: string) => {
21 const searchResponse = await API.get_search(q);
22 setSearchData(searchResponse);
23 };
24 return (
25 <div className="flex w-full flex-col justify-between p-3">
26 <input
27 ref={searchbarRef}
28 type="text"
29 id="searchbar"
30 placeholder="Search for map or a player..."
31 onChange={e => _handle_search_change(e.target.value)}
32 className="w-full py-2 px-[19px] bg-input rounded-[2000px] outline-none placeholder-bright placeholder:text-[18px] placeholder:font-barlow-semicondensed-regular"
33 />
34
35 {searchData && (
36 <div className="overflow-y-auto">
37 {searchData?.maps.map((q, index) => (
38 <Link to={`/maps/${q.id}`} className="block p-2 mb-1 bg-surface1 rounded hover:bg-surface2 transition-colors min-w-0" key={index}>
39 <span className="block text-xs text-subtext1 truncate">{q.game}</span>
40 <span className="block text-xs text-subtext1 truncate">{q.chapter}</span>
41 <span className="block text-sm text-foreground truncate">{q.map}</span>
42 </Link>
43 ))}
44 {searchData?.players.map((q, index) => (
45 <Link
46 to={
47 profile && q.steam_id === profile.steam_id
48 ? `/profile`
49 : `/users/${q.steam_id}`
50 }
51 className="flex items-center p-2 mb-1 bg-surface1 rounded hover:bg-surface2 transition-colors min-w-0"
52 key={index}
53 >
54 <img src={q.avatar_link} alt="pfp" className="w-6 h-6 rounded-full mr-2 flex-shrink-0" />
55 <span className="text-sm text-foreground truncate">
56 {q.user_name}
57 </span>
58 </Link>
59 ))}
60 </div>
61 )}
62 </div>
63 )
64}
65
66export default _Search;
diff --git a/frontend/src/components/Sidebar/Sidebar.module.css b/frontend/src/components/Sidebar/Sidebar.module.css
index 8079676..9baf415 100644
--- a/frontend/src/components/Sidebar/Sidebar.module.css
+++ b/frontend/src/components/Sidebar/Sidebar.module.css
@@ -6,18 +6,30 @@
6 border-radius: 2000px; 6 border-radius: 2000px;
7 transition: all 0.2s ease; 7 transition: all 0.2s ease;
8 padding: 4px 0px; 8 padding: 4px 0px;
9 height: 48px;
9} 10}
10 11
11.button:hover { 12.button:hover,
13.button-selected,
14.button-selected:hover {
12 background-color: var(--color-panel); 15 background-color: var(--color-panel);
13} 16}
14 17
15.button>img { 18.button>img {
16 padding: 0px 8px;
17 height: 28px; 19 height: 28px;
20 width: 28px;
21 transform: translateX(10px);
18} 22}
19 23
20button>span { 24button>span {
21 font-size: 22px; 25 font-size: 22px;
22 font-family: var(--font-barlow-semicondensed-regular); 26 font-family: var(--font-barlow-semicondensed-regular);
27 white-space: nowrap;
28 margin-left: 16px;
29}
30
31.button-hidden>span {
32 cursor: none;
33 pointer-events: none;
34 opacity: 0;
23} \ No newline at end of file 35} \ No newline at end of file
diff --git a/frontend/src/components/Sidebar/Sidebar.tsx b/frontend/src/components/Sidebar/Sidebar.tsx
index 2dafa2b..1d58d2e 100644
--- a/frontend/src/components/Sidebar/Sidebar.tsx
+++ b/frontend/src/components/Sidebar/Sidebar.tsx
@@ -2,9 +2,11 @@ import React, { useCallback, useRef } from "react";
2import { Link, useLocation } from "react-router-dom"; 2import { Link, useLocation } from "react-router-dom";
3import { UserProfile } from "@customTypes/Profile"; 3import { UserProfile } from "@customTypes/Profile";
4 4
5import Header from "./Header"; 5import _Header from "./Header";
6import Footer from "./Footer"; 6import _Footer from "./Footer";
7import Content from "./Content"; 7import _Content from "./Content";
8import _Search from "./Search";
9import links from "./Links";
8 10
9interface SidebarProps { 11interface SidebarProps {
10 setToken: React.Dispatch<React.SetStateAction<string | undefined>>; 12 setToken: React.Dispatch<React.SetStateAction<string | undefined>>;
@@ -19,78 +21,60 @@ const Sidebar: React.FC<SidebarProps> = ({
19 setProfile, 21 setProfile,
20 onUploadRun, 22 onUploadRun,
21}) => { 23}) => {
22 // const [isSidebarLocked, setIsSidebarLocked] = React.useState<boolean>(false); 24 const [isSearching, setIsSearching] = React.useState<boolean>(false);
23 const [isSidebarOpen, setSidebarOpen] = React.useState<boolean>(false); 25 const [isSidebarOpen, setSidebarOpen] = React.useState<boolean>(false);
24 const [selectedButtonIndex, setSelectedButtonIndex] = React.useState<number>(1); 26 const [selectedButtonIndex, setSelectedButtonIndex] = React.useState<number>(1);
25 27
26 const location = useLocation(); 28 const location = useLocation();
27 const path = location.pathname; 29 const path = location.pathname;
28 30
29 const sidebarRef = useRef<HTMLDivElement>(null);
30 const sidebarButtonRefs = useRef<(HTMLButtonElement | null)[]>([]);
31
32 // const _handle_sidebar_toggle = useCallback(() => {
33 // if (!sidebarRef.current) return;
34
35 // if (isSidebarOpen) {
36 // setSidebarOpen(false);
37 // } else {
38 // setSidebarOpen(true);
39 // searchbarRef.current?.focus();
40 // }
41 // }, [isSidebarOpen]);
42
43 const handle_sidebar_click = useCallback( 31 const handle_sidebar_click = useCallback(
44 (clicked_sidebar_idx: number) => { 32 (clicked_sidebar_idx: number) => {
45 setSelectedButtonIndex(clicked_sidebar_idx); 33 setSelectedButtonIndex(clicked_sidebar_idx);
46 if (isSidebarOpen) { 34
47 setSidebarOpen(false); 35 if (clicked_sidebar_idx == 0 && !isSearching) {
36 if (!isSearching) {
37 setIsSearching(true);
38 }
39 } else {
40 setIsSearching(false);
48 } 41 }
49 }, 42 },
50 [isSidebarOpen] 43 [isSearching]
51 ); 44 );
52 45
53 React.useEffect(() => { 46 React.useEffect(() => {
54 if (path === "/") { 47 links.content.forEach((link, i) => {
55 setSelectedButtonIndex(1); 48 if (path.includes(link.to)) {
56 } else if (path.includes("games")) { 49 handle_sidebar_click(i + 1);
57 setSelectedButtonIndex(2); 50 }
58 } else if (path.includes("rankings")) { 51 })
59 setSelectedButtonIndex(3);
60 } else if (path.includes("profile")) {
61 setSelectedButtonIndex(4);
62 } else if (path.includes("rules")) {
63 setSelectedButtonIndex(5);
64 } else if (path.includes("about")) {
65 setSelectedButtonIndex(6);
66 }
67 }, [path]);
68
69 const getButtonClasses = (buttonIndex: number) => {
70 const baseClasses = "flex items-center gap-3 w-full text-left bg-inherit cursor-pointer border-none rounded-[2000px] py-3 px-3 transition-all duration-300 hover:bg-panel";
71 const selectedClasses = selectedButtonIndex === buttonIndex ? "bg-primary text-background" : "bg-transparent text-foreground";
72 52
73 return `${baseClasses} ${selectedClasses}`; 53 links.footer.forEach((link, i) => {
74 }; 54 if (path.includes(link.to)) {
55 handle_sidebar_click(links.content.length + i + 1);
56 }
57 })
58 }, [path]);
75 59
76 return ( 60 return (
77 <div className={`w-80 not-md:w-full text-white bg-block flex flex-col not-md:flex-row 61 <div className={`h-screen w-80 not-md:w-full text-white bg-block flex flex-col not-md:flex-row not-md:bg-gradient-to-t not-md:from-block not-md:to-bright
78 }`}> 62 }`}>
79 63
80 {/* Header */} 64 {/* Header */}
81 <Header /> 65 <_Header />
82 66
83 <div className="flex h-full w-full"> 67 <div className="flex flex-1 overflow-hidden w-full not-md:hidden ">
84 <div className="flex flex-col"> 68 <div className={`flex flex-col transition-all duration-300 ${isSearching ? "w-[64px]" : "w-full"}`}>
85 {/* Sidebar Content */} 69 {/* Sidebar Content */}
86 <Content profile={profile} isSidebarOpen={isSidebarOpen} sidebarButtonRefs={sidebarButtonRefs} getButtonClasses={getButtonClasses} handle_sidebar_click={handle_sidebar_click} /> 70 <_Content profile={profile} isSearching={isSearching} selectedButtonIndex={selectedButtonIndex} isSidebarOpen={isSidebarOpen} handle_sidebar_click={handle_sidebar_click} />
87 71
88 {/* Bottom Section */} 72 {/* Bottom Section */}
89 <Footer profile={profile} onUploadRun={onUploadRun} setToken={setToken} setProfile={setProfile} sidebarButtonRefs={sidebarButtonRefs} getButtonClasses={getButtonClasses} handle_sidebar_click={handle_sidebar_click} /> 73 <_Footer profile={profile} isSearching={isSearching} selectedButtonIndex={selectedButtonIndex} onUploadRun={onUploadRun} setToken={setToken} setProfile={setProfile} handle_sidebar_click={handle_sidebar_click} />
90 </div> 74 </div>
91 75
92 <div className="w-20"> 76 <div className={`flex bg-panel ${isSearching ? 'w-full' : "w-0"}`}>
93 77 <_Search profile={profile} isSearching={isSearching} />
94 </div> 78 </div>
95 79
96 </div> 80 </div>