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).
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
// Configuration tab: frame settings + firmware card + take control.
|
||||
// window.FRAME_API is set by the template. Checkboxes are always sent
|
||||
// Frame name/mode live in the page header now (frame_header.js) and
|
||||
// Calendar settings have their own tab (frame_calendar.js). window.
|
||||
// FRAME_API is set by the template. Checkboxes are always sent
|
||||
// explicitly as "true"/"false" -- the server treats absent fields as
|
||||
// "leave unchanged", so a checkbox must never be simply omitted.
|
||||
|
||||
async function saveConfig() {
|
||||
const minutes = parseInt(document.getElementById('refresh_interval_minutes').value, 10) || 60;
|
||||
const body = new URLSearchParams({
|
||||
mode: document.getElementById('frame_mode').value,
|
||||
name: document.getElementById('frame_name').value || '',
|
||||
order: document.getElementById('order').value,
|
||||
orientation: document.getElementById('orientation').value,
|
||||
refresh_interval_s: String(minutes * 60),
|
||||
@@ -37,69 +37,6 @@ document.getElementById('config-form').addEventListener('submit', async (e) => {
|
||||
}
|
||||
});
|
||||
|
||||
// ---- Calendar card: mode/view toggling, its own save, self opt-in, preview ----
|
||||
|
||||
const calendarCard = document.getElementById('calendar-card');
|
||||
if (calendarCard) {
|
||||
document.getElementById('frame_mode').addEventListener('change', () => {
|
||||
calendarCard.style.display = document.getElementById('frame_mode').value === 'calendar' ? 'block' : 'none';
|
||||
});
|
||||
|
||||
const inlayRow = document.getElementById('calendar-inlay-row');
|
||||
const inlayHint = document.getElementById('calendar-inlay-hint');
|
||||
document.getElementById('calendar_view').addEventListener('change', () => {
|
||||
const isAgenda = document.getElementById('calendar_view').value === 'agenda';
|
||||
inlayRow.style.display = isAgenda ? 'flex' : 'none';
|
||||
inlayHint.style.display = isAgenda ? 'block' : 'none';
|
||||
});
|
||||
|
||||
document.getElementById('calendar-config-form').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
const body = new URLSearchParams({
|
||||
calendar_view: document.getElementById('calendar_view').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' });
|
||||
|
||||
Reference in New Issue
Block a user