Files
llink/js/desktop/src/components/composing-indicator.tsx
T
Arjun PatelandGitHub a8a0b7db1b infra: add linting and formatting for js projects (#230)
* wip

* wip

* wip

* format

* wip(mobile): lint and format

* cleanup

* nits

* nits

* idiomatic react

* nit

* format all root files
2026-06-02 07:44:24 -07:00

48 lines
1.6 KiB
TypeScript

import type { Human } from '@/api/types';
import { resolveHumanDisplay } from '@/lib/humans';
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 { displayName } = resolveHumanDisplay(u.humanId, networkHumans);
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">
{displayName} {modeLabel}
</span>
</div>
);
})}
</div>
);
}