Video is working
Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
parent
7bb7c74234
commit
f7e6d919e2
@ -100,8 +100,8 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
width: 30rem;
|
width: 25rem;
|
||||||
max-width: 30rem;
|
max-width: 25rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
z-index: 5000;
|
z-index: 5000;
|
||||||
}
|
}
|
||||||
@ -114,6 +114,10 @@ body {
|
|||||||
|
|
||||||
.Table .Trade {
|
.Table .Trade {
|
||||||
z-index: 25000;
|
z-index: 25000;
|
||||||
|
transform-origin: right center;
|
||||||
|
transform: scale(0.75);
|
||||||
|
right: 0;
|
||||||
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Table .Dialogs {
|
.Table .Dialogs {
|
||||||
|
@ -325,6 +325,7 @@ const Table = () => {
|
|||||||
<div className="Sidebar">
|
<div className="Sidebar">
|
||||||
{ name !== "" && <PlayerList/> }
|
{ name !== "" && <PlayerList/> }
|
||||||
{ name !== "" && <Chat/> }
|
{ name !== "" && <Chat/> }
|
||||||
|
{ /* name !== "" && <VideoFeeds/> */ }
|
||||||
{ loaded && <Actions {...{buildActive, setBuildActive}}/> }
|
{ loaded && <Actions {...{buildActive, setBuildActive}}/> }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,12 +1,3 @@
|
|||||||
.MediaAgent {
|
|
||||||
position: absolute;
|
|
||||||
display: none;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 50000;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.MediaControl {
|
.MediaControl {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -15,10 +6,20 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.MediaControl > div {
|
.MediaControl .Video {
|
||||||
display: flex;
|
width: 5rem;
|
||||||
|
height: 3.75rem;
|
||||||
|
max-width: 5rem;
|
||||||
|
max-height: 3.75rem;
|
||||||
|
background-color: #444;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
border: 1px solid black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.MediaAgent .Local {
|
|
||||||
border: 3px solid red;
|
.MediaControl > div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 0.5rem;
|
||||||
}
|
}
|
@ -6,27 +6,33 @@ import VolumeOff from '@mui/icons-material/VolumeOff';
|
|||||||
import VolumeUp from '@mui/icons-material/VolumeUp';
|
import VolumeUp from '@mui/icons-material/VolumeUp';
|
||||||
import MicOff from '@mui/icons-material/MicOff';
|
import MicOff from '@mui/icons-material/MicOff';
|
||||||
import Mic from '@mui/icons-material/Mic';
|
import Mic from '@mui/icons-material/Mic';
|
||||||
|
import VideocamOff from '@mui/icons-material/VideocamOff';
|
||||||
|
import Videocam from '@mui/icons-material/Videocam';
|
||||||
|
|
||||||
import { GlobalContext } from "./GlobalContext.js";
|
import { GlobalContext } from "./GlobalContext.js";
|
||||||
const debug = true;
|
const debug = true;
|
||||||
|
|
||||||
/* Proxy object so we can pass in srcObject to <audio> */
|
/* Proxy object so we can pass in srcObject to <audio> */
|
||||||
const Audio = ({ srcObject, ...props }) => {
|
const Video = ({ srcObject, local, ...props }) => {
|
||||||
const refAudio = useRef(null);
|
const refVideo = useRef(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!refAudio.current) {
|
if (!refVideo.current) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const ref = refAudio.current;
|
const ref = refVideo.current;
|
||||||
if (debug) console.log('<audio> bind');
|
if (debug) console.log('<video> bind');
|
||||||
ref.srcObject = srcObject;
|
ref.srcObject = srcObject;
|
||||||
|
if (local) {
|
||||||
|
ref.muted = true;
|
||||||
|
}
|
||||||
return () => {
|
return () => {
|
||||||
if (debug) console.log('<audio> unbind');
|
if (debug) console.log('<video> unbind');
|
||||||
if (ref) {
|
if (ref) {
|
||||||
ref.srcObject = undefined;
|
ref.srcObject = undefined;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [srcObject]);
|
}, [srcObject, local]);
|
||||||
return <audio ref={refAudio} {...props} />;
|
return <video ref={refVideo} {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MediaAgent = () => {
|
const MediaAgent = () => {
|
||||||
@ -38,20 +44,14 @@ const MediaAgent = () => {
|
|||||||
const connection = event.target;
|
const connection = event.target;
|
||||||
|
|
||||||
if (debug) console.log("ontrack", event);
|
if (debug) console.log("ontrack", event);
|
||||||
let isLocal = true;
|
|
||||||
for (let key in peers) {
|
for (let key in peers) {
|
||||||
if (peers[key].connection === connection) {
|
if (peers[key].connection === connection) {
|
||||||
isLocal = false;
|
|
||||||
Object.assign(peers[key].attributes, {
|
Object.assign(peers[key].attributes, {
|
||||||
srcObject: event.streams[0]
|
srcObject: event.streams[0]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLocal) {
|
|
||||||
throw new Error('Should not be local!');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debug) console.log(`media-agent - ontrack - remote`, peers);
|
if (debug) console.log(`media-agent - ontrack - remote`, peers);
|
||||||
setPeers(Object.assign({}, peers));
|
setPeers(Object.assign({}, peers));
|
||||||
}, [peers, setPeers]);
|
}, [peers, setPeers]);
|
||||||
@ -78,27 +78,9 @@ const MediaAgent = () => {
|
|||||||
const connection = new RTCPeerConnection({
|
const connection = new RTCPeerConnection({
|
||||||
configuration: {
|
configuration: {
|
||||||
offerToReceiveAudio: true,
|
offerToReceiveAudio: true,
|
||||||
offerToReceiveVideo: false
|
offerToReceiveVideo: true
|
||||||
},
|
},
|
||||||
iceServers: [
|
iceServers: [ {
|
||||||
/*
|
|
||||||
{ urls: "stun:stun.l.google.com:19302" },
|
|
||||||
{ urls: "stun:stun.stunprotocol.org:3478" },
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
urls: "turn:ketrenos.com:3478",
|
|
||||||
username: "ketra",
|
|
||||||
credential: "ketran"
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
/*{
|
|
||||||
urls: "turn:ketrenos.com:3478?transport=tcp",
|
|
||||||
username: "ketra",
|
|
||||||
credential: "ketran"
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
urls: "turns:ketrenos.com:5349",
|
urls: "turns:ketrenos.com:5349",
|
||||||
username: "ketra",
|
username: "ketra",
|
||||||
credential: "ketran"
|
credential: "ketran"
|
||||||
@ -112,15 +94,12 @@ const MediaAgent = () => {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
]
|
]
|
||||||
}, {
|
|
||||||
/* this will no longer be needed by chrome
|
|
||||||
* eventually (supposedly), but is necessary
|
|
||||||
* for now to get firefox to talk to chrome */
|
|
||||||
//optional: [{DtlsSrtpKeyAgreement: true}]
|
|
||||||
});
|
});
|
||||||
|
|
||||||
peers[peer_id] = {
|
peers[peer_id] = {
|
||||||
connection,
|
connection,
|
||||||
|
muted: false,
|
||||||
|
videoOn: true,
|
||||||
attributes: {
|
attributes: {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -206,19 +185,11 @@ const MediaAgent = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sessionDescription = ({ peer_id, session_description }) => {
|
const sessionDescription = ({ peer_id, session_description }) => {
|
||||||
/**
|
|
||||||
* Peers exchange session descriptions which contains information
|
|
||||||
* about their audio / video settings and that sort of stuff. First
|
|
||||||
* the 'offerer' sends a description to the 'answerer' (with type
|
|
||||||
* "offer"), then the answerer sends one back (with type "answer").
|
|
||||||
*/
|
|
||||||
// console.log('Remote description received: ', peer_id, session_description);
|
|
||||||
const peer = peers[peer_id];
|
const peer = peers[peer_id];
|
||||||
if (!peer) {
|
if (!peer) {
|
||||||
console.error(`media-agent - sessionDescription - No peer for ${peer_id}`);
|
console.error(`media-agent - sessionDescription - No peer for ${peer_id}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// console.log(session_description);
|
|
||||||
const { connection } = peer;
|
const { connection } = peer;
|
||||||
const desc = new RTCSessionDescription(session_description);
|
const desc = new RTCSessionDescription(session_description);
|
||||||
return connection.setRemoteDescription(desc, () => {
|
return connection.setRemoteDescription(desc, () => {
|
||||||
@ -240,15 +211,12 @@ const MediaAgent = () => {
|
|||||||
console.error(`media-agent - sessionDescription - Answer setLocalDescription failed!`);
|
console.error(`media-agent - sessionDescription - Answer setLocalDescription failed!`);
|
||||||
});
|
});
|
||||||
}, (error) => {
|
}, (error) => {
|
||||||
// console.log("Error creating answer: ", error);
|
console.error(error);
|
||||||
console.error(peer);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, (error) => {
|
}, (error) => {
|
||||||
console.log(`media-agent - sessionDescription - setRemoteDescription error: `, error);
|
console.log(`media-agent - sessionDescription - setRemoteDescription error: `, error);
|
||||||
});
|
});
|
||||||
|
|
||||||
// console.log("Description Object: ", desc);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const removePeer = ({peer_id}) => {
|
const removePeer = ({peer_id}) => {
|
||||||
@ -348,7 +316,10 @@ const MediaAgent = () => {
|
|||||||
peers[name] = {
|
peers[name] = {
|
||||||
local: true,
|
local: true,
|
||||||
muted: true,
|
muted: true,
|
||||||
|
videoOn: false,
|
||||||
attributes: {
|
attributes: {
|
||||||
|
local: true,
|
||||||
|
srcObject: stream
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -381,10 +352,25 @@ const MediaAgent = () => {
|
|||||||
navigator.mozGetUserMedia ||
|
navigator.mozGetUserMedia ||
|
||||||
navigator.msGetUserMedia);
|
navigator.msGetUserMedia);
|
||||||
|
|
||||||
return navigator.mediaDevices.getUserMedia({audio: true, video: false})//, "video": true})
|
return navigator.mediaDevices.getUserMedia({audio: true, video: true})
|
||||||
.then((media) => { /* user accepted access to a/v */
|
.then((media) => { /* user accepted access to a/v */
|
||||||
console.log("Access granted to audio/video");
|
console.log("Access granted to audio/video");
|
||||||
setStream(media);
|
media.getVideoTracks().forEach((track) => {
|
||||||
|
track.applyConstraints({
|
||||||
|
"video": {
|
||||||
|
"width": {
|
||||||
|
"min": 160,
|
||||||
|
"max": 320
|
||||||
|
},
|
||||||
|
"height": {
|
||||||
|
"min": 120,
|
||||||
|
"max": 240
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return media;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -393,105 +379,108 @@ const MediaAgent = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (debug) console.log(`media-agent - WebSocket open request. Attempting to create local media.`)
|
if (debug) console.log(`media-agent - WebSocket open request. Attempting to create local media.`)
|
||||||
setup_local_media().then(() => {
|
if (!stream) {
|
||||||
|
setup_local_media().then((media) => {
|
||||||
/* once the user has given us access to their
|
/* once the user has given us access to their
|
||||||
* microphone/camcorder, join the channel and start peering up */
|
* microphone/camcorder, join the channel and start peering up */
|
||||||
|
setStream(media);
|
||||||
join();
|
join();
|
||||||
}).catch((error) => { /* user denied access to a/v */
|
}).catch((error) => { /* user denied access to a/v */
|
||||||
console.error(error);
|
console.error(error);
|
||||||
console.log("Access denied for audio/video");
|
console.log("Access denied for audio/video");
|
||||||
});
|
});
|
||||||
}, [ws, setStream, name, sendMessage]);
|
}
|
||||||
|
}, [ws, setStream, stream, peers, name, sendMessage]);
|
||||||
|
|
||||||
if (!ws) {
|
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`media-agent - render`, peers);
|
|
||||||
|
|
||||||
const audioPeers = [];
|
|
||||||
for (let id in peers) {
|
|
||||||
const peer = peers[id];
|
|
||||||
if (peer.local) {
|
|
||||||
peer.attributes.srcObject = stream;
|
|
||||||
if (peer.attributes.srcObject) {
|
|
||||||
peer.attributes.srcObject.getAudioTracks().forEach((track) => {
|
|
||||||
track.enabled = !peer.muted;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
audioPeers.push(
|
|
||||||
<Audio
|
|
||||||
className={peer.local ? 'Local' : 'Remote'}
|
|
||||||
key={`Peer-${id}`}
|
|
||||||
autoPlay='autoplay'
|
|
||||||
controls
|
|
||||||
muted
|
|
||||||
{...peer.attributes}/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
if (peer.muted) {
|
|
||||||
audioPeers.push(
|
|
||||||
<Audio
|
|
||||||
className={peer.local ? 'Local' : 'Remote'}
|
|
||||||
key={`Peer-${id}`}
|
|
||||||
autoPlay='autoplay'
|
|
||||||
controls
|
|
||||||
muted
|
|
||||||
{...peer.attributes}/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
audioPeers.push(
|
|
||||||
<Audio
|
|
||||||
className={peer.local ? 'Local' : 'Remote'}
|
|
||||||
key={`Peer-${id}`}
|
|
||||||
autoPlay='autoplay'
|
|
||||||
controls
|
|
||||||
{...peer.attributes}/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return <div className="MediaAgent">
|
|
||||||
{ audioPeers }
|
|
||||||
</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MediaControl = ({isSelf, peer}) => {
|
const MediaControl = ({isSelf, peer}) => {
|
||||||
const { peers, setPeers } = useContext(GlobalContext);
|
const { peers } = useContext(GlobalContext);
|
||||||
const [control, setControl] = useState(undefined);
|
const [control, setControl] = useState(undefined);
|
||||||
|
const [media, setMedia] = useState(undefined);
|
||||||
|
const [muted, setMuted] = useState(undefined);
|
||||||
|
const [videoOn, setVideoOn] = useState(undefined);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setControl(peers[peer]);
|
setControl(peers[peer]);
|
||||||
}, [peer, peers, setControl]);
|
}, [peer, peers, setControl]);
|
||||||
|
|
||||||
const toggleMute = (event) => {
|
const toggleMute = (event) => {
|
||||||
if (control) {
|
if (debug) console.log(`MediaControl - toggleMute`, !muted);
|
||||||
control.muted = !control.muted;
|
setMuted(!muted);
|
||||||
}
|
|
||||||
const update = Object.assign({}, peers);
|
|
||||||
update[peer].muted = control.muted;
|
|
||||||
if (debug) console.log(`MediaControl - toggleMute`, update);
|
|
||||||
setPeers(update);
|
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const toggleVideo = (event) => {
|
||||||
|
if (debug) console.log(`MediaControl - toggleVideo`, !videoOn);
|
||||||
|
setVideoOn(!videoOn);
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!control) {
|
||||||
|
setMedia(undefined);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setMuted(control.muted);
|
||||||
|
setVideoOn(control.videoOn);
|
||||||
|
setMedia(control);
|
||||||
|
}, [control, setMedia]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!control) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (control.attributes.srcObject) {
|
||||||
|
control.attributes.srcObject.getAudioTracks().forEach((track) => {
|
||||||
|
track.enabled = !muted;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [control, muted]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!control) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (control.attributes.srcObject) {
|
||||||
|
control.attributes.srcObject.getVideoTracks().forEach((track) => {
|
||||||
|
track.enabled = videoOn;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [control, videoOn]);
|
||||||
|
|
||||||
if (!control) {
|
if (!control) {
|
||||||
return <div className="MediaControl">
|
return <div className="MediaControl">
|
||||||
|
<div>
|
||||||
{ isSelf && <MicOff color={'disabled'}/> }
|
{ isSelf && <MicOff color={'disabled'}/> }
|
||||||
{ !isSelf && <VolumeOff color={'disabled'}/> }
|
{ !isSelf && <VolumeOff color={'disabled'}/> }
|
||||||
|
<VideocamOff color={'disabled'}/>
|
||||||
|
</div>
|
||||||
|
<video className="Video"></video>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="MediaControl">
|
return <div className="MediaControl">
|
||||||
|
<div>
|
||||||
{ isSelf && <div onClick={toggleMute}>
|
{ isSelf && <div onClick={toggleMute}>
|
||||||
{ control.muted && <MicOff color={'primary'}/> }
|
{ muted && <MicOff color={'primary'}/> }
|
||||||
{ !control.muted && <Mic color={'primary'}/> }
|
{ !muted && <Mic color={'primary'}/> }
|
||||||
</div> }
|
</div> }
|
||||||
{ !isSelf && <div onClick={toggleMute}>
|
{ !isSelf && <div onClick={toggleMute}>
|
||||||
{ control.muted && <VolumeOff color={'primary'}/> }
|
{ muted && <VolumeOff color={'primary'}/> }
|
||||||
{ !control.muted && <VolumeUp color={'primary'}/> }
|
{ !muted && <VolumeUp color={'primary'}/> }
|
||||||
</div> }
|
</div> }
|
||||||
|
<div onClick={toggleVideo}>
|
||||||
|
{ !videoOn && <VideocamOff color={'primary'}/> }
|
||||||
|
{ videoOn && <Videocam color={'primary'}/> }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{ media && <Video className="Video"
|
||||||
|
autoPlay='autoplay'
|
||||||
|
{...media.attributes}/>
|
||||||
|
}
|
||||||
</div>;
|
</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-around;
|
||||||
}
|
}
|
||||||
|
|
||||||
.PlayerList .Unselected > div {
|
.PlayerList .Unselected > div {
|
||||||
@ -35,10 +36,15 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
margin: 0.25rem;
|
margin: 0.25rem;
|
||||||
padding: 0.25rem;
|
padding: 0.25rem;
|
||||||
|
max-width: 8rem;
|
||||||
|
width: 8rem;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
background-color: #eee;
|
||||||
|
border-radius: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.PlayerList .Unselected .Self {
|
.PlayerList .Unselected .Self {
|
||||||
background-color: rgba(255, 255, 0, 0.5);
|
border: 1px solid black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.PlayerList .PlayerSelector .PlayerColor {
|
.PlayerList .PlayerSelector .PlayerColor {
|
||||||
@ -66,18 +72,24 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.PlayerList .PlayerEntry {
|
.PlayerList .PlayerSelector .PlayerEntry {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
flex: 1 1 0px;
|
||||||
|
align-items: flex-start;
|
||||||
border: 1px solid rgba(0,0,0,0);
|
border: 1px solid rgba(0,0,0,0);
|
||||||
border-radius: 0.5em;
|
border-radius: 0.25em;
|
||||||
min-width: 10em;
|
min-width: 11em;
|
||||||
|
max-width: 11rem;
|
||||||
|
padding: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.PlayerList .PlayerSelector .PlayerEntry {
|
.PlayerList .PlayerSelector .PlayerEntry > div {
|
||||||
flex: 1 1 0px;
|
display: flex;
|
||||||
align-items: center;
|
|
||||||
display: inline-flex;
|
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
min-width: 10em;
|
align-items: center;
|
||||||
|
align-self: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.PlayerList .PlayerEntry[data-selectable=true]:hover {
|
.PlayerList .PlayerEntry[data-selectable=true]:hover {
|
||||||
@ -86,12 +98,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.PlayerList .PlayerEntry[data-selected=true] {
|
.PlayerList .PlayerEntry[data-selected=true] {
|
||||||
background-color: rgba(255, 255, 0, 0.5);
|
border: 1px solid black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.PlayerList .PlayerEntry .MediaControl {
|
.PlayerList .PlayerSelector .PlayerEntry .MediaControl {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-self: flex-end;
|
justify-self: flex-end;
|
||||||
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,9 +94,11 @@ const PlayerList = () => {
|
|||||||
className="PlayerEntry"
|
className="PlayerEntry"
|
||||||
onClick={() => { inLobby && selectable && toggleSelected(key) }}
|
onClick={() => { inLobby && selectable && toggleSelected(key) }}
|
||||||
key={`player-${key}`}>
|
key={`player-${key}`}>
|
||||||
|
<div>
|
||||||
<PlayerColor color={key}/>
|
<PlayerColor color={key}/>
|
||||||
<div className="Name">{name ? name : 'Available' }</div>
|
<div className="Name">{name ? name : 'Available' }</div>
|
||||||
{ name && !item.live && <div className="NoNetwork"></div> }
|
{ name && !item.live && <div className="NoNetwork"></div> }
|
||||||
|
</div>
|
||||||
{ name && item.live && <MediaControl peer={name} isSelf={key === color}/> }
|
{ name && item.live && <MediaControl peer={name} isSelf={key === color}/> }
|
||||||
{ !name && <div></div> }
|
{ !name && <div></div> }
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
.Trade {
|
.Trade {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin: 0.25rem;
|
margin: 0.25rem;
|
||||||
@ -11,7 +9,7 @@
|
|||||||
.Trade > * {
|
.Trade > * {
|
||||||
max-height: calc(100vh - 2rem);
|
max-height: calc(100vh - 2rem);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
width: 40rem;
|
width: 32rem;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -62,7 +62,7 @@ const Winner = ({ winnerDismissed, setWinnerDismissed }) => {
|
|||||||
type: 'goto-lobby'
|
type: 'goto-lobby'
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}, [ws]);
|
}, [ws, winnerDismissed, setWinnerDismissed]);
|
||||||
|
|
||||||
if (!winner || winnerDismissed) {
|
if (!winner || winnerDismissed) {
|
||||||
return <></>;
|
return <></>;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user