Per-frame palette calibration + sidebar battery indicator
Build and push server image / build-and-push (push) Successful in 40s
Build and push server image / build-and-push (push) Successful in 40s
Advanced configuration (Configuration tab, collapsed <details> section):
a color picker per ink color (black/white/yellow/red/blue/green),
overriding image_pipeline.DEFAULT_PALETTE_RGB for that frame's actual
panel -- different units can vary enough from the documented
approximations to be worth calibrating once you can compare a rendered
photo against the real hardware. Stored as Frame.palette_rgb (NULL =
default, schema migration v4), threaded through render_frame/
render_placeholder/_quantize_and_pack (which now builds the PIL palette
image per call instead of once at import) so both photos and the
unclaimed/unconfigured placeholder screen respect it. "Reset to
defaults" clears back to NULL. Config-save validates exactly 6 #rrggbb
values, rejecting anything else with a 400.
Also: each frame's sidebar entry now shows its last-reported battery
percent (🔋NN%) next to the name, using the frame_dot's existing
recently-seen indicator conventions -- silent when never reported
(mains-only frames, or before the first report), matching how battery
is hidden everywhere else it's not applicable.
Verified against the same live-shaped database as the SMTP work: the
v3->v4 migration, save/reload/reset round trip through the real HTTP
route, an actual rendered image using a custom palette (confirmed via
its packed panel-code bytes), input validation, and the sidebar badge
against real battery data -- plus the standing legacy-device curl suite.
This commit is contained in:
@@ -66,6 +66,41 @@ async function loadControl() {
|
||||
|
||||
document.getElementById('take-control').addEventListener('click', takeControl);
|
||||
|
||||
// ---- Advanced configuration: color palette ----
|
||||
|
||||
function paletteInputs() {
|
||||
return Array.from(document.querySelectorAll('[id^="palette_"]'))
|
||||
.sort((a, b) => Number(a.id.split('_')[1]) - Number(b.id.split('_')[1]));
|
||||
}
|
||||
|
||||
async function savePalette(body) {
|
||||
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.');
|
||||
} catch (e) {
|
||||
showStatus(false, e.message);
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('palette-save').addEventListener('click', () => {
|
||||
const body = new URLSearchParams();
|
||||
for (const input of paletteInputs()) {
|
||||
body.append('palette', input.value);
|
||||
}
|
||||
savePalette(body);
|
||||
});
|
||||
|
||||
document.getElementById('palette-reset').addEventListener('click', () => {
|
||||
const inputs = paletteInputs();
|
||||
window.DEFAULT_PALETTE_HEX.forEach((hex, i) => { inputs[i].value = hex; });
|
||||
savePalette(new URLSearchParams({ palette_reset: 'true' }));
|
||||
});
|
||||
|
||||
// ---- Battery alerts card ----
|
||||
|
||||
document.getElementById('battery-alert-save').addEventListener('click', async () => {
|
||||
|
||||
@@ -168,6 +168,30 @@ summary.card-title { cursor: pointer; margin-bottom: 0; }
|
||||
details.card[open] summary.card-title { margin-bottom: 14px; }
|
||||
details.card .sub { margin-top: 8px; }
|
||||
|
||||
.palette-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
|
||||
gap: 12px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
.palette-swatch {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-top: 0;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--text);
|
||||
}
|
||||
.palette-swatch input[type="color"] {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
padding: 2px;
|
||||
margin-top: 0;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
|
||||
Reference in New Issue
Block a user