3.3.1
Updated At A Glance - re-order and add category colour shades Pets image
This commit is contained in:
@@ -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). */
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
+5
-5
@@ -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`
|
||||
<div class=${`insight-row${alert ? ' insight-row--alert' : ''}`} key=${`${keyPrefix}${label}`}>
|
||||
const renderRow = ({ icon, label, value, alert, grp }, keyPrefix = '') => html`
|
||||
<div class=${`insight-row${alert ? ' insight-row--alert' : ''}${grp ? ` insight-row--${grp}` : ''}`} key=${`${keyPrefix}${label}`}>
|
||||
<span class="insight-icon">${icon}</span>
|
||||
<span class="insight-label">${label}</span>
|
||||
<span class="insight-value">${value}</span>
|
||||
@@ -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-')),
|
||||
];
|
||||
})()}
|
||||
|
||||
+37
-13
@@ -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,
|
||||
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',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user