mirror of
https://github.com/suitenumerique/meet.git
synced 2026-08-19 23:07:29 +00:00
9af42568bf
Rework how the participant name is displayed in the participant list to show as much of the name as possible before truncating. When the name has to be truncated, add a tooltip so users can hover to see the full name. Requested by users.
141 lines
4.4 KiB
TypeScript
141 lines
4.4 KiB
TypeScript
import { css } from '@/styled-system/css'
|
|
|
|
import { HStack, VStack } from '@/styled-system/jsx'
|
|
import { Text } from '@/primitives/Text'
|
|
import { useTranslation } from 'react-i18next'
|
|
import { Avatar } from '@/components/Avatar'
|
|
import { getParticipantColor } from '@/features/rooms/utils/getParticipantColor'
|
|
import {
|
|
getParticipantIsRoomAdmin,
|
|
getParticipantIsRoomOwner,
|
|
getParticipantIsRoomMember,
|
|
} from '@/features/rooms/utils/getParticipantIsRoomAdminOrOwner'
|
|
import { type LocalParticipant, type Participant, Track } from 'livekit-client'
|
|
import { isLocal } from '@/utils/livekit'
|
|
import {
|
|
useIsSpeaking,
|
|
useTrackMutedIndicator,
|
|
} from '@livekit/components-react'
|
|
import Source = Track.Source
|
|
import { RiMicFill, RiMicOffFill } from '@remixicon/react'
|
|
import { Button } from '@/primitives'
|
|
import { useState } from 'react'
|
|
import { useMuteParticipant } from '@/features/rooms/api/muteParticipant'
|
|
import { useCanMute } from '@/features/rooms/livekit/hooks/useCanMute'
|
|
import { ParticipantMenuButton } from './menu/ParticipantMenuButton'
|
|
import { PinBadge } from './PinBadge'
|
|
import { UnauthenticatedBadge } from './UnauthenticatedBadge'
|
|
import { MuteAlertDialog } from '@/features/rooms/livekit/components/MuteAlertDialog'
|
|
import { ParticipantName } from './ParticipantName'
|
|
|
|
type MicIndicatorProps = {
|
|
participant: Participant
|
|
}
|
|
|
|
const MicIndicator = ({ participant }: MicIndicatorProps) => {
|
|
const { t } = useTranslation('rooms')
|
|
const { muteParticipant } = useMuteParticipant()
|
|
const { isMuted } = useTrackMutedIndicator({
|
|
participant: participant,
|
|
source: Source.Microphone,
|
|
})
|
|
|
|
const canMute = useCanMute(participant)
|
|
const isSpeaking = useIsSpeaking(participant)
|
|
const [isAlertOpen, setIsAlertOpen] = useState(false)
|
|
const name = participant.name || participant.identity
|
|
|
|
const label = isLocal(participant)
|
|
? t('participants.muteYourself')
|
|
: t('participants.muteParticipant', {
|
|
name,
|
|
})
|
|
|
|
return (
|
|
<>
|
|
<Button
|
|
square
|
|
variant="greyscale"
|
|
size="sm"
|
|
tooltip={label}
|
|
aria-label={label}
|
|
isDisabled={isMuted || !canMute}
|
|
onPress={async () =>
|
|
!isMuted && isLocal(participant)
|
|
? await (participant as LocalParticipant)?.setMicrophoneEnabled(
|
|
false
|
|
)
|
|
: setIsAlertOpen(true)
|
|
}
|
|
data-attr="participants-mute"
|
|
>
|
|
{isMuted ? (
|
|
<RiMicOffFill color={'gray'} aria-hidden={true} />
|
|
) : (
|
|
<RiMicFill
|
|
className={css({
|
|
color: isSpeaking ? 'primaryDark.300' : 'primaryDark.50',
|
|
animation: isSpeaking
|
|
? 'pulse_background 800ms infinite'
|
|
: undefined,
|
|
})}
|
|
aria-hidden={true}
|
|
/>
|
|
)}
|
|
</Button>
|
|
<MuteAlertDialog
|
|
isOpen={isAlertOpen}
|
|
onSubmit={() =>
|
|
muteParticipant(participant).then(() => setIsAlertOpen(false))
|
|
}
|
|
onClose={() => setIsAlertOpen(false)}
|
|
name={name}
|
|
/>
|
|
</>
|
|
)
|
|
}
|
|
|
|
type ParticipantListItemProps = {
|
|
participant: Participant
|
|
}
|
|
|
|
export const ParticipantRow = ({ participant }: ParticipantListItemProps) => {
|
|
const { t } = useTranslation('rooms')
|
|
const name = participant.name || participant.identity
|
|
return (
|
|
<HStack
|
|
role="listitem"
|
|
justify="space-between"
|
|
id={participant.identity}
|
|
className={css({
|
|
padding: '0.25rem 0',
|
|
width: 'full',
|
|
})}
|
|
>
|
|
<HStack flex="1" minW="0">
|
|
<div className={css({ position: 'relative', flexShrink: 0 })}>
|
|
<Avatar name={name} bgColor={getParticipantColor(participant)} />
|
|
<PinBadge participant={participant} />
|
|
<UnauthenticatedBadge participant={participant} />
|
|
</div>
|
|
<VStack gap={0} alignItems="start" minW="0" flex="1">
|
|
<ParticipantName
|
|
displayedName={name}
|
|
isLocal={isLocal(participant)}
|
|
/>
|
|
<Text variant="xsNote">
|
|
{getParticipantIsRoomOwner(participant) && t('participants.host')}
|
|
{getParticipantIsRoomAdmin(participant) && t('participants.cohost')}
|
|
{getParticipantIsRoomMember(participant) &&
|
|
t('participants.member')}
|
|
</Text>
|
|
</VStack>
|
|
</HStack>
|
|
<HStack flexShrink={0}>
|
|
<MicIndicator participant={participant} />
|
|
<ParticipantMenuButton participant={participant} />
|
|
</HStack>
|
|
</HStack>
|
|
)
|
|
}
|