From 5902d5f0b14c692b6f12c450aa77777636b45d72 Mon Sep 17 00:00:00 2001 From: Nose Date: Wed, 15 Apr 2026 23:15:45 -0700 Subject: [PATCH] updated the calendar and settings pages, added a new calendar page, and made some minor styling changes to the app. --- app.js | 9 ++- app/styles.css | 33 ++++++++++ app/ui-home-calendar.js | 51 +++++++++++++-- app/ui-settings.js | 139 +++++++++++++++++++++++++++++++++++----- index.html | 16 +++-- 5 files changed, 222 insertions(+), 26 deletions(-) diff --git a/app.js b/app.js index 139922f..71824ae 100644 --- a/app.js +++ b/app.js @@ -133,7 +133,9 @@ const DEFAULT_SETTINGS = { longitude: -0.1278, timeFormat: "minutes", birthDate: "", - tarotDeck: DEFAULT_TAROT_DECK + tarotDeck: DEFAULT_TAROT_DECK, + stellariumBackgroundEnabled: false, + hasExplicitLocation: false }; const PLANET_CALENDAR_STYLES = { @@ -556,7 +558,7 @@ settingsUi.init?.({ appRuntime.applySettings?.(settings); currentSettings = settings; }, - onSyncSkyBackground: (geo, force) => homeUi.syncNowSkyBackground?.(geo, force), + onSyncSkyBackground: (geo, options) => homeUi.syncNowSkyBackground?.(geo, options), onStatus: (text) => setStatus(text), onConnectionSaved: async () => ensureConnectedApp(), getActiveSection: () => sectionStateUi.getActiveSection?.() || "home", @@ -579,7 +581,8 @@ calendarVisualsUi.init?.({ homeUi.init?.({ nowSkyLayerEl, nowPanelEl, - getCurrentGeo: () => appRuntime.getCurrentGeo?.() || null + getCurrentGeo: () => appRuntime.getCurrentGeo?.() || null, + getCurrentSettings: () => appRuntime.getCurrentSettings?.() || currentSettings }); if (nowOverlayToggleEl && nowPanelEl) { diff --git a/app/styles.css b/app/styles.css index 8715773..7334865 100644 --- a/app/styles.css +++ b/app/styles.css @@ -7023,6 +7023,32 @@ .settings-field input[type="password"] { letter-spacing: 0.04em; } + .settings-toggle-field { + gap: 8px; + } + .settings-toggle-row { + display: inline-flex; + align-items: center; + gap: 10px; + padding: 8px 10px; + border: 1px solid #3f3f46; + border-radius: 8px; + background: #09090b; + color: #f4f4f5; + } + .settings-toggle-row input { + width: auto; + margin: 0; + accent-color: #f4f4f5; + } + .settings-toggle-row:has(input:disabled) { + opacity: 0.6; + } + .settings-field-hint { + color: #a1a1aa; + font-size: 12px; + line-height: 1.4; + } .settings-actions { margin-top: 12px; display: flex; @@ -7150,6 +7176,13 @@ #now-panel.is-overlay-hidden::after { opacity: 0; } + #now-panel.is-sky-disabled #now-sky-layer { + opacity: 0; + } + #now-panel.is-sky-disabled::before, + #now-panel.is-sky-disabled::after { + opacity: 0; + } .now-panel-controls { position: absolute; top: 14px; diff --git a/app/ui-home-calendar.js b/app/ui-home-calendar.js index 320e7e1..3f529ed 100644 --- a/app/ui-home-calendar.js +++ b/app/ui-home-calendar.js @@ -19,6 +19,10 @@ return config.getCurrentGeo?.() || null; } + function getCurrentSettings() { + return config.getCurrentSettings?.() || null; + } + function normalizeGeoForSky(geo) { const latitude = Number(geo?.latitude); const longitude = Number(geo?.longitude); @@ -51,14 +55,53 @@ return wrapperUrl.toString(); } - function syncNowSkyBackground(geo, force = false) { + function normalizeSkySyncOptions(optionsOrForce = false) { + if (typeof optionsOrForce === "boolean") { + return { force: optionsOrForce }; + } + + return { + force: Boolean(optionsOrForce?.force), + backgroundEnabled: optionsOrForce?.backgroundEnabled, + hasExplicitLocation: optionsOrForce?.hasExplicitLocation + }; + } + + function clearNowSkyBackground() { const nowSkyLayerEl = getNowSkyLayerEl(); - if (!nowSkyLayerEl || !geo) { + if (!nowSkyLayerEl) { return; } + nowSkyLayerEl.removeAttribute("src"); + lastNowSkyGeoKey = ""; + lastNowSkySourceUrl = ""; + } + + function syncNowSkyBackground(geo, optionsOrForce = false) { + const nowSkyLayerEl = getNowSkyLayerEl(); + const nowPanelEl = getNowPanelEl(); + if (!nowSkyLayerEl) { + return; + } + + const options = normalizeSkySyncOptions(optionsOrForce); + const settings = getCurrentSettings(); + const backgroundEnabled = typeof options.backgroundEnabled === "boolean" + ? options.backgroundEnabled + : settings?.stellariumBackgroundEnabled === true; + const hasExplicitLocation = typeof options.hasExplicitLocation === "boolean" + ? options.hasExplicitLocation + : settings?.hasExplicitLocation === true; const normalizedGeo = normalizeGeoForSky(geo); - if (!normalizedGeo) { + const shouldLoadSky = Boolean(backgroundEnabled && hasExplicitLocation && normalizedGeo); + + if (nowPanelEl) { + nowPanelEl.classList.toggle("is-sky-disabled", !shouldLoadSky); + } + + if (!shouldLoadSky) { + clearNowSkyBackground(); return; } @@ -68,7 +111,7 @@ return; } - if (!force && geoKey === lastNowSkyGeoKey && stellariumUrl === lastNowSkySourceUrl) { + if (!options.force && geoKey === lastNowSkyGeoKey && stellariumUrl === lastNowSkySourceUrl) { return; } diff --git a/app/ui-settings.js b/app/ui-settings.js index e8b9bbf..c9c855e 100644 --- a/app/ui-settings.js +++ b/app/ui-settings.js @@ -9,7 +9,9 @@ longitude: -0.1278, timeFormat: "minutes", birthDate: "", - tarotDeck: "ceremonial-magick" + tarotDeck: "ceremonial-magick", + stellariumBackgroundEnabled: false, + hasExplicitLocation: false }, onSettingsApplied: null, onSyncSkyBackground: null, @@ -31,12 +33,57 @@ timeFormatEl: document.getElementById("time-format"), birthDateEl: document.getElementById("birth-date"), tarotDeckEl: document.getElementById("tarot-deck"), + stellariumBackgroundEl: document.getElementById("stellarium-background"), + stellariumBackgroundHintEl: document.getElementById("stellarium-background-hint"), apiBaseUrlEl: document.getElementById("api-base-url"), apiKeyEl: document.getElementById("api-key"), saveSettingsEl: document.getElementById("save-settings"), useLocationEl: document.getElementById("use-location") }; } + + function setLocationEntryState(isExplicit) { + const { latEl, lngEl } = getElements(); + const normalizedValue = isExplicit ? "true" : "false"; + + if (latEl) { + latEl.dataset.explicitLocation = normalizedValue; + } + + if (lngEl) { + lngEl.dataset.explicitLocation = normalizedValue; + } + } + + function hasExplicitLocationEntry() { + const { latEl } = getElements(); + return latEl?.dataset.explicitLocation === "true"; + } + + function syncStellariumBackgroundAvailability() { + const { stellariumBackgroundEl, stellariumBackgroundHintEl } = getElements(); + if (!stellariumBackgroundEl) { + return; + } + + const hasExplicitLocation = hasExplicitLocationEntry(); + stellariumBackgroundEl.disabled = !hasExplicitLocation; + + if (!hasExplicitLocation) { + stellariumBackgroundEl.checked = false; + } + + if (stellariumBackgroundHintEl) { + stellariumBackgroundHintEl.textContent = hasExplicitLocation + ? "Uses your saved location to load the live sky background." + : "Enter a location or use My Location before enabling the live sky background."; + } + } + + function markLocationAsExplicit() { + setLocationEntryState(true); + syncStellariumBackgroundAvailability(); + } function getConnectionSettings() { return window.TarotAppConfig?.getConnectionSettings?.() || { apiBaseUrl: String(window.TarotAppConfig?.apiBaseUrl || "").trim(), @@ -75,9 +122,9 @@ } } - function syncSky(geo, force) { + function syncSky(geo, options) { if (typeof config.onSyncSkyBackground === "function") { - config.onSyncSkyBackground(geo, force); + config.onSyncSkyBackground(geo, options); } } @@ -152,13 +199,35 @@ return Number.isFinite(parsed) ? parsed : fallback; } + function parseStoredBoolean(value, fallback = false) { + return typeof value === "boolean" ? value : fallback; + } + + function hasLegacyExplicitLocation(settings, normalizedLatitude, normalizedLongitude) { + const hasStoredCoordinates = Number.isFinite(Number(settings?.latitude)) && Number.isFinite(Number(settings?.longitude)); + if (!hasStoredCoordinates) { + return false; + } + + return Math.abs(normalizedLatitude - Number(config.defaultSettings.latitude)) > 0.00005 + || Math.abs(normalizedLongitude - Number(config.defaultSettings.longitude)) > 0.00005; + } + function normalizeSettings(settings) { + const latitude = parseStoredNumber(settings?.latitude, config.defaultSettings.latitude); + const longitude = parseStoredNumber(settings?.longitude, config.defaultSettings.longitude); + const hasExplicitLocation = typeof settings?.hasExplicitLocation === "boolean" + ? settings.hasExplicitLocation + : hasLegacyExplicitLocation(settings, latitude, longitude); + return { - latitude: parseStoredNumber(settings?.latitude, config.defaultSettings.latitude), - longitude: parseStoredNumber(settings?.longitude, config.defaultSettings.longitude), + latitude, + longitude, timeFormat: normalizeTimeFormat(settings?.timeFormat), birthDate: normalizeBirthDate(settings?.birthDate), - tarotDeck: normalizeTarotDeck(settings?.tarotDeck) + tarotDeck: normalizeTarotDeck(settings?.tarotDeck), + stellariumBackgroundEnabled: parseStoredBoolean(settings?.stellariumBackgroundEnabled, false) && hasExplicitLocation, + hasExplicitLocation }; } @@ -285,7 +354,7 @@ } function applySettingsToInputs(settings) { - const { latEl, lngEl, timeFormatEl, birthDateEl, tarotDeckEl } = getElements(); + const { latEl, lngEl, timeFormatEl, birthDateEl, tarotDeckEl, stellariumBackgroundEl } = getElements(); syncTarotDeckInputOptions(); syncConnectionInputs(); const normalized = normalizeSettings(settings); @@ -296,6 +365,11 @@ if (tarotDeckEl) { tarotDeckEl.value = normalized.tarotDeck; } + setLocationEntryState(normalized.hasExplicitLocation); + if (stellariumBackgroundEl) { + stellariumBackgroundEl.checked = normalized.stellariumBackgroundEnabled; + } + syncStellariumBackgroundAvailability(); if (window.TarotCardImages?.setActiveDeck) { window.TarotCardImages.setActiveDeck(normalized.tarotDeck); } @@ -304,9 +378,16 @@ } function getSettingsFromInputs() { - const { latEl, lngEl, timeFormatEl, birthDateEl, tarotDeckEl } = getElements(); - const latitude = Number(latEl.value); - const longitude = Number(lngEl.value); + const { latEl, lngEl, timeFormatEl, birthDateEl, tarotDeckEl, stellariumBackgroundEl } = getElements(); + const latitudeText = String(latEl?.value || "").trim(); + const longitudeText = String(lngEl?.value || "").trim(); + + if (!latitudeText || !longitudeText) { + throw new Error("Latitude/Longitude must be entered before saving settings."); + } + + const latitude = Number(latitudeText); + const longitude = Number(longitudeText); if (Number.isNaN(latitude) || Number.isNaN(longitude)) { throw new Error("Latitude/Longitude must be valid numbers."); @@ -317,7 +398,9 @@ longitude, timeFormat: normalizeTimeFormat(timeFormatEl.value), birthDate: normalizeBirthDate(birthDateEl.value), - tarotDeck: normalizeTarotDeck(tarotDeckEl?.value) + tarotDeck: normalizeTarotDeck(tarotDeckEl?.value), + stellariumBackgroundEnabled: Boolean(stellariumBackgroundEl?.checked), + hasExplicitLocation: hasExplicitLocationEntry() }); } @@ -363,7 +446,14 @@ const connectionChanged = hasConnectionChanged(previousConnectionSettings, connectionSettings); const connectionResult = window.TarotAppConfig?.updateConnectionSettings?.(connectionSettings) || { didPersist: true }; const normalized = applySettingsToInputs(settings); - syncSky({ latitude: normalized.latitude, longitude: normalized.longitude }, true); + syncSky( + { latitude: normalized.latitude, longitude: normalized.longitude }, + { + force: true, + backgroundEnabled: normalized.stellariumBackgroundEnabled, + hasExplicitLocation: normalized.hasExplicitLocation + } + ); const didPersist = saveSettings(normalized); emitSettingsUpdated(normalized); if (typeof config.getActiveSection === "function" && config.getActiveSection() !== "home") { @@ -396,8 +486,16 @@ ({ coords }) => { latEl.value = coords.latitude.toFixed(4); lngEl.value = coords.longitude.toFixed(4); - syncSky({ latitude: coords.latitude, longitude: coords.longitude }, true); - setStatus("Location set from browser. Click Save Settings to refresh."); + markLocationAsExplicit(); + syncSky( + { latitude: coords.latitude, longitude: coords.longitude }, + { + force: true, + backgroundEnabled: Boolean(getElements().stellariumBackgroundEl?.checked), + hasExplicitLocation: true + } + ); + setStatus("Location set from browser. Save Settings to use it across the app."); }, (err) => { const detail = err?.message || `code ${err?.code ?? "unknown"}`; @@ -414,7 +512,9 @@ openSettingsEl, closeSettingsEl, settingsPopupEl, - settingsPopupCardEl + settingsPopupCardEl, + latEl, + lngEl } = getElements(); if (saveSettingsEl) { @@ -427,6 +527,15 @@ useLocationEl.addEventListener("click", requestGeoLocation); } + [latEl, lngEl].forEach((inputEl) => { + if (!inputEl) { + return; + } + + inputEl.addEventListener("input", markLocationAsExplicit); + inputEl.addEventListener("change", markLocationAsExplicit); + }); + if (openSettingsEl) { openSettingsEl.addEventListener("click", (event) => { event.stopPropagation(); diff --git a/index.html b/index.html index 523bdfa..0149be5 100644 --- a/index.html +++ b/index.html @@ -16,7 +16,7 @@ - +
@@ -126,6 +126,14 @@ + @@ -1199,15 +1207,15 @@ - + - + - +