fix: hide navigation on keyboard visible
All checks were successful
Deploy to VPS (dist) / deploy (push) Successful in 1m32s

This commit is contained in:
Hewston Fox
2026-03-22 17:21:14 +02:00
parent 31d7eaf6ac
commit e5b3b97680
4 changed files with 97 additions and 17 deletions

72
pnpm-lock.yaml generated
View File

@@ -10,10 +10,10 @@ importers:
dependencies:
'@tailwindcss/vite':
specifier: ^4.2.1
version: 4.2.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2))
version: 4.2.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/devtools-vite':
specifier: ^0.5.3
version: 0.5.3(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2))
version: 0.5.3(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))
'@tanstack/react-devtools':
specifier: ^0.9.10
version: 0.9.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.11)
@@ -74,7 +74,7 @@ importers:
devDependencies:
'@tanstack/router-plugin':
specifier: ^1.166.3
version: 1.166.3(@tanstack/react-router@1.166.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2))
version: 1.166.3(@tanstack/react-router@1.166.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))
'@types/node':
specifier: ^24.10.1
version: 24.12.0
@@ -86,7 +86,7 @@ importers:
version: 19.2.3(@types/react@19.2.14)
'@vitejs/plugin-react-swc':
specifier: ^4.2.3
version: 4.2.3(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2))
version: 4.2.3(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))
globals:
specifier: ^17.4.0
version: 17.4.0
@@ -110,7 +110,7 @@ importers:
version: 5.9.3
vite:
specifier: ^7.3.1
version: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2)
version: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)
packages:
@@ -376,6 +376,9 @@ packages:
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
engines: {node: '>=6.0.0'}
'@jridgewell/source-map@0.3.11':
resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==}
'@jridgewell/sourcemap-codec@1.5.5':
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
@@ -1314,6 +1317,9 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'}
@@ -1359,6 +1365,9 @@ packages:
resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==}
engines: {node: '>=20'}
commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
@@ -2049,6 +2058,9 @@ packages:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
source-map-support@0.5.21:
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
source-map@0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
@@ -2092,6 +2104,11 @@ packages:
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
engines: {node: '>=6'}
terser@5.46.1:
resolution: {integrity: sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==}
engines: {node: '>=10'}
hasBin: true
tiny-invariant@1.3.3:
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
@@ -2466,6 +2483,12 @@ snapshots:
'@jridgewell/resolve-uri@3.1.2': {}
'@jridgewell/source-map@0.3.11':
dependencies:
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
optional: true
'@jridgewell/sourcemap-codec@1.5.5': {}
'@jridgewell/trace-mapping@0.3.31':
@@ -2872,12 +2895,12 @@ snapshots:
'@tailwindcss/oxide-win32-arm64-msvc': 4.2.1
'@tailwindcss/oxide-win32-x64-msvc': 4.2.1
'@tailwindcss/vite@4.2.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2))':
'@tailwindcss/vite@4.2.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@tailwindcss/node': 4.2.1
'@tailwindcss/oxide': 4.2.1
tailwindcss: 4.2.1
vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2)
vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)
'@tanstack/devtools-client@0.0.6':
dependencies:
@@ -2901,7 +2924,7 @@ snapshots:
transitivePeerDependencies:
- csstype
'@tanstack/devtools-vite@0.5.3(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2))':
'@tanstack/devtools-vite@0.5.3(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@babel/core': 7.29.0
'@babel/generator': 7.29.1
@@ -2913,7 +2936,7 @@ snapshots:
chalk: 5.6.2
launch-editor: 2.13.1
picomatch: 4.0.3
vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2)
vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
- bufferutil
- supports-color
@@ -3026,7 +3049,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@tanstack/router-plugin@1.166.3(@tanstack/react-router@1.166.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2))':
'@tanstack/router-plugin@1.166.3(@tanstack/react-router@1.166.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@babel/core': 7.29.0
'@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0)
@@ -3043,7 +3066,7 @@ snapshots:
zod: 3.25.76
optionalDependencies:
'@tanstack/react-router': 1.166.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2)
vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
- supports-color
@@ -3134,11 +3157,11 @@ snapshots:
dependencies:
csstype: 3.2.3
'@vitejs/plugin-react-swc@4.2.3(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2))':
'@vitejs/plugin-react-swc@4.2.3(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@rolldown/pluginutils': 1.0.0-rc.2
'@swc/core': 1.15.18
vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2)
vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
- '@swc/helpers'
@@ -3222,6 +3245,9 @@ snapshots:
node-releases: 2.0.36
update-browserslist-db: 1.2.3(browserslist@4.28.1)
buffer-from@1.1.2:
optional: true
call-bind-apply-helpers@1.0.2:
dependencies:
es-errors: 1.3.0
@@ -3270,6 +3296,9 @@ snapshots:
commander@14.0.3: {}
commander@2.20.3:
optional: true
convert-source-map@2.0.0: {}
cookie-es@2.0.0: {}
@@ -3908,6 +3937,12 @@ snapshots:
source-map-js@1.2.1: {}
source-map-support@0.5.21:
dependencies:
buffer-from: 1.1.2
source-map: 0.6.1
optional: true
source-map@0.6.1: {}
source-map@0.7.6: {}
@@ -3946,6 +3981,14 @@ snapshots:
tapable@2.3.0: {}
terser@5.46.1:
dependencies:
'@jridgewell/source-map': 0.3.11
acorn: 8.16.0
commander: 2.20.3
source-map-support: 0.5.21
optional: true
tiny-invariant@1.3.3: {}
tiny-warning@1.0.3: {}
@@ -4008,7 +4051,7 @@ snapshots:
varint@6.0.0:
optional: true
vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2):
vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
esbuild: 0.27.3
fdir: 6.5.0(picomatch@4.0.3)
@@ -4023,6 +4066,7 @@ snapshots:
lightningcss: 1.31.1
sass: 1.97.3
sass-embedded: 1.97.3
terser: 5.46.1
tsx: 4.21.0
yaml: 2.8.2

View File

@@ -76,6 +76,10 @@
pointer-events: none;
}
.hidden {
display: none;
}
.menuOverlay > * {
pointer-events: auto;
}

View File

@@ -1,6 +1,7 @@
import { type AnyRoute, useMatchRoute, useNavigate } from "@tanstack/react-router";
import { useTranslation } from "react-i18next";
import { AnimatePresence } from "motion/react";
import { useCallback, useEffect, useRef, useState } from "react";
import GlassSurface from "@components/surface/GlassSurface";
@@ -12,7 +13,6 @@ import CashdeskRoute from "@/routes/cashdesk";
import RouletteRoute from "@/routes/roulette";
import TasksRoute from "@/routes/tasks";
import EarningsRoute from "@/routes/earnings";
import { useCallback, useEffect, useRef, useState } from "react";
import shopIcon from "./assets/shop.svg";
import apiaryIcon from "./assets/apiary.svg";
@@ -51,6 +51,37 @@ const MENU_ITEMS = [
{ key: "nav.earnings", route: EarningsRoute, icon: earningsIcon, delay: 0 },
];
// 200px is larger than any OS chrome resize but smaller than the smallest software keyboard
const KEYBOARD_THRESHOLD = 200;
function useKeyboardVisible(): boolean {
const [keyboardVisible, setKeyboardVisible] = useState(false);
const baselineHeight = useRef<number>(0);
useEffect(() => {
const vv = window.visualViewport;
if (!vv) return;
baselineHeight.current = vv.height;
const handleResize = () => {
const newHeight = vv.height;
if (baselineHeight.current - newHeight > KEYBOARD_THRESHOLD) {
setKeyboardVisible(true);
} else {
setKeyboardVisible(false);
baselineHeight.current = newHeight;
}
};
vv.addEventListener("resize", handleResize);
return () => vv.removeEventListener("resize", handleResize);
}, []);
return keyboardVisible;
}
type BarProps = {
labelKey: string;
icon: string;
@@ -167,6 +198,7 @@ export default function Navigation() {
const navigate = useNavigate();
const [menuOpen, setMenuOpen] = useState<number>(0);
const navRef = useRef<HTMLDivElement>(null);
const keyboardVisible = useKeyboardVisible();
const handleOutsideClick = useCallback((e: MouseEvent) => {
if (navRef.current && !navRef.current.contains(e.target as Node)) {
@@ -193,7 +225,7 @@ export default function Navigation() {
};
return (
<div ref={navRef}>
<div ref={navRef} className={keyboardVisible ? classes.hidden : undefined}>
<div className={classes.menuOverlay}>
<AnimatePresence>
{menuOpen &&

View File

@@ -29,7 +29,7 @@
html,
body {
background: #9ebf3e;
height: var(--safe-area-height, 100dvh);
height: 100dvh;
width: var(--safe-area-width);
font-family: "BalsamiqSans", sans-serif;
overflow: hidden;