UI Overhaul
Profiles now in popup
Current profile always on screen
Hidden columns only when edit neeeded
Add pulldowns in to profile config
Customised the day tabs for vehicle, indoor and pet
This commit is contained in:
fraxle
2026-07-18 15:45:20 +01:00
parent f92e191a44
commit 916efca55e
13 changed files with 1594 additions and 610 deletions
+52
View File
@@ -0,0 +1,52 @@
// ------------------------------------------------------------------------
// activity-profile.js - Estimates the % chance of a good viewing on a given
// day for a multi-day cosmic event (meteor shower, conjunction), based on
// how far that day sits from the event's peak.
//
// The calendar data only has start/end/peak dates, not real activity
// curves, so this is a simplified heuristic (not live forecast data):
// chance falls off exponentially from 100% at peak, halving every
// `riseTau`/`decayTau` days on the approach/departure side. Values below
// are rough approximations of each shower's real-world activity profile
// (sharp showers like the Quadrantids get small tau, broad ones like the
// Eta Aquariids get larger tau) - good enough to gate "is this worth
// looking up for" without pretending to be precise astronomy.
//
// Single-day events (start === end) are always 100% - they only ever
// appear in COSMIC_CALENDAR on their one active day anyway.
// ------------------------------------------------------------------------
const ACTIVITY_PROFILES = {
quadrantids: { riseTau: 0.3, decayTau: 0.4 },
lyrids: { riseTau: 0.6, decayTau: 0.7 },
'eta-aquariids': { riseTau: 3.5, decayTau: 3.0 },
perseids: { riseTau: 2.2, decayTau: 1.8 },
orionids: { riseTau: 1.5, decayTau: 1.5 },
leonids: { riseTau: 0.5, decayTau: 0.6 },
geminids: { riseTau: 1.0, decayTau: 1.0 },
ursids: { riseTau: 0.4, decayTau: 0.4 },
'mars-conjunction': { riseTau: 1.0, decayTau: 1.0 },
'venus-jupiter-conjunction': { riseTau: 1.0, decayTau: 1.0 },
};
const DEFAULT_PROFILE = { riseTau: 1.0, decayTau: 1.0 };
function baseKey(id) {
return String(id).replace(/-\d{4}$/, '');
}
export function getActivityProfile(id) {
return ACTIVITY_PROFILES[baseKey(id)] || DEFAULT_PROFILE;
}
// Returns an integer 0-100.
export function activityChance(ev, dateStr) {
if (!ev.peak || ev.start === ev.end) return 100;
const today = new Date(dateStr + 'T00:00Z');
const peak = new Date(ev.peak + 'T00:00Z');
const diffDays = (today - peak) / 86400000;
const { riseTau, decayTau } = getActivityProfile(ev.id);
const tau = diffDays <= 0 ? riseTau : decayTau;
const pct = 100 * Math.pow(0.5, Math.abs(diffDays) / tau);
return Math.round(pct);
}
+1 -1
View File
@@ -153,7 +153,7 @@ export const cosmic = [
textColor: '#ffc8d8',
type: 'cosmic',
nightOnly: true,
start: '2026-06-30', end: '2026-07-02',
start: '2026-06-30', end: '2026-07-02', peak: '2026-07-01',
},
];
+9 -6
View File
@@ -2,11 +2,13 @@
// dynamic-message.js - Rewrites a cosmic event's message based on where
// today sits vs. the peak.
//
// Before peak : "is active and building - peak on <date>. <detail>"
// On peak -1d : "peaks tonight - <detail>"
// After peak : "is past its peak (<date>) but still possibly visible - <detail>"
// Before peak : "is active and building - peak on <date>. <detail> (~NN% chance...)"
// On peak -1d : "peaks tonight - <detail> (~NN% chance...)"
// After peak : "is past its peak (<date>) but still possibly visible - <detail> (~NN% chance...)"
//
// Single-day events (start === end) keep their static message unchanged.
// `ev.chance` (see ../events/activity-profile.js), when present, is
// appended as an estimated viewing-chance figure.
// ------------------------------------------------------------------------
export function dynamicCosmicMessage(ev, dateStr) {
@@ -19,11 +21,12 @@ export function dynamicCosmicMessage(ev, dateStr) {
.replace(/^.*?(?:peaks tonight|peak tonight|is active tonight|is active|peaks)\s*—\s*/i, '')
.trim();
var baseCapd = base.charAt(0).toUpperCase() + base.slice(1);
var chanceSuffix = typeof ev.chance === 'number' ? ' (~' + ev.chance + '% chance of a good show tonight)' : '';
if (diffDays < -1) {
return ev.title + ' is active and building — peak on ' + peakFmt + '. ' + baseCapd;
return ev.title + ' is active and building — peak on ' + peakFmt + '. ' + baseCapd + chanceSuffix;
} else if (diffDays <= 1) {
return ev.title + ' peaks tonight — ' + base;
return ev.title + ' peaks tonight — ' + base + chanceSuffix;
} else {
return ev.title + ' is past its peak (' + peakFmt + ') but still possibly visible — ' + base;
return ev.title + ' is past its peak (' + peakFmt + ') but still possibly visible — ' + base + chanceSuffix;
}
}