Web: expose month-navigation mode as a named dropdown

New 'Monatswechsel' setting (synced flag already existed as month_view_paged):
- Continuous scroll (week): current behaviour — wheel scrolls by a week,
  buttons/swipe jump 4 weeks.
- Page by page (month): wheel navigation is disabled; buttons and horizontal
  swipe jump a whole calendar month.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-15 06:26:02 +02:00
parent 7a89cc44f8
commit a7802778b6
4 changed files with 22 additions and 4 deletions

View File

@@ -1209,9 +1209,14 @@ function bindSwipeNavigation() {
function navigate(dir) { function navigate(dir) {
const d = state.currentDate; const d = state.currentDate;
if (state.currentView === 'month') { if (state.currentView === 'month') {
// Buttons jump 4 weeks (one screenful) if (state.settings && state.settings.month_view_paged) {
// Paged mode: jump a whole calendar month.
state.currentDate = new Date(d.getFullYear(), d.getMonth() + dir, Math.min(d.getDate(), 28));
} else {
// Scroll mode: buttons jump 4 weeks (one screenful of the rolling grid).
state.currentDate = new Date(d); state.currentDate = new Date(d);
state.currentDate.setDate(d.getDate() + dir * 28); state.currentDate.setDate(d.getDate() + dir * 28);
}
} else if (state.currentView === 'week') { } else if (state.currentView === 'week') {
state.currentDate = new Date(d); state.currentDate = new Date(d);
state.currentDate.setDate(d.getDate() + dir * 7); state.currentDate.setDate(d.getDate() + dir * 7);
@@ -1335,6 +1340,8 @@ function bindTopbar() {
_wheelLast = now; _wheelLast = now;
const dir = e.deltaY > 0 ? 1 : -1; const dir = e.deltaY > 0 ? 1 : -1;
if (state.currentView === 'month') { if (state.currentView === 'month') {
// Paged mode: no scroll navigation — only buttons / horizontal swipe.
if (state.settings && state.settings.month_view_paged) return;
state.currentDate = new Date(state.currentDate); state.currentDate = new Date(state.currentDate);
state.currentDate.setDate(state.currentDate.getDate() + dir * 7); state.currentDate.setDate(state.currentDate.getDate() + dir * 7);
fetchAndRender(); fetchAndRender();
@@ -3463,11 +3470,13 @@ function wireSettingRow(def) {
function readAppearanceTable() { function readAppearanceTable() {
const out = {}; const out = {};
const numKeys = new Set(['hour_height', 'default_event_duration_minutes']); const numKeys = new Set(['hour_height', 'default_event_duration_minutes']);
const boolKeys = new Set(['month_view_paged']);
SETTING_GROUPS.forEach(g => g.rows.forEach(def => { SETTING_GROUPS.forEach(g => g.rows.forEach(def => {
if (def.type === 'select') { if (def.type === 'select') {
const el = document.querySelector(`[data-skey="${def.key}"]`); const el = document.querySelector(`[data-skey="${def.key}"]`);
let v = el ? el.value : state.settings[def.key]; let v = el ? el.value : state.settings[def.key];
if (numKeys.has(def.key)) v = Number(v); if (numKeys.has(def.key)) v = Number(v);
else if (boolKeys.has(def.key)) v = (String(v) === 'true');
out[def.key] = v; out[def.key] = v;
} else if (def.type === 'toggle') { } else if (def.type === 'toggle') {
const el = document.querySelector(`[data-vtoggle="${def.key}"]`); const el = document.querySelector(`[data-vtoggle="${def.key}"]`);

View File

@@ -92,6 +92,9 @@ const translations = {
settings_week_start: 'Erster Wochentag', settings_week_start: 'Erster Wochentag',
week_start_monday: 'Montag', week_start_sunday: 'Sonntag', week_start_monday: 'Montag', week_start_sunday: 'Sonntag',
settings_dim_past: 'Vergangene Termine ausgrauen', settings_dim_past: 'Vergangene Termine ausgrauen',
settings_month_mode: 'Monatswechsel',
settings_month_mode_scroll: 'Fortlaufend scrollen (Woche)',
settings_month_mode_paged: 'Seitenweise blättern (Monat)',
settings_default_duration: 'Standard-Termindauer', settings_default_duration: 'Standard-Termindauer',
settings_privacy: 'Privatsphäre', settings_privacy: 'Privatsphäre',
settings_private_visibility: 'Private Termine für Gruppenmitglieder', settings_private_visibility: 'Private Termine für Gruppenmitglieder',
@@ -446,6 +449,9 @@ const translations = {
settings_week_start: 'First day of week', settings_week_start: 'First day of week',
week_start_monday: 'Monday', week_start_sunday: 'Sunday', week_start_monday: 'Monday', week_start_sunday: 'Sunday',
settings_dim_past: 'Dim past events', settings_dim_past: 'Dim past events',
settings_month_mode: 'Month switching',
settings_month_mode_scroll: 'Continuous scroll (week)',
settings_month_mode_paged: 'Page by page (month)',
settings_default_duration: 'Default event duration', settings_default_duration: 'Default event duration',
settings_privacy: 'Privacy', settings_privacy: 'Privacy',
settings_private_visibility: 'Private events for group members', settings_private_visibility: 'Private events for group members',

View File

@@ -34,6 +34,9 @@ export const SETTING_GROUPS = [
{ v: 'monday', tk: 'week_start_monday' }, { v: 'sunday', tk: 'week_start_sunday' }, { v: 'monday', tk: 'week_start_monday' }, { v: 'sunday', tk: 'week_start_sunday' },
] }, ] },
{ key: 'dim_past_events', labelKey: 'settings_dim_past', type: 'toggle' }, { key: 'dim_past_events', labelKey: 'settings_dim_past', type: 'toggle' },
{ key: 'month_view_paged', labelKey: 'settings_month_mode', type: 'select', opts: [
{ v: false, tk: 'settings_month_mode_scroll' }, { v: true, tk: 'settings_month_mode_paged' },
] },
{ key: 'hour_height', labelKey: 'settings_hour_height', type: 'select', opts: [ { key: 'hour_height', labelKey: 'settings_hour_height', type: 'select', opts: [
{ v: 28, tk: 'hour_compact' }, { v: 44, tk: 'hour_normal' }, { v: 28, tk: 'hour_compact' }, { v: 44, tk: 'hour_normal' },
{ v: 60, tk: 'hour_comfort' }, { v: 80, tk: 'hour_large' }, { v: 60, tk: 'hour_comfort' }, { v: 80, tk: 'hour_large' },

View File

@@ -7,7 +7,7 @@
// the entry HTML / version files). New releases take effect on the next // the entry HTML / version files). New releases take effect on the next
// reload, no manual SW unregister required. // reload, no manual SW unregister required.
const CACHE_VERSION = 'calendarr-v29'; const CACHE_VERSION = 'calendarr-v30';
const OFFLINE_SHELL = ['/', '/index.html']; const OFFLINE_SHELL = ['/', '/index.html'];
self.addEventListener('install', event => { self.addEventListener('install', event => {