style(ui): presets patterns and layout tweaks

Made-with: Cursor
This commit is contained in:
2026-04-19 23:28:08 +12:00
parent 35730b36f0
commit 5f9ff9bcc9
3 changed files with 25 additions and 12 deletions

View File

@@ -237,6 +237,7 @@ document.addEventListener('DOMContentLoaded', () => {
const norm = raw.endsWith('.py') ? raw.slice(0, -3).trim() : raw; const norm = raw.endsWith('.py') ? raw.slice(0, -3).trim() : raw;
try { try {
const response = await fetch('/patterns/definitions', { const response = await fetch('/patterns/definitions', {
cache: 'no-store',
headers: { Accept: 'application/json' }, headers: { Accept: 'application/json' },
}); });
if (!response.ok) { if (!response.ok) {
@@ -376,6 +377,7 @@ document.addEventListener('DOMContentLoaded', () => {
try { try {
const response = await fetch('/patterns', { const response = await fetch('/patterns', {
cache: 'no-store',
headers: { Accept: 'application/json' }, headers: { Accept: 'application/json' },
}); });
if (!response.ok) { if (!response.ok) {

View File

@@ -720,6 +720,7 @@ document.addEventListener('DOMContentLoaded', () => {
// Load pattern definitions from pattern.json // Load pattern definitions from pattern.json
let patternsPayload = null; let patternsPayload = null;
let response = await fetch('/patterns/definitions', { let response = await fetch('/patterns/definitions', {
cache: 'no-store',
headers: { Accept: 'application/json' }, headers: { Accept: 'application/json' },
}); });
if (response.ok) { if (response.ok) {
@@ -730,6 +731,7 @@ document.addEventListener('DOMContentLoaded', () => {
if (!Object.keys(normalized).length) { if (!Object.keys(normalized).length) {
// Fallback when definitions route is unavailable or returns an empty map. // Fallback when definitions route is unavailable or returns an empty map.
response = await fetch('/patterns', { response = await fetch('/patterns', {
cache: 'no-store',
headers: { Accept: 'application/json' }, headers: { Accept: 'application/json' },
}); });
if (!response.ok) { if (!response.ok) {
@@ -1341,26 +1343,27 @@ document.addEventListener('DOMContentLoaded', () => {
throw new Error('Failed to save preset'); throw new Error('Failed to save preset');
} }
// Same device targeting as Try: zone tab supplies names → /presets/push gets targets + select.
const section = document.querySelector('.presets-section[data-zone-id]');
const deviceNames = tabDeviceNamesFromSection(section);
// Use saved preset from server response for sending // Use saved preset from server response for sending
const saved = await response.json().catch(() => null); const saved = await response.json().catch(() => null);
if (saved && typeof saved === 'object') { if (saved && typeof saved === 'object') {
if (currentEditId) { if (currentEditId) {
// PUT returns the preset object directly; use the existing ID // PUT returns the preset object directly; use the existing ID
// Save & Send should not force-select the preset on devices. await sendPresetViaEspNow(currentEditId, saved, deviceNames, true, false);
await sendPresetViaEspNow(currentEditId, saved, [], true, false);
} else { } else {
// POST returns { id: preset } // POST returns { id: preset }
const entries = Object.entries(saved); const entries = Object.entries(saved);
if (entries.length > 0) { if (entries.length > 0) {
const [newId, presetData] = entries[0]; const [newId, presetData] = entries[0];
// Save & Send should not force-select the preset on devices. await sendPresetViaEspNow(newId, presetData, deviceNames, true, false);
await sendPresetViaEspNow(newId, presetData, [], true, false);
} }
} }
} else { } else {
// Fallback: send what we just built // Fallback: send what we just built
// Save & Send should not force-select the preset on devices. await sendPresetViaEspNow(currentEditId || payload.name, payload, deviceNames, true, false);
await sendPresetViaEspNow(payload.name, payload, [], true, false);
} }
await loadPresets(); await loadPresets();

View File

@@ -1253,24 +1253,32 @@ body.preset-ui-run .edit-mode-only {
} }
/* Preset editor: brightness/delay field wrappers */ /* Preset editor: brightness/delay field wrappers */
.preset-editor-field { #preset-editor-modal .preset-editor-field {
flex: 1; flex: 1;
min-width: 10rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: flex-end; align-items: stretch;
} }
.preset-editor-field label { #preset-editor-modal .preset-editor-field label {
align-self: stretch; align-self: stretch;
} }
.preset-editor-field input[type="number"] { #preset-editor-modal .preset-editor-field input[type="number"] {
width: var(--n-input-width, 5ch); width: 100%;
max-width: 100%; min-width: 5.5rem;
max-width: 7rem;
box-sizing: border-box; box-sizing: border-box;
text-align: right; text-align: right;
} }
/* Preset editor n-parameter inputs need extra room for values + spinner controls. */
#preset-editor-modal .n-input {
width: 6.5ch;
min-width: 5.5rem;
}
/* Pattern editor: numeric metadata row */ /* Pattern editor: numeric metadata row */
#pattern-editor-modal input[type="number"] { #pattern-editor-modal input[type="number"] {
width: var(--n-input-width, 5ch); width: var(--n-input-width, 5ch);