55 lines
2.1 KiB
JavaScript
55 lines
2.1 KiB
JavaScript
// Quick feedback animations (0.15 to 0.25 s), so buying feels immediate.
|
|
// All of them are plain CSS animations restarted from here; users who prefer
|
|
// reduced motion get none (see components.css).
|
|
|
|
const FALLBACK_MS = 400; // clean-up if the browser never fires animationend
|
|
|
|
/** Restart a one-shot CSS animation class on an element. */
|
|
function play(el, className) {
|
|
if (!el) return;
|
|
el.classList.remove(className);
|
|
void el.offsetWidth; // let the browser notice the class was removed
|
|
el.classList.add(className);
|
|
const done = () => el.classList.remove(className);
|
|
el.addEventListener('animationend', done, { once: true });
|
|
setTimeout(done, FALLBACK_MS);
|
|
}
|
|
|
|
/** A block that was just bought: a quick pop and an accent glow. */
|
|
export const pop = (el) => play(el, 'fx-pop');
|
|
|
|
/** A number that just changed: a quick bump. */
|
|
export const bump = (el) => play(el, 'fx-bump');
|
|
|
|
/** A resource that was just spent: a quick flash. */
|
|
export const spend = (el) => play(el, 'fx-spend');
|
|
|
|
/**
|
|
* A short "+3" that rises from the middle of `anchor` (or from a point) and fades.
|
|
* `at` = { x, y } in viewport coordinates, used when given instead of an element.
|
|
* `tone` ('good' | 'bad') colours it green or red; by default it takes the accent colour.
|
|
*/
|
|
export function floater(anchor, text, at, tone) {
|
|
const rect = at ? { left: at.x, top: at.y, width: 0 } : anchor?.getBoundingClientRect();
|
|
if (!rect) return;
|
|
const el = document.createElement('span');
|
|
el.className = tone ? `floater floater--${tone}` : 'floater';
|
|
el.textContent = text;
|
|
el.style.left = `${rect.left + rect.width / 2}px`;
|
|
el.style.top = `${rect.top}px`;
|
|
document.body.append(el);
|
|
el.addEventListener('animationend', () => el.remove(), { once: true });
|
|
setTimeout(() => el.remove(), FALLBACK_MS);
|
|
}
|
|
|
|
/**
|
|
* Pop a bought block, float a label above it and flash what was spent (the funds
|
|
* in the top bar unless `spentId` says otherwise, or is null for no flash).
|
|
*/
|
|
export function purchased(el, label, spentId = 'v-funds') {
|
|
pop(el);
|
|
floater(el, label);
|
|
if (spentId) spend(document.getElementById(spentId));
|
|
return true;
|
|
}
|