Show a visible source icon for Open-Meteo fallback values on NWS

Replace the hidden hover-only native title with a dedicated SourceTooltip
component: a small ⓘ badge rendered inline next to Pressure and UV values
(Current + Details views) that reveals a styled tooltip on hover/focus,
so it is obvious the value came from the non-selected source (Open-Meteo)
instead of requiring discovery by hovering the data.
This commit is contained in:
hermes-explorigin 2026-08-16 21:15:10 +00:00
parent c0ec45f170
commit 6c7fbf68eb
3 changed files with 89 additions and 7 deletions

View File

@ -1,6 +1,7 @@
<script>
import { app } from '../lib/stores/app.svelte.js'
import { getWeatherInfo, getWeatherSeverity } from '../lib/api/weather-codes.js'
import SourceTooltip from './SourceTooltip.svelte'
const data = $derived(app.forecastData)
const current = $derived(data?.current)
@ -71,15 +72,15 @@
<span class="metric-value">{Math.round(current.wind_speed_10m)} {windUnit}</span>
<span class="metric-sub">{windCompass(current.wind_direction_10m)}</span>
</div>
<div class="metric-card" title={fbPressure ? 'Pressure from Open-Meteo — NWS does not provide it' : undefined}>
<div class="metric-card">
<span class="metric-icon">🌡️</span>
<span class="metric-label">Pressure</span>
<span class="metric-value">{Math.round(current.pressure_msl || 0)} hPa</span>
<span class="metric-value">{Math.round(current.pressure_msl || 0)} hPa{#if fbPressure}<SourceTooltip label="Pressure from Open-Meteo — NWS does not provide it" />{/if}</span>
</div>
<div class="metric-card" title={fbUv ? 'UV index from Open-Meteo — NWS does not provide it' : undefined}>
<div class="metric-card">
<span class="metric-icon">☀️</span>
<span class="metric-label">UV Index</span>
<span class="metric-value">{current.uv_index != null ? Math.round(current.uv_index) : '--'}</span>
<span class="metric-value">{current.uv_index != null ? Math.round(current.uv_index) : '--'}{#if fbUv}<SourceTooltip label="UV index from Open-Meteo — NWS does not provide it" />{/if}</span>
{#if current.uv_index != null}
<span class="metric-sub">{current.uv_index <= 2 ? 'Low' : current.uv_index <= 5 ? 'Moderate' : current.uv_index <= 7 ? 'High' : 'Very High'}</span>
{/if}

View File

@ -0,0 +1,79 @@
<script>
/** Small info badge whose tooltip explains the value came from the
* non-selected source (e.g. Open-Meteo while NWS is selected). */
let { label = '' } = $props()
</script>
<span class="srctip" tabindex="0" role="note" aria-label={label}>
<span class="srctip-icon" aria-hidden="true"></span>
<span class="srctip-bubble">{label}</span>
</span>
<style>
.srctip {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
width: 17px;
height: 17px;
margin-left: 6px;
vertical-align: middle;
cursor: help;
flex: none;
color: var(--color-primary, #38bdf8);
}
.srctip-icon {
font-size: 0.98rem;
line-height: 1;
display: inline-flex;
align-items: center;
justify-content: center;
}
.srctip-bubble {
position: absolute;
bottom: calc(100% + 7px);
left: 50%;
transform: translateX(-50%);
width: max-content;
max-width: 210px;
padding: 7px 10px;
border-radius: 7px;
background: #0b1220;
color: #e2e8f0;
font-size: 0.74rem;
font-weight: 500;
line-height: 1.4;
white-space: normal;
text-align: left;
box-shadow: 0 5px 16px rgba(0, 0, 0, 0.4);
border: 1px solid rgba(255, 255, 255, 0.1);
opacity: 0;
visibility: hidden;
pointer-events: none;
transition: opacity 0.12s ease, visibility 0.12s ease;
z-index: 60;
}
/* small arrow */
.srctip-bubble::after {
content: '';
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
border: 5px solid transparent;
border-top-color: #0b1220;
}
.srctip:hover .srctip-bubble,
.srctip:focus .srctip-bubble,
.srctip:focus-visible .srctip-bubble {
opacity: 1;
visibility: visible;
}
.srctip:focus,
.srctip:focus-visible {
outline: 2px solid var(--color-primary, #38bdf8);
outline-offset: 2px;
border-radius: 50%;
}
</style>

View File

@ -1,6 +1,7 @@
<script>
import { app } from '../lib/stores/app.svelte.js'
import { getWeatherInfo } from '../lib/api/weather-codes.js'
import SourceTooltip from './SourceTooltip.svelte'
const data = $derived(app.forecastData)
const current = $derived(data?.current)
@ -97,7 +98,7 @@
</div>
<div class="detail-row">
<span>Pressure</span>
<span class="detail-value" title={fbPressure ? 'Pressure from Open-Meteo — NWS does not provide it' : undefined}>{Math.round(current.pressure_msl || 0)} hPa</span>
<span class="detail-value">{Math.round(current.pressure_msl || 0)} hPa{#if fbPressure}<SourceTooltip label="Pressure from Open-Meteo — NWS does not provide it" />{/if}</span>
</div>
<div class="detail-row">
<span>Feels Like</span>
@ -119,11 +120,12 @@
<div class="detail-body">
<div class="detail-row">
<span>UV Index</span>
<span class="detail-value" title={fbUv ? 'UV index from Open-Meteo — NWS does not provide it' : undefined}>
<span class="detail-value">
{current.uv_index != null ? Math.round(current.uv_index) : '--'}
{#if current.uv_index != null}
<span class="uv-badge uv-{getUVLevel(current.uv_index).toLowerCase().replace(' ', '-')}">{getUVLevel(current.uv_index)}</span>
{/if}
{#if fbUv}<SourceTooltip label="UV index from Open-Meteo — NWS does not provide it" />{/if}
</span>
</div>
<div class="detail-row">
@ -136,7 +138,7 @@
</div>
<div class="detail-row">
<span>Max UV Today</span>
<span class="detail-value" title={fbUv ? 'UV from Open-Meteo — NWS does not provide it' : undefined}>{daily?.uv_index_max?.[0] != null ? Math.round(daily.uv_index_max[0]) : '--'}</span>
<span class="detail-value">{daily?.uv_index_max?.[0] != null ? Math.round(daily.uv_index_max[0]) : '--'}{#if fbUv}<SourceTooltip label="UV from Open-Meteo — NWS does not provide it" />{/if}</span>
</div>
</div>
</div>