diff --git a/client/src/components/SessionUsersPanel.tsx b/client/src/components/SessionUsersPanel.tsx new file mode 100644 index 0000000..6df2a05 --- /dev/null +++ b/client/src/components/SessionUsersPanel.tsx @@ -0,0 +1,59 @@ +import UserCamera from "./ui/UserCamera"; +import UserDevicesControls from "./ui/UserDevicesControls"; + +export default function SessionUsersPanel() { + const users = [ + { + id: 1, + name: "John Doe", + isSpeaking: true, + isMuted: false, + isVideoOff: false, + isControlDisabled: false, + isAdmin: true, + }, + { + id: 2, + name: "Jane Doe", + isSpeaking: false, + isMuted: true, + isVideoOff: true, + isControlDisabled: true, + }, + { + id: 3, + name: "Jim Doe", + isSpeaking: false, + isMuted: false, + isVideoOff: false, + isControlDisabled: false, + }, + ]; + + function handleMute(id: number) { + console.log(`Mute user ${id}`); + } + function handleVideoOff(id: number) { + console.log(`Video off user ${id}`); + } + function handleCanControl(id: number) { + console.log(`Can control user ${id}`); + } + + return ( +
+
+ {users.map((user) => ( + handleMute(user.id)} + onVideoOff={() => handleVideoOff(user.id)} + onCanControl={() => handleCanControl(user.id)} + {...user} + /> + ))} +
+ +
+ ); +} diff --git a/client/src/components/indicators/Admin.tsx b/client/src/components/indicators/Admin.tsx index b4c517c..adfed1d 100644 --- a/client/src/components/indicators/Admin.tsx +++ b/client/src/components/indicators/Admin.tsx @@ -9,7 +9,7 @@ export default function Admin({ className }: { className?: string }) { className )} > -
+
diff --git a/client/src/components/ui/Tooltip.tsx b/client/src/components/ui/Tooltip.tsx index 022b4cb..82354d6 100644 --- a/client/src/components/ui/Tooltip.tsx +++ b/client/src/components/ui/Tooltip.tsx @@ -23,18 +23,14 @@ export default function Tooltip({ showDelay = 500, }: TooltipProps) { const [isVisible, setIsVisible] = useState(false); - const [tooltipPosition, setTooltipPosition] = useState({ - top: 0, - left: 0, - transform: "none", - }); + const [tooltipPosition, setTooltipPosition] = useState({}); const tooltipWrapperRef = useRef(null); const tooltipRef = useRef(null); useEffect(() => { if (!tooltipWrapperRef.current) return; const current = tooltipWrapperRef.current; - + current.addEventListener("mouseenter", () => setIsVisible(true)); current.addEventListener("mouseleave", () => setIsVisible(false)); return () => { diff --git a/client/src/components/ui/UserCamera.tsx b/client/src/components/ui/UserCamera.tsx new file mode 100644 index 0000000..557423a --- /dev/null +++ b/client/src/components/ui/UserCamera.tsx @@ -0,0 +1,160 @@ +import { AnimatePresence, motion } from "motion/react"; +import { useState } from "react"; + +import HandRaisedOffFilledIcon from "../icons/HandRaisedOffFilledIcon"; +import HandRaisedFilledIcon from "../icons/HandRaisedFilledIcon"; +import MicrophoneFilledIcon from "../icons/MicrophoneFilledIcon"; +import VideoOffFilledIcon from "../icons/VideoOffFilledIcon"; +import MicrophoneOffIcon from "../icons/MicrophoneOffIcon"; +import VideoFilledIcon from "../icons/VideoFilledIcon"; +import ControlButton from "./ControlButton"; +import Admin from "../indicators/Admin"; +import clsx from "clsx"; + +interface UserCameraControlsProps { + isMuted: boolean; + isVideoOff: boolean; + isControlDisabled: boolean; + onMute: () => void; + onVideoOff: () => void; + onCanControl: () => void; +} + +interface UserCameraProps extends UserCameraControlsProps { + isAdmin?: boolean; + name?: string; + mediaStream?: string; + isSpeaking?: boolean; +} + +export default function UserCamera({ + isMuted, + isVideoOff, + isControlDisabled, + onMute, + onVideoOff, + onCanControl, + + isSpeaking = false, + isAdmin = false, + name = "Гость", + mediaStream = "", +}: UserCameraProps) { + const [isHover, setIsHover] = useState(false); + + return ( + setIsHover(true)} + onMouseLeave={() => setIsHover(false)} + animate={{ + width: isHover ? "10.833vw" : "6.944vw", + border: isSpeaking + ? "0.139vw solid #7B60F3" + : "0.139vw solid #FFFFFF4D", + }} + className={clsx( + "aspect-square rounded-[1.667vw] bg-yellow-500 relative flex-shrink-0", + isAdmin && "order-last" + )} + > + {isAdmin && } + + {isHover && ( + + {name} + + )} + + + + ); +} + +function UserCameraControls({ + isMuted, + isVideoOff, + isControlDisabled, + isHover, + onMute, + onVideoOff, + onCanControl, +}: UserCameraControlsProps & { isHover: boolean }) { + return ( +
+ + {isHover ? ( + + : } + size={"small"} + enabled={!isMuted} + onClick={onMute} + /> + : } + size={"small"} + enabled={!isVideoOff} + onClick={onVideoOff} + /> + + ) : ( + + ) + } + size={"small"} + enabled={!isControlDisabled} + onClick={onCanControl} + /> + + ) : ( + +
+ +
+
+ )} +
+
+ ); +} diff --git a/client/src/components/ui/UserDevicesControls.tsx b/client/src/components/ui/UserDevicesControls.tsx new file mode 100644 index 0000000..5068667 --- /dev/null +++ b/client/src/components/ui/UserDevicesControls.tsx @@ -0,0 +1,52 @@ +import MicrophoneFilledIcon from "../icons/MicrophoneFilledIcon"; +import ControlButton from "./ControlButton"; +import VideoFilledIcon from "../icons/VideoFilledIcon"; +import HandRaisedFilledIcon from "../icons/HandRaisedFilledIcon"; +import CogFilledIcon from "../icons/CogFilledIcon"; +import useModalStore from "../../store/modalStore"; +import SettingsModal from "../modals/SettingsModal"; + +export default function UserDevicesControls() { + const { setModal } = useModalStore(); + function ToggleAudioDevice() { + console.log("Mute device"); + } + function ToggleVideoDevice() { + console.log("Video device"); + } + function ToggleCanControl() { + console.log("Can control device"); + } + function ToggleSettings() { + setModal(); + } + + return ( +
+ } + onClick={ToggleAudioDevice} + enabled={true} + /> + } + enabled={true} + onClick={ToggleVideoDevice} + /> + } + onClick={ToggleCanControl} + enabled={true} + /> + } + enabled={true} + onClick={ToggleSettings} + /> +
+ ); +} diff --git a/client/src/pages/HomePage.tsx b/client/src/pages/HomePage.tsx index ab75ce3..1c9ecfd 100644 --- a/client/src/pages/HomePage.tsx +++ b/client/src/pages/HomePage.tsx @@ -8,6 +8,7 @@ import SettingsModal from "../components/modals/SettingsModal"; import useModalStore from "../store/modalStore"; import CogFilledIcon from "../components/icons/CogFilledIcon"; import ParticipantsPopup from "../components/popups/ParticipantsPopup"; +import SessionUsersPanel from "../components/SessionUsersPanel"; function HomePage() { const { data: user } = useMe(); @@ -38,6 +39,7 @@ function HomePage() { +