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
+
+
+ +
+
+
+
Reader +
+ + + + + +
+ Font Size + +
@@ -1416,7 +1453,7 @@ - + @@ -1434,7 +1471,7 @@ - +