pl-fe: chat accessibility improvements
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -1,8 +1,14 @@
|
|||||||
import React, { HTMLAttributes } from 'react';
|
import React, { HTMLAttributes } from 'react';
|
||||||
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import IconButton from '@/components/ui/icon-button';
|
import IconButton from '@/components/ui/icon-button';
|
||||||
import { useSettings } from '@/stores/settings';
|
import { useSettings } from '@/stores/settings';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
expand: { id: 'chat_pane.header.expand', defaultMessage: 'Expand chats' },
|
||||||
|
collapse: { id: 'chat_pane.header.collapse', defaultMessage: 'Collapse chats' },
|
||||||
|
});
|
||||||
|
|
||||||
interface IChatPaneHeader {
|
interface IChatPaneHeader {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
isToggleable?: boolean;
|
isToggleable?: boolean;
|
||||||
@ -11,6 +17,7 @@ interface IChatPaneHeader {
|
|||||||
unreadCount?: number;
|
unreadCount?: number;
|
||||||
secondaryAction?(): void;
|
secondaryAction?(): void;
|
||||||
secondaryActionIcon?: string;
|
secondaryActionIcon?: string;
|
||||||
|
secondaryActionTitle?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChatPaneHeader = (props: IChatPaneHeader) => {
|
const ChatPaneHeader = (props: IChatPaneHeader) => {
|
||||||
@ -20,11 +27,13 @@ const ChatPaneHeader = (props: IChatPaneHeader) => {
|
|||||||
onToggle,
|
onToggle,
|
||||||
secondaryAction,
|
secondaryAction,
|
||||||
secondaryActionIcon,
|
secondaryActionIcon,
|
||||||
|
secondaryActionTitle,
|
||||||
title,
|
title,
|
||||||
unreadCount,
|
unreadCount,
|
||||||
...rest
|
...rest
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
const intl = useIntl();
|
||||||
const { demetricator } = useSettings();
|
const { demetricator } = useSettings();
|
||||||
|
|
||||||
const ButtonComp = isToggleable ? 'button' : 'div';
|
const ButtonComp = isToggleable ? 'button' : 'div';
|
||||||
@ -54,10 +63,11 @@ const ChatPaneHeader = (props: IChatPaneHeader) => {
|
|||||||
</ButtonComp>
|
</ButtonComp>
|
||||||
|
|
||||||
<div className='⁂-chat-widget__header__actions'>
|
<div className='⁂-chat-widget__header__actions'>
|
||||||
{secondaryAction ? (
|
{secondaryAction && secondaryActionIcon ? (
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={secondaryAction}
|
onClick={secondaryAction}
|
||||||
src={secondaryActionIcon as string}
|
src={secondaryActionIcon}
|
||||||
|
title={secondaryActionTitle}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
@ -65,6 +75,7 @@ const ChatPaneHeader = (props: IChatPaneHeader) => {
|
|||||||
onClick={onToggle}
|
onClick={onToggle}
|
||||||
src={require('@phosphor-icons/core/regular/caret-up.svg')}
|
src={require('@phosphor-icons/core/regular/caret-up.svg')}
|
||||||
className='⁂-chat-widget__header__open-button'
|
className='⁂-chat-widget__header__open-button'
|
||||||
|
title={isOpen ? intl.formatMessage(messages.collapse) : intl.formatMessage(messages.expand)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { defineMessages, useIntl } from 'react-intl';
|
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import Avatar from '@/components/ui/avatar';
|
import Avatar from '@/components/ui/avatar';
|
||||||
import HStack from '@/components/ui/hstack';
|
import HStack from '@/components/ui/hstack';
|
||||||
@ -15,19 +15,12 @@ import { useModalsActions } from '@/stores/modals';
|
|||||||
import ChatPaneHeader from './chat-pane-header';
|
import ChatPaneHeader from './chat-pane-header';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
blockMessage: { id: 'chat_settings.block.message', defaultMessage: 'Blocking will prevent this profile from direct messaging you and viewing your content. You can unblock later.' },
|
back: { id: 'card.back.label', defaultMessage: 'Back' },
|
||||||
blockHeading: { id: 'chat_settings.block.heading', defaultMessage: 'Block @{acct}' },
|
|
||||||
blockConfirm: { id: 'chat_settings.block.confirm', defaultMessage: 'Block' },
|
|
||||||
unblockMessage: { id: 'chat_settings.unblock.message', defaultMessage: 'Unblocking will allow this profile to direct message you and view your content.' },
|
|
||||||
unblockHeading: { id: 'chat_settings.unblock.heading', defaultMessage: 'Unblock @{acct}' },
|
unblockHeading: { id: 'chat_settings.unblock.heading', defaultMessage: 'Unblock @{acct}' },
|
||||||
unblockConfirm: { id: 'chat_settings.unblock.confirm', defaultMessage: 'Unblock' },
|
unblockConfirm: { id: 'chat_settings.unblock.confirm', defaultMessage: 'Unblock' },
|
||||||
leaveMessage: { id: 'chat_settings.leave.message', defaultMessage: 'Are you sure you want to leave this chat? Messages will be deleted for you and this chat will be removed from your inbox.' },
|
leaveMessage: { id: 'chat_settings.leave.message', defaultMessage: 'Are you sure you want to leave this chat? Messages will be deleted for you and this chat will be removed from your inbox.' },
|
||||||
leaveHeading: { id: 'chat_settings.leave.heading', defaultMessage: 'Leave chat' },
|
leaveHeading: { id: 'chat_settings.leave.heading', defaultMessage: 'Leave chat' },
|
||||||
leaveConfirm: { id: 'chat_settings.leave.confirm', defaultMessage: 'Leave chat' },
|
leaveConfirm: { id: 'chat_settings.leave.confirm', defaultMessage: 'Leave chat' },
|
||||||
title: { id: 'chat_settings.title', defaultMessage: 'Chat Details' },
|
|
||||||
blockUser: { id: 'chat_settings.options.block_user', defaultMessage: 'Block @{acct}' },
|
|
||||||
unblockUser: { id: 'chat_settings.options.unblock_user', defaultMessage: 'Unblock @{acct}' },
|
|
||||||
leaveChat: { id: 'chat_settings.options.leave_chat', defaultMessage: 'Leave chat' },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const ChatSettings = () => {
|
const ChatSettings = () => {
|
||||||
@ -61,7 +54,7 @@ const ChatSettings = () => {
|
|||||||
const handleUnblockUser = () => {
|
const handleUnblockUser = () => {
|
||||||
openModal('CONFIRM', {
|
openModal('CONFIRM', {
|
||||||
heading: intl.formatMessage(messages.unblockHeading, { acct: chat?.account.acct }),
|
heading: intl.formatMessage(messages.unblockHeading, { acct: chat?.account.acct }),
|
||||||
message: intl.formatMessage(messages.unblockMessage),
|
message: <FormattedMessage id='chat_settings.unblock.message' defaultMessage='Unblocking will allow this profile to direct message you and view your content.' />,
|
||||||
confirm: intl.formatMessage(messages.unblockConfirm),
|
confirm: intl.formatMessage(messages.unblockConfirm),
|
||||||
onConfirm: () => unblockAccount(),
|
onConfirm: () => unblockAccount(),
|
||||||
});
|
});
|
||||||
@ -70,7 +63,7 @@ const ChatSettings = () => {
|
|||||||
const handleLeaveChat = () => {
|
const handleLeaveChat = () => {
|
||||||
openModal('CONFIRM', {
|
openModal('CONFIRM', {
|
||||||
heading: intl.formatMessage(messages.leaveHeading),
|
heading: intl.formatMessage(messages.leaveHeading),
|
||||||
message: intl.formatMessage(messages.leaveMessage),
|
message: <FormattedMessage id='chat_settings.leave.message' defaultMessage='Are you sure you want to leave this chat? Messages will be deleted for you and this chat will be removed from your inbox.' />,
|
||||||
confirm: intl.formatMessage(messages.leaveConfirm),
|
confirm: intl.formatMessage(messages.leaveConfirm),
|
||||||
onConfirm: () => deleteChat.mutate(),
|
onConfirm: () => deleteChat.mutate(),
|
||||||
});
|
});
|
||||||
@ -88,7 +81,7 @@ const ChatSettings = () => {
|
|||||||
onToggle={minimizeChatPane}
|
onToggle={minimizeChatPane}
|
||||||
title={
|
title={
|
||||||
<HStack alignItems='center' space={2}>
|
<HStack alignItems='center' space={2}>
|
||||||
<button onClick={closeSettings}>
|
<button onClick={closeSettings} title={intl.formatMessage(messages.back)}>
|
||||||
<Icon
|
<Icon
|
||||||
src={require('@phosphor-icons/core/regular/arrow-left.svg')}
|
src={require('@phosphor-icons/core/regular/arrow-left.svg')}
|
||||||
className='size-6 text-gray-600 dark:text-gray-400 rtl:rotate-180'
|
className='size-6 text-gray-600 dark:text-gray-400 rtl:rotate-180'
|
||||||
@ -96,7 +89,7 @@ const ChatSettings = () => {
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<Text weight='semibold'>
|
<Text weight='semibold'>
|
||||||
{intl.formatMessage(messages.title)}
|
<FormattedMessage id='chat_settings.title' defaultMessage='Chat details' />
|
||||||
</Text>
|
</Text>
|
||||||
</HStack>
|
</HStack>
|
||||||
}
|
}
|
||||||
@ -113,14 +106,20 @@ const ChatSettings = () => {
|
|||||||
|
|
||||||
<Stack space={5}>
|
<Stack space={5}>
|
||||||
<button onClick={isBlocked ? handleUnblockUser : handleBlockUser} className='flex w-full items-center space-x-2 text-sm font-bold text-primary-600 dark:text-primary-400'>
|
<button onClick={isBlocked ? handleUnblockUser : handleBlockUser} className='flex w-full items-center space-x-2 text-sm font-bold text-primary-600 dark:text-primary-400'>
|
||||||
<Icon src={require('@phosphor-icons/core/regular/prohibit.svg')} className='size-5' />
|
<Icon src={require('@phosphor-icons/core/regular/prohibit.svg')} className='size-5' aria-hidden />
|
||||||
<span>{intl.formatMessage(isBlocked ? messages.unblockUser : messages.blockUser, { acct: chat.account.acct })}</span>
|
<span>
|
||||||
|
{isBlocked
|
||||||
|
? <FormattedMessage id='chat_settings.options.unblock_user' defaultMessage='Unblock @{acct}' values={{ acct: chat.account.acct }} />
|
||||||
|
: <FormattedMessage id='chat_settings.options.block_user' defaultMessage='Block @{acct}' values={{ acct: chat.account.acct }} />
|
||||||
|
}
|
||||||
|
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{features.chatsDelete && (
|
{features.chatsDelete && (
|
||||||
<button onClick={handleLeaveChat} className='flex w-full items-center space-x-2 text-sm font-bold text-danger-600'>
|
<button onClick={handleLeaveChat} className='flex w-full items-center space-x-2 text-sm font-bold text-danger-600'>
|
||||||
<Icon src={require('@phosphor-icons/core/regular/sign-out.svg')} className='size-5' />
|
<Icon src={require('@phosphor-icons/core/regular/sign-out.svg')} className='size-5' aria-hidden />
|
||||||
<span>{intl.formatMessage(messages.leaveChat)}</span>
|
<span><FormattedMessage id='chat_settings.options.leave_chat' defaultMessage='Leave chat' /></span>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { Link, type LinkProps } from '@tanstack/react-router';
|
import { Link, type LinkProps } from '@tanstack/react-router';
|
||||||
import React, { useRef } from 'react';
|
import React, { useRef } from 'react';
|
||||||
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import Avatar from '@/components/ui/avatar';
|
import Avatar from '@/components/ui/avatar';
|
||||||
import HStack from '@/components/ui/hstack';
|
import HStack from '@/components/ui/hstack';
|
||||||
@ -14,6 +15,12 @@ import Chat from '../chat';
|
|||||||
import ChatPaneHeader from './chat-pane-header';
|
import ChatPaneHeader from './chat-pane-header';
|
||||||
import ChatSettings from './chat-settings';
|
import ChatSettings from './chat-settings';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
back: { id: 'card.back.label', defaultMessage: 'Back' },
|
||||||
|
chatInfo: { id: 'chat_pane.header.chat_info', defaultMessage: 'Chat info' },
|
||||||
|
newChat: { id: 'chat_pane.header.new_chat', defaultMessage: 'New chat' },
|
||||||
|
});
|
||||||
|
|
||||||
const LinkWrapper = ({ enabled, children, ...rest }: LinkProps & { enabled: boolean; children: React.ReactNode }): JSX.Element => {
|
const LinkWrapper = ({ enabled, children, ...rest }: LinkProps & { enabled: boolean; children: React.ReactNode }): JSX.Element => {
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
return <>{children}</>;
|
return <>{children}</>;
|
||||||
@ -29,6 +36,7 @@ const LinkWrapper = ({ enabled, children, ...rest }: LinkProps & { enabled: bool
|
|||||||
/** Floating desktop chat window. */
|
/** Floating desktop chat window. */
|
||||||
const ChatWindow = () => {
|
const ChatWindow = () => {
|
||||||
const { chat, currentChatId, screen, changeScreen, isOpen, toggleChatPane } = useChatContext();
|
const { chat, currentChatId, screen, changeScreen, isOpen, toggleChatPane } = useChatContext();
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
const inputRef = useRef<HTMLTextAreaElement | null>(null);
|
const inputRef = useRef<HTMLTextAreaElement | null>(null);
|
||||||
|
|
||||||
@ -45,8 +53,6 @@ const ChatWindow = () => {
|
|||||||
changeScreen(ChatWidgetScreens.CHAT_SETTINGS, currentChatId);
|
changeScreen(ChatWidgetScreens.CHAT_SETTINGS, currentChatId);
|
||||||
};
|
};
|
||||||
|
|
||||||
const secondaryAction = () => isOpen ? openChatSettings : openSearch;
|
|
||||||
|
|
||||||
if (!chat) return null;
|
if (!chat) return null;
|
||||||
|
|
||||||
if (screen === ChatWidgetScreens.CHAT_SETTINGS) {
|
if (screen === ChatWidgetScreens.CHAT_SETTINGS) {
|
||||||
@ -59,7 +65,7 @@ const ChatWindow = () => {
|
|||||||
title={
|
title={
|
||||||
<HStack alignItems='center' space={2}>
|
<HStack alignItems='center' space={2}>
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<button onClick={closeChat}>
|
<button onClick={closeChat} title={intl.formatMessage(messages.back)}>
|
||||||
<Icon
|
<Icon
|
||||||
src={require('@phosphor-icons/core/regular/arrow-left.svg')}
|
src={require('@phosphor-icons/core/regular/arrow-left.svg')}
|
||||||
className='size-6 text-gray-600 dark:text-gray-400 rtl:rotate-180'
|
className='size-6 text-gray-600 dark:text-gray-400 rtl:rotate-180'
|
||||||
@ -85,8 +91,9 @@ const ChatWindow = () => {
|
|||||||
</HStack>
|
</HStack>
|
||||||
</HStack>
|
</HStack>
|
||||||
}
|
}
|
||||||
secondaryAction={secondaryAction()}
|
secondaryAction={isOpen ? openChatSettings : openSearch}
|
||||||
secondaryActionIcon={isOpen ? require('@phosphor-icons/core/regular/info.svg') : require('@phosphor-icons/core/regular/pencil-simple.svg')}
|
secondaryActionIcon={isOpen ? require('@phosphor-icons/core/regular/info.svg') : require('@phosphor-icons/core/regular/pencil-simple.svg')}
|
||||||
|
secondaryActionTitle={isOpen ? intl.formatMessage(messages.chatInfo) : intl.formatMessage(messages.newChat)}
|
||||||
isToggleable={!isOpen}
|
isToggleable={!isOpen}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onToggle={toggleChatPane}
|
onToggle={toggleChatPane}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { defineMessages, useIntl } from 'react-intl';
|
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import Icon from '@/components/ui/icon';
|
import Icon from '@/components/ui/icon';
|
||||||
import Text from '@/components/ui/text';
|
import Text from '@/components/ui/text';
|
||||||
@ -8,7 +8,7 @@ import { ChatWidgetScreens, useChatContext } from '@/contexts/chat-context';
|
|||||||
import ChatPaneHeader from '../chat-pane-header';
|
import ChatPaneHeader from '../chat-pane-header';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
title: { id: 'chat_search.title', defaultMessage: 'Messages' },
|
back: { id: 'card.back.label', defaultMessage: 'Back' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const ChatSearchHeader = () => {
|
const ChatSearchHeader = () => {
|
||||||
@ -25,6 +25,7 @@ const ChatSearchHeader = () => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
changeScreen(ChatWidgetScreens.INBOX);
|
changeScreen(ChatWidgetScreens.INBOX);
|
||||||
}}
|
}}
|
||||||
|
title={intl.formatMessage(messages.back)}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
src={require('@phosphor-icons/core/regular/arrow-left.svg')}
|
src={require('@phosphor-icons/core/regular/arrow-left.svg')}
|
||||||
@ -33,7 +34,7 @@ const ChatSearchHeader = () => {
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<Text size='sm' weight='bold' truncate>
|
<Text size='sm' weight='bold' truncate>
|
||||||
{intl.formatMessage(messages.title)}
|
<FormattedMessage id='chat_search.title' defaultMessage='Messages' />
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,7 @@ const Pane: React.FC<IPane> = ({ isOpen = false, children }) => (
|
|||||||
<div
|
<div
|
||||||
className={clsx('⁂-chat-widget', { '⁂-chat-widget--open': isOpen })}
|
className={clsx('⁂-chat-widget', { '⁂-chat-widget--open': isOpen })}
|
||||||
data-testid='pane'
|
data-testid='pane'
|
||||||
|
aria-expanded={isOpen}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -336,6 +336,10 @@
|
|||||||
"chat_pane.blankslate.action": "Message someone",
|
"chat_pane.blankslate.action": "Message someone",
|
||||||
"chat_pane.blankslate.body": "Search for someone to chat with.",
|
"chat_pane.blankslate.body": "Search for someone to chat with.",
|
||||||
"chat_pane.blankslate.title": "No messages yet",
|
"chat_pane.blankslate.title": "No messages yet",
|
||||||
|
"chat_pane.header.chat_info": "Chat info",
|
||||||
|
"chat_pane.header.collapse": "Collapse chats",
|
||||||
|
"chat_pane.header.expand": "Expand chats",
|
||||||
|
"chat_pane.header.new_chat": "New chat",
|
||||||
"chat_search.blankslate.body": "Search for someone to chat with.",
|
"chat_search.blankslate.body": "Search for someone to chat with.",
|
||||||
"chat_search.blankslate.title": "Start a chat",
|
"chat_search.blankslate.title": "Start a chat",
|
||||||
"chat_search.empty_results_blankslate.body": "Try searching for another name.",
|
"chat_search.empty_results_blankslate.body": "Try searching for another name.",
|
||||||
@ -351,7 +355,7 @@
|
|||||||
"chat_settings.options.block_user": "Block @{acct}",
|
"chat_settings.options.block_user": "Block @{acct}",
|
||||||
"chat_settings.options.leave_chat": "Leave chat",
|
"chat_settings.options.leave_chat": "Leave chat",
|
||||||
"chat_settings.options.unblock_user": "Unblock @{acct}",
|
"chat_settings.options.unblock_user": "Unblock @{acct}",
|
||||||
"chat_settings.title": "Chat Details",
|
"chat_settings.title": "Chat details",
|
||||||
"chat_settings.unblock.confirm": "Unblock",
|
"chat_settings.unblock.confirm": "Unblock",
|
||||||
"chat_settings.unblock.heading": "Unblock @{acct}",
|
"chat_settings.unblock.heading": "Unblock @{acct}",
|
||||||
"chat_settings.unblock.message": "Unblocking will allow this profile to direct message you and view your content.",
|
"chat_settings.unblock.message": "Unblocking will allow this profile to direct message you and view your content.",
|
||||||
|
|||||||
Reference in New Issue
Block a user