Skip to content

Commit

Permalink
Merge pull request #77 from FaberVitale/fix/a11y-fixes
Browse files Browse the repository at this point in the history
Fix/a11y fixes
  • Loading branch information
FaberVitale authored Jul 11, 2024
2 parents 436b262 + beebd82 commit 9cfcbdc
Show file tree
Hide file tree
Showing 27 changed files with 191 additions and 28 deletions.
8 changes: 7 additions & 1 deletion public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,11 @@
"ctaVenue": "Venue",
"prevPage": "Previous page",
"nextPage": "Next page",
"venue": "Venue"
"venue": "Venue",
"openMenu": "Open menu",
"closeMenu": "Close menu",
"mainSiteNav": "Main site navigation",
"itWebsite": "Italian website",
"enWebsite": "English website",
"skipToMainContent": "Skip to main content"
}
8 changes: 7 additions & 1 deletion public/locales/it/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,11 @@
"ctaVenue": "Scopri la location",
"prevPage": "Pagina precedente",
"nextPage": "Prossima pagina",
"venue": "Location"
"venue": "Location",
"openMenu": "Apri il menu",
"closeMenu": "Chiudi il menu",
"mainSiteNav": "Links del sito",
"itWebsite": "Sito in Italiano",
"enWebsite": "Sito in Inglese",
"skipToMainContent": "Vai al contenuto principale"
}
1 change: 1 addition & 0 deletions src/@types/hp.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface HpSection {
body: string[];
cta?: Link;
venue?: Link;
startDate?: { dateTime: string; label: string };
}

export interface HpContent {
Expand Down
1 change: 1 addition & 0 deletions src/components/BrandLogo/BrandLogo.astro
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const props = Astro.props;
fill="none"
xmlns="http://www.w3.org/2000/svg"
transition:name="logo"
aria-hidden="true"
>
<path
d="M223.955 0.271484H0.407227V223.819H223.955V0.271484Z"
Expand Down
11 changes: 9 additions & 2 deletions src/components/EventsList/components/PlaceholderEvent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,28 @@ import styles from '../styles.module.scss';
import { formatDate } from '@i18n/date-time';
import { CFPCta } from '@components/CFPCta/CFPCta';
import type { JSX } from 'solid-js/jsx-runtime';
import { Dynamic } from 'solid-js/web';

export interface PlaceholderEventProps {
date: Date;
lang: Lang;
heading?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
}

const defaultHeading: NonNullable<PlaceholderEventProps['heading']> = 'h2';

export function PlaceholderEvent(props: PlaceholderEventProps): JSX.Element {
return (
<section class={styles.event}>
<time datetime={props.date.toISOString()}>
{formatDate(props.lang, props.date)}
</time>
<h3 class={styles.eventHeading}>
<Dynamic
component={props.heading ?? defaultHeading}
class={styles.eventHeading}
>
TBD <CFPCta />
</h3>
</Dynamic>
</section>
);
}
11 changes: 9 additions & 2 deletions src/components/EventsList/components/ScheduledEvent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,28 @@ import type { JSX } from 'solid-js/jsx-runtime';
import styles from '../styles.module.scss';
import { formatDate } from '@i18n/date-time';
import type { MeetupEventType } from '@api/meetup/event.graqhql.types';
import { Dynamic } from 'solid-js/web';

export interface ScheduleEventProps {
event: MeetupEventType;
lang: Lang;
heading?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
}

const defaultHeading: NonNullable<ScheduleEventProps['heading']> = 'h2';

export function ScheduledEvent(props: ScheduleEventProps): JSX.Element {
return (
<section class={styles.event}>
<time datetime={new Date(props.event.dateTime).toISOString()}>
{formatDate(props.lang, new Date(props.event.dateTime))}
</time>
<h3 class={styles.eventHeading}>
<Dynamic
component={props.heading ?? defaultHeading}
class={styles.eventHeading}
>
<a href={props.event.eventUrl}>{props.event.title}</a>
</h3>
</Dynamic>
</section>
);
}
8 changes: 8 additions & 0 deletions src/components/LangSelector/LangSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import type { Lang } from '@i18n/types';
import { For, type JSX, splitProps } from 'solid-js';
import styles from './langSelector.module.scss';
import type { NavbarMessages } from '@components/Navbar/helpers';

export type LangSelectorProps = JSX.IntrinsicElements['nav'] & {
activeLang: Lang;
urlMap?: Partial<Record<Lang, string>> | null | undefined;
messages: NavbarMessages;
};

const langToLabelMap: Readonly<Record<string, keyof NavbarMessages>> = {
it: 'itWebsite',
en: 'enWebsite',
};

export function LangSelector(props: LangSelectorProps) {
Expand Down Expand Up @@ -39,6 +46,7 @@ export function LangSelector(props: LangSelectorProps) {
href={altUrl}
hreflang={lang}
lang={lang}
aria-label={props.messages[langToLabelMap[lang]]}
>
{lang}
</a>
Expand Down
15 changes: 11 additions & 4 deletions src/components/Navbar/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import styles from './navbar.module.scss';
import { createAppBreakpoints } from 'utils/media-queries';
import { navbarLinks, preventSelfNavigation, socialLinks } from 'utils/routing';
import type { Lang } from '@i18n/types';
import type { NavbarMessages } from './helpers';
import { openMenuBtnId, type NavbarMessages } from './helpers';

export interface NavbarProps {
lang: Lang;
Expand Down Expand Up @@ -40,7 +40,11 @@ export function Navbar(props: NavbarProps): JSX.Element {
<div class={styles.leftSide}>
<Show when={props.urlMap} keyed>
{(urlMap) => (
<LangSelector activeLang={props.lang} urlMap={urlMap} />
<LangSelector
messages={props.messages}
activeLang={props.lang}
urlMap={urlMap}
/>
)}
</Show>
</div>
Expand All @@ -50,7 +54,7 @@ export function Navbar(props: NavbarProps): JSX.Element {
[styles.rightSide]: true,
}}
>
<nav class={styles.navbarNav}>
<nav class={styles.navbarNav} aria-label={props.messages.mainSiteNav}>
<ul>
<li>
<a
Expand Down Expand Up @@ -83,7 +87,11 @@ export function Navbar(props: NavbarProps): JSX.Element {
</nav>
</div>
<button
id={openMenuBtnId}
aria-label={props.messages.openMenu}
type="button"
aria-haspopup="true"
aria-expanded={isMenuVisible()}
classList={{
[styles.hamburgerMenuBtn]: true,
[styles.rightSide]: true,
Expand All @@ -93,7 +101,6 @@ export function Navbar(props: NavbarProps): JSX.Element {
}}
>
<img aria-hidden="true" alt="menu" src={hamburgerMenuImg.src} />
<span class="visually-hidden">Open menu</span>
</button>
</div>
<Transition name="fade" appear>
Expand Down
18 changes: 13 additions & 5 deletions src/components/Navbar/components/MenuModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from '@components/LangSelector/LangSelector';
import { BrandMenuArea } from './BrandMenuArea';
import { navbarLinks, preventSelfNavigation, socialLinks } from 'utils/routing';
import type { NavbarMessages } from '../helpers';
import { closeMenuBtnId, openMenuBtnId, type NavbarMessages } from '../helpers';

export interface MenuModalProps extends LangSelectorProps {
class?: string;
Expand All @@ -20,8 +20,11 @@ export function MenuModal(props: MenuModalProps): JSX.Element {
createEffect(() => {
document.body.style.setProperty('overflow', 'hidden');

document.getElementById(closeMenuBtnId)?.focus();

onCleanup(() => {
document.body.style.removeProperty('overflow');
document.getElementById(openMenuBtnId)?.focus();
});
});

Expand All @@ -35,9 +38,15 @@ export function MenuModal(props: MenuModalProps): JSX.Element {
>
<div class={styles.menuTopNav}>
<div class={styles.leftSide}>
<LangSelector activeLang={props.activeLang} urlMap={props.urlMap} />
<LangSelector
messages={props.messages}
activeLang={props.activeLang}
urlMap={props.urlMap}
/>
</div>
<button
id={closeMenuBtnId}
aria-label={props.messages.closeMenu}
classList={{
[styles.rightSide]: true,
[styles.hamburgerMenuBtn]: true,
Expand All @@ -46,10 +55,9 @@ export function MenuModal(props: MenuModalProps): JSX.Element {
onClick={props.onCloseButtonClick}
>
<img src={hamburgerMenuOpenImg.src} alt="close" aria-hidden="true" />
<span class="visually-hidden">Close menu</span>
</button>
</div>
<nav class="d-contents">
<nav class="d-contents" aria-label={props.messages.mainSiteNav}>
<ul class={styles.menuLinks}>
<For each={navLinksEntries()}>
{([label, href]) => (
Expand Down Expand Up @@ -107,7 +115,7 @@ export function MenuModal(props: MenuModalProps): JSX.Element {
</a>
</li>
</ul>
<BrandMenuArea />
<BrandMenuArea aria-hidden="true" />
</div>
);
}
13 changes: 12 additions & 1 deletion src/components/Navbar/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { l10n } from '@i18n/config';

const l10nKeys = ['ctaWatchOurVideos', 'ctaJoinDiscordCta'] as const;
const l10nKeys = [
'ctaWatchOurVideos',
'ctaJoinDiscordCta',
'openMenu',
'closeMenu',
'mainSiteNav',
'itWebsite',
'enWebsite',
] as const;

export type NavbarMessages = Readonly<Record<typeof l10nKeys[number], string>>;

Expand All @@ -16,3 +24,6 @@ export function getNavbarMessages(): NavbarMessages {
l10nKeys.map((key) => [key, l10n(key)])
) as NavbarMessages;
}

export const closeMenuBtnId = 'rmjs-close-menu-btn';
export const openMenuBtnId = 'rmjs-open-menu-btn';
6 changes: 6 additions & 0 deletions src/components/Navbar/navbar.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,12 @@
}
}

.hamburgerMenuBtn:focus-visible {
outline-width: 2px;
outline-style: solid;
outline-offset: 2px;
}

.ctaLinks {
composes: list-style-none m-0 from global;
display: flex;
Expand Down
25 changes: 25 additions & 0 deletions src/components/SkipToMainContent/SkipToMainContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import styles from './styles.module.scss';

export interface SkipToMainContentProps {
targetId: string;
label: string;
}

export function SkipToMainContent(props: SkipToMainContentProps) {
const handleClick = () => {
document.getElementById(props.targetId)?.focus();
};

return (
<button
type="button"
classList={{
[styles.root]: true,
'btn btn-secondary h-1 visually-hidden-focusable': true,
}}
onClick={handleClick}
>
{props.label}
</button>
);
}
6 changes: 6 additions & 0 deletions src/components/SkipToMainContent/styles.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.root {
position: fixed;
top: 4px;
left: 4px;
z-index: calc(var(--navbar-menu-fullscreen-index, 2) + 2);
}
17 changes: 15 additions & 2 deletions src/components/SlantedHeader/SlantedHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { type JSX, Show, type JSXElement } from 'solid-js';
import { splitProps } from 'solid-js';
import styles from './styles.module.scss';
import { Dynamic } from 'solid-js/web';

export type SlantedHeaderProps = JSX.IntrinsicElements['header'] & {
title: string;
logoHref?: string;
logoLabel?: string;
children: JSXElement;
heading: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
headingId?: string;
headingTabIndex?: string;
};

export function SlantedHeader(props: SlantedHeaderProps): JSX.Element {
Expand All @@ -17,6 +21,9 @@ export function SlantedHeader(props: SlantedHeaderProps): JSX.Element {
'classList',
'logoHref',
'logoLabel',
'heading',
'headingId',
'headingTabIndex',
]);

const classList = () => {
Expand All @@ -41,9 +48,15 @@ export function SlantedHeader(props: SlantedHeaderProps): JSX.Element {
</a>
</Show>

<h1 class="h-1" classList={{ [styles.heading]: true }}>
<Dynamic
component={local.heading}
class="h-1"
tabIndex={local.headingTabIndex}
id={local.headingId}
classList={{ [styles.heading]: true }}
>
{local.title}
</h1>
</Dynamic>
</header>
);
}
5 changes: 5 additions & 0 deletions src/layouts/About.astro
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import type { Lang } from '@i18n/types';
import { getNavbarMessages } from '@components/Navbar/helpers';
import { ViewTransitions } from 'astro:transitions';
import BrandLogo from '@components/BrandLogo/BrandLogo.astro';
import { h1HeadingDomId, slantedHeaderH1Config } from 'utils/a11y';
import { SkipToMainContent } from '@components/SkipToMainContent/SkipToMainContent';
import { l10n } from '@i18n/config';
const { content } = Astro.props;
Expand All @@ -35,6 +38,7 @@ changeLanguage(lang);
</head>
<body class={styles.wallpaper}>
<article class="main">
<SkipToMainContent client:load targetId={h1HeadingDomId} label={l10n('skipToMainContent')} />
<Navbar
client:load
lang={lang}
Expand All @@ -43,6 +47,7 @@ changeLanguage(lang);
messages={getNavbarMessages()}
/>
<SlantedHeader
{...slantedHeaderH1Config}
title={title}
logoHref={navbarLinks[lang]?.home}
logoLabel={'homepage'}
Expand Down
Loading

0 comments on commit 9cfcbdc

Please sign in to comment.