StreamList.jsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import React from "react";
  2. import styled from "styled-components";
  3. import useOpenVidu from "./useOpenVidu";
  4. import useLocalStorage from "../hooks/useLocalStorage";
  5. import LocalStream from "./LocalStream";
  6. import RemoteStream from "./RemoteStream";
  7. const StyledWebConference = styled.div`
  8. position: fixed;
  9. top: 5em;
  10. right: 1em;
  11. bottom: 5.5em;
  12. z-index: 1;
  13. width: 150px;
  14. overflow-y: auto;
  15. overflow-x: hidden;
  16. padding: 0.5em;
  17. & video {
  18. border-radius: 5px;
  19. }
  20. & .local-stream {
  21. position: relative;
  22. & .actions {
  23. position: absolute;
  24. bottom: 2px;
  25. right: 0;
  26. left: 0;
  27. display: flex;
  28. justify-content: center;
  29. }
  30. & button {
  31. padding: 5px;
  32. margin: 5px;
  33. border-radius: 50%;
  34. opacity: 0.5;
  35. width: 30px;
  36. height: 30px;
  37. }
  38. & button.active {
  39. background-color: var(--color-primary);
  40. }
  41. &:hover button {
  42. opacity: 1;
  43. }
  44. }
  45. & .remote-stream {
  46. position: relative;
  47. margin-bottom: 0.5em;
  48. & .name {
  49. position: absolute;
  50. bottom: 0;
  51. left: 0;
  52. right: 0;
  53. padding: 2px 5px;
  54. background-color: #95959540;
  55. text-align: center;
  56. border-radius: 0 0 5px 5px;
  57. }
  58. }
  59. `;
  60. const WebConferenceContent = ({ users }) => {
  61. const { remoteStreams = [], localStream } = useOpenVidu();
  62. const [showLocalVideo, setShowLocalVideo] = useLocalStorage(
  63. "showLocalVideo",
  64. true
  65. );
  66. const [showLocalAudio, setShowLocalAudio] = useLocalStorage(
  67. "showLocalAudio",
  68. true
  69. );
  70. const toggleVideo = React.useCallback(() => {
  71. setShowLocalVideo((prev) => !prev);
  72. }, [setShowLocalVideo]);
  73. const toggleAudio = React.useCallback(() => {
  74. setShowLocalAudio((prev) => !prev);
  75. }, [setShowLocalAudio]);
  76. const streamMap = React.useMemo(
  77. () =>
  78. remoteStreams.reduce((acc, stream) => {
  79. acc[stream.data.uid] = stream;
  80. return acc;
  81. }, {}),
  82. [remoteStreams]
  83. );
  84. return (
  85. <StyledWebConference>
  86. {localStream && (
  87. <div className="local-stream">
  88. <LocalStream
  89. stream={localStream}
  90. video={showLocalVideo}
  91. audio={showLocalAudio}
  92. />
  93. <div className="actions">
  94. <button
  95. onClick={toggleVideo}
  96. className={showLocalVideo ? "active" : ""}
  97. >
  98. <img
  99. src={"https://icongr.am/entypo/camera.svg?size=16&color=f9fbfa"}
  100. />
  101. </button>
  102. <button
  103. onClick={toggleAudio}
  104. className={showLocalAudio ? "active" : ""}
  105. >
  106. <img
  107. src={"https://icongr.am/entypo/mic.svg?size=16&color=f9fbfa"}
  108. />
  109. </button>
  110. </div>
  111. </div>
  112. )}
  113. {users.map(
  114. ({ name, uid, color }) =>
  115. streamMap[uid] && (
  116. <div key={uid} className="remote-stream">
  117. <RemoteStream stream={streamMap[uid]} />
  118. <span className="name" style={{ backgroundColor: color }}>
  119. {name}
  120. </span>
  121. </div>
  122. )
  123. )}
  124. </StyledWebConference>
  125. );
  126. };
  127. export default WebConferenceContent;