💄(frontend) condition shortcut helper display based on layout
restrict shortcut helper to first tile in grid layout only
This commit is contained in:
@@ -40,6 +40,7 @@ import {
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { getShortcutById } from '@/features/shortcuts/catalog'
|
||||
import { formatShortcutLabel } from '@/features/shortcuts/formatLabels'
|
||||
import { participantLayoutStore } from '@/stores/participantLayout'
|
||||
|
||||
export function TrackRefContextIfNeeded(
|
||||
props: React.PropsWithChildren<{
|
||||
@@ -126,6 +127,18 @@ export const ParticipantTile: (
|
||||
formatShortcutLabel(openShortcutEffective) ??
|
||||
`${isMacintosh() ? '⌘' : 'Ctrl'} + /`
|
||||
|
||||
// Check if we should show the shortcut helper tooltip
|
||||
// Only show on the first tile when in grid layout (not in carousel/left column, not in focus mode)
|
||||
const { layoutType, firstGridTileTrackId } = useSnapshot(participantLayoutStore)
|
||||
const currentTrackId = isTrackReference(trackReference)
|
||||
? `${trackReference.participant.sid}-${trackReference.source}`
|
||||
: null
|
||||
|
||||
const shouldShowShortcutHelper =
|
||||
hasKeyboardFocus &&
|
||||
layoutType === 'grid' && // Only show in grid layout
|
||||
currentTrackId === firstGridTileTrackId // Only show on first tile
|
||||
|
||||
const interactiveProps = {
|
||||
...elementProps,
|
||||
// Ensure the tile is focusable to expose contextual controls to keyboard users.
|
||||
@@ -245,12 +258,14 @@ export const ParticipantTile: (
|
||||
)}
|
||||
</ParticipantContextIfNeeded>
|
||||
</TrackRefContextIfNeeded>
|
||||
<ShortcutHelpTooltip
|
||||
triggerLabel={t('toolbarHint', {
|
||||
binding: openShortcutLabel,
|
||||
})}
|
||||
isVisible={hasKeyboardFocus}
|
||||
/>
|
||||
{shouldShowShortcutHelper && (
|
||||
<ShortcutHelpTooltip
|
||||
triggerLabel={t('toolbarHint', {
|
||||
binding: openShortcutLabel,
|
||||
})}
|
||||
isVisible={hasKeyboardFocus}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
@@ -48,7 +48,7 @@ const containerStyle = css({
|
||||
|
||||
const triggerStyle = css({
|
||||
all: 'unset',
|
||||
cursor: 'pointer',
|
||||
cursor: 'default',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
|
||||
@@ -3,6 +3,7 @@ import { getScrollBarWidth } from '@livekit/components-core'
|
||||
import * as React from 'react'
|
||||
import { TrackLoop, useVisualStableUpdate } from '@livekit/components-react'
|
||||
import { useSize } from '@/features/rooms/livekit/hooks/useResizeObserver'
|
||||
import { setCarouselLayout, resetLayout } from '@/stores/participantLayout'
|
||||
|
||||
const MIN_HEIGHT = 130
|
||||
const MIN_WIDTH = 140
|
||||
@@ -79,6 +80,15 @@ export function CarouselLayout({
|
||||
}
|
||||
}, [maxVisibleTiles, carouselOrientation])
|
||||
|
||||
// Update store when carousel layout is active
|
||||
React.useEffect(() => {
|
||||
setCarouselLayout()
|
||||
|
||||
return () => {
|
||||
resetLayout()
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<aside
|
||||
key={carouselOrientation}
|
||||
|
||||
@@ -10,6 +10,8 @@ import { mergeProps } from '@/utils/mergeProps'
|
||||
import { PaginationIndicator } from '../controls/PaginationIndicator'
|
||||
import { useGridLayout } from '../../hooks/useGridLayout'
|
||||
import { PaginationControl } from '../controls/PaginationControl'
|
||||
import { setGridLayout, resetLayout } from '@/stores/participantLayout'
|
||||
import { isTrackReference } from '@livekit/components-core'
|
||||
|
||||
/** @public */
|
||||
export interface GridLayoutProps
|
||||
@@ -35,6 +37,11 @@ export interface GridLayoutProps
|
||||
* ```
|
||||
* @public
|
||||
*/
|
||||
const getTrackId = (trackRef: TrackReferenceOrPlaceholder): string | null => {
|
||||
if (!isTrackReference(trackRef)) return null
|
||||
return `${trackRef.participant.sid}-${trackRef.source}`
|
||||
}
|
||||
|
||||
export function GridLayout({ tracks, ...props }: GridLayoutProps) {
|
||||
const gridEl = React.createRef<HTMLDivElement>()
|
||||
|
||||
@@ -50,6 +57,17 @@ export function GridLayout({ tracks, ...props }: GridLayoutProps) {
|
||||
onRightSwipe: pagination.prevPage,
|
||||
})
|
||||
|
||||
// Update store when tracks change - set first tile ID for grid layout
|
||||
React.useEffect(() => {
|
||||
const firstTrack = pagination.tracks[0]
|
||||
const firstTrackId = firstTrack ? getTrackId(firstTrack) : null
|
||||
setGridLayout(firstTrackId)
|
||||
|
||||
return () => {
|
||||
resetLayout()
|
||||
}
|
||||
}, [pagination.tracks])
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={gridEl}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { proxy } from 'valtio'
|
||||
|
||||
type LayoutType = 'grid' | 'carousel' | null
|
||||
|
||||
type State = {
|
||||
layoutType: LayoutType
|
||||
firstGridTileTrackId: string | null
|
||||
}
|
||||
|
||||
export const participantLayoutStore = proxy<State>({
|
||||
layoutType: null,
|
||||
firstGridTileTrackId: null,
|
||||
})
|
||||
|
||||
export const setGridLayout = (firstTrackId: string | null) => {
|
||||
participantLayoutStore.layoutType = 'grid'
|
||||
participantLayoutStore.firstGridTileTrackId = firstTrackId
|
||||
}
|
||||
|
||||
export const setCarouselLayout = () => {
|
||||
participantLayoutStore.layoutType = 'carousel'
|
||||
participantLayoutStore.firstGridTileTrackId = null
|
||||
}
|
||||
|
||||
export const resetLayout = () => {
|
||||
participantLayoutStore.layoutType = null
|
||||
participantLayoutStore.firstGridTileTrackId = null
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user