🚸(frontend) add shortcut indication on doc option

For users to know the keyboard shortcut for opening
the presenter mode, we add a visual indication of the
shortcut in the doc option menu.
This commit is contained in:
Anthony LC
2026-09-21 14:16:29 +02:00
parent 441ddfbd7e
commit 74d822bb27
5 changed files with 65 additions and 11 deletions
+1
View File
@@ -13,6 +13,7 @@ and this project adheres to
- 🐛(frontend) reduce PostHog volume from web vitals and opt_in spam #2701
- ✨(backend) expose the attachment max size in the config endpoint #2577
- ✨(frontend) warn before uploading an attachment over the size limit #2577
- ✨(frontend) add keyboard shortcut to open presentation mode #2697
### Fixed
@@ -12,8 +12,10 @@ import {
const openPresenter = async (page: Page) => {
await page.getByLabel('Open the document options').first().click();
await page.getByRole('menuitem', { name: 'Present' }).click();
await page
.getByRole('menuitem')
.getByText(/Present/)
.click();
const overlay = page.getByRole('dialog', { name: 'Presenter mode' });
await expect(overlay).toBeVisible();
return overlay;
@@ -445,7 +445,10 @@ export const clickInEditorShareButton = async (page: Page) => {
.click();
};
export const clickInEditorMenu = async (page: Page, textButton: string) => {
export const clickInEditorMenu = async (
page: Page,
textButton: string | RegExp,
) => {
await clickInDocOptionMenu(
page,
page.getByTestId('floating-bar'),
@@ -456,7 +459,7 @@ export const clickInEditorMenu = async (page: Page, textButton: string) => {
export const clickInDocOptionMenu = async (
page: Page,
selector: Locator,
textButton: string,
textButton: string | RegExp,
) => {
await selector
.getByRole('button', { name: /Open the document options/ })
@@ -3,14 +3,17 @@ import {
ButtonProps,
DropdownMenu,
DropdownMenuItem,
DropdownMenuOption,
MenuItemSeparator,
} from '@gouvfr-lasuite/ui-components';
import { Present } from '@gouvfr-lasuite/ui-components/icons';
import { announce } from '@react-aria/live-announcer';
import dynamic from 'next/dynamic';
import { useRouter } from 'next/router';
import { memo, useEffect, useMemo, useState } from 'react';
import { ReactNode, memo, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Box } from '@/components/Box';
import { Text } from '@/components/Text';
import { useEditorStore } from '@/docs/doc-editor/stores/useEditorStore';
import { getWordCount } from '@/docs/doc-editor/utils';
@@ -37,6 +40,7 @@ import StarSlashIcon from '@/icons/star-slash.svg';
import StarIcon from '@/icons/star.svg';
import DeleteIcon from '@/icons/trash.svg';
import { useFocusStore, useResponsiveStore } from '@/stores';
import { isMacOS } from '@/utils/userAgent';
import {
KEY_DOC,
@@ -108,6 +112,18 @@ const ModalExport = dynamic(
{ ssr: false },
);
/**
* We widen the type of `DropdownMenuOption.label` to accept
* `ReactNode` instead of just `string`.
* @todo Widen the label type in the ui-kit package itself.
* This is a temporary workaround until the ui-kit package is updated.
*/
type MenuOptionWithNodeLabel = Omit<DropdownMenuOption, 'label'> & {
label: ReactNode;
};
type DropdownMenuItemWithNodeLabel =
MenuOptionWithNodeLabel | MenuItemSeparator;
interface DocToolBoxProps {
doc: Doc;
isCurrentDoc: boolean;
@@ -176,7 +192,7 @@ const DocToolBoxComponent = ({
listInvalidQueries: [KEY_LIST_DOC, KEY_DOC, KEY_LIST_FAVORITE_DOC],
});
const options: DropdownMenuItem[] = [
const options: DropdownMenuItemWithNodeLabel[] = [
{
label: t('Copy link', {
description: 'Dropdown menu item to copy the document link',
@@ -199,10 +215,38 @@ const DocToolBoxComponent = ({
showSeparator: isCurrentDoc,
},
{
label: t('Present', {
description:
'Dropdown menu item to open the document in presentation mode',
}),
label: (
<Box $direction="row" $gap="xxs">
<Text>
{t('Present', {
description:
'Dropdown menu item to open the document in presentation mode',
})}
</Text>
<Text
$variation="tertiary"
$size="xs"
$css={`
opacity: 0;
transition: opacity 0.2s;
.c__dropdown-menu-item:hover &,
.c__dropdown-menu-item[data-focused] & {
opacity: 1;
}
`}
>
{isMacOS
? t('Cmd+Alt+P', {
description:
'Dropdown menu item to open the document in presentation mode, macOS shortcut',
})
: t('Ctrl+Alt+P', {
description:
'Dropdown menu item to open the document in presentation mode, Windows/Linux shortcut',
})}
</Text>
</Box>
),
icon: <Present width={18} height={18} aria-hidden="true" />,
callback: () => {
openPresenter(0);
@@ -347,7 +391,7 @@ const DocToolBoxComponent = ({
return (
<>
<DropdownMenu
options={optionsDefault ?? options}
options={(optionsDefault ?? options) as DropdownMenuItem[]}
isOpen={openDropdown}
shouldCloseOnInteractOutside={() => true}
onOpenChange={(isOpen) => {
@@ -1,2 +1,6 @@
export const isFirefox = () =>
navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
export const isMacOS =
typeof navigator !== 'undefined' &&
/Mac|iPhone|iPad|iPod/.test(navigator.platform || navigator.userAgent);