feat(don): add volume slider to moderator
This commit is contained in:
@@ -13,7 +13,7 @@ import {
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import posthog from "posthog-js";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useEllipsisVisible } from "react-hook-text-overflow";
|
||||
import { DataTable } from "@/components/tantable";
|
||||
import { SimpleTooltip } from "@/components/tooltip";
|
||||
@@ -183,23 +183,15 @@ export function DonateAdminPage({
|
||||
}
|
||||
|
||||
// component cuz simplicity sake
|
||||
export function DonateWatcher({ sfx = false }: { sfx?: boolean }) {
|
||||
const player = useRef<HTMLAudioElement | null>(null);
|
||||
export function DonateWatcher() {
|
||||
const router = useRouter();
|
||||
useEffect(() => {
|
||||
if (!router) return;
|
||||
return sse.donate.subMany({
|
||||
ping: () => {
|
||||
router.refresh();
|
||||
player.current?.play();
|
||||
},
|
||||
update: () => router.refresh(),
|
||||
ping: router.refresh.bind(router),
|
||||
update: router.refresh.bind(router),
|
||||
}).clean;
|
||||
}, [router]);
|
||||
|
||||
if (sfx)
|
||||
return (
|
||||
<audio src="/assets/donate-mod-sfx.wav" preload="auto" ref={player} />
|
||||
);
|
||||
else return undefined;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
"use client";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Slider } from "@/components/ui/slider";
|
||||
import { shared } from "@/lib/comms";
|
||||
import { sse } from "@/lib/db/sse-endpoints";
|
||||
import { ExternalLink, RadioTower } from "lucide-react";
|
||||
import dynamic from "next/dynamic";
|
||||
@@ -39,10 +41,22 @@ export function PIP(props: ComponentProps<typeof ReactPIP>) {
|
||||
|
||||
export function ClientTracker() {
|
||||
const [connected, setConnected] = useState(0);
|
||||
const player = useRef<HTMLAudioElement>(null);
|
||||
const tracking = useRef(0);
|
||||
|
||||
shared.signal(
|
||||
"moderator.volume",
|
||||
(ev) => player.current && (player.current.volume = ev ?? 1),
|
||||
);
|
||||
|
||||
useEffect(
|
||||
() => sse.donate.sub("heartbeat", () => tracking.current++).clean,
|
||||
() =>
|
||||
player.current
|
||||
? sse.donate.subMany({
|
||||
heartbeat: () => tracking.current++,
|
||||
ping: player.current.play.bind(player.current),
|
||||
}).clean
|
||||
: undefined,
|
||||
[],
|
||||
);
|
||||
useEffect(() => {
|
||||
@@ -54,7 +68,28 @@ export function ClientTracker() {
|
||||
}, []);
|
||||
return (
|
||||
<Button variant="outline" disabled size="sm">
|
||||
<RadioTower /> Connected: {connected}
|
||||
<RadioTower /> {connected}
|
||||
<audio
|
||||
src="/assets/donate-mod-sfx.wav"
|
||||
preload="auto"
|
||||
ref={player}
|
||||
hidden
|
||||
/>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
export function VolumeChanger() {
|
||||
const [volume, setVolume] = shared.state("moderator.volume");
|
||||
|
||||
return (
|
||||
<div className="px-5 py-1">
|
||||
<Slider
|
||||
max={1}
|
||||
step={0.01}
|
||||
value={[volume ?? 0.5]}
|
||||
onValueChange={(v) => setVolume(v[0])}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { Spinner } from "@/components/ui/spinner";
|
||||
import { ActionButton } from "@/components/action-button";
|
||||
import { reloadWidget } from "../api";
|
||||
import { markDone } from "@/app/widget/donate/api";
|
||||
import { ClientTracker, PIP } from "./client";
|
||||
import { ClientTracker, PIP, VolumeChanger } from "./client";
|
||||
|
||||
export default async function DonateModeratorPage() {
|
||||
if (!(await adminCheck()))
|
||||
@@ -32,7 +32,7 @@ export default async function DonateModeratorPage() {
|
||||
|
||||
return (
|
||||
<PIP width={400} height={600}>
|
||||
<div className="dark flex w-full max-w-100 flex-col gap-1 bg-background p-1 text-foreground scheme-dark">
|
||||
<div className="dark flex w-full max-w-100 flex-col gap-1 rounded-md bg-background p-1 text-foreground scheme-dark">
|
||||
<span>Donate Moderator</span>
|
||||
{sub.image ? (
|
||||
<div className="relative flex aspect-square w-full max-w-100 items-center justify-center overflow-hidden rounded-lg border bg-black/50">
|
||||
@@ -67,7 +67,8 @@ export default async function DonateModeratorPage() {
|
||||
</ActionButton>
|
||||
<ClientTracker />
|
||||
</div>
|
||||
<DonateWatcher sfx />
|
||||
<VolumeChanger />
|
||||
<DonateWatcher />
|
||||
</div>
|
||||
</PIP>
|
||||
);
|
||||
|
||||
@@ -168,6 +168,13 @@ export const DocumentPictureInPicture = forwardRef<
|
||||
|
||||
div.style.width = "100%";
|
||||
div.style.height = "100%";
|
||||
div.style.background = "black";
|
||||
div.style.backgroundImage = "radial-gradient(#222 1px, transparent 1px)";
|
||||
div.style.backgroundSize = "24px 24px";
|
||||
div.style.height = "100svh";
|
||||
div.style.display = "flex";
|
||||
div.style.justifyContent = "center";
|
||||
div.style.alignItems = "center";
|
||||
|
||||
win.document.body.appendChild(div);
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ type SharedStates = Partial<{
|
||||
warning: "showcase" | "nf" | "guide" | "private";
|
||||
"warning.uid": string;
|
||||
"warning.src": "submit" | "input";
|
||||
"moderator.volume": number;
|
||||
_raw: Record<string, unknown>;
|
||||
}>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user