feat(call): add docked call panel and remote cursor overlay

- Implemented DockedCallPanel component to render the docked call interface when an active call is present.
- Created RemoteCursorOverlay component to display remote cursor positions during screen sharing.
- Added hooks for managing docked call state and remote cursor functionality.
- Introduced pending drag state management for seamless transitions between docked and floating states.
- Developed embed filter management components for personal and room-wide settings, allowing users to customize URL embed visibility.
- Implemented auto-joining functionality for rooms within spaces, enhancing user experience during space navigation.
- Added state management for tracking joining progress of rooms in spaces.
This commit is contained in:
2026-02-19 17:49:48 +11:00
parent bfbdf98468
commit 3f6f2134ad
42 changed files with 3801 additions and 219 deletions

View File

@@ -33,6 +33,7 @@ import { useElementSizeObserver } from '../../hooks/useElementSizeObserver';
import { getRoomAvatarUrl, getStateEvent } from '../../utils/room';
import { useStateEventCallback } from '../../hooks/useStateEventCallback';
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
import { JoinSpacePrompt } from '../join-space-prompt';
type GridColumnCount = '1' | '2' | '3';
const getGridColumnCount = (gridWidth: number): GridColumnCount => {
@@ -207,8 +208,32 @@ export const RoomCard = as<'div', RoomCardProps>(
const closeTopic = () => setViewTopic(false);
const openTopic = () => setViewTopic(true);
const [showSpaceJoinPrompt, setShowSpaceJoinPrompt] = useState(false);
const isSpace = roomType === RoomType.Space || joinedRoom?.isSpaceRoom();
const handleJoinClick = () => {
if (isSpace) {
setShowSpaceJoinPrompt(true);
} else {
join();
}
};
const handleSpaceJoinDone = (roomId: string) => {
setShowSpaceJoinPrompt(false);
onView?.(roomId);
};
return (
<RoomCardBase {...props} ref={ref}>
{showSpaceJoinPrompt && (
<JoinSpacePrompt
roomIdOrAlias={roomIdOrAlias}
viaServers={viaServers}
onDone={handleSpaceJoinDone}
onCancel={() => setShowSpaceJoinPrompt(false)}
/>
)}
<Box gap="200" justifyContent="SpaceBetween">
<Avatar size="500">
<RoomAvatar
@@ -222,7 +247,7 @@ export const RoomCard = as<'div', RoomCardProps>(
)}
/>
</Avatar>
{(roomType === RoomType.Space || joinedRoom?.isSpaceRoom()) && (
{isSpace && (
<Badge variant="Secondary" fill="Soft" outlined>
<Text size="L400">Space</Text>
</Badge>
@@ -269,10 +294,10 @@ export const RoomCard = as<'div', RoomCardProps>(
)}
{typeof joinedRoomId !== 'string' && joinState.status !== AsyncStatus.Error && (
<Button
onClick={join}
onClick={handleJoinClick}
variant="Secondary"
size="300"
disabled={joining}
disabled={joining || showSpaceJoinPrompt}
before={joining && <Spinner size="50" variant="Secondary" fill="Soft" />}
>
<Text size="B300" truncate>
@@ -283,7 +308,7 @@ export const RoomCard = as<'div', RoomCardProps>(
{typeof joinedRoomId !== 'string' && joinState.status === AsyncStatus.Error && (
<Box gap="200">
<Button
onClick={join}
onClick={handleJoinClick}
className={css.ActionButton}
variant="Critical"
fill="Solid"