diff --git a/backend/package.json b/backend/package.json index 11b8104..a8df2e7 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "rosterchirp-backend", - "version": "0.12.41", + "version": "0.12.42", "description": "RosterChirp backend server", "main": "src/index.js", "scripts": { diff --git a/build.sh b/build.sh index d814c17..16be5cd 100644 --- a/build.sh +++ b/build.sh @@ -13,7 +13,7 @@ # ───────────────────────────────────────────────────────────── set -euo pipefail -VERSION="${1:-0.12.41}" +VERSION="${1:-0.12.42}" ACTION="${2:-}" REGISTRY="${REGISTRY:-}" IMAGE_NAME="rosterchirp-dev" diff --git a/frontend/package.json b/frontend/package.json index e00ebb4..a517550 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "rosterchirp-frontend", - "version": "0.12.41", + "version": "0.12.42", "private": true, "scripts": { "dev": "vite", diff --git a/frontend/src/components/MobileEventForm.jsx b/frontend/src/components/MobileEventForm.jsx index 709ad2e..2c3c3ea 100644 --- a/frontend/src/components/MobileEventForm.jsx +++ b/frontend/src/components/MobileEventForm.jsx @@ -72,11 +72,32 @@ function fmt12(val) { function TimeInputMobile({ value, onChange }) { const [open, setOpen] = useState(false); const [inputVal, setInputVal] = useState(fmt12(value)); + const [keyboardOffset, setKeyboardOffset] = useState(0); const wrapRef = useRef(null); const listRef = useRef(null); useEffect(() => { setInputVal(fmt12(value)); }, [value]); + // Handle keyboard positioning with Visual Viewport API + useEffect(() => { + const handleViewportChange = () => { + if (window.visualViewport) { + const offset = window.innerHeight - window.visualViewport.height; + setKeyboardOffset(offset > 0 ? offset : 0); + } + }; + + if (open) { + handleViewportChange(); + window.visualViewport?.addEventListener('resize', handleViewportChange); + return () => { + window.visualViewport?.removeEventListener('resize', handleViewportChange); + }; + } else { + setKeyboardOffset(0); + } + }, [open]); + useEffect(() => { if (!open || !listRef.current) return; const idx = TIME_SLOTS.findIndex(s => s.value === value); @@ -108,16 +129,24 @@ function TimeInputMobile({ value, onChange }) { onKeyDown={e => { if (e.key === 'Enter') { e.preventDefault(); commit(inputVal); } if (e.key === 'Escape') { setInputVal(fmt12(value)); setOpen(false); } }} autoComplete="off" inputMode="text" + enterKeyHint="done" style={{ fontSize: 15, color: 'var(--primary)', fontWeight: 600, background: 'transparent', border: 'none', outline: 'none', cursor: 'text', width: 90 }} /> {open && (