♻️(frontend) refactor options menu
@manuhabitela introduced Menu and MenuTrigger components. Refactor the options menu to benefits from his components. Few details are not perfect yet. wip
This commit is contained in:
committed by
aleb_the_flash
parent
5b8c8d493a
commit
03b3630611
@@ -1,22 +1,38 @@
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { RiMore2Line } from '@remixicon/react'
|
import { RiMore2Line } from '@remixicon/react'
|
||||||
import { Button } from '@/primitives'
|
import { Button, Menu } from '@/primitives'
|
||||||
import { OptionsMenu } from '@/features/rooms/livekit/components/controls/Options/OptionsMenu.tsx'
|
|
||||||
import { MenuTrigger } from 'react-aria-components'
|
import { useState } from 'react'
|
||||||
|
import { UsernameDialog } from '@/features/rooms/livekit/components/dialogs/UsernameDialog'
|
||||||
|
import { SettingsDialog } from '@/features/settings'
|
||||||
|
import { OptionsMenuItems } from '@/features/rooms/livekit/components/controls/Options/OptionsMenuItems'
|
||||||
|
|
||||||
|
export type DialogState = 'username' | 'settings' | null
|
||||||
|
|
||||||
export const OptionsButton = () => {
|
export const OptionsButton = () => {
|
||||||
const { t } = useTranslation('rooms')
|
const { t } = useTranslation('rooms')
|
||||||
|
const [dialogOpen, setDialogOpen] = useState<DialogState>(null)
|
||||||
return (
|
return (
|
||||||
<MenuTrigger>
|
<>
|
||||||
<Button
|
<Menu>
|
||||||
square
|
<Button
|
||||||
legacyStyle
|
square
|
||||||
aria-label={t('options.buttonLabel')}
|
legacyStyle
|
||||||
tooltip={t('options.buttonLabel')}
|
aria-label={t('options.buttonLabel')}
|
||||||
>
|
tooltip={t('options.buttonLabel')}
|
||||||
<RiMore2Line />
|
>
|
||||||
</Button>
|
<RiMore2Line />
|
||||||
<OptionsMenu />
|
</Button>
|
||||||
</MenuTrigger>
|
<OptionsMenuItems onOpenDialog={setDialogOpen} />
|
||||||
|
</Menu>
|
||||||
|
<UsernameDialog
|
||||||
|
isOpen={dialogOpen === 'username'}
|
||||||
|
onOpenChange={(v) => !v && setDialogOpen(null)}
|
||||||
|
/>
|
||||||
|
<SettingsDialog
|
||||||
|
isOpen={dialogOpen === 'settings'}
|
||||||
|
onOpenChange={(v) => !v && setDialogOpen(null)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,118 +0,0 @@
|
|||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import {
|
|
||||||
RiFeedbackLine,
|
|
||||||
RiQuestionLine,
|
|
||||||
RiSettings3Line,
|
|
||||||
RiUser5Line,
|
|
||||||
} from '@remixicon/react'
|
|
||||||
import { useState } from 'react'
|
|
||||||
import { styled } from '@/styled-system/jsx'
|
|
||||||
import {
|
|
||||||
Menu as RACMenu,
|
|
||||||
MenuItem as RACMenuItem,
|
|
||||||
Popover as RACPopover,
|
|
||||||
Separator as RACSeparator,
|
|
||||||
} from 'react-aria-components'
|
|
||||||
import { SettingsDialog } from '@/features/settings'
|
|
||||||
import { UsernameDialog } from '../../dialogs/UsernameDialog'
|
|
||||||
|
|
||||||
// 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',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const StyledSeparator = styled(RACSeparator, {
|
|
||||||
base: {
|
|
||||||
height: '1px',
|
|
||||||
background: '#9ca3af',
|
|
||||||
margin: '2px 4px',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
type DialogState = 'username' | 'settings' | null
|
|
||||||
|
|
||||||
export const OptionsMenu = () => {
|
|
||||||
const { t } = useTranslation('rooms')
|
|
||||||
const [dialogOpen, setDialogOpen] = useState<DialogState>(null)
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<StyledPopover>
|
|
||||||
<StyledMenu>
|
|
||||||
<StyledMenuItem onAction={() => setDialogOpen('username')}>
|
|
||||||
<RiUser5Line size={18} />
|
|
||||||
{t('options.items.username')}
|
|
||||||
</StyledMenuItem>
|
|
||||||
<StyledSeparator />
|
|
||||||
<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={() => setDialogOpen('settings')}>
|
|
||||||
<RiSettings3Line size={18} />
|
|
||||||
{t('options.items.settings')}
|
|
||||||
</StyledMenuItem>
|
|
||||||
</StyledMenu>
|
|
||||||
</StyledPopover>
|
|
||||||
<UsernameDialog
|
|
||||||
isOpen={dialogOpen === 'username'}
|
|
||||||
onOpenChange={(v) => !v && setDialogOpen(null)}
|
|
||||||
/>
|
|
||||||
<SettingsDialog
|
|
||||||
isOpen={dialogOpen === 'settings'}
|
|
||||||
onOpenChange={(v) => !v && setDialogOpen(null)}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import { menuItemRecipe } from '@/primitives/menuItemRecipe'
|
||||||
|
import {
|
||||||
|
RiFeedbackLine,
|
||||||
|
RiQuestionLine,
|
||||||
|
RiSettings3Line,
|
||||||
|
RiUser5Line,
|
||||||
|
} from '@remixicon/react'
|
||||||
|
import { styled } from '@/styled-system/jsx'
|
||||||
|
import {
|
||||||
|
MenuItem,
|
||||||
|
Menu as RACMenu,
|
||||||
|
Separator as RACSeparator,
|
||||||
|
} from 'react-aria-components'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { Dispatch, SetStateAction } from 'react'
|
||||||
|
import { DialogState } from '@/features/rooms/livekit/components/controls/Options/OptionsButton'
|
||||||
|
|
||||||
|
const StyledSeparator = styled(RACSeparator, {
|
||||||
|
base: {
|
||||||
|
height: '1px',
|
||||||
|
background: 'gray.300',
|
||||||
|
margin: '4px 0',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// @todo try refactoring it to use MenuList component
|
||||||
|
export const OptionsMenuItems = ({
|
||||||
|
onOpenDialog,
|
||||||
|
}: {
|
||||||
|
onOpenDialog: Dispatch<SetStateAction<DialogState>>
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation('rooms')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RACMenu
|
||||||
|
style={{
|
||||||
|
minWidth: '150px',
|
||||||
|
width: '300px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MenuItem
|
||||||
|
className={menuItemRecipe({ icon: true })}
|
||||||
|
onAction={() => onOpenDialog('username')}
|
||||||
|
>
|
||||||
|
<RiUser5Line size={18} />
|
||||||
|
{t('options.items.username')}
|
||||||
|
</MenuItem>
|
||||||
|
<StyledSeparator />
|
||||||
|
<MenuItem
|
||||||
|
href="https://tchap.gouv.fr/#/room/!aGImQayAgBLjSBycpm:agent.dinum.tchap.gouv.fr?via=agent.dinum.tchap.gouv.fr"
|
||||||
|
target="_blank"
|
||||||
|
className={menuItemRecipe({ icon: true })}
|
||||||
|
>
|
||||||
|
<RiQuestionLine size={18} />
|
||||||
|
{t('options.items.support')}
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
href="https://grist.incubateur.net/o/docs/forms/1YrfNP1QSSy8p2gCxMFnSf/4"
|
||||||
|
target="_blank"
|
||||||
|
className={menuItemRecipe({ icon: true })}
|
||||||
|
>
|
||||||
|
<RiFeedbackLine size={18} />
|
||||||
|
{t('options.items.feedbacks')}
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
className={menuItemRecipe({ icon: true })}
|
||||||
|
onAction={() => onOpenDialog('settings')}
|
||||||
|
>
|
||||||
|
<RiSettings3Line size={18} />
|
||||||
|
{t('options.items.settings')}
|
||||||
|
</MenuItem>
|
||||||
|
</RACMenu>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -8,9 +8,8 @@ import { cva } from '@/styled-system/css'
|
|||||||
*/
|
*/
|
||||||
export const menuItemRecipe = cva({
|
export const menuItemRecipe = cva({
|
||||||
base: {
|
base: {
|
||||||
paddingY: 0.125,
|
paddingY: '0.4rem',
|
||||||
paddingX: 0.5,
|
paddingX: 0.5,
|
||||||
paddingLeft: 1.5,
|
|
||||||
textAlign: 'left',
|
textAlign: 'left',
|
||||||
width: 'full',
|
width: 'full',
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
@@ -37,4 +36,13 @@ export const menuItemRecipe = cva({
|
|||||||
outline: 'none!',
|
outline: 'none!',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
variants: {
|
||||||
|
icon: {
|
||||||
|
true: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '1rem',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user