mirror of
https://github.com/mastodon/mastodon.git
synced 2026-09-27 15:28:21 -05:00
Redesign: Fix "Skip to main content" link (#40626)
This commit is contained in:
@@ -6,6 +6,8 @@ import { Link } from 'react-router-dom';
|
||||
import { IconLogo } from '@/mastodon/components/logo';
|
||||
import { customAppIcon, domain, title } from '@/mastodon/initial_state';
|
||||
|
||||
import { getNavigationSkipLinkId } from '../../ui/components/skip_links';
|
||||
|
||||
import classes from './header.module.scss';
|
||||
|
||||
export const NavigationHeader: React.FC<{
|
||||
@@ -24,7 +26,11 @@ export const LogoLockup: React.FC<{
|
||||
className?: string;
|
||||
}> = ({ siteName, className }) => {
|
||||
return (
|
||||
<Link to='/' className={classNames(classes.siteNameLink, className)}>
|
||||
<Link
|
||||
to='/'
|
||||
className={classNames(classes.siteNameLink, className)}
|
||||
id={getNavigationSkipLinkId()}
|
||||
>
|
||||
{customAppIcon && (
|
||||
<img src={customAppIcon} alt='' className={classes.appIcon} />
|
||||
)}
|
||||
|
||||
@@ -11,6 +11,16 @@
|
||||
gap: var(--multi-column-gap);
|
||||
padding-inline-end: var(--multi-column-gap);
|
||||
overflow-x: auto;
|
||||
scroll-padding-inline-start: var(--multi-column-navigation-width);
|
||||
|
||||
&:focus-visible {
|
||||
// Scrollable elements are made focusable by some browsers, this adds
|
||||
// a visible outline in this case. Using `border` instead of `outline`
|
||||
// causes a light layout jump shift on focus, but an outline would be
|
||||
// rendered below the navbar and columns and didn't look right.
|
||||
border: var(--outline-focus-default);
|
||||
border-radius: var(--radius-2);
|
||||
}
|
||||
}
|
||||
|
||||
.navigationWrapper {
|
||||
|
||||
@@ -2,15 +2,16 @@ import { useCallback, useId } from 'react';
|
||||
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
import { isRedesignEnabled } from '@/mastodon/utils/environment';
|
||||
import { useAppSelector } from 'mastodon/store';
|
||||
|
||||
import classes from './skip_links.module.scss';
|
||||
|
||||
export const getNavigationSkipLinkId = () => 'skip-link-target-nav';
|
||||
export const getColumnSkipLinkId = (index: number) =>
|
||||
`skip-link-target-content-${index}`;
|
||||
export const getColumnSkipLinkId = (index: number | null) =>
|
||||
`skip-link-target-content-${index ?? ''}`;
|
||||
|
||||
export const SkipLinks: React.FC<{
|
||||
const LegacySkipLinks: React.FC<{
|
||||
multiColumn: boolean;
|
||||
onFocusGettingStartedColumn: () => void;
|
||||
}> = ({ multiColumn, onFocusGettingStartedColumn }) => {
|
||||
@@ -54,6 +55,23 @@ export const SkipLinks: React.FC<{
|
||||
);
|
||||
};
|
||||
|
||||
const RedesignSkipLinks: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<div className={classes.list}>
|
||||
<div className={classes.listItem}>
|
||||
<SkipLink target={getColumnSkipLinkId(1)} hotkey='2'>
|
||||
{intl.formatMessage({
|
||||
id: 'skip_links.skip_to_content',
|
||||
defaultMessage: 'Skip to main content',
|
||||
})}
|
||||
</SkipLink>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const SkipLink: React.FC<{
|
||||
children: string;
|
||||
target: string;
|
||||
@@ -82,3 +100,7 @@ const SkipLink: React.FC<{
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const SkipLinks = isRedesignEnabled()
|
||||
? RedesignSkipLinks
|
||||
: LegacySkipLinks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.list {
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
z-index: 200;
|
||||
margin: 10px;
|
||||
padding: 10px 16px;
|
||||
border-radius: 10px;
|
||||
|
||||
@@ -649,6 +649,7 @@ class UI extends PureComponent {
|
||||
<div className={classNames('ui', { 'is-composing': isComposing })} ref={this.setRef}>
|
||||
{!minimalShell && (
|
||||
<SkipLinks
|
||||
// TODO: Remove these props & related methods when isRedesignEnabled() flag is removed
|
||||
multiColumn={layout === 'multi-column'}
|
||||
onFocusGettingStartedColumn={this.handleHotkeyGoToStart}
|
||||
/>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { isRedesignEnabled } from '@/mastodon/utils/environment';
|
||||
|
||||
import {
|
||||
getColumnSkipLinkId,
|
||||
getNavigationSkipLinkId,
|
||||
@@ -45,11 +47,24 @@ function focusColumnTitle(index: number, multiColumn: boolean) {
|
||||
}
|
||||
}
|
||||
|
||||
function focusRedesignColumnTitle(index: number) {
|
||||
const idToFocus =
|
||||
index === 1 ? getNavigationSkipLinkId() : getColumnSkipLinkId(index - 1);
|
||||
|
||||
document.querySelector<HTMLElement>(`#${idToFocus}`)?.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Move focus to the column of the passed index (1-based).
|
||||
* Focus is placed on the topmost visible item, or the column title.
|
||||
*/
|
||||
export function focusColumn(index = 1) {
|
||||
if (isRedesignEnabled()) {
|
||||
// In the redesign, always focus the column title
|
||||
focusRedesignColumnTitle(index);
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip the leftmost drawer in multi-column mode
|
||||
const isMultiColumnLayout = !!document.querySelector(
|
||||
'body.layout-multiple-columns',
|
||||
|
||||
Reference in New Issue
Block a user