mirror of
https://github.com/suitenumerique/meet.git
synced 2026-07-26 11:58:53 +00:00
⚡️(frontend) optimize participant metadata rendering on raised hand
Push state down into the participant metadata subtree so a raised hand change no longer re-renders the whole metadata block. Use the children-as-props pattern so only the item actually related to the raised hand re-renders when its state changes. This also better encapsulates the color-update logic tied to the raised-hand state.
This commit is contained in:
committed by
aleb_the_flash
parent
5f52fa8d8d
commit
f21c4c91ed
@@ -1,7 +1,3 @@
|
||||
import {
|
||||
useRaisedHand,
|
||||
useRaisedHandPosition,
|
||||
} from '@/features/rooms/livekit/hooks/useRaisedHand'
|
||||
import {
|
||||
ConnectionQualityIndicator,
|
||||
LockLockedIcon,
|
||||
@@ -12,8 +8,8 @@ import {
|
||||
import { HStack } from '@/styled-system/jsx'
|
||||
import { Participant } from 'livekit-client'
|
||||
import { MutedMicIndicator } from './MutedMicIndicator'
|
||||
import { RiHand } from '@remixicon/react'
|
||||
import { ParticipantName } from './ParticipantName'
|
||||
import { RaisedHandMetadataWrapper } from './RaisedHandMetadataWrapper'
|
||||
|
||||
export const ParticipantMetadata = ({
|
||||
participant,
|
||||
@@ -24,52 +20,15 @@ export const ParticipantMetadata = ({
|
||||
}) => {
|
||||
const { identity, name } = useParticipantInfo({ participant })
|
||||
const isEncrypted = useIsEncrypted(participant)
|
||||
const { isHandRaised } = useRaisedHand({ participant })
|
||||
const { positionInQueue, firstInQueue } = useRaisedHandPosition({
|
||||
participant,
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="lk-participant-metadata">
|
||||
<HStack gap={0.25}>
|
||||
{!isScreenShare && <MutedMicIndicator participant={participant} />}
|
||||
<div
|
||||
className="lk-participant-metadata-item"
|
||||
style={{
|
||||
padding: '0.1rem 0.25rem',
|
||||
backgroundColor:
|
||||
isHandRaised && !isScreenShare
|
||||
? firstInQueue
|
||||
? '#fde047'
|
||||
: 'white'
|
||||
: undefined,
|
||||
color: isHandRaised && !isScreenShare ? 'black' : undefined,
|
||||
transition: 'background 200ms ease, color 400ms ease',
|
||||
}}
|
||||
<RaisedHandMetadataWrapper
|
||||
participant={participant}
|
||||
enabled={!isScreenShare}
|
||||
>
|
||||
{isHandRaised && !isScreenShare && (
|
||||
<span
|
||||
style={{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: '0.1rem',
|
||||
}}
|
||||
>
|
||||
<span>{positionInQueue}</span>
|
||||
<RiHand
|
||||
color="black"
|
||||
size={16}
|
||||
style={{
|
||||
marginRight: '0.4rem',
|
||||
marginLeft: '0.1rem',
|
||||
minWidth: '16px',
|
||||
animationDuration: '300ms',
|
||||
animationName: 'wave_hand',
|
||||
animationIterationCount: '2',
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
{isScreenShare && (
|
||||
<ScreenShareIcon
|
||||
style={{
|
||||
@@ -87,7 +46,7 @@ export const ParticipantMetadata = ({
|
||||
isScreenShare={isScreenShare}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</RaisedHandMetadataWrapper>
|
||||
</HStack>
|
||||
<ConnectionQualityIndicator className="lk-participant-metadata-item" />
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
import React, { ReactNode, RefObject, useEffect, useRef } from 'react'
|
||||
import {
|
||||
useRaisedHand,
|
||||
useRaisedHandPosition,
|
||||
} from '@/features/rooms/livekit/hooks/useRaisedHand'
|
||||
import { Participant } from 'livekit-client'
|
||||
import { RiHand } from '@remixicon/react'
|
||||
|
||||
const PositionInQueue = React.memo(
|
||||
({ positionInQueue }: { positionInQueue?: number }) => {
|
||||
if (!positionInQueue) return
|
||||
return (
|
||||
<span
|
||||
style={{ display: 'inline-flex', alignItems: 'center', gap: '0.1rem' }}
|
||||
>
|
||||
<span>{positionInQueue}</span>
|
||||
<RiHand
|
||||
color="black"
|
||||
size={16}
|
||||
style={{
|
||||
marginRight: '0.4rem',
|
||||
marginLeft: '0.1rem',
|
||||
minWidth: '16px',
|
||||
animationDuration: '300ms',
|
||||
animationName: 'wave_hand',
|
||||
animationIterationCount: '2',
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
PositionInQueue.displayName = 'PositionInQueue'
|
||||
|
||||
const RaisedHandActiveItem = ({
|
||||
participant,
|
||||
targetRef,
|
||||
}: {
|
||||
participant: Participant
|
||||
targetRef: RefObject<HTMLElement | null>
|
||||
}) => {
|
||||
const { positionInQueue, firstInQueue } = useRaisedHandPosition({
|
||||
participant,
|
||||
})
|
||||
useEffect(() => {
|
||||
const el = targetRef.current
|
||||
if (!el) return
|
||||
|
||||
el.style.backgroundColor = firstInQueue ? '#fde047' : 'white'
|
||||
el.style.color = 'black'
|
||||
|
||||
return () => {
|
||||
el.style.backgroundColor = ''
|
||||
el.style.color = ''
|
||||
}
|
||||
}, [targetRef, firstInQueue])
|
||||
|
||||
return <PositionInQueue positionInQueue={positionInQueue} />
|
||||
}
|
||||
|
||||
export const RaisedHandMetadataWrapper = ({
|
||||
participant,
|
||||
enabled = true,
|
||||
children,
|
||||
}: {
|
||||
participant: Participant
|
||||
enabled?: boolean
|
||||
children: ReactNode
|
||||
}) => {
|
||||
const ref = useRef(null)
|
||||
|
||||
const { isHandRaised } = useRaisedHand({ participant })
|
||||
const showHand = isHandRaised && enabled
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className="lk-participant-metadata-item"
|
||||
style={{
|
||||
padding: '0.1rem 0.25rem',
|
||||
transition: 'background 200ms ease',
|
||||
}}
|
||||
>
|
||||
{showHand && (
|
||||
<RaisedHandActiveItem participant={participant} targetRef={ref} />
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user