update settings page with status message area

This commit is contained in:
2026-04-22 00:07:04 -07:00
parent 0e7ba18f35
commit b3a11cf735
3 changed files with 152 additions and 1 deletions
+41 -1
View File
@@ -525,7 +525,47 @@
margin-top: 18px;
padding-top: 16px;
border-top: 1px solid rgba(63, 63, 70, 0.7);
justify-content: flex-end;
justify-content: space-between;
align-items: center;
gap: 16px;
flex-wrap: wrap;
}
.settings-page-status {
min-width: min(100%, 360px);
padding: 10px 12px;
border-radius: 14px;
border: 1px solid rgba(63, 63, 70, 0.92);
background: rgba(9, 9, 11, 0.78);
display: flex;
flex-direction: column;
gap: 4px;
box-sizing: border-box;
}
.settings-page-status[data-tone="info"] {
border-color: rgba(59, 130, 246, 0.55);
background: rgba(30, 64, 175, 0.14);
}
.settings-page-status[data-tone="success"] {
border-color: rgba(34, 197, 94, 0.5);
background: rgba(20, 83, 45, 0.18);
}
.settings-page-status[data-tone="warning"] {
border-color: rgba(245, 158, 11, 0.55);
background: rgba(120, 53, 15, 0.18);
}
.settings-page-status[data-tone="error"] {
border-color: rgba(239, 68, 68, 0.55);
background: rgba(127, 29, 29, 0.2);
}
.settings-page-status-text {
color: #f8fafc;
font-size: 13px;
line-height: 1.45;
}
.settings-page-status-time {
color: #94a3b8;
font-size: 12px;
line-height: 1.4;
}
.calendar-year-control {
display: flex;
+107
View File
@@ -2,6 +2,7 @@
"use strict";
const SETTINGS_STORAGE_KEY = "tarot-time-settings-v1";
const SETTINGS_LAST_SAVED_AT_STORAGE_KEY = "tarot-time-settings-last-saved-at-v1";
let config = {
defaultSettings: {
@@ -39,11 +40,89 @@
stellariumBackgroundHintEl: document.getElementById("stellarium-background-hint"),
apiBaseUrlEl: document.getElementById("api-base-url"),
apiKeyEl: document.getElementById("api-key"),
settingsPageStatusEl: document.getElementById("settings-page-status"),
settingsPageStatusTextEl: document.getElementById("settings-page-status-text"),
settingsPageStatusTimeEl: document.getElementById("settings-page-status-time"),
saveSettingsEl: document.getElementById("save-settings"),
useLocationEl: document.getElementById("use-location")
};
}
function loadLastSavedAt() {
try {
const raw = window.localStorage.getItem(SETTINGS_LAST_SAVED_AT_STORAGE_KEY);
const parsed = Number(raw);
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
} catch {
return null;
}
}
function persistLastSavedAt(timestamp) {
try {
window.localStorage.setItem(SETTINGS_LAST_SAVED_AT_STORAGE_KEY, String(timestamp));
return true;
} catch {
return false;
}
}
function formatLastSavedAt(timestamp) {
if (!Number.isFinite(timestamp) || timestamp <= 0) {
return "";
}
try {
return new Intl.DateTimeFormat(undefined, {
dateStyle: "medium",
timeStyle: "short"
}).format(new Date(timestamp));
} catch {
return new Date(timestamp).toLocaleString();
}
}
function setSettingsPageStatus(message, tone = "neutral", options = {}) {
const {
settingsPageStatusEl,
settingsPageStatusTextEl,
settingsPageStatusTimeEl
} = getElements();
if (settingsPageStatusEl) {
settingsPageStatusEl.dataset.tone = String(tone || "neutral");
}
if (settingsPageStatusTextEl) {
settingsPageStatusTextEl.textContent = String(message || "Settings ready.");
}
const savedAt = options.savedAt === undefined ? loadLastSavedAt() : options.savedAt;
const formattedSavedAt = formatLastSavedAt(savedAt);
if (settingsPageStatusTimeEl) {
settingsPageStatusTimeEl.hidden = !formattedSavedAt;
settingsPageStatusTimeEl.textContent = formattedSavedAt ? `Last saved ${formattedSavedAt}` : "";
}
}
function syncSavedSettingsStatus(message = "Settings ready.") {
setSettingsPageStatus(message, "neutral", { savedAt: loadLastSavedAt() });
}
function setSaveButtonBusy(isBusy) {
const { saveSettingsEl } = getElements();
if (!saveSettingsEl) {
return;
}
if (!saveSettingsEl.dataset.defaultLabel) {
saveSettingsEl.dataset.defaultLabel = String(saveSettingsEl.textContent || "Save Settings").trim() || "Save Settings";
}
saveSettingsEl.disabled = Boolean(isBusy);
saveSettingsEl.textContent = isBusy ? "Saving..." : saveSettingsEl.dataset.defaultLabel;
}
function setLocationEntryState(isExplicit) {
const { latEl, lngEl } = getElements();
const normalizedValue = isExplicit ? "true" : "false";
@@ -466,6 +545,7 @@
lastNonSettingsSection = activeSection;
}
applySettingsToInputs(loadSavedSettings());
syncSavedSettingsStatus();
config.setActiveSection?.("settings");
}
@@ -474,6 +554,9 @@
}
async function handleSaveSettings() {
setSaveButtonBusy(true);
setSettingsPageStatus("Saving settings...", "info");
try {
const settings = getSettingsFromInputs();
const previousConnectionSettings = getConnectionSettings();
@@ -501,22 +584,39 @@
}
if (!didPersist || connectionResult.didPersist === false) {
setSettingsPageStatus("Settings applied for this session. Browser storage is unavailable.", "warning", {
savedAt: loadLastSavedAt()
});
setStatus("Settings applied for this session. Browser storage is unavailable.");
} else {
const savedAt = Date.now();
persistLastSavedAt(savedAt);
setSettingsPageStatus("Settings saved.", "success", { savedAt });
setStatus("Settings saved.");
}
} catch (error) {
setSettingsPageStatus(error?.message || "Unable to save settings.", "error", {
savedAt: loadLastSavedAt()
});
setStatus(error?.message || "Unable to save settings.");
} finally {
setSaveButtonBusy(false);
}
}
function requestGeoLocation() {
const { latEl, lngEl } = getElements();
if (!navigator.geolocation) {
setSettingsPageStatus("Geolocation not available in this browser.", "warning", {
savedAt: loadLastSavedAt()
});
setStatus("Geolocation not available in this browser.");
return;
}
setSettingsPageStatus("Getting your location...", "info", {
savedAt: loadLastSavedAt()
});
setStatus("Getting your location...");
navigator.geolocation.getCurrentPosition(
({ coords }) => {
@@ -531,10 +631,16 @@
hasExplicitLocation: true
}
);
setSettingsPageStatus("Location captured. Save Settings to keep it in this browser.", "info", {
savedAt: loadLastSavedAt()
});
setStatus("Location set from browser. Save Settings to use it across the app.");
},
(err) => {
const detail = err?.message || `code ${err?.code ?? "unknown"}`;
setSettingsPageStatus(`Could not get location (${detail}).`, "error", {
savedAt: loadLastSavedAt()
});
setStatus(`Could not get location (${detail}).`);
},
{ enableHighAccuracy: true, timeout: 10000 }
@@ -612,6 +718,7 @@
}
};
syncSavedSettingsStatus();
bindInteractions();
}