Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix_sidebar_badge_alignment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
default: patch
---

Fix sidebar notification badge positioning so unread and unverified counts align consistently.
36 changes: 36 additions & 0 deletions src/app/components/sidebar/SidebarCountBadge.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { render } from '@testing-library/react';
import { describe, expect, it } from 'vitest';
import { SidebarItem } from './SidebarItem';
import { SidebarCountBadge } from './SidebarCountBadge';

describe('SidebarCountBadge', () => {
it('uses the UnverifiedTab top-left numbered badge anchor', () => {
const { container, getByText } = render(<SidebarCountBadge variant="Warning" count={1} />);

expect(container.firstElementChild).toHaveStyle({
top: '-0.375rem',
left: '-0.375rem',
right: 'auto',
});
expect(getByText('1')).toBeInTheDocument();
});

it('keeps the top-left anchor even when the parent contains a data-id button', () => {
const { container } = render(
<SidebarItem>
<button type="button" data-id="space-id">
space
</button>
<SidebarCountBadge variant="Warning" count={1} />
</SidebarItem>
);

const badge = container.querySelector('div[class*="Sidebar_SidebarItemBadge"]');
expect(badge).not.toBeNull();
expect(badge).toHaveStyle({
top: '-0.375rem',
left: '-0.375rem',
right: 'auto',
});
});
});
20 changes: 20 additions & 0 deletions src/app/components/sidebar/SidebarCountBadge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Badge, Text, toRem } from 'folds';
import { millify } from '$plugins/millify';
import { SidebarItemBadge } from './SidebarItem';

type SidebarCountBadgeProps = {
count: number;
variant: 'Warning' | 'Success' | 'Secondary';
};

export function SidebarCountBadge({ count, variant }: Readonly<SidebarCountBadgeProps>) {
return (
<SidebarItemBadge hasCount style={{ top: toRem(-6), left: toRem(-6), right: 'auto' }}>
<Badge variant={variant} size="400" fill="Solid" radii="Pill" outlined={false}>
<Text as="span" size="L400">
{millify(count)}
</Text>
</Badge>
</SidebarItemBadge>
);
}
1 change: 1 addition & 0 deletions src/app/components/sidebar/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './Sidebar';
export * from './SidebarCountBadge';
export * from './SidebarItem';
export * from './SidebarContent';
export * from './SidebarStack';
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/unread-badge/UnreadBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { millify } from '$plugins/millify';
import { useSetting } from '$state/hooks/settings';
import { settingsAtom } from '$state/settings';

type UnreadBadgeProps = {
export type UnreadBadgeProps = {
highlight?: boolean;
count: number;
/** Whether this badge belongs to a DM room. Used with the badgeCountDMsOnly setting. */
Expand Down
12 changes: 5 additions & 7 deletions src/app/pages/client/sidebar/AccountSwitcherTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ import {
backgroundUnreadCountsAtom,
} from '$state/sessions';
import {
SidebarCountBadge,
SidebarItem,
SidebarItemTooltip,
SidebarAvatar,
SidebarItemBadge,
} from '$components/sidebar';
import { UserAvatar } from '$components/user-avatar';
import { nameInitials } from '$utils/common';
Expand Down Expand Up @@ -287,12 +287,10 @@ export function AccountSwitcherTab() {
)}
</SidebarItemTooltip>
{(totalBackgroundUnread > 0 || anyBackgroundHighlight) && (
<SidebarItemBadge hasCount style={{ left: toRem(-6), right: 'auto' }}>
<UnreadBadge
highlight={anyBackgroundHighlight}
count={anyBackgroundHighlight ? totalBackgroundHighlight : totalBackgroundUnread}
/>
</SidebarItemBadge>
<SidebarCountBadge
variant={anyBackgroundHighlight ? 'Success' : 'Secondary'}
count={anyBackgroundHighlight ? totalBackgroundHighlight : totalBackgroundUnread}
/>
)}

<PopOut
Expand Down
22 changes: 6 additions & 16 deletions src/app/pages/client/sidebar/DirectDMsList.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { useMemo, useRef, useEffect } from 'react';
import * as Sentry from '@sentry/react';
import { useNavigate } from 'react-router-dom';
import { Avatar, Text, Box, toRem } from 'folds';
import { Avatar, Text, Box } from 'folds';
import { useAtomValue } from 'jotai';
import { Room } from '$types/matrix-sdk';
import { useMatrixClient } from '$hooks/useMatrixClient';
import { roomToUnreadAtom } from '$state/room/roomToUnread';
import { getDirectRoomPath } from '$pages/pathUtils';
import {
SidebarAvatar,
SidebarCountBadge,
SidebarItem,
SidebarItemBadge,
SidebarItemTooltip,
} from '$components/sidebar';
import { UnreadBadge } from '$components/unread-badge';
import { RoomAvatar } from '$components/room-avatar';
import { UserAvatar } from '$components/user-avatar';
import { getDirectRoomAvatarUrl } from '$utils/room';
Expand Down Expand Up @@ -139,19 +138,10 @@ function DMItem({ room, selected }: DMItemProps) {
)}
</SidebarItemTooltip>
{unread && (unread.total > 0 || unread.highlight > 0) && (
<SidebarItemBadge
hasCount={unread.total > 0}
style={{
left: unread.total > 0 ? toRem(-6) : toRem(-4),
right: 'auto',
}}
>
<UnreadBadge
highlight={unread.highlight > 0}
count={unread.highlight > 0 ? unread.highlight : unread.total}
dm
/>
</SidebarItemBadge>
<SidebarCountBadge
variant={unread.highlight > 0 ? 'Success' : 'Secondary'}
count={unread.highlight > 0 ? unread.highlight : unread.total}
/>
)}
</SidebarItem>
);
Expand Down
20 changes: 5 additions & 15 deletions src/app/pages/client/sidebar/DirectTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,11 @@ import { getDirectPath, joinPathComponent } from '$pages/pathUtils';
import { useRoomsUnread } from '$state/hooks/unread';
import {
SidebarAvatar,
SidebarCountBadge,
SidebarItem,
SidebarItemBadge,
SidebarItemTooltip,
} from '$components/sidebar';
import { useDirectSelected } from '$hooks/router/useDirectSelected';
import { UnreadBadge } from '$components/unread-badge';
import { ScreenSize, useScreenSizeContext } from '$hooks/useScreenSize';
import { useNavToActivePathAtom } from '$state/hooks/navToActivePath';
import { markAsRead } from '$utils/notifications';
Expand Down Expand Up @@ -115,19 +114,10 @@ export function DirectTab() {
)}
</SidebarItemTooltip>
{directUnread && (
<SidebarItemBadge
hasCount={directUnread.total > 0}
style={{
left: directUnread.total > 0 ? toRem(-6) : toRem(-4),
right: 'auto',
}}
>
<UnreadBadge
highlight={directUnread.highlight > 0}
count={directUnread.highlight > 0 ? directUnread.highlight : directUnread.total}
dm
/>
</SidebarItemBadge>
<SidebarCountBadge
variant={directUnread.highlight > 0 ? 'Success' : 'Secondary'}
count={directUnread.highlight > 0 ? directUnread.highlight : directUnread.total}
/>
)}
{menuAnchor && (
<PopOut
Expand Down
19 changes: 5 additions & 14 deletions src/app/pages/client/sidebar/HomeTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,11 @@ import { getHomePath, joinPathComponent } from '$pages/pathUtils';
import { useRoomsUnread } from '$state/hooks/unread';
import {
SidebarAvatar,
SidebarCountBadge,
SidebarItem,
SidebarItemBadge,
SidebarItemTooltip,
} from '$components/sidebar';
import { useHomeSelected } from '$hooks/router/useHomeSelected';
import { UnreadBadge } from '$components/unread-badge';
import { ScreenSize, useScreenSizeContext } from '$hooks/useScreenSize';
import { useNavToActivePathAtom } from '$state/hooks/navToActivePath';
import { markAsRead } from '$utils/notifications';
Expand Down Expand Up @@ -109,18 +108,10 @@ export function HomeTab() {
)}
</SidebarItemTooltip>
{homeUnread && (
<SidebarItemBadge
hasCount={homeUnread.total > 0}
style={{
left: homeUnread.total > 0 ? toRem(-6) : toRem(-4),
right: 'auto',
}}
>
<UnreadBadge
highlight={homeUnread.highlight > 0}
count={homeUnread.highlight > 0 ? homeUnread.highlight : homeUnread.total}
/>
</SidebarItemBadge>
<SidebarCountBadge
variant={homeUnread.highlight > 0 ? 'Success' : 'Secondary'}
count={homeUnread.highlight > 0 ? homeUnread.highlight : homeUnread.total}
/>
)}
{menuAnchor && (
<PopOut
Expand Down
11 changes: 3 additions & 8 deletions src/app/pages/client/sidebar/InboxTab.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useNavigate } from 'react-router-dom';
import { Icon, Icons, toRem } from 'folds';
import { Icon, Icons } from 'folds';
import { useAtomValue } from 'jotai';
import {
SidebarAvatar,
SidebarCountBadge,
SidebarItem,
SidebarItemBadge,
SidebarItemTooltip,
} from '$components/sidebar';
import { allInvitesAtom } from '$state/room-list/inviteList';
Expand All @@ -15,7 +15,6 @@ import {
joinPathComponent,
} from '$pages/pathUtils';
import { useInboxSelected } from '$hooks/router/useInbox';
import { UnreadBadge } from '$components/unread-badge';
import { ScreenSize, useScreenSizeContext } from '$hooks/useScreenSize';
import { useNavToActivePathAtom } from '$state/hooks/navToActivePath';

Expand Down Expand Up @@ -51,11 +50,7 @@ export function InboxTab() {
</SidebarAvatar>
)}
</SidebarItemTooltip>
{inviteCount > 0 && (
<SidebarItemBadge hasCount style={{ left: toRem(-6), right: 'auto' }}>
<UnreadBadge highlight count={inviteCount} />
</SidebarItemBadge>
)}
{inviteCount > 0 && <SidebarCountBadge variant="Success" count={inviteCount} />}
</SidebarItem>
);
}
35 changes: 9 additions & 26 deletions src/app/pages/client/sidebar/SpaceTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ import { allRoomsAtom } from '$state/room-list/roomList';
import { getSpaceLobbyPath, getSpacePath, joinPathComponent } from '$pages/pathUtils';
import {
SidebarAvatar,
SidebarCountBadge,
SidebarItem,
SidebarItemBadge,
SidebarItemTooltip,
SidebarStack,
SidebarStackSeparator,
Expand All @@ -60,7 +60,6 @@ import {
} from '$components/sidebar';
import { RoomUnreadProvider, RoomsUnreadProvider } from '$components/RoomUnreadProvider';
import { useSelectedSpace } from '$hooks/router/useSelectedSpace';
import { UnreadBadge } from '$components/unread-badge';
import { getCanonicalAliasOrRoomId, isRoomAlias } from '$utils/matrix';
import { RoomAvatar } from '$components/room-avatar';
import { nameInitials, randomStr } from '$utils/common';
Expand Down Expand Up @@ -465,18 +464,10 @@ function SpaceTab({
)}
</SidebarItemTooltip>
{unread && (
<SidebarItemBadge
hasCount={unread.total > 0}
style={{
left: unread.total > 0 ? toRem(-6) : toRem(-4),
right: 'auto',
}}
>
<UnreadBadge
highlight={unread.highlight > 0}
count={unread.highlight > 0 ? unread.highlight : unread.total}
/>
</SidebarItemBadge>
<SidebarCountBadge
variant={unread.highlight > 0 ? 'Success' : 'Secondary'}
count={unread.highlight > 0 ? unread.highlight : unread.total}
/>
)}
{menuAnchor && (
<PopOut
Expand Down Expand Up @@ -606,18 +597,10 @@ function ClosedSpaceFolder({
)}
</SidebarItemTooltip>
{unread && (
<SidebarItemBadge
hasCount={unread.total > 0}
style={{
left: unread.total > 0 ? toRem(-6) : toRem(-4),
right: 'auto',
}}
>
<UnreadBadge
highlight={unread.highlight > 0}
count={unread.highlight > 0 ? unread.highlight : unread.total}
/>
</SidebarItemBadge>
<SidebarCountBadge
variant={unread.highlight > 0 ? 'Success' : 'Secondary'}
count={unread.highlight > 0 ? unread.highlight : unread.total}
/>
)}
</SidebarItem>
)}
Expand Down
12 changes: 3 additions & 9 deletions src/app/pages/client/sidebar/UnverifiedTab.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useState } from 'react';
import { Badge, color, Icon, Icons, Text, toRem } from 'folds';
import { color, Icon, Icons } from 'folds';
import {
SidebarAvatar,
SidebarCountBadge,
SidebarItem,
SidebarItemBadge,
SidebarItemTooltip,
} from '$components/sidebar';
import { useDeviceIds, useDeviceList, useSplitCurrentDevice } from '$hooks/useDeviceList';
Expand Down Expand Up @@ -66,13 +66,7 @@ function UnverifiedIndicator() {
)}
</SidebarItemTooltip>
{!unverified && unverifiedDeviceCount && unverifiedDeviceCount > 0 && (
<SidebarItemBadge hasCount style={{ left: toRem(-6), right: 'auto' }}>
<Badge variant="Warning" size="400" fill="Solid" radii="Pill" outlined={false}>
<Text as="span" size="L400">
{unverifiedDeviceCount}
</Text>
</Badge>
</SidebarItemBadge>
<SidebarCountBadge count={unverifiedDeviceCount} variant="Warning" />
)}
</SidebarItem>
)}
Expand Down
Loading