mirror of
https://github.com/netbymatt/ws4kp.git
synced 2026-04-23 12:09:30 -07:00
portrait almanac #167
This commit is contained in:
BIN
server/images/backgrounds/3-portrait.png
Normal file
BIN
server/images/backgrounds/3-portrait.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 153 KiB |
BIN
server/images/gimp/3-portrait.xcf
Normal file
BIN
server/images/gimp/3-portrait.xcf
Normal file
Binary file not shown.
@@ -30,12 +30,13 @@ class Almanac extends WeatherDisplay {
|
|||||||
const superResponse = super.getData(weatherParameters, refresh);
|
const superResponse = super.getData(weatherParameters, refresh);
|
||||||
|
|
||||||
// get sun/moon data
|
// get sun/moon data
|
||||||
const { sun, moon } = this.calcSunMoonData(this.weatherParameters);
|
const { sun, moon, moonTransit } = this.calcSunMoonData(this.weatherParameters);
|
||||||
|
|
||||||
// store the data
|
// store the data
|
||||||
this.data = {
|
this.data = {
|
||||||
sun,
|
sun,
|
||||||
moon,
|
moon,
|
||||||
|
moonTransit,
|
||||||
};
|
};
|
||||||
// share data
|
// share data
|
||||||
this.getDataCallback();
|
this.getDataCallback();
|
||||||
@@ -47,7 +48,9 @@ class Almanac extends WeatherDisplay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
calcSunMoonData(weatherParameters) {
|
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
|
// brute force the moon phases by scanning the next 30 days
|
||||||
const moon = [];
|
const moon = [];
|
||||||
@@ -74,6 +77,7 @@ class Almanac extends WeatherDisplay {
|
|||||||
return {
|
return {
|
||||||
sun,
|
sun,
|
||||||
moon,
|
moon,
|
||||||
|
moonTransit,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,21 +125,52 @@ class Almanac extends WeatherDisplay {
|
|||||||
|
|
||||||
// Generate sun data grid in reading order (left-to-right, top-to-bottom)
|
// 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();
|
const Today = DateTime.local();
|
||||||
// fill all three days, even if some are hidden by non-enhanced
|
const portraitLines = [];
|
||||||
for (let i = 0; i < 3; i += 1) {
|
const moonPortraitLines = [];
|
||||||
this.elem.querySelector(`.day-${i}`).textContent = Today.plus({ days: i }).toLocaleString({ weekday: 'long' });
|
// 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);
|
// these only use the first 3 for standard and wide
|
||||||
const sunset = DateTime.fromJSDate(info.sun[i].sunset);
|
if (i < 3) {
|
||||||
const [sunriseFormatted, sunsetFormatted] = formatTimesForColumn([sunrise, sunset]);
|
this.elem.querySelector(`.day-${i}`).textContent = dayName;
|
||||||
this.elem.querySelector(`.rise-${i}`).textContent = sunriseFormatted;
|
this.elem.querySelector(`.rise-${i}`).textContent = sunrise;
|
||||||
this.elem.querySelector(`.set-${i}`).textContent = sunsetFormatted;
|
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
|
// Moon data
|
||||||
const days = info.moon.map((MoonPhase) => {
|
const days = info.moon.map((MoonPhase, idx) => {
|
||||||
const fill = {};
|
const fill = {};
|
||||||
|
|
||||||
const date = MoonPhase.date.toLocaleString({ month: 'short', day: 'numeric' });
|
const date = MoonPhase.date.toLocaleString({ month: 'short', day: 'numeric' });
|
||||||
@@ -144,7 +179,14 @@ class Almanac extends WeatherDisplay {
|
|||||||
fill.type = MoonPhase.phase;
|
fill.type = MoonPhase.phase;
|
||||||
fill.icon = { type: 'img', src: this.iconPaths[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');
|
const daysContainer = this.elem.querySelector('.moon .days');
|
||||||
@@ -181,19 +223,16 @@ const imageName = (type) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatTimesForColumn = (times) => {
|
const formatTimeForColumn = (time) => {
|
||||||
const formatted = times.map((dt) => dt.setZone(timeZone()).toFormat('h:mm a').toUpperCase());
|
// moonrise and set may not have a time each day
|
||||||
|
if (!time.isValid) return '-';
|
||||||
// Check if any time has a 2-digit hour (starts with '1')
|
const formatted = time.setZone(timeZone()).toFormat('h:mm a').toUpperCase();
|
||||||
const hasTwoDigitHour = formatted.some((time) => time.startsWith('1'));
|
|
||||||
|
|
||||||
// If mixed digit lengths, pad single-digit hours with non-breaking space
|
// If mixed digit lengths, pad single-digit hours with non-breaking space
|
||||||
if (hasTwoDigitHour) {
|
if (formatted.length === 8) {
|
||||||
return formatted.map((time) => (time.startsWith('1') ? time : `\u00A0${time}`));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, no padding needed
|
|
||||||
return formatted;
|
return formatted;
|
||||||
|
}
|
||||||
|
return `\u00A0${formatted}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
// register display
|
// register display
|
||||||
|
|||||||
@@ -4,10 +4,15 @@
|
|||||||
#almanac-html.weather-display {
|
#almanac-html.weather-display {
|
||||||
background-image: url('../images/backgrounds/3.png');
|
background-image: url('../images/backgrounds/3.png');
|
||||||
|
|
||||||
// repeat the background if wide-enhanced
|
// change the backgrounds for enhanced modes
|
||||||
.wide.enhanced & {
|
.wide.enhanced & {
|
||||||
background-image: url('../images/backgrounds/3-wide-enhanced.png');
|
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 {
|
.weather-display .main.almanac {
|
||||||
@@ -30,6 +35,10 @@
|
|||||||
grid-template-columns: repeat(4, auto);
|
grid-template-columns: repeat(4, auto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.portrait.enhanced & {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.grid-item {
|
.grid-item {
|
||||||
// Reset inherited styles that interfere with grid layout
|
// Reset inherited styles that interfere with grid layout
|
||||||
width: auto;
|
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 {
|
.moon {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 7px 50px;
|
padding: 7px 50px;
|
||||||
@@ -73,6 +99,8 @@
|
|||||||
.title {
|
.title {
|
||||||
color: c.$column-header-text;
|
color: c.$column-header-text;
|
||||||
padding-left: 13px;
|
padding-left: 13px;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.days {
|
.days {
|
||||||
@@ -93,6 +121,14 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
top: -10px;
|
top: -10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.wide-enhanced {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
.wide.enhanced & {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
server/styles/ws.min.css
vendored
2
server/styles/ws.min.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -14,6 +14,14 @@
|
|||||||
<div class="grid-item time set-1"></div>
|
<div class="grid-item time set-1"></div>
|
||||||
<div class="grid-item time set-2 wide-enhanced"></div>
|
<div class="grid-item time set-2 wide-enhanced"></div>
|
||||||
</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="moon">
|
||||||
<div class="title">Moon Data:</div>
|
<div class="title">Moon Data:</div>
|
||||||
<div class="days">
|
<div class="days">
|
||||||
@@ -23,5 +31,13 @@
|
|||||||
<div class="date"></div>
|
<div class="date"></div>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
||||||
</div>
|
</div>
|
||||||
Reference in New Issue
Block a user