🚸(frontend) refactor participant tile while being hovered
Inspired by GMeet. Make central actions available on a participant tile when a user hover it. This new interactive zone will be extended with more actions and controls.
This commit is contained in:
committed by
aleb_the_flash
parent
0b74cf96f2
commit
17f8ec6319
@@ -1,7 +1,6 @@
|
||||
import {
|
||||
AudioTrack,
|
||||
ConnectionQualityIndicator,
|
||||
FocusToggle,
|
||||
LockLockedIcon,
|
||||
ParticipantName,
|
||||
ParticipantTileProps,
|
||||
@@ -23,11 +22,12 @@ import {
|
||||
TrackReferenceOrPlaceholder,
|
||||
} from '@livekit/components-core'
|
||||
import { Track } from 'livekit-client'
|
||||
import { ParticipantPlaceholder } from '@/features/rooms/livekit/components/ParticipantPlaceholder'
|
||||
import { RiHand } from '@remixicon/react'
|
||||
import { useRaisedHand } from '@/features/rooms/livekit/hooks/useRaisedHand'
|
||||
import { useRaisedHand } from '../hooks/useRaisedHand'
|
||||
import { HStack } from '@/styled-system/jsx'
|
||||
import { MutedMicIndicator } from '@/features/rooms/livekit/components/MutedMicIndicator'
|
||||
import { MutedMicIndicator } from './MutedMicIndicator'
|
||||
import { ParticipantPlaceholder } from './ParticipantPlaceholder'
|
||||
import { ParticipantTileFocus } from './ParticipantTileFocus'
|
||||
|
||||
export function TrackRefContextIfNeeded(
|
||||
props: React.PropsWithChildren<{
|
||||
@@ -173,7 +173,9 @@ export const ParticipantTile: (
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{!disableMetadata && <FocusToggle trackRef={trackReference} />}
|
||||
{!disableMetadata && (
|
||||
<ParticipantTileFocus trackRef={trackReference} />
|
||||
)}
|
||||
</ParticipantContextIfNeeded>
|
||||
</TrackRefContextIfNeeded>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
import { css } from '@/styled-system/css'
|
||||
import { HStack } from '@/styled-system/jsx'
|
||||
import { Button } from '@/primitives'
|
||||
import { RiPushpin2Line, RiUnpinLine } from '@remixicon/react'
|
||||
import { useFocusToggle } from '@livekit/components-react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { TrackReferenceOrPlaceholder } from '@livekit/components-core'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
const FocusButton = ({
|
||||
trackRef,
|
||||
}: {
|
||||
trackRef: TrackReferenceOrPlaceholder
|
||||
}) => {
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'participantTileFocus' })
|
||||
const { mergedProps, inFocus } = useFocusToggle({
|
||||
trackRef,
|
||||
props: {},
|
||||
})
|
||||
return (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="primaryTextDark"
|
||||
square
|
||||
tooltip={inFocus ? t('pin.disable') : t('pin.enable')}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
onPress={(event) => mergedProps?.onClick?.(event as any)}
|
||||
>
|
||||
{inFocus ? <RiUnpinLine /> : <RiPushpin2Line />}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
export const ParticipantTileFocus = ({
|
||||
trackRef,
|
||||
}: {
|
||||
trackRef: TrackReferenceOrPlaceholder
|
||||
}) => {
|
||||
const [hovered, setHovered] = useState(false)
|
||||
const [opacity, setOpacity] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
if (hovered) {
|
||||
// Wait for next frame to ensure element is mounted
|
||||
requestAnimationFrame(() => {
|
||||
setOpacity(0.6)
|
||||
})
|
||||
} else {
|
||||
setOpacity(0)
|
||||
}
|
||||
}, [hovered])
|
||||
|
||||
return (
|
||||
<div
|
||||
className={css({
|
||||
position: 'absolute',
|
||||
left: '0',
|
||||
top: '0',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
})}
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
>
|
||||
{hovered && (
|
||||
<div
|
||||
className={css({
|
||||
backgroundColor: 'primaryDark.50',
|
||||
transition: 'opacity 200ms linear',
|
||||
zIndex: 1,
|
||||
borderRadius: '0.25rem',
|
||||
display: 'flex',
|
||||
_hover: {
|
||||
opacity: '0.95 !important',
|
||||
},
|
||||
})}
|
||||
style={{ opacity }}
|
||||
>
|
||||
<HStack
|
||||
gap={0.5}
|
||||
className={css({
|
||||
padding: '0.5rem',
|
||||
_hover: {
|
||||
opacity: '1 !important',
|
||||
},
|
||||
})}
|
||||
>
|
||||
<FocusButton trackRef={trackRef} />
|
||||
</HStack>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -189,5 +189,11 @@
|
||||
},
|
||||
"recording": {
|
||||
"label": ""
|
||||
},
|
||||
"participantTileFocus": {
|
||||
"pin": {
|
||||
"enable": "",
|
||||
"disable": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,5 +188,11 @@
|
||||
},
|
||||
"recording": {
|
||||
"label": "Recording"
|
||||
},
|
||||
"participantTileFocus": {
|
||||
"pin": {
|
||||
"enable": "Pin",
|
||||
"disable": "Unpin"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,5 +188,11 @@
|
||||
},
|
||||
"recording": {
|
||||
"label": "Enregistrement"
|
||||
},
|
||||
"participantTileFocus": {
|
||||
"pin": {
|
||||
"enable": "Épingler",
|
||||
"disable": "Annuler l'épinglage"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user