Add a curated theme system for "modern" style widgets, inspired by Tesserae
Build and push server image / test (push) Successful in 44s
Build and push server image / build-and-push (push) Successful in 3m33s
Build and push server image / deploy (push) Failing after 1m27s

Frame.theme (7 presets in app/theme_tokens.py) drives font family,
corner radius, drop shadow, and an accent hue for every modern-style
widget's header/accent region. Rich accent colors (not just the 6 flat
panel inks) are approximated via denser Bayer stippling confined to just
that region (html_render.ordered_dither_regions), so icon/text content
elsewhere stays exactly as crisp as it is today -- verified directly
against real Chromium renders, both in unit tests and via run-server.
"classic" is a byte-identical no-visual-change default: weather's header
keeps its original fixed blue gradient, tasks/calendar keep their flat
THEME_* ink.

Themes are purely stylistic -- battery's charge-level color, calendar/
tasks' per-owner event chips, and text's own per-widget font choice are
never touched.
This commit is contained in:
2026-07-31 10:34:28 +00:00
parent e331f5e5a1
commit 5f4f8f2ea7
32 changed files with 808 additions and 195 deletions
+18
View File
@@ -260,6 +260,24 @@ document.getElementById('photo-palette-reset').addEventListener('click', () => {
savePalette('photo-palette', 'photo_palette', { photo_palette_reset: 'true', photo_dither_strength: '1' });
});
// ---- Theme ----
document.getElementById('theme-save').addEventListener('click', async () => {
const body = new URLSearchParams({ theme: document.getElementById('theme-select').value });
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.');
loadPreview();
} catch (e) {
showStatus(false, e.message);
}
});
// ---- Preview: current photo vs. how it renders with saved settings ----
// Scoped to this frame's photo widget (window.PHOTO_WIDGET_PREVIEW_API,
// set by the template) rather than window.FRAME_API -- palette/color/