${glyph}
${sign} ${this.period}
${dateLabel ? html`
${dateLabel}
` : nothing}
${
energy !== null
? html`
${this.t('Energy {{value}}/10', { value: energy })}
`
: nothing
}
${
// The sky strip below is the evidence for this paragraph; the paragraph
// is the read of it.
d.overview && !this.hideReadings
? html`${d.overview}
`
: nothing
}
${this.renderSky(d)}
${
// Five headed paragraphs and nothing else, so the block goes whole rather
// than leaving five headings over nothing.
this.hideReadings
? nothing
: html`
${
d.love
? html`
${this.t('Love')}
${d.love}
`
: nothing
}
${
d.career
? html`
${this.t('Career')}
${d.career}
`
: nothing
}
${
d.health
? html`
${this.t('Health')}
${d.health}
`
: nothing
}
${
d.finance
? html`
${this.t('Finance')}
${d.finance}
`
: nothing
}
${
'advice' in d && d.advice
? html`
${this.t('Advice')}
${d.advice}
`
: nothing
}
`
}
${this.renderMonth(d)}
${(() => {
const luckyNumber =
'luckyNumber' in d && d.luckyNumber !== undefined
? d.luckyNumber
: undefined;
const luckyColor =
'luckyColor' in d && d.luckyColor ? d.luckyColor : '';
const luckyNumbers =
'luckyNumbers' in d && d.luckyNumbers ? d.luckyNumbers : [];
const luckyDays = 'luckyDays' in d && d.luckyDays ? d.luckyDays : [];
const compatibleSigns = d.compatibleSigns ?? [];
if (
luckyNumber === undefined &&
!luckyColor &&
luckyNumbers.length === 0 &&
luckyDays.length === 0 &&
compatibleSigns.length === 0
)
return nothing;
return html`
${
luckyNumber !== undefined
? html`${this.t('Lucky number')} ${luckyNumber}`
: nothing
}
${
luckyColor
? html`${this.t('Lucky color')} ${luckyColor}`
: nothing
}
${
luckyNumbers.length
? html`${this.t('Lucky numbers')}
${luckyNumbers.join(', ')}`
: nothing
}
${
luckyDays.length
? html`${this.t('Lucky days')} ${luckyDays.join(', ')}`
: nothing
}
${
compatibleSigns.length
? html`
${this.t('Best with')}
${compatibleSigns.map(
(s) => html`${s}`,
)}
`
: nothing
}
`;
})()}
`;
}
/**
* The sky behind the reading (daily only): where the Moon is, what phase it is in, and the transits the forecast was derived from. A daily horoscope that hides its transits is a fortune cookie; showing them is what makes this one auditable.
*/
private renderSky(d: HoroscopeData) {
const moonSign = 'moonSign' in d ? d.moonSign : '';
const moonPhase = 'moonPhase' in d ? d.moonPhase : '';
const transits = ('activeTransits' in d ? d.activeTransits : []) ?? [];
if (!moonSign && !moonPhase && transits.length === 0) return nothing;
const glyph = signGlyph(moonSign) ?? '';
return html`
${
moonSign || moonPhase
? html`
${
moonSign
? html`${this.t('Moon')}
${glyph} ${moonSign}`
: nothing
}
${
moonPhase
? html`${this.t('Phase')} ${moonPhase}`
: nothing
}
`
: nothing
}
${
transits.length
? html`
${transits.map((t) => html`- ${t}
`)}
`
: nothing
}
`;
}
/** Monthly arc: the week-by-week focus and the dated events (lunations, retrogrades, ingresses) the month turns on. */
private renderMonth(d: HoroscopeData) {
const weeks = ('weekByWeek' in d ? d.weekByWeek : []) ?? [];
const keyDates = ('keyDates' in d ? d.keyDates : []) ?? [];
if (weeks.length === 0 && keyDates.length === 0) return nothing;
return html`${
// Each week is a focus phrase and a line of advice, so the block is prose
// under its own heading and goes whole.
weeks.length && !this.hideReadings
? html`