diff options
Diffstat (limited to 'src/components')
| -rw-r--r-- | src/components/atoms/layout/sidebar.stories.tsx | 13 | ||||
| -rw-r--r-- | src/components/atoms/layout/sidebar.tsx | 8 | ||||
| -rw-r--r-- | src/components/atoms/links/link.module.scss | 23 | ||||
| -rw-r--r-- | src/components/molecules/layout/meta.tsx | 26 | ||||
| -rw-r--r-- | src/components/organisms/layout/footer.tsx | 15 | ||||
| -rw-r--r-- | src/components/organisms/layout/summary.module.scss | 5 | ||||
| -rw-r--r-- | src/components/organisms/layout/summary.tsx | 3 | ||||
| -rw-r--r-- | src/components/templates/page/page-layout.tsx | 18 |
8 files changed, 99 insertions, 12 deletions
diff --git a/src/components/atoms/layout/sidebar.stories.tsx b/src/components/atoms/layout/sidebar.stories.tsx index 337d0c9..175af94 100644 --- a/src/components/atoms/layout/sidebar.stories.tsx +++ b/src/components/atoms/layout/sidebar.stories.tsx @@ -9,6 +9,19 @@ export default { title: 'Atoms/Layout', component: SidebarComponent, argTypes: { + 'aria-label': { + control: { + type: 'text', + }, + description: 'An accessible name for the sidebar.', + table: { + category: 'Accessibility', + }, + type: { + name: 'string', + required: false, + }, + }, children: { control: { type: 'text', diff --git a/src/components/atoms/layout/sidebar.tsx b/src/components/atoms/layout/sidebar.tsx index d13cc0d..d86af37 100644 --- a/src/components/atoms/layout/sidebar.tsx +++ b/src/components/atoms/layout/sidebar.tsx @@ -3,6 +3,10 @@ import styles from './sidebar.module.scss'; export type SidebarProps = { /** + * An accessible name for the sidebar. + */ + 'aria-label'?: string; + /** * The sidebar body. */ children: ReactNode; @@ -17,9 +21,9 @@ export type SidebarProps = { * * Render an aside element. */ -const Sidebar: FC<SidebarProps> = ({ children, className = '' }) => { +const Sidebar: FC<SidebarProps> = ({ children, className = '', ...props }) => { return ( - <aside className={`${styles.wrapper} ${className}`}> + <aside className={`${styles.wrapper} ${className}`} {...props}> <div className={styles.body}>{children}</div> </aside> ); diff --git a/src/components/atoms/links/link.module.scss b/src/components/atoms/links/link.module.scss index 1b89727..5c97bd2 100644 --- a/src/components/atoms/links/link.module.scss +++ b/src/components/atoms/links/link.module.scss @@ -2,6 +2,29 @@ @use "@styles/abstracts/variables" as var; .link { + background: linear-gradient(to top, var(--color-primary) 50%, transparent 50%) + 0 0 / 100% 201% no-repeat; + color: var(--color-primary); + text-decoration-thickness: 0.15em; + text-underline-offset: 20%; + transition: all 0.3s linear 0s, text-decoration 0.18s ease-in-out 0s; + + &:hover { + color: var(--color-primary-light); + text-decoration-thickness: 0.25em; + } + + &:focus { + background-position: 0 100%; + color: var(--color-fg-inverted); + } + + &:active { + background-position: 0 0; + color: var(--color-primary-dark); + text-decoration-thickness: 18%; + } + &[hreflang] { &::after { display: inline-block; diff --git a/src/components/molecules/layout/meta.tsx b/src/components/molecules/layout/meta.tsx index 1d5e04b..1f6219a 100644 --- a/src/components/molecules/layout/meta.tsx +++ b/src/components/molecules/layout/meta.tsx @@ -14,6 +14,10 @@ export type CustomMeta = { export type MetaComments = { /** + * A page title. + */ + about: string; + /** * The comments count. */ count: number; @@ -269,19 +273,29 @@ const Meta: FC<MetaProps> = ({ * @param comments - The comments object. * @returns {string | JSX.Element} - The comments count. */ - const getCommentsCount = (comments: MetaComments) => { - const { count, target } = comments; + const getCommentsCount = (comments: MetaComments): string | JSX.Element => { + const { about, count, target } = comments; const commentsCount = intl.formatMessage( { defaultMessage: - '{commentsCount, plural, =0 {No comments} one {# comment} other {# comments}}', - id: 'adTrj7', + '{commentsCount, plural, =0 {No comments} one {# comment} other {# comments}}<a11y> about {title}</a11y>', + id: '02rgLO', description: 'Meta: comments count', }, - { commentsCount: count } + { + a11y: (chunks: ReactNode) => ( + <span className="screen-reader-text">{chunks}</span> + ), + commentsCount: count, + title: about, + } ); - return target ? <Link href={target}>{commentsCount}</Link> : commentsCount; + return target ? ( + <Link href={target}>{commentsCount as JSX.Element}</Link> + ) : ( + (commentsCount as JSX.Element) + ); }; /** diff --git a/src/components/organisms/layout/footer.tsx b/src/components/organisms/layout/footer.tsx index 15bfa24..1426e96 100644 --- a/src/components/organisms/layout/footer.tsx +++ b/src/components/organisms/layout/footer.tsx @@ -4,6 +4,7 @@ import Copyright, { import BackToTop from '@components/molecules/buttons/back-to-top'; import Nav, { type NavItem } from '@components/molecules/nav/nav'; import { FC } from 'react'; +import { useIntl } from 'react-intl'; import styles from './footer.module.scss'; export type FooterProps = { @@ -31,6 +32,13 @@ export type FooterProps = { * Renders a footer with copyright and nav; */ const Footer: FC<FooterProps> = ({ className, copyright, navItems, topId }) => { + const intl = useIntl(); + const ariaLabel = intl.formatMessage({ + defaultMessage: 'Footer', + description: 'Footer: an accessible name for footer nav', + id: 'd4N8nD', + }); + return ( <footer className={`${styles.wrapper} ${className}`}> <Copyright @@ -39,7 +47,12 @@ const Footer: FC<FooterProps> = ({ className, copyright, navItems, topId }) => { icon={copyright.icon} /> {navItems && ( - <Nav kind="footer" items={navItems} className={styles.nav} /> + <Nav + aria-label={ariaLabel} + kind="footer" + items={navItems} + className={styles.nav} + /> )} <BackToTop target={topId} className={styles['back-to-top']} /> </footer> diff --git a/src/components/organisms/layout/summary.module.scss b/src/components/organisms/layout/summary.module.scss index 9d28bc6..7e86dd2 100644 --- a/src/components/organisms/layout/summary.module.scss +++ b/src/components/organisms/layout/summary.module.scss @@ -80,6 +80,11 @@ } } +.link { + display: block; + width: fit-content; +} + .title { margin: 0; background: none; diff --git a/src/components/organisms/layout/summary.tsx b/src/components/organisms/layout/summary.tsx index 078f9ee..3831c0c 100644 --- a/src/components/organisms/layout/summary.tsx +++ b/src/components/organisms/layout/summary.tsx @@ -116,6 +116,7 @@ const Summary: FC<SummaryProps> = ({ </Link> )), comments: { + about: title, count: commentsCount || 0, target: `${url}#comments`, }, @@ -126,7 +127,7 @@ const Summary: FC<SummaryProps> = ({ <article className={styles.wrapper}> {cover && <ResponsiveImage className={styles.cover} {...cover} />} <header className={styles.header}> - <Link href={url}> + <Link href={url} className={styles.link}> <Heading level={titleLevel} className={styles.title}> {title} </Heading> diff --git a/src/components/templates/page/page-layout.tsx b/src/components/templates/page/page-layout.tsx index 045b8c1..4e4ff00 100644 --- a/src/components/templates/page/page-layout.tsx +++ b/src/components/templates/page/page-layout.tsx @@ -185,7 +185,14 @@ const PageLayout: FC<PageLayoutProps> = ({ className={styles.header} /> {withToC && ( - <Sidebar className={`${styles.sidebar} ${styles['sidebar--first']}`}> + <Sidebar + className={`${styles.sidebar} ${styles['sidebar--first']}`} + aria-label={intl.formatMessage({ + defaultMessage: 'Table of contents sidebar', + id: 'Q+1GbT', + description: 'PageLayout: accessible name for ToC sidebar', + })} + > {isMounted && bodyRef.current && ( <TableOfContents wrapper={bodyRef.current} /> )} @@ -203,7 +210,14 @@ const PageLayout: FC<PageLayoutProps> = ({ </div> )} <PageFooter meta={footerMeta} className={styles.footer} /> - <Sidebar className={`${styles.sidebar} ${styles['sidebar--last']}`}> + <Sidebar + className={`${styles.sidebar} ${styles['sidebar--last']}`} + aria-label={intl.formatMessage({ + defaultMessage: 'Sidebar', + id: 'c556Qo', + description: 'PageLayout: accessible name for the sidebar', + })} + > {widgets} </Sidebar> {hasCommentsSection && ( |
