* setup infra for pusher service * setup client sdk for pusher service * fix: ping parse failure * fix: send pong back to client avoid disconnections every 2.5 minutes * increase replicas * feat: show presence and compose indicator
48 lines
1.6 KiB
TypeScript
48 lines
1.6 KiB
TypeScript
import type { Human } from "@/api/types";
|
|
import type { ComposingUser } from "@/features/particles/stream-presence-context";
|
|
|
|
interface ComposingIndicatorProps {
|
|
users: ComposingUser[];
|
|
networkHumans?: Human[];
|
|
}
|
|
|
|
/**
|
|
* Composing indicators pinned to the left edge, text running bottom-to-top
|
|
* via writing-mode so it hugs the edge without transform math issues.
|
|
*/
|
|
export function ComposingIndicator({
|
|
users,
|
|
networkHumans,
|
|
}: ComposingIndicatorProps) {
|
|
if (users.length === 0) return null;
|
|
|
|
return (
|
|
<div
|
|
className="z-100 absolute left-2 top-1/2 z-20 flex -translate-y-1/2 flex-col gap-1.5 animate-in fade-in duration-200"
|
|
style={{ writingMode: "vertical-rl" }}
|
|
>
|
|
{users.map((u) => {
|
|
const human = networkHumans?.find((h) => h.id === u.humanId);
|
|
const name = human?.email_prefix ?? u.humanId;
|
|
const modeLabel = u.mode === "typing" ? "typing" : "recording";
|
|
|
|
return (
|
|
<div
|
|
key={u.humanId}
|
|
className="flex rotate-180 items-center gap-1.5 rounded-full bg-white/10 px-2 py-1 backdrop-blur-sm"
|
|
>
|
|
<span className="flex gap-0.5">
|
|
<span className="size-1 rounded-full bg-white/70 animate-bounce [animation-delay:0ms]" />
|
|
<span className="size-1 rounded-full bg-white/70 animate-bounce [animation-delay:150ms]" />
|
|
<span className="size-1 rounded-full bg-white/70 animate-bounce [animation-delay:300ms]" />
|
|
</span>
|
|
<span className="whitespace-nowrap text-[10px] text-white/50">
|
|
{name} {modeLabel}
|
|
</span>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
}
|