fix: respect ios safe areas
All checks were successful
CI / Lint, typecheck and build (push) Successful in 9m54s
All checks were successful
CI / Lint, typecheck and build (push) Successful in 9m54s
This commit is contained in:
@@ -46,7 +46,7 @@ html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
min-height: 100vh;
|
min-height: 100dvh;
|
||||||
background: hsl(var(--background));
|
background: hsl(var(--background));
|
||||||
color: hsl(var(--foreground));
|
color: hsl(var(--foreground));
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
@@ -89,12 +89,56 @@ select {
|
|||||||
scrollbar-gutter: stable;
|
scrollbar-gutter: stable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-header-safe {
|
||||||
|
padding-top: env(safe-area-inset-top);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-main-safe {
|
||||||
|
padding-bottom: calc(7rem + env(safe-area-inset-bottom));
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-nav-safe {
|
||||||
|
bottom: calc(0.75rem + env(safe-area-inset-bottom));
|
||||||
|
left: calc(0.75rem + env(safe-area-inset-left));
|
||||||
|
right: calc(0.75rem + env(safe-area-inset-right));
|
||||||
|
}
|
||||||
|
|
||||||
.modal-overlay {
|
.modal-overlay {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: -1px 0 0;
|
inset: -1px 0 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: calc(100dvh + 1px);
|
||||||
min-height: calc(100dvh + 1px);
|
min-height: calc(100dvh + 1px);
|
||||||
background: hsl(var(--foreground) / 0.55);
|
background: hsl(var(--foreground) / 0.55);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-safe-area {
|
||||||
|
padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
@layer utilities {
|
||||||
|
.modal-safe-area {
|
||||||
|
padding:
|
||||||
|
calc(1rem + env(safe-area-inset-top))
|
||||||
|
calc(1rem + env(safe-area-inset-right))
|
||||||
|
calc(1rem + env(safe-area-inset-bottom))
|
||||||
|
calc(1rem + env(safe-area-inset-left));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
@layer utilities {
|
||||||
|
.modal-safe-area {
|
||||||
|
padding:
|
||||||
|
calc(2rem + env(safe-area-inset-top))
|
||||||
|
calc(2rem + env(safe-area-inset-right))
|
||||||
|
calc(2rem + env(safe-area-inset-bottom))
|
||||||
|
calc(2rem + env(safe-area-inset-left));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@supports (-moz-appearance: none) {
|
@supports (-moz-appearance: none) {
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ export function DayForecastModal({
|
|||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{day ? (
|
{day ? (
|
||||||
<motion.div
|
<motion.div
|
||||||
className="modal-overlay z-[90] flex items-center justify-center p-0 sm:p-4 lg:p-8"
|
className="modal-overlay modal-safe-area z-[90] flex items-center justify-center"
|
||||||
initial={{ opacity: 0 }}
|
initial={{ opacity: 0 }}
|
||||||
animate={{ opacity: 1 }}
|
animate={{ opacity: 1 }}
|
||||||
exit={{ opacity: 0 }}
|
exit={{ opacity: 0 }}
|
||||||
@@ -98,7 +98,7 @@ export function DayForecastModal({
|
|||||||
role="dialog"
|
role="dialog"
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
aria-labelledby="day-forecast-title"
|
aria-labelledby="day-forecast-title"
|
||||||
className="h-full w-full overflow-hidden bg-background shadow-card sm:max-w-6xl sm:rounded-panel sm:border sm:border-border/70"
|
className="h-full max-h-full w-full overflow-hidden bg-background shadow-card sm:max-w-6xl sm:rounded-panel sm:border sm:border-border/70"
|
||||||
initial={{ opacity: 0, y: 28, scale: 0.985 }}
|
initial={{ opacity: 0, y: 28, scale: 0.985 }}
|
||||||
animate={{ opacity: 1, y: 0, scale: 1 }}
|
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||||
exit={{ opacity: 0, y: 20, scale: 0.99 }}
|
exit={{ opacity: 0, y: 20, scale: 0.99 }}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export function AppShell({ children }: { children: React.ReactNode }) {
|
|||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen overflow-x-hidden bg-background">
|
<div className="min-h-screen overflow-x-hidden bg-background">
|
||||||
<header className="sticky top-0 z-40 border-b border-border/70 bg-surface">
|
<header className="app-header-safe sticky top-0 z-40 border-b border-border/70 bg-surface">
|
||||||
<div className="mx-auto flex max-w-7xl items-center justify-between px-4 py-3 sm:px-6 lg:px-8">
|
<div className="mx-auto flex max-w-7xl items-center justify-between px-4 py-3 sm:px-6 lg:px-8">
|
||||||
<Link href="/" className="text-2xl font-semibold tracking-[-0.09em] text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent">
|
<Link href="/" className="text-2xl font-semibold tracking-[-0.09em] text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent">
|
||||||
wtr<span className="text-accent">.</span>
|
wtr<span className="text-accent">.</span>
|
||||||
@@ -35,8 +35,8 @@ export function AppShell({ children }: { children: React.ReactNode }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<main className="mx-auto max-w-7xl px-4 pb-28 pt-5 sm:px-6 sm:pt-8 lg:px-8">{children}</main>
|
<main className="app-main-safe mx-auto max-w-7xl px-4 pt-5 sm:px-6 sm:pt-8 lg:px-8">{children}</main>
|
||||||
<nav aria-label={t("nav.mobile")} className="fixed inset-x-3 bottom-3 z-50 flex justify-around rounded-panel border border-border/70 bg-surface p-1.5 shadow-card md:hidden">
|
<nav aria-label={t("nav.mobile")} className="mobile-nav-safe fixed z-50 flex justify-around rounded-panel border border-border/70 bg-surface p-1.5 shadow-card md:hidden">
|
||||||
{NAV_ITEMS.map((item, index) => {
|
{NAV_ITEMS.map((item, index) => {
|
||||||
const Icon = icons[index];
|
const Icon = icons[index];
|
||||||
const active = item.href === "/" ? pathname === "/" : pathname.startsWith(item.href);
|
const active = item.href === "/" ? pathname === "/" : pathname.startsWith(item.href);
|
||||||
|
|||||||
Reference in New Issue
Block a user