Google Page Insights Tweaks

This commit is contained in:
fraxle
2026-05-16 09:21:06 +01:00
parent 8d2bb6e608
commit de1f2f5a37
7 changed files with 114 additions and 91 deletions
+2 -1
View File
@@ -34,7 +34,8 @@
/* ── 1. FONTS + RESET ───────────────────────────────────────────────── */ /* ── 1. FONTS + RESET ───────────────────────────────────────────────── */
@import "https://fonts.bunny.net/css2?family=Fraunces:ital,wght@0,300;0,500;0,700;0,900;1,300;1,500;1,700;1,900&family=JetBrains+Mono:wght@400;600&family=Manrope:wght@400;500;600;700&display=swap"; /* Font loading is handled in index.html via a non-blocking <link rel="preload">
to avoid render-blocking. The @import has been intentionally removed. */
*, *,
*:before, *:before,
+5 -5
View File
@@ -141,7 +141,7 @@
font-size: 12px; font-size: 12px;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.18em; letter-spacing: 0.18em;
color: #b09870; color: #7a5c2a;
margin-right: 4px; margin-right: 4px;
white-space: nowrap; white-space: nowrap;
} }
@@ -151,7 +151,7 @@
cursor: pointer; cursor: pointer;
border: 1.5px solid #c9b08a; border: 1.5px solid #c9b08a;
background: #f5edd6; background: #f5edd6;
color: #9a7d5a; color: #6b4228;
font-family: JetBrains Mono, monospace; font-family: JetBrains Mono, monospace;
font-size: 13px; font-size: 13px;
text-transform: uppercase; text-transform: uppercase;
@@ -192,7 +192,7 @@
font-size: 12px; font-size: 12px;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.18em; letter-spacing: 0.18em;
color: #b09870; color: #7a5c2a;
margin-right: 4px; margin-right: 4px;
white-space: nowrap; white-space: nowrap;
} }
@@ -203,7 +203,7 @@
cursor: pointer; cursor: pointer;
border: 1.5px solid #c9b08a; border: 1.5px solid #c9b08a;
background: #f5edd6; background: #f5edd6;
color: #9a7d5a; color: #6b4228;
font-family: JetBrains Mono, monospace; font-family: JetBrains Mono, monospace;
font-size: 12px; font-size: 12px;
text-transform: uppercase; text-transform: uppercase;
@@ -295,7 +295,7 @@
border-left: 1px solid #d4c0a0; /* softer join line */ border-left: 1px solid #d4c0a0; /* softer join line */
border-radius: 0 20px 20px 0; border-radius: 0 20px 20px 0;
background: #fef8ee; background: #fef8ee;
color: #7a5c30; color: #6b4228;
user-select: none; user-select: none;
transition: background 0.15s, color 0.15s, border-color 0.15s; transition: background 0.15s, color 0.15s, border-color 0.15s;
white-space: nowrap; white-space: nowrap;
+23 -13
View File
@@ -20,9 +20,9 @@
cursor: pointer; cursor: pointer;
border: 1.5px solid #c9b08a; border: 1.5px solid #c9b08a;
background: #f5edd6; background: #f5edd6;
color: #9a7d5a; color: #6b4228;
font-family: JetBrains Mono, monospace; font-family: JetBrains Mono, monospace;
font-size: 12px; font-size: 13px;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.1em; letter-spacing: 0.1em;
transition: all 0.15s; transition: all 0.15s;
@@ -36,26 +36,36 @@
} }
/* Active state — brass border + brass text, parchment background */ /* Active state — brass border + brass text, parchment background */
.cs-btn.on { .cs-btn.on {
background: #c8922a;
border-color: #c8922a; border-color: #c8922a;
color: #c8922a; color: #fff;
background: #f5edd6;
font-weight: 600; font-weight: 600;
} }
.cs-btn.on:hover { .cs-btn.on:hover {
background: #fef3dc; background: #a06e18;
color: #a06e18;
border-color: #a06e18; border-color: #a06e18;
color: #fff;
} }
/* The chevron arrow inside the button */ /* The chevron arrow inside the button */
.cs-arrow { .cs-arrow {
font-size: 9px;
opacity: 0.6;
margin-left: 2px;
transition: transform 0.15s;
display: inline-block; display: inline-block;
width: 6px;
height: 6px;
border-right: 2px solid currentColor;
border-bottom: 2px solid currentColor;
transform: rotate(45deg);
margin-left: 5px;
margin-bottom: 3px;
opacity: 1;
transition: transform 0.15s;
vertical-align: middle;
} }
.cs-wrap.open .cs-arrow { .cs-wrap.open .cs-arrow {
transform: rotate(225deg);
margin-bottom: -1px;
}
.cs-wrap.open .cs-arrow-old {
transform: rotate(180deg); transform: rotate(180deg);
} }
@@ -140,7 +150,7 @@
padding-left: 11px; padding-left: 11px;
border-radius: 0 20px 20px 0; border-radius: 0 20px 20px 0;
background: #f5edd6; background: #f5edd6;
color: #9a7d5a; color: #6b4228;
user-select: none; user-select: none;
transition: background 0.15s, color 0.15s, border-color 0.15s; transition: background 0.15s, color 0.15s, border-color 0.15s;
white-space: nowrap; white-space: nowrap;
@@ -215,7 +225,7 @@
font-size: 10px; font-size: 10px;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.18em; letter-spacing: 0.18em;
color: #b09870; color: #7a5c2a;
margin-bottom: 12px; margin-bottom: 12px;
display: block; display: block;
font-weight: 600; font-weight: 600;
@@ -301,7 +311,7 @@
font-size: 10px; font-size: 10px;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.12em; letter-spacing: 0.12em;
color: #c0a880; color: #9a7d5a;
line-height: 2.2; line-height: 2.2;
} }
+70 -65
View File
@@ -139,12 +139,6 @@ export function UTCIForecast() {
icon: '🌡️', icon: '🌡️',
cols: { hour: true, air: true, rh: false, dew: false, wind: true, dir: false, cloud: true, sun: false, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: false, uvB: false, burn: false, utciP: true, precip: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false }, cols: { hour: true, air: true, rh: false, dew: false, wind: true, dir: false, cloud: true, sun: false, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: false, uvB: false, burn: false, utciP: true, precip: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false },
}, },
outdoors: {
label: 'Places',
icon: '🌤️',
// Default cols match the first variant (urban). Switching variant updates visibleCols.
cols: { hour: true, air: true, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: true, uvB: false, burn: true, utciP: true, precip: true, soilT: false, soilT6: false, soilM: false, concreteT: true, vehicleT: false, indoorT: false, managedT: false },
},
home: { home: {
label: 'Home', label: 'Home',
icon: '🏠', icon: '🏠',
@@ -160,11 +154,11 @@ export function UTCIForecast() {
icon: '🌾', icon: '🌾',
cols: { hour: true, air: true, rh: true, dew: true, wind: true, dir: true, cloud: true, sun: true, direct: false, diffuse: false, tmrt: false, delta: false, utci: true, uvA: false, uvB: false, burn: false, utciP: false, precip: true, soilT: true, soilT6: true, soilM: true, concreteT: false, vehicleT: false, indoorT: false, managedT: false }, cols: { hour: true, air: true, rh: true, dew: true, wind: true, dir: true, cloud: true, sun: true, direct: false, diffuse: false, tmrt: false, delta: false, utci: true, uvA: false, uvB: false, burn: false, utciP: false, precip: true, soilT: true, soilT6: true, soilM: true, concreteT: false, vehicleT: false, indoorT: false, managedT: false },
}, },
sailing: { outdoors: {
label: 'Sailing', label: 'Places',
icon: '', icon: '🌤️',
proOnly: true, // Default cols match the first variant (urban). Switching variant updates visibleCols.
cols: { hour: true, air: true, rh: false, dew: true, wind: true, dir: true, cloud: true, sun: true, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: true, uvB: false, burn: true, utciP: true, precip: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false }, cols: { hour: true, air: true, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: true, uvB: false, burn: true, utciP: true, precip: true, soilT: false, soilT6: false, soilM: false, concreteT: true, vehicleT: false, indoorT: false, managedT: false },
}, },
alltemps: { alltemps: {
label: 'Temps', label: 'Temps',
@@ -189,6 +183,7 @@ export function UTCIForecast() {
festival: { name: 'Festival', proOnly: true, cols: { hour: true, air: true, rh: false, dew: true, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: true, uvB: false, burn: true, utciP: true, precip: true, soilT: false, soilT6: false, soilM: true, concreteT: false, vehicleT: false, indoorT: false, managedT: false } }, festival: { name: 'Festival', proOnly: true, cols: { hour: true, air: true, rh: false, dew: true, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: true, uvB: false, burn: true, utciP: true, precip: true, soilT: false, soilT6: false, soilM: true, concreteT: false, vehicleT: false, indoorT: false, managedT: false } },
wintersports: { name: 'Winter Sports', proOnly: true, cols: { hour: true, air: true, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: true, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: true, uvB: true, burn: true, utciP: true, precip: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false } }, wintersports: { name: 'Winter Sports', proOnly: true, cols: { hour: true, air: true, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: true, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: true, uvB: true, burn: true, utciP: true, precip: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false } },
naturist: { name: 'Naturist', proOnly: true, cols: { hour: true, air: true, rh: false, dew: true, wind: true, dir: false, cloud: true, sun: true, direct: false, diffuse: false, tmrt: false, delta: false, utci: true, uvA: true, uvB: true, burn: true, utciP: true, precip: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false } }, naturist: { name: 'Naturist', proOnly: true, cols: { hour: true, air: true, rh: false, dew: true, wind: true, dir: false, cloud: true, sun: true, direct: false, diffuse: false, tmrt: false, delta: false, utci: true, uvA: true, uvB: true, burn: true, utciP: true, precip: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false } },
sailing: { name: 'Sailing', proOnly: true, cols: { hour: true, air: true, rh: false, dew: true, wind: true, dir: true, cloud: true, sun: true, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: true, uvB: false, burn: true, utciP: true, precip: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false } },
}; };
// Current active filter profile // Current active filter profile
@@ -692,7 +687,7 @@ export function UTCIForecast() {
<div class="lens-bloom-a"></div> <div class="lens-bloom-a"></div>
<div class="lens-bloom-b"></div> <div class="lens-bloom-b"></div>
<div class="utci-shell"> <main class="utci-shell">
<div class="utci-header"> <div class="utci-header">
<div> <div>
@@ -1025,6 +1020,41 @@ export function UTCIForecast() {
<span class="filter-profiles-label">Profile:</span> <span class="filter-profiles-label">Profile:</span>
${Object.entries(FILTER_PROFILES).map(([key, profile]) => { ${Object.entries(FILTER_PROFILES).map(([key, profile]) => {
const locked = profile.proOnly && !isPro; const locked = profile.proOnly && !isPro;
// The 'outdoors' profile becomes a CustomSelect dropdown
if (key === 'outdoors') {
return html`
<${CustomSelect}
key="outdoors"
value=${activeProfile === 'outdoors' ? outdoorsVariant : 'off'}
isOn=${activeProfile === 'outdoors'}
noHide=${true}
hideLabel=${`${profile.icon} ${profile.label}`}
options=${Object.entries(OUTDOORS_VARIANTS).map(([k, v]) => ({
value: k,
label: v.name + (v.proOnly && !isPro ? ' 🔒' : ''),
disabled: false,
}))}
onChange=${(v) => {
if (v === 'off') {
setActiveProfile('basic');
setVisibleCols({ ...FILTER_PROFILES.basic.cols });
setIndoorMode('off');
return;
}
if (OUTDOORS_VARIANTS[v]?.proOnly && !isPro) {
setProPromptSource(`variant:${v}`);
setProPromptDay(0);
return;
}
setActiveProfile('outdoors');
setOutdoorsVariant(v);
setVisibleCols({ ...OUTDOORS_VARIANTS[v].cols });
setIndoorMode('off');
}}
/>`;
}
return html` return html`
<button <button
key=${key} key=${key}
@@ -1038,10 +1068,7 @@ export function UTCIForecast() {
return; return;
} }
setActiveProfile(key); setActiveProfile(key);
if (key === 'outdoors') { if (key !== 'custom') {
// Apply the current variant's cols (default: urban on first switch)
setVisibleCols({ ...OUTDOORS_VARIANTS[outdoorsVariant].cols });
} else if (key !== 'custom') {
setVisibleCols({ ...profile.cols }); setVisibleCols({ ...profile.cols });
} }
// Auto-enable indoor column for profiles that include it; // Auto-enable indoor column for profiles that include it;
@@ -1067,28 +1094,6 @@ export function UTCIForecast() {
<div class="col-toggles"> <div class="col-toggles">
<span class="col-toggles-label">Columns:</span> <span class="col-toggles-label">Columns:</span>
${activeProfile === 'outdoors' && html`
<${CustomSelect}
value=${outdoorsVariant}
isOn=${true}
hideLabel="Outdoors"
hidingLabel="Hide Outdoors"
options=${Object.entries(OUTDOORS_VARIANTS).map(([k, v]) => ({
value: k,
label: v.name + (v.proOnly && !isPro ? ' 🔒' : ''),
disabled: false,
}))}
onChange=${(v) => {
if (OUTDOORS_VARIANTS[v]?.proOnly && !isPro) {
setProPromptSource(`variant:${v}`);
setProPromptDay(0);
return;
}
setOutdoorsVariant(v);
setVisibleCols({ ...OUTDOORS_VARIANTS[v].cols });
}}
/>`}
${isPro && (activeProfile === 'custom' || FILTER_PROFILES[activeProfile].cols['air']) && html`<button class=${`col-toggle${visibleCols.air ? ' on' : ''}`} onClick=${() => toggleCol('air')}>Air</button>`} ${isPro && (activeProfile === 'custom' || FILTER_PROFILES[activeProfile].cols['air']) && html`<button class=${`col-toggle${visibleCols.air ? ' on' : ''}`} onClick=${() => toggleCol('air')}>Air</button>`}
${isPro && (activeProfile === 'custom' || FILTER_PROFILES[activeProfile].cols['rh']) && html`<button class=${`col-toggle${visibleCols.rh ? ' on' : ''}`} onClick=${() => toggleCol('rh')}>RH</button>`} ${isPro && (activeProfile === 'custom' || FILTER_PROFILES[activeProfile].cols['rh']) && html`<button class=${`col-toggle${visibleCols.rh ? ' on' : ''}`} onClick=${() => toggleCol('rh')}>RH</button>`}
${isPro && (activeProfile === 'custom' || FILTER_PROFILES[activeProfile].cols['dew']) && html`<button class=${`col-toggle${visibleCols.dew ? ' on' : ''}`} onClick=${() => toggleCol('dew')}>Dew</button>`} ${isPro && (activeProfile === 'custom' || FILTER_PROFILES[activeProfile].cols['dew']) && html`<button class=${`col-toggle${visibleCols.dew ? ' on' : ''}`} onClick=${() => toggleCol('dew')}>Dew</button>`}
@@ -1214,31 +1219,31 @@ export function UTCIForecast() {
<table class="utci-table utci-table-head" ref=${headTableRef}> <table class="utci-table utci-table-head" ref=${headTableRef}>
<thead> <thead>
<tr> <tr>
<th class="col-info-th" onClick=${(e) => handleThClick('hour', e)}>Hour</th> <th class="col-info-th" scope="col" onClick=${(e) => handleThClick('hour', e)}>Hour</th>
${visibleCols.air && html`<th class="utci-tight-head col-info-th" onClick=${(e) => handleThClick('air', e)}>Air <span class="col-unit">°C</span></th>`} ${visibleCols.air && html`<th class="utci-tight-head col-info-th" scope="col" onClick=${(e) => handleThClick('air', e)}>Air <span class="col-unit">°C</span></th>`}
${visibleCols.rh && html`<th class="col-info-th" onClick=${(e) => handleThClick('rh', e)}>RH <span class="col-unit">%</span></th>`} ${visibleCols.rh && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('rh', e)}>RH <span class="col-unit">%</span></th>`}
${visibleCols.dew && html`<th class="col-info-th" onClick=${(e) => handleThClick('dew', e)}>Dew <span class="col-unit">°C</span></th>`} ${visibleCols.dew && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('dew', e)}>Dew <span class="col-unit">°C</span></th>`}
${visibleCols.soilT && html`<th class="col-info-th" onClick=${(e) => handleThClick('soilT', e)}>Soil °C <span class="col-unit">surface</span></th>`} ${visibleCols.soilT && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('soilT', e)}>Soil °C <span class="col-unit">surface</span></th>`}
${visibleCols.soilT6 && html`<th class="col-info-th" onClick=${(e) => handleThClick('soilT6', e)}>Soil 6cm <span class="col-unit">°C root</span></th>`} ${visibleCols.soilT6 && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('soilT6', e)}>Soil 6cm <span class="col-unit">°C root</span></th>`}
${visibleCols.soilM && html`<th class="col-info-th" onClick=${(e) => handleThClick('soilM', e)}>Soil moist <span class="col-unit">m³/m³</span></th>`} ${visibleCols.soilM && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('soilM', e)}>Soil moist <span class="col-unit">m³/m³</span></th>`}
${visibleCols.concreteT && html`<th class="col-info-th" onClick=${(e) => handleThClick('concreteT', e)}>Concrete <span class="col-unit">°C surface</span></th>`} ${visibleCols.concreteT && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('concreteT', e)}>Concrete <span class="col-unit">°C surface</span></th>`}
${visibleCols.wind && html`<th class="col-info-th" onClick=${(e) => handleThClick('wind', e)}>Wind <span class="col-unit">m/s (gust)</span></th>`} ${visibleCols.wind && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('wind', e)}>Wind <span class="col-unit">m/s (gust)</span></th>`}
${visibleCols.dir && html`<th class="utci-dir-cell col-info-th" onClick=${(e) => handleThClick('dir', e)}>Dir <span class="col-unit">-</span></th>`} ${visibleCols.dir && html`<th class="utci-dir-cell col-info-th" scope="col" onClick=${(e) => handleThClick('dir', e)}>Dir <span class="col-unit">-</span></th>`}
${visibleCols.cloud && html`<th class="col-info-th" onClick=${(e) => handleThClick('cloud', e)}>Cloud <span class="col-unit">%</span></th>`} ${visibleCols.cloud && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('cloud', e)}>Cloud <span class="col-unit">%</span></th>`}
${visibleCols.sun && html`<th class="col-info-th" onClick=${(e) => handleThClick('sun', e)}>Sun <span class="col-unit">elev°</span></th>`} ${visibleCols.sun && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('sun', e)}>Sun <span class="col-unit">elev°</span></th>`}
${visibleCols.direct && html`<th class="col-info-th" onClick=${(e) => handleThClick('direct', e)}>Direct <span class="col-unit">W/m²</span></th>`} ${visibleCols.direct && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('direct', e)}>Direct <span class="col-unit">W/m²</span></th>`}
${visibleCols.diffuse && html`<th class="col-info-th" onClick=${(e) => handleThClick('diffuse', e)}>Diffuse <span class="col-unit">W/m²</span></th>`} ${visibleCols.diffuse && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('diffuse', e)}>Diffuse <span class="col-unit">W/m²</span></th>`}
${visibleCols.tmrt && html`<th class="col-info-th" onClick=${(e) => handleThClick('tmrt', e)}>Tmrt <span class="col-unit">°C</span></th>`} ${visibleCols.tmrt && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('tmrt', e)}>Tmrt <span class="col-unit">°C</span></th>`}
${visibleCols.delta && html`<th class="col-info-th" onClick=${(e) => handleThClick('delta', e)}>Δ <span class="col-unit">UTCIAir</span></th>`} ${visibleCols.delta && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('delta', e)}>Δ <span class="col-unit">UTCIAir</span></th>`}
${visibleCols.utci && html`<th class="col-info-th" onClick=${(e) => handleThClick('utci', e)}>UTCI <span class="col-unit">°C felt</span></th>`} ${visibleCols.utci && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('utci', e)}>UTCI <span class="col-unit">°C felt</span></th>`}
${visibleCols.uvA && html`<th class="col-info-th" onClick=${(e) => handleThClick('uvA', e)}>UV-A <span class="col-unit">est. idx</span></th>`} ${visibleCols.uvA && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('uvA', e)}>UV-A <span class="col-unit">est. idx</span></th>`}
${visibleCols.uvB && html`<th class="col-info-th" onClick=${(e) => handleThClick('uvB', e)}>UV-B <span class="col-unit">est. idx</span></th>`} ${visibleCols.uvB && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('uvB', e)}>UV-B <span class="col-unit">est. idx</span></th>`}
${visibleCols.burn && html`<th class="col-info-th" onClick=${(e) => handleThClick('burn', e)}>Burn <span class="col-unit">to MED</span></th>`} ${visibleCols.burn && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('burn', e)}>Burn <span class="col-unit">to MED</span></th>`}
${visibleCols.vehicleT && html`<th class="col-info-th" onClick=${(e) => handleThClick('vehicleT', e)}>Vehicle <span class="col-unit">°C peak</span></th>`} ${visibleCols.vehicleT && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('vehicleT', e)}>Vehicle <span class="col-unit">°C peak</span></th>`}
${indoorMode === 'on' && !indoorManaged && html`<th class="col-info-th" onClick=${(e) => handleThClick('indoorT', e)}>Indoors <span class="col-unit">°C est.</span></th>`} ${indoorMode === 'on' && !indoorManaged && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('indoorT', e)}>Indoors <span class="col-unit">°C est.</span></th>`}
${indoorMode === 'on' && indoorManaged && html`<th class="col-info-th" onClick=${(e) => handleThClick('managedT', e)}>Managed <span class="col-unit">°C est.</span></th>`} ${indoorMode === 'on' && indoorManaged && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('managedT', e)}>Managed <span class="col-unit">°C est.</span></th>`}
${visibleCols.precip && html`<th class="utci-tight-head col-info-th" onClick=${(e) => handleThClick('precip', e)}>Pcpt <span class="col-unit">mm/h</span></th>`} ${visibleCols.precip && html`<th class="utci-tight-head col-info-th" scope="col" onClick=${(e) => handleThClick('precip', e)}>Pcpt <span class="col-unit">mm/h</span></th>`}
${visibleCols.utciP && html`<th class="col-info-th" onClick=${(e) => handleThClick('utciP', e)}>UTCI+P <span class="col-unit">°C adj.</span></th>`} ${visibleCols.utciP && html`<th class="col-info-th" scope="col" onClick=${(e) => handleThClick('utciP', e)}>UTCI+P <span class="col-unit">°C adj.</span></th>`}
</tr> </tr>
</thead> </thead>
</table> </table>
@@ -1420,7 +1425,7 @@ export function UTCIForecast() {
{ l: '-13 to 0 Freezing', bg: '#7eb0e0', fg: '#111' }, { l: '-13 to 0 Freezing', bg: '#7eb0e0', fg: '#111' },
{ l: '0 to 9 Cold', bg: '#bcd9ec', fg: '#111' }, { l: '0 to 9 Cold', bg: '#bcd9ec', fg: '#111' },
{ l: '9 to 18 Chilled', bg: '#c8dcc0', fg: '#111' }, { l: '9 to 18 Chilled', bg: '#c8dcc0', fg: '#111' },
{ l: '18 to 26 Comfortable', bg: '#6ab05a', fg: '#fff' }, { l: '18 to 26 Comfortable', bg: '#4a8a3a', fg: '#fff' },
{ l: '26 to 32 Mod heat', bg: '#e8c547', fg: '#111' }, { l: '26 to 32 Mod heat', bg: '#e8c547', fg: '#111' },
{ l: '32 to 38 Strong heat', bg: '#dc8a3a', fg: '#111' }, { l: '32 to 38 Strong heat', bg: '#dc8a3a', fg: '#111' },
{ l: '38 to 46 V. strong', bg: '#c44a3a', fg: '#fff' }, { l: '38 to 46 V. strong', bg: '#c44a3a', fg: '#fff' },
@@ -1460,6 +1465,6 @@ export function UTCIForecast() {
On clear sunny days this gap can exceed 10 °C even at modest air temperatures. On clear sunny days this gap can exceed 10 °C even at modest air temperatures.
</div> </div>
</div> </main>
</div>`; </div>`;
} }
+3 -3
View File
@@ -36,7 +36,7 @@ const html = htm.bind(h);
// groupedLeft — bool — fuse right side with a VentPill // groupedLeft — bool — fuse right side with a VentPill
// isLastChild — bool — restore right border-radius when no sibling follows // isLastChild — bool — restore right border-radius when no sibling follows
// ═══════════════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════════════
export function CustomSelect({ value, options, onChange, hideLabel, hidingLabel, isOn, groupedLeft, isLastChild }) { export function CustomSelect({ value, options, onChange, hideLabel, hidingLabel, isOn, noHide, groupedLeft, isLastChild }) {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const wrapRef = useRef(null); const wrapRef = useRef(null);
@@ -78,11 +78,11 @@ export function CustomSelect({ value, options, onChange, hideLabel, hidingLabel,
type="button" type="button"
> >
${btnLabel} ${btnLabel}
<span class="cs-arrow"></span> <span class="cs-arrow"></span>
</button> </button>
${open && html` ${open && html`
<div class="cs-panel" role="listbox"> <div class="cs-panel" role="listbox">
${isOn && html` ${isOn && !noHide && html`
<span <span
class="cs-option" class="cs-option"
role="option" role="option"
+1 -1
View File
@@ -33,7 +33,7 @@ export function utciCategory(u) {
if (u < 0) return { label: 'Freezing', bg: '#7eb0e0', fg: '#1a1612' }; if (u < 0) return { label: 'Freezing', bg: '#7eb0e0', fg: '#1a1612' };
if (u < 9) return { label: 'Cold', bg: '#bcd9ec', fg: '#1a1612' }; if (u < 9) return { label: 'Cold', bg: '#bcd9ec', fg: '#1a1612' };
if (u < 18) return { label: 'Chilled', bg: '#c8dcc0', fg: '#1a1612' }; if (u < 18) return { label: 'Chilled', bg: '#c8dcc0', fg: '#1a1612' };
if (u < 26) return { label: 'Comfortable', bg: '#6ab05a', fg: '#fff' }; if (u < 26) return { label: 'Comfortable', bg: '#4a8a3a', fg: '#fff' };
if (u < 32) return { label: 'Moderate heat', bg: '#e8c547', fg: '#1a1612' }; if (u < 32) return { label: 'Moderate heat', bg: '#e8c547', fg: '#1a1612' };
if (u < 38) return { label: 'Strong heat', bg: '#dc8a3a', fg: '#1a1612' }; if (u < 38) return { label: 'Strong heat', bg: '#dc8a3a', fg: '#1a1612' };
if (u < 46) return { label: 'Very strong heat', bg: '#c44a3a', fg: '#fff' }; if (u < 46) return { label: 'Very strong heat', bg: '#c44a3a', fg: '#fff' };
+9 -2
View File
@@ -68,8 +68,15 @@
} }
</script> </script>
<link rel="preconnect" href="https://fonts.bunny.net" /> <link rel="preconnect" href="https://fonts.bunny.net" crossorigin />
<link rel="preconnect" href="https://api.open-meteo.com" /> <link rel="preconnect" href="https://api.open-meteo.com" crossorigin />
<link rel="preload" as="style"
href="https://fonts.bunny.net/css2?family=Fraunces:ital,wght@0,700;0,900;1,300;1,500;1,900&family=JetBrains+Mono:wght@400;600&family=Manrope:wght@400;500;600;700&display=swap"
onload="this.onload=null;this.rel='stylesheet'" />
<noscript>
<link rel="stylesheet"
href="https://fonts.bunny.net/css2?family=Fraunces:ital,wght@0,700;0,900;1,300;1,500;1,900&family=JetBrains+Mono:wght@400;600&family=Manrope:wght@400;500;600;700&display=swap" />
</noscript>
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>☀️</text></svg>" /> <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>☀️</text></svg>" />
<link rel="stylesheet" href="./assets/sunscope.css?v=15a"> <link rel="stylesheet" href="./assets/sunscope.css?v=15a">
</head> </head>