feat: release 0.7.0 celebration flow
This commit is contained in:
@@ -20,9 +20,50 @@
|
||||
const quickWinSortIds = document.getElementById("quickWinSortIds");
|
||||
const quickWinSortSave = document.getElementById("quickWinSortSave");
|
||||
const quickWinToggleButtons = document.querySelectorAll("[data-quick-win-toggle]");
|
||||
const celebrationLayer = document.getElementById("celebrationLayer");
|
||||
const celebratePoints = Number.parseInt(document.body.dataset.celebratePoints || "", 10);
|
||||
const scrollRestoreKey = "putzliga:scroll-restore";
|
||||
let draggedQuickWin = null;
|
||||
let quickWinSortDirty = false;
|
||||
|
||||
function rememberScrollPosition() {
|
||||
try {
|
||||
window.sessionStorage.setItem(
|
||||
scrollRestoreKey,
|
||||
JSON.stringify({
|
||||
path: window.location.pathname,
|
||||
y: window.scrollY,
|
||||
}),
|
||||
);
|
||||
} catch (_) {
|
||||
// Ignore storage errors and continue normally.
|
||||
}
|
||||
}
|
||||
|
||||
function restoreScrollPosition() {
|
||||
try {
|
||||
const rawValue = window.sessionStorage.getItem(scrollRestoreKey);
|
||||
if (!rawValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
const saved = JSON.parse(rawValue);
|
||||
window.sessionStorage.removeItem(scrollRestoreKey);
|
||||
|
||||
if (!saved || saved.path !== window.location.pathname || typeof saved.y !== "number") {
|
||||
return;
|
||||
}
|
||||
|
||||
window.requestAnimationFrame(() => {
|
||||
window.requestAnimationFrame(() => {
|
||||
window.scrollTo({ top: saved.y, behavior: "auto" });
|
||||
});
|
||||
});
|
||||
} catch (_) {
|
||||
// Ignore malformed storage data.
|
||||
}
|
||||
}
|
||||
|
||||
function buildCompletionOptions(button) {
|
||||
const options = [];
|
||||
const assignedPairs = [
|
||||
@@ -60,6 +101,7 @@
|
||||
choiceButton.textContent = option.label;
|
||||
choiceButton.addEventListener("click", () => {
|
||||
dialogChoice.value = option.value;
|
||||
rememberScrollPosition();
|
||||
dialog.close();
|
||||
dialogForm.submit();
|
||||
});
|
||||
@@ -74,13 +116,33 @@
|
||||
}
|
||||
|
||||
if (quickTaskOpen && quickTaskDialog) {
|
||||
quickTaskOpen.addEventListener("click", () => quickTaskDialog.showModal());
|
||||
quickTaskOpen.addEventListener("click", () => {
|
||||
if (!quickTaskDialog.open) {
|
||||
quickTaskDialog.showModal();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (quickTaskClose && quickTaskDialog) {
|
||||
quickTaskClose.addEventListener("click", () => quickTaskDialog.close());
|
||||
quickTaskClose.addEventListener("click", () => {
|
||||
if (quickTaskDialog.open) {
|
||||
quickTaskDialog.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[dialog, quickTaskDialog].forEach((activeDialog) => {
|
||||
if (!activeDialog) {
|
||||
return;
|
||||
}
|
||||
|
||||
activeDialog.addEventListener("click", (event) => {
|
||||
if (event.target === activeDialog && activeDialog.open) {
|
||||
activeDialog.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function updateQuickWinsState() {
|
||||
const selectedPresetCount = [...quickWinInputs].filter((input) => input.checked).length;
|
||||
const customSelected = quickWinCustomToggle?.checked === true;
|
||||
@@ -123,6 +185,25 @@
|
||||
});
|
||||
}
|
||||
|
||||
if (dialogForm) {
|
||||
dialogForm.addEventListener("submit", () => {
|
||||
rememberScrollPosition();
|
||||
});
|
||||
}
|
||||
|
||||
document.querySelectorAll('form[action*="/complete"]').forEach((form) => {
|
||||
form.addEventListener("submit", () => {
|
||||
rememberScrollPosition();
|
||||
});
|
||||
});
|
||||
|
||||
const quickWinsForm = document.getElementById("quickWinsForm");
|
||||
if (quickWinsForm) {
|
||||
quickWinsForm.addEventListener("submit", () => {
|
||||
rememberScrollPosition();
|
||||
});
|
||||
}
|
||||
|
||||
function syncQuickWinSortIds() {
|
||||
if (!quickWinSortList || !quickWinSortIds) {
|
||||
return;
|
||||
@@ -140,6 +221,65 @@
|
||||
}
|
||||
}
|
||||
|
||||
function clearCelebrationQuery() {
|
||||
if (!window.history.replaceState) {
|
||||
return;
|
||||
}
|
||||
const url = new URL(window.location.href);
|
||||
if (!url.searchParams.has("celebrate_points")) {
|
||||
return;
|
||||
}
|
||||
url.searchParams.delete("celebrate_points");
|
||||
const nextUrl = `${url.pathname}${url.search}${url.hash}`;
|
||||
window.history.replaceState({}, document.title, nextUrl);
|
||||
}
|
||||
|
||||
function celebrateCompletion(points) {
|
||||
if (!celebrationLayer || !Number.isFinite(points) || points <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||
celebrationLayer.hidden = false;
|
||||
celebrationLayer.setAttribute("aria-hidden", "false");
|
||||
celebrationLayer.innerHTML = "";
|
||||
|
||||
const score = document.createElement("div");
|
||||
score.className = "celebration-score";
|
||||
score.textContent = points;
|
||||
celebrationLayer.appendChild(score);
|
||||
|
||||
const glow = document.createElement("div");
|
||||
glow.className = "celebration-glow";
|
||||
celebrationLayer.appendChild(glow);
|
||||
|
||||
if (!prefersReducedMotion) {
|
||||
const colors = [
|
||||
"rgba(94, 168, 255, 0.96)",
|
||||
"rgba(52, 211, 153, 0.95)",
|
||||
"rgba(250, 204, 21, 0.92)",
|
||||
"rgba(191, 219, 254, 0.96)",
|
||||
];
|
||||
|
||||
Array.from({ length: 14 }).forEach((_, index) => {
|
||||
const particle = document.createElement("span");
|
||||
particle.className = "celebration-particle";
|
||||
particle.style.setProperty("--angle", `${Math.round((360 / 14) * index + Math.random() * 18)}deg`);
|
||||
particle.style.setProperty("--distance", `${72 + Math.round(Math.random() * 44)}px`);
|
||||
particle.style.setProperty("--delay", `${(Math.random() * 0.08).toFixed(2)}s`);
|
||||
particle.style.setProperty("--size", `${7 + Math.round(Math.random() * 7)}px`);
|
||||
particle.style.background = colors[index % colors.length];
|
||||
celebrationLayer.appendChild(particle);
|
||||
});
|
||||
}
|
||||
|
||||
window.setTimeout(() => {
|
||||
celebrationLayer.hidden = true;
|
||||
celebrationLayer.setAttribute("aria-hidden", "true");
|
||||
celebrationLayer.innerHTML = "";
|
||||
}, prefersReducedMotion ? 520 : 1500);
|
||||
}
|
||||
|
||||
if (quickWinSortList) {
|
||||
syncQuickWinSortIds();
|
||||
setQuickWinSortDirty(false);
|
||||
@@ -282,4 +422,11 @@
|
||||
togglePush().catch((error) => console.error("Push toggle failed", error));
|
||||
});
|
||||
}
|
||||
|
||||
if (Number.isFinite(celebratePoints) && celebratePoints > 0) {
|
||||
celebrateCompletion(celebratePoints);
|
||||
clearCelebrationQuery();
|
||||
}
|
||||
|
||||
restoreScrollPosition();
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user