From fb8547c8b8b7ac2653923193695cb2eb5bb625ef Mon Sep 17 00:00:00 2001 From: fraxle Date: Thu, 9 Jul 2026 20:16:10 +0100 Subject: [PATCH] 3.3.1 Updated At A Glance - re-order and add category colour shades Pets image --- assets/css/ui.css | 24 ++++++++++++++ assets/images/profiles/pets.png | Bin 0 -> 28613 bytes assets/js/app.js | 10 +++--- assets/js/compute.js | 54 +++++++++++++++++++++++--------- 4 files changed, 68 insertions(+), 20 deletions(-) create mode 100644 assets/images/profiles/pets.png diff --git a/assets/css/ui.css b/assets/css/ui.css index ff34ce3..35d8a3d 100644 --- a/assets/css/ui.css +++ b/assets/css/ui.css @@ -1726,6 +1726,19 @@ padding-bottom: 0; } +/* Group-tinted rows remove the divider border since the background pill + provides the visual separation. */ +.insight-row--felt, +.insight-row--surface, +.insight-row--ambient, +.insight-row--precip, +.insight-row--sky, +.insight-row--wind, +.insight-row--airqual, +.insight-row--solar { + border-bottom: none; +} + .insight-icon { width: 20px; text-align: center; @@ -1807,6 +1820,17 @@ font-weight: 700; } +/* Group-tinted backgrounds for insight rows — very light shade matching + the column group colour so items feel categorised at a glance. */ +.insight-row--felt { background: rgba(223,243,236,0.50); margin: 0 -10px; padding: 5px 10px; border-radius: 6px; } +.insight-row--surface { background: rgba(221,234,248,0.50); margin: 0 -10px; padding: 5px 10px; border-radius: 6px; } +.insight-row--ambient { background: rgba(236,234,227,0.50); margin: 0 -10px; padding: 5px 10px; border-radius: 6px; } +.insight-row--precip { background: rgba(247,228,238,0.50); margin: 0 -10px; padding: 5px 10px; border-radius: 6px; } +.insight-row--sky { background: rgba(234,232,252,0.50); margin: 0 -10px; padding: 5px 10px; border-radius: 6px; } +.insight-row--wind { background: rgba(250,230,224,0.50); margin: 0 -10px; padding: 5px 10px; border-radius: 6px; } +.insight-row--airqual { background: rgba(229,240,216,0.50); margin: 0 -10px; padding: 5px 10px; border-radius: 6px; } +.insight-row--solar { background: rgba(250,234,204,0.50); margin: 0 -10px; padding: 5px 10px; border-radius: 6px; } + /* ── Wide screens - the rail is narrow (240px), so stack each value beneath its label instead of letting long values overflow sideways. Mobile keeps the inline label/value layout (plenty of width there). */ diff --git a/assets/images/profiles/pets.png b/assets/images/profiles/pets.png new file mode 100644 index 0000000000000000000000000000000000000000..fb384552c2f7b0c77aeefb996d7c5af678f19c20 GIT binary patch literal 28613 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 literal 0 HcmV?d00001 diff --git a/assets/js/app.js b/assets/js/app.js index d5b9cb9..a5a9bbf 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -1694,8 +1694,8 @@ export function UTCIForecast() { ${(() => { const heatEvents = eventGlanceItems.filter(e => /heat caution|heat warning|extreme heat/i.test(e.label)).map(e => ({ ...e, alert: true })); const otherEvents = eventGlanceItems.filter(e => !/heat caution|heat warning|extreme heat/i.test(e.label)); - const renderRow = ({ icon, label, value, alert }, keyPrefix = '') => html` -
+ const renderRow = ({ icon, label, value, alert, grp }, keyPrefix = '') => html` +
${icon} ${label} ${value} @@ -1705,8 +1705,8 @@ export function UTCIForecast() { const hasFeltAnchor = glanceSummary.some(i => i.label === 'Peak felt temp'); const comfortItem = hasFeltAnchor ? glanceSummary.find(i => i.label === 'Comfortable window') : null; const drivingItem = hasFeltAnchor ? glanceSummary.find(i => i.label === 'Good driving time') : null; - const climateRows = hasFeltAnchor ? glanceSummary.filter(i => i.label === '1991-2020 High' || i.label === '1991-2020 Average') : []; - const restSummary = glanceSummary.filter(i => !(hasFeltAnchor && (i.label === 'Comfortable window' || i.label === 'Good driving time' || i.label === '1991-2020 High' || i.label === '1991-2020 Average'))); + const climateRows = glanceSummary.filter(i => i.label === '1991-2020 High' || i.label === '1991-2020 Average'); + const restSummary = glanceSummary.filter(i => i.label !== '1991-2020 High' && i.label !== '1991-2020 Average' && !(hasFeltAnchor && (i.label === 'Comfortable window' || i.label === 'Good driving time'))); return [ ...restSummary.flatMap(item => [ renderRow(item), @@ -1715,11 +1715,11 @@ export function UTCIForecast() { ? [ ...heatEvents.map(e => renderRow(e, 'ev-')), ...(drivingItem ? [renderRow(drivingItem)] : []), - ...climateRows.map(item => renderRow(item)), ...(comfortItem ? [renderRow(comfortItem)] : []), ] : []), ]), + ...climateRows.map(item => renderRow(item)), ...otherEvents.map(e => renderRow(e, 'ev-')), ]; })()} diff --git a/assets/js/compute.js b/assets/js/compute.js index fd28ea6..316c2bb 100644 --- a/assets/js/compute.js +++ b/assets/js/compute.js @@ -479,6 +479,7 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols label: 'Lightning risk', value: `${lightningRisk} at ${hhmm(peakLightningRow.iso)}`, alert: peakLightning >= 5, + grp: 'precip', }] : []; const moistureLabel = (v) => { @@ -513,22 +514,20 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols if (taVals.length === 0) return []; const dayHigh = Math.max(...taVals); const dayMean = taVals.reduce((a, b) => a + b, 0) / taVals.length; - const fmt = (anom) => { - const mag = Math.abs(anom); - return mag < 0.5 - ? 'About average' - : `${anom >= 0 ? '+' : '−'}${mag.toFixed(1)}° ${anom >= 0 ? 'warmer' : 'cooler'}`; - }; const out = []; const nHigh = normals.high?.[doy]; if (nHigh != null) { const a = dayHigh - nHigh; - out.push({ icon: '🌡', label: '1991-2020 High', value: fmt(a), alert: a >= 5 }); + if (Math.abs(a) >= 3) { + out.push({ icon: '🌡', label: '1991-2020 High', value: `${a >= 0 ? '+' : '−'}${Math.abs(a).toFixed(1)}° ${a >= 0 ? 'warmer' : 'cooler'}`, alert: a >= 5, grp: 'ambient' }); + } } const nMean = normals.mean?.[doy]; if (nMean != null) { const a = dayMean - nMean; - out.push({ icon: '🌡', label: '1991-2020 Average', value: fmt(a), alert: a >= 5 }); + if (Math.abs(a) >= 3) { + out.push({ icon: '🌡', label: '1991-2020 Average', value: `${a >= 0 ? '+' : '−'}${Math.abs(a).toFixed(1)}° ${a >= 0 ? 'warmer' : 'cooler'}`, alert: a >= 5, grp: 'ambient' }); + } } return out; })(); @@ -557,6 +556,7 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols label: 'Good driving time', value: formatWindows(drivingWins) ?? 'Drive with care', alert: drivingWins.length === 0, + grp: 'felt', }; // ── Farming ──────────────────────────────────────────────────────────── @@ -575,12 +575,14 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols label: 'Best field work', value: formatWindows(fieldWins) ?? 'No suitable window', alert: fieldWins.length === 0, + grp: 'surface', }, ...(show('soilT') ? [{ icon: '🌱', label: 'Soil warms to 10°C by', value: soilWarmRow ? (hhmm(soilWarmRow.iso) === '00:00' ? 'All Day' : hhmm(soilWarmRow.iso)) : 'Not today', alert: !soilWarmRow, + grp: 'surface', }] : []), ...(show('precipProb') ? [rainItem] : []), ...lightningItem, @@ -589,6 +591,7 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols label: 'Soil moisture', value: moistureLabel(soilM) ?? '-', alert: soilM != null && (soilM < 0.10 || soilM > 0.50), + grp: 'surface', }] : []), ...(weekDays ? computeCropAdvice(weekDays, lat) : []), ...(show('pollen') && maxPollen >= 10 ? [{ @@ -596,6 +599,7 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols label: 'Grass pollen', value: pollenLabel(maxPollen), alert: maxPollen >= 50, + grp: 'airqual', }] : []), ]; } @@ -612,11 +616,13 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols label: 'Peak cabin temp', value: peakCabin ? `${Math.round(peakCabin.vehicleT)}° at ${hhmm(peakCabin.iso)}` : '-', alert: !!(peakCabin && peakCabin.vehicleT > 31.5), + grp: 'felt', }, { icon: '🧒', label: 'Children/pets in car', value: dangerFrom ? `Unsafe from ${hhmm(dangerFrom.iso)}` : 'Safe all day', alert: !!dangerFrom, + grp: 'felt', }] : []), ...(show('precipProb') ? [rainItem] : []), ...lightningItem, @@ -630,6 +636,7 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols return best ? `${hhmm(best.iso)} (${Math.round(best.utciAdj)}° felt)` : '-'; })(), alert: false, + grp: 'felt', }, ]; } @@ -651,18 +658,21 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols label: 'Peak indoor (unmanaged)', value: peakIndoor ? `${Math.round(peakIndoor.indoorT)}° at ${hhmm(peakIndoor.iso)}` : '-', alert: !!(peakIndoor && peakIndoor.indoorT >= 28), + grp: 'felt', }] : []), ...(show('managedT') ? [{ icon: '🌡', label: 'Peak indoor (managed)', value: peakManaged ? `${Math.round(peakManaged.managedT)}°` : '-', alert: !!(peakManaged && peakManaged.managedT >= 28), + grp: 'felt', }] : []), ...(show('indoorT') ? [{ icon: '🪟', label: 'Open windows', value: formatWindows(ventWins) ?? 'Keep closed', alert: false, + grp: 'felt', }] : []), ...lightningItem, ...(show('aqi') ? [{ @@ -676,6 +686,7 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols label: 'Pollen', value: pollenLabel(maxPollen), alert: maxPollen >= 50, + grp: 'airqual', }] : []), ]; } @@ -695,24 +706,28 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols label: 'Sunsoak for pet', value: peakFur ? `${Math.round(peakFur.furSurfaceT)}° at ${hhmm(peakFur.iso)}` : '-', alert: !!(peakFur && peakFur.furSurfaceT >= 45), + grp: 'surface', }] : []), ...(show('petShadeT') ? [{ icon: '🌳', label: 'Shade for pet', value: peakShade ? `${Math.round(peakShade.shadeT)}° at ${hhmm(peakShade.iso)}` : '-', alert: !!(peakShade && peakShade.shadeT >= 26), + grp: 'ambient', }] : []), ...(show('petHomeT') ? [{ icon: '🏠', label: 'Pet at home', value: peakIndoor ? `${Math.round(peakIndoor.indoorT)}° at ${hhmm(peakIndoor.iso)}` : '-', alert: !!(peakIndoor && peakIndoor.indoorT >= 26), + grp: 'felt', }] : []), ...(show('vehicleT') ? [{ icon: '🧒', label: 'Kids/pets in car', value: carDanger ? `Unsafe from ${hhmm(carDanger.iso)}` : 'Safe all day', alert: !!carDanger, + grp: 'felt', }] : []), ...lightningItem, ...(show('aqi') ? [{ @@ -720,12 +735,14 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols label: 'Air quality', value: peakAqi > 0 ? aqiLabel(peakAqi) : '-', alert: peakAqi >= 60, + grp: 'airqual', }] : []), ...(show('pollen') && maxPollen >= 10 ? [{ icon: '🌼', label: 'Pollen', value: pollenLabel(maxPollen), alert: maxPollen >= 50, + grp: 'airqual', }] : []), ]; } @@ -749,6 +766,7 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols label: `Best ${variant} window`, value: formatWindows(coolWins) ?? 'No cool window today', alert: coolWins.length === 0, + grp: 'felt', }, ...(show('precipProb') ? [rainItem] : []), ...lightningItem, @@ -757,6 +775,7 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols label: 'UV burn time (peak)', value: burnMins, alert: !!(peakUvRow && peakUvRow.uv >= 6), + grp: 'solar', }] : []), ...(show('aqi') ? [{ icon: '💨', @@ -793,18 +812,21 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols label: 'Comfortable window', value: formatWindows(comfortWins) ?? 'No comfortable window', alert: comfortWins.length === 0, + grp: 'felt', }, { icon: '🌡', label: 'Peak felt temp', value: peakFelt ? `${Math.round(peakFelt.utciAdj)}° at ${hhmm(peakFelt.iso)}` : '-', alert: !!(peakFelt && (peakFelt.utciAdj >= 32 || peakFelt.utciAdj < 0)), + grp: 'felt', }, ...((show('burn') || show('uvA')) && burnMins ? [{ icon: '☀', label: 'UV burn time (peak)', value: burnMins, alert: !!(peakUvRow && peakUvRow.uv >= 6), + grp: 'solar', }] : []), ...(show('precipProb') ? [rainItem] : []), ...lightningItem, @@ -812,13 +834,15 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols icon: '💨', label: 'Air quality', value: peakAqi > 0 ? aqiLabel(peakAqi) : '-', - alert: peakAqi >= 60, - }] : []), - ...(show('pollen') && maxPollen >= 10 ? [{ +alert: peakAqi >= 60, + grp: 'airqual', + }] : []), + ...(show('pollen') && maxPollen >= 10 ? [{ icon: '🌿', label: 'Pollen', value: pollenLabel(maxPollen), alert: maxPollen >= 50, + grp: 'airqual', }] : []), ]; } @@ -894,11 +918,11 @@ export function computeCropAdvice(weekDays, lat) { const ready = sowSeason.filter(c => weekSoilT != null && weekSoilT >= c.sow.minSoilT && !groundWet); out.push(ready.length ? { - icon: '🌱', label: 'Good to sow', value: listCrops(ready), alert: false, + icon: '🌱', label: 'Good to sow', value: listCrops(ready), alert: false, grp: 'surface', } : { icon: '🌱', label: 'Good to sow', value: groundWet ? 'Hold off — ground too wet' : 'Hold off — soil still cold', - alert: true, + alert: true, grp: 'surface', }); } @@ -911,10 +935,10 @@ export function computeCropAdvice(weekDays, lat) { out.push(ready.length ? { icon: '🌾', label: 'Good to harvest', value: dryDriven ? `${listCrops(ready)} (${dryRange()})` : listCrops(ready), - alert: false, + alert: false, grp: 'surface', } : { icon: '🌾', label: 'Good to harvest', - value: 'Hold — too wet to harvest grain', alert: true, + value: 'Hold — too wet to harvest grain', alert: true, grp: 'surface', }); }