/* ============================================================================
INSTÄLLNINGAR · LASTFÖNSTER — fönsterlistan i settings-formspråket
----------------------------------------------------------------------------
Samma logik som Last-fliken (lastfonster.js, lw*), samma regler, samma
texter — men renderad med settings.css i stället för Tailwind. Två
editorer får aldrig validera olika; därför delar de logiken och skiljer
sig bara i utseende.
Kravlista: DESIGN_KRAVLISTA_lastfonster_2026-09-02 p1–p3, p5.
========================================================================== */
const SLW_BOX = { border:'1px solid rgba(255,255,255,.07)', borderRadius:8,
padding:'10px 10px 8px', marginBottom:8, background:'rgba(255,255,255,.015)' };
const SLW_BOX_BAD = { ...SLW_BOX, borderColor:'rgba(255,107,107,.45)', background:'rgba(255,107,107,.05)' };
const SLW_DAY = (on) => ({ font:'inherit', fontSize:11.5, fontWeight:700, flex:1,
padding:'5px 0', cursor:'pointer', borderRadius:6,
border: on ? '1px solid rgba(91,168,255,.55)' : '1px solid var(--line)',
background: on ? 'rgba(91,168,255,.18)' : 'transparent',
color: on ? '#BBD7FF' : 'var(--ink-3)' });
const SLW_PILL = (on) => ({ font:'inherit', fontSize:11.5, fontWeight:600,
padding:'5px 10px', cursor:'pointer', borderRadius:6,
border: on ? '1px solid rgba(244,200,75,.45)' : '1px solid var(--line)',
background: on ? 'rgba(244,200,75,.14)' : 'transparent',
color: on ? '#F4C84B' : 'var(--ink-2)' });
const SLW_PILL_B = (on) => ({ ...SLW_PILL(on),
border: on ? '1px solid rgba(91,168,255,.5)' : '1px solid var(--line)',
background: on ? 'rgba(91,168,255,.16)' : 'transparent',
color: on ? '#BBD7FF' : 'var(--ink-2)' });
function SettingsWindowRow({ win, idx, count, err, measured, reportsPower, showMeasured, load, onChange, onRemove }){
const w = { ...window.LW_WIN_DEFAULT, ...(win || {}) };
const days = Array.isArray(w.days) ? w.days : [];
const span = window.lwSpan(w);
const mTxt = window.lwRunsText(measured);
const planned = showMeasured && reportsPower ? window.lwPlanned(measured, load, w) : null;
const prog = showMeasured && reportsPower ? window.lwProgress(measured) : null;
const running = !!(measured && measured.running === true);
const hist = (measured && Array.isArray(measured.history)) ? measured.history.slice(0, 10) : [];
const [open, setOpen] = React.useState(false);
const toggleDay = (d) => onChange({ days: days.indexOf(d) >= 0
? days.filter(x => x !== d) : days.concat([d]).sort((a, b) => a - b) });
return (
Fönster {idx + 1}
{count > 1 && (
)}
{window.LW_DAY_SHORT.map((s, d) => (
))}
onChange({earliest: v})}/>
onChange({latest: v})}/>
onChange({duration_hours: v})}
help="Körtid för DETTA fönster — HEMS lägger den på de billigaste kvartarna inom fönstret"/>
{w.mode === 'split' && (
)}
{w.solar_only === true &&
{window.LW_HELP_SOLAR}
}
{span && span.wrap &&
{window.LW_HELP_WRAP}
}
{err &&
{err}
}
{/* Vad HEMS planerar med (Andrés beslut 3/9) — blocket finns bara när
backend svarar med enabled:true. Flagga av eller endpoint saknas ⇒
ingenting (spec §5). */}
{showMeasured && (