From 96d698785854604f64363e0790cfab6ed9dc8cbe Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Fri, 2 May 2025 08:19:48 -0400 Subject: [PATCH] fix: Mobile toolbar overlaps with home indicator (#9119) --- app/components/Sidebar/Sidebar.tsx | 1 + app/editor/components/FloatingToolbar.tsx | 7 +++++- shared/styles/globals.ts | 7 ++++++ shared/utils/browser.ts | 26 +++++++++++++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/app/components/Sidebar/Sidebar.tsx b/app/components/Sidebar/Sidebar.tsx index b475e10de1..975d7c73bf 100644 --- a/app/components/Sidebar/Sidebar.tsx +++ b/app/components/Sidebar/Sidebar.tsx @@ -321,6 +321,7 @@ const Container = styled(Flex)` z-index: ${depths.mobileSidebar}; max-width: 80%; min-width: 280px; + padding-left: var(--sal); ${fadeOnDesktopBackgrounded()} @media print { diff --git a/app/editor/components/FloatingToolbar.tsx b/app/editor/components/FloatingToolbar.tsx index 5aaa082cf1..be304adc86 100644 --- a/app/editor/components/FloatingToolbar.tsx +++ b/app/editor/components/FloatingToolbar.tsx @@ -7,6 +7,7 @@ import { isCode } from "@shared/editor/lib/isCode"; import { findParentNode } from "@shared/editor/queries/findParentNode"; import { EditorStyleHelper } from "@shared/editor/styles/EditorStyleHelper"; import { depths, s } from "@shared/styles"; +import { getSafeAreaInsets } from "@shared/utils/browser"; import { HEADER_HEIGHT } from "~/components/Header"; import { Portal } from "~/components/Portal"; import useEventListener from "~/hooks/useEventListener"; @@ -241,12 +242,16 @@ const FloatingToolbar = React.forwardRef(function FloatingToolbar_( if (props.active) { const rect = document.body.getBoundingClientRect(); + const safeAreaInsets = getSafeAreaInsets(); + return ( {props.children} diff --git a/shared/styles/globals.ts b/shared/styles/globals.ts index 37cc45956b..cef435efd7 100644 --- a/shared/styles/globals.ts +++ b/shared/styles/globals.ts @@ -113,4 +113,11 @@ export default createGlobalStyle` outline-offset: -1px; outline-width: initial; } + + :root { + --sat: env(safe-area-inset-top); + --sar: env(safe-area-inset-right); + --sab: env(safe-area-inset-bottom); + --sal: env(safe-area-inset-left); + } `; diff --git a/shared/utils/browser.ts b/shared/utils/browser.ts index f159989bfe..e9d9218ceb 100644 --- a/shared/utils/browser.ts +++ b/shared/utils/browser.ts @@ -13,6 +13,32 @@ export function isTouchDevice(): boolean { return window.matchMedia?.("(hover: none) and (pointer: coarse)")?.matches; } +/** + * Returns the safe area insets for the current device. + */ +export function getSafeAreaInsets(): { + top: number; + right: number; + bottom: number; + left: number; +} { + // Check if CSS environment variables are supported + const style = getComputedStyle(document.documentElement); + const supportsEnv = window.CSS?.supports?.("top", "env(safe-area-inset-top)"); + + if (supportsEnv) { + return { + top: parseFloat(style.getPropertyValue("--sat") || "0"), + right: parseFloat(style.getPropertyValue("--sar") || "0"), + bottom: parseFloat(style.getPropertyValue("--sab") || "0"), + left: parseFloat(style.getPropertyValue("--sal") || "0"), + }; + } + + // Fallback to zero if not supported + return { top: 0, right: 0, bottom: 0, left: 0 }; +} + /** * Returns true if the client is running on a Mac. */