From abe51e4e3f9d8db9f03905a70728700ddc45dad7 Mon Sep 17 00:00:00 2001
From: AssetMantle Dev <52166434+deepanshutr@users.noreply.github.com>
Date: Mon, 6 Jul 2026 23:04:30 +0530
Subject: [PATCH 1/2] feat(responsive): unblock mobile, add bottom tab bar,
stack Transact
- remove the d-none d-md-block gate + 'open on a larger device' screen so
the app renders at all viewports
- add a bottom tab bar (5 primary + More sheet) for < xl; keep the desktop
top nav for xl+; Connect stays visible in the mobile header
- relax the fixed-viewport-height shell below lg so pages flow and scroll
naturally instead of each section scrolling independently
- Transact: stack Send/Receive (col-12 col-lg-8 / col-12 col-lg-4)
Verified: desktop 1440 unchanged; mobile 390 unblocked + stacks.
---
components/Layout.js | 74 +++----------
components/MobileTabBar.jsx | 128 +++++++++++++++++++++++
components/ScrollableSectionContainer.js | 3 +-
config/styles/index.scss | 76 ++++++++++++++
pages/index.jsx | 6 +-
views/Header.js | 44 ++------
6 files changed, 229 insertions(+), 102 deletions(-)
create mode 100644 components/MobileTabBar.jsx
diff --git a/components/Layout.js b/components/Layout.js
index 8915c0ff..cda24a3f 100644
--- a/components/Layout.js
+++ b/components/Layout.js
@@ -1,70 +1,22 @@
-import React, { useState } from "react";
+import React from "react";
import Balance from "../views/Balance";
import Header from "../views/Header";
-// import Banner from "./Banner";
-// import Vesting from "../views/Vesting";
+import MobileTabBar from "./MobileTabBar";
import ScrollableSectionContainer from "./ScrollableSectionContainer";
export default function Layout({ children }) {
- const [leftCol, setLeftCol] = useState(false);
return (
- <>
-
-
-
-
-
-
- Please open the app on a Tab or Larger device.
-
-
-
+
- >
+
+
+
);
}
diff --git a/components/MobileTabBar.jsx b/components/MobileTabBar.jsx
new file mode 100644
index 00000000..0ca2a65d
--- /dev/null
+++ b/components/MobileTabBar.jsx
@@ -0,0 +1,128 @@
+import Link from "next/link";
+import { useRouter } from "next/router";
+import React, { useState } from "react";
+import { NavBarData } from "../data";
+
+// Bottom tab bar for < xl viewports (phone + tablet). The desktop top nav in
+// Header.js stays for xl+. Five primary destinations sit on the bar; the rest
+// of NavBarData.navs (plus the external links) live in a "More" sheet so every
+// section stays reachable on a phone.
+const PRIMARY_HREFS = ["/", "/stake", "/vote", "/bridge"];
+
+function isActive(router, href) {
+ return router.asPath === href || router.asPath.split("?")[0] === href;
+}
+
+function TabLink({ item, active }) {
+ return (
+
+
+ {item.icon}
+ {item.title || "Help"}
+
+
+ );
+}
+
+export default function MobileTabBar() {
+ const router = useRouter();
+ const [moreOpen, setMoreOpen] = useState(false);
+
+ const primary = PRIMARY_HREFS.map((href) =>
+ NavBarData.navs.find((n) => n.href === href)
+ ).filter(Boolean);
+ const overflow = [
+ ...NavBarData.navs.filter((n) => !PRIMARY_HREFS.includes(n.href)),
+ ...NavBarData.rightNav,
+ ];
+ const moreActive = overflow.some(
+ (n) => !n.target && isActive(router, n.href)
+ );
+
+ return (
+ <>
+ {moreOpen && (
+
setMoreOpen(false)}
+ />
+ )}
+
+
+
More
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/components/ScrollableSectionContainer.js b/components/ScrollableSectionContainer.js
index e814b0e0..2077c4da 100644
--- a/components/ScrollableSectionContainer.js
+++ b/components/ScrollableSectionContainer.js
@@ -3,8 +3,7 @@ import React from "react";
export default function ScrollableSectionContainer({ className, children }) {
return (
{children}
diff --git a/config/styles/index.scss b/config/styles/index.scss
index 2f91b1d1..76ba9322 100644
--- a/config/styles/index.scss
+++ b/config/styles/index.scss
@@ -1310,3 +1310,79 @@ body::before {
opacity: 1;
}
}
+
+// Mobile bottom tab bar + "More" sheet (< xl). Surface + active accent reuse
+// .nav-bg / .text-primary from the theme; only layout/animation live here.
+.am-tab-bar {
+ border-top: 1px solid $white-400;
+ padding-bottom: env(safe-area-inset-bottom, 0px);
+ min-height: 56px;
+}
+.am-tab {
+ padding: 0.5rem 0.25rem;
+ text-decoration: none;
+ background: transparent;
+ border: 0;
+ transition: color 150ms ease;
+ .caption2 {
+ line-height: 1;
+ }
+ &:focus-visible {
+ outline: 2px solid $primary-main;
+ outline-offset: -2px;
+ }
+}
+.am-tab-scrim {
+ background: rgba(0, 0, 0, 0.5);
+}
+.am-tab-sheet {
+ bottom: calc(56px + env(safe-area-inset-bottom, 0px));
+ border-top: 1px solid $white-400;
+ border-top-left-radius: 16px;
+ border-top-right-radius: 16px;
+ max-height: 70vh;
+ overflow-y: auto;
+ transform: translateY(150%);
+ transition: transform 220ms ease;
+ &.open {
+ transform: translateY(0);
+ }
+}
+.am-tab-row {
+ text-decoration: none;
+ &:active {
+ background: rgba(255, 255, 255, 0.06);
+ }
+}
+// keep page content clear of the fixed bar on < xl
+@media (max-width: 1199.98px) {
+ .am_app_container {
+ padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px));
+ }
+}
+@media (prefers-reduced-motion: reduce) {
+ .am-tab-sheet {
+ transition: none;
+ }
+}
+
+// Desktop uses a fixed-viewport-height shell where each section scrolls on its
+// own (.am-scroll-section). On phone/tablet (< lg) that fights natural reading:
+// relax the height chain so the PAGE flows and scrolls, and sections size to
+// their content and stack.
+.am-scroll-section {
+ overflow-y: auto;
+}
+@media (max-width: 991.98px) {
+ .am_app_container .am-scroll-section {
+ height: auto !important;
+ overflow-y: visible;
+ padding-bottom: 1rem;
+ }
+ .am_app_container main.h-100,
+ .am_app_container .row.h-100,
+ .am_app_container .col-lg-9.h-100,
+ .am_app_container .col-lg-3 {
+ height: auto !important;
+ }
+}
diff --git a/pages/index.jsx b/pages/index.jsx
index 17a788e0..8c7b11f0 100644
--- a/pages/index.jsx
+++ b/pages/index.jsx
@@ -404,8 +404,8 @@ export default function Transact() {
Transact | MantleWallet
-
-
+
+
-
+
{status === "Connected" ? (
) : (
diff --git a/views/Header.js b/views/Header.js
index cbebf36e..925b3fcd 100644
--- a/views/Header.js
+++ b/views/Header.js
@@ -15,14 +15,11 @@ import {
} from "../data";
import { cleanString, shortenAddress } from "../lib";
-export default function Header({ setLeftCol }) {
+export default function Header() {
const chainContext = useChain(defaultChainName);
const { username, address, wallet, disconnect } = chainContext;
const [showModal, setShowModal] = useState(false);
- // menus ham
- const [rightHam, setRightHam] = useState(false);
-
const router = useRouter();
// Events
@@ -187,46 +184,21 @@ export default function Header({ setLeftCol }) {
className="container-xxl d-flex align-items-center gap-3 p-3 px-4"
style={{ maxWidth: "1920px" }}
>
- setLeftCol(true)}
- >
-
-
{appLogoJSX}
-