diff --git a/packages/frontend/src/components/AccountListSidebar/AccountItem.tsx b/packages/frontend/src/components/AccountListSidebar/AccountItem.tsx index 8ec5323f85..1df31ee8df 100644 --- a/packages/frontend/src/components/AccountListSidebar/AccountItem.tsx +++ b/packages/frontend/src/components/AccountListSidebar/AccountItem.tsx @@ -242,70 +242,78 @@ export default function AccountItem({ // for a different account, and upon initial render. return ( - + + ) } diff --git a/packages/frontend/src/components/AccountListSidebar/AccountListSidebar.tsx b/packages/frontend/src/components/AccountListSidebar/AccountListSidebar.tsx index 30c46a8539..acf7b6bab5 100644 --- a/packages/frontend/src/components/AccountListSidebar/AccountListSidebar.tsx +++ b/packages/frontend/src/components/AccountListSidebar/AccountListSidebar.tsx @@ -46,7 +46,7 @@ export default function AccountListSidebar({ }: Props) { const tx = useTranslationFunction() - const accountsListRef = useRef(null) + const accountsListRef = useRef(null) const { openDialog } = useDialog() const [accounts, setAccounts] = useState([]) const [{ accounts: noficationSettings }] = useAccountNotificationStore() @@ -144,8 +144,12 @@ export default function AccountListSidebar({ data-tauri-drag-region /> )} -
))} - +
  • + +
  • -
    + {/* The condition is the same as in https://github.com/deltachat/deltachat-desktop/blob/63af023437ff1828a27de2da37bf94ab180ec528/src/renderer/contexts/KeybindingsContext.tsx#L26 */} {window.__screen === Screens.Main && (
    diff --git a/packages/frontend/src/components/AccountListSidebar/styles.module.scss b/packages/frontend/src/components/AccountListSidebar/styles.module.scss index 249c00174d..22d77a81e9 100644 --- a/packages/frontend/src/components/AccountListSidebar/styles.module.scss +++ b/packages/frontend/src/components/AccountListSidebar/styles.module.scss @@ -50,6 +50,10 @@ --als-avatar-margin: 5px; --als-active-indicator-color: white; + margin: 0; + padding: 0; + list-style: none; + align-items: center; display: flex; flex-direction: column; @@ -63,6 +67,28 @@ } } + .accountWrapper { + margin-bottom: var(--als-avatar-margin); + margin-top: var(--als-avatar-margin); + + &.isSticky { + position: sticky; + bottom: var(--als-avatar-margin); + top: var(--als-avatar-margin); + // Only needed when this account is scrolled _above_ the visible region. + z-index: map-get($z-index, account-list-sidebar-scope-sticky-account); + + .account { + .avatar { + opacity: 1; + .content { + box-shadow: 0px 0px 4px 2px #00000040; + } + } + } + } + } + .account { border: none; background: none; @@ -71,8 +97,6 @@ height: var(--als-avatar-size); - margin-bottom: var(--als-avatar-margin); - margin-top: var(--als-avatar-margin); // Adding extra `var(--als-avatar-size) + 2 * var(--als-avatar-margin)` // to the margins so that // if there is another `.isSticky` account, then that account does not @@ -107,21 +131,6 @@ } } - &.isSticky { - position: sticky; - bottom: var(--als-avatar-margin); - top: var(--als-avatar-margin); - // Only needed when this account is scrolled _above_ the visible region. - z-index: map-get($z-index, account-list-sidebar-scope-sticky-account); - - .avatar { - opacity: 1; - .content { - box-shadow: 0px 0px 4px 2px #00000040; - } - } - } - &.active, &:hover, &.context-menu-active { diff --git a/packages/frontend/src/components/chat/ChatList.tsx b/packages/frontend/src/components/chat/ChatList.tsx index 7ed0e8d73a..30c6aedcbb 100644 --- a/packages/frontend/src/components/chat/ChatList.tsx +++ b/packages/frontend/src/components/chat/ChatList.tsx @@ -5,6 +5,8 @@ import React, { useCallback, ComponentType, useMemo, + HTMLAttributes, + useLayoutEffect, } from 'react' import { FixedSizeList as List, @@ -60,6 +62,7 @@ export function ChatListPart({ height, itemKey, setListRef, + olElementAttrs, itemData, itemHeight, }: { @@ -71,6 +74,10 @@ export function ChatListPart({ height: number itemKey: ListItemKeySelector setListRef?: (ref: List | null) => void + /** + * This does _not_ support maps with dynamically added/removed keys. + */ + olElementAttrs?: HTMLAttributes itemData: ChatListItemData | ContactChatListItemData | MessageChatListItemData itemHeight: number }) { @@ -92,6 +99,26 @@ export function ChatListPart({ // So let's play it safe. }) + const olRef = useRef(null) + // 'react-window' does not expose API to set attributes on its element, + // so we have to `useLayoutEffect`. + useLayoutEffect(() => { + if (olRef.current == null) { + return + } + if (olElementAttrs == undefined) { + return + } + + for (const [key, value] of Object.entries(olElementAttrs)) { + if (value == undefined) { + olRef.current.removeAttribute(key) + } else { + olRef.current.setAttribute(key, value) + } + } + }) + return ( ( {({ height }) => (
    -
    +
    {tx('search_in', searchChatInfo.name)} {messageResultIds.length !== 0 && ': ' + translate_n('n_messages', messageResultIds.length)} @@ -378,6 +409,9 @@ export default function ChatList(props: { classNameOfTargetElements={rovingTabindexItemsClassName} > ( <> {isSearchActive && ( -
    +
    {translate_n('n_chats', chatListIds.length)}
    )} @@ -419,6 +456,18 @@ export default function ChatList(props: { >
    {isSearchActive && ( <> -
    +
    {translate_n('n_contacts', contactIds.length)}
    -
    +
    {translated_messages_label(messageResultIds.length)}
    @@ -483,6 +541,9 @@ export default function ChatList(props: { >
    void disabledContacts?: number[] onContactContextMenu?: (contact: Type.Contact) => void + olElementAttrs?: Omit, 'style'> }) { const { contacts, @@ -32,9 +33,13 @@ export function ContactList(props: { onRemoveClick, disabledContacts, onContactContextMenu, + olElementAttrs, } = props return ( -
      +
        {contacts.map(contact => { let checked = false if (showCheckbox && typeof isChecked === 'function') { diff --git a/packages/frontend/src/components/dialogs/CreateChat/index.tsx b/packages/frontend/src/components/dialogs/CreateChat/index.tsx index 3f33dceb08..8ce3deed21 100644 --- a/packages/frontend/src/components/dialogs/CreateChat/index.tsx +++ b/packages/frontend/src/components/dialogs/CreateChat/index.tsx @@ -565,7 +565,7 @@ export function CreateGroup(props: CreateGroupProps) { type='group' /> -
        +
        {tx('n_members', groupMembers.length.toString(), { quantity: groupMembers.length, })} @@ -587,6 +587,9 @@ export function CreateGroup(props: CreateGroupProps) { onRemoveClick={c => { removeGroupMember(c) }} + olElementAttrs={{ + 'aria-labelledby': 'create-group-members-title', + }} />
        @@ -693,7 +696,10 @@ function CreateBroadcastList(props: CreateBroadcastListProps) { />
        {broadcastRecipients.length > 0 && ( -
        +
        {tx('n_recipients', broadcastRecipients.length.toString(), { quantity: broadcastRecipients.length, })} @@ -716,6 +722,9 @@ function CreateBroadcastList(props: CreateBroadcastListProps) { onRemoveClick={c => { removeBroadcastRecipient(c) }} + olElementAttrs={{ + 'aria-labelledby': 'create-broadcast-list-recipients-title', + }} />
        diff --git a/packages/frontend/src/components/dialogs/SelectChat/index.tsx b/packages/frontend/src/components/dialogs/SelectChat/index.tsx index e7a245181f..2b30379465 100644 --- a/packages/frontend/src/components/dialogs/SelectChat/index.tsx +++ b/packages/frontend/src/components/dialogs/SelectChat/index.tsx @@ -64,6 +64,9 @@ export default function SelectChat(props: Props) { {({ height }) => ( {isRelatedChatsEnabled && ( <> -
        {tx('related_chats')}
        +
        )} -
        +
        {!isBroadcast ? tx('n_members', groupMembers.length.toString(), { quantity: groupMembers.length, @@ -340,12 +351,20 @@ function ViewGroupInner( setProfileContact(contact) }} onRemoveClick={showRemoveGroupMemberConfirmationDialog} + olElementAttrs={{ + 'aria-labelledby': 'view-group-members-recipients-title', + }} />
        {pastContacts.length > 0 && ( <> -
        {tx('past_members')}
        +
        + {tx('past_members')} +
        diff --git a/packages/frontend/src/components/dialogs/ViewProfile/index.tsx b/packages/frontend/src/components/dialogs/ViewProfile/index.tsx index d54146d6fa..c1facafbe1 100644 --- a/packages/frontend/src/components/dialogs/ViewProfile/index.tsx +++ b/packages/frontend/src/components/dialogs/ViewProfile/index.tsx @@ -327,7 +327,9 @@ export function ViewProfileInner({ )} {!(isDeviceChat || isSelfChat) && ( <> -
        {tx('profile_shared_chats')}
        +
        + {tx('profile_shared_chats')} +
        {({ height }) => ( loadMissingMessages: () => Promise }) => { + const tx = useTranslationFunction() + const { onScroll, onScrollEnd, @@ -859,14 +861,14 @@ export const MessageListInner = React.memo( if (!loaded) { return (
        -
          +
            ) } return (
            -
              +
                {messageListItems.length === 0 && } {activeView.map(messageId => {