Merge branch 'main' of http://192.168.1.163:3000/inmake/stream.graff.tech-new
This commit is contained in:
@@ -25,6 +25,7 @@ function PopupContainer() {
|
||||
transition={{ bounce: 0, ease: "easeInOut" }}
|
||||
drag={isMobile ? "y" : false}
|
||||
dragConstraints={{ top: 0, bottom: 0 }}
|
||||
dragElastic={{ top: 0, bottom: 0 }}
|
||||
onDragEnd={handleDragEnd}
|
||||
>
|
||||
{popup}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import clsx from "clsx";
|
||||
import Warning from "../indicators/Warning";
|
||||
|
||||
interface ControlButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
@@ -10,18 +11,20 @@ function ControlButton({
|
||||
size,
|
||||
icon,
|
||||
className,
|
||||
disabled,
|
||||
onClick,
|
||||
...props
|
||||
}: ControlButtonProps) {
|
||||
return (
|
||||
<button
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
{...props}
|
||||
className={clsx(
|
||||
"backdrop-blur-[10px] rounded-full transition-colors cursor-pointer disabled:!cursor-default outline-none disabled:bg-[#FF4517] disabled:hover:bg-[#FF4517]/85",
|
||||
"backdrop-blur-[10px] rounded-full transition-colors cursor-pointer outline-none disabled:!cursor-default",
|
||||
size === "large"
|
||||
? "2xl:p-[0.833vw] p-3 enabled:bg-[#FFFFFF]/15 enabled:hover:bg-[#FFFFFF]/25"
|
||||
: "2xl:p-[0.417vw] p-[6px] enabled:bg-[#141414]/15 enabled:hover:bg-[#141414]/25",
|
||||
? "2xl:p-[0.833vw] p-3 bg-[#FFFFFF]/15 hover:bg-[#FFFFFF]/25"
|
||||
: "2xl:p-[0.417vw] p-[6px] bg-[#141414]/15 hover:bg-[#141414]/25",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -35,6 +38,11 @@ function ControlButton({
|
||||
>
|
||||
{icon}
|
||||
</div>
|
||||
{disabled && size === "large" && (
|
||||
<div className="absolute 2xl:-top-[0.139vw] 2xl:-right-[0.139vw] -top-0.5 -right-0.5">
|
||||
<Warning type="critical" className="text-white" />
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import clsx from "clsx";
|
||||
import Warning from "../indicators/Warning";
|
||||
|
||||
interface FloatingActionButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
@@ -12,6 +13,7 @@ function FloatingActionButton({
|
||||
variant = "default",
|
||||
className,
|
||||
onClick,
|
||||
disabled,
|
||||
ref,
|
||||
...props
|
||||
}: FloatingActionButtonProps) {
|
||||
@@ -19,16 +21,22 @@ function FloatingActionButton({
|
||||
<button
|
||||
onClick={onClick}
|
||||
ref={ref}
|
||||
disabled={disabled}
|
||||
className={clsx(
|
||||
"2xl:p-[0.833vw] p-3 rounded-full transition-all cursor-pointer disabled:!cursor-default outline-none backdrop-blur-[10px]",
|
||||
variant === "default" &&
|
||||
"2xl:border-[0.069vw] border border-[#FFFFFF]/15 bg-[#000000]/15 hover:bg-[#000000]/25 hover:border-[#FFFFFF]/25 active:bg-[#7B60F3] active:border-[#FFFFFF]/25",
|
||||
"2xl:border-[0.069vw] border border-[#FFFFFF]/15 bg-[#000000]/15 hover:bg-[#000000]/25 hover:border-[#FFFFFF]/25 enabled:active:bg-[#7B60F3] enabled:active:border-[#FFFFFF]/25",
|
||||
variant === "critical" && "bg-[#FF4517] hover:bg-[#FF4517]/85",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
{disabled && (
|
||||
<div className="absolute 2xl:-top-[0.139vw] 2xl:-right-[0.139vw] -top-0.5 -right-0.5">
|
||||
<Warning type="critical" className="text-white" />
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import clsx from "clsx";
|
||||
import VolumeIcon from "../icons/VolumeIcon";
|
||||
import VolumeOffIcon from "../icons/VolumeOffIcon";
|
||||
import { useVoiceActivity } from "../../hooks/useVoiceActivity";
|
||||
import MicrophoneOffFilledIcon from "../icons/MicrophoneOffFilledIcon";
|
||||
|
||||
interface UserCameraControlsProps {
|
||||
isMuted: boolean;
|
||||
@@ -267,7 +268,7 @@ export default function UserCamera({
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"aspect-square h-fit group 2xl:rounded-[1.667vw] rounded-2xl relative flex-shrink-0 pointer-events-auto hover:w-[10.833vw] w-[6.944vw] overflow-hidden",
|
||||
"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",
|
||||
isLocal && "order-last",
|
||||
isVideoOff ? "bg-green-500" : "bg-yellow-500/10"
|
||||
)}
|
||||
@@ -427,7 +428,9 @@ function UserCameraControls({
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
>
|
||||
<ControlButton
|
||||
icon={isMuted ? <MicrophoneOffIcon /> : <MicrophoneFilledIcon />}
|
||||
icon={
|
||||
isMuted ? <MicrophoneOffFilledIcon /> : <MicrophoneFilledIcon />
|
||||
}
|
||||
size={"small"}
|
||||
disabled={false}
|
||||
onClick={onMute}
|
||||
@@ -447,7 +450,7 @@ function UserCameraControls({
|
||||
)
|
||||
}
|
||||
size={"small"}
|
||||
disabled={isControlDisabled}
|
||||
disabled={false}
|
||||
onClick={onCanControl}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import MicrophoneFilledIcon from "../icons/MicrophoneFilledIcon";
|
||||
import MicrophoneOffIcon from "../icons/MicrophoneOffIcon";
|
||||
import ControlButton from "./ControlButton";
|
||||
import VideoFilledIcon from "../icons/VideoFilledIcon";
|
||||
import VideoOffFilledIcon from "../icons/VideoOffFilledIcon";
|
||||
@@ -7,6 +6,7 @@ import HandRaisedFilledIcon from "../icons/HandRaisedFilledIcon";
|
||||
import CogFilledIcon from "../icons/CogFilledIcon";
|
||||
import useModalStore from "../../store/modalStore";
|
||||
import SettingsModal from "../modals/SettingsModal";
|
||||
import MicrophoneOffFilledIcon from "../icons/MicrophoneOffFilledIcon";
|
||||
|
||||
export interface UserDevicesControlsProps {
|
||||
toggleAudio: () => void;
|
||||
@@ -34,14 +34,26 @@ export default function UserDevicesControls({
|
||||
<ControlButton
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
size="large"
|
||||
icon={isAudioMuted ? <MicrophoneOffIcon /> : <MicrophoneFilledIcon />}
|
||||
icon={
|
||||
isAudioMuted || !hasLocalStream ? (
|
||||
<MicrophoneOffFilledIcon />
|
||||
) : (
|
||||
<MicrophoneFilledIcon />
|
||||
)
|
||||
}
|
||||
disabled={!hasLocalStream}
|
||||
onClick={toggleAudio}
|
||||
/>
|
||||
<ControlButton
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
size="large"
|
||||
icon={isVideoMuted ? <VideoOffFilledIcon /> : <VideoFilledIcon />}
|
||||
icon={
|
||||
isVideoMuted || !hasLocalStream ? (
|
||||
<VideoOffFilledIcon />
|
||||
) : (
|
||||
<VideoFilledIcon />
|
||||
)
|
||||
}
|
||||
disabled={!hasLocalStream}
|
||||
onClick={toggleVideo}
|
||||
/>
|
||||
|
||||
@@ -23,6 +23,9 @@ import WarningIcon from "../components/icons/WarningIcon";
|
||||
import Button from "../components/ui/Button";
|
||||
import LoaderIcon from "../components/icons/LoaderIcon";
|
||||
import SessionUsersPanel from "../components/SessionUsersPanel";
|
||||
import { useWebRTC } from "../hooks/useWebRTC";
|
||||
import MicrophoneOffFilledIcon from "../components/icons/MicrophoneOffFilledIcon";
|
||||
import VideoFilledIcon from "../components/icons/VideoFilledIcon";
|
||||
|
||||
function SessionPage() {
|
||||
const { setPopup } = usePopupStore();
|
||||
@@ -98,6 +101,9 @@ function SessionPage() {
|
||||
// }
|
||||
// }, [session?.status, navigate]);
|
||||
|
||||
const { localStream, toggleAudio, isAudioMuted, toggleVideo, isVideoMuted } =
|
||||
useWebRTC(session?.id, true);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex justify-center items-center min-h-screen bg-gray-50">
|
||||
@@ -139,7 +145,7 @@ function SessionPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex overflow-hidden relative order-3 w-screen h-screen bg-black justify-center_items-center">
|
||||
<div className="flex overflow-hidden relative order-3 w-screen h-dvh bg-black justify-center_items-center touch-none">
|
||||
{/* Pixel Streaming - показывается только когда сессия активна */}
|
||||
{session.status === "started" &&
|
||||
session.mode === "stream" &&
|
||||
@@ -205,14 +211,30 @@ function SessionPage() {
|
||||
<ShareFilledIcon />
|
||||
</div>
|
||||
</FloatingActionButton>
|
||||
<FloatingActionButton className="2xl:hidden">
|
||||
<FloatingActionButton
|
||||
className="2xl:hidden"
|
||||
disabled={!localStream}
|
||||
onClick={toggleAudio}
|
||||
>
|
||||
<div className="text-white size-4">
|
||||
<MicrophoneFilledIcon />
|
||||
{!localStream || isAudioMuted ? (
|
||||
<MicrophoneOffFilledIcon />
|
||||
) : (
|
||||
<MicrophoneFilledIcon />
|
||||
)}
|
||||
</div>
|
||||
</FloatingActionButton>
|
||||
<FloatingActionButton className="2xl:hidden">
|
||||
<FloatingActionButton
|
||||
className="2xl:hidden"
|
||||
disabled={!localStream}
|
||||
onClick={toggleVideo}
|
||||
>
|
||||
<div className="text-white size-4">
|
||||
<VideoOffFilledIcon />
|
||||
{!localStream || isVideoMuted ? (
|
||||
<VideoOffFilledIcon />
|
||||
) : (
|
||||
<VideoFilledIcon />
|
||||
)}
|
||||
</div>
|
||||
</FloatingActionButton>
|
||||
<FloatingActionButton
|
||||
|
||||
@@ -21,8 +21,7 @@ export const serverSessions = pgTable("server_sessions", {
|
||||
appId: uuid("app_id")
|
||||
.notNull()
|
||||
.references(() => apps.id),
|
||||
userId: uuid("user_id")
|
||||
.references(() => users.id), // для авторизованных пользователей (nullable - если пользователь не авторизован)
|
||||
userId: uuid("user_id").references(() => users.id), // для авторизованных пользователей (nullable - если пользователь не авторизован)
|
||||
guestId: uuid("guest_id"), // UUID v4 генерируется на клиенте для неавторизованных пользователей (nullable - если пользователь авторизован)
|
||||
startAt: timestamp("start_at", { withTimezone: true }).defaultNow().notNull(),
|
||||
endAt: timestamp("end_at", { withTimezone: true }), // Default 30 minutes from start_at
|
||||
|
||||
Reference in New Issue
Block a user