diff --git a/apps/web/src/components/QuickCreate.vue b/apps/web/src/components/QuickCreate.vue index fb7a866..1b2a31a 100644 --- a/apps/web/src/components/QuickCreate.vue +++ b/apps/web/src/components/QuickCreate.vue @@ -78,8 +78,18 @@ let dragMoved = false; let dragOffsetX = 0; let dragOffsetY = 0; +function mobileTabbarPx(): number { + if (typeof window === 'undefined' || viewport.value.w > 900) return 0; + const bar = document.querySelector('.mobile-tabbar'); + if (bar instanceof HTMLElement) { + const h = bar.getBoundingClientRect().height; + if (h > 0) return h; + } + return 64; +} + function defaultPos(): FabPos { - const extra = viewport.value.w <= 900 ? 64 : 0; + const extra = mobileTabbarPx(); return { left: FAB_MARGIN_LEFT, top: Math.max(8, viewport.value.h - FAB_MARGIN_BOTTOM - extra - FAB_SIZE), @@ -88,7 +98,7 @@ function defaultPos(): FabPos { function clampPos(pos: FabPos): FabPos { const margin = 8; - const bottomGap = viewport.value.w <= 900 ? 64 : 0; + const bottomGap = mobileTabbarPx(); return { left: Math.min(Math.max(margin, pos.left), viewport.value.w - FAB_SIZE - margin), top: Math.min( diff --git a/apps/web/src/styles/main.css b/apps/web/src/styles/main.css index 1f0b260..1db995a 100644 --- a/apps/web/src/styles/main.css +++ b/apps/web/src/styles/main.css @@ -2,6 +2,8 @@ @import "./tokens.css"; :root { + --mobile-tabbar-h: 0px; + /* Surface & Background */ --bg: #f8fafc; --surface: #ffffff; @@ -251,6 +253,10 @@ textarea { } @media (max-width: 900px) { + :root { + --mobile-tabbar-h: calc(3.65rem + env(safe-area-inset-bottom, 0px)); + } + h1 { font-size: clamp(1.35rem, 5vw, 1.75rem); } diff --git a/apps/web/src/views/ActivityDetailView.vue b/apps/web/src/views/ActivityDetailView.vue index 744d4e8..be7945b 100644 --- a/apps/web/src/views/ActivityDetailView.vue +++ b/apps/web/src/views/ActivityDetailView.vue @@ -319,6 +319,7 @@ onMounted(load); margin: 0; display: grid; gap: 0.9rem; + padding-bottom: 5.5rem; } .nav { @@ -572,7 +573,7 @@ dd { .dock { position: fixed; inset-inline: 0.85rem; - bottom: calc(0.55rem + env(safe-area-inset-bottom)); + bottom: calc(0.55rem + var(--mobile-tabbar-h)); display: grid; grid-template-columns: 1.15fr 1fr 1fr; gap: 0.5rem; @@ -607,6 +608,10 @@ dd { } @media (min-width: 900px) { + .page { + padding-bottom: 0; + } + .dock { position: sticky; inset-inline: auto; diff --git a/apps/web/src/views/ActivityFormView.vue b/apps/web/src/views/ActivityFormView.vue index 9e4f5f7..fb2c29b 100644 --- a/apps/web/src/views/ActivityFormView.vue +++ b/apps/web/src/views/ActivityFormView.vue @@ -661,6 +661,10 @@ watch([id, isNew], () => void load(), { immediate: true });