From 4173d2c0586be5a9ec26342fe08f0ed0a27b25ef Mon Sep 17 00:00:00 2001 From: nmemmert <67961292+nmemmert@users.noreply.github.com> Date: Thu, 22 Oct 2026 08:59:29 -0400 Subject: [PATCH] Planner: one compact toolbar (title, Calendar | Tasks, view switch, agenda range, Add event) Co-Authored-By: Claude Sonnet 5.5 --- public/calendar.js | 12 ++++++------ public/planner.js | 11 ++++++----- public/style.css | 12 ++++++++++-- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/public/calendar.js b/public/calendar.js index 297dede..4434d0b 100644 --- a/public/calendar.js +++ b/public/calendar.js @@ -54,11 +54,13 @@ const calState = { y: now0.getFullYear(), m: now0.getMonth(), sel: ymd(now0) }; async function viewCalendar() { const mode = store.get('cal_view', 'month'); const v = $('#view'); - v.innerHTML = `
${plannerHead('calendar', ``)} -
${[['month', 'Month'], ['week', 'Week'], ['day', 'Day'], ['agenda', 'Agenda']].map(([k, l]) => `${l}`).join('')}
+ const views = `
${[['month', 'Month'], ['week', 'Week'], ['day', 'Day'], ['agenda', 'Agenda']].map(([k, l]) => `${l}`).join('')}
` + + (mode === 'agenda' ? `` : ''); + v.innerHTML = `
${plannerHead('calendar', ``, views)}

Loading…

`; $('#ne').onclick = () => newEvent(mode === 'agenda' ? ymd(new Date()) : calState.sel); - v.querySelectorAll('.seg a[data-v]').forEach(a => a.onclick = e => { e.preventDefault(); store.set('cal_view', a.dataset.v); viewCalendar(); }); + if ($('#crange')) $('#crange').onchange = e => { store.set('cal_range', +e.target.value); viewCalendar(); }; + v.querySelectorAll('.sgrp a[data-v]').forEach(a => a.onclick = e => { e.preventDefault(); store.set('cal_view', a.dataset.v); viewCalendar(); }); $('#mc').onclick = manageCalendars; try { const cals = await jfetch('/api/cal/list'); @@ -72,10 +74,8 @@ async function renderAgendaList() { const { byDay, errors } = await loadAgenda(range); if (!location.hash.startsWith('#/calendar') || !$('#cbody')) return; const keys = [...byDay.keys()].sort(); - $('#cbody').innerHTML = `
${[[1, 'Today'], [7, '7 days'], [30, '30 days']].map(([n, l]) => `${l}`).join('')}
` - + (keys.map(k => `

${esc(dayLabel(k))}

${byDay.get(k).map(evRow).join('')}
`).join('') || '

Nothing coming up

') + $('#cbody').innerHTML = (keys.map(k => `

${esc(dayLabel(k))}

${byDay.get(k).map(evRow).join('')}
`).join('') || '

Nothing coming up

') + errors.map(e => `

${esc(e)}

`).join(''); - $('#cbody').querySelectorAll('.seg a[data-n]').forEach(a => a.onclick = e => { e.preventDefault(); store.set('cal_range', +a.dataset.n); viewCalendar(); }); } async function renderMonth() { diff --git a/public/planner.js b/public/planner.js index c740289..53a5d97 100644 --- a/public/planner.js +++ b/public/planner.js @@ -6,11 +6,12 @@ function viewPlanner(args = []) { const want = args[0] && ok.includes(args[0]) ? args[0] : store.get('planner_pane', ok[0]); location.replace('#/' + (ok.includes(want) ? want : ok[0] || 'home')); } -/** The page heading, with a Calendar | Tasks switch when this person may use both. `extra` (a button, say) sits on the same row, at the right. */ -function plannerHead(active, extra = '') { +/** One compact toolbar instead of stacked rows: title, Calendar | Tasks switch, then `mid` (the view switch) and `extra` (a button) pushed to the right. */ +function plannerHead(active, extra = '', mid = '') { try { localStorage.setItem(nk('planner_pane'), JSON.stringify(active)); } catch {} const panes = PLANNER_PANES.filter(p => allowed(p[0])); - const seg = panes.length < 2 ? '' : `
${panes.map(([k, l]) => `${l}`).join('')}
`; - const title = panes.length < 2 ? (PLANNER_PANES.find(p => p[0] === active) || [0, 'Planner'])[1] : 'Planner'; - return `

${esc(title)}

${seg || extra ? `
${seg}${extra}
` : ''}`; + const two = panes.length > 1; + const group = two ? `
${panes.map(([k, l]) => `${l}`).join('')}
` : ''; + const title = two ? 'Planner' : (PLANNER_PANES.find(p => p[0] === active) || [0, 'Planner'])[1]; + return `

${esc(title)}

${group}${mid}${extra}
`; } diff --git a/public/style.css b/public/style.css index d591c15..9d05e9d 100644 --- a/public/style.css +++ b/public/style.css @@ -560,5 +560,13 @@ body.lyropen { overflow: hidden; } body.nav-mini .ngrp { margin: 6px 14px; padding-top: 0; } body.nav-mini .ngrp span { display: none; } -.prow { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin: 6px 0 10px; } -.prow .seg { margin: 0; } + +/* Planner toolbar: one row (wraps on phones) */ +.ptop { display: flex; align-items: center; gap: 10px 12px; flex-wrap: wrap; margin: 0 0 12px; } +.ptop h1 { margin: 0 4px 0 0; font-size: 24px; } +.pspace { flex: 1; } +.sgrp { display: inline-flex; background: var(--panel2); border-radius: 999px; padding: 3px; gap: 2px; max-width: 100%; overflow-x: auto; } +.sgrp a { padding: 6px 14px; border-radius: 999px; color: var(--muted); font-size: 14px; white-space: nowrap; min-height: 32px; display: flex; align-items: center; } +.sgrp a.on { background: var(--accent); color: var(--accent-t); font-weight: 600; } +.psel { width: auto; min-height: 38px; padding: 0 12px; border-radius: 999px; font-size: 14px; } +@media (max-width: 560px) { .ptop h1 { width: 100%; } .pspace { display: none; } .ptop .btn { margin-left: auto; } }