mirror of
https://github.com/suitenumerique/meet.git
synced 2026-07-26 11:58:53 +00:00
♻️(frontend) normalize PiP component patterns
Extract OverflowItems, replace `any`, convert function declarations to const arrows.
This commit is contained in:
@@ -30,10 +30,10 @@ const COLLAPSE_ORDER: CollapsibleControl[] = [
|
||||
const BUTTON_SLOT = 50
|
||||
const ESSENTIAL_WIDTH = 260
|
||||
|
||||
function getHiddenControls(
|
||||
const getHiddenControls = (
|
||||
containerWidth: number,
|
||||
showScreenShare: boolean
|
||||
): Set<CollapsibleControl> {
|
||||
): Set<CollapsibleControl> => {
|
||||
const hidden = new Set<CollapsibleControl>()
|
||||
if (containerWidth <= 0) return hidden
|
||||
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
import { Menu as RACMenu, MenuItem, MenuSection } from 'react-aria-components'
|
||||
import {
|
||||
RiHand,
|
||||
RiClosedCaptioningLine,
|
||||
RiArrowUpLine,
|
||||
RiEmotionLine,
|
||||
} from '@remixicon/react'
|
||||
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'
|
||||
@@ -12,12 +6,7 @@ import { EffectsMenuItem } from '@/features/rooms/livekit/components/controls/Op
|
||||
import { SupportMenuItem } from '@/features/rooms/livekit/components/controls/Options/SupportMenuItem'
|
||||
import { PictureInPictureMenuItem } from '@/features/rooms/livekit/components/controls/Options/PictureInPictureMenuItem'
|
||||
import { pipLayoutStore } from '@/features/pip/stores/pipLayoutStore'
|
||||
import { menuRecipe } from '@/primitives/menuRecipe'
|
||||
import { useRoomContext } 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 { PipOverflowItems } from './PipOverflowItems'
|
||||
import type { CollapsibleControl } from '../PipControlBar'
|
||||
|
||||
type PipOptionsMenuItemsProps = {
|
||||
@@ -40,7 +29,7 @@ export const PipOptionsMenuItems = ({
|
||||
{hasOverflow && (
|
||||
<>
|
||||
<MenuSection>
|
||||
<OverflowItems overflowControls={overflowControls} t={t} />
|
||||
<PipOverflowItems overflowControls={overflowControls} t={t} />
|
||||
</MenuSection>
|
||||
<Separator />
|
||||
</>
|
||||
@@ -57,60 +46,3 @@ export const PipOptionsMenuItems = ({
|
||||
</RACMenu>
|
||||
)
|
||||
}
|
||||
|
||||
const OverflowItems = ({
|
||||
overflowControls,
|
||||
t,
|
||||
}: {
|
||||
overflowControls: Set<CollapsibleControl>
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
t: any
|
||||
}) => {
|
||||
const room = useRoomContext()
|
||||
const { isHandRaised, toggleRaisedHand } = useRaisedHand({
|
||||
participant: room.localParticipant,
|
||||
})
|
||||
const { areSubtitlesOpen, toggleSubtitles } = useSubtitles()
|
||||
const areSubtitlesAvailable = useAreSubtitlesAvailable()
|
||||
const pipSnap = useSnapshot(pipLayoutStore)
|
||||
const toggleReactions = () => {
|
||||
pipLayoutStore.showReactionsToolbar = !pipSnap.showReactionsToolbar
|
||||
}
|
||||
const itemClass = menuRecipe({ icon: true, variant: 'dark' }).item
|
||||
|
||||
return (
|
||||
<>
|
||||
{overflowControls.has('reactions') && (
|
||||
<MenuItem onAction={toggleReactions} className={itemClass}>
|
||||
<RiEmotionLine size={20} />
|
||||
{t('controls.reactions.button')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{overflowControls.has('screenShare') && (
|
||||
<MenuItem
|
||||
onAction={() => {
|
||||
/* screen share requires track toggle, handled externally */
|
||||
}}
|
||||
className={itemClass}
|
||||
>
|
||||
<RiArrowUpLine size={20} />
|
||||
{t('controls.screenShare.start')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{overflowControls.has('subtitles') && areSubtitlesAvailable && (
|
||||
<MenuItem onAction={toggleSubtitles} className={itemClass}>
|
||||
<RiClosedCaptioningLine size={20} />
|
||||
{areSubtitlesOpen
|
||||
? t('controls.subtitles.open')
|
||||
: t('controls.subtitles.closed')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{overflowControls.has('hand') && (
|
||||
<MenuItem onAction={toggleRaisedHand} className={itemClass}>
|
||||
<RiHand size={20} />
|
||||
{isHandRaised ? t('controls.hand.lower') : t('controls.hand.raise')}
|
||||
</MenuItem>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import { MenuItem } from 'react-aria-components'
|
||||
import {
|
||||
RiHand,
|
||||
RiClosedCaptioningLine,
|
||||
RiArrowUpLine,
|
||||
RiEmotionLine,
|
||||
} from '@remixicon/react'
|
||||
import { TFunction } from 'i18next'
|
||||
import { pipLayoutStore } from '@/features/pip/stores/pipLayoutStore'
|
||||
import { menuRecipe } from '@/primitives/menuRecipe'
|
||||
import { useRoomContext } 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'
|
||||
|
||||
type PipOverflowItemsProps = {
|
||||
overflowControls: Set<CollapsibleControl>
|
||||
t: TFunction<'rooms'>
|
||||
}
|
||||
|
||||
export const PipOverflowItems = ({
|
||||
overflowControls,
|
||||
t,
|
||||
}: PipOverflowItemsProps) => {
|
||||
const room = useRoomContext()
|
||||
const { isHandRaised, toggleRaisedHand } = useRaisedHand({
|
||||
participant: room.localParticipant,
|
||||
})
|
||||
const { areSubtitlesOpen, toggleSubtitles } = useSubtitles()
|
||||
const areSubtitlesAvailable = useAreSubtitlesAvailable()
|
||||
const pipSnap = useSnapshot(pipLayoutStore)
|
||||
const toggleReactions = () => {
|
||||
pipLayoutStore.showReactionsToolbar = !pipSnap.showReactionsToolbar
|
||||
}
|
||||
const itemClass = menuRecipe({ icon: true, variant: 'dark' }).item
|
||||
|
||||
return (
|
||||
<>
|
||||
{overflowControls.has('reactions') && (
|
||||
<MenuItem onAction={toggleReactions} className={itemClass}>
|
||||
<RiEmotionLine size={20} />
|
||||
{t('controls.reactions.button')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{overflowControls.has('screenShare') && (
|
||||
<MenuItem
|
||||
onAction={() => {
|
||||
/* screen share requires track toggle, handled externally */
|
||||
}}
|
||||
className={itemClass}
|
||||
>
|
||||
<RiArrowUpLine size={20} />
|
||||
{t('controls.screenShare.start')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{overflowControls.has('subtitles') && areSubtitlesAvailable && (
|
||||
<MenuItem onAction={toggleSubtitles} className={itemClass}>
|
||||
<RiClosedCaptioningLine size={20} />
|
||||
{areSubtitlesOpen
|
||||
? t('controls.subtitles.open')
|
||||
: t('controls.subtitles.closed')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{overflowControls.has('hand') && (
|
||||
<MenuItem onAction={toggleRaisedHand} className={itemClass}>
|
||||
<RiHand size={20} />
|
||||
{isHandRaised ? t('controls.hand.lower') : t('controls.hand.raise')}
|
||||
</MenuItem>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -17,31 +17,31 @@ type PipFocusLayoutProps = {
|
||||
* above/below when the window shape doesn't match the source.
|
||||
* The thumbnail keeps the usual cover fill.
|
||||
*/
|
||||
export const PipFocusLayout = memo(function PipFocusLayout({
|
||||
mainTrack,
|
||||
thumbnailTrack,
|
||||
}: PipFocusLayoutProps) {
|
||||
return (
|
||||
<FocusContainer>
|
||||
<MainSlot>
|
||||
<ParticipantTile
|
||||
key={getTrackKey(mainTrack)}
|
||||
trackRef={mainTrack}
|
||||
disableMetadata
|
||||
/>
|
||||
</MainSlot>
|
||||
{thumbnailTrack && (
|
||||
<Thumbnail>
|
||||
export const PipFocusLayout = memo(
|
||||
({ mainTrack, thumbnailTrack }: PipFocusLayoutProps) => {
|
||||
return (
|
||||
<FocusContainer>
|
||||
<MainSlot>
|
||||
<ParticipantTile
|
||||
key={getTrackKey(thumbnailTrack)}
|
||||
trackRef={thumbnailTrack}
|
||||
key={getTrackKey(mainTrack)}
|
||||
trackRef={mainTrack}
|
||||
disableMetadata
|
||||
/>
|
||||
</Thumbnail>
|
||||
)}
|
||||
</FocusContainer>
|
||||
)
|
||||
})
|
||||
</MainSlot>
|
||||
{thumbnailTrack && (
|
||||
<Thumbnail>
|
||||
<ParticipantTile
|
||||
key={getTrackKey(thumbnailTrack)}
|
||||
trackRef={thumbnailTrack}
|
||||
disableMetadata
|
||||
/>
|
||||
</Thumbnail>
|
||||
)}
|
||||
</FocusContainer>
|
||||
)
|
||||
}
|
||||
)
|
||||
PipFocusLayout.displayName = 'PipFocusLayout'
|
||||
|
||||
const FocusContainer = styled('div', {
|
||||
base: {
|
||||
|
||||
@@ -21,9 +21,7 @@ type PipGridLayoutProps = {
|
||||
*
|
||||
* Tiles keep a stable key so resizing never remounts <video> elements.
|
||||
*/
|
||||
export const PipGridLayout = memo(function PipGridLayout({
|
||||
tracks,
|
||||
}: PipGridLayoutProps) {
|
||||
export const PipGridLayout = memo(({ tracks }: PipGridLayoutProps) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const { width, height } = usePipElementSize(containerRef)
|
||||
|
||||
@@ -54,6 +52,7 @@ export const PipGridLayout = memo(function PipGridLayout({
|
||||
</GridContainer>
|
||||
)
|
||||
})
|
||||
PipGridLayout.displayName = 'PipGridLayout'
|
||||
|
||||
const GridContainer = styled('div', {
|
||||
base: {
|
||||
|
||||
Reference in New Issue
Block a user