Revert precip% hiding; headline now says 'slim chance of rain' instead
Wrong direction on the previous fix -- hiding the number lost real information. Better fix: when no hour's icon is rain-classified but there's still a real (if low) numeric precip_prob somewhere in the day, the headline now says 'Mostly dry, slim chance of rain' instead of a flat 'Dry today' that silently disagreed with a 5% sitting on an hour card. Rain% is shown unconditionally again everywhere (hourly cards, next-2-days cards, the Now hero line). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
7780ef42a3
commit
c6be990f6b
2 changed files with 13 additions and 13 deletions
|
|
@ -27,6 +27,13 @@ export function summarizeToday(points, nowHour) {
|
||||||
const rainFraction = rainPoints.length / points.length
|
const rainFraction = rainPoints.length / points.length
|
||||||
const snowFraction = snowPoints.length / points.length
|
const snowFraction = snowPoints.length / points.length
|
||||||
|
|
||||||
|
// precip_prob is a separate field from the icon (see the frontend fix this
|
||||||
|
// replaces) — an hour's icon can be non-rain while it still carries a real, if
|
||||||
|
// slim, numeric chance. Worth surfacing in the headline rather than a flat "Dry"
|
||||||
|
// that silently disagrees with a "5%" sitting right there on an hour card.
|
||||||
|
const precipValues = points.map(p => p.precip_prob).filter(v => v != null)
|
||||||
|
const maxPrecip = precipValues.length ? Math.max(...precipValues) : null
|
||||||
|
|
||||||
const laterPoints = points.filter(p => hourOf(p) >= nowHour)
|
const laterPoints = points.filter(p => hourOf(p) >= nowHour)
|
||||||
const earlierPoints = points.filter(p => hourOf(p) < nowHour)
|
const earlierPoints = points.filter(p => hourOf(p) < nowHour)
|
||||||
const laterWetFraction = laterPoints.length
|
const laterWetFraction = laterPoints.length
|
||||||
|
|
@ -38,7 +45,7 @@ export function summarizeToday(points, nowHour) {
|
||||||
if (snowFraction > 0.3) {
|
if (snowFraction > 0.3) {
|
||||||
headline = 'Snow expected today'
|
headline = 'Snow expected today'
|
||||||
} else if (rainPoints.length === 0 && thunderPoints.length === 0) {
|
} else if (rainPoints.length === 0 && thunderPoints.length === 0) {
|
||||||
headline = 'Dry today'
|
headline = maxPrecip != null && maxPrecip >= 15 ? 'Mostly dry, slim chance of rain' : 'Dry today'
|
||||||
} else if (rainPoints.some(isHeavyRain) && rainFraction > 0.5) {
|
} else if (rainPoints.some(isHeavyRain) && rainFraction > 0.5) {
|
||||||
headline = 'Heavy rain today'
|
headline = 'Heavy rain today'
|
||||||
} else if (rainFraction > 0.6) {
|
} else if (rainFraction > 0.6) {
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,6 @@ function compassFromDeg(deg: number): string {
|
||||||
return COMPASS[Math.round(deg / 45) % 8]
|
return COMPASS[Math.round(deg / 45) % 8]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Below this, a rain% reads as noise, not information — and worse, it can visibly
|
|
||||||
// contradict the "Dry today" headline (which is icon-based, not precip_prob-based:
|
|
||||||
// an hour can have a non-rain icon and still carry a token 5% chance). Hiding trivial
|
|
||||||
// percentages keeps what's shown consistent with what "Dry today" is actually saying.
|
|
||||||
const MIN_PRECIP_DISPLAY = 15
|
|
||||||
|
|
||||||
function roundTemp(c: number): string {
|
function roundTemp(c: number): string {
|
||||||
return `${Math.round(c)}°`
|
return `${Math.round(c)}°`
|
||||||
}
|
}
|
||||||
|
|
@ -61,15 +55,14 @@ function AstroRow({ astro }: { astro?: Astro }) {
|
||||||
// the text size for today's hourly cards; the next-2-days cards stay at the
|
// the text size for today's hourly cards; the next-2-days cards stay at the
|
||||||
// smaller default so today still reads as the primary/detailed view.
|
// smaller default so today still reads as the primary/detailed view.
|
||||||
function PointMeta({ point, large }: { point: ForecastPoint; large?: boolean }) {
|
function PointMeta({ point, large }: { point: ForecastPoint; large?: boolean }) {
|
||||||
const showPrecip = point.precip_prob != null && point.precip_prob >= MIN_PRECIP_DISPLAY
|
if (point.precip_prob == null && point.wind_speed_mph == null) return null
|
||||||
if (!showPrecip && point.wind_speed_mph == null) return null
|
|
||||||
const iconSize = large ? 13 : 10
|
const iconSize = large ? 13 : 10
|
||||||
return (
|
return (
|
||||||
<span className={`wx-meta${large ? ' wx-meta-lg' : ''}`}>
|
<span className={`wx-meta${large ? ' wx-meta-lg' : ''}`}>
|
||||||
{showPrecip && (
|
{point.precip_prob != null && (
|
||||||
<span className="wx-meta-line wx-meta-precip">
|
<span className="wx-meta-line wx-meta-precip">
|
||||||
<Droplet size={iconSize} strokeWidth={2} />
|
<Droplet size={iconSize} strokeWidth={2} />
|
||||||
{Math.round(point.precip_prob!)}%
|
{Math.round(point.precip_prob)}%
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{point.wind_speed_mph != null && (
|
{point.wind_speed_mph != null && (
|
||||||
|
|
@ -172,8 +165,8 @@ export default function Display() {
|
||||||
{data.summary && <span className="wx-summary-headline">{data.summary.headline}</span>}
|
{data.summary && <span className="wx-summary-headline">{data.summary.headline}</span>}
|
||||||
<span>
|
<span>
|
||||||
{currentPoint.feels_like_c != null && <>Feels like {roundTemp(currentPoint.feels_like_c)}</>}
|
{currentPoint.feels_like_c != null && <>Feels like {roundTemp(currentPoint.feels_like_c)}</>}
|
||||||
{currentPoint.feels_like_c != null && currentPoint.precip_prob != null && currentPoint.precip_prob >= MIN_PRECIP_DISPLAY && ' · '}
|
{currentPoint.feels_like_c != null && currentPoint.precip_prob != null && ' · '}
|
||||||
{currentPoint.precip_prob != null && currentPoint.precip_prob >= MIN_PRECIP_DISPLAY && <>{Math.round(currentPoint.precip_prob)}% chance of rain</>}
|
{currentPoint.precip_prob != null && <>{Math.round(currentPoint.precip_prob)}% chance of rain</>}
|
||||||
</span>
|
</span>
|
||||||
{data.summary?.note && <span className="wx-summary-note">{data.summary.note}</span>}
|
{data.summary?.note && <span className="wx-summary-note">{data.summary.note}</span>}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue