nicolium: more accessibility tweaks
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -83,7 +83,9 @@ const FilterBar = () => {
|
||||
});
|
||||
} else {
|
||||
items.push({
|
||||
text: <Icon className='size-4' src={require('@phosphor-icons/core/regular/at.svg')} />,
|
||||
text: (
|
||||
<Icon className='size-4' src={require('@phosphor-icons/core/regular/at.svg')} aria-hidden />
|
||||
),
|
||||
title: intl.formatMessage(messages.mentions),
|
||||
action: onClick('mention'),
|
||||
name: 'mention',
|
||||
@ -94,6 +96,7 @@ const FilterBar = () => {
|
||||
<Icon
|
||||
className='size-4'
|
||||
src={require('@phosphor-icons/core/regular/bell-simple-ringing.svg')}
|
||||
aria-hidden
|
||||
/>
|
||||
),
|
||||
title: intl.formatMessage(messages.statuses),
|
||||
@ -101,13 +104,25 @@ const FilterBar = () => {
|
||||
name: 'status',
|
||||
});
|
||||
items.push({
|
||||
text: <Icon className='size-4' src={require('@phosphor-icons/core/regular/star.svg')} />,
|
||||
text: (
|
||||
<Icon
|
||||
className='size-4'
|
||||
src={require('@phosphor-icons/core/regular/star.svg')}
|
||||
aria-hidden
|
||||
/>
|
||||
),
|
||||
title: intl.formatMessage(messages.favourites),
|
||||
action: onClick('favourite'),
|
||||
name: 'favourite',
|
||||
});
|
||||
items.push({
|
||||
text: <Icon className='size-4' src={require('@phosphor-icons/core/regular/repeat.svg')} />,
|
||||
text: (
|
||||
<Icon
|
||||
className='size-4'
|
||||
src={require('@phosphor-icons/core/regular/repeat.svg')}
|
||||
aria-hidden
|
||||
/>
|
||||
),
|
||||
title: intl.formatMessage(messages.boosts),
|
||||
action: onClick('reblog'),
|
||||
name: 'reblog',
|
||||
@ -115,7 +130,11 @@ const FilterBar = () => {
|
||||
if (features.polls)
|
||||
items.push({
|
||||
text: (
|
||||
<Icon className='size-4' src={require('@phosphor-icons/core/regular/chart-bar.svg')} />
|
||||
<Icon
|
||||
className='size-4'
|
||||
src={require('@phosphor-icons/core/regular/chart-bar.svg')}
|
||||
aria-hidden
|
||||
/>
|
||||
),
|
||||
title: intl.formatMessage(messages.polls),
|
||||
action: onClick('poll'),
|
||||
@ -127,6 +146,7 @@ const FilterBar = () => {
|
||||
<Icon
|
||||
className='size-4'
|
||||
src={require('@phosphor-icons/core/regular/calendar-dots.svg')}
|
||||
aria-hidden
|
||||
/>
|
||||
),
|
||||
title: intl.formatMessage(messages.events),
|
||||
@ -134,7 +154,13 @@ const FilterBar = () => {
|
||||
name: 'events',
|
||||
});
|
||||
items.push({
|
||||
text: <Icon className='size-4' src={require('@phosphor-icons/core/regular/user-plus.svg')} />,
|
||||
text: (
|
||||
<Icon
|
||||
className='size-4'
|
||||
src={require('@phosphor-icons/core/regular/user-plus.svg')}
|
||||
aria-hidden
|
||||
/>
|
||||
),
|
||||
title: intl.formatMessage(messages.follows),
|
||||
action: onClick('follow'),
|
||||
name: 'follow',
|
||||
|
||||
@ -20,7 +20,11 @@ const AltIndicator: React.FC<IAltIndicator> = React.forwardRef<HTMLSpanElement,
|
||||
ref={ref}
|
||||
>
|
||||
{warning && (
|
||||
<Icon className='size-4' src={require('@phosphor-icons/core/regular/warning.svg')} />
|
||||
<Icon
|
||||
className='size-4'
|
||||
src={require('@phosphor-icons/core/regular/warning.svg')}
|
||||
aria-hidden
|
||||
/>
|
||||
)}
|
||||
{message ?? (
|
||||
<FormattedMessage id='upload_form.description_missing.indicator' defaultMessage='Alt' />
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import clsx from 'clsx';
|
||||
import React, { useState, useRef, useLayoutEffect, CSSProperties } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import AltIndicator from '@/components/alt-indicator';
|
||||
import Blurhash from '@/components/blurhash';
|
||||
@ -30,6 +30,10 @@ import type { MediaAttachment } from 'pl-api';
|
||||
const ATTACHMENT_LIMIT = 4;
|
||||
const MAX_FILENAME_LENGTH = 45;
|
||||
|
||||
const messages = defineMessages({
|
||||
altText: { id: 'media_gallery.alt_indicator', defaultMessage: 'Show image description' },
|
||||
});
|
||||
|
||||
interface Dimensions {
|
||||
w: CSSProperties['width'];
|
||||
h: CSSProperties['height'];
|
||||
@ -90,6 +94,7 @@ const Item: React.FC<IItem> = ({
|
||||
total,
|
||||
visible,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const { autoPlayGif } = useSettings();
|
||||
const { mediaPreview } = useFrontendConfig();
|
||||
|
||||
@ -231,6 +236,7 @@ const Item: React.FC<IItem> = ({
|
||||
</Stack>
|
||||
}
|
||||
isFlush
|
||||
title={intl.formatMessage(messages.altText)}
|
||||
>
|
||||
<AltIndicator className='absolute bottom-2 left-2 z-10 opacity-80 transition-opacity hover:opacity-100' />
|
||||
</Popover>
|
||||
|
||||
@ -150,7 +150,7 @@ const StatusReactionsBar: React.FC<IStatusReactionsBar> = ({ status, collapsed }
|
||||
className='⁂-status-reactions-bar__picker-button emoji-picker-dropdown'
|
||||
title={intl.formatMessage(messages.addEmoji)}
|
||||
>
|
||||
<Icon src={require('@phosphor-icons/core/regular/smiley-sticker.svg')} />
|
||||
<Icon src={require('@phosphor-icons/core/regular/smiley-sticker.svg')} aria-hidden />
|
||||
</button>
|
||||
</EmojiPickerDropdown>
|
||||
)}
|
||||
|
||||
@ -40,6 +40,7 @@ import StatusInfo from './statuses/status-info';
|
||||
import Tombstone from './tombstone';
|
||||
|
||||
const messages = defineMessages({
|
||||
edited: { id: 'status.edited', defaultMessage: 'Edited {date}' },
|
||||
reblogged_by: { id: 'status.reblogged_by', defaultMessage: '{name} reposted' },
|
||||
});
|
||||
|
||||
@ -47,37 +48,49 @@ interface IAccountInfo {
|
||||
status: SelectedStatus;
|
||||
}
|
||||
|
||||
const AccountInfo: React.FC<IAccountInfo> = React.memo(({ status }) => (
|
||||
<div className='flex flex-row-reverse items-center gap-1 self-baseline'>
|
||||
<Link
|
||||
to='/@{$username}/posts/$statusId'
|
||||
params={{ username: status.account.acct, statusId: status.id }}
|
||||
className='hover:underline'
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<RelativeTimestamp
|
||||
timestamp={status.created_at}
|
||||
theme='muted'
|
||||
size='sm'
|
||||
className='whitespace-nowrap'
|
||||
/>
|
||||
</Link>
|
||||
<StatusTypeIcon visibility={status.visibility} />
|
||||
<StatusLanguagePicker status={status} />
|
||||
{!!status.edited_at && (
|
||||
<>
|
||||
<span className='⁂-separator' />
|
||||
|
||||
<Icon
|
||||
className='size-4 text-gray-700 dark:text-gray-600'
|
||||
src={require('@phosphor-icons/core/regular/pencil-simple.svg')}
|
||||
const AccountInfo: React.FC<IAccountInfo> = React.memo(({ status }) => {
|
||||
const intl = useIntl();
|
||||
return (
|
||||
<div className='flex flex-row-reverse items-center gap-1 self-baseline'>
|
||||
<Link
|
||||
to='/@{$username}/posts/$statusId'
|
||||
params={{ username: status.account.acct, statusId: status.id }}
|
||||
className='hover:underline'
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<RelativeTimestamp
|
||||
timestamp={status.created_at}
|
||||
theme='muted'
|
||||
size='sm'
|
||||
className='whitespace-nowrap'
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
));
|
||||
</Link>
|
||||
<StatusTypeIcon visibility={status.visibility} />
|
||||
<StatusLanguagePicker status={status} />
|
||||
{!!status.edited_at && (
|
||||
<>
|
||||
<span className='⁂-separator' />
|
||||
|
||||
<Icon
|
||||
className='size-4 text-gray-700 dark:text-gray-600'
|
||||
src={require('@phosphor-icons/core/regular/pencil-simple.svg')}
|
||||
title={intl.formatMessage(messages.edited, {
|
||||
date: intl.formatDate(new Date(status.edited_at), {
|
||||
hour12: true,
|
||||
month: 'short',
|
||||
day: '2-digit',
|
||||
hour: 'numeric',
|
||||
minute: '2-digit',
|
||||
}),
|
||||
})}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
interface IStatusFollowedTagInfo {
|
||||
status: SelectedStatus;
|
||||
|
||||
@ -31,6 +31,7 @@ interface IPopover {
|
||||
referenceElementClassName?: string;
|
||||
offsetOptions?: OffsetOptions;
|
||||
placements?: Array<Placement>;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -47,6 +48,7 @@ const Popover: React.FC<IPopover> = ({
|
||||
isFlush = false,
|
||||
offsetOptions = 10,
|
||||
placements = ['top', 'bottom'],
|
||||
title,
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
|
||||
@ -95,7 +97,11 @@ const Popover: React.FC<IPopover> = ({
|
||||
ref: refs.setReference,
|
||||
...getReferenceProps(),
|
||||
className: clsx(children.props.className, referenceElementClassName),
|
||||
'aria-haspopup': interaction === 'click' ? 'dialog' : undefined,
|
||||
'aria-expanded': isOpen,
|
||||
role: interaction === 'click' ? 'button' : undefined,
|
||||
tabIndex: interaction === 'click' ? 0 : undefined,
|
||||
title: title || children.props.title,
|
||||
})}
|
||||
|
||||
{isMounted && (
|
||||
@ -109,6 +115,7 @@ const Popover: React.FC<IPopover> = ({
|
||||
left: x ?? 0,
|
||||
...styles,
|
||||
}}
|
||||
role='dialog'
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
|
||||
@ -237,8 +237,11 @@ const Upload: React.FC<IUpload> = ({
|
||||
</span>
|
||||
|
||||
{onDescriptionChange && !description && (
|
||||
<button onClick={handleOpenAltTextModal}>
|
||||
<AltIndicator warning title={intl.formatMessage(messages.descriptionMissingTitle)} />
|
||||
<button
|
||||
onClick={handleOpenAltTextModal}
|
||||
title={intl.formatMessage(messages.descriptionMissingTitle)}
|
||||
>
|
||||
<AltIndicator warning />
|
||||
</button>
|
||||
)}
|
||||
</HStack>
|
||||
|
||||
@ -131,6 +131,7 @@ const messages = defineMessages({
|
||||
notePlaceholder: { id: 'account_note.placeholder', defaultMessage: 'Add a note' },
|
||||
noteSaved: { id: 'account_note.success', defaultMessage: 'Note saved' },
|
||||
noteSaveFailed: { id: 'account_note.fail', defaultMessage: 'Failed to save note' },
|
||||
headerAlt: { id: 'account.header.alt.popover', defaultMessage: 'Show profile header alt text' },
|
||||
});
|
||||
|
||||
interface IMovedNote {
|
||||
@ -745,6 +746,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
||||
</Stack>
|
||||
}
|
||||
isFlush
|
||||
title={intl.formatMessage(messages.headerAlt)}
|
||||
>
|
||||
<AltIndicator
|
||||
className='ml-6 mt-6 w-fit'
|
||||
|
||||
@ -53,6 +53,10 @@ const messages = defineMessages({
|
||||
id: 'compose_event.fetch_fail',
|
||||
defaultMessage: 'Failed to fetch edited event information',
|
||||
},
|
||||
eventHeaderDescription: {
|
||||
id: 'compose_event.header_description',
|
||||
defaultMessage: 'Add header alt text.',
|
||||
},
|
||||
});
|
||||
|
||||
interface IEditEvent {
|
||||
@ -262,11 +266,13 @@ const EditEvent: React.FC<IEditEvent> = ({ statusId }) => {
|
||||
<IconButton
|
||||
src={require('@phosphor-icons/core/regular/x.svg')}
|
||||
onClick={handleClearBanner}
|
||||
title={intl.formatMessage(messages.resetLocation)}
|
||||
/>
|
||||
<button
|
||||
type='button'
|
||||
className='absolute bottom-1 left-1'
|
||||
onClick={handleChangeDescriptionClick}
|
||||
title={intl.formatMessage(messages.eventHeaderDescription)}
|
||||
>
|
||||
<AltIndicator warning={!banner.description} />
|
||||
</button>
|
||||
|
||||
@ -21,6 +21,11 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Image description',
|
||||
},
|
||||
changeHeaderDescriptionConfirm: { id: 'group.upload_banner.alt.confirm', defaultMessage: 'Save' },
|
||||
clearHeader: { id: 'group.upload_banner.clear', defaultMessage: 'Clear header image' },
|
||||
changeDescription: {
|
||||
id: 'group.upload_banner.change_description',
|
||||
defaultMessage: 'Change alt text',
|
||||
},
|
||||
});
|
||||
|
||||
interface IMediaInput {
|
||||
@ -111,6 +116,7 @@ const HeaderPicker = React.forwardRef<HTMLInputElement, IMediaInput>(
|
||||
theme='dark'
|
||||
className='absolute right-2 top-2 z-10 hover:scale-105 hover:bg-gray-900'
|
||||
iconClassName='h-5 w-5'
|
||||
title={intl.formatMessage(messages.clearHeader)}
|
||||
/>
|
||||
)}
|
||||
{onChangeDescription && src && (
|
||||
@ -118,6 +124,7 @@ const HeaderPicker = React.forwardRef<HTMLInputElement, IMediaInput>(
|
||||
type='button'
|
||||
className='absolute left-2 top-2'
|
||||
onClick={handleChangeDescriptionClick}
|
||||
title={intl.formatMessage(messages.changeDescription)}
|
||||
>
|
||||
<AltIndicator warning={!description} />
|
||||
</button>
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
"account.follows.empty": "This user doesn't follow anyone yet.",
|
||||
"account.follows_you": "Follows you",
|
||||
"account.header.alt": "Profile header",
|
||||
"account.header.alt.popover": "Show profile header alt text",
|
||||
"account.header.description": "Header description",
|
||||
"account.hide_reblogs": "Hide reposts from @{name}",
|
||||
"account.instance_favicon": "Visit {domain} timeline",
|
||||
@ -552,6 +553,7 @@
|
||||
"compose_event.fields.name_placeholder": "Name",
|
||||
"compose_event.fields.start_time_label": "Event start date",
|
||||
"compose_event.fields.start_time_placeholder": "Event begins on…",
|
||||
"compose_event.header_description": "Add header alt text.",
|
||||
"compose_event.participation_requests.authorize": "Authorize",
|
||||
"compose_event.participation_requests.authorize.fail": "Failed to authorize event participation request",
|
||||
"compose_event.participation_requests.authorize.success": "Event participation request authorized successfully",
|
||||
@ -567,6 +569,7 @@
|
||||
"compose_event.update": "Update",
|
||||
"compose_event.upload_banner": "Upload event banner",
|
||||
"compose_form.approval_required": "The reply needs to be approved by the post author.",
|
||||
"compose_form.approval_required.quote": "The quote needs to be approved by the post author.",
|
||||
"compose_form.content_type.change": "Change content type",
|
||||
"compose_form.direct_message_warning": "This post will only be sent to the mentioned users.",
|
||||
"compose_form.drive_button": "Select from drive",
|
||||
@ -1060,6 +1063,8 @@
|
||||
"group.upload_banner.alt.confirm": "Save",
|
||||
"group.upload_banner.alt.heading": "Change header description",
|
||||
"group.upload_banner.alt.placeholder": "Image description",
|
||||
"group.upload_banner.change_description": "Change alt text",
|
||||
"group.upload_banner.clear": "Clear header image",
|
||||
"group.upload_banner.title": "Upload background picture",
|
||||
"groups.discover.search.results.member_count": "{members, plural, one {member} other {members}}",
|
||||
"groups.empty.subtitle": "Start discovering groups to join or create your own.",
|
||||
@ -1276,6 +1281,7 @@
|
||||
"media.default_description.gifv": "GIFV",
|
||||
"media.default_description.image": "Image",
|
||||
"media.default_description.video": "Video",
|
||||
"media_gallery.alt_indicator": "Show image description",
|
||||
"media_panel.empty_message": "No media found.",
|
||||
"media_panel.title": "Media",
|
||||
"mfa.confirm.success_message": "MFA confirmed",
|
||||
|
||||
Reference in New Issue
Block a user