🚸(frontend) offer additionnal controls on participant tile
On hover, based on participant's type (remove/local) offer an appropriate action. Either applying effects on the local participant video or muting the remote participant. This is a huge enhancement in term of UX, nobody was finding these two controls in the current menus, and though the features were not implemented.
This commit is contained in:
committed by
aleb_the_flash
parent
03f6e6519b
commit
6373593de3
@@ -1,11 +1,24 @@
|
|||||||
import { css } from '@/styled-system/css'
|
import { css } from '@/styled-system/css'
|
||||||
import { HStack } from '@/styled-system/jsx'
|
import { HStack } from '@/styled-system/jsx'
|
||||||
import { Button } from '@/primitives'
|
import { Button } from '@/primitives'
|
||||||
import { RiPushpin2Line, RiUnpinLine } from '@remixicon/react'
|
import {
|
||||||
import { useFocusToggle } from '@livekit/components-react'
|
RiImageCircleAiFill,
|
||||||
|
RiMicLine,
|
||||||
|
RiMicOffLine,
|
||||||
|
RiPushpin2Line,
|
||||||
|
RiUnpinLine,
|
||||||
|
} from '@remixicon/react'
|
||||||
|
import {
|
||||||
|
useFocusToggle,
|
||||||
|
useTrackMutedIndicator,
|
||||||
|
} from '@livekit/components-react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { TrackReferenceOrPlaceholder } from '@livekit/components-core'
|
import { TrackReferenceOrPlaceholder } from '@livekit/components-core'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
import { useSidePanel } from '@/features/rooms/livekit/hooks/useSidePanel'
|
||||||
|
import { Participant, Track } from 'livekit-client'
|
||||||
|
import { MuteAlertDialog } from './MuteAlertDialog'
|
||||||
|
import { useMuteParticipant } from '../api/muteParticipant'
|
||||||
|
|
||||||
const FocusButton = ({
|
const FocusButton = ({
|
||||||
trackRef,
|
trackRef,
|
||||||
@@ -31,6 +44,59 @@ const FocusButton = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const EffectsButton = () => {
|
||||||
|
const { t } = useTranslation('rooms', { keyPrefix: 'participantTileFocus' })
|
||||||
|
const { isEffectsOpen, toggleEffects } = useSidePanel()
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
size={'sm'}
|
||||||
|
variant={'primaryTextDark'}
|
||||||
|
square
|
||||||
|
tooltip={t('effects')}
|
||||||
|
onPress={() => !isEffectsOpen && toggleEffects()}
|
||||||
|
>
|
||||||
|
<RiImageCircleAiFill />
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const MuteButton = ({ participant }: { participant: Participant }) => {
|
||||||
|
const { t } = useTranslation('rooms', { keyPrefix: 'participantTileFocus' })
|
||||||
|
|
||||||
|
const { isMuted } = useTrackMutedIndicator({
|
||||||
|
participant: participant,
|
||||||
|
source: Track.Source.Microphone,
|
||||||
|
})
|
||||||
|
|
||||||
|
const { muteParticipant } = useMuteParticipant()
|
||||||
|
const [isAlertOpen, setIsAlertOpen] = useState(false)
|
||||||
|
|
||||||
|
const name = participant.name || participant.identity
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
isDisabled={isMuted}
|
||||||
|
size={'sm'}
|
||||||
|
variant={'primaryTextDark'}
|
||||||
|
square
|
||||||
|
onPress={() => setIsAlertOpen(true)}
|
||||||
|
tooltip={t('muteParticipant', { name })}
|
||||||
|
>
|
||||||
|
{!isMuted ? <RiMicLine /> : <RiMicOffLine />}
|
||||||
|
</Button>
|
||||||
|
<MuteAlertDialog
|
||||||
|
isOpen={isAlertOpen}
|
||||||
|
onSubmit={() =>
|
||||||
|
muteParticipant(participant).then(() => setIsAlertOpen(false))
|
||||||
|
}
|
||||||
|
onClose={() => setIsAlertOpen(false)}
|
||||||
|
name={name}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export const ParticipantTileFocus = ({
|
export const ParticipantTileFocus = ({
|
||||||
trackRef,
|
trackRef,
|
||||||
}: {
|
}: {
|
||||||
@@ -50,6 +116,8 @@ export const ParticipantTileFocus = ({
|
|||||||
}
|
}
|
||||||
}, [hovered])
|
}, [hovered])
|
||||||
|
|
||||||
|
const participant = trackRef.participant
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={css({
|
className={css({
|
||||||
@@ -89,6 +157,11 @@ export const ParticipantTileFocus = ({
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<FocusButton trackRef={trackRef} />
|
<FocusButton trackRef={trackRef} />
|
||||||
|
{participant.isLocal ? (
|
||||||
|
<EffectsButton />
|
||||||
|
) : (
|
||||||
|
<MuteButton participant={participant} />
|
||||||
|
)}
|
||||||
</HStack>
|
</HStack>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -195,6 +195,8 @@
|
|||||||
"pin": {
|
"pin": {
|
||||||
"enable": "",
|
"enable": "",
|
||||||
"disable": ""
|
"disable": ""
|
||||||
}
|
},
|
||||||
|
"effects": "",
|
||||||
|
"muteParticipant": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,6 +194,8 @@
|
|||||||
"pin": {
|
"pin": {
|
||||||
"enable": "Pin",
|
"enable": "Pin",
|
||||||
"disable": "Unpin"
|
"disable": "Unpin"
|
||||||
}
|
},
|
||||||
|
"effects": "Apply visual effects",
|
||||||
|
"muteParticipant": "Mute {{name}}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,6 +194,8 @@
|
|||||||
"pin": {
|
"pin": {
|
||||||
"enable": "Épingler",
|
"enable": "Épingler",
|
||||||
"disable": "Annuler l'épinglage"
|
"disable": "Annuler l'épinglage"
|
||||||
}
|
},
|
||||||
|
"effects": "Appliquer des effets",
|
||||||
|
"muteParticipant": "Couper le micro de {{name}}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user