feature(ui) - design changes

This commit is contained in:
Shekar Siri 2021-07-08 10:52:30 +05:30
parent 2e77aa3ca7
commit 2c2fa5b0b5
11 changed files with 155 additions and 50 deletions

View file

@ -0,0 +1,29 @@
.controls {
height: 38px;
/* margin-top: 5px; */
/* background-color: white; */
/* border-top: solid thin #CCC; */
}
.btnWrapper {
display: flex;
align-items: center;
height: 24px;
font-size: 12px;
color: $gray-medium;
&.disabled {
/* background-color: red; */
& svg {
fill: red;
}
}
}
.endButton {
background-color: $red;
border-radius: 3px;
padding: 2px 8px;
color: white;
font-size: 12px;
}

View file

@ -0,0 +1,54 @@
import React, { useState } from 'react'
import stl from './ChatControls.css'
import cn from 'classnames'
import { Button, Icon } from 'UI'
interface Props {
stream: MediaStream | null,
endCall: () => void
}
function ChatControls({ stream, endCall } : Props) {
const [audioEnabled, setAudioEnabled] = useState(true)
const [videoEnabled, setVideoEnabled] = useState(true)
const toggleAudio = () => {
if (!stream) { return; }
const aEn = !audioEnabled
stream.getAudioTracks().forEach(track => track.enabled = aEn);
setAudioEnabled(aEn);
}
const toggleVideo = () => {
if (!stream) { return; }
const vEn = !videoEnabled;
stream.getVideoTracks().forEach(track => track.enabled = vEn);
setVideoEnabled(vEn)
}
return (
<div className={cn(stl.controls, "flex items-center w-full justify-start bottom-0 px-2")}>
<div className="flex items-center">
<div className={cn(stl.btnWrapper, { [stl.disabled]: !audioEnabled})}>
<Button plain size="small" onClick={toggleAudio} noPadding className="flex items-center">
<Icon name={audioEnabled ? 'mic' : 'mic-mute'} size="16" />
<span className="ml-2 color-gray-medium text-sm">{audioEnabled ? 'Mute' : 'Unmute'}</span>
</Button>
</div>
<div className={cn(stl.btnWrapper, { [stl.disabled]: !videoEnabled})}>
<Button plain size="small" onClick={toggleVideo} noPadding className="flex items-center">
<Icon name={ videoEnabled ? 'camera-video' : 'camera-video-off' } size="16" />
<span className="ml-2 color-gray-medium text-sm">{videoEnabled ? 'Stop Video' : 'Start Video'}</span>
</Button>
</div>
</div>
<div className="ml-auto">
<button className={stl.endButton} onClick={endCall}>
END
</button>
</div>
</div>
)
}
export default ChatControls

View file

@ -0,0 +1 @@
export { default } from './ChatControls'

View file

@ -1,29 +1,35 @@
import React, { useState, FC } from 'react'
import VideoContainer from '../components/VideoContainer'
import { Icon, Popup } from 'UI'
import { Icon, Popup, Button } from 'UI'
import cn from 'classnames'
import Counter from 'App/components/shared/SessionItem/Counter'
import stl from './chatWindow.css'
import ChatControls from '../ChatControls/ChatControls'
export interface Props {
incomeStream: MediaStream | null,
localStream: MediaStream | null
// call: (oStream: MediaStream, cb: (iStream: MediaStream)=>void)=>void
localStream: MediaStream | null,
userId: String,
endCall: () => void
}
const ChatWindow: FC<Props> = function ChatWindow({ incomeStream, localStream }) {
const ChatWindow: FC<Props> = function ChatWindow({ userId, incomeStream, localStream, endCall }) {
const [minimize, setMinimize] = useState(false)
return (
<div
className="fixed border radius bg-white z-50 shadow-xl mt-16 p-2"
style={{ width: '220px' }}
className={cn(stl.wrapper, "fixed radius bg-white z-50 shadow-xl mt-16")}
style={{ width: '280px' }}
>
<div className="flex items-center">
<div className="flex items-center p-2">
<div>
<button onClick={() => setMinimize(!minimize)}>
<div className={stl.headerTitle}><b>Meeting</b> {userId}</div>
{/* <button onClick={() => setMinimize(!minimize)}>
<Icon name={ minimize ? "plus" : "minus" } size="14" />
</button>
</button> */}
</div>
<Popup
<Counter startTime={new Date().getTime() } className="text-sm ml-auto" />
{/* <Popup
trigger={
<button className="flex items-center ml-auto">
<Icon name="high-engagement" size="16" color="teal" />
@ -33,14 +39,16 @@ const ChatWindow: FC<Props> = function ChatWindow({ incomeStream, localStream })
size="tiny"
inverted
position="top center"
/>
/> */}
</div>
<div className={cn({'hidden' : minimize}, 'mt-2')}>
<div className={cn({'hidden' : minimize}, 'relative')}>
<VideoContainer stream={ incomeStream } />
<div className="py-1" />
<VideoContainer stream={ localStream } muted/>
<div className="absolute bottom-0 right-0 z-50">
<VideoContainer stream={ localStream } muted height={50} />
</div>
</div>
</div>
<ChatControls stream={localStream} endCall={endCall} />
</div>
)
}

View file

@ -1,8 +1,15 @@
.wrapepr {
.wrapper {
background-color: white;
border: solid thin #CCC;
border: solid thin #000;
border-radius: 3px;
position: fixed;
height: 400px;
width: 300px;
}
.headerTitle {
font-size: 12px;
max-width: 180px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

View file

@ -3,6 +3,6 @@ import ChatWindow from './ChatWindow';
storiesOf('Assist', module)
.add('ChatWindow', () => (
<ChatWindow />
<ChatWindow userId="test@test.com" />
))

View file

@ -56,15 +56,16 @@ function AssistActions({ toggleChatWindow, userId, calling }: Props) {
<Popup
trigger={
<div
className={cn('cursor-pointer p-2 mr-2')}
className={cn('cursor-pointer p-2 mr-2 flex items-center')}
onClick={inCall ? endCall : call}
role="button"
>
<Icon
name="telephone-fill"
name="headset"
size="20"
color={ calling !== 2 ? "red" : "teal" }
color={ inCall ? "red" : "gray-darkest" }
/>
<span className={cn("ml-2", { 'red' : inCall })}>{ inCall ? 'End Meeting' : 'Start Meeting' }</span>
</div>
}
content={ `Call ${userId}` }
@ -73,7 +74,7 @@ function AssistActions({ toggleChatWindow, userId, calling }: Props) {
position="top right"
/>
<div className="fixed ml-3 left-0 top-0 z-50">
{ inCall && <ChatWindow incomeStream={incomeStream} localStream={localStream} /> }
{ inCall && <ChatWindow endCall={endCall} userId={userId} incomeStream={incomeStream} localStream={localStream} /> }
</div>
</div>
)

View file

@ -1,6 +1,6 @@
.controls {
margin-bottom: 8px;
margin-right: 15px;
.controls {
height: 28px;
background-color: red;
}
.btnWrapper {

View file

@ -5,12 +5,13 @@ import stl from './VideoContainer.css'
interface Props {
stream: MediaStream | null
muted?: boolean
muted?: boolean,
height?: number
}
function VideoContainer({ stream, muted = false }: Props) {
const [audioEnabled, setAudioEnabled] = useState(true)
const [videoEnabled, setVideoEnabled] = useState(true)
function VideoContainer({ stream, muted = false, height = 280 }: Props) {
// const [audioEnabled, setAudioEnabled] = useState(true)
// const [videoEnabled, setVideoEnabled] = useState(true)
const ref = useRef<HTMLVideoElement>(null);
useEffect(() => {
@ -19,25 +20,25 @@ function VideoContainer({ stream, muted = false }: Props) {
}
}, [ ref.current, stream ])
const toggleAudio = () => {
if (!stream) { return; }
const aEn = !audioEnabled
stream.getAudioTracks().forEach(track => track.enabled = aEn);
setAudioEnabled(aEn);
}
// const toggleAudio = () => {
// if (!stream) { return; }
// const aEn = !audioEnabled
// stream.getAudioTracks().forEach(track => track.enabled = aEn);
// setAudioEnabled(aEn);
// }
const toggleVideo = () => {
if (!stream) { return; }
const vEn = !videoEnabled;
stream.getVideoTracks().forEach(track => track.enabled = vEn);
setVideoEnabled(vEn)
}
// const toggleVideo = () => {
// if (!stream) { return; }
// const vEn = !videoEnabled;
// stream.getVideoTracks().forEach(track => track.enabled = vEn);
// setVideoEnabled(vEn)
// }
return (
<div className="relative bg-gray-light-shade" style={{ height: '152px' }}>
<div className="absolute inset-0 flex justify-center border border-gray-300 bg-white radius bg-opacity-25">
<video autoPlay ref={ ref } muted={ muted } />
<div className={cn(stl.controls, "flex items-center absolute w-full justify-end bottom-0")}>
<div className="relative bg-gray-light-shade">
<div className="justify-center border border-gray-800 radius bg-opacity-25">
<video autoPlay ref={ ref } muted={ muted } style={{ width: height }} />
{/* <div className={cn(stl.controls, "flex items-center border-t w-full justify-start bottom-0")}>
<div className={cn(stl.btnWrapper, { [stl.disabled]: !audioEnabled})}>
<Button plain size="small" onClick={toggleAudio} noPadding>
<Icon name={audioEnabled ? 'mic' : 'mic-mute'} size="14" />
@ -49,7 +50,7 @@ function VideoContainer({ stream, muted = false }: Props) {
<Icon name={ videoEnabled ? 'camera-video' : 'camera-video-off' } size="14" />
</Button>
</div>
</div>
</div> */}
</div>
</div>
)

View file

@ -2,10 +2,11 @@ import React, { useState, useEffect } from 'react'
import { Duration } from 'luxon';
interface Props {
startTime: any
startTime: any,
className: string
}
function Counter({ startTime }: Props) {
function Counter({ startTime, className }: Props) {
let intervalId;
const [duration, setDuration] = useState(new Date().getTime() - startTime)
@ -19,7 +20,7 @@ function Counter({ startTime }: Props) {
}, [duration])
return (
<div className="mx-2">
<div className={className}>
{startTime && Duration.fromMillis(duration).toFormat('m:ss')}
</div>
)

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" class="bi bi-headset" viewBox="0 0 16 16">
<path d="M8 1a5 5 0 0 0-5 5v1h1a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V6a6 6 0 1 1 12 0v6a2.5 2.5 0 0 1-2.5 2.5H9.366a1 1 0 0 1-.866.5h-1a1 1 0 1 1 0-2h1a1 1 0 0 1 .866.5H11.5A1.5 1.5 0 0 0 13 12h-1a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1h1V6a5 5 0 0 0-5-5z"/>
</svg>

After

Width:  |  Height:  |  Size: 349 B