✨(frontend) introduce a menu with more actions
Replaced the existing settings button with a new `OptionsButton` component. This new component integrates a menu for more actions, providing an extensible and accessible interface. Refactoring will follow to enhance code maintainability. A legacy style was introduced to keep visual coherence with the other controls from the controls bar. It's temporary, until we redesign the whole bar. It doesn't match pixel-perfect the legacy styles. A new public Tchap chan was created. All users, and not only beta users, can now join it using the link in the menu, and reach us.
This commit is contained in:
committed by
aleb_the_flash
parent
8c7aed4b00
commit
1715ec10dd
@@ -0,0 +1,22 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiMore2Line } from '@remixicon/react'
|
||||
import { Button } from '@/primitives'
|
||||
import { OptionsMenu } from '@/features/rooms/livekit/components/controls/Options/OptionsMenu.tsx'
|
||||
import { MenuTrigger } from 'react-aria-components'
|
||||
|
||||
export const OptionsButton = () => {
|
||||
const { t } = useTranslation('rooms')
|
||||
return (
|
||||
<MenuTrigger>
|
||||
<Button
|
||||
square
|
||||
legacyStyle
|
||||
aria-label={t('options.buttonLabel')}
|
||||
tooltip={t('options.buttonLabel')}
|
||||
>
|
||||
<RiMore2Line />
|
||||
</Button>
|
||||
<OptionsMenu />
|
||||
</MenuTrigger>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
RiFeedbackLine,
|
||||
RiQuestionLine,
|
||||
RiSettings3Line,
|
||||
} from '@remixicon/react'
|
||||
import { styled } from '@/styled-system/jsx'
|
||||
import {
|
||||
Menu as RACMenu,
|
||||
MenuItem as RACMenuItem,
|
||||
Popover as RACPopover,
|
||||
} from 'react-aria-components'
|
||||
|
||||
// Styled components to be refactored
|
||||
const StyledMenu = styled(RACMenu, {
|
||||
base: {
|
||||
maxHeight: 'inherit',
|
||||
boxSizing: 'border-box',
|
||||
overflow: 'auto',
|
||||
padding: '2px',
|
||||
minWidth: '150px',
|
||||
outline: 'none',
|
||||
},
|
||||
})
|
||||
|
||||
const StyledMenuItem = styled(RACMenuItem, {
|
||||
base: {
|
||||
margin: '2px',
|
||||
padding: '0.286rem 0.571rem',
|
||||
borderRadius: '6px',
|
||||
outline: 'none',
|
||||
cursor: 'default',
|
||||
color: 'black',
|
||||
fontSize: '1.072rem',
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '20px',
|
||||
forcedColorAdjust: 'none',
|
||||
'&[data-focused]': {
|
||||
color: 'primary.text',
|
||||
backgroundColor: 'primary',
|
||||
outline: 'none!',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const StyledPopover = styled(RACPopover, {
|
||||
base: {
|
||||
border: '1px solid #9ca3af',
|
||||
boxShadow: '0 8px 20px rgba(0, 0, 0, 0.1)',
|
||||
borderRadius: '4px',
|
||||
background: 'white',
|
||||
color: 'var(--text-color)',
|
||||
outline: 'none',
|
||||
minWidth: '112px',
|
||||
width: '300px',
|
||||
},
|
||||
})
|
||||
|
||||
export const OptionsMenu = () => {
|
||||
const { t } = useTranslation('rooms')
|
||||
|
||||
return (
|
||||
<StyledPopover>
|
||||
<StyledMenu>
|
||||
<StyledMenuItem
|
||||
href="https://tchap.gouv.fr/#/room/!aGImQayAgBLjSBycpm:agent.dinum.tchap.gouv.fr?via=agent.dinum.tchap.gouv.fr"
|
||||
target="_blank"
|
||||
>
|
||||
<RiQuestionLine size={18} />
|
||||
{t('options.items.support')}
|
||||
</StyledMenuItem>
|
||||
<StyledMenuItem
|
||||
href="https://grist.incubateur.net/o/docs/forms/1YrfNP1QSSy8p2gCxMFnSf/4"
|
||||
target="_blank"
|
||||
>
|
||||
<RiFeedbackLine size={18} />
|
||||
{t('options.items.feedbacks')}
|
||||
</StyledMenuItem>
|
||||
<StyledMenuItem onAction={() => alert('delete')}>
|
||||
<RiSettings3Line size={18} />
|
||||
{t('options.items.settings')}
|
||||
</StyledMenuItem>
|
||||
</StyledMenu>
|
||||
</StyledPopover>
|
||||
)
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
import * as React from 'react'
|
||||
import { useLayoutContext } from '@livekit/components-react'
|
||||
import { mergeProps } from '@/utils/mergeProps'
|
||||
|
||||
/** @alpha */
|
||||
export interface UseSettingsToggleProps {
|
||||
props: React.ButtonHTMLAttributes<HTMLButtonElement>
|
||||
}
|
||||
|
||||
/**
|
||||
* The `useSettingsToggle` hook provides state and functions for toggling the settings menu.
|
||||
* @remarks
|
||||
* Depends on the `LayoutContext` to work properly.
|
||||
* @see {@link SettingsMenu}
|
||||
* @alpha
|
||||
*/
|
||||
export function useSettingsToggle({ props }: UseSettingsToggleProps) {
|
||||
const { dispatch, state } = useLayoutContext().widget
|
||||
const className = 'lk-button lk-settings-toggle'
|
||||
|
||||
const mergedProps = React.useMemo(() => {
|
||||
return mergeProps(props, {
|
||||
className,
|
||||
onClick: () => {
|
||||
if (dispatch) dispatch({ msg: 'toggle_settings' })
|
||||
},
|
||||
'aria-pressed': state?.showSettings ? 'true' : 'false',
|
||||
})
|
||||
}, [props, className, dispatch, state])
|
||||
|
||||
return { mergedProps }
|
||||
}
|
||||
|
||||
/** @alpha */
|
||||
export interface SettingsMenuToggleProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement> {}
|
||||
|
||||
/**
|
||||
* The `SettingsMenuToggle` component is a button that toggles the visibility of the `SettingsMenu` component.
|
||||
* @remarks
|
||||
* For the component to have any effect it has to live inside a `LayoutContext` context.
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
export const SettingsMenuToggle: (
|
||||
props: SettingsMenuToggleProps & React.RefAttributes<HTMLButtonElement>
|
||||
) => React.ReactNode = /* @__PURE__ */ React.forwardRef<
|
||||
HTMLButtonElement,
|
||||
SettingsMenuToggleProps
|
||||
>(function SettingsMenuToggle(props: SettingsMenuToggleProps, ref) {
|
||||
const { mergedProps } = useSettingsToggle({ props })
|
||||
|
||||
return (
|
||||
<button ref={ref} {...mergedProps}>
|
||||
{props.children}
|
||||
</button>
|
||||
)
|
||||
})
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
ChatIcon,
|
||||
ChatToggle,
|
||||
DisconnectButton,
|
||||
GearIcon,
|
||||
LeaveIcon,
|
||||
MediaDeviceMenu,
|
||||
TrackToggle,
|
||||
@@ -15,12 +14,11 @@ import {
|
||||
usePersistentUserChoices,
|
||||
} from '@livekit/components-react'
|
||||
|
||||
import { SettingsMenuToggle } from '../components/controls/SettingsMenuToggle'
|
||||
import { mergeProps } from '@/utils/mergeProps.ts'
|
||||
import { StartMediaButton } from '../components/controls/StartMediaButton'
|
||||
import { useMediaQuery } from '../hooks/useMediaQuery'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { SettingsButton } from '@/features/settings'
|
||||
import { OptionsButton } from '../components/controls/Options/OptionsButton'
|
||||
|
||||
/** @public */
|
||||
export type ControlBarControls = {
|
||||
@@ -189,10 +187,7 @@ export function ControlBar({
|
||||
{showIcon && <ChatIcon />}
|
||||
{showText && t('controls.chat')}
|
||||
</ChatToggle>
|
||||
<SettingsMenuToggle>
|
||||
{showIcon && <GearIcon />}
|
||||
{showText && t('controls.settings')}
|
||||
</SettingsMenuToggle>
|
||||
<OptionsButton />
|
||||
<DisconnectButton>
|
||||
{showIcon && <LeaveIcon />}
|
||||
{showText && t('controls.leave')}
|
||||
|
||||
@@ -187,14 +187,6 @@ export function VideoConference({
|
||||
messageEncoder={chatMessageEncoder}
|
||||
messageDecoder={chatMessageDecoder}
|
||||
/>
|
||||
{SettingsComponent && (
|
||||
<div
|
||||
className="lk-settings-menu-modal"
|
||||
style={{ display: widgetState.showSettings ? 'block' : 'none' }}
|
||||
>
|
||||
<SettingsComponent />
|
||||
</div>
|
||||
)}
|
||||
</LayoutContextProvider>
|
||||
)}
|
||||
<RoomAudioRenderer />
|
||||
|
||||
@@ -29,7 +29,14 @@
|
||||
"shareScreen": "",
|
||||
"stopScreenShare": "",
|
||||
"chat": "",
|
||||
"settings": "",
|
||||
"leave": ""
|
||||
},
|
||||
"options": {
|
||||
"buttonLabel": "",
|
||||
"items": {
|
||||
"feedbacks": "",
|
||||
"support": "",
|
||||
"settings": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,14 @@
|
||||
"shareScreen": "Share screen",
|
||||
"stopScreenShare": "Stop screen share",
|
||||
"chat": "Chat",
|
||||
"settings": "Settings",
|
||||
"leave": "Leave"
|
||||
},
|
||||
"options": {
|
||||
"buttonLabel": "More Options",
|
||||
"items": {
|
||||
"feedbacks": "Give us feedbacks",
|
||||
"support": "Get Help on Tchap",
|
||||
"settings": "Settings"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,14 @@
|
||||
"shareScreen": "Partager l'écran",
|
||||
"stopScreenShare": "Arrêter le partage",
|
||||
"chat": "Chat",
|
||||
"settings": "Paramètres",
|
||||
"leave": "Quitter"
|
||||
},
|
||||
"options": {
|
||||
"buttonLabel": "Plus d'options",
|
||||
"items": {
|
||||
"feedbacks": "Partager votre avis",
|
||||
"support": "Obtenir de l'aide sur Tchap",
|
||||
"settings": "Paramètres"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,17 @@ const button = cva({
|
||||
width: 'full',
|
||||
},
|
||||
},
|
||||
legacyStyle: {
|
||||
true: {
|
||||
borderColor: 'gray.400',
|
||||
'&[data-hovered]': {
|
||||
borderColor: 'gray.500',
|
||||
},
|
||||
'&[data-pressed]': {
|
||||
borderColor: 'gray.500',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
size: 'default',
|
||||
|
||||
Reference in New Issue
Block a user