✨(frontend) introduce a side panel for effects
It simply renders the video track if enabled. It's a basis for building the 'blur your screen' feature. More in the upcoming commits.
This commit is contained in:
committed by
aleb_the_flash
parent
00fa7beebd
commit
756be17cc7
@@ -0,0 +1,68 @@
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { useLocalParticipant } from '@livekit/components-react'
|
||||
import { LocalVideoTrack } from 'livekit-client'
|
||||
import { Div, P } from '@/primitives'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
export const Effects = () => {
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'effects' })
|
||||
const { isCameraEnabled, cameraTrack } = useLocalParticipant()
|
||||
const videoRef = useRef<HTMLVideoElement>(null)
|
||||
|
||||
const localCameraTrack = cameraTrack?.track as LocalVideoTrack
|
||||
|
||||
useEffect(() => {
|
||||
const videoElement = videoRef.current
|
||||
|
||||
const attachVideoTrack = async () => {
|
||||
if (!videoElement) return
|
||||
localCameraTrack?.attach(videoElement)
|
||||
}
|
||||
|
||||
attachVideoTrack()
|
||||
|
||||
return () => {
|
||||
if (!videoElement) return
|
||||
localCameraTrack.detach(videoElement)
|
||||
}
|
||||
}, [localCameraTrack, isCameraEnabled])
|
||||
|
||||
return (
|
||||
<Div padding="0 1.5rem">
|
||||
{localCameraTrack && isCameraEnabled ? (
|
||||
<video
|
||||
ref={videoRef}
|
||||
width="100%"
|
||||
muted
|
||||
style={{
|
||||
transform: 'rotateY(180deg)',
|
||||
minHeight: '173px',
|
||||
borderRadius: '4px',
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '174px',
|
||||
display: 'flex',
|
||||
backgroundColor: 'black',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<P
|
||||
style={{
|
||||
color: 'white',
|
||||
textAlign: 'center',
|
||||
textWrap: 'balance',
|
||||
marginBottom: 0,
|
||||
}}
|
||||
>
|
||||
{t('activateCamera')}
|
||||
</P>
|
||||
</div>
|
||||
)}
|
||||
</Div>
|
||||
)
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import { ParticipantsList } from './controls/Participants/ParticipantsList'
|
||||
import { useWidgetInteraction } from '../hooks/useWidgetInteraction'
|
||||
import { ReactNode } from 'react'
|
||||
import { Effects } from './Effects'
|
||||
|
||||
type StyledSidePanelProps = {
|
||||
title: string
|
||||
@@ -65,7 +66,7 @@ export const SidePanel = () => {
|
||||
const layoutSnap = useSnapshot(layoutStore)
|
||||
const sidePanel = layoutSnap.sidePanel
|
||||
|
||||
const { isParticipantsOpen } = useWidgetInteraction()
|
||||
const { isParticipantsOpen, isEffectsOpen } = useWidgetInteraction()
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'sidePanel' })
|
||||
|
||||
if (!sidePanel) {
|
||||
@@ -81,6 +82,7 @@ export const SidePanel = () => {
|
||||
})}
|
||||
>
|
||||
{isParticipantsOpen && <ParticipantsList />}
|
||||
{isEffectsOpen && <Effects />}
|
||||
</StyledSidePanel>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import { Dispatch, SetStateAction } from 'react'
|
||||
import { DialogState } from './OptionsButton'
|
||||
import { Separator } from '@/primitives/Separator'
|
||||
import { useWidgetInteraction } from '../../../hooks/useWidgetInteraction'
|
||||
|
||||
// @todo try refactoring it to use MenuList component
|
||||
export const OptionsMenuItems = ({
|
||||
@@ -18,7 +19,7 @@ export const OptionsMenuItems = ({
|
||||
onOpenDialog: Dispatch<SetStateAction<DialogState>>
|
||||
}) => {
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'options.items' })
|
||||
|
||||
const { toggleEffects } = useWidgetInteraction()
|
||||
return (
|
||||
<RACMenu
|
||||
style={{
|
||||
@@ -28,7 +29,7 @@ export const OptionsMenuItems = ({
|
||||
>
|
||||
<Section>
|
||||
<MenuItem
|
||||
onAction={() => console.log('open dialog')}
|
||||
onAction={() => toggleEffects()}
|
||||
className={menuItemRecipe({ icon: true })}
|
||||
>
|
||||
<RiAccountBoxLine size={20} />
|
||||
|
||||
@@ -9,6 +9,7 @@ export const useWidgetInteraction = () => {
|
||||
const sidePanel = layoutSnap.sidePanel
|
||||
|
||||
const isParticipantsOpen = sidePanel == 'participants'
|
||||
const isEffectsOpen = sidePanel == 'effects'
|
||||
|
||||
const toggleParticipants = () => {
|
||||
if (dispatch && state?.showChat) {
|
||||
@@ -26,11 +27,20 @@ export const useWidgetInteraction = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const toggleEffects = () => {
|
||||
if (dispatch && state?.showChat) {
|
||||
dispatch({ msg: 'toggle_chat' })
|
||||
}
|
||||
layoutStore.sidePanel = isEffectsOpen ? null : 'effects'
|
||||
}
|
||||
|
||||
return {
|
||||
toggleParticipants,
|
||||
toggleChat,
|
||||
toggleEffects,
|
||||
isChatOpen: state?.showChat,
|
||||
unreadMessages: state?.unreadMessages,
|
||||
isParticipantsOpen,
|
||||
isEffectsOpen,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,12 +73,17 @@
|
||||
"effects": ""
|
||||
}
|
||||
},
|
||||
"effects": {
|
||||
"activateCamera": ""
|
||||
},
|
||||
"sidePanel": {
|
||||
"heading": {
|
||||
"participants": ""
|
||||
"participants": "",
|
||||
"effects": ""
|
||||
},
|
||||
"content": {
|
||||
"participants": ""
|
||||
"participants": "",
|
||||
"effects": ""
|
||||
},
|
||||
"closeButton": ""
|
||||
},
|
||||
|
||||
@@ -71,12 +71,17 @@
|
||||
"effects": "Apply effects"
|
||||
}
|
||||
},
|
||||
"effects": {
|
||||
"activateCamera": "Camera is disabled"
|
||||
},
|
||||
"sidePanel": {
|
||||
"heading": {
|
||||
"participants": "Participants"
|
||||
"participants": "Participants",
|
||||
"effects": "Effects"
|
||||
},
|
||||
"content": {
|
||||
"participants": "participants"
|
||||
"participants": "participants",
|
||||
"effects": "effects"
|
||||
},
|
||||
"closeButton": "Hide {{content}}"
|
||||
},
|
||||
|
||||
@@ -71,12 +71,17 @@
|
||||
"effects": "Appliquer des effets"
|
||||
}
|
||||
},
|
||||
"effects": {
|
||||
"activateCamera": "Votre camera est désactivée"
|
||||
},
|
||||
"sidePanel": {
|
||||
"heading": {
|
||||
"participants": "Participants"
|
||||
"participants": "Participants",
|
||||
"effects": "Effets"
|
||||
},
|
||||
"content": {
|
||||
"participants": "les participants"
|
||||
"participants": "les participants",
|
||||
"effects": "les effets"
|
||||
},
|
||||
"closeButton": "Masquer {{content}}"
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@ import { proxy } from 'valtio'
|
||||
|
||||
type State = {
|
||||
showHeader: boolean
|
||||
sidePanel: 'participants' | null
|
||||
sidePanel: 'participants' | 'effects' | null
|
||||
}
|
||||
|
||||
export const layoutStore = proxy<State>({
|
||||
|
||||
Reference in New Issue
Block a user