Hide trivial rain% (<15%) -- was contradicting the 'Dry today' headline

The headline is icon-based (does any hour have a rain-classified icon), not
precip_prob-based, so an hour can have a non-rain icon and still carry a
token 5% chance -- both numbers are real, they're just independent fields.
Nothing was gating the tiny one from display, so a hour card could show
'5%' right next to 'Dry today'. New MIN_PRECIP_DISPLAY threshold (15) hides
percentages below that everywhere it's shown (hourly cards, next-2-days
cards, the Now hero line) rather than second-guessing the provider's own
icon classification.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-08-25 13:18:19 +00:00
parent 1a5c37d011
commit 7780ef42a3

View file

@ -33,6 +33,12 @@ 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)}°`
} }
@ -55,14 +61,15 @@ 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 }) {
if (point.precip_prob == null && point.wind_speed_mph == null) return null const showPrecip = point.precip_prob != null && point.precip_prob >= MIN_PRECIP_DISPLAY
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' : ''}`}>
{point.precip_prob != null && ( {showPrecip && (
<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 && (
@ -165,8 +172,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.feels_like_c != null && currentPoint.precip_prob != null && currentPoint.precip_prob >= MIN_PRECIP_DISPLAY && ' · '}
{currentPoint.precip_prob != null && <>{Math.round(currentPoint.precip_prob)}% chance of rain</>} {currentPoint.precip_prob != null && currentPoint.precip_prob >= MIN_PRECIP_DISPLAY && <>{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>