Move mode picker below device status bar; fix invisible calendar lines; add CalDAV calendar support
Build and push server image / build-and-push (push) Successful in 50s
Build and push server image / build-and-push (push) Successful in 50s
Calendar rule/grid lines were light gray, which dithers away to near-invisible on the 6-color e-ink palette -- now black. CalDAV accounts (Nextcloud, Fastmail, iCloud, ...) can now be linked alongside the existing single ICS subscription, since one account can expose several calendars. A frame's Calendar tab now lists calendars per person rather than one opt-in per person: your own row shows every calendar you have available with a full add/remove toggle, while other linked users' rows show only calendars they've included, toggleable off (mute) but not on -- only a calendar's owner can add it to a shared frame. FrameCalendar replaces the old single-boolean UserFrame.calendar_included; existing opt-ins are migrated forward.
This commit is contained in:
@@ -24,19 +24,27 @@ document.getElementById('calendar-config-form').addEventListener('submit', async
|
||||
}
|
||||
});
|
||||
|
||||
// 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) => {
|
||||
// Each calendar's own include/mute toggle -- auto-saves on change, not
|
||||
// batched into the form above, since it's a data-sharing choice (see
|
||||
// api_frames.py's /calendar-select), not a frame-wide setting. Works the
|
||||
// same element for your own calendars (full add/remove) and other
|
||||
// people's (mute only) -- the server enforces which direction is allowed
|
||||
// and this just reverts the checkbox with an error message if rejected.
|
||||
document.querySelectorAll('.calendar-toggle').forEach((el) => {
|
||||
el.addEventListener('change', async () => {
|
||||
try {
|
||||
const resp = await fetch(`${window.FRAME_API}/calendar-included`, {
|
||||
const resp = await fetch(`${window.FRAME_API}/calendar-select`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ included: el.checked }),
|
||||
body: JSON.stringify({
|
||||
user_id: Number(el.dataset.userId),
|
||||
calendar_key: el.dataset.key,
|
||||
calendar_label: el.dataset.label,
|
||||
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.');
|
||||
showStatus(true, el.checked ? 'Calendar included on this frame.' : 'Calendar removed from this frame.');
|
||||
} catch (e) {
|
||||
el.checked = !el.checked;
|
||||
showStatus(false, e.message);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// Settings page: "Discover calendars" against the CalDAV account already
|
||||
// saved on this form (same idiom as frame_photos.js's Load Albums using
|
||||
// the frame's already-saved Immich creds) -- so this only works after
|
||||
// the CalDAV URL/username/password have been saved once.
|
||||
|
||||
const discoverBtn = document.getElementById('caldav-discover');
|
||||
if (discoverBtn) {
|
||||
discoverBtn.addEventListener('click', async () => {
|
||||
const list = document.getElementById('caldav-calendar-list');
|
||||
discoverBtn.disabled = true;
|
||||
try {
|
||||
const resp = await fetch('/api/settings/caldav-discover', { method: 'POST' });
|
||||
if (!resp.ok) throw new Error(await apiError(resp));
|
||||
const calendars = await resp.json();
|
||||
list.innerHTML = '';
|
||||
if (calendars.length === 0) {
|
||||
list.innerHTML = '<li>No calendars found in this account.</li>';
|
||||
} else {
|
||||
for (const c of calendars) {
|
||||
const li = document.createElement('li');
|
||||
li.textContent = c.display_name;
|
||||
list.appendChild(li);
|
||||
}
|
||||
}
|
||||
showStatus(true, `Found ${calendars.length} calendar${calendars.length === 1 ? '' : 's'}.`);
|
||||
} catch (e) {
|
||||
showStatus(false, e.message);
|
||||
} finally {
|
||||
discoverBtn.disabled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -261,6 +261,11 @@ input:focus, select:focus {
|
||||
.checkbox-row input { width: auto; margin-top: 0; }
|
||||
.checkbox-row label { margin-top: 0; font-weight: normal; }
|
||||
|
||||
.calendar-user-list { list-style: none; margin: 12px 0 0; padding: 0; }
|
||||
.calendar-user-list > li { margin-top: 14px; }
|
||||
.calendar-user-list > li:first-child { margin-top: 0; }
|
||||
.calendar-user-name { margin: 0; font-size: 13px; font-weight: 600; color: var(--text); }
|
||||
|
||||
button {
|
||||
margin-top: 20px;
|
||||
padding: 10px 16px;
|
||||
@@ -540,6 +545,9 @@ code {
|
||||
.device-status-row { column-gap: 16px; }
|
||||
}
|
||||
|
||||
.mode-picker-row { display: flex; align-items: center; gap: 8px; margin-bottom: 18px; }
|
||||
.mode-picker-label { font-size: 13px; font-weight: 600; color: var(--text-muted); }
|
||||
|
||||
/* Mobile: sidebar off-canvas, hamburger in a slim top bar. */
|
||||
.mobile-bar { display: none; }
|
||||
.sidebar-backdrop { display: none; }
|
||||
|
||||
Reference in New Issue
Block a user