initial people aside bar

This commit is contained in:
Jon 2021-06-17 13:13:21 +01:00
parent f6229317d8
commit 84a9e3ea3e
17 changed files with 238 additions and 15 deletions

View File

@ -3,6 +3,7 @@ import { useCallState } from '@dailyjs/shared/contexts/CallProvider';
import { useCallUI } from '@dailyjs/shared/hooks/useCallUI';
import Room from '../Room';
import { Asides } from './Asides';
import { Modals } from './Modals';
export const App = () => {
@ -19,6 +20,7 @@ export const App = () => {
<div className="app">
{componentForState()}
<Modals />
<Asides />
<style jsx>{`
color: white;
height: 100vh;

View File

@ -0,0 +1,10 @@
import React from 'react';
import { PeopleAside } from '@dailyjs/shared/components/Aside';
export const Asides = () => (
<>
<PeopleAside />
</>
);
export default Asides;

View File

@ -14,6 +14,7 @@ import { ReactComponent as IconCameraOn } from '@dailyjs/shared/icons/camera-on-
import { ReactComponent as IconLeave } from '@dailyjs/shared/icons/leave-md.svg';
import { ReactComponent as IconMicOff } from '@dailyjs/shared/icons/mic-off-md.svg';
import { ReactComponent as IconMicOn } from '@dailyjs/shared/icons/mic-on-md.svg';
import { ReactComponent as IconPeople } from '@dailyjs/shared/icons/people-md.svg';
import { ReactComponent as IconSettings } from '@dailyjs/shared/icons/settings-md.svg';
import PropTypes from 'prop-types';
@ -23,7 +24,7 @@ import { Tray, TrayButton } from './Tray';
export const Room = ({ onLeave }) => {
const { callObject } = useCallState();
const { setShowDeviceModal } = useUIState();
const { setShowDeviceModal, setShowPeopleAside } = useUIState();
const { isCamMuted, isMicMuted } = useMediaDevices();
const { setShowModal, showModal } = useWaitingRoom();
const { localParticipant } = useParticipants();
@ -75,6 +76,13 @@ export const Room = ({ onLeave }) => {
<IconSettings />
</TrayButton>
<TrayButton
label="People"
onClick={() => setShowPeopleAside((p) => !p)}
>
<IconPeople />
</TrayButton>
<span className="divider" />
<TrayButton label="Leave" onClick={onLeave} orange>

View File

@ -0,0 +1,31 @@
import React from 'react';
import PropTypes from 'prop-types';
export const ASIDE_WIDTH = 380;
export const Aside = ({ children }) => (
<aside className="call-aside">
<div className="inner">{children}</div>
<style jsx>{`
.call-aside {
background: white;
width: ${ASIDE_WIDTH}px;
height: 100vh;
box-sizing: border-box;
box-shadow: 0px 15px 35px rgba(18, 26, 36, 0.25);
color: var(--text-default);
overflow: hidden;
}
.call-aside .inner {
overflow-y: scroll;
}
`}</style>
</aside>
);
Aside.propTypes = {
children: PropTypes.node,
};
export default Aside;

View File

@ -0,0 +1,122 @@
import React from 'react';
import Aside from '@dailyjs/shared/components/Aside';
import { ReactComponent as IconCamOff } from '@dailyjs/shared/icons/camera-off-sm.svg';
import { ReactComponent as IconCamOn } from '@dailyjs/shared/icons/camera-on-sm.svg';
import { ReactComponent as IconMicOff } from '@dailyjs/shared/icons/mic-off-sm.svg';
import { ReactComponent as IconMicOn } from '@dailyjs/shared/icons/mic-on-sm.svg';
import PropTypes from 'prop-types';
import { useCallState } from '../../contexts/CallProvider';
import { useParticipants } from '../../contexts/ParticipantsProvider';
import { useUIState } from '../../contexts/UIStateProvider';
import { Button } from '../Button';
const PersonRow = ({ participant, isOwner = false }) => (
<div className="person-row">
<div>
{participant.name} {participant.isLocal && '(You)'}
</div>
<div className="actions">
{!isOwner ? (
<>
<span
className={participant.isCamMuted ? 'state error' : 'state success'}
>
{participant.isCamMuted ? <IconCamOff /> : <IconCamOn />}
</span>
<span
className={participant.isMicMuted ? 'state error' : 'state success'}
>
{participant.isMicMuted ? <IconMicOff /> : <IconMicOn />}
</span>
</>
) : (
<>
<Button
size="medium-square"
variant={participant.isCamMuted ? 'error-light' : 'success-light'}
>
{participant.isCamMuted ? <IconCamOff /> : <IconCamOn />}
</Button>
<Button
size="medium-square"
variant={participant.isMicMuted ? 'error-light' : 'success-light'}
>
{participant.isMicMuted ? <IconMicOff /> : <IconMicOn />}
</Button>
</>
)}
</div>
<style jsx>{`
.person-row {
display: flex;
border-bottom: 1px solid var(--gray-light);
padding: var(--spacing-xs) 0;
justify-content: space-between;
align-items: center;
margin: 0 var(--spacing-xs);
}
.person-row .actions {
display: flex;
gap: var(--spacing-xxs);
}
.mute-state {
display: flex;
width: 24px;
height: 24px;
align-items: center;
justify-content: center;
}
.state.error {
color: var(--red-default);
}
.state.success {
color: var(--green-default);
}
`}</style>
</div>
);
PersonRow.propTypes = {
participant: PropTypes.object,
isOwner: PropTypes.bool,
};
export const PeopleAside = () => {
const { callObject } = useCallState();
const { showPeopleAside } = useUIState();
const { allParticipants, isOwner } = useParticipants();
if (!showPeopleAside) {
return null;
}
return (
<Aside>
{isOwner && (
<>
<Button
onClick={() =>
callObject.updateParticipants({ '*': { setAudio: false } })
}
>
Mute all mics
</Button>
<Button
onClick={() =>
callObject.updateParticipants({ '*': { setVideo: false } })
}
>
Mute all cam
</Button>
</>
)}
{allParticipants.map((p) => (
<PersonRow participant={p} key={p.id} isOwner={isOwner} />
))}
</Aside>
);
};
export default PeopleAside;

View File

@ -0,0 +1,3 @@
export { Aside as default } from './Aside';
export { Aside } from './Aside';
export { PeopleAside } from './PeopleAside';

View File

@ -121,17 +121,42 @@ export const Button = forwardRef(
cursor: not-allowed;
}
.button.error {
.button.warning {
background: var(--secondary-default);
border-color: var(--secondary-default);
}
.button.error:focus {
.button.warning:focus {
box-shadow: 0 0 0px 3px ${hexa(theme.secondary.default, 0.35)};
}
.button.error:hover {
.button.warning:hover {
border-color: var(--secondary-dark);
}
.button.error {
background: var(--red-default);
border-color: var(--red-default);
}
.button.error:focus {
box-shadow: 0 0 0px 3px ${hexa(theme.red.default, 0.35)};
}
.button.error:hover {
border-color: var(--red-dark);
}
.button.error-light {
background: var(--red-light);
border-color: var(--red-light);
color: var(--red-default);
}
.button.error-light:focus {
box-shadow: 0 0 0px 3px ${hexa(theme.red.default, 0.35)};
}
.button.error-light:hover {
color: white;
background: var(--red-default);
border-color: var(--red-default);
}
.button.success {
background: var(--green-default);
border-color: var(--green-default);
@ -143,6 +168,20 @@ export const Button = forwardRef(
border-color: var(--green-dark);
}
.button.success-light {
background: var(--green-light);
border-color: var(--green-light);
color: var(--green-default);
}
.button.success-light:focus {
box-shadow: 0 0 0px 3px ${hexa(theme.green.default, 0.35)};
}
.button.success-light:hover {
color: white;
background: var(--green-default);
border-color: var(--green-default);
}
.button.shadow {
box-shadow: 0 0 4px 0 rgb(0 0 0 / 8%), 0 4px 4px 0 rgb(0 0 0 / 4%);
}
@ -179,7 +218,6 @@ export const Button = forwardRef(
color: white;
border: 0px;
}
.button.translucent:hover,
.button.translucent:focus,
.button.translucent:active {
@ -194,7 +232,6 @@ export const Button = forwardRef(
color: white;
border: 0px;
}
.button.blur:hover,
.button.blur:focus,
.button.blur:active {
@ -202,7 +239,6 @@ export const Button = forwardRef(
box-shadow: none;
background: ${hexa(theme.blue.default, 1)};
}
.button.blur:focus {
box-shadow: 0 0 0px 3px ${hexa(theme.blue.default, 0.35)};
}
@ -212,14 +248,12 @@ export const Button = forwardRef(
color: white;
border: 0px;
}
.button.dark:hover,
.button.dark:focus,
.button.dark:active {
background: ${theme.blue.default};
border: 0px;
}
.button.dark:focus {
box-shadow: 0 0 0px 3px rgba(255, 255, 255, 0.15);
}

View File

@ -20,7 +20,7 @@ export const WaitingParticipantRow = ({ participant }) => {
<Button onClick={handleAllowClick} size="small" variant="success">
Allow
</Button>
<Button onClick={handleDenyClick} size="small" variant="error">
<Button onClick={handleDenyClick} size="small" variant="warning">
Deny
</Button>
</div>

View File

@ -26,7 +26,7 @@ export const WaitingRoomModal = ({ onClose }) => {
<Button fullWidth onClick={handleAllowAllClick} variant="success">
Allow all
</Button>,
<Button fullWidth onClick={handleDenyAllClick} variant="error">
<Button fullWidth onClick={handleDenyAllClick} variant="warning">
Deny all
</Button>,
]}

View File

@ -84,7 +84,7 @@ export const WaitingRoomNotification = () => {
Allow
</Button>
)}
<Button onClick={handleDenyClick} size="small" variant="error">
<Button onClick={handleDenyClick} size="small" variant="warning">
{hasMultiplePeopleWaiting ? 'Deny All' : 'Deny'}
</Button>
</CardFooter>

View File

@ -81,6 +81,11 @@ export const ParticipantsProvider = ({ children }) => {
[allParticipants]
);
const isOwner = useDeepCompareMemo(
() => localParticipant?.isOwner,
[localParticipant]
);
/**
* The participant who should be rendered prominently right now
*/
@ -221,6 +226,7 @@ export const ParticipantsProvider = ({ children }) => {
setUsername,
swapParticipantPosition,
username,
isOwner,
}}
>
{children}

View File

@ -5,12 +5,15 @@ export const UIStateContext = createContext();
export const UIStateProvider = ({ children }) => {
const [showDeviceModal, setShowDeviceModal] = useState(false);
const [showPeopleAside, setShowPeopleAside] = useState(false);
return (
<UIStateContext.Provider
value={{
showDeviceModal,
setShowDeviceModal,
showPeopleAside,
setShowPeopleAside,
}}
>
{children}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><g fill="currentColor"><path d="M10,12H8.242l-2,2H10a2,2,0,0,0,2-2V9.6L16,12V4.242l-6,6Z" fill="currentColor"></path><path d="M15.707.293a1,1,0,0,0-1.414,0L11.674,2.912A2,2,0,0,0,10,2H2A2,2,0,0,0,0,4v8a2,2,0,0,0,.912,1.674l-.619.619a1,1,0,1,0,1.414,1.414l14-14A1,1,0,0,0,15.707.293ZM2,12V4h8v.586L2.586,12Z" fill="currentColor"></path></g></svg>

After

Width:  |  Height:  |  Size: 428 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><g fill="currentColor"><path d="M16,4,12,6.4V4a2,2,0,0,0-2-2H2A2,2,0,0,0,0,4v8a2,2,0,0,0,2,2h8a2,2,0,0,0,2-2V9.6L16,12ZM2,12V4h8v8Z" fill="currentColor"></path></g></svg>

After

Width:  |  Height:  |  Size: 253 B

View File

@ -6,8 +6,5 @@
<path d="M3.00007 16.5C2.81644 16.4998 2.63639 16.4491 2.47968 16.3534C2.32297 16.2576 2.19565 16.1206 2.11167 15.9573C2.02769 15.794 1.9903 15.6107 2.0036 15.4276C2.0169 15.2444 2.08038 15.0685 2.18707 14.919L12.1871 0.918991C12.3412 0.703105 12.5747 0.557273 12.8363 0.513577C13.0979 0.469881 13.3662 0.5319 13.5821 0.685991C13.798 0.840082 13.9438 1.07362 13.9875 1.33524C14.0312 1.59685 13.9692 1.8651 13.8151 2.08099L3.81507 16.081C3.72246 16.2107 3.60017 16.3165 3.45839 16.3893C3.31662 16.4622 3.15948 16.5002 3.00007 16.5Z" fill="currentColor"/>
</g>
<defs>
<clipPath id="clip0">
<rect width="16" height="16" fill="white" transform="translate(0 0.5)"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><title>microphone</title><g fill="currentColor"><path fill="currentColor" d="M8,10c2.2,0,4-1.8,4-4V4c0-2.2-1.8-4-4-4C5.8,0,4,1.8,4,4v2C4,8.2,5.8,10,8,10z"></path> <path d="M15.9,7.1C16,6.6,15.6,6.1,15.1,6c-0.5-0.1-1.1,0.3-1.1,0.8C13.5,9.8,11,12,8,12 S2.5,9.8,2.1,6.9C2,6.3,1.5,5.9,0.9,6C0.4,6.1,0,6.6,0.1,7.1c0.5,3.6,3.4,6.3,6.9,6.8V16h2v-2.1C12.5,13.5,15.4,10.7,15.9,7.1z"></path></g></svg>

After

Width:  |  Height:  |  Size: 474 B

View File

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19 21H23V16.677C22.9999 16.4772 22.9399 16.282 22.8278 16.1166C22.7157 15.9512 22.5566 15.8231 22.371 15.749L18.629 14.249C18.4438 14.175 18.2849 14.0473 18.1728 13.8823C18.0607 13.7173 18.0005 13.5225 18 13.323V12.445C18.6065 12.097 19.1107 11.5953 19.4617 10.9906C19.8128 10.3858 19.9985 9.69929 20 9.00001V7.00001C20.0002 6.29779 19.8154 5.6079 19.4644 4.9997C19.1134 4.3915 18.6085 3.88642 18.0004 3.53524C17.3923 3.18406 16.7024 2.99915 16.0002 2.99911C15.298 2.99908 14.6081 3.1839 14 3.53501" stroke="currentColor" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14.371 16.749L10.629 15.249C10.4438 15.175 10.2849 15.0473 10.1728 14.8823C10.0607 14.7172 10.0005 14.5225 10 14.323V13.445C10.6065 13.0969 11.1107 12.5953 11.4617 11.9906C11.8128 11.3858 11.9985 10.6993 12 10V8C12 6.93913 11.5786 5.92172 10.8284 5.17157C10.0783 4.42143 9.06087 4 8 4C6.93913 4 5.92172 4.42143 5.17157 5.17157C4.42143 5.92172 4 6.93913 4 8V10C4.00153 10.6993 4.18717 11.3858 4.53826 11.9906C4.88935 12.5953 5.3935 13.0969 6 13.445V14.323C5.99987 14.5228 5.93989 14.718 5.82777 14.8834C5.71566 15.0488 5.55656 15.1769 5.371 15.251L1.629 16.751C1.44375 16.825 1.28488 16.9527 1.17279 17.1177C1.0607 17.2828 1.00053 17.4775 1 17.677V21H15V17.677C14.9999 17.4772 14.9399 17.282 14.8278 17.1166C14.7157 16.9512 14.5566 16.8231 14.371 16.749Z" stroke="currentColor" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB