New SunSoak multiselect UTCI modifiers pulldown
Linked new SunSoak to profiles
Updated content to match new changes
This commit is contained in:
fraxle
2026-05-25 11:24:46 +01:00
parent 2cb4ebe52b
commit 2f76f98632
8 changed files with 239 additions and 93 deletions
+49 -17
View File
@@ -30,7 +30,7 @@ import {
} from './utils.js';
import { SkyScope, WindVane, CloudIcon, ScopeReticle, PrecipIcon, CustomSelect, VentPill } from './components.js';
import { getCellTagEvents, getUpcomingEvents } from './events.js';
import { POLLEN_TYPES, COL_DESCRIPTIONS } from './config.js';
import { POLLEN_TYPES, COL_DESCRIPTIONS, UTCI_ENVIRONMENTS } from './config.js';
import { useAppState } from './hooks/useAppState.js';
import { DayTabs } from './components/DayTabs.js';
@@ -64,6 +64,7 @@ export function UTCIForecast() {
indoorManaged, setIndoorManaged,
indoorMode, setIndoorMode,
pollenType, setPollenTypeAndSave,
utciEnv, setUtciEnv,
headStickyRef, headTrackRef, headTableRef,
bodyScrollRef, bodyTableRef, tableWrapRef,
colPopup, colPopupRef,
@@ -334,11 +335,34 @@ export function UTCIForecast() {
/>`}
${(isPro || activeCols['burn'] || activeCols['vehicleT'] || activeCols['indoorT'] || activeCols['managedT'] || activeCols['pollen']) && html`
${(isPro || activeCols['utciP'] || activeCols['burn'] || activeCols['vehicleT'] || activeCols['indoorT'] || activeCols['managedT'] || activeCols['pollen']) && html`
<div class="col-toggles">
<span class="col-toggles-label">Columns:</span>
${isPro && (activeProfile === 'custom' || activeProfile === 'showall' || activeCols['utciP']) && html`<button class=${`col-toggle grp-felt${visibleCols.utciP ? ' on' : ''}`} onClick=${() => toggleCol('utciP')}>UTCI+P</button>`}
${(isPro ? (activeProfile === 'custom' || activeProfile === 'showall' || activeCols['utciP']) : activeCols['utciP']) && html`
<span class=${'col-toggle-group' + (visibleCols.utciP ? ' col-toggle-group--expanded' : '')}>
<${CustomSelect}
value=${utciEnv}
isOn=${visibleCols.utciP}
grpClass="grp-felt"
hideLabel="SunSoak"
hidingLabel="Hide SunSoak"
groupedLeft=${true}
isLastChild=${true}
options=${Object.entries(UTCI_ENVIRONMENTS).map(([k, v]) => ({
value: k,
label: v.label,
}))}
onChange=${(v) => {
if (v === 'off') {
setVisibleCols(prev => ({ ...prev, utciP: false }));
} else {
setUtciEnv(v);
setVisibleCols(prev => ({ ...prev, utciP: true }));
}
}}
/>
</span>`}
${(isPro ? (activeProfile === 'custom' || activeProfile === 'showall' || activeCols['vehicleT']) : activeCols['vehicleT']) && html`
<span class=${'col-toggle-group' + (visibleCols.vehicleT ? ' col-toggle-group--expanded' : '')}>
<${CustomSelect}
@@ -491,7 +515,7 @@ ${isPro && (activeProfile === 'custom' || activeProfile === 'showall' || activeC
${groupLabelRow()}
<tr>
<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('hour', e)} onMouseEnter=${(e) => handleThEnter('hour', e)} onMouseLeave=${handleThLeave}>Hour</th>
${visibleCols.utciP && html`<th class=${`col-info-th ${groupStart('utciP')} ${groupColor('utciP')}`} scope="col" onClick=${(e) => handleThClick('utciP', e)} onMouseEnter=${(e) => handleThEnter('utciP', e)} onMouseLeave=${handleThLeave}>UTCI+P <span class="col-unit">°C adj.</span></th>`}
${visibleCols.utciP && html`<th class=${`col-info-th ${groupStart('utciP')} ${groupColor('utciP')}`} scope="col" onClick=${(e) => handleThClick('utciP', e)} onMouseEnter=${(e) => handleThEnter('utciP', e)} onMouseLeave=${handleThLeave}>SunSoak <span class="col-unit">°C felt</span></th>`}
${visibleCols.vehicleT && html`<th class=${`col-info-th ${groupStart('vehicleT')} ${groupColor('vehicleT')}`} scope="col" onClick=${(e) => handleThClick('vehicleT', e)} onMouseEnter=${(e) => handleThEnter('vehicleT', e)} onMouseLeave=${handleThLeave}>Vehicle <span class="col-unit">°C peak</span></th>`}
${indoorMode === 'on' && !indoorManaged && html`<th class=${`col-info-th ${groupStart('indoorT')} ${groupColor('indoorT')}`} scope="col" onClick=${(e) => handleThClick('indoorT', e)} onMouseEnter=${(e) => handleThEnter('indoorT', e)} onMouseLeave=${handleThLeave}>Indoors <span class="col-unit">°C est.</span></th>`}
${indoorMode === 'on' && indoorManaged && html`<th class=${`col-info-th ${groupStart('managedT')} ${groupColor('managedT')}`} scope="col" onClick=${(e) => handleThClick('managedT', e)} onMouseEnter=${(e) => handleThEnter('managedT', e)} onMouseLeave=${handleThLeave}>Managed <span class="col-unit">°C est.</span></th>`}
@@ -879,26 +903,34 @@ ${isPro && (activeProfile === 'custom' || activeProfile === 'showall' || activeC
<p class="utci-about-text">
SunScope is a free hourly weather forecast built around <strong>felt temperature</strong>,
not just air temperature. It uses the <strong>Universal Thermal Climate Index (UTCI)</strong>
the biometeorological standard used in heat-health warning systems worldwide to combine
air temperature, humidity, wind, and solar radiation into a single honest number. The
<strong>UTCI+P</strong> column adds an original rain and snow penalty so wet, windy days
read as cold as they feel.
the biometeorological standard used in heat-health warning systems worldwide as its
foundation, combining air temperature, humidity, wind, and solar radiation into a single
honest number. Then it goes further. Our <strong>SunSoak</strong> index layers three extra
dimensions on top: a rain and snow penalty so wet, windy days read as cold as they feel;
an <strong>environment modifier</strong> that adjusts the solar load for where you actually
are forest canopy, alpine altitude, lakeside glare, shaded riverbank, desert ground heat;
and the full radiant heat absorbed from surrounding surfaces. One number that honestly
answers: <em>what will my body actually feel out there?</em>
</p>
<p class="utci-about-text">
Beyond felt temperature, SunScope calculates <strong>vehicle cabin heat</strong> (choose
your vehicle type; toggle windows open), <strong>indoor temperature</strong> (seven
building types; managed heatwave mode), <strong>urban concrete surface temperature</strong>,
<strong>UV index and sunburn time</strong> by skin type, and <strong>soil temperature
and moisture</strong> for farming and motorhome use. Switch profiles to see the data
that matters for your situation or go Custom and build your own view.
Beyond SunSoak, SunScope calculates <strong>vehicle cabin heat</strong> (choose your
vehicle type; toggle windows open), <strong>indoor temperature</strong> (seven building
types including office blocks; managed heatwave mode), <strong>urban concrete surface
temperature</strong>, <strong>UV index and sunburn time</strong> by skin type, and
<strong>soil temperature and moisture</strong> for farming and motorhome use. Switch
profiles Places, Activities, Work to see the data that matters for your situation,
or go Custom and build your own view.
<a href="./about.html" class="utci-about-link">Learn more </a>
</p>
</div>
<div class="utci-footer">
<em>Reading the table.</em> A large positive Δ means your body is absorbing
far more heat than the air temperature alone suggests typically due to direct solar radiation.
On clear sunny days this gap can exceed 10 °C even at modest air temperatures.
<em>Reading the table.</em> SunSoak is the number to watch it reflects everything your body
actually experiences, not just what the thermometer says. A large gap between SunSoak and Air
temperature means solar radiation is doing significant work on your body. On clear sunny days
that gap can exceed 10 °C even at modest air temperatures. The environment modifier in the
SunSoak dropdown adjusts the solar load for your surroundings switch it to match where you are
for the most accurate reading.
${isPro && html`
<div style=${{ marginTop: '10px', paddingTop: '10px', borderTop: '1px solid #d4c0a0' }}>
SunScope Extra is active.