Files
espresso_frame/server/app/static/frame_calendar.js
T
tfaour 3a0007118c Move frame name/mode into the page header; Calendar gets its own tab
Frame name (pencil-icon inline edit) and the Photos/Calendar mode
selector now live in the page header, shared across all four per-frame
pages instead of being buried in the Configuration form -- so renaming
a frame or flipping its mode no longer requires navigating to a
specific tab first.

Calendar settings move out of a conditionally-hidden card on the
Configuration tab into their own dedicated tab (new /frames/{id}/
calendar route), visually greyed out when the frame is in Photos mode
but still fully usable so calendar settings can be configured ahead of
switching modes. Also wires the week-start setting into the UI for the
first time (the column/backend support landed earlier but had no
control anywhere).
2026-07-22 21:21:00 -04:00

83 lines
3.1 KiB
JavaScript

// Calendar tab: view/week-start/photo-inlay settings, per-user opt-in,
// and the rendered preview. Extracted from frame_config.js when the
// Calendar card became its own tab (window.FRAME_API is set by the
// template; checkboxes are always sent explicitly as "true"/"false").
document.getElementById('calendar-config-form').addEventListener('submit', async (e) => {
e.preventDefault();
const body = new URLSearchParams({
calendar_view: document.getElementById('calendar_view').value,
calendar_week_start: document.getElementById('calendar_week_start').value,
calendar_photo_inlay: String(document.getElementById('calendar_photo_inlay').checked),
});
try {
const resp = await fetch(`${window.FRAME_API}/config`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body,
});
if (!resp.ok) throw new Error(await apiError(resp));
showStatus(true, 'Saved.');
loadCalendarPreview();
} catch (e) {
showStatus(false, e.message);
}
});
// Each person's own opt-in -- auto-saves on toggle, not batched into the
// form above, since it's the toggling user's own preference (see
// api_frames.py's /calendar-included), not a frame-wide setting.
document.querySelectorAll('.calendar-self-toggle').forEach((el) => {
el.addEventListener('change', async () => {
try {
const resp = await fetch(`${window.FRAME_API}/calendar-included`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ included: el.checked }),
});
if (!resp.ok) throw new Error(await apiError(resp));
showStatus(true, el.checked ? 'Your calendar is included on this frame.' : 'Your calendar removed from this frame.');
} catch (e) {
el.checked = !el.checked;
showStatus(false, e.message);
}
});
});
function loadCalendarPreview() {
document.getElementById('calendar-preview').src = `${window.FRAME_API}/preview/calendar?_=${Date.now()}`;
}
document.getElementById('calendar-preview-refresh').addEventListener('click', loadCalendarPreview);
loadCalendarPreview();
async function takeControl() {
try {
const resp = await fetch(`${window.FRAME_API}/take-control`, { method: 'POST' });
if (!resp.ok) throw new Error(await apiError(resp));
showStatus(true, 'You have control now.');
loadControl();
} catch (e) {
showStatus(false, e.message);
}
}
async function loadControl() {
const banner = document.getElementById('control-banner');
try {
const resp = await fetch(`${window.FRAME_API}/queue`);
if (!resp.ok) return; // unconfigured frame: control still works via 409s
const data = await resp.json();
if (data.control && !data.control.you) {
banner.style.display = 'flex';
document.getElementById('control-holder').textContent = data.control.controller
? `${data.control.controller} currently has control of this frame.`
: 'Nobody has control of this frame yet.';
} else {
banner.style.display = 'none';
}
} catch (e) { /* banner is best-effort */ }
}
document.getElementById('take-control').addEventListener('click', takeControl);
loadControl();