Skip to content

Commit 5bf2653

Browse files
author
AugistineCreates
authored
feat: implement mobile-first responsive layout for dashboard (#361)
1 parent 45bc4a1 commit 5bf2653

2 files changed

Lines changed: 182 additions & 55 deletions

File tree

frontend/src/components/Navbar.tsx

Lines changed: 85 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ const Navbar: FC<NavbarProps> = ({
5959
};
6060
}, [walletAddress]);
6161

62+
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
63+
6264
return (
6365
<nav
6466
aria-label="Primary"
@@ -81,6 +83,7 @@ const Navbar: FC<NavbarProps> = ({
8183
to="/"
8284
className="flex items-center gap-sm"
8385
style={{ textDecoration: "none" }}
86+
onClick={() => setIsMobileMenuOpen(false)}
8487
>
8588
<div
8689
style={{
@@ -110,7 +113,7 @@ const Navbar: FC<NavbarProps> = ({
110113
</span>
111114
</NavLink>
112115

113-
<div className="flex gap-lg" style={{ marginLeft: "32px" }}>
116+
<div className="flex gap-lg nav-desktop-links" style={{ marginLeft: "32px" }}>
114117
<NavLink
115118
to="/"
116119
style={({ isActive }) => ({
@@ -154,41 +157,94 @@ const Navbar: FC<NavbarProps> = ({
154157
</div>
155158

156159
<div className="flex items-center gap-md">
157-
{walletAddress ? (
160+
<div className="flex items-center gap-sm nav-desktop-links">
161+
{walletAddress ? (
162+
<span
163+
aria-label="Network badge"
164+
title={`Connected network: ${networkLabel}`}
165+
style={{
166+
padding: "6px 10px",
167+
borderRadius: "999px",
168+
fontSize: "0.75rem",
169+
fontWeight: "var(--font-semibold)",
170+
letterSpacing: "0.04em",
171+
textTransform: "uppercase",
172+
border:
173+
networkLabel === "Mainnet"
174+
? "1px solid rgba(34, 197, 94, 0.45)"
175+
: "1px solid rgba(56, 189, 248, 0.45)",
176+
color:
177+
networkLabel === "Mainnet"
178+
? "rgb(34, 197, 94)"
179+
: "var(--accent-cyan)",
180+
background:
181+
networkLabel === "Mainnet"
182+
? "rgba(34, 197, 94, 0.08)"
183+
: "rgba(0, 240, 255, 0.08)",
184+
}}
185+
>
186+
{networkLabel}
187+
</span>
188+
) : null}
189+
<ThemeToggle />
190+
</div>
191+
192+
<WalletConnect
193+
walletAddress={walletAddress}
194+
usdcBalance={usdcBalance}
195+
onConnect={onConnect}
196+
onDisconnect={onDisconnect}
197+
/>
198+
199+
<button
200+
className="nav-mobile-toggle"
201+
style={{ display: "none" }}
202+
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
203+
aria-label={isMobileMenuOpen ? "Close menu" : "Open menu"}
204+
>
205+
{isMobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
206+
</button>
207+
</div>
208+
</div>
209+
210+
<div className={`nav-mobile-menu ${isMobileMenuOpen ? "is-open" : ""}`}>
211+
<NavLink
212+
to="/"
213+
className={({ isActive }) => `nav-mobile-link ${isActive ? "active" : ""}`}
214+
onClick={() => setIsMobileMenuOpen(false)}
215+
>
216+
{t("nav.vaults")}
217+
</NavLink>
218+
<NavLink
219+
to="/portfolio"
220+
className={({ isActive }) => `nav-mobile-link ${isActive ? "active" : ""}`}
221+
onClick={() => setIsMobileMenuOpen(false)}
222+
>
223+
{t("nav.portfolio")}
224+
</NavLink>
225+
<NavLink
226+
to="/analytics"
227+
className={({ isActive }) => `nav-mobile-link ${isActive ? "active" : ""}`}
228+
onClick={() => setIsMobileMenuOpen(false)}
229+
>
230+
{t("nav.analytics")}
231+
</NavLink>
232+
<div className="flex items-center justify-between" style={{ marginTop: "auto", paddingTop: "24px" }}>
233+
<ThemeToggle />
234+
{walletAddress && (
158235
<span
159-
aria-label="Network badge"
160-
title={`Connected network: ${networkLabel}`}
161236
style={{
162-
padding: "6px 10px",
237+
padding: "6px 12px",
163238
borderRadius: "999px",
164-
fontSize: "0.75rem",
165-
fontWeight: "var(--font-semibold)",
166-
letterSpacing: "0.04em",
167-
textTransform: "uppercase",
168-
border:
169-
networkLabel === "Mainnet"
170-
? "1px solid rgba(34, 197, 94, 0.45)"
171-
: "1px solid rgba(56, 189, 248, 0.45)",
172-
color:
173-
networkLabel === "Mainnet"
174-
? "rgb(34, 197, 94)"
175-
: "var(--accent-cyan)",
176-
background:
177-
networkLabel === "Mainnet"
178-
? "rgba(34, 197, 94, 0.08)"
179-
: "rgba(0, 240, 255, 0.08)",
239+
fontSize: "0.8rem",
240+
fontWeight: 600,
241+
background: networkLabel === "Mainnet" ? "rgba(34, 197, 94, 0.1)" : "rgba(0, 240, 255, 0.1)",
242+
color: networkLabel === "Mainnet" ? "rgb(34, 197, 94)" : "var(--accent-cyan)",
180243
}}
181244
>
182245
{networkLabel}
183246
</span>
184-
) : null}
185-
<ThemeToggle />
186-
<WalletConnect
187-
walletAddress={walletAddress}
188-
usdcBalance={usdcBalance}
189-
onConnect={onConnect}
190-
onDisconnect={onDisconnect}
191-
/>
247+
)}
192248
</div>
193249
</div>
194250
</nav>

frontend/src/index.css

Lines changed: 97 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,12 @@ button {
352352
padding: 0 var(--space-6);
353353
}
354354

355+
@media (max-width: 480px) {
356+
.container {
357+
padding: 0 var(--space-4);
358+
}
359+
}
360+
355361
.flex {
356362
display: flex;
357363
}
@@ -481,6 +487,19 @@ button {
481487
height: clamp(200px, 58vw, 280px);
482488
min-height: 200px;
483489
}
490+
491+
.vault-dashboard-stats > .glass-panel,
492+
.vault-dashboard-actions > .glass-panel {
493+
padding: 24px 16px !important;
494+
}
495+
496+
.gap-lg { gap: var(--space-4); }
497+
498+
.vault-chart-panel .flex.justify-between {
499+
flex-direction: column;
500+
align-items: flex-start;
501+
gap: 16px;
502+
}
484503
}
485504

486505
/* Gradients & Text Effects */
@@ -604,8 +623,13 @@ button {
604623
align-items: center;
605624
gap: 4px;
606625
transition: opacity 0.2s, color 0.2s;
607-
min-height: auto;
608-
min-width: auto;
626+
}
627+
628+
@media (max-width: 768px) {
629+
.btn-link {
630+
min-height: 44px;
631+
padding: 8px 0;
632+
}
609633
}
610634

611635
.btn-link:hover {
@@ -1154,57 +1178,104 @@ button {
11541178
}
11551179

11561180
@media (max-width: 768px) {
1181+
1182+
11571183
.data-table-scroll {
1158-
overflow-x: visible;
1184+
overflow-x: auto;
1185+
-webkit-overflow-scrolling: touch;
1186+
margin: 0 -18px;
1187+
padding: 0 18px;
1188+
}
1189+
1190+
.data-table {
1191+
min-width: 600px; /* Ensure enough width for horizontal scrolling */
11591192
}
11601193

11611194
.data-table thead {
1162-
display: none;
1195+
display: table-header-group;
11631196
}
11641197

11651198
.data-table,
11661199
.data-table tbody,
11671200
.data-table tr,
11681201
.data-table td {
1169-
display: block;
1170-
width: 100%;
1202+
display: table-cell; /* Revert to table layout */
1203+
width: auto;
11711204
}
1172-
1173-
.data-table-row {
1174-
padding: 16px 18px;
1175-
border-bottom: 1px solid var(--border-glass);
1205+
1206+
.data-table tr {
1207+
display: table-row;
11761208
}
1177-
1178-
.data-table-row:last-child {
1179-
border-bottom: none;
1209+
1210+
.data-table tbody {
1211+
display: table-row-group;
11801212
}
11811213

1182-
.data-table td {
1183-
border-bottom: none;
1184-
padding: 8px 0;
1185-
text-align: left !important;
1214+
.data-table-row {
1215+
padding: 0;
11861216
}
11871217

11881218
.data-table td::before {
1189-
content: attr(data-label);
1190-
display: block;
1191-
color: var(--text-secondary);
1192-
font-size: var(--text-xs);
1193-
text-transform: uppercase;
1194-
letter-spacing: 0.05em;
1195-
margin-bottom: 4px;
1196-
font-weight: var(--font-semibold);
1219+
display: none; /* Hide data-label as we are scrolling now */
11971220
}
11981221

11991222
.data-table-mobile-detail {
1200-
display: block;
1223+
display: none;
12011224
}
12021225

12031226
.toast-viewport {
12041227
left: 16px;
12051228
right: 16px;
12061229
width: auto;
12071230
}
1231+
1232+
/* Navigation Mobile Styles */
1233+
.nav-desktop-links {
1234+
display: none !important;
1235+
}
1236+
1237+
.nav-mobile-toggle {
1238+
display: flex !important;
1239+
align-items: center;
1240+
justify-content: center;
1241+
width: 44px;
1242+
height: 44px;
1243+
color: var(--text-primary);
1244+
}
1245+
1246+
.nav-mobile-menu {
1247+
position: fixed;
1248+
top: 76px; /* height of navbar */
1249+
left: 0;
1250+
right: 0;
1251+
bottom: 0;
1252+
background: var(--bg-surface);
1253+
backdrop-filter: blur(20px);
1254+
-webkit-backdrop-filter: blur(20px);
1255+
z-index: 99;
1256+
display: flex;
1257+
flex-direction: column;
1258+
padding: var(--space-8) var(--space-6);
1259+
gap: var(--space-6);
1260+
transform: translateX(100%);
1261+
transition: transform 0.3s ease-in-out;
1262+
}
1263+
1264+
.nav-mobile-menu.is-open {
1265+
transform: translateX(0);
1266+
}
1267+
1268+
.nav-mobile-link {
1269+
font-size: var(--text-xl);
1270+
font-weight: var(--font-semibold);
1271+
color: var(--text-secondary);
1272+
padding: var(--space-4) 0;
1273+
border-bottom: 1px solid var(--border-glass);
1274+
}
1275+
1276+
.nav-mobile-link.active {
1277+
color: var(--accent-cyan);
1278+
}
12081279
}
12091280

12101281
/* ── Compact Mode ───────────────────────────────────────────────── */

0 commit comments

Comments
 (0)