diff --git a/static/js/calendar.js b/static/js/calendar.js index 717e6967f..9e443af3a 100644 --- a/static/js/calendar.js +++ b/static/js/calendar.js @@ -9,7 +9,7 @@ import { makeWindowDraggable } from './windowDrag.js'; import { attachColorPicker } from './colorPicker.js'; import { bindMenuDismiss } from './escMenuStack.js'; import { - WEEKDAYS, MONTHS, MON_SHORT, + WEEKDAYS, WEEKDAYS_SUN, MONTHS, MON_SHORT, CAL_PALETTE, CAL_COLORS, _CAL_CUSTOM_GRADIENT, _TYPE_PALETTE, _trashIcon, _moreIcon, _bellIcon, _isCalBgImage, _calBgImageUrl, _calBgCss, @@ -64,6 +64,8 @@ let _hiddenTypes = new Set(); // event_type values to hide let _onlyImportant = false; let _filtersCollapsed = localStorage.getItem('cal-filters-collapsed') === '1'; +// Week-start preference: 'mon' (default, Mon=first col) or 'sun' (Sun=first col). +let _weekStartSun = localStorage.getItem('cal-week-start') === 'sun'; let _selectedDay = null; let _view = 'month'; let _searchQuery = ''; @@ -360,14 +362,14 @@ function _today() { return _ds(new Date()); } function _monthRange(d) { const y = d.getFullYear(), m = d.getMonth(); const first = new Date(y, m, 1); - const dow = (first.getDay() + 6) % 7; + const dow = _weekStartSun ? first.getDay() : (first.getDay() + 6) % 7; const gs = new Date(y, m, 1 - dow); const ge = new Date(gs); ge.setDate(gs.getDate() + 42); return [_ds(gs), _ds(ge)]; } function _weekRange(d) { - const dow = (d.getDay() + 6) % 7; + const dow = _weekStartSun ? d.getDay() : (d.getDay() + 6) % 7; const s = new Date(d); s.setDate(d.getDate() - dow); const e = new Date(s); e.setDate(s.getDate() + 7); return [_ds(s), _ds(e)]; @@ -928,11 +930,11 @@ async function _renderMonth() { _slideDir = 0; let h = _headerHTML() + _filtersRowHTML() + `
`; h += '
'; - for (const wd of WEEKDAYS) h += `
${wd}
`; + for (const wd of (_weekStartSun ? WEEKDAYS_SUN : WEEKDAYS)) h += `
${wd}
`; h += '
'; const first = new Date(y, m, 1); - const dow = (first.getDay() + 6) % 7; + const dow = _weekStartSun ? first.getDay() : (first.getDay() + 6) % 7; const gs = new Date(y, m, 1 - dow); const multiDay = _events.filter(e => { @@ -1204,8 +1206,8 @@ async function _renderWeek() { const timedEvents = _eventsForDay(ds).filter(e => _eventVisible(e) && !e.all_day); const isSun = d.getDay() === 0; - colsHtml += `
`; - colsHtml += `
${WEEKDAYS[idx]}${d.getDate()}
`; + colsHtml += `
`; + colsHtml += `
${(_weekStartSun ? WEEKDAYS_SUN : WEEKDAYS)[idx]}${d.getDate()}
`; // All-day strip colsHtml += `
`; for (const ev of allDayEvents) { @@ -1724,9 +1726,9 @@ async function _renderYear() { for (let m = 0; m < 12; m++) { h += `
${MON_SHORT[m]}
`; h += '
'; - for (const wd of ['M', 'T', 'W', 'T', 'F', 'S', 'S']) h += `
${wd}
`; + for (const wd of (_weekStartSun ? ['S','M','T','W','T','F','S'] : ['M','T','W','T','F','S','S'])) h += `
${wd}
`; const first = new Date(y, m, 1); - const dow = (first.getDay() + 6) % 7; + const dow = _weekStartSun ? first.getDay() : (first.getDay() + 6) % 7; const daysInMonth = new Date(y, m + 1, 0).getDate(); for (let p = 0; p < dow; p++) h += '
'; for (let d = 1; d <= daysInMonth; d++) { @@ -2474,6 +2476,13 @@ async function _showCalSettings() {
Download a calendar as .ics for backup or to import into another app.
+
+
Week starts on
+
+ + +
+
Sync
@@ -2494,6 +2503,28 @@ async function _showCalSettings() { overlay.querySelector('#cal-settings-close').addEventListener('click', cleanup); overlay.addEventListener('click', (e) => { if (e.target === overlay) cleanup(); }); + // Week-start toggle: save to localStorage, update module state, re-render. + const _monBtn = overlay.querySelector('#cal-wstart-mon'); + const _sunBtn = overlay.querySelector('#cal-wstart-sun'); + const _activeStyle = 'color-mix(in srgb, var(--accent,var(--red)) 18%, var(--panel))'; + const _inactiveStyle = 'var(--panel)'; + const _applyWeekStartActive = () => { + if (_monBtn) _monBtn.style.background = _weekStartSun ? _inactiveStyle : _activeStyle; + if (_sunBtn) _sunBtn.style.background = _weekStartSun ? _activeStyle : _inactiveStyle; + }; + _monBtn?.addEventListener('click', () => { + _weekStartSun = false; + localStorage.setItem('cal-week-start', 'mon'); + _applyWeekStartActive(); + if (_open) _render(); + }); + _sunBtn?.addEventListener('click', () => { + _weekStartSun = true; + localStorage.setItem('cal-week-start', 'sun'); + _applyWeekStartActive(); + if (_open) _render(); + }); + // Create a new (local) calendar. Defaults the name + next palette color, then // reopens the panel so the user can rename it inline and pick a color. overlay.querySelector('#cal-settings-add')?.addEventListener('click', async (e) => { diff --git a/static/js/calendar/utils.js b/static/js/calendar/utils.js index a33cc1c66..7e6dd68e8 100644 --- a/static/js/calendar/utils.js +++ b/static/js/calendar/utils.js @@ -3,7 +3,9 @@ // Pure constants + zero-state helpers for the calendar UI. // No DOM, no fetch, no global mutable state — safe to import anywhere. -export const WEEKDAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; +export const WEEKDAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; +export const WEEKDAYS_SUN = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; + export const MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];