v012.42 updated
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "rosterchirp-backend",
|
"name": "rosterchirp-backend",
|
||||||
"version": "0.12.41",
|
"version": "0.12.42",
|
||||||
"description": "RosterChirp backend server",
|
"description": "RosterChirp backend server",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
2
build.sh
2
build.sh
@@ -13,7 +13,7 @@
|
|||||||
# ─────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
VERSION="${1:-0.12.41}"
|
VERSION="${1:-0.12.42}"
|
||||||
ACTION="${2:-}"
|
ACTION="${2:-}"
|
||||||
REGISTRY="${REGISTRY:-}"
|
REGISTRY="${REGISTRY:-}"
|
||||||
IMAGE_NAME="rosterchirp-dev"
|
IMAGE_NAME="rosterchirp-dev"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "rosterchirp-frontend",
|
"name": "rosterchirp-frontend",
|
||||||
"version": "0.12.41",
|
"version": "0.12.42",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -72,11 +72,32 @@ function fmt12(val) {
|
|||||||
function TimeInputMobile({ value, onChange }) {
|
function TimeInputMobile({ value, onChange }) {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [inputVal, setInputVal] = useState(fmt12(value));
|
const [inputVal, setInputVal] = useState(fmt12(value));
|
||||||
|
const [keyboardOffset, setKeyboardOffset] = useState(0);
|
||||||
const wrapRef = useRef(null);
|
const wrapRef = useRef(null);
|
||||||
const listRef = useRef(null);
|
const listRef = useRef(null);
|
||||||
|
|
||||||
useEffect(() => { setInputVal(fmt12(value)); }, [value]);
|
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(() => {
|
useEffect(() => {
|
||||||
if (!open || !listRef.current) return;
|
if (!open || !listRef.current) return;
|
||||||
const idx = TIME_SLOTS.findIndex(s => s.value === value);
|
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); } }}
|
onKeyDown={e => { if (e.key === 'Enter') { e.preventDefault(); commit(inputVal); } if (e.key === 'Escape') { setInputVal(fmt12(value)); setOpen(false); } }}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
inputMode="text"
|
inputMode="text"
|
||||||
|
enterKeyHint="done"
|
||||||
style={{ fontSize: 15, color: 'var(--primary)', fontWeight: 600, background: 'transparent', border: 'none', outline: 'none', cursor: 'text', width: 90 }}
|
style={{ fontSize: 15, color: 'var(--primary)', fontWeight: 600, background: 'transparent', border: 'none', outline: 'none', cursor: 'text', width: 90 }}
|
||||||
/>
|
/>
|
||||||
{open && (
|
{open && (
|
||||||
<div
|
<div
|
||||||
ref={listRef}
|
ref={listRef}
|
||||||
style={{
|
style={{
|
||||||
position: 'fixed', zIndex: 400,
|
position: 'fixed',
|
||||||
background: 'var(--surface)', border: '1px solid var(--border)',
|
zIndex: 400,
|
||||||
borderRadius: 8, boxShadow: '0 4px 20px rgba(0,0,0,0.2)',
|
background: 'var(--surface)',
|
||||||
width: 130, maxHeight: 5 * 40, overflowY: 'auto',
|
border: '1px solid var(--border)',
|
||||||
|
borderRadius: 8,
|
||||||
|
boxShadow: '0 4px 20px rgba(0,0,0,0.2)',
|
||||||
|
width: 130,
|
||||||
|
maxHeight: 5 * 40,
|
||||||
|
overflowY: 'auto',
|
||||||
|
bottom: keyboardOffset > 0 ? keyboardOffset + 10 : 'auto',
|
||||||
|
top: keyboardOffset > 0 ? 'auto' : '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{TIME_SLOTS.map(s => (
|
{TIME_SLOTS.map(s => (
|
||||||
@@ -486,7 +515,7 @@ export default function MobileEventForm({ event, eventTypes, userGroups, selecte
|
|||||||
|
|
||||||
{/* form wrapper suppresses Chrome Android's autofill chip bar; autoComplete="new-password"
|
{/* form wrapper suppresses Chrome Android's autofill chip bar; autoComplete="new-password"
|
||||||
on individual inputs is ignored by Chrome but respected on the form element */}
|
on individual inputs is ignored by Chrome but respected on the form element */}
|
||||||
<form autoComplete="off" onSubmit={e => e.preventDefault()} style={{ flex:1,overflowY:'auto', marginBottom:'50vh' }}>
|
<form autoComplete="off" onSubmit={e => e.preventDefault()} style={{ flex:1,overflowY:'auto' }}>
|
||||||
{/* Title */}
|
{/* Title */}
|
||||||
<div style={{ padding:'16px 20px',borderBottom:'1px solid var(--border)' }}>
|
<div style={{ padding:'16px 20px',borderBottom:'1px solid var(--border)' }}>
|
||||||
<input value={title} onChange={e => setTitle(e.target.value)} autoComplete="new-password" placeholder="Add title" autoCorrect="off" autoCapitalize="sentences" spellCheck={false} style={{ width:'100%',border:'none',background:'transparent',fontSize:22,fontWeight:700,color:'var(--text-primary)',outline:'none' }}/>
|
<input value={title} onChange={e => setTitle(e.target.value)} autoComplete="new-password" placeholder="Add title" autoCorrect="off" autoCapitalize="sentences" spellCheck={false} style={{ width:'100%',border:'none',background:'transparent',fontSize:22,fontWeight:700,color:'var(--text-primary)',outline:'none' }}/>
|
||||||
|
|||||||
@@ -198,6 +198,7 @@ function TimeInput({ value, onChange, style }) {
|
|||||||
style={{ width: '100%', cursor: 'text' }}
|
style={{ width: '100%', cursor: 'text' }}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
inputMode="text"
|
inputMode="text"
|
||||||
|
enterKeyHint="done"
|
||||||
placeholder="9:00 AM"
|
placeholder="9:00 AM"
|
||||||
/>
|
/>
|
||||||
{open && (
|
{open && (
|
||||||
|
|||||||
Reference in New Issue
Block a user