diff --git a/app/styles.css b/app/styles.css
index 02983aa..f83eae8 100644
--- a/app/styles.css
+++ b/app/styles.css
@@ -5863,6 +5863,45 @@
min-width: 0;
}
+ .alpha-text-font-size-control {
+ display: flex;
+ gap: 10px;
+ align-items: center;
+ color: #e4e4e7;
+ font-size: 13px;
+ flex-wrap: wrap;
+ }
+
+ .alpha-text-font-size-control .alpha-text-select {
+ width: auto;
+ padding: 4px 10px;
+ font-size: 12px;
+ }
+
+ .alpha-text-font-small .alpha-text-verse-text {
+ font-size: 14px;
+ }
+
+ .alpha-text-font-small .alpha-text-verse-text--original {
+ font-size: 16px;
+ }
+
+ .alpha-text-font-large .alpha-text-verse-text {
+ font-size: 18px;
+ }
+
+ .alpha-text-font-large .alpha-text-verse-text--original {
+ font-size: 22px;
+ }
+
+ .alpha-text-font-xlarge .alpha-text-verse-text {
+ font-size: 21px;
+ }
+
+ .alpha-text-font-xlarge .alpha-text-verse-text--original {
+ font-size: 26px;
+ }
+
.alpha-text-search-controls--detail {
padding: 14px;
border: 1px solid #2f2f39;
diff --git a/app/ui-alphabet-text.js b/app/ui-alphabet-text.js
index dac9168..e4be4e9 100644
--- a/app/ui-alphabet-text.js
+++ b/app/ui-alphabet-text.js
@@ -3,7 +3,13 @@
const dataService = window.TarotDataService || {};
const STORAGE_KEYS = {
- showVerseHeads: "tarotime.alphaText.showVerseHeads"
+ showVerseHeads: "tarotime.alphaText.showVerseHeads",
+ showSourceOverview: "tarotime.alphaText.showSourceOverview",
+ showEntryTotals: "tarotime.alphaText.showEntryTotals",
+ showLocalSearch: "tarotime.alphaText.showLocalSearch",
+ showWorkSection: "tarotime.alphaText.showWorkSection",
+ showExtraCard: "tarotime.alphaText.showExtraCard",
+ readerFontSize: "tarotime.alphaText.readerFontSize"
};
function readStoredBoolean(key, fallback) {
@@ -30,6 +36,27 @@
}
}
+ function readStoredString(key, fallback) {
+ try {
+ const value = window.localStorage?.getItem?.(key);
+ if (value) {
+ return value;
+ }
+ } catch (error) {
+ // Ignore storage failures.
+ }
+
+ return fallback;
+ }
+
+ function writeStoredString(key, value) {
+ try {
+ window.localStorage?.setItem?.(key, value);
+ } catch (error) {
+ // Ignore storage failures.
+ }
+ }
+
const state = {
initialized: false,
catalog: null,
@@ -59,7 +86,13 @@
searchRequestId: 0,
highlightedVerseId: "",
displayPreferencesBySource: {},
- showVerseHeads: readStoredBoolean(STORAGE_KEYS.showVerseHeads, true)
+ showVerseHeads: readStoredBoolean(STORAGE_KEYS.showVerseHeads, true),
+ showSourceOverview: readStoredBoolean(STORAGE_KEYS.showSourceOverview, true),
+ showEntryTotals: readStoredBoolean(STORAGE_KEYS.showEntryTotals, true),
+ showLocalSearch: readStoredBoolean(STORAGE_KEYS.showLocalSearch, true),
+ showWorkSection: readStoredBoolean(STORAGE_KEYS.showWorkSection, true),
+ showExtraCard: readStoredBoolean(STORAGE_KEYS.showExtraCard, true),
+ readerFontSize: readStoredString(STORAGE_KEYS.readerFontSize, "normal")
};
let sourceListEl;
@@ -85,6 +118,13 @@
let detailBodyEl;
let textLayoutEl;
let showVerseHeadsEl;
+ let showSourceOverviewEl;
+ let showEntryTotalsEl;
+ let showLocalSearchEl;
+ let showWorkSectionEl;
+ let showExtraCardEl;
+ let readerFontSizeSelectEl;
+ let exportButtonEl;
let lexiconPopupEl;
let lexiconPopupTitleEl;
let lexiconPopupSubtitleEl;
@@ -108,6 +148,13 @@
localSearchInputEl = document.getElementById("alpha-text-local-search-input");
localSearchClearEl = document.getElementById("alpha-text-local-search-clear");
showVerseHeadsEl = document.getElementById("alpha-text-show-verse-heads");
+ showSourceOverviewEl = document.getElementById("alpha-text-show-source-overview");
+ showEntryTotalsEl = document.getElementById("alpha-text-show-entry-totals");
+ showLocalSearchEl = document.getElementById("alpha-text-show-local-search");
+ showWorkSectionEl = document.getElementById("alpha-text-show-work-section");
+ showExtraCardEl = document.getElementById("alpha-text-show-extra-card");
+ readerFontSizeSelectEl = document.getElementById("alpha-text-font-size-select");
+ exportButtonEl = document.querySelector("#alphabet-text-section .detail-export-btn");
translationSelectEl = document.getElementById("alpha-text-translation-select");
translationControlEl = translationSelectEl?.closest?.(".alpha-text-control") || null;
compareSelectEl = document.getElementById("alpha-text-compare-select");
@@ -126,14 +173,66 @@
ensureLexiconPopup();
}
+ function toggleLocalSearchForm() {
+ if (localSearchFormEl) {
+ localSearchFormEl.style.display = state.showLocalSearch ? "" : "none";
+ }
+ }
+
+ function toggleWorkSectionSelects() {
+ const card = document.querySelector("#alphabet-text-section .alpha-text-controls--heading:not(.alpha-text-reader-panel)");
+ const workControl = workSelectEl?.closest?.(".alpha-text-control");
+ const sectionControl = sectionSelectEl?.closest?.(".alpha-text-control");
+ if (workControl instanceof HTMLElement) {
+ workControl.style.display = state.showWorkSection ? "" : "none";
+ }
+ if (sectionControl instanceof HTMLElement) {
+ sectionControl.style.display = state.showWorkSection ? "" : "none";
+ }
+ if (card instanceof HTMLElement) {
+ card.style.display = state.showWorkSection ? "" : "none";
+ }
+ }
+
function syncReaderDisplayControls() {
if (showVerseHeadsEl instanceof HTMLInputElement) {
showVerseHeadsEl.checked = Boolean(state.showVerseHeads);
}
+ if (showSourceOverviewEl instanceof HTMLInputElement) {
+ showSourceOverviewEl.checked = Boolean(state.showSourceOverview);
+ }
+
+ if (showEntryTotalsEl instanceof HTMLInputElement) {
+ showEntryTotalsEl.checked = Boolean(state.showEntryTotals);
+ }
+
+ if (showLocalSearchEl instanceof HTMLInputElement) {
+ showLocalSearchEl.checked = Boolean(state.showLocalSearch);
+ }
+
+ if (showWorkSectionEl instanceof HTMLInputElement) {
+ showWorkSectionEl.checked = Boolean(state.showWorkSection);
+ }
+
+ if (showExtraCardEl instanceof HTMLInputElement) {
+ showExtraCardEl.checked = Boolean(state.showExtraCard);
+ }
+
+ if (readerFontSizeSelectEl instanceof HTMLSelectElement) {
+ readerFontSizeSelectEl.value = state.readerFontSize;
+ }
+
+ toggleLocalSearchForm();
+ toggleWorkSectionSelects();
+
if (textLayoutEl instanceof HTMLElement) {
textLayoutEl.classList.toggle("alpha-text-hide-verse-heads", !state.showVerseHeads);
textLayoutEl.setAttribute("data-show-verse-heads", state.showVerseHeads ? "true" : "false");
+ textLayoutEl.classList.remove("alpha-text-font-small", "alpha-text-font-large", "alpha-text-font-xlarge");
+ if (state.readerFontSize !== "normal") {
+ textLayoutEl.classList.add(`alpha-text-font-${state.readerFontSize}`);
+ }
}
}
@@ -1445,6 +1544,7 @@
metaGrid.className = "alpha-text-meta-grid";
const overviewCard = createCard("Source Overview");
+ overviewCard.hidden = !state.showSourceOverview;
overviewCard.innerHTML += `
- Source
- ${source?.title || "--"}
@@ -1462,6 +1562,7 @@
metaGrid.appendChild(overviewCard);
const totalsCard = createCard("Entry Totals");
+ totalsCard.hidden = !state.showEntryTotals;
const totals = sumPassageCounts(passage, source, displayPreferences);
totalsCard.innerHTML += `
@@ -1476,6 +1577,8 @@
if (displayPreferences.capabilities.hasAnyExtras) {
const extraCard = createCard("Extra");
extraCard.classList.add("alpha-text-extra-card");
+ extraCard.hidden = !state.showExtraCard;
+
if (displayPreferences.availableTextModes.length > 1) {
const displayGroup = document.createElement("div");
@@ -1536,12 +1639,6 @@
metaGrid.appendChild(extraCard);
}
- if (source?.features?.hasTokenAnnotations) {
- const noteCard = createCard("Reader Mode");
- noteCard.appendChild(createEmptyMessage("This source is tokenized. Click a Strong's code chip to open its lexicon entry."));
- metaGrid.appendChild(noteCard);
- }
-
return metaGrid;
}
@@ -1698,24 +1795,61 @@
const navigation = document.createElement("div");
navigation.className = "alpha-text-reader-navigation";
- if (passage?.navigation?.previous) {
+ const passageSourceId = passage?.source?.id;
+ const passageWorkId = passage?.work?.id;
+ const passageSectionId = passage?.section?.id;
+ if (!passageSourceId || !passageWorkId || !passageSectionId) {
+ return null;
+ }
+
+ const catalogSource = findById(getSources(), passageSourceId);
+ if (!catalogSource) {
+ return null;
+ }
+
+ const catalogWork = findById(catalogSource.works, passageWorkId);
+ if (!catalogWork) {
+ return null;
+ }
+
+ const sections = Array.isArray(catalogWork.sections) ? catalogWork.sections : [];
+ const currentIndex = sections.findIndex(
+ (section) => normalizeId(section.id) === normalizeId(passageSectionId)
+ );
+ if (currentIndex < 0) {
+ return null;
+ }
+
+ if (currentIndex > 0) {
+ const previousSection = sections[currentIndex - 1];
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);
+ state.selectedSectionId = previousSection.id;
+ state.selectedWorkId = passageWorkId;
+ state.selectedSourceId = passageSourceId;
+ state.lexiconEntry = null;
+ renderSelectors();
+ void loadSelectedPassage();
});
navigation.appendChild(previousButton);
}
- if (passage?.navigation?.next) {
+ if (currentIndex >= 0 && currentIndex < sections.length - 1) {
+ const nextSection = sections[currentIndex + 1];
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);
+ state.selectedSectionId = nextSection.id;
+ state.selectedWorkId = passageWorkId;
+ state.selectedSourceId = passageSourceId;
+ state.lexiconEntry = null;
+ renderSelectors();
+ void loadSelectedPassage();
});
navigation.appendChild(nextButton);
}
@@ -2174,6 +2308,54 @@
});
}
+ if (showSourceOverviewEl instanceof HTMLInputElement) {
+ showSourceOverviewEl.addEventListener("change", () => {
+ state.showSourceOverview = Boolean(showSourceOverviewEl.checked);
+ writeStoredBoolean(STORAGE_KEYS.showSourceOverview, state.showSourceOverview);
+ renderDetail();
+ });
+ }
+
+ if (showEntryTotalsEl instanceof HTMLInputElement) {
+ showEntryTotalsEl.addEventListener("change", () => {
+ state.showEntryTotals = Boolean(showEntryTotalsEl.checked);
+ writeStoredBoolean(STORAGE_KEYS.showEntryTotals, state.showEntryTotals);
+ renderDetail();
+ });
+ }
+
+ if (showLocalSearchEl instanceof HTMLInputElement) {
+ showLocalSearchEl.addEventListener("change", () => {
+ state.showLocalSearch = Boolean(showLocalSearchEl.checked);
+ writeStoredBoolean(STORAGE_KEYS.showLocalSearch, state.showLocalSearch);
+ toggleLocalSearchForm();
+ });
+ }
+
+ if (showWorkSectionEl instanceof HTMLInputElement) {
+ showWorkSectionEl.addEventListener("change", () => {
+ state.showWorkSection = Boolean(showWorkSectionEl.checked);
+ writeStoredBoolean(STORAGE_KEYS.showWorkSection, state.showWorkSection);
+ toggleWorkSectionSelects();
+ });
+ }
+
+ if (showExtraCardEl instanceof HTMLInputElement) {
+ showExtraCardEl.addEventListener("change", () => {
+ state.showExtraCard = Boolean(showExtraCardEl.checked);
+ writeStoredBoolean(STORAGE_KEYS.showExtraCard, state.showExtraCard);
+ renderDetail();
+ });
+ }
+
+ if (readerFontSizeSelectEl instanceof HTMLSelectElement) {
+ readerFontSizeSelectEl.addEventListener("change", () => {
+ state.readerFontSize = readerFontSizeSelectEl.value;
+ writeStoredString(STORAGE_KEYS.readerFontSize, state.readerFontSize);
+ syncReaderDisplayControls();
+ });
+ }
+
if (translationSelectEl instanceof HTMLSelectElement) {
translationSelectEl.addEventListener("change", () => {
const sourceGroup = getSelectedSourceGroup();
@@ -2250,6 +2432,15 @@
}
});
+ if (exportButtonEl instanceof HTMLButtonElement) {
+ exportButtonEl.addEventListener("click", () => {
+ const detailPanel = document.querySelector("#alphabet-text-section .planet-detail-panel");
+ if (detailPanel instanceof HTMLElement) {
+ window.TarotChromeUi?.exportDetailPaneAsWebp?.(detailPanel, "alphabet-text-section", exportButtonEl);
+ }
+ });
+ }
+
state.initialized = true;
}
diff --git a/app/ui-chrome.js b/app/ui-chrome.js
index 601f3aa..587eac2 100644
--- a/app/ui-chrome.js
+++ b/app/ui-chrome.js
@@ -489,6 +489,10 @@
}
exportClone.querySelectorAll(".detail-pane-export-controls").forEach((node) => node.remove());
+ exportClone.querySelectorAll(".detail-sequence-btn:not(.detail-export-btn)").forEach((node) => { node.style.display = "none"; });
+ exportClone.querySelectorAll(".detail-sequence-position").forEach((node) => { node.style.display = "none"; });
+ exportClone.querySelectorAll(".alpha-text-reader-nav-btn").forEach((node) => { node.style.display = "none"; });
+ exportClone.querySelectorAll(".alpha-text-reader-panel").forEach((node) => { node.style.display = "none"; });
const contentWidth = Math.max(
320,
@@ -536,6 +540,10 @@
imageTimeout: 12000,
onclone(clonedDocument) {
clonedDocument.querySelectorAll(".detail-pane-export-controls").forEach((node) => node.remove());
+ clonedDocument.querySelectorAll(".detail-sequence-btn:not(.detail-export-btn)").forEach((node) => { node.style.display = "none"; });
+ clonedDocument.querySelectorAll(".detail-sequence-position").forEach((node) => { node.style.display = "none"; });
+ clonedDocument.querySelectorAll(".alpha-text-reader-nav-btn").forEach((node) => { node.style.display = "none"; });
+ clonedDocument.querySelectorAll(".alpha-text-reader-panel").forEach((node) => { node.style.display = "none"; });
}
});
@@ -791,6 +799,7 @@
setTopbarMenuOpen,
setTopbarDropdownOpen,
closeTopbarDropdowns,
- bindTopbarDropdownInteractions
+ bindTopbarDropdownInteractions,
+ exportDetailPaneAsWebp
};
})();
diff --git a/app/ui-home-calendar.js b/app/ui-home-calendar.js
index 3f529ed..dcd3511 100644
--- a/app/ui-home-calendar.js
+++ b/app/ui-home-calendar.js
@@ -37,6 +37,14 @@
};
}
+ function buildRoundedIsoTimestamp(stepMinutes = 5) {
+ const rounded = new Date();
+ const minute = rounded.getUTCMinutes();
+ const bucket = Math.floor(minute / stepMinutes) * stepMinutes;
+ rounded.setUTCMinutes(bucket, 0, 0);
+ return rounded.toISOString();
+ }
+
function buildStellariumObserverUrl(geo) {
const normalizedGeo = normalizeGeoForSky(geo);
if (!normalizedGeo) {
@@ -47,7 +55,7 @@
wrapperUrl.searchParams.set("lat", String(normalizedGeo.latitude));
wrapperUrl.searchParams.set("lng", String(normalizedGeo.longitude));
wrapperUrl.searchParams.set("elev", "0");
- wrapperUrl.searchParams.set("date", new Date().toISOString());
+ wrapperUrl.searchParams.set("date", buildRoundedIsoTimestamp(5));
wrapperUrl.searchParams.set("az", "0");
wrapperUrl.searchParams.set("alt", "90");
wrapperUrl.searchParams.set("fov", NOW_SKY_FOV_DEGREES);
diff --git a/index.html b/index.html
index 19a09e2..e0c24da 100644
--- a/index.html
+++ b/index.html
@@ -1113,6 +1113,11 @@
--
Select a text source to begin reading
+
+
+