diff --git a/src/frontend/src/features/pip/components/PipControlBar.tsx b/src/frontend/src/features/pip/components/PipControlBar.tsx index 2a4e9b1d..ff9756f1 100644 --- a/src/frontend/src/features/pip/components/PipControlBar.tsx +++ b/src/frontend/src/features/pip/components/PipControlBar.tsx @@ -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 { +): Set => { const hidden = new Set() if (containerWidth <= 0) return hidden diff --git a/src/frontend/src/features/pip/components/controls/PipOptionsMenuItems.tsx b/src/frontend/src/features/pip/components/controls/PipOptionsMenuItems.tsx index e6b4a40e..3d41e2bf 100644 --- a/src/frontend/src/features/pip/components/controls/PipOptionsMenuItems.tsx +++ b/src/frontend/src/features/pip/components/controls/PipOptionsMenuItems.tsx @@ -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 && ( <> - + @@ -57,60 +46,3 @@ export const PipOptionsMenuItems = ({ ) } - -const OverflowItems = ({ - overflowControls, - t, -}: { - overflowControls: Set - // 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') && ( - - - {t('controls.reactions.button')} - - )} - {overflowControls.has('screenShare') && ( - { - /* screen share requires track toggle, handled externally */ - }} - className={itemClass} - > - - {t('controls.screenShare.start')} - - )} - {overflowControls.has('subtitles') && areSubtitlesAvailable && ( - - - {areSubtitlesOpen - ? t('controls.subtitles.open') - : t('controls.subtitles.closed')} - - )} - {overflowControls.has('hand') && ( - - - {isHandRaised ? t('controls.hand.lower') : t('controls.hand.raise')} - - )} - - ) -} diff --git a/src/frontend/src/features/pip/components/controls/PipOverflowItems.tsx b/src/frontend/src/features/pip/components/controls/PipOverflowItems.tsx new file mode 100644 index 00000000..40f16dcb --- /dev/null +++ b/src/frontend/src/features/pip/components/controls/PipOverflowItems.tsx @@ -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 + 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') && ( + + + {t('controls.reactions.button')} + + )} + {overflowControls.has('screenShare') && ( + { + /* screen share requires track toggle, handled externally */ + }} + className={itemClass} + > + + {t('controls.screenShare.start')} + + )} + {overflowControls.has('subtitles') && areSubtitlesAvailable && ( + + + {areSubtitlesOpen + ? t('controls.subtitles.open') + : t('controls.subtitles.closed')} + + )} + {overflowControls.has('hand') && ( + + + {isHandRaised ? t('controls.hand.lower') : t('controls.hand.raise')} + + )} + + ) +} diff --git a/src/frontend/src/features/pip/components/layouts/PipFocusLayout.tsx b/src/frontend/src/features/pip/components/layouts/PipFocusLayout.tsx index 5cd54202..198a064a 100644 --- a/src/frontend/src/features/pip/components/layouts/PipFocusLayout.tsx +++ b/src/frontend/src/features/pip/components/layouts/PipFocusLayout.tsx @@ -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 ( - - - - - {thumbnailTrack && ( - +export const PipFocusLayout = memo( + ({ mainTrack, thumbnailTrack }: PipFocusLayoutProps) => { + return ( + + - - )} - - ) -}) + + {thumbnailTrack && ( + + + + )} + + ) + } +) +PipFocusLayout.displayName = 'PipFocusLayout' const FocusContainer = styled('div', { base: { diff --git a/src/frontend/src/features/pip/components/layouts/PipGridLayout.tsx b/src/frontend/src/features/pip/components/layouts/PipGridLayout.tsx index 1c0080bb..77ccc2b4 100644 --- a/src/frontend/src/features/pip/components/layouts/PipGridLayout.tsx +++ b/src/frontend/src/features/pip/components/layouts/PipGridLayout.tsx @@ -21,9 +21,7 @@ type PipGridLayoutProps = { * * Tiles keep a stable key so resizing never remounts