Add confetti burst after suggestion submit
This commit is contained in:
114
wwwroot/app.js
114
wwwroot/app.js
@@ -511,11 +511,12 @@ function setupHandlers() {
|
||||
await api.createSuggestion(data);
|
||||
form.reset();
|
||||
toast(t("toast.suggestionAdded"));
|
||||
triggerCelebration(form.querySelector("button[type=submit]"));
|
||||
await loadSuggestData();
|
||||
} catch (err) {
|
||||
toast(err.message, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("set-phase").addEventListener("click", async () => {
|
||||
const phase = $("phase-select").value;
|
||||
@@ -874,6 +875,117 @@ function setupBackgroundPan(config = {}) {
|
||||
step();
|
||||
}
|
||||
|
||||
// Celebration FX -----------------------------------------------------
|
||||
let fxCanvas;
|
||||
let fxCtx;
|
||||
let fxParticles = [];
|
||||
let fxAnimating = false;
|
||||
|
||||
function ensureFxCanvas() {
|
||||
if (fxCanvas) return;
|
||||
fxCanvas = document.createElement("canvas");
|
||||
fxCanvas.className = "fx-canvas";
|
||||
fxCanvas.style.position = "fixed";
|
||||
fxCanvas.style.inset = "0";
|
||||
fxCanvas.style.pointerEvents = "none";
|
||||
fxCanvas.style.zIndex = "120";
|
||||
fxCanvas.width = window.innerWidth;
|
||||
fxCanvas.height = window.innerHeight;
|
||||
fxCtx = fxCanvas.getContext("2d");
|
||||
document.body.appendChild(fxCanvas);
|
||||
window.addEventListener("resize", () => {
|
||||
fxCanvas.width = window.innerWidth;
|
||||
fxCanvas.height = window.innerHeight;
|
||||
});
|
||||
}
|
||||
|
||||
function triggerCelebration(button) {
|
||||
ensureFxCanvas();
|
||||
const rect = (button || document.body).getBoundingClientRect();
|
||||
const x = rect.left + rect.width / 2;
|
||||
const y = rect.top + rect.height / 2;
|
||||
spawnConfetti(x, y, 80);
|
||||
spawnFirework(x, y, 40);
|
||||
if (!fxAnimating) {
|
||||
fxAnimating = true;
|
||||
requestAnimationFrame(fxStep);
|
||||
}
|
||||
}
|
||||
|
||||
function spawnConfetti(x, y, count) {
|
||||
for (let i = 0; i < count; i++) {
|
||||
fxParticles.push({
|
||||
x,
|
||||
y,
|
||||
vx: (Math.random() - 0.5) * 6,
|
||||
vy: Math.random() * -6 - 2,
|
||||
size: 6 + Math.random() * 4,
|
||||
life: 60 + Math.random() * 20,
|
||||
color: randomColor(),
|
||||
type: "confetti",
|
||||
wobble: Math.random() * Math.PI * 2,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function spawnFirework(x, y, count) {
|
||||
for (let i = 0; i < count; i++) {
|
||||
const angle = (Math.PI * 2 * i) / count + Math.random() * 0.3;
|
||||
const speed = 3 + Math.random() * 3;
|
||||
fxParticles.push({
|
||||
x,
|
||||
y,
|
||||
vx: Math.cos(angle) * speed,
|
||||
vy: Math.sin(angle) * speed,
|
||||
size: 4 + Math.random() * 3,
|
||||
life: 50 + Math.random() * 20,
|
||||
color: randomColor(),
|
||||
type: "spark",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function fxStep() {
|
||||
if (!fxCtx || !fxCanvas) return;
|
||||
fxCtx.clearRect(0, 0, fxCanvas.width, fxCanvas.height);
|
||||
fxParticles = fxParticles.filter((p) => p.life > 0);
|
||||
for (const p of fxParticles) {
|
||||
if (p.type === "confetti") {
|
||||
p.vy += 0.18;
|
||||
p.vx *= 0.99;
|
||||
p.wobble += 0.2;
|
||||
p.x += p.vx + Math.cos(p.wobble) * 0.8;
|
||||
p.y += p.vy;
|
||||
} else {
|
||||
p.vy += 0.08;
|
||||
p.vx *= 0.995;
|
||||
p.x += p.vx;
|
||||
p.y += p.vy;
|
||||
}
|
||||
p.life -= 1;
|
||||
fxCtx.fillStyle = p.color;
|
||||
fxCtx.beginPath();
|
||||
if (p.type === "confetti") {
|
||||
fxCtx.fillRect(p.x, p.y, p.size, p.size * 0.6);
|
||||
} else {
|
||||
fxCtx.arc(p.x, p.y, p.size * 0.5, 0, Math.PI * 2);
|
||||
fxCtx.fill();
|
||||
}
|
||||
}
|
||||
if (fxParticles.length > 0) {
|
||||
requestAnimationFrame(fxStep);
|
||||
} else {
|
||||
fxCtx.clearRect(0, 0, fxCanvas.width, fxCanvas.height);
|
||||
fxAnimating = false;
|
||||
}
|
||||
}
|
||||
|
||||
function randomColor() {
|
||||
const palette = ["#ff595e", "#ffca3a", "#8ac926", "#1982c4", "#6a4c93"];
|
||||
return palette[Math.floor(Math.random() * palette.length)];
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
async function main() {
|
||||
setupHandlers();
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user