feat(import): fire confetti when the complete banner appears
Vendors canvas-confetti 1.9.3 and wires an ImportConfetti hook on the alert-success banner that /imports/:id already renders when run.status == "complete". The hook uses the "realistic look" preset from confetti.js.org and runs on mount, so it fires exactly once — when the banner first appears.
This commit is contained in:
parent
cec74c727c
commit
b4a36890da
4 changed files with 54 additions and 1 deletions
|
|
@ -9,6 +9,7 @@ import {Socket} from "phoenix"
|
|||
import {LiveSocket} from "phoenix_live_view"
|
||||
import {hooks as colocatedHooks} from "phoenix-colocated/microwaveprop"
|
||||
import topbar from "../vendor/topbar"
|
||||
import "../vendor/canvas-confetti"
|
||||
|
||||
import initLiveStash from "../../deps/live_stash/assets/js/live-stash.js"
|
||||
import {PropagationMap} from "./propagation_map_hook"
|
||||
|
|
@ -46,6 +47,25 @@ interface CommaNumberHook extends ViewHook {
|
|||
format(): void
|
||||
}
|
||||
|
||||
// Realistic-look recipe from https://confetti.js.org (the "realistic" preset).
|
||||
// Fires exactly once when the hook element mounts — we attach the hook to
|
||||
// the import-complete banner, which only renders when run.status == "complete".
|
||||
const ImportConfetti = {
|
||||
mounted(this: ViewHook) {
|
||||
const fire = window.confetti
|
||||
if (typeof fire !== "function") return
|
||||
const count = 200
|
||||
const defaults = { origin: { y: 0.7 } }
|
||||
const burst = (particleRatio: number, opts: ConfettiOptions) =>
|
||||
fire({ ...defaults, ...opts, particleCount: Math.floor(count * particleRatio) })
|
||||
burst(0.25, { spread: 26, startVelocity: 55 })
|
||||
burst(0.2, { spread: 60 })
|
||||
burst(0.35, { spread: 100, decay: 0.91, scalar: 0.8 })
|
||||
burst(0.1, { spread: 120, startVelocity: 25, decay: 0.92, scalar: 1.2 })
|
||||
burst(0.1, { spread: 120, startVelocity: 45 })
|
||||
}
|
||||
}
|
||||
|
||||
const CommaNumber = {
|
||||
mounted(this: CommaNumberHook) {
|
||||
this.el.addEventListener("input", () => this.format())
|
||||
|
|
@ -74,7 +94,7 @@ const csrfToken = document.querySelector("meta[name='csrf-token']")!.getAttribut
|
|||
const liveSocket = new LiveSocket("/live", Socket, {
|
||||
longPollFallbackMs: 2500,
|
||||
params: initLiveStash({_csrf_token: csrfToken}),
|
||||
hooks: {...colocatedHooks, PropagationMap, UtcClock, ContactMap, ContactsMap, ElevationProfile, WeatherMap, LocateMe, CopyLink, RoverMap, BeaconMap, BeaconsListMap, CommaNumber},
|
||||
hooks: {...colocatedHooks, PropagationMap, UtcClock, ContactMap, ContactsMap, ElevationProfile, WeatherMap, LocateMe, CopyLink, RoverMap, BeaconMap, BeaconsListMap, CommaNumber, ImportConfetti},
|
||||
})
|
||||
|
||||
// live_table rows are dead on their own — wire up whole-row clicks to
|
||||
|
|
|
|||
24
assets/js/types/global.d.ts
vendored
24
assets/js/types/global.d.ts
vendored
|
|
@ -48,6 +48,29 @@ declare module "../vendor/chart.js" {
|
|||
}
|
||||
}
|
||||
|
||||
// canvas-confetti UMD attaches to window.confetti as a side effect.
|
||||
declare module "../vendor/canvas-confetti" {
|
||||
const _default: void
|
||||
export default _default
|
||||
}
|
||||
|
||||
type ConfettiOptions = {
|
||||
particleCount?: number
|
||||
angle?: number
|
||||
spread?: number
|
||||
startVelocity?: number
|
||||
decay?: number
|
||||
gravity?: number
|
||||
drift?: number
|
||||
ticks?: number
|
||||
origin?: { x?: number; y?: number }
|
||||
colors?: string[]
|
||||
shapes?: string[]
|
||||
scalar?: number
|
||||
zIndex?: number
|
||||
disableForReducedMotion?: boolean
|
||||
}
|
||||
|
||||
declare module "../vendor/leaflet/leaflet.js" {
|
||||
export = L
|
||||
}
|
||||
|
|
@ -89,4 +112,5 @@ interface Window {
|
|||
L: typeof import("leaflet")
|
||||
liveSocket: any
|
||||
liveReloader: any
|
||||
confetti: (opts?: ConfettiOptions) => Promise<void> | null
|
||||
}
|
||||
|
|
|
|||
8
assets/vendor/canvas-confetti.js
vendored
Normal file
8
assets/vendor/canvas-confetti.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -114,6 +114,7 @@ defmodule MicrowavepropWeb.ImportLive do
|
|||
:if={@run.status == "complete"}
|
||||
id="import-complete-panel"
|
||||
class="alert alert-success"
|
||||
phx-hook="ImportConfetti"
|
||||
>
|
||||
<.icon name="hero-check-circle" class="w-6 h-6" />
|
||||
<div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue