From c684a424ebc8ab7c763e060411a7816f60931879 Mon Sep 17 00:00:00 2001 From: Scarriffle Date: Tue, 9 Jun 2026 20:32:01 +0200 Subject: [PATCH] Web: caret/selection fix, reminder options & labels, group mute, rounded modal - Stop the blinking text caret / selection on non-editable UI chrome (headings, buttons, icons, dropdowns): body is user-select:none, with text selection opted back in for inputs/textareas. Felt like an editable field. - Reminder options trimmed to 5/15/30 min, 1 h, 1 day, 1 week (dropped 10 min, 2 h, 2 days; added 1 week). Labels now read "5 Minuten vorher", "1 Tag vorher", "1 Woche vorher" instead of "vor 5 Min." / "vor 1 Tag(en)". - Group calendars can now be muted (reminder bell) in the sidebar when owned. - Event modal corners rounded (20px) to match the pill buttons. - version v45 -> v46. Co-Authored-By: Claude Opus 4.8 --- frontend/css/app.css | 9 ++++++++- frontend/js/calendar.js | 13 ++++++++----- frontend/js/i18n.js | 20 ++++++++++++++------ frontend/js/version.js | 2 +- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/frontend/css/app.css b/frontend/css/app.css index 403fb09..909297b 100644 --- a/frontend/css/app.css +++ b/frontend/css/app.css @@ -44,6 +44,13 @@ body { } input, select, textarea, button { font-family: inherit; font-size: inherit; color: inherit; } button { cursor: pointer; border: none; background: none; } +/* Treat the app like native UI chrome: clicking a heading, button, icon or + dropdown must not place a blinking text caret or select the label. Real text + entry (inputs / textareas) opts selection back in. */ +body { -webkit-user-select: none; user-select: none; } +input, textarea, [contenteditable="true"], .selectable { + -webkit-user-select: text; user-select: text; +} a { color: var(--primary); text-decoration: none; } ::-webkit-scrollbar { width: 6px; height: 6px; } ::-webkit-scrollbar-track { background: transparent; } @@ -936,7 +943,7 @@ a { color: var(--primary); text-decoration: none; } .modal-card { background: var(--bg-surface); border: 1px solid var(--border); - border-radius: var(--radius); + border-radius: 20px; width: 100%; max-height: 90vh; overflow-y: auto; box-shadow: var(--shadow-lg); diff --git a/frontend/js/calendar.js b/frontend/js/calendar.js index ea45173..82247a1 100644 --- a/frontend/js/calendar.js +++ b/frontend/js/calendar.js @@ -713,10 +713,12 @@ function renderCalendarList() { sourceLabel: `${t('shared_with_me')} · ${cal.shared_by || ''}`, remove: null }); }); // Group calendars (owned by the creator or reached via membership) — shown so - // they can be toggled/recoloured; marked with the group emoji. + // they can be toggled/recoloured. Owned group calendars can also be muted + // (reminders), which the server then syncs; member-reached ones can't (no PUT). state.localCalendars.filter(c => c.group).forEach(cal => { entries.push({ key: `local:${cal.id}`, source: 'local', dataId: `data-cal-id="${cal.id}"`, name: cal.name, color: cal.color, enabled: cal.enabled, + reminders: cal.owned !== false, remindersEnabled: cal.reminders_enabled !== false, sourceLabel: `${t('groups_title')} · ${cal.shared_by || ''}`, isGroupCal: true, remove: null }); }); state.icalSubscriptions.forEach(sub => { @@ -1718,13 +1720,14 @@ function resetColorPicker(color) { } // ── Reminders (local events only) ───────────────────────── -const REMINDER_OPTIONS = [0, 5, 10, 15, 30, 60, 120, 1440, 2880]; +const REMINDER_OPTIONS = [0, 5, 15, 30, 60, 1440, 10080]; function reminderLabel(min) { if (min <= 0) return t('reminder_at_start'); - if (min < 60) return t('reminder_min', { n: min }); - if (min < 1440) return t('reminder_hour', { n: min / 60 }); - return t('reminder_day', { n: min / 1440 }); + if (min < 60) return t('reminder_minutes', { n: min }); + if (min < 1440) { const h = min / 60; return h === 1 ? t('reminder_hour_one') : t('reminder_hours', { n: h }); } + if (min < 10080) { const d = min / 1440; return d === 1 ? t('reminder_day_one') : t('reminder_days', { n: d }); } + const w = min / 10080; return w === 1 ? t('reminder_week_one') : t('reminder_weeks', { n: w }); } function setEventReminders(arr) { diff --git a/frontend/js/i18n.js b/frontend/js/i18n.js index efd841c..3d5bc4e 100644 --- a/frontend/js/i18n.js +++ b/frontend/js/i18n.js @@ -97,9 +97,13 @@ const translations = { reminders: 'Benachrichtigungen', reminder_add: 'Benachrichtigung hinzufügen', reminder_at_start: 'Zur Startzeit', - reminder_min: 'vor {n} Min.', - reminder_hour: 'vor {n} Std.', - reminder_day: 'vor {n} Tag(en)', + reminder_minutes: '{n} Minuten vorher', + reminder_hour_one: '1 Stunde vorher', + reminder_hours: '{n} Stunden vorher', + reminder_day_one: '1 Tag vorher', + reminder_days: '{n} Tage vorher', + reminder_week_one: '1 Woche vorher', + reminder_weeks: '{n} Wochen vorher', calendar_reminders_on: 'Benachrichtigungen aktiviert', calendar_reminders_off: 'Benachrichtigungen deaktiviert', share: 'Teilen', @@ -378,9 +382,13 @@ const translations = { reminders: 'Reminders', reminder_add: 'Add reminder', reminder_at_start: 'At start time', - reminder_min: '{n} min before', - reminder_hour: '{n} h before', - reminder_day: '{n} day(s) before', + reminder_minutes: '{n} minutes before', + reminder_hour_one: '1 hour before', + reminder_hours: '{n} hours before', + reminder_day_one: '1 day before', + reminder_days: '{n} days before', + reminder_week_one: '1 week before', + reminder_weeks: '{n} weeks before', calendar_reminders_on: 'Reminders enabled', calendar_reminders_off: 'Reminders disabled', share: 'Share', diff --git a/frontend/js/version.js b/frontend/js/version.js index c061003..a175639 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 = 'v45'; +export const APP_VERSION = 'v46';