Enhance DraggableContainer to set initial position based on bounding rectangle and update SessionUsersPanel to limit local cameras to one. Refactor UserCamera styling for consistency and improve PopoverWrapper positioning logic. Clean up unnecessary code in SessionUsersPanel for better readability.
This commit is contained in:
@@ -446,6 +446,15 @@ export default function DraggableContainer({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isDragging]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!containerRef.current) return;
|
||||
const rect = containerRef.current.getBoundingClientRect();
|
||||
setPosition({
|
||||
top: rect.top,
|
||||
left: rect.left,
|
||||
});
|
||||
}, []);
|
||||
|
||||
// Устанавливаем cursor стили на элемент-хэндл
|
||||
useEffect(() => {
|
||||
if (!draggable || !dragHandleRef?.current) return;
|
||||
@@ -496,7 +505,7 @@ export default function DraggableContainer({
|
||||
|
||||
// Если компонент отключен, просто рендерим children без стилей и логики
|
||||
if (!enabled) {
|
||||
return <>{children}</>;
|
||||
return <div className={className}>{children}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useWebRTC } from "../hooks/useWebRTC";
|
||||
import clsx from "clsx";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
const LOCAL_CAMERAS_COUNT = 10;
|
||||
const LOCAL_CAMERAS_COUNT = 1;
|
||||
|
||||
interface SessionUsersPanelProps {
|
||||
roomId: string;
|
||||
@@ -157,91 +157,76 @@ function SessionUsersPanel({
|
||||
windowDimensions.width >= 640 ? "bottom-right" : "top-right"
|
||||
}
|
||||
padding="1.111vw"
|
||||
// className={clsx(
|
||||
// "z-[100] 2xl:gap-[0.556vw] gap-2",
|
||||
// mode === "mini"
|
||||
// ? "flex"
|
||||
// : `2xl:p-[5vw] p-4 w-full 2xl:h-dvh max-2xl:portrait:max-h-[calc(100dvh-17.778vw)] max-2xl:landscape:max-h-[calc(100dvh-8.75vw)] grid grid-cols-${gridColumns} relative bg-black`
|
||||
// )}
|
||||
className={clsx(
|
||||
"z-[100] 2xl:gap-[0.556vw] gap-2",
|
||||
mode === "mini"
|
||||
? "flex"
|
||||
: `2xl:p-[2.778vw_5vw_5vw] p-[12px_12px_72px] w-full 2xl:h-dvh grid grid-cols-${gridColumns} relative 2xl:bg-black auto-rows-fr`
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
"z-[100] 2xl:gap-[0.556vw] gap-2",
|
||||
mode === "mini"
|
||||
? "flex"
|
||||
: `2xl:p-[5vw] p-4 w-full 2xl:h-dvh max-2xl:portrait:max-h-[calc(100dvh-17.778vw)] max-2xl:landscape:max-h-[calc(100dvh-8.75vw)] grid grid-cols-${gridColumns} relative bg-black`
|
||||
)}
|
||||
>
|
||||
{localStream &&
|
||||
Array.from({ length: LOCAL_CAMERAS_COUNT }).map((_, index) => (
|
||||
<UserCamera
|
||||
key={index}
|
||||
mode={mode}
|
||||
name="Вы"
|
||||
isMuted={isLocalAudioMuted}
|
||||
isVideoOff={isLocalVideoMuted}
|
||||
isControlDisabled={false}
|
||||
isAdmin={true}
|
||||
isLocal={true}
|
||||
mediaStream={localStream}
|
||||
onMute={toggleAudio}
|
||||
onVideoOff={toggleVideo}
|
||||
onCanControl={() => console.log("Toggle control")}
|
||||
onSpeakingChange={handleSpeakingChange}
|
||||
className={clsx(
|
||||
mode === "full" && activeCamerasCount <= 2
|
||||
? "m-auto"
|
||||
: activeCamerasCount > 12
|
||||
? "!aspect-square w-full"
|
||||
: "w-full"
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
{mode === "full" && <div className="fixed bg-black inset-0 2xl:hidden" />}
|
||||
{localStream &&
|
||||
Array.from({ length: LOCAL_CAMERAS_COUNT }).map((_, index) => (
|
||||
<UserCamera
|
||||
key={index}
|
||||
mode={mode}
|
||||
name="Вы"
|
||||
isMuted={isLocalAudioMuted}
|
||||
isVideoOff={isLocalVideoMuted}
|
||||
isControlDisabled={false}
|
||||
isAdmin={true}
|
||||
isLocal={true}
|
||||
mediaStream={localStream}
|
||||
onMute={toggleAudio}
|
||||
onVideoOff={toggleVideo}
|
||||
onCanControl={() => console.log("Toggle control")}
|
||||
onSpeakingChange={handleSpeakingChange}
|
||||
className={clsx(
|
||||
mode === "full" &&
|
||||
(activeCamerasCount <= 2 ? "m-auto" : "min-w-full min-h-full")
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Камеры удаленных участников - показываем только если есть поток с активными треками */}
|
||||
{participants
|
||||
.filter(
|
||||
(participant) =>
|
||||
participant.stream != null &&
|
||||
participant.stream.getTracks().length > 0
|
||||
)
|
||||
.map((participant) => (
|
||||
<UserCamera
|
||||
className={clsx(
|
||||
mode === "full" &&
|
||||
(activeCamerasCount <= 2
|
||||
? "m-auto"
|
||||
: activeCamerasCount > 12
|
||||
? "!aspect-square w-full"
|
||||
: "w-full")
|
||||
)}
|
||||
key={participant.id}
|
||||
mode={mode}
|
||||
name={participant.id}
|
||||
isMuted={participant.isMuted || false}
|
||||
isVideoOff={participant.isVideoOff || false}
|
||||
isSpeaking={participant.isSpeaking}
|
||||
isControlDisabled={true}
|
||||
isAdmin={true}
|
||||
mediaStream={participant.stream}
|
||||
hasLocalMediaPermission={hasLocalStream}
|
||||
onMute={() => console.log(`Mute user ${participant.id}`)}
|
||||
onVideoOff={() => console.log(`Video off user ${participant.id}`)}
|
||||
onCanControl={() =>
|
||||
console.log(`Can control user ${participant.id}`)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
{/* Камеры удаленных участников - показываем только если есть поток с активными треками */}
|
||||
{participants
|
||||
.filter(
|
||||
(participant) =>
|
||||
participant.stream != null &&
|
||||
participant.stream.getTracks().length > 0
|
||||
)
|
||||
.map((participant) => (
|
||||
<UserCamera
|
||||
className={clsx(
|
||||
mode === "full" &&
|
||||
(activeCamerasCount <= 2 ? "m-auto" : "min-w-full min-h-full")
|
||||
)}
|
||||
key={participant.id}
|
||||
mode={mode}
|
||||
name={participant.name}
|
||||
isMuted={participant.isMuted || false}
|
||||
isVideoOff={participant.isVideoOff || false}
|
||||
isSpeaking={participant.isSpeaking}
|
||||
isControlDisabled={true}
|
||||
isAdmin={true}
|
||||
mediaStream={participant.stream}
|
||||
hasLocalMediaPermission={hasLocalStream}
|
||||
onMute={() => console.log(`Mute user ${participant.id}`)}
|
||||
onVideoOff={() => console.log(`Video off user ${participant.id}`)}
|
||||
onCanControl={() =>
|
||||
console.log(`Can control user ${participant.id}`)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
|
||||
<UserDevicesControls
|
||||
mode={mode}
|
||||
toggleAudio={toggleAudio}
|
||||
toggleVideo={toggleVideo}
|
||||
isAudioMuted={isLocalAudioMuted}
|
||||
isVideoMuted={isLocalVideoMuted}
|
||||
hasLocalStream={hasLocalStream}
|
||||
/>
|
||||
</div>
|
||||
<UserDevicesControls
|
||||
mode={mode}
|
||||
toggleAudio={toggleAudio}
|
||||
toggleVideo={toggleVideo}
|
||||
isAudioMuted={isLocalAudioMuted}
|
||||
isVideoMuted={isLocalVideoMuted}
|
||||
hasLocalStream={hasLocalStream}
|
||||
/>
|
||||
</DraggableContainer>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ function PopoverWrapper({
|
||||
(position === "side" || position === "vertical")
|
||||
) {
|
||||
const buttonRect = parentElRef.current.getBoundingClientRect();
|
||||
console.log(buttonRect);
|
||||
const spaceBelow = window.innerHeight - buttonRect.bottom;
|
||||
const spaceAbove = buttonRect.top;
|
||||
setOpenUpwards(spaceBelow < menuHeight && spaceAbove > menuHeight);
|
||||
@@ -99,9 +100,7 @@ function PopoverWrapper({
|
||||
}}
|
||||
style={getPositionStyles()}
|
||||
className={clsx(
|
||||
"fixed z-[99999] shadow-[0_4px_40px_0_rgba(15,16,17,0.1)] overflow-hidden bg-white 2xl:rounded-[1.111vw] rounded-2xl",
|
||||
position === "side" && "-translate-x-full",
|
||||
position === "vertical" && "-translate-x-full",
|
||||
"fixed z-[99999] shadow-[0_4px_40px_0_rgba(15,16,17,0.1)] overflow-hidden bg-white 2xl:rounded-[1.111vw] rounded-2xl -translate-x-full",
|
||||
className
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -280,7 +280,7 @@ export default function UserCamera({
|
||||
className={clsx(
|
||||
mode === "mini"
|
||||
? "aspect-square h-fit group 2xl:rounded-[1.667vw] rounded-2xl relative flex-shrink-0 pointer-events-auto 2xl:hover:w-[10.833vw] 2xl:w-[6.944vw] sm:w-[15.625vw] w-[27.778vw] overflow-hidden"
|
||||
: "aspect-video 2xl:rounded-[2.222vw] rounded-[32px] overflow-hidden group relative pointer-events-auto max-w-full h-full self-center object-cover",
|
||||
: "aspect-video 2xl:rounded-[1.667vw] rounded-2xl overflow-hidden group relative pointer-events-auto max-w-full 2xl:h-full object-cover",
|
||||
isLocal && "order-last",
|
||||
isVideoOff ? "bg-green-500" : "bg-yellow-500/10",
|
||||
className
|
||||
@@ -302,10 +302,7 @@ export default function UserCamera({
|
||||
>
|
||||
{isLocal && <Admin className="absolute top-0 right-0" />}
|
||||
|
||||
<div
|
||||
key="name"
|
||||
className="absolute whitespace-nowrap transition-opacity duration-300 group-hover:opacity-100 opacity-0 text-white button-s top-[0.556vw] left-1/2 translate-x-[-50%] px-[0.556vw] py-[0.278vw] rounded-full bg-[#14141440] backdrop-blur-[4px]"
|
||||
>
|
||||
<div className="absolute whitespace-nowrap transition-opacity duration-300 group-hover:opacity-100 opacity-0 text-white button-s top-[0.556vw] left-1/2 translate-x-[-50%] px-[0.556vw] py-[0.278vw] rounded-full bg-[#14141440] backdrop-blur-[4px]">
|
||||
{name}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user