upd
This commit is contained in:
+83
-201
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-irregular-whitespace */
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
@@ -9,7 +10,7 @@ import { io } from "socket.io-client";
|
||||
import userAgentParser from "ua-parser-js";
|
||||
import { Player } from "./components/Player";
|
||||
import { Trans } from "react-i18next";
|
||||
import { useScreen } from "usehooks-ts";
|
||||
// import { useScreen } from "usehooks-ts";
|
||||
import ShareIcon from "./components/icons/ShareIcon";
|
||||
import ModalContainer from "./components/ModalContainer";
|
||||
import useModalStore from "./stores/useModalStore";
|
||||
@@ -20,14 +21,9 @@ import "react-toastify/dist/ReactToastify.css";
|
||||
import FullscreenIcon from "./components/icons/FullscreenIcon";
|
||||
import WindowedModeIcon from "./components/icons/WindowedModeIcon";
|
||||
import QRIcon from "./components/icons/QRIcon";
|
||||
import AdminUserIcon from "./components/icons/AdminUserIcon";
|
||||
import UserIcon from "./components/icons/UserIcon";
|
||||
import MobilePhoneIcon from "./components/icons/MobilePhoneIcon";
|
||||
import DesktopIcon from "./components/icons/DesktopIcon";
|
||||
import HandOffIcon from "./components/icons/HandOffIcon";
|
||||
import HandOnIcon from "./components/icons/HandOnIcon";
|
||||
import ExitIcon from "./components/icons/ExitIcon";
|
||||
import QRCodeModal from "./components/modals/QRCodeModal";
|
||||
import PersonsIcon from "./components/icons/PersonsIcon";
|
||||
import UsersManagementModal from "./components/modals/UsersManagementModal";
|
||||
|
||||
function StreamPage() {
|
||||
const params = useParams();
|
||||
@@ -38,18 +34,18 @@ function StreamPage() {
|
||||
const [socket, setSocket] = useState<any>(null);
|
||||
const [users, setUsers] = useState<any>([]);
|
||||
const [me, setMe] = useState<any>({});
|
||||
const [isOpenSidebar, setIsOpenSidebar] = useState<boolean>(false);
|
||||
const screen = useScreen();
|
||||
|
||||
// const screen = useScreen();
|
||||
const [modal, setModal] = useModalStore((state) => [
|
||||
state.modal,
|
||||
state.setModal,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (screen?.orientation.type.includes("portrait")) {
|
||||
// alert("portrait");
|
||||
}
|
||||
}, [screen]);
|
||||
// useEffect(() => {
|
||||
// if (screen?.orientation.type.includes("portrait")) {
|
||||
// alert("portrait");
|
||||
// }
|
||||
// }, [screen]);
|
||||
|
||||
function toastWarn(text: string) {
|
||||
toast.warn(text, {
|
||||
@@ -116,6 +112,8 @@ function StreamPage() {
|
||||
socket.on("join", (_socketId, room) => {
|
||||
setUsers(room.users);
|
||||
// console.log("join: ", _socketId, room.users);
|
||||
|
||||
toastInfo("Присоеденился новый участник");
|
||||
});
|
||||
|
||||
socket.on("update", (_socketId, room) => {
|
||||
@@ -147,192 +145,7 @@ function StreamPage() {
|
||||
}, [me]);
|
||||
|
||||
return (
|
||||
<FullScreen handle={handleFullScreen} className="h-screen text-[#F2F2F2] ">
|
||||
<div
|
||||
className={[
|
||||
"absolute z-30 top-0 left-0 h-screen bg-[#1C1D21] space-y-2 flex flex-col justify-between text-xs whitespace-nowrap text-clip transition-all",
|
||||
isOpenSidebar ? "w-[280px]" : "w-0",
|
||||
].join(" ")}
|
||||
>
|
||||
<div
|
||||
className={[
|
||||
"p-2 transition-opacity",
|
||||
isOpenSidebar ? "opacity-100" : "opacity-0",
|
||||
].join(" ")}
|
||||
>
|
||||
<div className="flex flex-col overflow-hidden">
|
||||
{!handleFullScreen.active ? (
|
||||
<button
|
||||
onClick={handleFullScreen.enter}
|
||||
className="p-2 flex space-x-2 items-center outline-none"
|
||||
>
|
||||
<FullscreenIcon />
|
||||
<span>
|
||||
<Trans i18nKey={"fullscreenMode"}>Полноэкранный режим</Trans>
|
||||
</span>
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={handleFullScreen.exit}
|
||||
className="p-2 flex space-x-2 items-center outline-none"
|
||||
>
|
||||
<WindowedModeIcon />
|
||||
<span>
|
||||
<Trans i18nKey={"windowedMode"}>Оконный режим</Trans>
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={() => setModal(<QRCodeModal />)}
|
||||
className="p-2 flex space-x-2 items-center outline-none"
|
||||
>
|
||||
<QRIcon />
|
||||
<span>
|
||||
<Trans i18nKey={"inviteByQR"}>Пригласить по QR</Trans>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => setModal(<ShareModal />)}
|
||||
className="p-2 flex space-x-2 items-center outline-none"
|
||||
>
|
||||
<ShareIcon />
|
||||
<span>Поделиться</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="m-1 h-0.5 bg-[#2E3038]"></div>
|
||||
|
||||
<div className="">
|
||||
{users.map((user: any) => (
|
||||
<div
|
||||
key={user.id}
|
||||
className="p-2 border-gray-700 flex items-center space-x-2"
|
||||
>
|
||||
<div className="flex flex-col justify-center items-center">
|
||||
{user.admin ? <AdminUserIcon /> : <UserIcon />}
|
||||
|
||||
{me && me.id === user.id && (
|
||||
<p className="text-[#73788C]">Вы</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="font-bold">
|
||||
{user.admin ? "Администратор" : "Пользователь"}
|
||||
</p>
|
||||
<p>({user.city})</p>
|
||||
</div>
|
||||
|
||||
{new userAgentParser(user.ua).getDevice().type === "mobile" ? (
|
||||
<MobilePhoneIcon />
|
||||
) : (
|
||||
<DesktopIcon />
|
||||
)}
|
||||
|
||||
{!user.admin && (
|
||||
<>
|
||||
{user.allowControl ? (
|
||||
<button
|
||||
onClick={() => update(user.id, { allowControl: false })}
|
||||
className="outline-none mt-1"
|
||||
>
|
||||
<HandOnIcon />
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={() => update(user.id, { allowControl: true })}
|
||||
className="outline-none mt-1"
|
||||
>
|
||||
<HandOffIcon />
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{me && me.admin && !user.admin && (
|
||||
<button
|
||||
onClick={() => kick(user.id)}
|
||||
className="outline-none"
|
||||
>
|
||||
<ExitIcon />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="absolute top-[50%] -right-[29px] -translate-y-[50%] transition-all">
|
||||
{!isOpenSidebar ? (
|
||||
<button
|
||||
onClick={() => setIsOpenSidebar(true)}
|
||||
className="p-2 relative outline-none"
|
||||
>
|
||||
<svg
|
||||
width="24"
|
||||
height="130"
|
||||
viewBox="0 0 24 130"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M0 1H3.69231L22.4433 30.547C23.4601 32.1492 24 34.0076 24 35.9053V94.0947C24 95.9924 23.4601 97.8508 22.4433 99.453L3.69231 129H0V1Z"
|
||||
fill="#1C1D21"
|
||||
/>
|
||||
<path
|
||||
d="M13 70L18 65L13 60"
|
||||
stroke="#C5C7CE"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M8 75L8 65L8 55"
|
||||
stroke="#C5C7CE"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={() => setIsOpenSidebar(false)}
|
||||
className="p-2 outline-none"
|
||||
>
|
||||
<svg
|
||||
width="24"
|
||||
height="130"
|
||||
viewBox="0 0 24 130"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M0 1H3.69231L22.4433 30.547C23.4601 32.1492 24 34.0076 24 35.9053V94.0947C24 95.9924 23.4601 97.8508 22.4433 99.453L3.69231 129H0V1Z"
|
||||
fill="#1C1D21"
|
||||
/>
|
||||
<path
|
||||
d="M11 70L6 65L11 60"
|
||||
stroke="#C5C7CE"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M16 75L16 65L16 55"
|
||||
stroke="#C5C7CE"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<FullScreen handle={handleFullScreen} className="h-screen text-[#F2F2F2]">
|
||||
{!isStreamEnded ? (
|
||||
isStreamLoaded ? (
|
||||
<>{streamUrl && <Player ss={streamUrl} />}</>
|
||||
@@ -369,6 +182,75 @@ function StreamPage() {
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="absolute top-0 left-0 min-h-screen flex flex-col justify-center transition-all">
|
||||
<div className="flex flex-col gap-2 lg:p-4 p-2">
|
||||
{new userAgentParser().getDevice().model !== "iPhone" && (
|
||||
<>
|
||||
{!handleFullScreen.active ? (
|
||||
<button
|
||||
onClick={() => handleFullScreen.enter()}
|
||||
className="relative group outline-none bg-[#131313] rounded-full shadow-lg shadow-[#131313] p-2 opacity-90"
|
||||
>
|
||||
<FullscreenIcon />
|
||||
<span className="absolute left-12 top-[50%] -translate-y-[50%] invisible group-hover:visible opacity-0 group-hover:opacity-100 text-xs transition-all px-2 py-1 bg-[#131313] rounded">
|
||||
Полноэкранный режим
|
||||
</span>
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={() => handleFullScreen.exit()}
|
||||
className="relative group outline-none bg-[#131313] rounded-full shadow-lg shadow-[#131313] p-2 opacity-90"
|
||||
>
|
||||
<WindowedModeIcon />
|
||||
<span className="absolute left-12 top-[50%] -translate-y-[50%] invisible group-hover:visible opacity-0 group-hover:opacity-100 text-xs transition-all px-2 py-1 bg-[#131313] rounded">
|
||||
Оконный режим
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={() => setModal(<QRCodeModal />)}
|
||||
className="relative group outline-none bg-[#131313] rounded-full shadow-lg shadow-[#131313] p-2 opacity-90"
|
||||
>
|
||||
<QRIcon />
|
||||
<span className="absolute left-12 top-[50%] -translate-y-[50%] invisible group-hover:visible opacity-0 group-hover:opacity-100 text-xs transition-all px-2 py-1 bg-[#131313] rounded">
|
||||
Пригласить по QR
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => setModal(<ShareModal />)}
|
||||
className="relative group outline-none bg-[#131313] rounded-full shadow-lg shadow-[#131313] p-2 opacity-90"
|
||||
>
|
||||
<ShareIcon />
|
||||
<span className="absolute left-12 top-[50%] -translate-y-[50%] invisible group-hover:visible opacity-0 group-hover:opacity-100 text-xs transition-all px-2 py-1 bg-[#131313] rounded">
|
||||
Пригласить по ссылке
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<UsersManagementModal
|
||||
users={users}
|
||||
me={me}
|
||||
handleUpdate={(socketId, params) => update(socketId, params)}
|
||||
handleKick={(socketId) => kick(socketId)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
className="relative group outline-none bg-[#131313] rounded-full shadow-lg shadow-[#131313] p-2 opacity-90"
|
||||
>
|
||||
<PersonsIcon />
|
||||
<span className="absolute left-12 top-[50%] -translate-y-[50%] invisible group-hover:visible opacity-0 group-hover:opacity-100 text-xs transition-all px-2 py-1 bg-[#131313] rounded">
|
||||
Участники
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Transition
|
||||
in={modal ? true : false}
|
||||
timeout={200}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1,28 @@
|
||||
interface IconProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
function ChevronDownIcon({ className }: IconProps) {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<g id="Icon/Chevron_Down">
|
||||
<path
|
||||
id="Vector 106 (Stroke)"
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M11.2929 16.7071C11.6834 17.0976 12.3166 17.0976 12.7071 16.7071L19.7071 9.70713C20.0976 9.31661 20.0976 8.68344 19.7071 8.29292C19.3165 7.90239 18.6834 7.90239 18.2928 8.29292L12 14.5858L5.70711 8.29292C5.31658 7.90239 4.68342 7.90239 4.29289 8.29292C3.90237 8.68344 3.90237 9.31661 4.29289 9.70713L11.2929 16.7071Z"
|
||||
fill="white"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default ChevronDownIcon;
|
||||
@@ -1,4 +1,8 @@
|
||||
function ChevronLeftIcon() {
|
||||
interface IconProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
function ChevronLeftIcon({ className }: IconProps) {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
@@ -6,6 +10,7 @@ function ChevronLeftIcon() {
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<g id="Icon/Chevron_Left">
|
||||
<path
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
function ChevronRightIcon() {
|
||||
interface IconProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
function ChevronRightIcon({ className }: IconProps) {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
@@ -6,6 +10,7 @@ function ChevronRightIcon() {
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<g id="Icon/Chevron_Right">
|
||||
<path
|
||||
|
||||
@@ -28,8 +28,8 @@ function LoaderIcon({ className }: IconProps) {
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(12 12) rotate(45) scale(7.9196)"
|
||||
>
|
||||
<stop offset="0.874517" stop-color="white" />
|
||||
<stop offset="0.982613" stop-color="white" stop-opacity="0" />
|
||||
<stop offset="0.874517" stopColor="white" />
|
||||
<stop offset="0.982613" stopColor="white" stopOpacity="0" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
function PersonsIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g id="Icon/Persons">
|
||||
<g id="user">
|
||||
<path
|
||||
d="M17.4495 8.63457C17.4495 10.6419 15.9051 12.7428 13.9999 12.7428C12.0948 12.7428 10.5504 10.6419 10.5504 8.63457C10.5504 6.62725 12.0948 5 13.9999 5C15.9051 5 17.4495 6.62725 17.4495 8.63457Z"
|
||||
fill="#F2F2F2"
|
||||
/>
|
||||
<path
|
||||
d="M14 19.9999C17.4171 19.9999 18.4866 20.0186 19.3999 19.4209C19.8272 19.1412 20.0379 18.6262 19.9944 18.0927C19.935 17.364 19.6934 16.6363 19.4474 16.0591C19.1244 15.3012 18.9916 14.9503 18.4873 14.416C17.2309 13.0848 15.7818 14.9671 14 14.9671C12.2182 14.9671 10.7691 13.0848 9.51271 14.416C9.00842 14.9503 8.87561 15.3012 8.55259 16.0591C8.30658 16.6363 8.06495 17.364 8.0056 18.0927C7.96214 18.6262 8.17276 19.1412 8.6001 19.4209C9.51336 20.0186 10.5829 19.9999 14 19.9999Z"
|
||||
fill="#F2F2F2"
|
||||
/>
|
||||
</g>
|
||||
<path
|
||||
id="Subtract"
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M10.8041 10.0751C11.7912 9.29544 12.4495 7.94506 12.4495 6.63457C12.4495 6.23357 12.3879 5.84773 12.274 5.48701C11.2435 6.11561 10.5503 7.28985 10.5503 8.63469C10.5503 9.11967 10.6405 9.61012 10.8041 10.0751ZM8.91837 10.7415C7.0509 10.6827 5.55037 8.61317 5.55037 6.63457C5.55037 4.62725 7.09478 3 8.99993 3C9.82378 3 10.5802 3.3043 11.1734 3.81204C9.57742 4.81661 8.55031 6.64022 8.55031 8.63469C8.55031 9.35547 8.68173 10.0702 8.91837 10.7415ZM6.0089 17.9735C4.79527 17.9257 4.16752 17.7923 3.6001 17.4209C3.17276 17.1412 2.96214 16.6262 3.0056 16.0927C3.06495 15.364 3.30658 14.6363 3.55259 14.0591L3.60475 13.9365C3.89151 13.2617 4.03642 12.9206 4.51271 12.416C5.27428 11.6091 6.10665 11.9829 7.041 12.4025C7.42296 12.574 7.82195 12.7532 8.24012 12.8625C8.17815 12.9202 8.11747 12.9805 8.05815 13.0434C7.33114 13.8137 7.06365 14.4459 6.77613 15.1255L6.71268 15.2751C6.42491 15.9502 6.09598 16.9012 6.01215 17.9304C6.01098 17.9447 6.0099 17.9591 6.0089 17.9735ZM14.7454 14.8664C14.8661 15.2559 14.9603 15.6741 14.9944 16.0927C15.0379 16.6262 14.8272 17.1412 14.3999 17.4209C13.5141 18.0007 12.4811 18.0005 9.30138 18L9 17.9999L8.69862 18C8.45849 18 8.2306 18 8.01409 17.9998C8.08546 17.3025 8.31698 16.6119 8.55254 16.0592L8.60469 15.9366C8.89145 15.2618 9.03637 14.9208 9.51265 14.4161C10.2742 13.6092 11.1066 13.983 12.0409 14.4026C12.648 14.6753 13.2982 14.9672 13.9999 14.9672C14.2551 14.9672 14.5035 14.9286 14.7454 14.8664ZM13.7595 12.7318C13.1417 12.6743 12.5687 12.3982 12.083 11.9825C12.579 11.877 13.0451 11.9475 13.4873 12.416C13.5925 12.5274 13.6815 12.6309 13.7595 12.7318Z"
|
||||
fill="#F2F2F2"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default PersonsIcon;
|
||||
@@ -1,17 +1,15 @@
|
||||
import { Trans } from "react-i18next";
|
||||
import QRCode from "react-qr-code";
|
||||
import { useParams } from "react-router-dom";
|
||||
import CloseIcon from "../icons/CloseIcon";
|
||||
import useModalStore from "../../stores/useModalStore";
|
||||
|
||||
function QRCodeModal() {
|
||||
const params = useParams();
|
||||
const [setModal] = useModalStore((state) => [state.setModal]);
|
||||
|
||||
return (
|
||||
<div className="relative p-10 bg-[#131317] rounded shadow-lg w-[320px]">
|
||||
<div className="flex flex-col items-center gap-8">
|
||||
<p className="font-gilroy text-xl">
|
||||
<div className="relative lg:p-10 p-6 bg-[#131317] rounded shadow-lg w-[320px]">
|
||||
<div className="flex flex-col items-center lg:gap-8 gap-4">
|
||||
<p className="font-gilroy lg:text-xl">
|
||||
<Trans i18nKey={"scanQRCode"}>
|
||||
Отсканируйте QR-код
|
||||
<br />
|
||||
@@ -22,8 +20,8 @@ function QRCodeModal() {
|
||||
<QRCode
|
||||
bgColor="#131317"
|
||||
fgColor="#F2F2F2"
|
||||
size={256}
|
||||
value={`https://stream.graff.tech/stream/${params.id}`}
|
||||
size={128}
|
||||
value={window.location.href}
|
||||
viewBox={`0 0 256 256`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -30,15 +30,15 @@ function ShareModal() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="relative p-10 bg-[#131317] rounded shadow-lg w-[320px]">
|
||||
<div className="flex flex-col gap-8">
|
||||
<p className="font-gilroy text-2xl">
|
||||
<div className="relative lg:p-10 p-6 bg-[#131317] rounded shadow-lg w-[320px]">
|
||||
<div className="flex flex-col lg:gap-8 gap-4">
|
||||
<p className="font-gilroy lg:text-2xl">
|
||||
Пригласить
|
||||
<br />
|
||||
на демонстрацию
|
||||
</p>
|
||||
<div className="flex flex-col gap-4">
|
||||
<p className="font-gilroy text-xl">Ссылка для подключения</p>
|
||||
<p className="font-gilroy lg:text-xl">Ссылка для подключения</p>
|
||||
<input
|
||||
ref={clipboard.target}
|
||||
readOnly
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
import useModalStore from "../../stores/useModalStore";
|
||||
import userAgentParser from "ua-parser-js";
|
||||
import AdminUserIcon from "../icons/AdminUserIcon";
|
||||
import DesktopIcon from "../icons/DesktopIcon";
|
||||
import ExitIcon from "../icons/ExitIcon";
|
||||
import HandOffIcon from "../icons/HandOffIcon";
|
||||
import HandOnIcon from "../icons/HandOnIcon";
|
||||
import MobilePhoneIcon from "../icons/MobilePhoneIcon";
|
||||
import UserIcon from "../icons/UserIcon";
|
||||
import CloseIcon from "../icons/CloseIcon";
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
interface UsersManagementModalProps {
|
||||
users: any[];
|
||||
me: any;
|
||||
handleUpdate: (socketId: string, params: any) => void;
|
||||
handleKick: (socketId: string) => void;
|
||||
}
|
||||
|
||||
function UsersManagementModal({
|
||||
users,
|
||||
me,
|
||||
handleUpdate,
|
||||
handleKick,
|
||||
}: UsersManagementModalProps) {
|
||||
const [setModal] = useModalStore((state) => [state.setModal]);
|
||||
|
||||
return (
|
||||
<div className="relative lg:p-10 p-6 bg-[#131317] rounded shadow-lg w-[320px] flex flex-col gap-2">
|
||||
{users.map((user: any, index: number) => (
|
||||
<div key={index} className="relative">
|
||||
<div className="flex items-center gap-2 text-white">
|
||||
<div className="flex flex-col">
|
||||
{user.admin ? <AdminUserIcon /> : <UserIcon />}
|
||||
|
||||
{me && me.id === user.id && (
|
||||
<span className="text-[#73788C] text-sm">Вы</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{new userAgentParser().getDevice().type !== "mobile" ? (
|
||||
<DesktopIcon />
|
||||
) : (
|
||||
<MobilePhoneIcon />
|
||||
)}
|
||||
|
||||
<span className="text-sm">{user.city}</span>
|
||||
|
||||
{!user.admin && (
|
||||
<>
|
||||
{!user.allowControl ? (
|
||||
<button
|
||||
onClick={() =>
|
||||
handleUpdate(user.id, { allowControl: true })
|
||||
}
|
||||
className="outline-none"
|
||||
>
|
||||
<HandOffIcon />
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={() =>
|
||||
handleUpdate(user.id, { allowControl: false })
|
||||
}
|
||||
className="outline-none"
|
||||
>
|
||||
<HandOnIcon />
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{me && me.admin && !user.admin && (
|
||||
<button
|
||||
onClick={() => handleKick(user.id)}
|
||||
className="outline-none"
|
||||
>
|
||||
<ExitIcon />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="relative"></div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<button
|
||||
onClick={() => setModal(null)}
|
||||
className="absolute top-3 right-3 p-2 rounded-full transition-colors hover:bg-white hover:bg-opacity-5"
|
||||
>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default UsersManagementModal;
|
||||
Reference in New Issue
Block a user