From b4d5f8d8dbc0fd811ed9b92b4c81e86f1bb8e024 Mon Sep 17 00:00:00 2001 From: Arda Samadi Date: Thu, 18 Jun 2026 13:42:51 +0330 Subject: [PATCH] fix(ios): respect safe-area insets so chrome clears the notch/home bar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Content was drawing under the iOS status bar and home indicator because the app uses viewport-fit=cover + black-translucent but the fixed/sticky chrome didn't reserve the safe areas. - bottom nav (MyLayout): move the 50px row into an inner box and let the bar extend by env(safe-area-inset-bottom) so icons sit above the home indicator (previously the fixed height clipped the inset padding). - top headers gain env(safe-area-inset-top): HomePageTopBar, ExploreTopBar, SearchTopBar, CartHeader, ChatHeader, and wrapper-padded HeaderWithSupport / ProfilePagesHeader (so their absolutely-positioned buttons shift too). - chat input pads bottom by the inset; chat scroll area height accounts for the taller header/input. - _index.tsx no longer overrides the viewport meta (it was dropping viewport-fit=cover on the home page); the global one in root.tsx wins. env(safe-area-inset-*) is 0 on non-notch devices, so desktop/Android render identically — only iOS gains the padding. Co-Authored-By: Claude Opus 4.8 --- app/components/HeaderWithSupport.tsx | 36 ++++++++-------- app/components/MyLayout.tsx | 54 ++++++++++++------------ app/components/ProfilePagesHeader.tsx | 24 ++++++----- app/components/SearchTopBar.tsx | 2 +- app/components/cart/CartHeader.tsx | 4 +- app/components/explore/ExploreTopBar.tsx | 2 +- app/components/home/HomePageTopBar.tsx | 2 +- app/components/thread/ChatHeader.tsx | 4 +- app/components/thread/MessageInput.tsx | 2 +- app/components/thread/ThreadChatPage.tsx | 2 +- app/routes/_index.tsx | 4 +- 11 files changed, 72 insertions(+), 64 deletions(-) diff --git a/app/components/HeaderWithSupport.tsx b/app/components/HeaderWithSupport.tsx index 96fbd8f..db8799e 100644 --- a/app/components/HeaderWithSupport.tsx +++ b/app/components/HeaderWithSupport.tsx @@ -39,23 +39,25 @@ const HeaderWithSupport = memo(function HeaderWithSupport({ return ( <> -
- -

{title}

- {!hideSupportButton && ( -
- -
- )} +
+
+ +

{title}

+ {!hideSupportButton && ( +
+ +
+ )} +
{ }`} >
@@ -364,34 +364,36 @@ const MobileBottomNavigation = ({ return ( <>
- {navItems.map((item) => ( - - {typeof item.icon === "string" ? ( - {item.link} - ) : ( - item.icon - )} - {item.badge ? ( - - {item.badge > 99 ? "99+" : item.badge} - - ) : null} - - ))} +
+ {navItems.map((item) => ( + + {typeof item.icon === "string" ? ( + {item.link} + ) : ( + item.icon + )} + {item.badge ? ( + + {item.badge > 99 ? "99+" : item.badge} + + ) : null} + + ))} +
); diff --git a/app/components/ProfilePagesHeader.tsx b/app/components/ProfilePagesHeader.tsx index a09c11f..5145486 100644 --- a/app/components/ProfilePagesHeader.tsx +++ b/app/components/ProfilePagesHeader.tsx @@ -20,17 +20,19 @@ const ProfilePagesHeader = memo(function ProfilePagesHeader({ }, [navigate]); return ( -
- {!hideBackButton && ( - - )} -

{title}

- {rightContent && ( -
{rightContent}
- )} +
+
+ {!hideBackButton && ( + + )} +

{title}

+ {rightContent && ( +
{rightContent}
+ )} +
); }); diff --git a/app/components/SearchTopBar.tsx b/app/components/SearchTopBar.tsx index 81b47cb..4e9bf6a 100644 --- a/app/components/SearchTopBar.tsx +++ b/app/components/SearchTopBar.tsx @@ -42,7 +42,7 @@ const SearchTopBar: React.FC = ({ }; return ( -
+
{ const navigate = useNavigate(); return (

{step === 0 @@ -29,7 +29,7 @@ export const CartHeader = ({ cart, step, setStep }: CartHeaderProps) => { if (step > 0) setStep((p) => p - 1); else safeGoBack(navigate); }} - className="absolute top-4 right-4" + className="absolute top-[calc(1rem_+_env(safe-area-inset-top))] right-4" /> {cart && cart.items && cart.items.length > 0 && ( <> diff --git a/app/components/explore/ExploreTopBar.tsx b/app/components/explore/ExploreTopBar.tsx index d918ee3..82752de 100644 --- a/app/components/explore/ExploreTopBar.tsx +++ b/app/components/explore/ExploreTopBar.tsx @@ -41,7 +41,7 @@ const ExploreTopBar = memo(function ExploreTopBar({ }, [setSearchValue]); return ( -

+
{ ); return ( -
+
+
safeGoBack(navigate)} - className="absolute top-5 right-5" + className="absolute top-[calc(1.25rem_+_env(safe-area-inset-top))] right-5" /> {isConnected ? (
)} -
+
{replyToMessage && (
diff --git a/app/components/thread/ThreadChatPage.tsx b/app/components/thread/ThreadChatPage.tsx index 5c448a6..24eddba 100644 --- a/app/components/thread/ThreadChatPage.tsx +++ b/app/components/thread/ThreadChatPage.tsx @@ -254,7 +254,7 @@ export default function ThreadChatPage({ threadId }: ThreadChatPageProps) { ) : ( <>
{/* Messages list */} { }, { name: "author", content: "Vitrown" }, { name: "robots", content: "index, follow" }, - { name: "viewport", content: "width=device-width, initial-scale=1" }, + // viewport is defined globally in root.tsx (with viewport-fit=cover for + // iOS safe-area handling); don't override it here or the home page loses + // edge-to-edge / notch support. // Open Graph { property: "og:type", content: "website" },