apply safe area insets to mobile layout in PWA mode using viewport-fit=cover

This commit is contained in:
Josh Hawkins 2026-06-04 10:11:21 -05:00
parent 9107c9581d
commit 8e878cd9c4
5 changed files with 16 additions and 16 deletions

View File

@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" href="/images/branding/favicon.ico" /> <link rel="icon" href="/images/branding/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
<title>Frigate</title> <title>Frigate</title>
<link <link
rel="apple-touch-icon" rel="apple-touch-icon"

View File

@ -78,7 +78,9 @@ function DefaultAppView() {
className={cn( className={cn(
"absolute right-0 top-0 overflow-hidden", "absolute right-0 top-0 overflow-hidden",
isMobile isMobile
? `bottom-${isPWA ? 16 : 12} left-0 md:bottom-16 landscape:bottom-14 landscape:md:bottom-16` ? isPWA
? "bottom-[calc(3rem+env(safe-area-inset-bottom))] left-0 pt-[env(safe-area-inset-top)] md:bottom-[calc(4rem+env(safe-area-inset-bottom))] landscape:pl-[env(safe-area-inset-left)] landscape:pr-[env(safe-area-inset-right)]"
: "bottom-12 left-0 md:bottom-16"
: "bottom-8 left-[52px]", : "bottom-8 left-[52px]",
)} )}
> >

View File

@ -146,9 +146,10 @@ export function MobilePageContent({
<motion.div <motion.div
ref={containerRef} ref={containerRef}
className={cn( className={cn(
"fixed inset-0 z-50 mb-12 bg-background", "fixed inset-0 z-50 bg-background",
isPWA && "mb-16", isPWA
"landscape:mb-14 landscape:md:mb-16", ? "mb-[calc(3rem+env(safe-area-inset-bottom))] md:mb-[calc(4rem+env(safe-area-inset-bottom))]"
: "mb-12 md:mb-16",
className, className,
)} )}
initial={{ x: "100%" }} initial={{ x: "100%" }}

View File

@ -14,7 +14,7 @@ import {
} from "@/context/statusbar-provider"; } from "@/context/statusbar-provider";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { isIOS, isMobile } from "react-device-detect"; import { isMobile } from "react-device-detect";
import { isPWA } from "@/utils/isPWA"; import { isPWA } from "@/utils/isPWA";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@ -24,11 +24,11 @@ function Bottombar() {
return ( return (
<div <div
className={cn( className={cn(
"absolute inset-x-4 bottom-0 flex h-16 flex-row justify-between", "absolute inset-x-4 bottom-0 flex h-16 flex-row items-center justify-between",
isPWA && isIOS isMobile &&
? "portrait:items-start portrait:pt-1 landscape:items-center" (isPWA
: "items-center", ? "h-[calc(3rem+env(safe-area-inset-bottom))] pb-[env(safe-area-inset-bottom)] md:h-[calc(4rem+env(safe-area-inset-bottom))]"
isMobile && !isPWA && "h-12 md:h-16", : "h-12 md:h-16 md:pb-2"),
)} )}
> >
{navItems.map((item) => ( {navItems.map((item) => (

View File

@ -2,8 +2,6 @@ import * as React from "react";
import { Drawer as DrawerPrimitive } from "vaul"; import { Drawer as DrawerPrimitive } from "vaul";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { isPWA } from "@/utils/isPWA";
import { isIOS } from "react-device-detect";
const Drawer = ({ const Drawer = ({
shouldScaleBackground = true, shouldScaleBackground = true,
@ -43,10 +41,9 @@ const DrawerContent = React.forwardRef<
<DrawerPrimitive.Content <DrawerPrimitive.Content
ref={ref} ref={ref}
className={cn( className={cn(
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background", "fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border border-b-0 bg-background",
className, className,
isIOS && isPWA && "pb-5", "pb-[calc(0.25rem+env(safe-area-inset-bottom))]",
isIOS && !isPWA && "md:pb-5",
)} )}
{...props} {...props}
> >