From ab54126414c37233b3299b62e1d147be5944c344 Mon Sep 17 00:00:00 2001 From: Pierre Ecarlat <pecarlat@grandlyon.com> Date: Wed, 11 Sep 2024 08:24:03 +0000 Subject: [PATCH] feat(a11y): Add a quick access link --- src/components/App.tsx | 32 +++++++++++++++------------ src/components/SkipLink/SkipLink.scss | 18 +++++++++++++++ src/components/SkipLink/SkipLink.tsx | 23 +++++++++++++++++++ src/components/Terms/CGUModal.tsx | 2 +- src/locales/fr.json | 3 ++- src/styles/base/_z-index.scss | 1 + 6 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 src/components/SkipLink/SkipLink.scss create mode 100644 src/components/SkipLink/SkipLink.tsx diff --git a/src/components/App.tsx b/src/components/App.tsx index d8bead7a2..21b8c485d 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -10,6 +10,7 @@ import { useLocation } from 'react-router-dom' import { useAppSelector } from 'store/hooks' import MatomoTracker from 'utils/matomoTracker' import usePageTitle from './Hooks/usePageTitle' +import SkipLink from './SkipLink/SkipLink' interface AppProps { tracker: undefined | MatomoTracker @@ -38,20 +39,23 @@ export const App = ({ tracker }: AppProps) => { }, [webviewIntent]) return ( - <Layout> - <SplashRoot> - {termsStatus.accepted && ( - <> - <WelcomeModal open={!onboarding.isWelcomeSeen} /> - <Navbar /> - </> - )} - <main className="app-content"> - <AppRoutes termsStatus={termsStatus} /> - </main> - </SplashRoot> - {process.env.NODE_ENV !== 'production' ? <CozyDevtools /> : null} - </Layout> + <> + <SkipLink /> + <Layout> + <SplashRoot> + {termsStatus.accepted && ( + <> + <WelcomeModal open={!onboarding.isWelcomeSeen} /> + <Navbar /> + </> + )} + <main id="app-content" className="app-content" tabIndex={-1}> + <AppRoutes termsStatus={termsStatus} /> + </main> + </SplashRoot> + {process.env.NODE_ENV !== 'production' ? <CozyDevtools /> : null} + </Layout> + </> ) } diff --git a/src/components/SkipLink/SkipLink.scss b/src/components/SkipLink/SkipLink.scss new file mode 100644 index 000000000..c893a4a3a --- /dev/null +++ b/src/components/SkipLink/SkipLink.scss @@ -0,0 +1,18 @@ +@import 'src/styles/base/color'; +@import 'src/styles/base/z-index'; + +.skip-link { + position: absolute; + top: -40px; + left: 0; + background: $dark; + color: $white; + border: $white; + padding: 8px; + z-index: $skip-link; + text-decoration: 'none'; + transition: top 0.3s; + &:focus { + top: 0; + } +} diff --git a/src/components/SkipLink/SkipLink.tsx b/src/components/SkipLink/SkipLink.tsx new file mode 100644 index 000000000..b00fb54e6 --- /dev/null +++ b/src/components/SkipLink/SkipLink.tsx @@ -0,0 +1,23 @@ +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import React from 'react' +import './SkipLink.scss' + +const SkipLink = () => { + const { t } = useI18n() + + const handleSkip = (event: React.MouseEvent<HTMLButtonElement>) => { + event.preventDefault() + const mainContent = document.getElementById('app-content') + if (mainContent) { + mainContent.focus() + } + } + + return ( + <button className="skip-link" onClick={handleSkip}> + {t('common.accessibility.skip_link')} + </button> + ) +} + +export default SkipLink diff --git a/src/components/Terms/CGUModal.tsx b/src/components/Terms/CGUModal.tsx index 5398cea05..8bd6c0cbb 100644 --- a/src/components/Terms/CGUModal.tsx +++ b/src/components/Terms/CGUModal.tsx @@ -1,11 +1,11 @@ import { Button } from '@material-ui/core' import Dialog from '@material-ui/core/Dialog' import CloseIcon from 'assets/icons/ico/close.svg' +import StyledIconButton from 'components/CommonKit/IconButton/StyledIconButton' import GCUContent from 'components/Options/GCU/GCUContent' import { useI18n } from 'cozy-ui/transpiled/react/I18n' import React from 'react' import './termsView.scss' -import StyledIconButton from 'components/CommonKit/IconButton/StyledIconButton' interface CGUModalProps { open: boolean diff --git a/src/locales/fr.json b/src/locales/fr.json index 389b6ee5d..727e662ac 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -22,7 +22,8 @@ "title_sge_connect": "Connexion à l'électricité", "title_gas_connect": "Connexion au gaz", "accessibility": { - "loading": "Chargement" + "loading": "Chargement", + "skip_link": "Aller au contenu" }, "funders_logo": "Logo des financeurs : Métropole de Lyon, Etat via la Banque des Territoires et son programme France 2030, Union Européenne" }, diff --git a/src/styles/base/_z-index.scss b/src/styles/base/_z-index.scss index 17a5dea8e..4fe88ba94 100644 --- a/src/styles/base/_z-index.scss +++ b/src/styles/base/_z-index.scss @@ -3,3 +3,4 @@ $z-pieChart: 5; $z-dialog: 10; $z-header: 18; $z-splash: 1500; +$skip-link: 1000001; -- GitLab