Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions music-charts.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@
list.replaceChildren();
if (!period || !Array.isArray(period.tracks) || period.tracks.length === 0) {
status.hidden = false;
status.textContent = "No listening history found for this period yet.";
status.textContent = "No scrobbles were returned from your Last.fm history for this date range.";
if (data && data.generatedAt) status.textContent += " Last checked: " + new Date(data.generatedAt).toLocaleString() + ".";
return;
}
status.hidden = false;
Expand Down Expand Up @@ -103,7 +104,9 @@
const response = await fetch(endpoint, { headers: { Accept: "application/json" }, cache: "no-store" });
const result = await response.json().catch(() => null);
if (!response.ok || !result || !result.periods) {
throw new Error(result && result.error ? result.error : "Charts are temporarily unavailable.");
const message = result && result.error ? result.error : "Charts are temporarily unavailable.";
const detail = result && result.detail ? " — " + result.detail : "";
throw new Error(message + detail);
}
data = result;
lastLoaded = Date.now();
Expand Down
49 changes: 49 additions & 0 deletions script.js
Original file line number Diff line number Diff line change
Expand Up @@ -431,3 +431,52 @@ if (wipayOpen && wipayDialog) {
});
}
}


// ---------- Shared modal behaviour: lock the page behind every native dialog ----------
(function () {
const body = document.body;
const root = document.documentElement;
let locked = false;
let savedScrollY = 0;
let originalStyles = null;

function syncModalScroll() {
const modalOpen = Boolean(document.querySelector("dialog[open]"));
if (modalOpen && !locked) {
savedScrollY = window.scrollY;
originalStyles = {
position: body.style.position,
top: body.style.top,
left: body.style.left,
right: body.style.right,
width: body.style.width,
overflow: body.style.overflow
};
body.style.position = "fixed";
body.style.top = "-" + savedScrollY + "px";
body.style.left = "0";
body.style.right = "0";
body.style.width = "100%";
body.style.overflow = "hidden";
body.classList.add("modal-scroll-locked");
locked = true;
} else if (!modalOpen && locked) {
body.classList.remove("modal-scroll-locked");
Object.keys(originalStyles).forEach(property => {
body.style[property] = originalStyles[property];
});
locked = false;
window.scrollTo(0, savedScrollY);
}
}

const observer = new MutationObserver(syncModalScroll);
observer.observe(root, {
subtree: true,
childList: true,
attributes: true,
attributeFilter: ["open"]
});
document.addEventListener("close", syncModalScroll, true);
})();
3 changes: 3 additions & 0 deletions style.css
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,9 @@ html[data-bg="grid"] body {
.now-playing-artwork { width:52px; height:52px; object-fit:cover; border-radius:10px; }
.now-playing-open { color:var(--cyan); }
.spotify-confirm { width:min(92vw,390px); margin:auto; padding:1.5rem; color:var(--text); background:var(--surface); border:1px solid var(--border); border-radius:22px; }
/* Keep every native prompt centred, contained, and scrollable without moving the page behind it. */
dialog[open] { margin:auto; max-height:90vh; max-height:90dvh; overflow-y:auto; overscroll-behavior:contain; }
body.modal-scroll-locked { overscroll-behavior:none; }
.spotify-confirm::backdrop { background:rgba(0,0,0,.68); backdrop-filter:blur(4px); }
.spotify-confirm h3 { margin-bottom:.5rem; }
.spotify-confirm form > p:not(.eyebrow) { color:var(--muted); }
Expand Down
Loading