5.1
Combine and relabel table view switch. Remove and re-arrange some table columns Group Pets together
This commit is contained in:
+28
-52
@@ -765,11 +765,13 @@
|
||||
.active-profile-row.grp-wind { border-color: rgba(106,34,16,0.30); }
|
||||
.active-profile-row.grp-ambient { border-color: rgba(60,58,53,0.30); }
|
||||
.active-profile-row.grp-surface { border-color: rgba(11,62,114,0.30); }
|
||||
.active-profile-row.grp-pets { border-color: rgba(10,81,88,0.30); }
|
||||
|
||||
.active-profile-row.grp-felt .active-profile-row-value { color: #075c3a; }
|
||||
.active-profile-row.grp-wind .active-profile-row-value { color: #6a2210; }
|
||||
.active-profile-row.grp-ambient .active-profile-row-value { color: #3c3a35; }
|
||||
.active-profile-row.grp-surface .active-profile-row-value { color: #0b3e72; }
|
||||
.active-profile-row.grp-pets .active-profile-row-value { color: #0a5158; }
|
||||
|
||||
/* Vertical rule separating general-use profiles from technical ones */
|
||||
.profile-divider {
|
||||
@@ -1085,6 +1087,7 @@
|
||||
|
||||
.col-toggle.grp-felt { background: rgba(223,243,236,0.50); color: #075c3a; border-color: rgba(7,92,58,0.35); }
|
||||
.col-toggle.grp-surface { background: rgba(221,234,248,0.50); color: #0b3e72; border-color: rgba(11,62,114,0.30); }
|
||||
.col-toggle.grp-pets { background: rgba(214,238,240,0.50); color: #0a5158; border-color: rgba(10,81,88,0.30); }
|
||||
.col-toggle.grp-ambient { background: rgba(236,234,227,0.50); color: #3c3a35; border-color: rgba(60,58,53,0.30); }
|
||||
.col-toggle.grp-precip { background: rgba(247,228,238,0.50); color: #6b1e3a; border-color: rgba(107,30,58,0.30); }
|
||||
.col-toggle.grp-sky { background: rgba(234,232,252,0.50); color: #352e7a; border-color: rgba(53,46,122,0.30); }
|
||||
@@ -1094,6 +1097,7 @@
|
||||
|
||||
.col-toggle.grp-felt:hover { background: rgba(213,233,226,0.80); color: #075c3a; border-color: rgba(7,92,58,0.55); }
|
||||
.col-toggle.grp-surface:hover { background: rgba(211,224,238,0.80); color: #0b3e72; border-color: rgba(11,62,114,0.50); }
|
||||
.col-toggle.grp-pets:hover { background: rgba(204,228,230,0.80); color: #0a5158; border-color: rgba(10,81,88,0.50); }
|
||||
.col-toggle.grp-ambient:hover { background: rgba(226,224,217,0.80); color: #3c3a35; border-color: rgba(60,58,53,0.50); }
|
||||
.col-toggle.grp-precip:hover { background: rgba(237,218,228,0.80); color: #6b1e3a; border-color: rgba(107,30,58,0.50); }
|
||||
.col-toggle.grp-sky:hover { background: rgba(224,222,242,0.80); color: #352e7a; border-color: rgba(53,46,122,0.50); }
|
||||
@@ -1103,6 +1107,7 @@
|
||||
|
||||
.col-toggle.grp-felt.on { background: #0f9e63; border-color: #0f9e63; color: #fff; }
|
||||
.col-toggle.grp-surface.on { background: #2672c8; border-color: #2672c8; color: #fff; }
|
||||
.col-toggle.grp-pets.on { background: #17868f; border-color: #17868f; color: #fff; }
|
||||
.col-toggle.grp-ambient.on { background: #7a7870; border-color: #7a7870; color: #fff; }
|
||||
.col-toggle.grp-precip.on { background: #b03060; border-color: #b03060; color: #fff; }
|
||||
.col-toggle.grp-sky.on { background: #6058c8; border-color: #6058c8; color: #fff; }
|
||||
@@ -1112,6 +1117,7 @@
|
||||
|
||||
.col-toggle.grp-felt.on:hover { background: #0c7d4e; border-color: #0c7d4e; color: #fff; }
|
||||
.col-toggle.grp-surface.on:hover { background: #1e5aa0; border-color: #1e5aa0; color: #fff; }
|
||||
.col-toggle.grp-pets.on:hover { background: #116b73; border-color: #116b73; color: #fff; }
|
||||
.col-toggle.grp-ambient.on:hover { background: #5e5c56; border-color: #5e5c56; color: #fff; }
|
||||
.col-toggle.grp-precip.on:hover { background: #8c264c; border-color: #8c264c; color: #fff; }
|
||||
.col-toggle.grp-sky.on:hover { background: #4c48a8; border-color: #4c48a8; color: #fff; }
|
||||
@@ -1816,6 +1822,7 @@
|
||||
|
||||
.utci-table th.grp-felt { background: rgba(223,243,236,0.50); color: #075c3a; }
|
||||
.utci-table th.grp-surface { background: rgba(221,234,248,0.50); color: #0b3e72; }
|
||||
.utci-table th.grp-pets { background: rgba(214,238,240,0.50); color: #0a5158; }
|
||||
.utci-table th.grp-ambient { background: rgba(236,234,227,0.50); color: #3c3a35; }
|
||||
.utci-table th.grp-precip { background: rgba(247,228,238,0.50); color: #6b1e3a; }
|
||||
.utci-table th.grp-sky { background: rgba(234,232,252,0.50); color: #352e7a; }
|
||||
@@ -1825,6 +1832,7 @@
|
||||
|
||||
.utci-table th.grp-felt.col-info-th:hover { background: rgba(213,233,226,0.80); }
|
||||
.utci-table th.grp-surface.col-info-th:hover { background: rgba(211,224,238,0.80); }
|
||||
.utci-table th.grp-pets.col-info-th:hover { background: rgba(204,228,230,0.80); }
|
||||
.utci-table th.grp-ambient.col-info-th:hover { background: rgba(226,224,217,0.80); }
|
||||
.utci-table th.grp-precip.col-info-th:hover { background: rgba(237,218,228,0.80); }
|
||||
.utci-table th.grp-sky.col-info-th:hover { background: rgba(224,222,242,0.80); }
|
||||
@@ -1834,6 +1842,7 @@
|
||||
|
||||
.utci-table th.grp-felt .col-unit { color: #0f9e63; }
|
||||
.utci-table th.grp-surface .col-unit { color: #2672c8; }
|
||||
.utci-table th.grp-pets .col-unit { color: #17868f; }
|
||||
.utci-table th.grp-ambient .col-unit { color: #7a7870; }
|
||||
.utci-table th.grp-precip .col-unit { color: #b03060; }
|
||||
.utci-table th.grp-sky .col-unit { color: #6058c8; }
|
||||
@@ -1859,6 +1868,7 @@
|
||||
|
||||
.utci-table .grp-label-row th.grp-felt { background: rgba(223,243,236,0.50); border-left: 2px solid rgba(74,50,24,0.18); border-bottom: 1px solid rgba(74,50,24,0.18);}
|
||||
.utci-table .grp-label-row th.grp-surface { background: rgba(221,234,248,0.50); border-left: 2px solid rgba(74,50,24,0.18); border-bottom: 1px solid rgba(74,50,24,0.18);}
|
||||
.utci-table .grp-label-row th.grp-pets { background: rgba(214,238,240,0.50); border-left: 2px solid rgba(74,50,24,0.18); border-bottom: 1px solid rgba(74,50,24,0.18);}
|
||||
.utci-table .grp-label-row th.grp-ambient { background: rgba(236,234,227,0.50); border-left: 2px solid rgba(74,50,24,0.18); border-bottom: 1px solid rgba(74,50,24,0.18);}
|
||||
.utci-table .grp-label-row th.grp-precip { background: rgba(247,228,238,0.50); border-left: 2px solid rgba(74,50,24,0.18); border-bottom: 1px solid rgba(74,50,24,0.18);}
|
||||
.utci-table .grp-label-row th.grp-sky { background: rgba(234,232,252,0.50); border-left: 2px solid rgba(74,50,24,0.18); border-bottom: 1px solid rgba(74,50,24,0.18);}
|
||||
@@ -2201,8 +2211,14 @@
|
||||
.fvt-btn:first-child {
|
||||
border-radius: 3px 0 0 3px;
|
||||
}
|
||||
.fvt-btn:last-child {
|
||||
/* Only the outer corners are rounded; every segment after the first drops
|
||||
its left border so neighbours share one 1.5px rule rather than stacking
|
||||
two. Keyed off the sibling rather than :last-child so it still holds with
|
||||
three segments (Quick / Detailed / Table). */
|
||||
.fvt-btn + .fvt-btn {
|
||||
border-left: none;
|
||||
}
|
||||
.fvt-btn:last-child {
|
||||
border-radius: 0 3px 3px 0;
|
||||
}
|
||||
.fvt-btn:hover {
|
||||
@@ -2650,6 +2666,7 @@
|
||||
two different backgrounds is what makes them drift apart. */
|
||||
.utci-table-rotated .grp-felt { --grp-tint: rgba(223,243,236,0.50); }
|
||||
.utci-table-rotated .grp-surface { --grp-tint: rgba(221,234,248,0.50); }
|
||||
.utci-table-rotated .grp-pets { --grp-tint: rgba(214,238,240,0.50); }
|
||||
.utci-table-rotated .grp-ambient { --grp-tint: rgba(236,234,227,0.50); }
|
||||
.utci-table-rotated .grp-precip { --grp-tint: rgba(247,228,238,0.50); }
|
||||
.utci-table-rotated .grp-sky { --grp-tint: rgba(234,232,252,0.50); }
|
||||
@@ -2734,11 +2751,11 @@
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
/* Icon-only on narrow screens — the toolbar is already tight. */
|
||||
.table-rotate-btn {
|
||||
font-size: 0;
|
||||
gap: 0;
|
||||
padding: 6px 7px;
|
||||
/* Tighter segments on narrow screens — the toolbar is already tight,
|
||||
and there are three of them now. */
|
||||
.fvt-btn {
|
||||
padding: 6px 6px;
|
||||
gap: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2769,58 +2786,17 @@
|
||||
}
|
||||
|
||||
/* ── TOOLBAR BUTTON HEIGHTS ───────────────────────────────────────────
|
||||
Quick/Detailed, Rotate and Edit columns sit on one row and have to
|
||||
agree on height. They didn't: the first two set line-height:1 while
|
||||
Edit columns leaves it at normal, so the same 6px padding produced a
|
||||
box ~3px taller. Pinning one line-height and one min-height across all
|
||||
three settles it regardless of font-size differences. */
|
||||
The view segments and Edit columns sit on one row and have to agree on
|
||||
height. They didn't: the segments set line-height:1 while Edit columns
|
||||
leaves it at normal, so the same 6px padding produced a box ~3px
|
||||
taller. Pinning one line-height and one min-height across both settles
|
||||
it regardless of font-size differences. */
|
||||
.fvt-btn,
|
||||
.table-rotate-btn,
|
||||
.col-toggles-edit-btn {
|
||||
min-height: 29px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
/* ── ROTATE BUTTON ────────────────────────────────────────────────────
|
||||
Sits beside the Quick/Detailed view toggle and only while the detailed
|
||||
table is showing. Deliberately mirrors .fvt-btn — same type, padding,
|
||||
border and states — so it reads as part of that control group rather
|
||||
than a stray button. Standalone, so it keeps a radius on all corners
|
||||
where .fvt-btn splits its radius across the segmented pair. */
|
||||
.table-rotate-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-family: Manrope, sans-serif;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
padding: 6px 8px;
|
||||
cursor: pointer;
|
||||
border: 1.5px solid #c9b08a;
|
||||
border-radius: 3px;
|
||||
background: #f5edd6;
|
||||
color: #6b4228;
|
||||
transition: background 0.12s, border-color 0.12s, color 0.12s;
|
||||
}
|
||||
.table-rotate-btn:hover {
|
||||
border-color: #c8922a;
|
||||
background: #fef3dc;
|
||||
}
|
||||
.table-rotate-btn.on {
|
||||
background: #c8922a;
|
||||
border-color: #c8922a;
|
||||
color: #fff;
|
||||
}
|
||||
/* The icon turns with the state it describes — flat when hours run down
|
||||
the side, quarter-turned when they run along the top. */
|
||||
.table-rotate-btn .fvt-btn-icon {
|
||||
transition: transform 0.18s ease;
|
||||
}
|
||||
.table-rotate-btn.on .fvt-btn-icon {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
/* ── MOBILE ───────────────────────────────────────────────────────── */
|
||||
@media (max-width: 640px) {
|
||||
.utci-rotated-scroll {
|
||||
|
||||
@@ -234,6 +234,7 @@
|
||||
|
||||
.cs-btn.grp-felt { background: rgba(223,243,236,0.50); color: #075c3a; border-color: rgba(7,92,58,0.35); }
|
||||
.cs-btn.grp-surface { background: rgba(221,234,248,0.50); color: #0b3e72; border-color: rgba(11,62,114,0.30); }
|
||||
.cs-btn.grp-pets { background: rgba(214,238,240,0.50); color: #0a5158; border-color: rgba(10,81,88,0.30); }
|
||||
.cs-btn.grp-ambient { background: rgba(236,234,227,0.50); color: #3c3a35; border-color: rgba(60,58,53,0.30); }
|
||||
.cs-btn.grp-precip { background: rgba(247,228,238,0.50); color: #6b1e3a; border-color: rgba(107,30,58,0.30); }
|
||||
.cs-btn.grp-sky { background: rgba(234,232,252,0.50); color: #352e7a; border-color: rgba(53,46,122,0.30); }
|
||||
@@ -243,6 +244,7 @@
|
||||
|
||||
.cs-btn.grp-felt:hover { background: rgba(213,233,226,0.80); color: #075c3a; border-color: rgba(7,92,58,0.55); }
|
||||
.cs-btn.grp-surface:hover { background: rgba(211,224,238,0.80); color: #0b3e72; border-color: rgba(11,62,114,0.50); }
|
||||
.cs-btn.grp-pets:hover { background: rgba(204,228,230,0.80); color: #0a5158; border-color: rgba(10,81,88,0.50); }
|
||||
.cs-btn.grp-ambient:hover { background: rgba(226,224,217,0.80); color: #3c3a35; border-color: rgba(60,58,53,0.50); }
|
||||
.cs-btn.grp-precip:hover { background: rgba(237,218,228,0.80); color: #6b1e3a; border-color: rgba(107,30,58,0.50); }
|
||||
.cs-btn.grp-sky:hover { background: rgba(224,222,242,0.80); color: #352e7a; border-color: rgba(53,46,122,0.50); }
|
||||
@@ -253,6 +255,7 @@
|
||||
/* Dropdown buttons - lighter palette to match toggle pills */
|
||||
.cs-btn.grp-felt.on { background: #2ab578; border-color: #2ab578; color: #fff; }
|
||||
.cs-btn.grp-surface.on { background: #4088d4; border-color: #4088d4; color: #fff; }
|
||||
.cs-btn.grp-pets.on { background: #34a0a8; border-color: #34a0a8; color: #fff; }
|
||||
.cs-btn.grp-ambient.on { background: #929088; border-color: #929088; color: #fff; }
|
||||
.cs-btn.grp-precip.on { background: #c24e6c; border-color: #c24e6c; color: #fff; }
|
||||
.cs-btn.grp-sky.on { background: #786ec8; border-color: #786ec8; color: #fff; }
|
||||
@@ -262,6 +265,7 @@
|
||||
|
||||
.cs-btn.grp-felt.on:hover { background: #1e9e64; border-color: #1e9e64; color: #fff; }
|
||||
.cs-btn.grp-surface.on:hover { background: #2e72bc; border-color: #2e72bc; color: #fff; }
|
||||
.cs-btn.grp-pets.on:hover { background: #17868f; border-color: #17868f; color: #fff; }
|
||||
.cs-btn.grp-ambient.on:hover { background: #7a7870; border-color: #7a7870; color: #fff; }
|
||||
.cs-btn.grp-precip.on:hover { background: #a83c5a; border-color: #a83c5a; color: #fff; }
|
||||
.cs-btn.grp-sky.on:hover { background: #6258b0; border-color: #6258b0; color: #fff; }
|
||||
@@ -272,6 +276,7 @@
|
||||
/* Toggle pills - lighter palette */
|
||||
.col-toggle.grp-felt.on { background: #2ab578; border-color: #2ab578; color: #fff; }
|
||||
.col-toggle.grp-surface.on { background: #4088d4; border-color: #4088d4; color: #fff; }
|
||||
.col-toggle.grp-pets.on { background: #34a0a8; border-color: #34a0a8; color: #fff; }
|
||||
.col-toggle.grp-ambient.on { background: #929088; border-color: #929088; color: #fff; }
|
||||
.col-toggle.grp-precip.on { background: #c24e6c; border-color: #c24e6c; color: #fff; }
|
||||
.col-toggle.grp-sky.on { background: #786ec8; border-color: #786ec8; color: #fff; }
|
||||
@@ -281,6 +286,7 @@
|
||||
|
||||
.col-toggle.grp-felt.on:hover { background: #1e9e64; border-color: #1e9e64; color: #fff; }
|
||||
.col-toggle.grp-surface.on:hover { background: #2e72bc; border-color: #2e72bc; color: #fff; }
|
||||
.col-toggle.grp-pets.on:hover { background: #17868f; border-color: #17868f; color: #fff; }
|
||||
.col-toggle.grp-ambient.on:hover { background: #7a7870; border-color: #7a7870; color: #fff; }
|
||||
.col-toggle.grp-precip.on:hover { background: #a83c5a; border-color: #a83c5a; color: #fff; }
|
||||
.col-toggle.grp-sky.on:hover { background: #6258b0; border-color: #6258b0; color: #fff; }
|
||||
|
||||
+31
-31
@@ -233,7 +233,7 @@ export function UTCIForecast() {
|
||||
indoorMode, setIndoorMode,
|
||||
pollenType, setPollenTypeAndSave,
|
||||
utciEnv, setUtciEnv,
|
||||
tableRotated, toggleTableRotated,
|
||||
tableRotated, setTableRotated,
|
||||
headStickyRef, headTrackRef, headTableRef,
|
||||
bodyScrollRef, bodyTableRef, tableWrapRef,
|
||||
colPopup, colPopupRef,
|
||||
@@ -430,10 +430,11 @@ export function UTCIForecast() {
|
||||
// Columns that mark the start of a logical group - used to draw a faint
|
||||
// vertical border separating groups in the forecast table.
|
||||
const GROUP_ORDER = {
|
||||
felt: ['utciP', 'shadeT', 'vehicleT', 'indoorT', 'managedT', 'burn', 'utci', 'delta', 'tmrt'],
|
||||
surface: ['concreteT', 'soilT', 'soilT6', 'soilM', 'furSurfaceT', 'pawT'],
|
||||
ambient: ['petShadeT', 'petHomeT', 'air', 'rh', 'dew'],
|
||||
precip: ['precip', 'precipProb', 'lightning'],
|
||||
felt: ['utciP', 'shadeT', 'vehicleT', 'indoorT', 'managedT', 'utci', 'burn'],
|
||||
surface: ['concreteT', 'soilT', 'soilT6', 'soilM'],
|
||||
pets: ['furSurfaceT', 'pawT', 'petShadeT', 'petHomeT'],
|
||||
ambient: ['air', 'rh', 'dew'],
|
||||
precip: ['precip', 'precipProb'],
|
||||
sky: ['cloud', 'vis'],
|
||||
wind: ['wind', 'dir'],
|
||||
airqual: ['aqi', 'pollen'],
|
||||
@@ -464,7 +465,7 @@ export function UTCIForecast() {
|
||||
};
|
||||
// Display names for the column groups — used for the spanning labels
|
||||
// above the columns normally, and for the divider rows when rotated.
|
||||
const GROUP_LABELS = { felt: 'Felt', surface: 'Surface', ambient: 'Ambient', precip: 'Precip', sky: 'Sky', wind: 'Wind', airqual: 'Air quality', solar: 'Solar' };
|
||||
const GROUP_LABELS = { felt: 'Felt', surface: 'Surface', pets: 'Pets', ambient: 'Ambient', precip: 'Precip', sky: 'Sky', wind: 'Wind', airqual: 'Air quality', solar: 'Solar' };
|
||||
// Builds the group label row above the column headers.
|
||||
// Each visible group gets one spanning cell; groups with no visible
|
||||
// columns are skipped entirely. Hour always gets a blank lead cell.
|
||||
@@ -1168,30 +1169,32 @@ export function UTCIForecast() {
|
||||
<div class="table-toolbar-row">
|
||||
<span class="fvt-toolbar-left">
|
||||
<span class="forecast-view-toggle-label">View:</span>
|
||||
${/* One three-way control. Quick is the card layout; the other
|
||||
two are the same hourly table on opposite axes — Detailed
|
||||
runs hours along the top, Table runs them down the side.
|
||||
Rotation used to be a separate toggle that only appeared
|
||||
once you were already in the table, which hid the layout
|
||||
people wanted behind a mode they had to find first. */''}
|
||||
<span class="forecast-view-toggle">
|
||||
<button type="button" title="Quick view – visual card layout" class=${'fvt-btn' + (forecastView === 'simple' ? ' on' : '')} onClick=${() => setForecastView('simple')}>
|
||||
<button type="button" title="Quick view – visual card layout" class=${'fvt-btn' + (forecastView === 'simple' ? ' on' : '')}
|
||||
aria-pressed=${forecastView === 'simple' ? 'true' : 'false'}
|
||||
onClick=${() => setForecastView('simple')}>
|
||||
<svg class="fvt-btn-icon" viewBox="0 0 12 12" width="12" height="12"><rect x=".5" y=".5" width="4.5" height="4.5" rx=".8" fill="currentColor"/><rect x="7" y=".5" width="4.5" height="4.5" rx=".8" fill="currentColor"/><rect x=".5" y="7" width="4.5" height="4.5" rx=".8" fill="currentColor"/><rect x="7" y="7" width="4.5" height="4.5" rx=".8" fill="currentColor"/></svg>
|
||||
Quick
|
||||
</button>
|
||||
<button type="button" title="Detailed view – full hourly table" class=${'fvt-btn' + (forecastView === 'table' ? ' on' : '')} onClick=${() => setForecastView('table')}>
|
||||
<svg class="fvt-btn-icon" viewBox="0 0 12 12" width="12" height="12"><rect x=".5" y="1.5" width="11" height="3" rx=".6" fill="currentColor"/><rect x=".5" y="5.5" width="11" height="2.5" rx=".5" fill="currentColor" opacity=".35"/><rect x=".5" y="8.8" width="11" height="2.5" rx=".5" fill="currentColor" opacity=".25"/></svg>
|
||||
<button type="button" title="Detailed view – hours along the top, metrics down the side" class=${'fvt-btn' + (forecastView === 'table' && tableRotated ? ' on' : '')}
|
||||
aria-pressed=${forecastView === 'table' && tableRotated ? 'true' : 'false'}
|
||||
onClick=${() => { setForecastView('table'); setTableRotated(true); }}>
|
||||
<svg class="fvt-btn-icon" viewBox="0 0 12 12" width="12" height="12" aria-hidden="true"><rect x=".5" y="1.5" width="3" height="10" rx=".6" fill="currentColor"/><rect x="4.5" y="1.5" width="2.5" height="10" rx=".5" fill="currentColor" opacity=".35"/><rect x="8" y="1.5" width="2.5" height="10" rx=".5" fill="currentColor" opacity=".25"/></svg>
|
||||
Detailed
|
||||
</button>
|
||||
<button type="button" title="Table view – hours down the side, metrics along the top" class=${'fvt-btn' + (forecastView === 'table' && !tableRotated ? ' on' : '')}
|
||||
aria-pressed=${forecastView === 'table' && !tableRotated ? 'true' : 'false'}
|
||||
onClick=${() => { setForecastView('table'); setTableRotated(false); }}>
|
||||
<svg class="fvt-btn-icon" viewBox="0 0 12 12" width="12" height="12"><rect x=".5" y="1.5" width="11" height="3" rx=".6" fill="currentColor"/><rect x=".5" y="5.5" width="11" height="2.5" rx=".5" fill="currentColor" opacity=".35"/><rect x=".5" y="8.8" width="11" height="2.5" rx=".5" fill="currentColor" opacity=".25"/></svg>
|
||||
Table
|
||||
</button>
|
||||
</span>
|
||||
${forecastView === 'table' && html`
|
||||
<button type="button"
|
||||
class=${'table-rotate-btn' + (tableRotated ? ' on' : '')}
|
||||
title=${tableRotated ? 'Hours run along the top — click for hours down the side' : 'Hours run down the side — click for hours along the top'}
|
||||
aria-pressed=${tableRotated ? 'true' : 'false'}
|
||||
onClick=${toggleTableRotated}>
|
||||
<svg class="fvt-btn-icon" viewBox="0 0 12 12" width="12" height="12" aria-hidden="true">
|
||||
<path d="M2.4 6.6a3.7 3.7 0 0 1 6-3.2" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<path d="M9.6 5.4a3.7 3.7 0 0 1-6 3.2" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<path d="M6.3 1.1l2.4 2.2-2.4 1.8" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M5.7 10.9L3.3 8.7l2.4-1.8" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
Rotate
|
||||
</button>`}
|
||||
<button
|
||||
class=${'col-toggles-edit-btn col-toggles-edit-btn--toolbar' + (colTogglesOpen ? ' col-toggles-edit-btn--open' : '') + (isPro ? '' : ' col-toggles-edit-btn--locked')}
|
||||
title=${isPro ? '' : 'Custom columns are part of SunScope Extra'}
|
||||
@@ -1242,25 +1245,22 @@ export function UTCIForecast() {
|
||||
${colOffered('utciP') && html`<button class=${`col-toggle grp-felt${visibleCols.utciP ? ' on' : ''}`} onClick=${() => toggleCol('utciP')}>SunSoak</button>`}
|
||||
${colOffered('vehicleT') && html`<button class=${`col-toggle grp-felt${visibleCols.vehicleT ? ' on' : ''}`} onClick=${() => { if (visibleCols.vehicleT) setVehicleVent(false); toggleCol('vehicleT'); }}>Vehicle</button>`}
|
||||
${(colOffered('indoorT') || colOffered('managedT')) && html`<button class=${`col-toggle grp-felt${indoorMode === 'on' ? ' on' : ''}`} onClick=${() => { if (indoorMode === 'on') { setIndoorMode('off'); setIndoorManaged(false); } else { setIndoorMode('on'); } }}>Indoors</button>`}
|
||||
${colOffered('furSurfaceT') && html`<button class=${`col-toggle grp-surface${visibleCols.furSurfaceT ? ' on' : ''}`} onClick=${() => toggleCol('furSurfaceT')}>Fur</button>`}
|
||||
${colOffered('pawT') && html`<button class=${`col-toggle grp-surface${visibleCols.pawT ? ' on' : ''}`} onClick=${() => toggleCol('pawT')}>Paw</button>`}
|
||||
${colOffered('petShadeT') && html`<button class=${`col-toggle grp-ambient${visibleCols.petShadeT ? ' on' : ''}`} onClick=${() => toggleCol('petShadeT')}>Pet Shade</button>`}
|
||||
${colOffered('petHomeT') && html`<button class=${`col-toggle grp-ambient${visibleCols.petHomeT ? ' on' : ''}`} onClick=${() => toggleCol('petHomeT')}>Pet Home</button>`}
|
||||
${colOffered('burn') && html`<button class=${`col-toggle grp-felt${visibleCols.burn ? ' on' : ''}`} onClick=${() => toggleCol('burn')}>Burn</button>`}
|
||||
${colOffered('utci') && html`<button class=${`col-toggle grp-felt${visibleCols.utci ? ' on' : ''}`} onClick=${() => toggleCol('utci')}>UTCI</button>`}
|
||||
${colOffered('delta') && html`<button class=${`col-toggle grp-felt${visibleCols.delta ? ' on' : ''}`} onClick=${() => toggleCol('delta')}>Δ</button>`}
|
||||
${colOffered('tmrt') && html`<button class=${`col-toggle grp-felt${visibleCols.tmrt ? ' on' : ''}`} onClick=${() => toggleCol('tmrt')}>Tmrt</button>`}
|
||||
${colOffered('burn') && html`<button class=${`col-toggle grp-felt${visibleCols.burn ? ' on' : ''}`} onClick=${() => toggleCol('burn')}>Burn</button>`}
|
||||
${colOffered('concreteT') && html`<button class=${`col-toggle grp-surface${visibleCols.concreteT ? ' on' : ''}`} onClick=${() => toggleCol('concreteT')}>Concrete</button>`}
|
||||
${colOffered('soilT') && html`<button class=${`col-toggle grp-surface${visibleCols.soilT ? ' on' : ''}`} onClick=${() => toggleCol('soilT')}>Soil °C</button>`}
|
||||
${colOffered('soilT6') && html`<button class=${`col-toggle grp-surface${visibleCols.soilT6 ? ' on' : ''}`} onClick=${() => toggleCol('soilT6')}>Soil 6cm</button>`}
|
||||
${colOffered('soilM') && html`<button class=${`col-toggle grp-surface${visibleCols.soilM ? ' on' : ''}`} onClick=${() => toggleCol('soilM')}>Soil moist</button>`}
|
||||
${colOffered('furSurfaceT') && html`<button class=${`col-toggle grp-pets${visibleCols.furSurfaceT ? ' on' : ''}`} onClick=${() => toggleCol('furSurfaceT')}>Fur</button>`}
|
||||
${colOffered('pawT') && html`<button class=${`col-toggle grp-pets${visibleCols.pawT ? ' on' : ''}`} onClick=${() => toggleCol('pawT')}>Paw</button>`}
|
||||
${colOffered('petShadeT') && html`<button class=${`col-toggle grp-pets${visibleCols.petShadeT ? ' on' : ''}`} onClick=${() => toggleCol('petShadeT')}>Pet Shade</button>`}
|
||||
${colOffered('petHomeT') && html`<button class=${`col-toggle grp-pets${visibleCols.petHomeT ? ' on' : ''}`} onClick=${() => toggleCol('petHomeT')}>Pet Home</button>`}
|
||||
${colOffered('shadeT') && html`<button class=${`col-toggle grp-ambient${visibleCols.shadeT ? ' on' : ''}`} onClick=${() => toggleCol('shadeT')}>Shade</button>`}
|
||||
${colOffered('air') && html`<button class=${`col-toggle grp-ambient${visibleCols.air ? ' on' : ''}`} onClick=${() => toggleCol('air')}>Air</button>`}
|
||||
${colOffered('rh') && html`<button class=${`col-toggle grp-ambient${visibleCols.rh ? ' on' : ''}`} onClick=${() => toggleCol('rh')}>RH</button>`}
|
||||
${colOffered('dew') && html`<button class=${`col-toggle grp-ambient${visibleCols.dew ? ' on' : ''}`} onClick=${() => toggleCol('dew')}>Dew</button>`}
|
||||
${colOffered('precip') && html`<button class=${`col-toggle grp-precip${visibleCols.precip ? ' on' : ''}`} onClick=${() => toggleCol('precip')}>Precip</button>`}
|
||||
${colOffered('precipProb') && html`<button class=${`col-toggle grp-precip${visibleCols.precipProb ? ' on' : ''}`} onClick=${() => toggleCol('precipProb')}>Rain%</button>`}
|
||||
${colOffered('lightning') && html`<button class=${`col-toggle grp-precip${visibleCols.lightning ? ' on' : ''}`} onClick=${() => toggleCol('lightning')}>Lightning</button>`}
|
||||
${colOffered('cloud') && html`<button class=${`col-toggle grp-sky${visibleCols.cloud ? ' on' : ''}`} onClick=${() => toggleCol('cloud')}>Cloud</button>`}
|
||||
${colOffered('vis') && html`<button class=${`col-toggle grp-sky${visibleCols.vis ? ' on' : ''}`} onClick=${() => toggleCol('vis')}>Visibility</button>`}
|
||||
${colOffered('wind') && html`<button class=${`col-toggle grp-wind${visibleCols.wind ? ' on' : ''}`} onClick=${() => toggleCol('wind')}>Wind</button>`}
|
||||
|
||||
@@ -224,7 +224,7 @@ export function ConfigPanel({
|
||||
{ key: 'fur', show: showFur, node: html`
|
||||
<span class="config-item-label">Fur Colour</span>
|
||||
<${CustomSelect}
|
||||
value=${furColor} isOn=${true} noHide=${true} grpClass="grp-surface"
|
||||
value=${furColor} isOn=${true} noHide=${true} grpClass="grp-pets"
|
||||
hideLabel="Fur Colour"
|
||||
options=${Object.entries(FUR_COLORS).map(([k, v]) => ({ value: k, label: v.name }))}
|
||||
onChange=${(v) => setFurColor(v)}
|
||||
|
||||
@@ -155,7 +155,7 @@ export function DayTabs({
|
||||
// those controls rather than a separate, unrelated style.
|
||||
const rowGrpClass = mainConfigKey === 'vehicle' ? 'grp-wind'
|
||||
: mainConfigKey === 'indoor' ? 'grp-ambient'
|
||||
: mainConfigKey === 'fur' ? 'grp-surface'
|
||||
: mainConfigKey === 'fur' ? 'grp-pets'
|
||||
: 'grp-felt';
|
||||
|
||||
// Within that group, shade further by the exact option chosen — same idea
|
||||
|
||||
+31
-34
@@ -32,25 +32,25 @@ export const FILTER_PROFILES = {
|
||||
// Basic is the "just tell me" preset - it opens in Quick view (see `view`
|
||||
// below) with the smallest useful column set behind it.
|
||||
view: 'simple',
|
||||
cols: { hour: true, air: false, shadeT: true, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: false, uvB: false, burn: false, utciP: true, precip: true, precipProb: false, lightning: false, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: false, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false },
|
||||
cols: { hour: true, air: false, shadeT: true, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, utci: false, uvA: false, uvB: false, burn: false, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: false, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false },
|
||||
},
|
||||
home: {
|
||||
label: 'Home',
|
||||
icon: '🏠',
|
||||
scene: "url('assets/images/profiles/home.png') center / cover no-repeat, linear-gradient(160deg,#b0d890,#d0ecb8)",
|
||||
cols: { hour: true, air: true, shadeT: false, rh: true, dew: true, 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: false, precip: true, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: true, managedT: true, vis: false, aqi: true, pollen: true, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false },
|
||||
cols: { hour: true, air: true, shadeT: false, rh: true, dew: true, wind: true, dir: false, cloud: true, sun: false, direct: false, diffuse: false, utci: false, uvA: false, uvB: false, burn: false, utciP: false, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: true, managedT: true, vis: false, aqi: true, pollen: true, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false },
|
||||
},
|
||||
vehicle: {
|
||||
label: 'Vehicle',
|
||||
icon: '🚗',
|
||||
scene: "url('assets/images/profiles/vehicle.png') center / cover no-repeat, linear-gradient(160deg,#a8bcc8,#ccd8e4)",
|
||||
cols: { hour: true, air: true, shadeT: false, 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, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: true, concreteT: false, vehicleT: true, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false },
|
||||
cols: { hour: true, air: true, shadeT: false, rh: false, dew: false, wind: true, dir: false, cloud: true, sun: false, direct: false, diffuse: false, utci: false, uvA: false, uvB: false, burn: false, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: true, concreteT: false, vehicleT: true, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false },
|
||||
},
|
||||
pets: {
|
||||
label: 'Pets',
|
||||
icon: '🐾',
|
||||
scene: "url('assets/images/profiles/pets.png') center / cover no-repeat, linear-gradient(160deg,#e0c0a0,#f0ddc8)",
|
||||
cols: { hour: true, air: true, shadeT: false, 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: false, precip: true, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: true, indoorT: false, managedT: false, vis: false, aqi: true, pollen: true, furSurfaceT: true, pawT: true, petShadeT: true, petHomeT: true },
|
||||
cols: { hour: true, air: true, shadeT: false, rh: false, dew: false, wind: true, dir: false, cloud: true, sun: false, direct: false, diffuse: false, utci: false, uvA: false, uvB: false, burn: false, utciP: false, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: true, indoorT: false, managedT: false, vis: false, aqi: true, pollen: true, furSurfaceT: true, pawT: true, petShadeT: true, petHomeT: true },
|
||||
},
|
||||
farming: {
|
||||
label: 'Farming',
|
||||
@@ -59,7 +59,7 @@ export const FILTER_PROFILES = {
|
||||
// Farming sits in the Work menu alongside the outdoors variants, so it
|
||||
// opens the detailed table the same way they do.
|
||||
view: 'table',
|
||||
cols: { hour: true, air: true, shadeT: true, rh: true, dew: true, wind: true, dir: true, cloud: true, sun: true, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: false, uvB: false, burn: false, utciP: true, precip: true, precipProb: true, lightning: true, soilT: true, soilT6: true, soilM: true, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: false, aqi: true, pollen: true, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false },
|
||||
cols: { hour: true, air: true, shadeT: true, rh: true, dew: true, wind: true, dir: true, cloud: true, sun: true, direct: false, diffuse: false, utci: false, uvA: false, uvB: false, burn: false, utciP: true, precip: true, precipProb: true, soilT: true, soilT6: true, soilM: true, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: false, aqi: true, pollen: true, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false },
|
||||
},
|
||||
outdoors: {
|
||||
label: 'Places',
|
||||
@@ -67,21 +67,21 @@ export const FILTER_PROFILES = {
|
||||
scene: "url('assets/images/profiles/places.png') center / cover no-repeat, linear-gradient(160deg,#98ccc0,#c4e4dc)",
|
||||
view: 'table',
|
||||
// Default cols match the first variant (urban). Switching variant updates visibleCols.
|
||||
cols: { hour: true, air: true, shadeT: 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, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: true, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: true, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false },
|
||||
cols: { hour: true, air: true, shadeT: true, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, utci: false, uvA: true, uvB: false, burn: true, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: true, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: true, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false },
|
||||
},
|
||||
alltemps: {
|
||||
label: 'Temps',
|
||||
icon: '🌡️',
|
||||
scene: "url('assets/images/profiles/temps.png') center / cover no-repeat, linear-gradient(160deg,#d8b0b0,#ecd0c8)",
|
||||
proOnly: true,
|
||||
cols: { hour: true, air: true, shadeT: true, rh: false, dew: false, wind: false, dir: false, cloud: false, sun: false, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: false, uvB: false, burn: false, utciP: true, precip: false, precipProb: false, lightning: false, soilT: true, soilT6: false, soilM: false, concreteT: true, vehicleT: true, indoorT: true, managedT: true, vis: false, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false },
|
||||
cols: { hour: true, air: true, shadeT: true, rh: false, dew: false, wind: false, dir: false, cloud: false, sun: false, direct: false, diffuse: false, utci: false, uvA: false, uvB: false, burn: false, utciP: true, precip: false, precipProb: false, soilT: true, soilT6: false, soilM: false, concreteT: true, vehicleT: true, indoorT: true, managedT: true, vis: false, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false },
|
||||
},
|
||||
showall: {
|
||||
label: 'Show All',
|
||||
icon: '⚙️',
|
||||
scene: "url('assets/images/profiles/all.png') center / cover no-repeat, linear-gradient(160deg,#b4b4d4,#d4d4ec)",
|
||||
proOnly: true,
|
||||
cols: { hour: true, air: true, shadeT: true, rh: true, dew: true, wind: true, dir: true, cloud: true, sun: true, direct: true, diffuse: true, tmrt: true, delta: true, utci: true, uvA: true, uvB: true, burn: true, utciP: true, precip: true, precipProb: true, lightning: true, soilT: true, soilT6: true, soilM: true, concreteT: true, vehicleT: true, indoorT: true, managedT: true, vis: true, aqi: true, pollen: true, furSurfaceT: true, pawT: true, petShadeT: true, petHomeT: true },
|
||||
cols: { hour: true, air: true, shadeT: true, rh: true, dew: true, wind: true, dir: true, cloud: true, sun: true, direct: true, diffuse: true, utci: true, uvA: true, uvB: true, burn: true, utciP: true, precip: true, precipProb: true, soilT: true, soilT6: true, soilM: true, concreteT: true, vehicleT: true, indoorT: true, managedT: true, vis: true, aqi: true, pollen: true, furSurfaceT: true, pawT: true, petShadeT: true, petHomeT: true },
|
||||
},
|
||||
custom: {
|
||||
label: 'Custom',
|
||||
@@ -89,39 +89,39 @@ export const FILTER_PROFILES = {
|
||||
scene: "url('assets/images/profiles/custom.png') center / cover no-repeat, linear-gradient(160deg,#d8b0cc,#ecd0e4)",
|
||||
proOnly: true,
|
||||
// Blank slate - only Hour is on. User enables whichever columns they want.
|
||||
cols: { hour: true, air: false, shadeT: false, rh: false, dew: false, wind: false, dir: false, cloud: false, sun: false, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: false, uvB: false, burn: false, utciP: false, precip: false, precipProb: false, lightning: false, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: false, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false },
|
||||
cols: { hour: true, air: false, shadeT: false, rh: false, dew: false, wind: false, dir: false, cloud: false, sun: false, direct: false, diffuse: false, utci: false, uvA: false, uvB: false, burn: false, utciP: false, precip: false, precipProb: false, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: false, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false },
|
||||
},
|
||||
};
|
||||
|
||||
// Places sub-variants - each has its own column set.
|
||||
// Selecting a variant applies its cols to visibleCols.
|
||||
export const OUTDOORS_VARIANTS = {
|
||||
urban: { name: 'Urban', scene: "url('assets/images/profiles/urban.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: 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, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: true, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: true, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
beach: { name: 'Beach', scene: "url('assets/images/profiles/beach.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: 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: true, burn: true, utciP: true, precip: true, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
events: { name: 'Events', scene: "url('assets/images/profiles/events.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: 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, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: true, vehicleT: false, indoorT: false, managedT: false, vis: false, aqi: false, pollen: true } },
|
||||
festival: { name: 'Festival', scene: "url('assets/images/profiles/festival.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: 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, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: true, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: false, aqi: true, pollen: true } },
|
||||
wintersports: { name: 'Winter Sports', proOnly: true, scene: "url('assets/images/profiles/winter.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, 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, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
naturist: { name: 'Naturist', proOnly: true, scene: "url('assets/images/profiles/naturist.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: 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, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: false, aqi: true, pollen: true } },
|
||||
sailing: { name: 'Sailing', proOnly: true, scene: "url('assets/images/profiles/sailing.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, 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, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
urban: { name: 'Urban', scene: "url('assets/images/profiles/urban.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: true, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, utci: false, uvA: true, uvB: false, burn: true, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: true, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: true, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
beach: { name: 'Beach', scene: "url('assets/images/profiles/beach.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: true, rh: false, dew: true, wind: true, dir: true, cloud: true, sun: true, direct: false, diffuse: false, utci: false, uvA: true, uvB: true, burn: true, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
events: { name: 'Events', scene: "url('assets/images/profiles/events.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: true, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, utci: false, uvA: true, uvB: false, burn: true, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: true, vehicleT: false, indoorT: false, managedT: false, vis: false, aqi: false, pollen: true } },
|
||||
festival: { name: 'Festival', scene: "url('assets/images/profiles/festival.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: true, rh: false, dew: true, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, utci: false, uvA: true, uvB: false, burn: true, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: true, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: false, aqi: true, pollen: true } },
|
||||
wintersports: { name: 'Winter Sports', proOnly: true, scene: "url('assets/images/profiles/winter.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: true, direct: false, diffuse: false, utci: false, uvA: true, uvB: true, burn: true, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
naturist: { name: 'Naturist', proOnly: true, scene: "url('assets/images/profiles/naturist.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: true, rh: false, dew: true, wind: true, dir: false, cloud: true, sun: true, direct: false, diffuse: false, utci: true, uvA: true, uvB: true, burn: true, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: false, aqi: true, pollen: true } },
|
||||
sailing: { name: 'Sailing', proOnly: true, scene: "url('assets/images/profiles/sailing.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, rh: false, dew: true, wind: true, dir: true, cloud: true, sun: true, direct: false, diffuse: false, utci: false, uvA: true, uvB: false, burn: true, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
// Places - free
|
||||
park: { name: 'Park / Picnic', scene: "url('assets/images/profiles/park.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: 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: true, utciP: true, precip: true, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: false, aqi: false, pollen: true } },
|
||||
forest: { name: 'Forest / Woodland', scene: "url('assets/images/profiles/forest.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, 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: true, utciP: true, precip: true, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: true, pollen: true } },
|
||||
airport: { name: 'Airport / Travel', scene: "url('assets/images/profiles/airport.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: false, uvB: false, burn: false, utciP: false, precip: true, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
park: { name: 'Park / Picnic', scene: "url('assets/images/profiles/park.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: true, rh: false, dew: false, wind: true, dir: false, cloud: true, sun: false, direct: false, diffuse: false, utci: false, uvA: false, uvB: false, burn: true, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: false, aqi: false, pollen: true } },
|
||||
forest: { name: 'Forest / Woodland', scene: "url('assets/images/profiles/forest.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, rh: false, dew: false, wind: true, dir: false, cloud: true, sun: false, direct: false, diffuse: false, utci: false, uvA: false, uvB: false, burn: true, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: true, pollen: true } },
|
||||
airport: { name: 'Airport / Travel', scene: "url('assets/images/profiles/airport.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, utci: false, uvA: false, uvB: false, burn: false, utciP: false, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
// Places - Pro
|
||||
construction: { name: 'Construction', proOnly: true, scene: "url('assets/images/profiles/construction.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: true, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, tmrt: false, delta: false, utci: true, uvA: false, uvB: false, burn: false, utciP: true, precip: true, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: true, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
construction: { name: 'Construction', proOnly: true, scene: "url('assets/images/profiles/construction.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: true, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, utci: true, uvA: false, uvB: false, burn: false, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: true, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
// Activities - free
|
||||
cycling: { name: 'Cycling', scene: "url('assets/images/profiles/cycling.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: false, uvB: false, burn: true, utciP: true, precip: true, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
running: { name: 'Running', scene: "url('assets/images/profiles/running.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, rh: true, dew: false, wind: true, dir: false, cloud: true, sun: false, direct: false, diffuse: false, tmrt: false, delta: false, utci: true, uvA: false, uvB: false, burn: true, utciP: true, precip: true, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: false, aqi: false, pollen: true } },
|
||||
dogwalk: { name: 'Dog Walking', scene: "url('assets/images/profiles/walking.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, 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, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: false, aqi: false, pollen: true } },
|
||||
cycling: { name: 'Cycling', scene: "url('assets/images/profiles/cycling.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, utci: false, uvA: false, uvB: false, burn: true, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
running: { name: 'Running', scene: "url('assets/images/profiles/running.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, rh: true, dew: false, wind: true, dir: false, cloud: true, sun: false, direct: false, diffuse: false, utci: true, uvA: false, uvB: false, burn: true, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: false, aqi: false, pollen: true } },
|
||||
dogwalk: { name: 'Dog Walking', scene: "url('assets/images/profiles/walking.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, rh: false, dew: false, wind: true, dir: false, cloud: true, sun: false, direct: false, diffuse: false, utci: false, uvA: false, uvB: false, burn: false, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: false, aqi: false, pollen: true } },
|
||||
// Activities - Pro
|
||||
hiking: { name: 'Hiking', proOnly: true, scene: "url('assets/images/profiles/hiking.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: true, direct: false, diffuse: false, tmrt: false, delta: false, utci: true, uvA: true, uvB: true, burn: true, utciP: true, precip: true, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
photography: { name: 'Photography', proOnly: true, scene: "url('assets/images/profiles/photography.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: true, rh: false, dew: false, wind: false, dir: false, cloud: true, sun: true, direct: true, diffuse: true, tmrt: false, delta: false, utci: false, uvA: false, uvB: false, burn: false, utciP: false, precip: true, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
fishing: { name: 'Fishing', proOnly: true, scene: "url('assets/images/profiles/fishing.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: true, rh: false, dew: true, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: false, uvB: false, burn: false, utciP: true, precip: true, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
hiking: { name: 'Hiking', proOnly: true, scene: "url('assets/images/profiles/hiking.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: true, direct: false, diffuse: false, utci: true, uvA: true, uvB: true, burn: true, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
photography: { name: 'Photography', proOnly: true, scene: "url('assets/images/profiles/photography.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: true, rh: false, dew: false, wind: false, dir: false, cloud: true, sun: true, direct: true, diffuse: true, utci: false, uvA: false, uvB: false, burn: false, utciP: false, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
fishing: { name: 'Fishing', proOnly: true, scene: "url('assets/images/profiles/fishing.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: true, rh: false, dew: true, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, utci: false, uvA: false, uvB: false, burn: false, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
// Work variants
|
||||
market: { name: 'Market Trading', proOnly: true, scene: "url('assets/images/profiles/market.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: true, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: false, uvB: false, burn: false, utciP: true, precip: true, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
windowcleaning: { name: 'Window Cleaning', proOnly: true, scene: "url('assets/images/profiles/window.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, tmrt: false, delta: false, utci: false, uvA: false, uvB: false, burn: false, utciP: true, precip: true, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
office: { name: 'Office', proOnly: true, scene: "url('assets/images/profiles/office.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, rh: true, dew: false, wind: false, dir: false, cloud: true, sun: true, direct: true, diffuse: false, tmrt: false, delta: false, utci: false, uvA: false, uvB: false, burn: false, utciP: true, precip: true, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: true, vis: false, aqi: true, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
driver: { name: 'Driver / Trucker', proOnly: true, scene: "url('assets/images/profiles/vehicle.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, 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: false, utciP: false, precip: true, precipProb: true, lightning: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: true, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
market: { name: 'Market Trading', proOnly: true, scene: "url('assets/images/profiles/market.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: true, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, utci: false, uvA: false, uvB: false, burn: false, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
windowcleaning: { name: 'Window Cleaning', proOnly: true, scene: "url('assets/images/profiles/window.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, utci: false, uvA: false, uvB: false, burn: false, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
office: { name: 'Office', proOnly: true, scene: "url('assets/images/profiles/office.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, rh: true, dew: false, wind: false, dir: false, cloud: true, sun: true, direct: true, diffuse: false, utci: false, uvA: false, uvB: false, burn: false, utciP: true, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: false, indoorT: false, managedT: true, vis: false, aqi: true, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
driver: { name: 'Driver / Trucker', proOnly: true, scene: "url('assets/images/profiles/vehicle.png') center / cover no-repeat, linear-gradient(160deg,#c2d4cc,#e2ece6)", cols: { hour: true, air: true, shadeT: false, rh: false, dew: false, wind: true, dir: true, cloud: true, sun: false, direct: false, diffuse: false, utci: false, uvA: true, uvB: false, burn: false, utciP: false, precip: true, precipProb: true, soilT: false, soilT6: false, soilM: false, concreteT: false, vehicleT: true, indoorT: false, managedT: false, vis: true, aqi: false, pollen: false, furSurfaceT: false, pawT: false, petShadeT: false, petHomeT: false } },
|
||||
};
|
||||
|
||||
// Pollen type options shown in the pulldown selector.
|
||||
@@ -279,16 +279,13 @@ export const COL_DESCRIPTIONS = {
|
||||
sun: { title: 'Sun Elevation', desc: 'The angle of the sun above the horizon in degrees. Below 0° the sun has set. The higher the elevation, the more intense the solar radiation reaching the ground.', short: "The angle of the sun above the horizon. Below 0° the sun has set; higher angles mean stronger radiation.", link: "./columns.html#col-sun" },
|
||||
direct: { title: 'Direct Radiation', desc: 'Shortwave solar radiation arriving in a direct beam from the sun (W/m²). The primary driver of skin heating on sunny days.', short: "Solar radiation arriving in a direct beam from the sun (W/m²) — the main driver of skin heating on sunny days.", link: "./columns.html#col-direct" },
|
||||
diffuse: { title: 'Diffuse Radiation', desc: 'Scattered solar radiation arriving from all directions across the sky (W/m²). Present even under cloud; contributes to overall solar load.', short: "Solar radiation scattered across the sky (W/m²). Present even under cloud, and adds to the total solar load.", link: "./columns.html#col-diffuse" },
|
||||
tmrt: { title: 'Mean Radiant Temp', desc: 'The combined heat from direct sun, scattered sky light, and ground reflection expressed as a temperature. Typically well above air temperature even on overcast days, and is one of the inputs used to calculate UTCI.', short: "Heat from direct sun, sky light and ground reflection expressed as a temperature. One of the inputs to UTCI.", link: "./columns.html#col-tmrt" },
|
||||
delta: { title: 'UTCI − Air Delta', desc: 'The difference between the UTCI felt temperature and the plain air temperature. A large positive value means solar radiation is adding significant heat stress beyond what the thermometer shows.', short: "The gap between UTCI felt temperature and plain air temperature. A big positive value means the sun is adding real heat stress.", link: "./columns.html#col-delta" },
|
||||
utci: { title: 'UTCI', desc: 'Universal Thermal Climate Index — the peer-reviewed standard felt temperature, combining air temp, humidity, wind, and solar radiation. Always computed from the raw open-ground reading: it does NOT move when you change the Solar Model, and it does not include precipitation. That is the point of it — a fixed benchmark to read SunSoak against, so the gap between the two columns shows exactly what your surroundings and the weather are adding.', short: "The peer-reviewed standard felt temperature. Always taken from the raw open-ground reading, so it stays fixed as a benchmark to read SunSoak against.", link: "./columns.html#col-utci" },
|
||||
uvA: { title: 'UV-A Index', desc: 'Estimated UV-A radiation index. UV-A penetrates deeper into the skin and contributes to long-term ageing and some skin cancers, even through glass.', short: "Estimated UV-A index. UV-A reaches deeper into the skin and drives long-term ageing, even through glass.", link: "./columns.html#col-uvA" },
|
||||
uvB: { title: 'UV-B Index', desc: 'Estimated UV-B radiation index. UV-B causes sunburn and is the main driver of vitamin D production. Intensity depends strongly on solar elevation and cloud cover.', short: "Estimated UV-B index. UV-B causes sunburn and drives vitamin D production.", link: "./columns.html#col-uvB" },
|
||||
burn: { title: 'Burn Time', desc: 'Estimated time to reach one Minimal Erythemal Dose (MED) — the threshold for sunburn — based on the UV index and your selected skin type. This is a guide, not a medical measurement.', short: "Estimated time to sunburn (one MED) for your selected skin type. A guide, not a medical measurement.", link: "./columns.html#col-burn" },
|
||||
utciP: { title: 'SunSoak', desc: 'SunScope\'s felt-temperature index. Based on UTCI — the standard combining air temp, humidity, wind, and solar radiation — with added adjustments for rain/snow and your chosen surroundings.', short: "SunScope's felt-temperature index: UTCI plus adjustments for rain or snow and your chosen surroundings.", link: "./columns.html#col-utciP" },
|
||||
precip: { title: 'Precipitation', desc: 'Expected rainfall or snowfall in mm per hour. Snow is shown in cm. Even light drizzle meaningfully reduces felt temperature when combined with wind.', short: "Expected rainfall in mm per hour, or snow in cm. Even drizzle cuts felt temperature noticeably in wind.", link: "./columns.html#col-precip" },
|
||||
precipProb: { title: 'Rain Probability', desc: 'Probability of precipitation for this hour as a percentage (0-100%). Derived from Open-Meteo ensemble model runs. A high value means rain is likely even if the expected rate is low - useful for spotting showers that the deterministic forecast may miss.', short: "Chance of precipitation this hour, from ensemble model runs. Useful for spotting showers the main forecast misses.", link: "./columns.html#col-precipProb" },
|
||||
lightning: { title: 'Lightning Potential', desc: 'Lightning Potential Index (LPI) from Open-Meteo in J/kg. A convective energy index — values above 5 suggest moderate lightning risk, above 25 suggest high risk.', short: "Lightning Potential Index in J/kg. Above 5 suggests moderate risk, above 25 high risk.", link: "./columns.html#col-lightning" },
|
||||
precipProb: { title: 'Rain Probability', desc: 'Probability of precipitation for this hour as a percentage (0-100%). Derived from Open-Meteo ensemble model runs. A high value means rain is likely even if the expected rate is low - useful for spotting showers that the deterministic forecast may miss. A ⚡ marks a thundery hour: it appears once the Lightning Potential Index passes 5 J/kg (moderate risk) and turns bold above 25 (high risk), tinting the cell amber.', short: "Chance of precipitation this hour, from ensemble model runs. A ⚡ marks hours with lightning potential.", link: "./columns.html#col-precipProb" },
|
||||
soilT: { title: 'Soil Temperature', desc: 'Temperature of the soil at the surface (0 cm depth). Useful for planting decisions — most seeds germinate above 7–10 °C.', short: "Soil temperature at the surface. Most seeds germinate above 7–10 °C.", link: "./columns.html#col-soilT" },
|
||||
soilT6: { title: 'Soil Temp 6 cm', desc: 'Temperature of the soil at 6 cm depth, the root zone for many crops and seedlings. Lags behind surface temperature by several hours.', short: "Soil temperature at 6 cm — the root zone for many crops. Lags the surface by several hours.", link: "./columns.html#col-soilT6" },
|
||||
soilM: { title: 'Soil Moisture', desc: 'Water saturation of the top 1 cm of soil as a percentage. Above 40% suggests saturated ground; below 20% indicates dry conditions.', short: "Water saturation of the top 1 cm of soil. Above 40% is saturated ground; below 20% is dry.", link: "./columns.html#col-soilM" },
|
||||
|
||||
@@ -442,8 +442,12 @@ export function useAppState() {
|
||||
if (key !== 'custom') {
|
||||
setVisibleCols({ ...profile.cols });
|
||||
const hasIndoor = profile.cols['indoorT'] || profile.cols['managedT'];
|
||||
setIndoorMode(hasIndoor ? 'on' : 'off');
|
||||
setIndoorManaged(false);
|
||||
// Must go through the persisting setters: the Indoors pill and column
|
||||
// read indoorMode, and its initialiser reads it back from localStorage
|
||||
// on the next load. Setting only the React state left the stored value
|
||||
// behind, so a reload restored the previous profile's Indoors state.
|
||||
setIndoorModeAndSave(hasIndoor ? 'on' : 'off');
|
||||
setIndoorManagedAndSave(false);
|
||||
if (hasIndoor) setBuildingTypeAndSave('brick');
|
||||
const defaultEnv = VARIANT_DEFAULT_ENV[key];
|
||||
if (defaultEnv) setUtciEnvAndSave(defaultEnv);
|
||||
@@ -453,8 +457,8 @@ export function useAppState() {
|
||||
if (customCols) {
|
||||
setVisibleCols({ ...customCols });
|
||||
const hasIndoor = customCols['indoorT'] || customCols['managedT'];
|
||||
setIndoorMode(hasIndoor ? 'on' : 'off');
|
||||
setIndoorManaged(false);
|
||||
setIndoorModeAndSave(hasIndoor ? 'on' : 'off');
|
||||
setIndoorManagedAndSave(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -501,7 +505,7 @@ export function useAppState() {
|
||||
if (variantCols) {
|
||||
setVisibleCols({ ...variantCols });
|
||||
const hasIndoor = variantCols['indoorT'] || variantCols['managedT'];
|
||||
setIndoorMode(hasIndoor ? 'on' : 'off');
|
||||
setIndoorModeAndSave(hasIndoor ? 'on' : 'off');
|
||||
}
|
||||
// Auto-set UTCI environment modifier to match the selected variant.
|
||||
const defaultEnv = VARIANT_DEFAULT_ENV[v] ?? 'open';
|
||||
@@ -548,11 +552,19 @@ export function useAppState() {
|
||||
};
|
||||
const [indoorMode, setIndoorMode] = useState(() => {
|
||||
try {
|
||||
const saved = localStorage.getItem('sunscope_indoor_mode');
|
||||
if (saved) return saved;
|
||||
const profile = localStorage.getItem('sunscope_profile') || 'basic';
|
||||
const cols = FILTER_PROFILES[profile]?.cols ?? FILTER_PROFILES.basic.cols;
|
||||
return (cols['indoorT'] || cols['managedT']) ? 'on' : 'off';
|
||||
const cols = profile === 'outdoors'
|
||||
? (OUTDOORS_VARIANTS[localStorage.getItem('sunscope_outdoors_variant') || 'urban']?.cols
|
||||
?? FILTER_PROFILES.outdoors.cols)
|
||||
: (FILTER_PROFILES[profile]?.cols ?? FILTER_PROFILES.basic.cols);
|
||||
const offered = !!(cols['indoorT'] || cols['managedT']);
|
||||
// A profile that has no Indoors columns has no Indoors pill either, so
|
||||
// an 'on' left over from a profile that did would show the column with
|
||||
// no way to turn it off. The profile decides whether it's available;
|
||||
// the saved value only decides the state within a profile that offers it.
|
||||
if (!offered) return 'off';
|
||||
const saved = localStorage.getItem('sunscope_indoor_mode');
|
||||
return saved || 'on';
|
||||
} catch (e) { return 'off'; }
|
||||
});
|
||||
const setIndoorModeAndSave = (v) => {
|
||||
@@ -643,11 +655,10 @@ export function useAppState() {
|
||||
const [tableRotated, setTableRotated] = useState(() => {
|
||||
try { return localStorage.getItem('sunscope_table_rotated') === '1'; } catch (e) { return false; }
|
||||
});
|
||||
const toggleTableRotated = () => setTableRotated(v => {
|
||||
const next = !v;
|
||||
const setTableRotatedAndSave = (next) => {
|
||||
try { localStorage.setItem('sunscope_table_rotated', next ? '1' : '0'); } catch (e) { /* ignore */ }
|
||||
return next;
|
||||
});
|
||||
setTableRotated(!!next);
|
||||
};
|
||||
|
||||
// Table row interval: 1 = every hour, 2/3/4 = clock-aligned buckets. Default 2.
|
||||
const [tableInterval, setTableIntervalState] = useState(() => {
|
||||
@@ -903,7 +914,7 @@ export function useAppState() {
|
||||
panelOpen, openPanel, closePanel,
|
||||
showUnits, toggleShowUnits,
|
||||
tableInterval, setTableInterval,
|
||||
tableRotated, toggleTableRotated,
|
||||
tableRotated, setTableRotated: setTableRotatedAndSave,
|
||||
forecastView, setForecastView,
|
||||
// table refs
|
||||
headStickyRef, headTrackRef, headTableRef,
|
||||
|
||||
+21
-44
@@ -18,7 +18,8 @@
|
||||
// label heading text
|
||||
// unit the small print under the heading ("°C", "mm/h", …)
|
||||
// unitNone true → render the unit muted+italic (no data for this day)
|
||||
// group felt | surface | ambient | precip | sky | wind | airqual | solar
|
||||
// group felt | surface | pets | ambient | precip | sky | wind |
|
||||
// airqual | solar
|
||||
// visible resolved from visibleCols / indoorMode
|
||||
// headClass extra class on the heading cell ('utci-tight-head', …)
|
||||
// cellClass extra class on the data cell ('utci-dir-cell', …)
|
||||
@@ -163,14 +164,6 @@ const soilMoistureBg = (v) => {
|
||||
return { bg: `rgba(${r},${g},${b},0.18)`, fg: '#3a2a10' };
|
||||
};
|
||||
|
||||
const deltaBg = (v) => {
|
||||
if (v == null || isNaN(v)) return 'transparent';
|
||||
if (Math.abs(v) < 1) return 'transparent';
|
||||
const x = Math.min(1, Math.abs(v) / 12);
|
||||
const a = 0.035 + x * 0.13;
|
||||
return v > 0 ? `rgba(230,140,50,${a.toFixed(3)})` : `rgba(80,135,210,${a.toFixed(3)})`;
|
||||
};
|
||||
|
||||
const burnBg = (mins, uv) => {
|
||||
if (!isFinite(mins) || uv <= 0) return 'transparent';
|
||||
if (mins >= 240) return 'transparent';
|
||||
@@ -229,6 +222,7 @@ export function buildColumnDefs(ctx) {
|
||||
...tempCol('managedT', 'Managed', '°C est.', 'felt', r => r.managedT),
|
||||
visible: indoorMode === 'on' && indoorManaged,
|
||||
},
|
||||
tempCol('utci', 'UTCI', '°C felt', 'felt', r => r.utci),
|
||||
{
|
||||
key: 'burn', label: 'Burn', unit: 'to MED', group: 'felt',
|
||||
visible: !!visibleCols.burn,
|
||||
@@ -243,25 +237,7 @@ export function buildColumnDefs(ctx) {
|
||||
};
|
||||
},
|
||||
},
|
||||
tempCol('utci', 'UTCI', '°C felt', 'felt', r => r.utci),
|
||||
{
|
||||
key: 'delta', label: 'Δ', unit: 'UTCI−Air', group: 'felt',
|
||||
visible: !!visibleCols.delta,
|
||||
render: (r) => {
|
||||
const d = r.utci - r.Ta;
|
||||
return {
|
||||
content: `${d > 0 ? '+' : ''}${fmt(d)}${u('°C')}`,
|
||||
style: {
|
||||
color: d > 3 ? '#c8601a' : d < -3 ? '#3f73c4' : '#4a3218',
|
||||
background: deltaBg(d),
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
tempCol('tmrt', 'Tmrt', '°C', 'felt', r => r.Tmrt),
|
||||
tempCol('concreteT', 'Concrete', '°C surface', 'surface', r => r.concreteT),
|
||||
tempCol('furSurfaceT', 'Fur', '°C surface', 'surface', r => r.furSurfaceT, { pet: true, petTitle: true }),
|
||||
tempCol('pawT', 'Paw', '°C surface', 'surface', r => r.pawT, { pet: true, petTitle: true }),
|
||||
tempCol('soilT', 'Soil °C', 'surface', 'surface', r => r.soilT0),
|
||||
tempCol('soilT6', 'Soil 6cm', '°C root', 'surface', r => r.soilT6),
|
||||
{
|
||||
@@ -275,10 +251,12 @@ export function buildColumnDefs(ctx) {
|
||||
};
|
||||
},
|
||||
},
|
||||
tempCol('petShadeT', 'Pet Shade', '°C', 'ambient', r => r.petShadeT, { pet: true, petTitle: true, headClass: 'utci-tight-head' }),
|
||||
tempCol('furSurfaceT', 'Fur', '°C surface', 'pets', r => r.furSurfaceT, { pet: true, petTitle: true }),
|
||||
tempCol('pawT', 'Paw', '°C surface', 'pets', r => r.pawT, { pet: true, petTitle: true }),
|
||||
tempCol('petShadeT', 'Pet Shade', '°C', 'pets', r => r.petShadeT, { pet: true, petTitle: true, headClass: 'utci-tight-head' }),
|
||||
// Pet Home reads the same indoorT figure as the Indoors column, just on
|
||||
// the pet-calibrated colour scale.
|
||||
tempCol('petHomeT', 'Pet Home', '°C est.', 'ambient', r => r.indoorT, { pet: true, petTitle: true }),
|
||||
tempCol('petHomeT', 'Pet Home', '°C est.', 'pets', r => r.indoorT, { pet: true, petTitle: true }),
|
||||
tempCol('air', 'Air', '°C', 'ambient', r => r.Ta, { headClass: 'utci-tight-head' }),
|
||||
{
|
||||
key: 'rh', label: 'RH', unit: '%', group: 'ambient',
|
||||
@@ -306,27 +284,26 @@ export function buildColumnDefs(ctx) {
|
||||
}),
|
||||
},
|
||||
{
|
||||
// Rain % carries the storm warning too: rather than spend a whole
|
||||
// column on the Lightning Potential Index, an amber ⚡ rides alongside
|
||||
// the percentage whenever LPI clears the moderate-risk threshold (5),
|
||||
// going bold at the high-risk one (25). Same thresholds the old
|
||||
// Lightning column and the Lightning-risk insight use.
|
||||
key: 'precipProb', label: 'Rain', unit: '%', group: 'precip',
|
||||
visible: !!visibleCols.precipProb, headClass: 'utci-tight-head',
|
||||
render: (r) => ({
|
||||
content: `${r.precipProb}${u('%')}`,
|
||||
style: {
|
||||
background: scaleBg(r.precipProb, 0, 100, '70,145,200'),
|
||||
color: r.precipProb >= 50 ? '#1a4a70' : r.precipProb > 0 ? '#2a6a90' : '#7a8a90',
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
key: 'lightning', label: '⚡', unit: 'LPI', group: 'precip',
|
||||
visible: !!visibleCols.lightning, headClass: 'utci-tight-head',
|
||||
render: (r) => {
|
||||
const lpi = r.lightning ?? 0;
|
||||
const storm = lpi >= 25 ? 'high' : lpi >= 5 ? 'mod' : null;
|
||||
return {
|
||||
content: lpi > 0 ? `${Math.round(lpi)}` : '',
|
||||
title: storm ? `Lightning potential ${Math.round(lpi)} J/kg — ${storm === 'high' ? 'high' : 'moderate'} risk` : undefined,
|
||||
content: html`${r.precipProb}${u('%')}${storm
|
||||
? html`<span style=${{ marginLeft: '4px', fontWeight: storm === 'high' ? 700 : 'normal', opacity: storm === 'high' ? 1 : 0.75, color: storm === 'high' ? '#7a4800' : '#6a5800' }}>⚡</span>`
|
||||
: ''}`,
|
||||
style: {
|
||||
background: lpi >= 25 ? 'rgba(255,180,0,0.25)' : lpi >= 5 ? 'rgba(255,210,0,0.15)' : 'transparent',
|
||||
color: lpi >= 25 ? '#7a4800' : lpi >= 5 ? '#6a5800' : '#7a8a90',
|
||||
textAlign: 'center',
|
||||
background: storm === 'high' ? 'rgba(255,180,0,0.25)'
|
||||
: storm === 'mod' ? 'rgba(255,210,0,0.15)'
|
||||
: scaleBg(r.precipProb, 0, 100, '70,145,200'),
|
||||
color: r.precipProb >= 50 ? '#1a4a70' : r.precipProb > 0 ? '#2a6a90' : '#7a8a90',
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user