Participants popup; Actions popover
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 2.2 KiB |
@@ -75,7 +75,7 @@ function PopupWrapper({
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
className={clsx(
|
||||
"2xl:rounded-[2.222vw] rounded-[32px] relative bg-white shadow-[0_4px_40px_0_rgba(15,16,17,0.1)]",
|
||||
"2xl:rounded-[2.222vw] rounded-[32px] relative bg-white shadow-[0_4px_40px_0_rgba(15,16,17,0.1)] overflow-hid den",
|
||||
className
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -3,6 +3,7 @@ import SendIcon from "../icons/SendIcon";
|
||||
import Button from "../ui/Button";
|
||||
import { useMe } from "../../hooks/useAuth";
|
||||
import clsx from "clsx";
|
||||
import PopupWrapper from "../PopupWrapper";
|
||||
|
||||
export default function ChatPopup() {
|
||||
const [messages, setMessages] = useState<MessageItemProps[]>([
|
||||
@@ -23,7 +24,7 @@ export default function ChatPopup() {
|
||||
setMessages([
|
||||
...messages,
|
||||
{
|
||||
senderId: "1",
|
||||
senderId: "2",
|
||||
timestamp: "12:22",
|
||||
content: message,
|
||||
},
|
||||
@@ -31,10 +32,12 @@ export default function ChatPopup() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col w-full h-full relative">
|
||||
<MessageFeed messages={messages} />
|
||||
<MessageInput onMessageSend={onMessageSend} />
|
||||
</div>
|
||||
<PopupWrapper title="Чат" draggable className="max-h-[40]">
|
||||
<div className="flex flex-col h-[27.778vw] relative -m-[1.389vw]">
|
||||
<MessageFeed messages={messages} />
|
||||
<MessageInput onMessageSend={onMessageSend} />
|
||||
</div>
|
||||
</PopupWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import PopupWrapper from "../PopupWrapper";
|
||||
import ActionsPopover from "../ui/ActionsPopover";
|
||||
import MicrophoneFilledIcon from "../icons/MicrophoneFilledIcon";
|
||||
import VideoOffFilledIcon from "../icons/VideoOffFilledIcon";
|
||||
import HandRaisedFilledIcon from "../icons/HandRaisedFilledIcon";
|
||||
import XMarkFilledIcon from "../icons/XMarkFilledIcon";
|
||||
|
||||
export default function ParticipantsPopup() {
|
||||
const participants = [1, 2, 3];
|
||||
return (
|
||||
<PopupWrapper title="Чат" draggable className="h-max">
|
||||
<div className="flex flex-col w-[21.667vw] relative">
|
||||
<ul className="flex flex-col gap-[1.111vw]">
|
||||
{participants.map((participant, index) => (
|
||||
<>
|
||||
<ParticipantItem key={participant} id={participant.toString()} />
|
||||
{index !== participants.length - 1 && (
|
||||
<div className="w-full h-[1px] bg-[#F6F6F6]" />
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</PopupWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
function ParticipantItem({ id }: { id: string }) {
|
||||
return (
|
||||
<div className="flex items-center justify-between w-full h-[2.5vw]">
|
||||
<div className="flex items-center gap-[0.833vw]">
|
||||
<div className="size-[2.5vw] rounded-full bg-[#F6F6F6]">
|
||||
<img
|
||||
src="/img/popups/MessageUserPfp.png"
|
||||
className="size-full object-cover"
|
||||
alt="user"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-[0.278vw]">
|
||||
<span className="button-m">Иван Иванович {id}</span>
|
||||
<span className="caption-s text-[#CCCCCC]">Роль</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<ActionsPopover
|
||||
options={[
|
||||
{
|
||||
icon: <MicrophoneFilledIcon />,
|
||||
label: "Выключить микрофон",
|
||||
onClick: () => {},
|
||||
},
|
||||
{
|
||||
icon: <VideoOffFilledIcon />,
|
||||
label: "Выключить камеру",
|
||||
onClick: () => {},
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
icon: <HandRaisedFilledIcon />,
|
||||
label: "Передать управление",
|
||||
onClick: () => {},
|
||||
},
|
||||
{
|
||||
icon: <XMarkFilledIcon />,
|
||||
label: "Удалить со встречи",
|
||||
onClick: () => {},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
|
||||
interface ActionsPopoverProps {
|
||||
options: {
|
||||
label: string;
|
||||
onClick: () => void;
|
||||
icon?: React.ReactNode;
|
||||
disabled?: boolean;
|
||||
}[];
|
||||
}
|
||||
|
||||
export default function ActionsPopover({ options }: ActionsPopoverProps) {
|
||||
const [isOpened, setIsOpened] = useState(false);
|
||||
const [openUpwards, setOpenUpwards] = useState(false);
|
||||
const popoverRef = useRef<HTMLDivElement>(null);
|
||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||
const [menuHeight, setMenuHeight] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
popoverRef.current &&
|
||||
!popoverRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setIsOpened(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpened && buttonRef.current) {
|
||||
const buttonRect = buttonRef.current.getBoundingClientRect();
|
||||
const spaceBelow = window.innerHeight - buttonRect.bottom;
|
||||
const spaceAbove = buttonRect.top;
|
||||
|
||||
console.log(spaceBelow, menuHeight, spaceAbove);
|
||||
// Если снизу недостаточно места, но сверху достаточно - открываем вверх
|
||||
if (spaceBelow < menuHeight && spaceAbove > menuHeight) {
|
||||
setOpenUpwards(true);
|
||||
} else {
|
||||
setOpenUpwards(false);
|
||||
}
|
||||
}
|
||||
}, [isOpened, menuHeight, options.length]);
|
||||
|
||||
return (
|
||||
<div className="relative" ref={popoverRef}>
|
||||
<button
|
||||
ref={buttonRef}
|
||||
className="flex items-center justify-center gap-[0.139vw] size-[1.667vw]"
|
||||
onClick={() => setIsOpened(!isOpened)}
|
||||
>
|
||||
<div className="size-[0.208vw] rounded-full bg-[#CCCCCC]" />
|
||||
<div className="size-[0.208vw] rounded-full bg-[#CCCCCC]" />
|
||||
<div className="size-[0.208vw] rounded-full bg-[#CCCCCC]" />
|
||||
</button>
|
||||
|
||||
{isOpened && (
|
||||
<div
|
||||
ref={(el) => {
|
||||
setMenuHeight(el?.offsetHeight || 0);
|
||||
}}
|
||||
className={`absolute z-10 right-0 w-[13.333vw] bg-white rounded-[1.111vw] shadow-[0_4px_40px_0_rgba(15,16,17,0.1)] ${
|
||||
openUpwards ? "bottom-[100%]" : "top-[100%]"
|
||||
}`}
|
||||
>
|
||||
{options.map((option) => (
|
||||
<button
|
||||
className="p-[0.833vw] button-s text-[#7D7D7D] w-full flex items-center gap-[0.556vw]"
|
||||
key={option.label}
|
||||
onClick={option.onClick}
|
||||
disabled={option.disabled}
|
||||
style={{
|
||||
backgroundColor: option.disabled ? "#F6F6F6" : "transparent",
|
||||
opacity: option.disabled ? 0.5 : 1,
|
||||
}}
|
||||
>
|
||||
<div className="size-[1.111vw] ">{option.icon}</div>
|
||||
{option.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,14 +1,10 @@
|
||||
<<<<<<< HEAD
|
||||
import ChatPopup from "../components/popups/ChatPopup";
|
||||
=======
|
||||
>>>>>>> 8aef8a530bcdd53af4add911e773f2691e0027e4
|
||||
import Button from "../components/ui/Button";
|
||||
import FloatingActionButton from "../components/ui/FloatingActionButton";
|
||||
import { useMe, useLogout } from "../hooks/useAuth";
|
||||
import { useNavigate } from "react-router";
|
||||
import ShareFilledIcon from "../components/icons/ShareFilledIcon";
|
||||
import SharePopup from "../components/popups/SharePopup";
|
||||
import usePopupStore from "../store/popupStore";
|
||||
import ParticipantsPopup from "../components/popups/ParticipantsPopup";
|
||||
|
||||
function HomePage() {
|
||||
const { data: user } = useMe();
|
||||
@@ -32,8 +28,7 @@ function HomePage() {
|
||||
|
||||
<FloatingActionButton
|
||||
variant="default"
|
||||
// onClick={() => setModal(<ShareModal />)}
|
||||
onClick={() => setPopup(<SharePopup />)}
|
||||
onClick={() => setPopup(<ParticipantsPopup />)}
|
||||
>
|
||||
<div className="2xl:size-[1.111vw] size-4 text-white">
|
||||
<ShareFilledIcon />
|
||||
|
||||
Reference in New Issue
Block a user