Style Fix and Subscription Fix

This commit is contained in:
fraxle
2026-05-16 10:19:47 +01:00
parent de1f2f5a37
commit e730e3f008
2 changed files with 67 additions and 18 deletions
+10
View File
@@ -146,6 +146,16 @@
white-space: nowrap; white-space: nowrap;
} }
/* Vertical rule separating general-use profiles from technical ones */
.profile-divider {
display: inline-block;
width: 1px;
align-self: stretch;
background: #c9b08a;
margin: 2px 6px;
opacity: 0.6;
}
.profile-btn { .profile-btn {
padding: 5px 13px; padding: 5px 13px;
cursor: pointer; cursor: pointer;
+57 -18
View File
@@ -681,8 +681,12 @@ export function UTCIForecast() {
return html` return html`
<div class="utci-app"> <div class="utci-app">
<nav class="utci-topnav"> <nav class="utci-topnav">
<a href="./index.html">Home</a> <a href="./index.html">Forecast</a>
<a href="./about.html">About</a> <a href="./about.html">About</a>
<a href=${isPro
? 'https://billing.stripe.com/p/login/9B63cw7vl8k15Ei9DQd7q00'
: 'https://buy.stripe.com/9B63cw7vl8k15Ei9DQd7q00'}
target="_blank" rel="noopener noreferrer">Account</a>
</nav> </nav>
<div class="lens-bloom-a"></div> <div class="lens-bloom-a"></div>
<div class="lens-bloom-b"></div> <div class="lens-bloom-b"></div>
@@ -927,7 +931,7 @@ export function UTCIForecast() {
alignItems: 'flex-end', alignItems: 'flex-end',
}}> }}>
<a <a
href="https://buy.stripe.com/test_28E00j4xr6Es0izeE3fw400" href="https://buy.stripe.com/9B63cw7vl8k15Ei9DQd7q00"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
style=${{ style=${{
@@ -961,6 +965,23 @@ export function UTCIForecast() {
> >
Already subscribed? Restore access → Already subscribed? Restore access →
</a> </a>
<a
href="https://billing.stripe.com/p/login/9B63cw7vl8k15Ei9DQd7q00"
target="_blank"
rel="noopener noreferrer"
style=${{
fontFamily: 'JetBrains Mono, monospace',
fontSize: '10px',
textTransform: 'uppercase',
letterSpacing: '0.14em',
color: '#b09870',
textDecoration: 'none',
borderBottom: '1px solid rgba(176,152,112,0.4)',
paddingBottom: '1px',
}}
>
Manage or cancel subscription →
</a>
<button <button
onClick=${() => setProPromptDay(null)} onClick=${() => setProPromptDay(null)}
style=${{ style=${{
@@ -1021,7 +1042,8 @@ export function UTCIForecast() {
${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 // The 'outdoors' profile becomes a CustomSelect dropdown,
// followed by a separator dividing general-use from technical profiles.
if (key === 'outdoors') { if (key === 'outdoors') {
return html` return html`
<${CustomSelect} <${CustomSelect}
@@ -1052,7 +1074,8 @@ export function UTCIForecast() {
setVisibleCols({ ...OUTDOORS_VARIANTS[v].cols }); setVisibleCols({ ...OUTDOORS_VARIANTS[v].cols });
setIndoorMode('off'); setIndoorMode('off');
}} }}
/>`; />
<span class="profile-divider" aria-hidden="true"></span>`;
} }
return html` return html`
@@ -1261,6 +1284,15 @@ ${isPro && (activeProfile === 'custom' || FILTER_PROFILES[activeProfile].cols['a
const isNow = r.iso.slice(0, 13) === nowLocalISO; const isNow = r.iso.slice(0, 13) === nowLocalISO;
const delta = r.utci - r.Ta; const delta = r.utci - r.Ta;
const adjCat = utciCategory(r.utciAdj); const adjCat = utciCategory(r.utciAdj);
// Converts a band hex colour to rgba at the given alpha — used to
// tint the UTCI and UTCI+P cells directly from the band colour.
const hexToRgba = (hex, a) => {
const h = hex.replace('#', '');
const r = parseInt(h.slice(0,2),16);
const g = parseInt(h.slice(2,4),16);
const b = parseInt(h.slice(4,6),16);
return `rgba(${r},${g},${b},${a})`;
};
// Returns a very light background tint based on temperature value. // Returns a very light background tint based on temperature value.
// Cold → faint blue, cool → faint green, warm → faint amber, hot → faint red. // Cold → faint blue, cool → faint green, warm → faint amber, hot → faint red.
const tempBg = (t) => { const tempBg = (t) => {
@@ -1276,6 +1308,7 @@ ${isPro && (activeProfile === 'custom' || FILTER_PROFILES[activeProfile].cols['a
}; };
const scaleBg = (v, min, max, rgb, maxAlpha = 0.14) => { const scaleBg = (v, min, max, rgb, maxAlpha = 0.14) => {
if (v == null || isNaN(v)) return 'transparent'; if (v == null || isNaN(v)) return 'transparent';
if (v <= min) return 'transparent';
const x = Math.max(0, Math.min(1, (v - min) / (max - min))); const x = Math.max(0, Math.min(1, (v - min) / (max - min)));
const a = 0.035 + x * maxAlpha; const a = 0.035 + x * maxAlpha;
return `rgba(${rgb},${a.toFixed(3)})`; return `rgba(${rgb},${a.toFixed(3)})`;
@@ -1287,9 +1320,9 @@ ${isPro && (activeProfile === 'custom' || FILTER_PROFILES[activeProfile].cols['a
const a = 0.035 + x * 0.13; const a = 0.035 + x * 0.13;
return v > 0 ? `rgba(230,140,50,${a.toFixed(3)})` : `rgba(80,135,210,${a.toFixed(3)})`; return v > 0 ? `rgba(230,140,50,${a.toFixed(3)})` : `rgba(80,135,210,${a.toFixed(3)})`;
}; };
const burnBg = (mins) => { const burnBg = (mins, uv) => {
if (!isFinite(mins)) return 'transparent'; if (!isFinite(mins) || uv <= 0) return 'transparent';
if (mins >= 240) return 'rgba(110,180,110,0.07)'; if (mins >= 240) return 'transparent';
const x = Math.max(0, Math.min(1, (240 - mins) / 220)); const x = Math.max(0, Math.min(1, (240 - mins) / 220));
return `rgba(210,70,50,${(0.04 + x * 0.15).toFixed(3)})`; return `rgba(210,70,50,${(0.04 + x * 0.15).toFixed(3)})`;
}; };
@@ -1330,13 +1363,13 @@ ${isPro && (activeProfile === 'custom' || FILTER_PROFILES[activeProfile].cols['a
<span class="wind-dir-label" style=${{ fontFamily: 'JetBrains Mono, monospace', fontSize: '11px' }}>${r.compass.label}</span> <span class="wind-dir-label" style=${{ fontFamily: 'JetBrains Mono, monospace', fontSize: '11px' }}>${r.compass.label}</span>
</span> </span>
</td>`} </td>`}
${visibleCols.cloud && html`<td style=${{ background: scaleBg(r.cc, 0, 100, '110,130,150') }}> ${visibleCols.cloud && html`<td style=${{ background: scaleBg(r.cc, 0, 100, '110,130,150', 0.07) }}>
<span style=${{ display: 'inline-flex', alignItems: 'center', gap: '6px', verticalAlign: 'middle' }}> <span style=${{ display: 'inline-flex', alignItems: 'center', gap: '6px', verticalAlign: 'middle' }}>
<${CloudIcon} category=${r.cloudCat} elev=${r.elev} dt=${r.dt} size=${28} /> <${CloudIcon} category=${r.cloudCat} elev=${r.elev} dt=${r.dt} size=${28} />
<span>${Math.round(r.cc)}</span> <span>${Math.round(r.cc)}</span>
</span> </span>
</td>`} </td>`}
${visibleCols.sun && html`<td style=${{ background: scaleBg(Math.max(0, r.elev), 0, 70, '225,160,45') }}>${r.elev > 0 ? r.elev.toFixed(1) : ''}</td>`} ${visibleCols.sun && html`<td style=${{ background: scaleBg(r.elev > 0 ? r.elev : null, 0, 70, '225,160,45') }}>${r.elev > 0 ? r.elev.toFixed(1) : ''}</td>`}
${visibleCols.direct && html`<td style=${{ background: scaleBg(r.dir, 0, 850, '230,155,35') }}>${Math.round(r.dir)}</td>`} ${visibleCols.direct && html`<td style=${{ background: scaleBg(r.dir, 0, 850, '230,155,35') }}>${Math.round(r.dir)}</td>`}
${visibleCols.diffuse && html`<td style=${{ background: scaleBg(r.dif, 0, 450, '230,190,70') }}>${Math.round(r.dif)}</td>`} ${visibleCols.diffuse && html`<td style=${{ background: scaleBg(r.dif, 0, 450, '230,190,70') }}>${Math.round(r.dif)}</td>`}
${visibleCols.tmrt && html`<td style=${{ background: tempBg(r.Tmrt) }}>${r.Tmrt.toFixed(1)}</td>`} ${visibleCols.tmrt && html`<td style=${{ background: tempBg(r.Tmrt) }}>${r.Tmrt.toFixed(1)}</td>`}
@@ -1349,10 +1382,8 @@ ${isPro && (activeProfile === 'custom' || FILTER_PROFILES[activeProfile].cols['a
${delta > 0 ? '+' : ''}${delta.toFixed(1)} ${delta > 0 ? '+' : ''}${delta.toFixed(1)}
</td>`} </td>`}
${visibleCols.utci && html` ${visibleCols.utci && html`
<td style=${{ background: tempBg(r.utci) }}> <td style=${{ background: hexToRgba(cat.bg, 0.22), color: cat.fg === '#fff' ? cat.fg : '#2a1a08', fontWeight: 600 }}>
<span class="utci-cell" style=${{ background: cat.bg, color: cat.fg }}> ${r.utci.toFixed(1)}°
${r.utci.toFixed(1)}
</span>
</td>`} </td>`}
${visibleCols.uvA && html` ${visibleCols.uvA && html`
<td style=${{ color: r.uvA > 0 ? '#c8922a' : '#4a3218', background: scaleBg(r.uvA, 0, 8, '220,155,40') }}> <td style=${{ color: r.uvA > 0 ? '#c8922a' : '#4a3218', background: scaleBg(r.uvA, 0, 8, '220,155,40') }}>
@@ -1363,7 +1394,7 @@ ${isPro && (activeProfile === 'custom' || FILTER_PROFILES[activeProfile].cols['a
${r.uvB > 0 ? r.uvB.toFixed(2) : ''} ${r.uvB > 0 ? r.uvB.toFixed(2) : ''}
</td>`} </td>`}
${visibleCols.burn && html` ${visibleCols.burn && html`
<td style=${{ color: r.uv > 0 ? (burnMins < 30 ? '#c44a3a' : '#c8601a') : '#4a3218', background: burnBg(burnMins) }}> <td style=${{ color: r.uv > 0 ? (burnMins < 30 ? '#c44a3a' : '#c8601a') : '#4a3218', background: burnBg(burnMins, r.uv) }}>
${burnLabel(burnMins)} ${burnLabel(burnMins)}
</td>`} </td>`}
${visibleCols.vehicleT && html` ${visibleCols.vehicleT && html`
@@ -1388,10 +1419,8 @@ ${isPro && (activeProfile === 'custom' || FILTER_PROFILES[activeProfile].cols['a
</span> </span>
</td>`} </td>`}
${visibleCols.utciP && html` ${visibleCols.utciP && html`
<td style=${{ background: tempBg(r.utciAdj) }}> <td style=${{ background: hexToRgba(adjCat.bg, 0.55), color: adjCat.fg === '#fff' ? adjCat.fg : '#2a1a08', fontWeight: 700, fontSize: '16px' }}>
<span class="utci-cell utci-cell-hero" style=${{ background: adjCat.bg, color: adjCat.fg }}> ${r.utciAdj.toFixed(1)}°
${r.utciAdj.toFixed(1)}
</span>
</td>`} </td>`}
</tr>`; </tr>`;
})} })}
@@ -1463,6 +1492,16 @@ ${isPro && (activeProfile === 'custom' || FILTER_PROFILES[activeProfile].cols['a
<em>Reading the table.</em> A large positive Δ means your body is absorbing <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. 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. On clear sunny days this gap can exceed 10 °C even at modest air temperatures.
${isPro && html`
<div style=${{ marginTop: '10px', paddingTop: '10px', borderTop: '1px solid #d4c0a0' }}>
SunScope Extra is active.
<a href="https://billing.stripe.com/p/login/9B63cw7vl8k15Ei9DQd7q00"
target="_blank" rel="noopener noreferrer"
style=${{ color: '#9a7d5a', borderBottom: '1px solid rgba(154,125,90,0.4)', paddingBottom: '1px', textDecoration: 'none' }}>
Manage or cancel subscription
</a>
</div>
`}
</div> </div>
</main> </main>