feat(bangs): add bang counter dashboard widget

Adds a new "bangs" module with a dashboard widget that tracks household
bang events. The widget shows the total count, a configurable recent-bang
list, and an "Add Bang" button that accepts a backdatable date.

On submission, a full celebration sequence fires: screen flash, widget
shake, count pop animation, synthesized firework sound (Web Audio API),
50 full-screen emoji particles via portal, canvas-confetti star bursts,
side cannons, and a timed sequence of 7 firework bursts.

- New bang_events table (migration 0017)
- canvas-confetti dependency for fireworks/confetti effects
- CSS keyframe animations: shake, countPop, emojiFloat
- Fixes pre-existing Drizzle snapshot chain collision (0007/0008)
- Adds OpenPlantBook env vars to compose.yaml
This commit is contained in:
ginnoir
2026-06-02 04:26:22 -05:00
parent 48063e4b7f
commit b5a966e3a9
13 changed files with 2002 additions and 2 deletions
+78
View File
@@ -1346,3 +1346,81 @@ select {
inset 0 1px 2px rgba(0, 0, 0, 0.12),
0 0 0 2px rgba(244, 239, 229, 0.08);
}
/* ─── Bang Counter celebration animations ─────────────────────────────────── */
@keyframes shake {
0%,
100% {
transform: translateX(0);
}
10% {
transform: translateX(-6px) rotate(-1deg);
}
20% {
transform: translateX(6px) rotate(1deg);
}
30% {
transform: translateX(-5px) rotate(-0.8deg);
}
40% {
transform: translateX(5px) rotate(0.8deg);
}
50% {
transform: translateX(-4px) rotate(-0.5deg);
}
60% {
transform: translateX(4px) rotate(0.5deg);
}
70% {
transform: translateX(-2px);
}
80% {
transform: translateX(2px);
}
90% {
transform: translateX(-1px);
}
}
@keyframes countPop {
0% {
transform: scale(1);
}
30% {
transform: scale(1.45);
}
60% {
transform: scale(0.9);
}
80% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
@keyframes emojiFloat {
0% {
transform: translateY(0) scale(1);
opacity: 1;
}
50% {
transform: translateY(-60px) scale(1.2);
opacity: 0.9;
}
100% {
transform: translateY(-120px) scale(0.7);
opacity: 0;
}
}
.animate-shake {
animation: shake 0.35s ease-in-out both;
}
.animate-count-pop {
animation: countPop 0.4s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
}
.animate-emoji-float {
animation: emojiFloat 1.8s ease-out both;
}