(frontend) hide decorative icons, label menus, avoid name duplicates

improves a11y by hiding decorative icons, labeling menus and deduping names

Signed-off-by: Cyril <c.gromoff@gmail.com>
This commit is contained in:
Cyril
2025-09-10 14:02:58 +02:00
parent 7a903041f8
commit ef08ba3a00
15 changed files with 86 additions and 14 deletions

View File

@@ -15,6 +15,7 @@ and this project adheres to
- #1349
- #1271
- #1341
- #1362
### Changed

View File

@@ -201,7 +201,7 @@ test.describe('Document create member', () => {
await page.getByLabel('Reader').click();
const moreActions = userInvitation.getByRole('button', {
name: 'more_horiz',
name: 'Open invitation actions menu',
});
await moreActions.click();

View File

@@ -227,6 +227,7 @@ export const DropdownMenu = ({
$theme="greyscale"
$variation={isDisabled ? '400' : '1000'}
iconName={option.icon}
aria-hidden="true"
/>
)}
<Text $variation={isDisabled ? '400' : '1000'}>
@@ -235,7 +236,12 @@ export const DropdownMenu = ({
</Box>
{(option.isSelected ||
selectedValues?.includes(option.value ?? '')) && (
<Icon iconName="check" $size="20px" $theme="greyscale" />
<Icon
iconName="check"
$size="20px"
$theme="greyscale"
aria-hidden="true"
/>
)}
</BoxButton>
{option.showSeparator && (

View File

@@ -250,8 +250,9 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
aria-label={t('Export the document')}
/>
)}
<DropdownMenu options={options}>
<DropdownMenu options={options} label={t('Open the document options')}>
<IconOptions
aria-hidden="true"
isHorizontal
$theme="primary"
$padding={{ all: 'xs' }}
@@ -267,7 +268,6 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
`
: ''}
`}
aria-label={t('Open the document options')}
/>
</DropdownMenu>
</Box>

View File

@@ -118,8 +118,9 @@ export const DocShareInvitationItem = ({
<DropdownMenu
data-testid="doc-share-invitation-more-actions"
options={moreActions}
label={t('Open invitation actions menu')}
>
<IconOptions isHorizontal $variation="600" />
<IconOptions isHorizontal $variation="600" aria-hidden="true" />
</DropdownMenu>
)}
</Box>
@@ -158,7 +159,12 @@ export const DocShareModalInviteUserRow = ({
<Text $theme="primary" $variation="800">
{t('Add')}
</Text>
<Icon $theme="primary" $variation="800" iconName="add" />
<Icon
$theme="primary"
$variation="800"
iconName="add"
aria-hidden="true"
/>
</Box>
}
/>

View File

@@ -155,6 +155,7 @@ export const DocTreeItemActions = ({
options={options}
isOpen={isOpen}
onOpenChange={onOpenChange}
aria-label={t('Open document actions menu')}
>
<Icon
onClick={(e) => {
@@ -166,6 +167,7 @@ export const DocTreeItemActions = ({
variant="filled"
$theme="primary"
$variation="600"
aria-hidden="true"
/>
</DropdownMenu>
{doc.abilities.children_create && (

View File

@@ -191,6 +191,7 @@ export const DraggableDocGridContentList = ({
data-testid="drag-doc-overlay"
$height="auto"
role="alert"
aria-label={t('Drag and drop status')}
>
<Text $size="xs" $variation="000" $weight="500">
{overlayText}

View File

@@ -100,7 +100,7 @@ export const DocsGrid = ({
)}
{hasDocs && (
<Box $gap="6px" $overflow="auto">
<Box role="grid">
<Box role="grid" aria-label={t('Documents grid')}>
<Box role="rowgroup">
<Box
$direction="row"

View File

@@ -83,19 +83,23 @@ export const DocsGridActions = ({
return (
<>
<DropdownMenu options={options} label={menuLabel}>
<DropdownMenu
options={options}
label={menuLabel}
aria-label={t('More options')}
>
<Icon
data-testid={`docs-grid-actions-button-${doc.id}`}
iconName="more_horiz"
$theme="primary"
$variation="600"
aria-label={t('More options')}
$css={css`
cursor: pointer;
&:hover {
opacity: 0.8;
}
`}
aria-hidden="true"
/>
</DropdownMenu>

View File

@@ -95,6 +95,11 @@ export const DocsGridItem = ({ doc, dragMode = false }: DocsGridItemProps) => {
$variation="600"
$size="14px"
iconName={isPublic ? 'public' : 'vpn_lock'}
aria-label={
isPublic
? t('Accessible to anyone')
: t('Accessible to authenticated users')
}
/>
)}
{!dragMode && (
@@ -114,6 +119,11 @@ export const DocsGridItem = ({ doc, dragMode = false }: DocsGridItemProps) => {
$variation="600"
$size="14px"
iconName={isPublic ? 'public' : 'vpn_lock'}
aria-label={
isPublic
? t('Accessible to anyone')
: t('Accessible to authenticated users')
}
/>
</div>
</Tooltip>

View File

@@ -33,7 +33,11 @@ export function HomeContent() {
const isFrLanguage = i18n.resolvedLanguage === 'fr';
return (
<Box as="main" className="--docs--home-content">
<Box
as="main"
className="--docs--home-content"
aria-label={t('Main content')}
>
<HomeHeader />
{isSmallMobile && (
<Box $css="& .--docs--left-panel-header{display: none;}">

View File

@@ -55,12 +55,16 @@ export const LanguagePicker = () => {
>
<Text
$theme="primary"
aria-label={t('Language')}
$direction="row"
$gap="0.5rem"
className="--docs--language-picker-text"
>
<Icon iconName="translate" $color="inherit" $size="xl" />
<Icon
iconName="translate"
$color="inherit"
$size="xl"
aria-hidden="true"
/>
{currentLanguageLabel}
</Text>
</DropdownMenu>

View File

@@ -371,6 +371,11 @@
"Open Source": "Open Source",
"Open the document options": "Öffnen Sie die Dokumentoptionen",
"Open the header menu": "Öffne das Kopfzeilen-Menü",
"Open document actions menu": "Dokumentaktionsmenü öffnen",
"Main content": "Hauptinhalt",
"Home content": "Startseiten-Inhalt",
"Documents grid": "Dokumentenraster",
"Drag and drop status": "Drag-and-Drop-Status",
"Organize": "Organisieren",
"Others are editing. Your network prevent changes.": "Ihre Änderung konnte nicht übernommen werden, da andere Benutzer diesen Bereich zurzeit bearbeiten.",
"Owner": "Besitzer",
@@ -458,6 +463,11 @@
"Document title": "Document title",
"Search docs": "Search docs",
"More options": "More options",
"Open document actions menu": "Open document actions menu",
"Main content": "Main content",
"Home content": "Home content",
"Documents grid": "Documents grid",
"Drag and drop status": "Drag and drop status",
"Pinned documents": "Pinned documents",
"Close the access request modal": "Close the access request modal",
"Close the delete modal": "Close the delete modal",
@@ -596,6 +606,11 @@
"Open Source": "Código abierto",
"Open the document options": "Abrir las opciones del documento",
"Open the header menu": "Abrir el menú de encabezado",
"Open document actions menu": "Abrir menú de acciones del documento",
"Main content": "Contenido principal",
"Home content": "Contenido de inicio",
"Documents grid": "Lista de documentos",
"Drag and drop status": "Estado de arrastrar y soltar",
"Organize": "Organiza",
"Owner": "Propietario",
"PDF": "PDF",
@@ -823,7 +838,12 @@
"Open Source": "Open Source",
"Open the document options": "Ouvrir les options du document",
"Open the header menu": "Ouvrir le menu d'en-tête",
"Open document actions menu": "Ouvrir le menu d'actions du document",
"Open the menu of actions for the document: {{title}}": "Ouvrir le menu des actions du document : {{title}}",
"Main content": "Contenu principal",
"Home content": "Contenu d'accueil",
"Documents grid": "Grille des documents",
"Drag and drop status": "État du glisser-déposer",
"Organize": "Organiser",
"Others are editing this document. Unfortunately your network blocks WebSockets, the technology enabling real-time co-editing.": "D'autres sont en train de modifier ce document. Malheureusement, votre réseau bloque les web sockets, la technologie permettant la coédition en temps réel.",
"Others are editing. Your network prevent changes.": "D'autres sont en cours d'édition. Votre réseau empêche les changements.",
@@ -1183,6 +1203,11 @@
"Open Source": "Open Source",
"Open the document options": "Open document opties",
"Open the header menu": "Open het hoofdmenu",
"Open document actions menu": "Open documentactiemenu",
"Main content": "Hoofdinhoud",
"Home content": "Startpagina-inhoud",
"Documents grid": "Documentenraster",
"Drag and drop status": "Slepen en neerzetten status",
"Organize": "Organiseer",
"Owner": "Eigenaar",
"PDF": "PDF",

View File

@@ -1,4 +1,5 @@
import { PropsWithChildren } from 'react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import { Box } from '@/components';
@@ -20,6 +21,7 @@ export function MainLayout({
const { isDesktop } = useResponsiveStore();
const { colorsTokens } = useCunninghamTheme();
const currentBackgroundColor = !isDesktop ? 'white' : backgroundColor;
const { t } = useTranslation();
return (
<Box className="--docs--main-layout">
@@ -32,6 +34,7 @@ export function MainLayout({
<LeftPanel />
<Box
as="main"
aria-label={t('Main content')}
id={MAIN_LAYOUT_ID}
$align="center"
$flex={1}

View File

@@ -1,4 +1,5 @@
import { PropsWithChildren } from 'react';
import { useTranslation } from 'react-i18next';
import { Box } from '@/components';
import { Footer } from '@/features/footer';
@@ -15,7 +16,7 @@ export function PageLayout({
withFooter = true,
}: PropsWithChildren<PageLayoutProps>) {
const { isDesktop } = useResponsiveStore();
const { t } = useTranslation();
return (
<Box
$minHeight={`calc(100vh - ${HEADER_HEIGHT}px)`}
@@ -23,7 +24,12 @@ export function PageLayout({
className="--docs--page-layout"
>
<Header />
<Box as="main" $width="100%" $css="flex-grow:1;">
<Box
as="main"
$width="100%"
$css="flex-grow:1;"
aria-label={t('Main content')}
>
{!isDesktop && <LeftPanel />}
{children}
</Box>