From c6b95e23c7b875120b84be2c9ac94c1d0bf62751 Mon Sep 17 00:00:00 2001 From: Nose Date: Thu, 23 Jul 2026 00:15:21 -0700 Subject: [PATCH] update lots of reader fixes --- app.js | 9 +- app/app-runtime.js | 15 ++- app/data-service.js | 24 +++-- app/styles.css | 87 +++++++++++++++ app/ui-alphabet-text.js | 227 ++++++++++++++++++++++++++++++++++++---- app/ui-chrome.js | 107 ++++++++++++------- app/ui-home-calendar.js | 5 +- app/ui-navigation.js | 4 + app/ui-section-state.js | 9 +- index.html | 173 ++++++++++++++++-------------- 10 files changed, 510 insertions(+), 150 deletions(-) diff --git a/app.js b/app.js index 6db48c8..0f5c0e9 100644 --- a/app.js +++ b/app.js @@ -44,6 +44,7 @@ const tarotSectionEl = document.getElementById("tarot-section"); const tarotFrameSectionEl = document.getElementById("tarot-frame-section"); const tarotHouseSectionEl = document.getElementById("tarot-house-section"); const astronomySectionEl = document.getElementById("astronomy-section"); +const skySectionEl = document.getElementById("sky-section"); const natalSectionEl = document.getElementById("natal-section"); const planetSectionEl = document.getElementById("planet-section"); const cyclesSectionEl = document.getElementById("cycles-section"); @@ -96,6 +97,7 @@ const openNumbersEl = document.getElementById("open-numbers"); const openNumbersBrowseEl = document.getElementById("open-numbers-browse"); const openNumbersTheoryEl = document.getElementById("open-numbers-theory"); const openZodiacEl = document.getElementById("open-zodiac"); +const openSkyEl = document.getElementById("open-sky"); const openNatalEl = document.getElementById("open-natal"); const openQuizEl = document.getElementById("open-quiz"); const openGodsEl = document.getElementById("open-gods"); @@ -104,6 +106,7 @@ const latEl = document.getElementById("lat"); const lngEl = document.getElementById("lng"); const nowSkyLayerEl = document.getElementById("now-sky-layer"); const nowPanelEl = document.getElementById("now-panel"); +const homeWelcomeEl = document.getElementById("home-welcome"); const nowOverlayToggleEl = document.getElementById("now-overlay-toggle"); const connectionGateEl = document.getElementById("connection-gate"); const connectionGateBaseUrlEl = document.getElementById("connection-gate-base-url"); @@ -281,7 +284,7 @@ appRuntime.init?.({ calendarVisualsUi, homeUi, hasTarotAccess: () => hasTarotFeatureAccess(), - shouldPollNow: () => (sectionStateUi.getActiveSection?.() || "home") === "home" && document.hidden !== true, + shouldPollNow: () => (sectionStateUi.getActiveSection?.() || "home") === "sky" && document.hidden !== true, nowPollIntervalMs: 5 * 60 * 1000, onStatus: (text) => setStatus(text), services: { @@ -554,6 +557,7 @@ sectionStateUi.init?.({ calendarEl, monthStripEl, nowPanelEl, + homeWelcomeEl, settingsSectionEl, timelineSectionEl, calendarSectionEl, @@ -564,6 +568,7 @@ sectionStateUi.init?.({ tarotFrameSectionEl, tarotHouseSectionEl, astronomySectionEl, + skySectionEl, natalSectionEl, planetSectionEl, cyclesSectionEl, @@ -615,6 +620,7 @@ sectionStateUi.init?.({ openNumbersBrowseEl, openNumbersTheoryEl, openZodiacEl, + openSkyEl, openNatalEl, openQuizEl, openGodsEl, @@ -739,6 +745,7 @@ navigationUi.init?.({ openNumbersBrowseEl, openNumbersTheoryEl, openZodiacEl, + openSkyEl, openNatalEl, openQuizEl, openGodsEl, diff --git a/app/app-runtime.js b/app/app-runtime.js index 032a864..7663b99 100644 --- a/app/app-runtime.js +++ b/app/app-runtime.js @@ -126,11 +126,20 @@ function syncNowTickerState() { if (config.shouldPollNow?.() === false) { stopNowTicker(); + config.homeUi?.clearNowSkyBackground?.(); return; } if (!nowInterval && referenceData && currentGeo) { startNowTicker(); + return; + } + + if (nowInterval && referenceData && currentGeo) { + const now = new Date(); + config.homeUi?.syncNowPanelTheme?.(now); + void config.services.updateNowPanel?.(referenceData, currentGeo, config.nowElements, currentTimeFormat); + config.calendarVisualsUi?.applyDynamicNowIndicatorVisual?.(now); } } @@ -144,8 +153,10 @@ try { const tarotAccessEnabled = config.hasTarotAccess?.() === true; currentGeo = parseGeoInput(); - config.homeUi?.syncNowPanelTheme?.(new Date()); - config.homeUi?.syncNowSkyBackground?.(currentGeo); + if (config.shouldPollNow?.()) { + config.homeUi?.syncNowPanelTheme?.(new Date()); + config.homeUi?.syncNowSkyBackground?.(currentGeo); + } if (!referenceData || !magickDataset) { setStatus(tarotAccessEnabled diff --git a/app/data-service.js b/app/data-service.js index bf1a0ee..8b07130 100644 --- a/app/data-service.js +++ b/app/data-service.js @@ -133,18 +133,26 @@ : undefined; } - async function fetchJson(path) { + async function fetchJson(path, { timeoutMs = 30000 } = {}) { if (!path) { throw new Error("API connection is not configured."); } - const response = await fetch(path, { - headers: buildRequestHeaders() - }); - if (!response.ok) { - throw new Error(`Failed to load ${path} (${response.status})`); + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), timeoutMs); + + try { + const response = await fetch(path, { + headers: buildRequestHeaders(), + signal: controller.signal + }); + if (!response.ok) { + throw new Error(`Failed to load ${path} (${response.status})`); + } + return response.json(); + } finally { + clearTimeout(timeoutId); } - return response.json(); } function buildObjectPath(target, pathParts, value) { @@ -240,7 +248,7 @@ } const activeSection = String(window.TarotSectionStateUi?.getActiveSection?.() || "home").trim(); - return activeSection === "home"; + return activeSection === "home" || activeSection === "sky"; } function toApiAssetUrl(assetPath) { diff --git a/app/styles.css b/app/styles.css index f83eae8..64c59b6 100644 --- a/app/styles.css +++ b/app/styles.css @@ -5902,6 +5902,60 @@ font-size: 26px; } + .alpha-text-settings-popover { + position: absolute; + top: 100%; + right: 0; + z-index: 100; + min-width: 280px; + max-width: 380px; + margin-top: 6px; + } + + .alpha-text-settings-popover[hidden] { + display: none; + } + + .alpha-text-settings-popover-inner { + background: #1a1a26; + border: 1px solid #3f3f46; + border-radius: 10px; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); + overflow: hidden; + } + + .alpha-text-settings-popover-head { + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px 14px; + border-bottom: 1px solid #27272a; + color: #e4e4e7; + font-size: 13px; + } + + .alpha-text-settings-close { + background: none; + border: none; + color: #a1a1aa; + font-size: 18px; + cursor: pointer; + padding: 2px 6px; + line-height: 1; + } + + .alpha-text-settings-close:hover { + color: #e4e4e7; + } + + .alpha-text-settings-popover .alpha-text-reader-toggle-list { + padding: 10px 14px; + } + + .alpha-text-settings-popover .alpha-text-reader-toggle { + padding: 4px 0; + } + .alpha-text-search-controls--detail { padding: 14px; border: 1px solid #2f2f39; @@ -6032,6 +6086,20 @@ display: none !important; } + .planet-layout.alpha-text-global-search-only > .planet-detail-panel { + display: grid !important; + grid-template-rows: 1fr !important; + min-height: 0 !important; + overflow: auto !important; + } + + .planet-layout.alpha-text-global-search-only .alpha-text-detail-body { + display: block !important; + min-height: 120px !important; + visibility: visible !important; + opacity: 1 !important; + } + @media (max-width: 1040px) { .alpha-text-heading-tools { grid-template-columns: 1fr; @@ -6257,6 +6325,25 @@ box-shadow: inset 0 0 0 1px rgba(165, 180, 252, 0.22); } + .alpha-text-verse.is-highlighted-fresh { + animation: alpha-text-verse-pulse 2.5s ease-out; + } + + @keyframes alpha-text-verse-pulse { + 0% { + background: rgba(99, 102, 241, 0.35); + box-shadow: inset 0 0 0 2px rgba(165, 180, 252, 0.5), 0 0 24px rgba(99, 102, 241, 0.3); + } + 60% { + background: rgba(99, 102, 241, 0.2); + box-shadow: inset 0 0 0 1px rgba(165, 180, 252, 0.3), 0 0 8px rgba(99, 102, 241, 0.1); + } + 100% { + background: rgba(67, 56, 202, 0.18); + box-shadow: inset 0 0 0 1px rgba(165, 180, 252, 0.22); + } + } + .alpha-text-verse:first-child { border-top: none; padding-top: 0; diff --git a/app/ui-alphabet-text.js b/app/ui-alphabet-text.js index e4be4e9..6fa7695 100644 --- a/app/ui-alphabet-text.js +++ b/app/ui-alphabet-text.js @@ -85,6 +85,7 @@ searchError: "", searchRequestId: 0, highlightedVerseId: "", + highlightedVerseFresh: false, displayPreferencesBySource: {}, showVerseHeads: readStoredBoolean(STORAGE_KEYS.showVerseHeads, true), showSourceOverview: readStoredBoolean(STORAGE_KEYS.showSourceOverview, true), @@ -125,6 +126,8 @@ let showExtraCardEl; let readerFontSizeSelectEl; let exportButtonEl; + let settingsBtnEl; + let settingsPopoverEl; let lexiconPopupEl; let lexiconPopupTitleEl; let lexiconPopupSubtitleEl; @@ -132,6 +135,15 @@ let lexiconPopupCloseEl; let lexiconReturnFocusEl = null; + let searchTimer = null; + + function debounceRunSearch(scope) { + clearTimeout(searchTimer); + searchTimer = setTimeout(() => { + void runSearch(scope); + }, 300); + } + function normalizeId(value) { return String(value || "") .trim() @@ -155,6 +167,8 @@ 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"); + settingsBtnEl = document.getElementById("alpha-text-settings-btn"); + settingsPopoverEl = document.getElementById("alpha-text-settings-popover"); translationSelectEl = document.getElementById("alpha-text-translation-select"); translationControlEl = translationSelectEl?.closest?.(".alpha-text-control") || null; compareSelectEl = document.getElementById("alpha-text-compare-select"); @@ -757,7 +771,9 @@ input.value = ""; } - state.searchQuery = ""; + const keepQuery = preserveHighlight && state.searchQuery ? state.searchQuery : ""; + + state.searchQuery = preserveHighlight ? keepQuery : ""; state.searchResults = null; state.searchLoading = false; state.searchError = ""; @@ -766,8 +782,6 @@ if (!preserveHighlight) { state.highlightedVerseId = ""; } - - updateSearchControls(); } function getSourceDisplayCapabilities(source, passage) { @@ -1924,10 +1938,34 @@ return null; } - const card = createCard("Search Results"); + const payload = state.searchResults; + const totalMatches = Number(payload?.totalMatches) || 0; const scopeLabel = state.activeSearchScope === "global" ? "all texts" - : (state.searchResults?.scope?.source?.title || getSelectedSource()?.title || "current source"); + : (payload?.scope?.source?.title || getSelectedSource()?.title || "current source"); + + const card = createCard("Search Results"); + + const diagnostic = document.createElement("div"); + diagnostic.className = "alpha-text-search-diagnostic"; + diagnostic.style.cssText = "padding:12px 16px;border:2px solid #ef4444;border-radius:8px;margin-bottom:12px;font-size:13px;line-height:1.6;color:#fca5a5;background:#1a0a0a"; + + const lines = [ + `Query: "${state.searchQuery || "--"}"`, + `Scope: ${scopeLabel}`, + state.searchLoading + ? `Status: Searching...` + : state.searchError + ? `Status: Error: ${state.searchError}` + : totalMatches > 0 + ? `Status: Found ${totalMatches} match${totalMatches !== 1 ? "es" : ""}${payload?.truncated ? ` (showing ${payload.resultCount})` : ""}` + : `Status: No matches found`, + payload ? `API Response: totalMatches=${totalMatches} resultCount=${payload.resultCount} truncated=${payload.truncated} results.length=${Array.isArray(payload.results) ? payload.results.length : "N/A"}` : "", + `` + ].filter(Boolean); + + diagnostic.innerHTML = lines.join("
"); + card.appendChild(diagnostic); const summary = document.createElement("p"); summary.className = "alpha-text-search-summary"; @@ -1957,12 +1995,19 @@ return card; } - const payload = state.searchResults; - const totalMatches = Number(payload?.totalMatches) || 0; - const truncatedNote = payload?.truncated ? ` Showing the first ${payload.resultCount} results.` : ""; - summary.textContent = `${totalMatches} matches in ${scopeLabel}.${truncatedNote}`; + summary.textContent = ""; card.append(summary, actions); + if (state.searchLoading) { + card.appendChild(createEmptyMessage("Searching...")); + return card; + } + + if (state.searchError) { + card.appendChild(createEmptyMessage(state.searchError)); + return card; + } + if (!Array.isArray(payload?.results) || !payload.results.length) { card.appendChild(createEmptyMessage(`No matches found for \"${state.searchQuery}\".`)); return card; @@ -2027,7 +2072,18 @@ const globalSearchOnlyMode = isGlobalSearchOnlyMode(); setGlobalSearchHeadingMode(globalSearchOnlyMode); - if (!source || !work || !section) { + if (!detailBodyEl) { + return; + } + + if (!globalSearchOnlyMode && (!source || !work || !section)) { + if (state.searchQuery) { + const fallbackCard = createCard("Search"); + fallbackCard.appendChild(createEmptyMessage(`Searching for "${state.searchQuery}"...`)); + detailBodyEl.replaceChildren(); + detailBodyEl.appendChild(fallbackCard); + return; + } renderPlaceholder("Text Reader", "Select a source to begin", "Choose a text source and section from the left panel."); renderLexiconPopup(); return; @@ -2047,11 +2103,99 @@ return; } - detailBodyEl.replaceChildren(); + if (globalSearchOnlyMode) { + const existing = document.getElementById("alpha-text-search-overlay"); + if (existing) { + existing.remove(); + } + + if (!state.searchResults && !state.searchError && state.searchLoading) { + return; + } + + const banner = document.createElement("div"); + banner.id = "alpha-text-search-overlay"; + banner.style.cssText = "position:fixed;inset:0;z-index:9999;background:#0c0c12;overflow:auto;padding:24px"; + const header = document.createElement("div"); + header.style.cssText = "margin-bottom:16px;display:flex;align-items:center;justify-content:space-between"; + const title = document.createElement("h2"); + title.style.cssText = "color:#e4e4e7;margin:0;font-size:20px"; + title.textContent = state.searchQuery ? `Search: "${state.searchQuery}"` : "Search Results"; + const closeBtn = document.createElement("button"); + closeBtn.type = "button"; + closeBtn.textContent = "✕ Close"; + closeBtn.style.cssText = "padding:8px 16px;border:1px solid #3f3f46;border-radius:6px;background:#18181b;color:#d4d4d8;cursor:pointer"; + closeBtn.addEventListener("click", () => { + banner.remove(); + clearTimeout(searchTimer); + clearSearchState(); + clearScopedSearch("global"); + clearScopedSearch("source"); + state.searchRequestId += 1; + setGlobalSearchHeadingMode(false); + void loadSelectedPassage(); + }); + header.append(title, closeBtn); + + const content = document.createElement("div"); + if (state.searchLoading) { + content.textContent = "Searching..."; + content.style.cssText = "color:#a1a1aa;padding:24px;text-align:center"; + } else if (state.searchError) { + content.textContent = state.searchError; + content.style.cssText = "color:#f87171;padding:24px"; + } else if (state.searchResults) { + const p = state.searchResults; + const summary = document.createElement("p"); + summary.style.cssText = "color:#a1a1aa;margin:0 0 16px"; + const matchCount = p.truncated ? p.resultCount : p.totalMatches; + summary.textContent = `${matchCount}${p.truncated ? "+" : ""} match${matchCount !== 1 ? "es" : ""}`; + content.appendChild(summary); + if (Array.isArray(p.results)) { + p.results.forEach((r) => { + const btn = document.createElement("button"); + btn.type = "button"; + const isActive = normalizeId(r?.sourceId) === normalizeId(state.selectedSourceId) + && normalizeId(r?.workId) === normalizeId(state.selectedWorkId) + && normalizeId(r?.sectionId) === normalizeId(state.selectedSectionId) + && normalizeId(r?.verseId) === normalizeId(state.highlightedVerseId); + btn.style.cssText = "display:block;width:100%;text-align:left;padding:10px 14px;margin-bottom:8px;border:2px solid " + + (isActive ? "#818cf8" : "#3f3f46") + + ";border-radius:8px;background:" + (isActive ? "rgba(99,102,241,0.15)" : "#18181b") + + ";color:#d4d4d8;cursor:pointer"; + + const refEl = document.createElement("strong"); + refEl.textContent = r.reference || ""; + btn.appendChild(refEl); + btn.appendChild(document.createElement("br")); + + const previewEl = document.createElement("small"); + appendHighlightedText(previewEl, (r.preview || "").slice(0, 200), state.searchQuery); + btn.appendChild(previewEl); + btn.addEventListener("click", () => { + state.highlightedVerseFresh = true; + banner.remove(); + void openSearchResult(r); + }); + content.appendChild(btn); + }); + } + } else { + content.textContent = "No results."; + content.style.cssText = "color:#a1a1aa;padding:24px"; + } + + banner.append(header, content); + document.body.appendChild(banner); + return; + } const searchCard = createSearchCard(); - if (searchCard) { + + if (searchCard && (globalSearchOnlyMode || state.searchLoading)) { + detailBodyEl.replaceChildren(); detailBodyEl.appendChild(searchCard); + return; } if (globalSearchOnlyMode) { @@ -2059,6 +2203,8 @@ return; } + detailBodyEl.replaceChildren(); + if (!state.currentPassage) { const loadingCard = createCard("Text Reader"); loadingCard.appendChild(createEmptyMessage("Loading section…")); @@ -2160,7 +2306,19 @@ renderDetail(); if (state.highlightedVerseId) { - requestAnimationFrame(scrollHighlightedVerseIntoView); + requestAnimationFrame(() => { + scrollHighlightedVerseIntoView(); + if (state.highlightedVerseFresh) { + const verseEl = detailBodyEl?.querySelector?.(".alpha-text-verse.is-highlighted"); + if (verseEl instanceof HTMLElement) { + verseEl.classList.add("is-highlighted-fresh"); + setTimeout(() => { + verseEl.classList.remove("is-highlighted-fresh"); + }, 2600); + } + state.highlightedVerseFresh = false; + } + }); } } @@ -2185,15 +2343,13 @@ updateSearchControls(); if (!query) { - clearSearchState(); + state.searchLoading = false; + state.searchError = `Search query is empty (scope: ${normalizedScope}, input: ${getSearchInput(normalizedScope) ? "found" : "missing"}, stored: "${getStoredSearchQuery(normalizedScope) || "none"}")`; + state.searchResults = null; renderDetail(); return; } - if (normalizedScope === "global" || normalizedScope === "source") { - showDetailOnlyMode(); - } - const requestId = state.searchRequestId + 1; state.searchRequestId = requestId; state.searchLoading = true; @@ -2242,7 +2398,7 @@ showDetailOnlyMode(); await loadSelectedPassage(); clearActiveSearchUi({ preserveHighlight: true }); - renderDetail(); + updateSearchControls(); } function bindControls() { @@ -2253,7 +2409,7 @@ if (globalSearchFormEl instanceof HTMLFormElement) { globalSearchFormEl.addEventListener("submit", (event) => { event.preventDefault(); - void runSearch("global"); + debounceRunSearch("global"); }); } @@ -2278,7 +2434,7 @@ if (localSearchFormEl instanceof HTMLFormElement) { localSearchFormEl.addEventListener("submit", (event) => { event.preventDefault(); - void runSearch("source"); + void debounceRunSearch("source"); }); } @@ -2441,6 +2597,35 @@ }); } + if (settingsBtnEl instanceof HTMLButtonElement && settingsPopoverEl instanceof HTMLElement) { + settingsBtnEl.addEventListener("click", () => { + const isOpen = settingsPopoverEl.hidden === false; + settingsPopoverEl.hidden = isOpen; + settingsBtnEl.setAttribute("aria-expanded", isOpen ? "false" : "true"); + }); + + const closeBtn = settingsPopoverEl.querySelector(".alpha-text-settings-close"); + if (closeBtn instanceof HTMLButtonElement) { + closeBtn.addEventListener("click", () => { + settingsPopoverEl.hidden = true; + settingsBtnEl.setAttribute("aria-expanded", "false"); + }); + } + + document.addEventListener("click", (event) => { + if (settingsPopoverEl.hidden) { + return; + } + const target = event.target; + if (target instanceof Node) { + if (!settingsPopoverEl.contains(target) && target !== settingsBtnEl) { + settingsPopoverEl.hidden = true; + settingsBtnEl.setAttribute("aria-expanded", "false"); + } + } + }); + } + state.initialized = true; } diff --git a/app/ui-chrome.js b/app/ui-chrome.js index 587eac2..1af91fa 100644 --- a/app/ui-chrome.js +++ b/app/ui-chrome.js @@ -488,62 +488,99 @@ throw new Error("Detail pane is not ready to export."); } - 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 exportStripSelectors = [ + ".detail-sequence-nav", + ".detail-pane-export-controls", + ".alpha-text-reader-nav-btn", + ".alpha-text-reader-panel", + ".alpha-text-heading-tools", + ".alpha-text-search-controls", + ".alpha-text-controls--heading", + ".alpha-text-reader-toggle-control", + ".alpha-text-compare-toggle", + ".alpha-text-translation-select", + ".alpha-text-compare-select", + ".alpha-text-work-select", + ".alpha-text-section-select", + ".planet-detail-summary" + ]; - const contentWidth = Math.max( - 320, - Math.ceil(detailPanel.clientWidth || detailPanel.getBoundingClientRect().width || 0) - ); - const contentHeight = Math.max( - 240, - Math.ceil(detailPanel.scrollHeight || detailPanel.getBoundingClientRect().height || 0) - ); + exportStripSelectors.forEach((selector) => { + exportClone.querySelectorAll(selector).forEach((node) => node.remove()); + }); + + exportClone.querySelectorAll("*").forEach((node) => { + if (node instanceof HTMLElement && node.hidden) { + node.remove(); + } + }); + + exportClone.style.position = "fixed"; + exportClone.style.left = "-100000px"; + exportClone.style.top = "0"; + exportClone.style.visibility = "hidden"; + exportClone.style.width = "max-content"; + exportClone.style.maxWidth = "900px"; + exportClone.style.minWidth = "280px"; + exportClone.style.height = "auto"; + exportClone.style.overflow = "visible"; + exportClone.style.padding = "24px"; + exportClone.style.boxSizing = "border-box"; + document.body.appendChild(exportClone); + + const measureWidth = Math.ceil(exportClone.getBoundingClientRect().width || 280); + document.body.removeChild(exportClone); + + exportClone.style.position = ""; + exportClone.style.left = ""; + exportClone.style.top = ""; + exportClone.style.visibility = ""; sandboxEl = document.createElement("div"); sandboxEl.style.position = "fixed"; sandboxEl.style.left = "-100000px"; sandboxEl.style.top = "0"; - sandboxEl.style.width = `${contentWidth}px`; - sandboxEl.style.height = `${contentHeight}px`; - sandboxEl.style.overflow = "hidden"; sandboxEl.style.pointerEvents = "none"; sandboxEl.style.opacity = "0"; - exportClone.style.width = `${contentWidth}px`; - exportClone.style.minWidth = `${contentWidth}px`; - exportClone.style.maxWidth = `${contentWidth}px`; - exportClone.style.height = `${contentHeight}px`; - exportClone.style.minHeight = `${contentHeight}px`; - exportClone.style.maxHeight = `${contentHeight}px`; + exportClone.style.width = `${measureWidth}px`; + exportClone.style.minWidth = ""; + exportClone.style.maxWidth = ""; + exportClone.style.height = "auto"; + exportClone.style.minHeight = ""; + exportClone.style.maxHeight = ""; exportClone.style.overflow = "visible"; + exportClone.style.padding = "24px"; + exportClone.style.boxSizing = "border-box"; sandboxEl.appendChild(exportClone); document.body.appendChild(sandboxEl); - const exportScale = Math.max(2, Math.min(2.5, Number(window.devicePixelRatio) || 1)); + const exportScale = 2; const canvas = await html2canvas(exportClone, { - backgroundColor: null, + backgroundColor: "#0c0c12", scale: exportScale, useCORS: true, allowTaint: false, logging: false, - width: contentWidth, - height: contentHeight, - windowWidth: contentWidth, - windowHeight: contentHeight, - scrollX: 0, - scrollY: 0, 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"; }); + clonedDocument.querySelectorAll( + ".detail-sequence-nav, .detail-pane-export-controls, .alpha-text-reader-nav-btn, .alpha-text-reader-panel, .alpha-text-heading-tools, .alpha-text-search-controls, .alpha-text-controls--heading, .alpha-text-reader-toggle-control, .alpha-text-compare-toggle, .planet-detail-summary" + ).forEach((node) => node.remove()); + clonedDocument.querySelectorAll("*").forEach((node) => { + if (node instanceof HTMLElement && node.hidden) { + node.remove(); + } + }); + const detailClone = clonedDocument.querySelector(".planet-detail-panel, .tarot-detail-panel, .kab-detail-panel"); + if (detailClone instanceof HTMLElement) { + detailClone.style.padding = "24px"; + detailClone.style.boxSizing = "border-box"; + detailClone.style.width = "max-content"; + detailClone.style.maxWidth = "900px"; + detailClone.style.minWidth = "280px"; + } } }); diff --git a/app/ui-home-calendar.js b/app/ui-home-calendar.js index dcd3511..b6dca2f 100644 --- a/app/ui-home-calendar.js +++ b/app/ui-home-calendar.js @@ -81,7 +81,7 @@ return; } - nowSkyLayerEl.removeAttribute("src"); + nowSkyLayerEl.src = "about:blank"; lastNowSkyGeoKey = ""; lastNowSkySourceUrl = ""; } @@ -164,6 +164,7 @@ ...(window.TarotHomeUi || {}), init, syncNowSkyBackground, - syncNowPanelTheme + syncNowPanelTheme, + clearNowSkyBackground }; })(); diff --git a/app/ui-navigation.js b/app/ui-navigation.js index 1fccc3c..aeb28f2 100644 --- a/app/ui-navigation.js +++ b/app/ui-navigation.js @@ -249,6 +249,10 @@ setActiveSection(getActiveSection() === "zodiac" ? "home" : "zodiac"); }); + bindClick(elements.openSkyEl, () => { + setActiveSection(getActiveSection() === "sky" ? "home" : "sky"); + }); + bindClick(elements.openNatalEl, () => { setActiveSection(getActiveSection() === "natal" ? "home" : "natal"); }); diff --git a/app/ui-section-state.js b/app/ui-section-state.js index 6eac40e..18ac87c 100644 --- a/app/ui-section-state.js +++ b/app/ui-section-state.js @@ -15,6 +15,7 @@ "astronomy", "planets", "cycles", + "sky", "natal", "elements", "iching", @@ -78,7 +79,6 @@ requestAnimationFrame(() => { config.calendar?.render?.(); config.calendarVisualsUi?.updateMonthStrip?.(); - config.homeUi?.syncNowPanelTheme?.(new Date()); }); } @@ -116,11 +116,12 @@ const isTarotHouseOpen = activeSection === "tarot-house"; const isTarotMenuOpen = isTarotOpen || isTarotFrameOpen || isTarotHouseOpen; const isAstronomyOpen = activeSection === "astronomy"; + const isSkyOpen = activeSection === "sky"; const isPlanetOpen = activeSection === "planets"; const isCyclesOpen = activeSection === "cycles"; const isNatalOpen = activeSection === "natal"; const isZodiacOpen = activeSection === "zodiac"; - const isAstronomyMenuOpen = isAstronomyOpen || isPlanetOpen || isCyclesOpen || isZodiacOpen || isNatalOpen; + const isAstronomyMenuOpen = isAstronomyOpen || isPlanetOpen || isCyclesOpen || isZodiacOpen || isNatalOpen || isSkyOpen; const isElementsOpen = activeSection === "elements"; const isIChingOpen = activeSection === "iching"; const isKabbalahOpen = activeSection === "kabbalah"; @@ -149,6 +150,7 @@ setHidden(elements.tarotFrameSectionEl, !isTarotFrameOpen); setHidden(elements.tarotHouseSectionEl, !isTarotHouseOpen); setHidden(elements.astronomySectionEl, !isAstronomyOpen); + setHidden(elements.skySectionEl, !isSkyOpen); setHidden(elements.planetSectionEl, !isPlanetOpen); setHidden(elements.cyclesSectionEl, !isCyclesOpen); setHidden(elements.natalSectionEl, !isNatalOpen); @@ -168,7 +170,8 @@ setHidden(elements.quizSectionEl, !isQuizOpen); setHidden(elements.godsSectionEl, !isGodsOpen); setHidden(elements.enochianSectionEl, !isEnochianOpen); - setHidden(elements.nowPanelEl, !isHomeOpen); + setHidden(elements.nowPanelEl, !isSkyOpen); + setHidden(elements.homeWelcomeEl, !isHomeOpen); setPressed(elements.openHomeEl, isHomeOpen); setPressed(elements.openSettingsEl, isSettingsOpen); diff --git a/index.html b/index.html index e0c24da..3d7563a 100644 --- a/index.html +++ b/index.html @@ -39,6 +39,7 @@ +
@@ -776,11 +777,60 @@
+ + @@ -1116,35 +1166,16 @@
+
-
-
- -