fix(layout): swap 100vh/h-screen for dvh so bottom navs survive browser chrome

In non-PWA browser tabs (especially iOS Safari), 100vh is the largest possible
viewport — it doesn't shrink when the bottom URL bar slides in, so fixed-bottom
navs get occluded. 100dvh tracks the dynamic viewport, so layouts reflow and
nav stays clickable. Safe-area-inset-bottom padding on the navs themselves is
already in place.
This commit is contained in:
Padreug 2026-05-06 07:13:52 +02:00
commit a2c4cfd955
19 changed files with 29 additions and 29 deletions

View file

@ -26,8 +26,8 @@ async function handleLoginSuccess() {
</script> </script>
<template> <template>
<div class="min-h-screen bg-background font-sans antialiased"> <div class="min-h-dvh bg-background font-sans antialiased">
<div class="relative flex min-h-screen flex-col" <div class="relative flex min-h-dvh flex-col"
style="padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom)"> style="padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom)">
<div v-if="!isLoginPage && !isAuthenticated" class="fixed top-0 right-0 z-50 p-3" style="padding-top: env(safe-area-inset-top)"> <div v-if="!isLoginPage && !isAuthenticated" class="fixed top-0 right-0 z-50 p-3" style="padding-top: env(safe-area-inset-top)">

View file

@ -49,8 +49,8 @@ async function handleLoginSuccess() {
</script> </script>
<template> <template>
<div class="min-h-screen bg-background font-sans antialiased"> <div class="min-h-dvh bg-background font-sans antialiased">
<div class="relative flex min-h-screen flex-col" <div class="relative flex min-h-dvh flex-col"
style="padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom)"> style="padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom)">
<!-- Top bar with login --> <!-- Top bar with login -->

View file

@ -46,8 +46,8 @@ async function handleLoginSuccess() {
</script> </script>
<template> <template>
<div class="min-h-screen bg-background font-sans antialiased"> <div class="min-h-dvh bg-background font-sans antialiased">
<div class="relative flex min-h-screen flex-col" <div class="relative flex min-h-dvh flex-col"
style="padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom)"> style="padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom)">
<!-- Main content (with bottom padding for nav bar) --> <!-- Main content (with bottom padding for nav bar) -->

View file

@ -26,8 +26,8 @@ async function handleLoginSuccess() {
</script> </script>
<template> <template>
<div class="min-h-screen bg-background font-sans antialiased"> <div class="min-h-dvh bg-background font-sans antialiased">
<div class="relative flex min-h-screen flex-col" <div class="relative flex min-h-dvh flex-col"
style="padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom)"> style="padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom)">
<div v-if="!isLoginPage && !isAuthenticated" class="fixed top-0 right-0 z-50 p-3" style="padding-top: env(safe-area-inset-top)"> <div v-if="!isLoginPage && !isAuthenticated" class="fixed top-0 right-0 z-50 p-3" style="padding-top: env(safe-area-inset-top)">

View file

@ -12,7 +12,7 @@ const openSidebar = () => {
</script> </script>
<template> <template>
<div class="min-h-screen bg-background"> <div class="min-h-dvh bg-background">
<!-- Mobile Drawer --> <!-- Mobile Drawer -->
<MobileDrawer v-model:open="sidebarOpen" /> <MobileDrawer v-model:open="sidebarOpen" />

View file

@ -59,8 +59,8 @@ async function handleLoginSuccess() {
</script> </script>
<template> <template>
<div class="min-h-screen bg-background font-sans antialiased"> <div class="min-h-dvh bg-background font-sans antialiased">
<div class="relative flex min-h-screen flex-col" <div class="relative flex min-h-dvh flex-col"
style="padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom)"> style="padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom)">
<div v-if="!isLoginPage && !isAuthenticated" class="fixed top-0 right-0 z-50 p-3" style="padding-top: env(safe-area-inset-top)"> <div v-if="!isLoginPage && !isAuthenticated" class="fixed top-0 right-0 z-50 p-3" style="padding-top: env(safe-area-inset-top)">

View file

@ -69,8 +69,8 @@ async function handleLoginSuccess() {
</script> </script>
<template> <template>
<div class="min-h-screen bg-background font-sans antialiased"> <div class="min-h-dvh bg-background font-sans antialiased">
<div class="relative flex min-h-screen flex-col" <div class="relative flex min-h-dvh flex-col"
style="padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom)"> style="padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom)">
<main class="flex-1" :class="{ 'pb-16': !isLoginPage }"> <main class="flex-1" :class="{ 'pb-16': !isLoginPage }">

View file

@ -26,7 +26,7 @@ onMounted(() => {
</script> </script>
<template> <template>
<div class="flex flex-col h-[calc(100vh-3.5rem)]"> <div class="flex flex-col h-[calc(100dvh-3.5rem)]">
<!-- Loading overlay --> <!-- Loading overlay -->
<div v-if="isLoading && geoActivities.length === 0" class="flex-1 flex items-center justify-center"> <div v-if="isLoading && geoActivities.length === 0" class="flex-1 flex items-center justify-center">
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-primary" /> <div class="animate-spin rounded-full h-8 w-8 border-b-2 border-primary" />

View file

@ -1,6 +1,6 @@
<template> <template>
<!-- Loading State --> <!-- Loading State -->
<div v-if="isLoading" class="flex flex-col items-center justify-center min-h-screen"> <div v-if="isLoading" class="flex flex-col items-center justify-center min-h-dvh">
<div class="flex flex-col items-center space-y-4"> <div class="flex flex-col items-center space-y-4">
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-primary"></div> <div class="animate-spin rounded-full h-12 w-12 border-b-2 border-primary"></div>
<div class="text-center space-y-2"> <div class="text-center space-y-2">
@ -11,7 +11,7 @@
</div> </div>
<!-- Error State --> <!-- Error State -->
<div v-else-if="error" class="flex flex-col items-center justify-center min-h-screen"> <div v-else-if="error" class="flex flex-col items-center justify-center min-h-dvh">
<div class="text-center space-y-4"> <div class="text-center space-y-4">
<h2 class="text-xl font-semibold text-red-600">Failed to load chat</h2> <h2 class="text-xl font-semibold text-red-600">Failed to load chat</h2>
<p class="text-muted-foreground">{{ error }}</p> <p class="text-muted-foreground">{{ error }}</p>
@ -22,7 +22,7 @@
</div> </div>
<!-- Chat Content - Only render when module is ready --> <!-- Chat Content - Only render when module is ready -->
<div v-else class="h-[calc(100vh-3.5rem)] lg:h-[calc(100vh-4rem)] xl:h-[calc(100vh-5rem)] w-full"> <div v-else class="h-[calc(100dvh-3.5rem)] lg:h-[calc(100dvh-4rem)] xl:h-[calc(100dvh-5rem)] w-full">
<ChatComponent /> <ChatComponent />
</div> </div>
</template> </template>

View file

@ -275,7 +275,7 @@ watch(comments, (newComments) => {
</script> </script>
<template> <template>
<div class="min-h-screen bg-background"> <div class="min-h-dvh bg-background">
<!-- Header --> <!-- Header -->
<header class="sticky top-0 z-30 bg-background/95 backdrop-blur border-b"> <header class="sticky top-0 z-30 bg-background/95 backdrop-blur border-b">
<div class="max-w-4xl mx-auto px-4 py-3"> <div class="max-w-4xl mx-auto px-4 py-3">

View file

@ -11,7 +11,7 @@ function onSubmissionClick(submission: SubmissionWithMeta) {
</script> </script>
<template> <template>
<div class="flex flex-col h-screen bg-background"> <div class="flex flex-col h-dvh bg-background">
<div class="sticky top-0 z-30 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 border-b"> <div class="sticky top-0 z-30 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 border-b">
<div class="max-w-4xl mx-auto flex items-center justify-between px-4 py-2 sm:px-6"> <div class="max-w-4xl mx-auto flex items-center justify-between px-4 py-2 sm:px-6">
<h1 class="text-lg font-semibold">Forum</h1> <h1 class="text-lg font-semibold">Forum</h1>

View file

@ -275,7 +275,7 @@ watch(comments, (newComments) => {
</script> </script>
<template> <template>
<div class="min-h-screen bg-background"> <div class="min-h-dvh bg-background">
<!-- Header --> <!-- Header -->
<header class="sticky top-0 z-30 bg-background/95 backdrop-blur border-b"> <header class="sticky top-0 z-30 bg-background/95 backdrop-blur border-b">
<div class="max-w-4xl mx-auto px-4 py-3"> <div class="max-w-4xl mx-auto px-4 py-3">

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="flex flex-col h-screen bg-background"> <div class="flex flex-col h-dvh bg-background">
<!-- Header --> <!-- Header -->
<div class="sticky top-0 z-40 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 border-b"> <div class="sticky top-0 z-40 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 border-b">
<div class="flex items-center justify-between px-4 py-2 sm:px-6"> <div class="flex items-center justify-between px-4 py-2 sm:px-6">

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="flex flex-col h-screen bg-background"> <div class="flex flex-col h-dvh bg-background">
<PWAInstallPrompt auto-show /> <PWAInstallPrompt auto-show />
<!-- Header --> <!-- Header -->

View file

@ -96,7 +96,7 @@ function notImplemented() {
</script> </script>
<template> <template>
<div class="relative h-screen flex flex-col text-foreground overflow-hidden bg-background" <div class="relative h-dvh flex flex-col text-foreground overflow-hidden bg-background"
style=" style="
background-image: background-image:
linear-gradient(to bottom, linear-gradient(to bottom,

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="min-h-screen flex items-center justify-center p-4 bg-gradient-to-br from-background via-background to-muted/20"> <div class="min-h-dvh flex items-center justify-center p-4 bg-gradient-to-br from-background via-background to-muted/20">
<div class="w-full max-w-md space-y-8"> <div class="w-full max-w-md space-y-8">
<!-- Logo and Title --> <!-- Logo and Title -->
<div class="text-center space-y-6"> <div class="text-center space-y-6">

View file

@ -1,6 +1,6 @@
<template> <template>
<div <div
class="min-h-screen flex items-start sm:items-center justify-center px-4 sm:px-6 lg:px-8 xl:px-12 2xl:px-16 py-8 sm:py-12"> class="min-h-dvh flex items-start sm:items-center justify-center px-4 sm:px-6 lg:px-8 xl:px-12 2xl:px-16 py-8 sm:py-12">
<div class="flex flex-col items-center justify-center space-y-3 sm:space-y-6 max-w-4xl mx-auto w-full mt-8 sm:mt-0"> <div class="flex flex-col items-center justify-center space-y-3 sm:space-y-6 max-w-4xl mx-auto w-full mt-8 sm:mt-0">
<!-- Welcome Section --> <!-- Welcome Section -->
<div class="text-center space-y-2 sm:space-y-4"> <div class="text-center space-y-2 sm:space-y-4">

View file

@ -26,8 +26,8 @@ async function handleLoginSuccess() {
</script> </script>
<template> <template>
<div class="min-h-screen bg-background font-sans antialiased"> <div class="min-h-dvh bg-background font-sans antialiased">
<div class="relative flex min-h-screen flex-col" <div class="relative flex min-h-dvh flex-col"
style="padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom)"> style="padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom)">
<div v-if="!isLoginPage && !isAuthenticated" class="fixed top-0 right-0 z-50 p-3" style="padding-top: env(safe-area-inset-top)"> <div v-if="!isLoginPage && !isAuthenticated" class="fixed top-0 right-0 z-50 p-3" style="padding-top: env(safe-area-inset-top)">

View file

@ -26,8 +26,8 @@ async function handleLoginSuccess() {
</script> </script>
<template> <template>
<div class="min-h-screen bg-background font-sans antialiased"> <div class="min-h-dvh bg-background font-sans antialiased">
<div class="relative flex min-h-screen flex-col" <div class="relative flex min-h-dvh flex-col"
style="padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom)"> style="padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom)">
<!-- Top bar with login --> <!-- Top bar with login -->