portrait almanac #167

This commit is contained in:
Matt Walsh
2026-04-22 21:35:53 -05:00
parent 033bed96b9
commit 0395e2cd08
7 changed files with 117 additions and 53 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

View File

@@ -30,12 +30,13 @@ class Almanac extends WeatherDisplay {
const superResponse = super.getData(weatherParameters, refresh);
// get sun/moon data
const { sun, moon } = this.calcSunMoonData(this.weatherParameters);
const { sun, moon, moonTransit } = this.calcSunMoonData(this.weatherParameters);
// store the data
this.data = {
sun,
moon,
moonTransit,
};
// share data
this.getDataCallback();
@@ -47,7 +48,9 @@ class Almanac extends WeatherDisplay {
}
calcSunMoonData(weatherParameters) {
const sun = [0, 1, 2, 3, 4, 5, 6].map((days) => SunCalc.getTimes(DateTime.local().plus({ days }).toJSDate(), weatherParameters.latitude, weatherParameters.longitude));
const dayOffsets = [0, 1, 2, 3, 4, 5, 6];
const sun = dayOffsets.map((days) => SunCalc.getTimes(DateTime.local().plus({ days }).toJSDate(), weatherParameters.latitude, weatherParameters.longitude));
const moonTransit = dayOffsets.map((days) => SunCalc.getMoonTimes(DateTime.local().plus({ days }).toJSDate(), weatherParameters.latitude, weatherParameters.longitude));
// brute force the moon phases by scanning the next 30 days
const moon = [];
@@ -74,6 +77,7 @@ class Almanac extends WeatherDisplay {
return {
sun,
moon,
moonTransit,
};
}
@@ -121,21 +125,52 @@ class Almanac extends WeatherDisplay {
// Generate sun data grid in reading order (left-to-right, top-to-bottom)
// Set day names
// Set day names and sunset times
const Today = DateTime.local();
// fill all three days, even if some are hidden by non-enhanced
for (let i = 0; i < 3; i += 1) {
this.elem.querySelector(`.day-${i}`).textContent = Today.plus({ days: i }).toLocaleString({ weekday: 'long' });
const portraitLines = [];
const moonPortraitLines = [];
// fill all days, even if some are hidden by the mode selection.
for (let i = 0; i < 7; i += 1) {
// format some data
const dayName = Today.plus({ days: i }).toLocaleString({ weekday: 'long' });
const sunrise = formatTimeForColumn(DateTime.fromJSDate(info.sun[i].sunrise));
const sunset = formatTimeForColumn(DateTime.fromJSDate(info.sun[i].sunset));
const sunrise = DateTime.fromJSDate(info.sun[i].sunrise);
const sunset = DateTime.fromJSDate(info.sun[i].sunset);
const [sunriseFormatted, sunsetFormatted] = formatTimesForColumn([sunrise, sunset]);
this.elem.querySelector(`.rise-${i}`).textContent = sunriseFormatted;
this.elem.querySelector(`.set-${i}`).textContent = sunsetFormatted;
// these only use the first 3 for standard and wide
if (i < 3) {
this.elem.querySelector(`.day-${i}`).textContent = dayName;
this.elem.querySelector(`.rise-${i}`).textContent = sunrise;
this.elem.querySelector(`.set-${i}`).textContent = sunset;
}
// and also fill the portrait oriented info
portraitLines.push(this.fillTemplate('dayname', { 'grid-item': dayName }));
portraitLines.push(this.fillTemplate('sunrise', { 'grid-item': sunrise }));
portraitLines.push(this.fillTemplate('sunset', { 'grid-item': sunset }));
// including the bonus moon rise/set data in portrait
const moonrise = formatTimeForColumn(DateTime.fromJSDate(info.moonTransit[i].rise));
const moonset = formatTimeForColumn(DateTime.fromJSDate(info.moonTransit[i].set));
moonPortraitLines.push(this.fillTemplate('dayname', { 'grid-item': dayName }));
moonPortraitLines.push(this.fillTemplate('sunrise', { 'grid-item': moonrise }));
moonPortraitLines.push(this.fillTemplate('sunset', { 'grid-item': moonset }));
}
// add the portrait lines to the page
const sunPortrait = this.elem.querySelector('.sun-portrait');
const replaceable = sunPortrait.querySelectorAll(':has(.replaceable)');
replaceable.forEach((elem) => elem.remove());
sunPortrait.append(...portraitLines);
// and the moon too
const moonPortrait = this.elem.querySelector('.moonrise.sun-portrait');
const moonReplaceable = moonPortrait.querySelectorAll(':has(.replaceable)');
moonReplaceable.forEach((elem) => elem.remove());
moonPortrait.append(...moonPortraitLines);
// Moon data
const days = info.moon.map((MoonPhase) => {
const days = info.moon.map((MoonPhase, idx) => {
const fill = {};
const date = MoonPhase.date.toLocaleString({ month: 'short', day: 'numeric' });
@@ -144,7 +179,14 @@ class Almanac extends WeatherDisplay {
fill.type = MoonPhase.phase;
fill.icon = { type: 'img', src: this.iconPaths[MoonPhase.phase] };
return this.fillTemplate('day', fill);
const filledTemplate = this.fillTemplate('day', fill);
// add class to hide >4 moon phases when not wide-enhanced
if (idx > 3) {
filledTemplate.classList.add('wide-enhanced');
}
return filledTemplate;
});
const daysContainer = this.elem.querySelector('.moon .days');
@@ -181,19 +223,16 @@ const imageName = (type) => {
}
};
const formatTimesForColumn = (times) => {
const formatted = times.map((dt) => dt.setZone(timeZone()).toFormat('h:mm a').toUpperCase());
// Check if any time has a 2-digit hour (starts with '1')
const hasTwoDigitHour = formatted.some((time) => time.startsWith('1'));
const formatTimeForColumn = (time) => {
// moonrise and set may not have a time each day
if (!time.isValid) return '-';
const formatted = time.setZone(timeZone()).toFormat('h:mm a').toUpperCase();
// If mixed digit lengths, pad single-digit hours with non-breaking space
if (hasTwoDigitHour) {
return formatted.map((time) => (time.startsWith('1') ? time : `\u00A0${time}`));
if (formatted.length === 8) {
return formatted;
}
// Otherwise, no padding needed
return formatted;
return `\u00A0${formatted}`;
};
// register display

View File

@@ -4,10 +4,15 @@
#almanac-html.weather-display {
background-image: url('../images/backgrounds/3.png');
// repeat the background if wide-enhanced
// change the backgrounds for enhanced modes
.wide.enhanced & {
background-image: url('../images/backgrounds/3-wide-enhanced.png');
}
// change background for portrait
.portrait.enhanced & {
background-image: url(../images/backgrounds/3-portrait.png);
}
}
.weather-display .main.almanac {
@@ -30,6 +35,10 @@
grid-template-columns: repeat(4, auto);
}
.portrait.enhanced & {
display: none;
}
.grid-item {
// Reset inherited styles that interfere with grid layout
width: auto;
@@ -65,6 +74,23 @@
}
}
.portrait.enhanced & {
font-size: 28pt;
}
.sun.sun-portrait {
display: none;
.portrait.enhanced & {
display: grid;
}
.grid-item {
margin: 8px 0px;
}
}
.moon {
position: relative;
padding: 7px 50px;
@@ -73,6 +99,8 @@
.title {
color: c.$column-header-text;
padding-left: 13px;
}
.days {
@@ -93,6 +121,14 @@
position: relative;
top: -10px;
}
&.wide-enhanced {
display: none;
.wide.enhanced & {
display: inline-block;
}
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -14,6 +14,14 @@
<div class="grid-item time set-1"></div>
<div class="grid-item time set-2 wide-enhanced"></div>
</div>
<div class="sun sun-portrait portrait-only">
<div class="grid-item empty"></div>
<div class="grid-item header sunrise">Sunrise</div>
<div class="grid-item header sunset">Sunset</div>
<div class="dayname template"><div class="grid-item row-label replaceable"></div></div>
<div class="sunrise template"><div class="grid-item time replaceable"></div></div>
<div class="sunset template"><div class="grid-item time replaceable"></div></div>
</div>
<div class="moon">
<div class="title">Moon Data:</div>
<div class="days">
@@ -24,4 +32,12 @@
</div>
</div>
</div>
<div class="sun moonrise sun-portrait portrait-only">
<div class="grid-item empty"></div>
<div class="grid-item header sunrise">Moonrise</div>
<div class="grid-item header sunset">Moonset</div>
<div class="dayname template"><div class="grid-item row-label replaceable"></div></div>
<div class="moonrise template"><div class="grid-item time replaceable"></div></div>
<div class="moonset template"><div class="grid-item time replaceable"></div></div>
</div>
</div>