feat(calls): live-call dot on the space rail (#148)
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s

A small red dot on a space tab when any room in that space (recursively)
has an active MatrixRTC session, so a live call is visible even when you
are looking at a different space or your DMs. Hidden while the space is
selected — the room list already shows the Live badge there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
2026-09-19 23:25:49 -04:00
co-authored by Claude Opus 5
parent b69099a862
commit 4fe9c87010
3 changed files with 81 additions and 0 deletions
@@ -0,0 +1,16 @@
import { style } from '@vanilla-extract/css';
import { color, toRem } from 'folds';
/** [Gitea #148] Bottom-right live-call dot on a space tab. */
export const LiveDot = style({
position: 'absolute',
right: toRem(-2),
bottom: toRem(-2),
width: toRem(10),
height: toRem(10),
borderRadius: '50%',
backgroundColor: color.Critical.Main,
boxShadow: `0 0 0 ${toRem(2)} ${color.Background.Container}`,
pointerEvents: 'none',
zIndex: 1,
});
@@ -47,6 +47,8 @@ import {
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { roomToParentsAtom } from '../../../state/room/roomToParents';
import { allRoomsAtom } from '../../../state/room-list/roomList';
import { useAnyRoomLiveCall } from '../../../hooks/useSpaceLiveCall';
import { LiveDot } from './SpaceTabs.css';
import {
getOriginBaseUrl,
getSpaceLobbyPath,
@@ -450,6 +452,15 @@ function SpaceTab({
const [menuAnchor, setMenuAnchor] = useState<RectCords>();
// [Gitea #148] Subtle live-call dot for a space you're not looking at.
const roomToParentsForLive = useAtomValue(roomToParentsAtom);
const liveChildren = useSpaceChildren(
allRoomsAtom,
space.roomId,
useRecursiveChildScopeFactory(mx, roomToParentsForLive),
);
const liveCall = useAnyRoomLiveCall(liveChildren);
const handleContextMenu: MouseEventHandler<HTMLButtonElement> = (evt) => {
evt.preventDefault();
const cords = evt.currentTarget.getBoundingClientRect();
@@ -497,6 +508,14 @@ function SpaceTab({
<UnreadBadge highlight={unread.highlight > 0} count={unread.total} />
</SidebarItemBadge>
)}
{liveCall && !selected && (
<span
className={LiveDot}
role="img"
aria-label="A call is live in this space"
title="A call is live in this space"
/>
)}
{menuAnchor && (
<PopOut
anchor={menuAnchor}