Integrate fonts
Add office profile
Fix onload pulldown selections
This commit is contained in:
fraxle
2026-05-25 10:23:51 +01:00
parent e9a6cc9912
commit 2cb4ebe52b
20 changed files with 185 additions and 52 deletions
+78 -32
View File
@@ -26,7 +26,7 @@ import { useState, useEffect, useRef, useCallback } from '../../vendor/preact-ho
import {
FREE_DAYS, FILTER_PROFILES, OUTDOORS_VARIANTS,
profileButtonOrder, variantIcons,
activityVariantKeys, placeVariantKeys,
activityVariantKeys, placeVariantKeys, workVariantKeys,
} from '../config.js';
import { utciCategory } from '../utils.js';
import { buildHourlyRows } from '../compute.js';
@@ -167,8 +167,20 @@ export function useAppState() {
// ── 5. SKIN, VEHICLE, INDOOR, POLLEN ─────────────────────────────────
const [skinType, setSkinType] = useState('II');
const [vehicleType, setVehicleType] = useState('car');
const [vehicleVent, setVehicleVent] = useState(false);
const [vehicleType, setVehicleType] = useState(() => {
try { return localStorage.getItem('sunscope_vehicle_type') || 'car'; } catch (e) { return 'car'; }
});
const setVehicleTypeAndSave = (v) => {
try { localStorage.setItem('sunscope_vehicle_type', v); } catch (e) { /* ignore */ }
setVehicleType(v);
};
const [vehicleVent, setVehicleVent] = useState(() => {
try { return localStorage.getItem('sunscope_vehicle_vent') === '1'; } catch (e) { return false; }
});
const setVehicleVentAndSave = (v) => {
try { localStorage.setItem('sunscope_vehicle_vent', v ? '1' : '0'); } catch (e) { /* ignore */ }
setVehicleVent(v);
};
const [outdoorsVariant, setOutdoorsVariant] = useState(() => {
try { return localStorage.getItem('sunscope_outdoors_variant') || 'urban'; } catch (e) { return 'urban'; }
@@ -190,15 +202,40 @@ export function useAppState() {
? (OUTDOORS_VARIANTS[outdoorsVariant]?.cols ?? FILTER_PROFILES.outdoors.cols)
: (FILTER_PROFILES[activeProfile]?.cols ?? FILTER_PROFILES.basic.cols);
const [buildingType, setBuildingType] = useState('brick');
const [indoorManaged, setIndoorManaged] = useState(false);
const [indoorMode, setIndoorMode] = useState(() => {
const [buildingType, setBuildingType] = useState(() => {
try {
const saved = localStorage.getItem('sunscope_profile') || 'basic';
const cols = FILTER_PROFILES[saved]?.cols ?? FILTER_PROFILES.basic.cols;
const saved = localStorage.getItem('sunscope_building_type');
if (saved) return saved;
// Fall back to office if the saved variant is office and no explicit building saved
const savedVariant = localStorage.getItem('sunscope_outdoors_variant') || '';
if (savedVariant === 'office') return 'office';
} catch (e) { /* ignore */ }
return 'brick';
});
const setBuildingTypeAndSave = (v) => {
try { localStorage.setItem('sunscope_building_type', v); } catch (e) { /* ignore */ }
setBuildingType(v);
};
const [indoorManaged, setIndoorManaged] = useState(() => {
try { return localStorage.getItem('sunscope_indoor_managed') === '1'; } catch (e) { return false; }
});
const setIndoorManagedAndSave = (v) => {
try { localStorage.setItem('sunscope_indoor_managed', v ? '1' : '0'); } catch (e) { /* ignore */ }
setIndoorManaged(v);
};
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';
} catch (e) { return 'off'; }
});
const setIndoorModeAndSave = (v) => {
try { localStorage.setItem('sunscope_indoor_mode', v); } catch (e) { /* ignore */ }
setIndoorMode(v);
};
const [pollenType, setPollenType] = useState(() => {
try { return localStorage.getItem('sunscope_pollen_type') || 'all_pollen'; } catch (e) { return 'all_pollen'; }
@@ -233,19 +270,13 @@ export function useAppState() {
const searchTimeout = useRef(null);
// Derived selectors used by profile controls
const activityOptions = [
{
value: 'farming',
label: `${FILTER_PROFILES.farming.icon} ${FILTER_PROFILES.farming.label}`,
},
...activityVariantKeys.map((k) => {
const v = OUTDOORS_VARIANTS[k];
return {
value: k,
label: `${variantIcons[k]} ${v.name}${v.proOnly && !isPro ? ' 🔒' : ''}`,
};
}),
];
const activityOptions = activityVariantKeys.map((k) => {
const v = OUTDOORS_VARIANTS[k];
return {
value: k,
label: `${variantIcons[k]} ${v.name}${v.proOnly && !isPro ? ' 🔒' : ''}`,
};
});
const placeOptions = placeVariantKeys.map((k) => {
const v = OUTDOORS_VARIANTS[k];
return {
@@ -253,17 +284,31 @@ export function useAppState() {
label: `${variantIcons[k]} ${v.name}${v.proOnly && !isPro ? ' 🔒' : ''}`,
};
});
const workOptions = workVariantKeys.map((k) => {
const v = k === 'farming'
? { name: FILTER_PROFILES.farming.label, proOnly: false }
: OUTDOORS_VARIANTS[k];
const icon = k === 'farming' ? FILTER_PROFILES.farming.icon : variantIcons[k];
return {
value: k,
label: `${icon} ${v.name}${v.proOnly && !isPro ? ' 🔒' : ''}`,
};
});
const activityValue = activeProfile === 'farming'
? 'farming'
: activeProfile === 'outdoors' && activityVariantKeys.includes(outdoorsVariant)
? outdoorsVariant
: 'off';
const activityValue = activeProfile === 'outdoors' && activityVariantKeys.includes(outdoorsVariant)
? outdoorsVariant
: 'off';
const activityLabel = activityOptions.find((o) => o.value === activityValue)?.label;
const placeValue = activeProfile === 'outdoors' && placeVariantKeys.includes(outdoorsVariant)
? outdoorsVariant
: 'off';
const placeLabel = placeOptions.find((o) => o.value === placeValue)?.label;
const workValue = activeProfile === 'farming'
? 'farming'
: activeProfile === 'outdoors' && workVariantKeys.includes(outdoorsVariant)
? outdoorsVariant
: 'off';
const workLabel = workOptions.find((o) => o.value === workValue)?.label;
// ── 6. TABLE REFS ────────────────────────────────────────────────────
const headStickyRef = useRef(null);
@@ -439,17 +484,18 @@ export function useAppState() {
activeProfile, setActiveProfile,
activateProfile, activeCols,
visibleCols, setVisibleCols, toggleCol,
activityOptions, placeOptions,
activityOptions, placeOptions, workOptions,
activityValue, activityLabel,
placeValue, placeLabel,
workValue, workLabel,
// skin, vehicle, indoor, pollen
skinType, setSkinType,
vehicleType, setVehicleType,
vehicleVent, setVehicleVent,
vehicleType, setVehicleType: setVehicleTypeAndSave,
vehicleVent, setVehicleVent: setVehicleVentAndSave,
outdoorsVariant, setOutdoorsVariantAndSave,
buildingType, setBuildingType,
indoorManaged, setIndoorManaged,
indoorMode, setIndoorMode,
buildingType, setBuildingType: setBuildingTypeAndSave,
indoorManaged, setIndoorManaged: setIndoorManagedAndSave,
indoorMode, setIndoorMode: setIndoorModeAndSave,
pollenType, setPollenTypeAndSave,
showDecimals, toggleShowDecimals,
showUnits, toggleShowUnits,