update text and now panel

This commit is contained in:
2026-03-10 14:55:01 -07:00
parent 28d9573154
commit 31b94b818b
4 changed files with 565 additions and 127 deletions

View File

@@ -1183,13 +1183,15 @@
gap: 12px;
align-items: start;
}
.planet-meta-card {
.planet-meta-card,
.detail-meta-card {
border: 1px solid #3f3f46;
border-radius: 10px;
padding: 10px;
background: #111118;
}
.planet-meta-card strong {
.planet-meta-card strong,
.detail-meta-card strong {
display: block;
margin-bottom: 8px;
color: #a1a1aa;
@@ -3173,9 +3175,36 @@
.alpha-text-controls {
display: grid;
gap: 10px;
padding: 12px;
border-top: 1px solid #27272a;
background: #101018;
}
.alpha-text-detail-heading {
display: grid;
gap: 14px;
padding-right: 108px;
}
.alpha-text-heading-main {
display: grid;
gap: 4px;
}
.alpha-text-heading-tools {
display: grid;
grid-template-columns: minmax(260px, 420px) minmax(320px, 1fr);
gap: 12px;
align-items: stretch;
}
.alpha-text-controls--heading {
grid-template-columns: repeat(2, minmax(0, 1fr));
padding: 14px;
border: 1px solid #2f2f39;
border-radius: 14px;
background:
linear-gradient(180deg, rgba(24, 24, 38, 0.98), rgba(12, 12, 18, 0.98));
box-shadow: inset 0 0 0 1px rgba(99, 102, 241, 0.08);
box-sizing: border-box;
align-content: start;
}
.alpha-text-search-controls {
@@ -3197,6 +3226,36 @@
background:
linear-gradient(180deg, rgba(24, 24, 38, 0.98), rgba(12, 12, 18, 0.98));
box-shadow: inset 0 0 0 1px rgba(99, 102, 241, 0.08);
box-sizing: border-box;
}
.alpha-text-search-controls--heading {
align-content: start;
height: 100%;
}
.alpha-text-search-inline {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 8px;
align-items: stretch;
}
.alpha-text-search-submit-inline {
min-height: 42px;
padding: 0 14px;
display: inline-flex;
align-items: center;
justify-content: center;
white-space: nowrap;
box-sizing: border-box;
}
.alpha-text-detail-heading .detail-toggle-inline {
position: absolute;
top: 0;
right: 0;
margin-left: 0;
}
.alpha-text-control {
@@ -3212,6 +3271,7 @@
.alpha-text-select {
width: 100%;
min-height: 42px;
padding: 7px 8px;
border-radius: 6px;
border: 1px solid #3f3f46;
@@ -3223,6 +3283,7 @@
.alpha-text-search-input {
width: 100%;
min-height: 42px;
padding: 9px 10px;
border-radius: 8px;
border: 1px solid #4338ca;
@@ -3269,6 +3330,31 @@
min-width: 0;
}
@media (max-width: 1040px) {
.alpha-text-heading-tools {
grid-template-columns: 1fr;
}
}
@media (max-width: 720px) {
.alpha-text-detail-heading {
padding-right: 0;
}
.alpha-text-controls--heading {
grid-template-columns: 1fr;
}
.alpha-text-search-inline {
grid-template-columns: 1fr;
}
.alpha-text-detail-heading .detail-toggle-inline {
position: static;
justify-self: start;
}
}
.alpha-text-meta-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
@@ -3276,6 +3362,30 @@
align-items: start;
}
.alpha-text-extra-card {
align-content: start;
}
.alpha-text-extra-group {
display: grid;
gap: 6px;
}
.alpha-text-extra-group + .alpha-text-extra-group {
margin-top: 10px;
}
.alpha-text-extra-label {
color: #a1a1aa;
font-size: 11px;
letter-spacing: 0.03em;
text-transform: uppercase;
}
.alpha-text-extra-actions {
margin-top: 0;
}
.alpha-text-toolbar {
display: flex;
flex-wrap: wrap;
@@ -3289,6 +3399,24 @@
gap: 0;
}
.alpha-text-reader-card {
display: grid;
gap: 0;
}
.alpha-text-reader-navigation {
display: flex;
gap: 8px;
align-items: center;
margin-top: 16px;
padding-top: 12px;
border-top: 1px solid #27272a;
}
.alpha-text-reader-nav-btn--next {
margin-left: auto;
}
.alpha-text-search-summary {
margin: 0 0 10px;
color: #a1a1aa;
@@ -3410,6 +3538,16 @@
line-height: 1.65;
}
.alpha-text-verse-text--original {
color: #f5f3ff;
font-family: var(--font-script-arabic), "Noto Serif", serif;
}
.alpha-text-verse-text--transliteration {
color: #cbd5f5;
font-style: italic;
}
.alpha-text-token-grid {
display: flex;
flex-wrap: wrap;
@@ -4629,11 +4767,11 @@
font-weight: 700;
}
.now-stats-sabian {
font-size: clamp(17px, 2.5vmin, 23px);
font-weight: 550;
line-height: 1.32;
font-size: clamp(13px, 1.75vmin, 16px);
font-weight: 500;
line-height: 1.42;
color: #f8fafc;
white-space: pre-line;
white-space: normal;
overflow: visible;
max-height: none;
}

View File

@@ -25,17 +25,16 @@
searchLoading: false,
searchError: "",
searchRequestId: 0,
highlightedVerseId: ""
highlightedVerseId: "",
displayPreferencesBySource: {}
};
let sourceListEl;
let sourceCountEl;
let globalSearchFormEl;
let globalSearchInputEl;
let globalSearchClearEl;
let localSearchFormEl;
let localSearchInputEl;
let localSearchClearEl;
let workSelectEl;
let sectionSelectEl;
let detailNameEl;
@@ -59,10 +58,8 @@
sourceCountEl = document.getElementById("alpha-text-source-count");
globalSearchFormEl = document.getElementById("alpha-text-global-search-form");
globalSearchInputEl = document.getElementById("alpha-text-global-search-input");
globalSearchClearEl = document.getElementById("alpha-text-global-search-clear");
localSearchFormEl = document.getElementById("alpha-text-local-search-form");
localSearchInputEl = document.getElementById("alpha-text-local-search-input");
localSearchClearEl = document.getElementById("alpha-text-local-search-clear");
workSelectEl = document.getElementById("alpha-text-work-select");
sectionSelectEl = document.getElementById("alpha-text-section-select");
detailNameEl = document.getElementById("alpha-text-detail-name");
@@ -151,6 +148,82 @@
return findById(work?.sections, state.selectedSectionId);
}
function normalizeTextValue(value) {
return String(value || "").trim();
}
const GREEK_TRANSLITERATION_MAP = {
α: "a", β: "b", γ: "g", δ: "d", ε: "e", ζ: "z", η: "e", θ: "th",
ι: "i", κ: "k", λ: "l", μ: "m", ν: "n", ξ: "x", ο: "o", π: "p",
ρ: "r", σ: "s", ς: "s", τ: "t", υ: "u", φ: "ph", χ: "ch", ψ: "ps",
ω: "o"
};
const HEBREW_TRANSLITERATION_MAP = {
א: "a", ב: "b", ג: "g", ד: "d", ה: "h", ו: "v", ז: "z", ח: "ch",
ט: "t", י: "y", כ: "k", ך: "k", ל: "l", מ: "m", ם: "m", נ: "n",
ן: "n", ס: "s", ע: "a", פ: "p", ף: "p", צ: "ts", ץ: "ts", ק: "q",
ר: "r", ש: "sh", ת: "t"
};
function stripSourceScriptMarks(value) {
return String(value || "")
.normalize("NFD")
.replace(/[\u0300-\u036f\u0591-\u05c7]/g, "");
}
function transliterateSourceScriptText(value) {
const stripped = stripSourceScriptMarks(value);
let result = "";
for (const character of stripped) {
const lowerCharacter = character.toLowerCase();
const mapped = GREEK_TRANSLITERATION_MAP[lowerCharacter]
|| HEBREW_TRANSLITERATION_MAP[character]
|| HEBREW_TRANSLITERATION_MAP[lowerCharacter];
result += mapped != null ? mapped : character;
}
return result
.replace(/\s+([,.;:!?])/g, "$1")
.replace(/\s+/g, " ")
.trim();
}
function buildTokenDerivedTransliteration(verse) {
const tokenText = (Array.isArray(verse?.tokens) ? verse.tokens : [])
.map((token) => normalizeTextValue(token?.original))
.filter(Boolean)
.join(" ")
.replace(/\s+([,.;:!?])/g, "$1")
.trim();
return tokenText ? transliterateSourceScriptText(tokenText) : "";
}
function getVerseTransliteration(verse, source = null) {
const metadata = verse?.metadata && typeof verse.metadata === "object" ? verse.metadata : {};
const explicit = [
verse?.transliteration,
verse?.xlit,
metadata?.transliteration,
metadata?.transliterationText,
metadata?.xlit,
metadata?.romanizedText,
metadata?.romanized
].map(normalizeTextValue).find(Boolean) || "";
if (explicit) {
return explicit;
}
if (source?.features?.hasTokenAnnotations) {
return buildTokenDerivedTransliteration(verse);
}
return "";
}
function getSearchInput(scope) {
return scope === "source" ? localSearchInputEl : globalSearchInputEl;
}
@@ -169,12 +242,131 @@
}
function updateSearchControls() {
if (globalSearchClearEl instanceof HTMLButtonElement) {
globalSearchClearEl.disabled = !String(globalSearchInputEl?.value || state.globalSearchQuery || "").trim();
return;
}
function clearActiveSearchUi(options = {}) {
const preserveHighlight = options.preserveHighlight === true;
const scope = state.activeSearchScope === "source" ? "source" : "global";
setStoredSearchQuery(scope, "");
const input = getSearchInput(scope);
if (input instanceof HTMLInputElement) {
input.value = "";
}
if (localSearchClearEl instanceof HTMLButtonElement) {
localSearchClearEl.disabled = !String(localSearchInputEl?.value || state.localSearchQuery || "").trim();
state.searchQuery = "";
state.searchResults = null;
state.searchLoading = false;
state.searchError = "";
state.searchRequestId += 1;
if (!preserveHighlight) {
state.highlightedVerseId = "";
}
updateSearchControls();
}
function getSourceDisplayCapabilities(source, passage) {
const verses = Array.isArray(passage?.verses) ? passage.verses : [];
const hasOriginal = verses.some((verse) => normalizeTextValue(verse?.originalText));
const hasTransliteration = verses.some((verse) => getVerseTransliteration(verse, source));
const hasInterlinear = Boolean(source?.features?.hasTokenAnnotations);
const textModeCount = 1 + (hasOriginal ? 1 : 0) + (hasTransliteration ? 1 : 0);
return {
hasTranslation: true,
hasOriginal,
hasTransliteration,
hasInterlinear,
hasAnyExtras: hasOriginal || hasTransliteration || hasInterlinear,
supportsAllTextMode: textModeCount > 1
};
}
function getDefaultTextDisplayMode(capabilities) {
if (capabilities?.hasTranslation) {
return "translation";
}
if (capabilities?.hasOriginal) {
return "original";
}
if (capabilities?.hasTransliteration) {
return "transliteration";
}
return "translation";
}
function getAvailableTextDisplayModes(capabilities) {
const modes = [];
if (capabilities?.hasTranslation) {
modes.push("translation");
}
if (capabilities?.hasOriginal) {
modes.push("original");
}
if (capabilities?.hasTransliteration) {
modes.push("transliteration");
}
if (capabilities?.supportsAllTextMode) {
modes.push("all");
}
return modes;
}
function getSourceDisplayPreferences(source, passage) {
const sourceId = normalizeId(source?.id);
const capabilities = getSourceDisplayCapabilities(source, passage);
const availableTextModes = getAvailableTextDisplayModes(capabilities);
const stored = sourceId ? state.displayPreferencesBySource[sourceId] : null;
let textMode = stored?.textMode;
if (!availableTextModes.includes(textMode)) {
textMode = getDefaultTextDisplayMode(capabilities);
}
const preferences = {
textMode,
showInterlinear: capabilities.hasInterlinear ? Boolean(stored?.showInterlinear) : false
};
if (sourceId) {
state.displayPreferencesBySource[sourceId] = preferences;
}
return {
...preferences,
capabilities,
availableTextModes
};
}
function updateSourceDisplayPreferences(source, patch) {
const sourceId = normalizeId(source?.id);
if (!sourceId) {
return;
}
const current = state.displayPreferencesBySource[sourceId] || {};
state.displayPreferencesBySource[sourceId] = {
...current,
...patch
};
}
function formatTextDisplayModeLabel(mode) {
switch (mode) {
case "translation":
return "Translation";
case "original":
return "Original";
case "transliteration":
return "Transliteration";
case "all":
return "All";
default:
return "Display";
}
}
@@ -269,7 +461,7 @@
function createCard(title) {
const card = document.createElement("div");
card.className = "planet-meta-card";
card.className = "detail-meta-card planet-meta-card";
if (title) {
const heading = document.createElement("strong");
heading.textContent = title;
@@ -302,6 +494,25 @@
detailBodyEl.appendChild(card);
}
function navigateToPassageTarget(target) {
if (!target) {
return;
}
state.selectedWorkId = target.workId;
state.selectedSectionId = target.sectionId;
state.lexiconEntry = null;
renderSelectors();
void loadSelectedPassage();
}
function getPassageLocationLabel(passage) {
const source = passage?.source || getSelectedSource();
const work = passage?.work || getSelectedWork(source);
const section = passage?.section || getSelectedSection(source, work);
return `${work?.title || "--"} · ${section?.title || section?.label || "--"}`;
}
function syncSelectionForSource(source) {
const works = Array.isArray(source?.works) ? source.works : [];
if (!works.length) {
@@ -739,6 +950,7 @@
const source = passage?.source || getSelectedSource();
const work = passage?.work || getSelectedWork(source);
const section = passage?.section || getSelectedSection(source, work);
const displayPreferences = getSourceDisplayPreferences(source, passage);
const metaGrid = document.createElement("div");
metaGrid.className = "alpha-text-meta-grid";
@@ -755,49 +967,68 @@
`;
metaGrid.appendChild(overviewCard);
const navigationCard = createCard("Navigation");
const toolbar = document.createElement("div");
toolbar.className = "alpha-text-toolbar";
if (displayPreferences.capabilities.hasAnyExtras) {
const extraCard = createCard("Extra");
extraCard.classList.add("alpha-text-extra-card");
const previousButton = document.createElement("button");
previousButton.type = "button";
previousButton.className = "alpha-nav-btn";
previousButton.textContent = "← Previous";
previousButton.disabled = !passage?.navigation?.previous;
previousButton.addEventListener("click", () => {
if (!passage?.navigation?.previous) {
return;
if (displayPreferences.availableTextModes.length > 1) {
const displayGroup = document.createElement("div");
displayGroup.className = "alpha-text-extra-group";
const displayLabel = document.createElement("span");
displayLabel.className = "alpha-text-extra-label";
displayLabel.textContent = "Display";
const displayButtons = document.createElement("div");
displayButtons.className = "alpha-nav-btns alpha-text-extra-actions";
displayPreferences.availableTextModes.forEach((mode) => {
const button = document.createElement("button");
button.type = "button";
button.className = "alpha-nav-btn";
button.textContent = formatTextDisplayModeLabel(mode);
button.setAttribute("aria-pressed", displayPreferences.textMode === mode ? "true" : "false");
button.classList.toggle("is-selected", displayPreferences.textMode === mode);
button.addEventListener("click", () => {
updateSourceDisplayPreferences(source, { textMode: mode });
renderDetail();
});
displayButtons.appendChild(button);
});
displayGroup.append(displayLabel, displayButtons);
extraCard.appendChild(displayGroup);
}
state.selectedWorkId = passage.navigation.previous.workId;
state.selectedSectionId = passage.navigation.previous.sectionId;
state.lexiconEntry = null;
renderSelectors();
void loadSelectedPassage();
});
const nextButton = document.createElement("button");
nextButton.type = "button";
nextButton.className = "alpha-nav-btn";
nextButton.textContent = "Next →";
nextButton.disabled = !passage?.navigation?.next;
nextButton.addEventListener("click", () => {
if (!passage?.navigation?.next) {
return;
if (displayPreferences.capabilities.hasInterlinear) {
const interlinearGroup = document.createElement("div");
interlinearGroup.className = "alpha-text-extra-group";
const interlinearLabel = document.createElement("span");
interlinearLabel.className = "alpha-text-extra-label";
interlinearLabel.textContent = "Reader";
const interlinearButtons = document.createElement("div");
interlinearButtons.className = "alpha-nav-btns alpha-text-extra-actions";
const interlinearButton = document.createElement("button");
interlinearButton.type = "button";
interlinearButton.className = "alpha-nav-btn";
interlinearButton.textContent = "Interlinear";
interlinearButton.setAttribute("aria-pressed", displayPreferences.showInterlinear ? "true" : "false");
interlinearButton.classList.toggle("is-selected", displayPreferences.showInterlinear);
interlinearButton.addEventListener("click", () => {
updateSourceDisplayPreferences(source, { showInterlinear: !displayPreferences.showInterlinear });
renderDetail();
});
interlinearButtons.appendChild(interlinearButton);
interlinearGroup.append(interlinearLabel, interlinearButtons);
extraCard.appendChild(interlinearGroup);
}
state.selectedWorkId = passage.navigation.next.workId;
state.selectedSectionId = passage.navigation.next.sectionId;
state.lexiconEntry = null;
renderSelectors();
void loadSelectedPassage();
});
const location = document.createElement("div");
location.className = "planet-text";
location.textContent = `${work?.title || "--"} · ${section?.title || "--"}`;
toolbar.append(previousButton, nextButton);
navigationCard.append(toolbar, location);
metaGrid.appendChild(navigationCard);
metaGrid.appendChild(extraCard);
}
if (source?.features?.hasTokenAnnotations) {
const noteCard = createCard("Reader Mode");
@@ -809,6 +1040,8 @@
}
function createPlainVerse(verse) {
const source = getSelectedSource();
const displayPreferences = getSourceDisplayPreferences(source, state.currentPassage);
const article = document.createElement("article");
article.className = "alpha-text-verse";
article.classList.toggle("is-highlighted", isHighlightedVerse(verse));
@@ -820,12 +1053,9 @@
reference.className = "alpha-text-verse-reference";
reference.textContent = verse.reference || (verse.number ? `Verse ${verse.number}` : "");
const text = document.createElement("p");
text.className = "alpha-text-verse-text";
appendHighlightedText(text, verse.text || "", isHighlightedVerse(verse) ? state.searchQuery : "");
head.append(reference);
article.append(head, text);
article.append(head);
appendVerseTextLines(article, verse, source, displayPreferences, verse.text || "");
return article;
}
@@ -840,9 +1070,52 @@
return glossText || String(fallbackText || "").trim();
}
function createTokenVerse(verse, lexiconId) {
function appendVerseTextLines(target, verse, source, displayPreferences, translationText) {
if (!(target instanceof HTMLElement)) {
return;
}
const mode = displayPreferences?.textMode || "translation";
const originalText = normalizeTextValue(verse?.originalText);
const transliterationText = getVerseTransliteration(verse, source);
const lines = [];
const appendLine = (text, variant) => {
const normalizedText = normalizeTextValue(text);
if (!normalizedText || lines.some((entry) => entry.text === normalizedText)) {
return;
}
lines.push({ text: normalizedText, variant });
};
if (mode === "all") {
appendLine(translationText, "translation");
appendLine(originalText, "original");
appendLine(transliterationText, "transliteration");
} else if (mode === "original") {
appendLine(originalText || translationText, originalText ? "original" : "translation");
} else if (mode === "transliteration") {
appendLine(transliterationText || translationText, transliterationText ? "transliteration" : "translation");
} else {
appendLine(translationText, "translation");
}
if (!lines.length) {
appendLine(translationText, "translation");
}
lines.forEach((line) => {
const text = document.createElement("p");
text.className = `alpha-text-verse-text alpha-text-verse-text--${line.variant}`;
appendHighlightedText(text, line.text, isHighlightedVerse(verse) ? state.searchQuery : "");
target.appendChild(text);
});
}
function createTokenVerse(verse, lexiconId, displayPreferences, source) {
const article = document.createElement("article");
article.className = "alpha-text-verse alpha-text-verse--interlinear";
article.className = "alpha-text-verse";
article.classList.toggle("alpha-text-verse--interlinear", Boolean(displayPreferences?.showInterlinear));
article.classList.toggle("is-highlighted", isHighlightedVerse(verse));
const head = document.createElement("div");
@@ -852,14 +1125,6 @@
reference.className = "alpha-text-verse-reference";
reference.textContent = verse.reference || (verse.number ? `Verse ${verse.number}` : "");
const gloss = document.createElement("p");
gloss.className = "alpha-text-verse-text";
appendHighlightedText(
gloss,
buildTokenTranslationText(verse?.tokens, verse?.text),
isHighlightedVerse(verse) ? state.searchQuery : ""
);
const tokenGrid = document.createElement("div");
tokenGrid.className = "alpha-text-token-grid";
@@ -895,13 +1160,19 @@
});
head.append(reference);
article.append(head, gloss, tokenGrid);
article.append(head);
appendVerseTextLines(article, verse, source, displayPreferences, buildTokenTranslationText(verse?.tokens, verse?.text));
if (displayPreferences?.showInterlinear) {
article.appendChild(tokenGrid);
}
return article;
}
function createReaderCard(passage) {
const source = passage?.source || getSelectedSource();
const card = createCard(`${source?.title || "Text"} Reader`);
const displayPreferences = getSourceDisplayPreferences(source, passage);
const card = createCard(getPassageLocationLabel(passage));
card.classList.add("alpha-text-reader-card");
const reader = document.createElement("div");
reader.className = "alpha-text-reader";
@@ -920,12 +1191,42 @@
verses.forEach((verse) => {
const verseEl = source?.features?.hasTokenAnnotations
? createTokenVerse(verse, source.features.lexiconIds?.[0] || "")
? createTokenVerse(verse, source.features.lexiconIds?.[0] || "", displayPreferences, source)
: createPlainVerse(verse);
reader.appendChild(verseEl);
});
card.appendChild(reader);
const navigation = document.createElement("div");
navigation.className = "alpha-text-reader-navigation";
if (passage?.navigation?.previous) {
const previousButton = document.createElement("button");
previousButton.type = "button";
previousButton.className = "alpha-nav-btn alpha-text-reader-nav-btn";
previousButton.textContent = "← Previous";
previousButton.addEventListener("click", () => {
navigateToPassageTarget(passage.navigation.previous);
});
navigation.appendChild(previousButton);
}
if (passage?.navigation?.next) {
const nextButton = document.createElement("button");
nextButton.type = "button";
nextButton.className = "alpha-nav-btn alpha-text-reader-nav-btn alpha-text-reader-nav-btn--next";
nextButton.textContent = "Next →";
nextButton.addEventListener("click", () => {
navigateToPassageTarget(passage.navigation.next);
});
navigation.appendChild(nextButton);
}
if (navigation.childElementCount) {
card.appendChild(navigation);
}
return card;
}
@@ -1168,6 +1469,8 @@
renderSourceList();
renderSelectors();
await loadSelectedPassage();
clearActiveSearchUi({ preserveHighlight: true });
renderDetail();
}
function bindControls() {
@@ -1193,13 +1496,6 @@
});
}
if (globalSearchClearEl instanceof HTMLButtonElement) {
globalSearchClearEl.addEventListener("click", () => {
clearScopedSearch("global");
renderDetail();
});
}
if (localSearchFormEl instanceof HTMLFormElement) {
localSearchFormEl.addEventListener("submit", (event) => {
event.preventDefault();
@@ -1218,13 +1514,6 @@
});
}
if (localSearchClearEl instanceof HTMLButtonElement) {
localSearchClearEl.addEventListener("click", () => {
clearScopedSearch("source");
renderDetail();
});
}
if (workSelectEl) {
workSelectEl.addEventListener("change", () => {
state.selectedWorkId = String(workSelectEl.value || "");

View File

@@ -27,6 +27,18 @@
let moonCountdownCache = null;
let decanCountdownCache = null;
function joinSabianPhrases(phrases) {
const parts = (Array.isArray(phrases) ? phrases : [])
.map((phrase) => String(phrase || "").trim())
.filter(Boolean);
if (!parts.length) {
return "--";
}
return parts.join(" ");
}
function renderNowStatsFromSnapshot(elements, stats) {
if (elements.nowStatsPlanetsEl) {
elements.nowStatsPlanetsEl.replaceChildren();
@@ -47,13 +59,10 @@
if (elements.nowStatsSabianEl) {
const sunSabianSymbol = stats?.sunSabianSymbol || null;
const moonSabianSymbol = stats?.moonSabianSymbol || null;
const sunLine = sunSabianSymbol?.phrase
? `Sun Sabian ${sunSabianSymbol.absoluteDegree}: ${sunSabianSymbol.phrase}`
: "Sun Sabian: --";
const moonLine = moonSabianSymbol?.phrase
? `Moon Sabian ${moonSabianSymbol.absoluteDegree}: ${moonSabianSymbol.phrase}`
: "Moon Sabian: --";
elements.nowStatsSabianEl.textContent = `${sunLine}\n${moonLine}`;
elements.nowStatsSabianEl.textContent = joinSabianPhrases([
moonSabianSymbol?.phrase,
sunSabianSymbol?.phrase
]);
}
}