Попытка
This commit is contained in:
18
.env.example
18
.env.example
@@ -1,18 +0,0 @@
|
||||
# Server
|
||||
PORT=3001
|
||||
JWT_SECRET=your-secure-random-secret-key-here
|
||||
CORS_ORIGINS=http://localhost:5173,http://localhost:3000
|
||||
|
||||
# Database (PostgreSQL)
|
||||
DATABASE_URL=postgresql://user:password@localhost:5432/vortex
|
||||
|
||||
# Message encryption (AES-256-GCM) — 64-char hex key (32 bytes)
|
||||
# Generate with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
||||
# WARNING: if you lose this key, all encrypted messages become unreadable!
|
||||
ENCRYPTION_KEY=
|
||||
|
||||
# TURN server for voice/video calls (optional, recommended for production)
|
||||
# Install coturn: sudo apt install coturn
|
||||
# TURN_URL=turn:your-domain.com:3478
|
||||
# TURN_SECRET=your-coturn-shared-secret
|
||||
# STUN_URLS=stun:stun.l.google.com:19302,stun:stun1.l.google.com:19302
|
||||
@@ -1576,37 +1576,38 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{/* === Main Content Area === */}
|
||||
<div className="flex-1 flex flex-col relative overflow-hidden">
|
||||
{/*
|
||||
CRITICAL: Single stable remote video element.
|
||||
We keep it always mounted so WebRTC srcObject is never lost
|
||||
during transitions between voice and video modes.
|
||||
*/}
|
||||
<video
|
||||
ref={remoteVideoRef}
|
||||
autoPlay
|
||||
playsInline
|
||||
className={`
|
||||
bg-black transition-all duration-500
|
||||
${showVideoArea
|
||||
? 'w-full h-full object-contain'
|
||||
: 'w-0 h-0 opacity-0 absolute pointer-events-none'
|
||||
}
|
||||
`}
|
||||
onContextMenu={(e) => { e.preventDefault(); setShowVolumeSlider(true); }}
|
||||
/>
|
||||
|
||||
{showVideoArea ? (
|
||||
{/* === Main Content Area === */}
|
||||
<div className="flex-1 flex flex-col relative overflow-hidden bg-black min-h-[400px]">
|
||||
{showVideoArea && (
|
||||
<div
|
||||
ref={videoContainerRef}
|
||||
className="absolute inset-0 flex items-center justify-center bg-black"
|
||||
className="absolute inset-0 flex items-center justify-center z-0"
|
||||
>
|
||||
{/* Placeholder shown when video track is not yet arrived or muted */}
|
||||
<video
|
||||
ref={remoteVideoRef}
|
||||
autoPlay
|
||||
playsInline
|
||||
className="w-full h-full object-contain"
|
||||
onContextMenu={(e) => { e.preventDefault(); setShowVolumeSlider(true); }}
|
||||
/>
|
||||
|
||||
{/* Placeholder shown ONLY when track is not yet ready */}
|
||||
{!hasRemoteVideo && (
|
||||
<div className="absolute inset-0 flex flex-col items-center justify-center bg-zinc-900/50 backdrop-blur-sm z-10">
|
||||
<div className="absolute inset-0 flex flex-col items-center justify-center bg-zinc-900 z-10">
|
||||
<div className="relative mb-6">
|
||||
<div className="absolute inset-0 rounded-full bg-vortex-500/20 animate-ping" />
|
||||
{displayAvatar ? (
|
||||
<img src={displayAvatar} alt="" className="relative w-32 h-32 rounded-full object-cover border-4 border-vortex-500/30" />
|
||||
) : (
|
||||
<div className="relative w-32 h-32 rounded-full bg-gradient-to-br from-vortex-500 to-purple-600 flex items-center justify-center text-white text-4xl font-bold border-4 border-vortex-500/30">
|
||||
{initials}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<VideoOff size={48} className="text-zinc-500 mb-2" />
|
||||
<span className="text-sm text-zinc-500">{displayName}</span>
|
||||
<span className="text-xl text-white font-medium mb-1">{displayName}</span>
|
||||
<span className="text-sm text-zinc-500 animate-pulse">Соединение...</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user