mirror of
https://github.com/Since-3/since3-website.git
synced 2026-10-12 21:41:16 +00:00
60 lines
1.9 KiB
TypeScript
60 lines
1.9 KiB
TypeScript
"use client"
|
|
|
|
import { useSyncExternalStore } from "react"
|
|
|
|
import { SOUND_CHANGE_EVENT, isEnabled, play, setEnabled } from "@/lib/sound"
|
|
import { cn } from "@/lib/utils"
|
|
|
|
function subscribe(onChange: () => void) {
|
|
window.addEventListener(SOUND_CHANGE_EVENT, onChange)
|
|
window.addEventListener("storage", onChange)
|
|
return () => {
|
|
window.removeEventListener(SOUND_CHANGE_EVENT, onChange)
|
|
window.removeEventListener("storage", onChange)
|
|
}
|
|
}
|
|
|
|
// Each bar gets its own speed so the equalizer looks organic
|
|
const BAR_DURATIONS = ["0.9s", "0.65s", "1.1s", "0.8s"]
|
|
|
|
/** Equalizer bars that dance while sound is on and lie flat while it is off. */
|
|
export function SoundToggle({ className }: { className?: string }) {
|
|
const enabled = useSyncExternalStore(subscribe, isEnabled, () => false)
|
|
|
|
const toggle = () => {
|
|
const next = !enabled
|
|
setEnabled(next)
|
|
// Forced, so switching off is still audible as feedback
|
|
play(next ? "on" : "off", { force: true })
|
|
}
|
|
|
|
return (
|
|
<button
|
|
type="button"
|
|
data-sound="off"
|
|
onClick={toggle}
|
|
aria-pressed={enabled}
|
|
aria-label={enabled ? "Sound ausschalten" : "Sound einschalten"}
|
|
className={cn(
|
|
"flex h-10 items-center gap-2.5 rounded-full px-2 font-mono text-label",
|
|
className
|
|
)}
|
|
>
|
|
<span aria-hidden="true" className="flex h-3.5 items-end gap-0.5">
|
|
{BAR_DURATIONS.map((duration, index) => (
|
|
<span
|
|
key={index}
|
|
style={{ animationDuration: duration, animationDelay: `${index * -0.23}s` }}
|
|
className={cn(
|
|
"h-full w-0.5 origin-bottom bg-current transition-[scale] duration-300",
|
|
enabled ? "animate-equalizer" : "scale-y-25"
|
|
)}
|
|
/>
|
|
))}
|
|
</span>
|
|
<span aria-hidden="true" className="hidden opacity-80 md:inline">
|
|
{enabled ? "Sound an" : "Sound aus"}
|
|
</span>
|
|
</button>
|
|
)
|
|
}
|