From fdf9af09cdede6ed9d2c51a1a4550081fabf6af4 Mon Sep 17 00:00:00 2001
From: Scarriffle
Date: Thu, 7 May 2026 18:52:51 +0200
Subject: [PATCH] fix(mobile): Zoom blocken, Long-Press, KW-Bubble, Swipe-Nav,
Safe-Area
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Viewport: maximum-scale=1, user-scalable=no — kein Pinch-Zoom mehr
- Profil-Dropdown öffnet wieder: overflow:hidden auf .topbar-right
in der Mobile-Media-Query entfernt (hatte das absolut positionierte
Dropdown abgeschnitten)
- Long-Press auf Kalenderzellen markiert keinen Text mehr:
user-select/touch-callout/tap-highlight in der ganzen Mobile-UI aus
- Long-Press auf Avatar zeigt nicht "Bild speichern":
-webkit-touch-callout:none + pointer-events:none auf
- Kalenderwochen erscheinen als kleine Bubble oben links in jeder
Zeile statt als eigene 38px-Spalte
- Status-Bar-Overlap im Settings-Modal behoben: safe-area-inset-top
auf .settings-page-header und Modal-Header in der Mobile-Media-Query
- Swipe links/rechts auf #view-container navigiert prev/next
(≥60 px, überwiegend horizontal, < 700 ms)
- Version v3 → v4 (auch SW-Cache)
Co-Authored-By: Claude Sonnet 4.6
---
frontend/css/app.css | 60 ++++++++++++++++++++++++++++++++++++++++-
frontend/index.html | 10 +++----
frontend/js/calendar.js | 28 +++++++++++++++++++
frontend/js/version.js | 2 +-
frontend/sw.js | 2 +-
5 files changed, 94 insertions(+), 8 deletions(-)
diff --git a/frontend/css/app.css b/frontend/css/app.css
index bbca5fb..213afb0 100644
--- a/frontend/css/app.css
+++ b/frontend/css/app.css
@@ -1270,7 +1270,7 @@ a { color: var(--primary); text-decoration: none; }
}
.topbar-right {
min-width: 0;
- overflow: hidden;
+ /* no overflow:hidden — would clip the user dropdown on tap */
}
.view-switcher {
overflow-x: auto;
@@ -1346,6 +1346,64 @@ a { color: var(--primary); text-decoration: none; }
/* ── Misc safety: prevent overflow on flex topbar items ──── */
.main-view { width: 100%; min-width: 0; }
#view-container { max-width: 100%; overflow-x: hidden; }
+
+ /* ── Long-press / text-selection / image-save fixes ──────── */
+ /* Calendar UI shouldn't be selectable on touch — long-press
+ should reach our handlers, not trigger iOS text selection. */
+ .topbar, .sidebar, .main-view,
+ .month-view, .month-row, .month-col, .cell-day, .month-events-overlay, .month-span-event,
+ .week-view, .day-view, .week-day-col, .week-day-header, .week-allday-row,
+ .quarter-view, .agenda-view,
+ .view-switcher, .view-btn, .btn, .icon-btn, .user-avatar, .user-dropdown, .dropdown-item {
+ -webkit-user-select: none;
+ user-select: none;
+ -webkit-touch-callout: none;
+ -webkit-tap-highlight-color: transparent;
+ }
+ /* Faster taps, no double-tap zoom on interactive elements */
+ .icon-btn, .btn, .view-btn, .user-avatar, .month-col, .week-day-col, .dropdown-item,
+ .sidebar-copyright, .impressum-link, .modal-close, [data-modal] {
+ touch-action: manipulation;
+ }
+ /* Avatar long-press: don't show "Save Image" — taps reach parent */
+ .user-avatar img {
+ -webkit-touch-callout: none;
+ pointer-events: none;
+ }
+
+ /* ── Calendar weeks (KW) shown as a small bubble, not a column ── */
+ .month-header {
+ grid-template-columns: repeat(7, 1fr) !important;
+ }
+ .month-kw-header { display: none !important; }
+ .month-row-right {
+ margin-left: 0 !important;
+ }
+ .month-kw-cell {
+ position: absolute;
+ left: 3px; top: 3px;
+ width: auto; height: auto;
+ bottom: auto;
+ padding: 1px 7px;
+ background: var(--bg-active);
+ border: none !important;
+ border-radius: 10px;
+ font-size: 10px; font-weight: 600;
+ color: var(--text-2);
+ z-index: 5;
+ display: inline-flex;
+ align-items: center;
+ }
+
+ /* ── Status-bar safe area inside full-screen modals (PWA) ── */
+ .modal-card .modal-header,
+ .settings-page-header {
+ padding-top: calc(16px + env(safe-area-inset-top, 0px));
+ }
+ .modal-footer,
+ .settings-page-body {
+ padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
+ }
}
/* iOS notch / home-indicator safe areas (PWA standalone) */
diff --git a/frontend/index.html b/frontend/index.html
index 69bce84..9efd076 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -2,9 +2,9 @@
-
+
- Calendarr v3
+ Calendarr v4
@@ -77,7 +77,7 @@
-
+
@@ -179,7 +179,7 @@
-
+
@@ -841,7 +841,7 @@
scarriffleservices@gmail.com
diff --git a/frontend/js/calendar.js b/frontend/js/calendar.js
index 1135044..464aeda 100644
--- a/frontend/js/calendar.js
+++ b/frontend/js/calendar.js
@@ -76,6 +76,7 @@ export async function initCalendar() {
bindHAAccountModal();
bindSettingsModal();
bindProfileModal();
+ bindSwipeNavigation();
handleHAOAuthReturn();
}
@@ -755,6 +756,33 @@ function renderCalendarList() {
});
}
+// ── Swipe navigation (mobile) ─────────────────────────────
+function bindSwipeNavigation() {
+ const container = document.getElementById('view-container');
+ if (!container) return;
+ let startX = 0, startY = 0, startT = 0, active = false;
+ container.addEventListener('touchstart', e => {
+ if (e.touches.length !== 1) { active = false; return; }
+ startX = e.touches[0].clientX;
+ startY = e.touches[0].clientY;
+ startT = Date.now();
+ active = true;
+ }, { passive: true });
+ container.addEventListener('touchend', e => {
+ if (!active) return;
+ active = false;
+ const t = e.changedTouches[0];
+ const dx = t.clientX - startX;
+ const dy = t.clientY - startY;
+ const dt = Date.now() - startT;
+ // Horizontal swipe: ≥ 60px, mostly horizontal, faster than 700ms
+ if (Math.abs(dx) > 60 && Math.abs(dx) > Math.abs(dy) * 1.5 && dt < 700) {
+ navigate(dx < 0 ? 1 : -1);
+ fetchAndRender();
+ }
+ }, { passive: true });
+}
+
// ── Navigation ────────────────────────────────────────────
function navigate(dir) {
const d = state.currentDate;
diff --git a/frontend/js/version.js b/frontend/js/version.js
index b54d089..9f06a98 100644
--- a/frontend/js/version.js
+++ b/frontend/js/version.js
@@ -1,2 +1,2 @@
// Increment APP_VERSION with every code change
-export const APP_VERSION = 'v3';
+export const APP_VERSION = 'v4';
diff --git a/frontend/sw.js b/frontend/sw.js
index 81d23ad..0213bb1 100644
--- a/frontend/sw.js
+++ b/frontend/sw.js
@@ -1,7 +1,7 @@
// Calendarr Service Worker
// Cache-first for static assets, network-first for /api/* (graceful offline)
-const CACHE_VERSION = 'calendarr-v3';
+const CACHE_VERSION = 'calendarr-v4';
const STATIC_ASSETS = [
'/',
'/index.html',