fixup! ♻️(frontend) normalize PiP component patterns

This commit is contained in:
Cyril
2026-05-07 11:08:42 +02:00
parent 47ec78973b
commit f9ca489b2f
3 changed files with 37 additions and 31 deletions
@@ -14,17 +14,21 @@ import { usePipElementSize } from '../hooks/usePipElementSize'
import { PipOptionsMenu } from './controls/PipOptionsMenu'
import { PipReactionsToggle } from './PipReactionsToggle'
export const CollapsibleControls = {
HAND: 'hand',
SUBTITLES: 'subtitles',
SCREEN_SHARE: 'screenShare',
REACTIONS: 'reactions',
} as const
export type CollapsibleControl =
| 'hand'
| 'subtitles'
| 'screenShare'
| 'reactions'
(typeof CollapsibleControls)[keyof typeof CollapsibleControls]
const COLLAPSE_ORDER: CollapsibleControl[] = [
'hand',
'subtitles',
'screenShare',
'reactions',
CollapsibleControls.HAND,
CollapsibleControls.SUBTITLES,
CollapsibleControls.SCREEN_SHARE,
CollapsibleControls.REACTIONS,
]
const BUTTON_SLOT = 50
@@ -39,7 +43,7 @@ const getHiddenControls = (
const collapsible = showScreenShare
? COLLAPSE_ORDER
: COLLAPSE_ORDER.filter((c) => c !== 'screenShare')
: COLLAPSE_ORDER.filter((c) => c !== CollapsibleControls.SCREEN_SHARE)
const available = containerWidth - ESSENTIAL_WIDTH
const maxVisible = Math.max(0, Math.floor(available / BUTTON_SLOT))
@@ -84,10 +88,10 @@ export const PipControlBar = ({
<PipControlsCenter>
<AudioDevicesControl hideMenu />
<VideoDeviceControl hideMenu />
{!hidden.has('reactions') && <PipReactionsToggle />}
{showScreenShare && !hidden.has('screenShare') && <ScreenShareToggle />}
{!hidden.has('subtitles') && <SubtitlesToggle />}
{!hidden.has('hand') && <HandToggle />}
{!hidden.has(CollapsibleControls.REACTIONS) && <PipReactionsToggle />}
{showScreenShare && !hidden.has(CollapsibleControls.SCREEN_SHARE) && <ScreenShareToggle />}
{!hidden.has(CollapsibleControls.SUBTITLES) && <SubtitlesToggle />}
{!hidden.has(CollapsibleControls.HAND) && <HandToggle />}
<PipOptionsMenu overflowControls={hidden} />
<LeaveButton />
<StartMediaButton />
@@ -1,5 +1,4 @@
import { Menu as RACMenu, MenuSection } from 'react-aria-components'
import { useTranslation } from 'react-i18next'
import { Separator } from '@/primitives/Separator'
import { FeedbackMenuItem } from '@/features/rooms/livekit/components/controls/Options/FeedbackMenuItem'
import { EffectsMenuItem } from '@/features/rooms/livekit/components/controls/Options/EffectsMenuItem'
@@ -16,7 +15,6 @@ type PipOptionsMenuItemsProps = {
export const PipOptionsMenuItems = ({
overflowControls,
}: PipOptionsMenuItemsProps) => {
const { t } = useTranslation('rooms')
const hasOverflow = overflowControls && overflowControls.size > 0
return (
@@ -29,7 +27,7 @@ export const PipOptionsMenuItems = ({
{hasOverflow && (
<>
<MenuSection>
<PipOverflowItems overflowControls={overflowControls} t={t} />
<PipOverflowItems overflowControls={overflowControls} />
</MenuSection>
<Separator />
</>
@@ -1,3 +1,4 @@
import React from 'react'
import { MenuItem } from 'react-aria-components'
import {
RiHand,
@@ -5,57 +6,60 @@ import {
RiArrowUpLine,
RiEmotionLine,
} from '@remixicon/react'
import { TFunction } from 'i18next'
import { useTranslation } from 'react-i18next'
import { Track } from 'livekit-client'
import { pipLayoutStore } from '@/features/pip/stores/pipLayoutStore'
import { menuRecipe } from '@/primitives/menuRecipe'
import { useRoomContext } from '@livekit/components-react'
import { useRoomContext, useTrackToggle } from '@livekit/components-react'
import { useRaisedHand } from '@/features/rooms/livekit/hooks/useRaisedHand'
import { useSubtitles } from '@/features/subtitle/hooks/useSubtitles'
import { useAreSubtitlesAvailable } from '@/features/subtitle/hooks/useAreSubtitlesAvailable'
import { useSnapshot } from 'valtio'
import type { CollapsibleControl } from '../PipControlBar'
import { CollapsibleControls, type CollapsibleControl } from '../PipControlBar'
type PipOverflowItemsProps = {
overflowControls: Set<CollapsibleControl>
t: TFunction<'rooms'>
}
export const PipOverflowItems = ({
overflowControls,
t,
}: PipOverflowItemsProps) => {
const { t } = useTranslation('rooms')
const room = useRoomContext()
const { isHandRaised, toggleRaisedHand } = useRaisedHand({
participant: room.localParticipant,
})
const { areSubtitlesOpen, toggleSubtitles } = useSubtitles()
const areSubtitlesAvailable = useAreSubtitlesAvailable()
const pipSnap = useSnapshot(pipLayoutStore)
const { buttonProps: screenShareProps, enabled: isScreenSharing } =
useTrackToggle({
source: Track.Source.ScreenShare,
captureOptions: { audio: true, selfBrowserSurface: 'include' },
})
const pipLayoutSnap = useSnapshot(pipLayoutStore)
const toggleReactions = () => {
pipLayoutStore.showReactionsToolbar = !pipSnap.showReactionsToolbar
pipLayoutStore.showReactionsToolbar = !pipLayoutSnap.showReactionsToolbar
}
const itemClass = menuRecipe({ icon: true, variant: 'dark' }).item
return (
<>
{overflowControls.has('reactions') && (
{overflowControls.has(CollapsibleControls.REACTIONS) && (
<MenuItem onAction={toggleReactions} className={itemClass}>
<RiEmotionLine size={20} />
{t('controls.reactions.button')}
</MenuItem>
)}
{overflowControls.has('screenShare') && (
{overflowControls.has(CollapsibleControls.SCREEN_SHARE) && (
<MenuItem
onAction={() => {
/* screen share requires track toggle, handled externally */
}}
onAction={() => screenShareProps.onClick?.({} as React.MouseEvent<HTMLButtonElement>)}
className={itemClass}
>
<RiArrowUpLine size={20} />
{t('controls.screenShare.start')}
{t(isScreenSharing ? 'controls.screenShare.stop' : 'controls.screenShare.start')}
</MenuItem>
)}
{overflowControls.has('subtitles') && areSubtitlesAvailable && (
{overflowControls.has(CollapsibleControls.SUBTITLES) && areSubtitlesAvailable && (
<MenuItem onAction={toggleSubtitles} className={itemClass}>
<RiClosedCaptioningLine size={20} />
{areSubtitlesOpen
@@ -63,7 +67,7 @@ export const PipOverflowItems = ({
: t('controls.subtitles.closed')}
</MenuItem>
)}
{overflowControls.has('hand') && (
{overflowControls.has(CollapsibleControls.HAND) && (
<MenuItem onAction={toggleRaisedHand} className={itemClass}>
<RiHand size={20} />
{isHandRaised ? t('controls.hand.lower') : t('controls.hand.raise')}