Add max count to sidebar icons
This commit is contained in:
parent
d0960de07c
commit
be136fe6cf
8 changed files with 34 additions and 11 deletions
|
@ -5,18 +5,19 @@ import { Counter } from 'soapbox/components/ui';
|
|||
|
||||
interface IIconWithCounter extends React.HTMLAttributes<HTMLDivElement> {
|
||||
count: number,
|
||||
countMax?: number
|
||||
icon?: string;
|
||||
src?: string;
|
||||
}
|
||||
|
||||
const IconWithCounter: React.FC<IIconWithCounter> = ({ icon, count, ...rest }) => {
|
||||
const IconWithCounter: React.FC<IIconWithCounter> = ({ icon, count, countMax, ...rest }) => {
|
||||
return (
|
||||
<div className='relative'>
|
||||
<Icon id={icon} {...rest as IIcon} />
|
||||
|
||||
{count > 0 && (
|
||||
<i className='absolute -top-2 -right-2'>
|
||||
<Counter count={count} />
|
||||
<Counter count={count} countMax={countMax} />
|
||||
</i>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -2,11 +2,13 @@ import classNames from 'clsx';
|
|||
import React from 'react';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
|
||||
import { Icon, Text } from './ui';
|
||||
import { Counter, HStack, Icon, Text } from './ui';
|
||||
|
||||
interface ISidebarNavigationLink {
|
||||
/** Notification count, if any. */
|
||||
count?: number,
|
||||
/** Optional max to cap count (ie: N+) */
|
||||
countMax?: number
|
||||
/** URL to an SVG icon. */
|
||||
icon: string,
|
||||
/** Link label. */
|
||||
|
@ -19,7 +21,7 @@ interface ISidebarNavigationLink {
|
|||
|
||||
/** Desktop sidebar navigation link. */
|
||||
const SidebarNavigationLink = React.forwardRef((props: ISidebarNavigationLink, ref: React.ForwardedRef<HTMLAnchorElement>): JSX.Element => {
|
||||
const { icon, text, to = '', count, onClick } = props;
|
||||
const { icon, text, to = '', count, countMax, onClick } = props;
|
||||
const isActive = location.pathname === to;
|
||||
|
||||
const handleClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
|
@ -44,14 +46,19 @@ const SidebarNavigationLink = React.forwardRef((props: ISidebarNavigationLink, r
|
|||
<span className='relative'>
|
||||
<Icon
|
||||
src={icon}
|
||||
count={count}
|
||||
className={classNames('h-5 w-5 group-hover:text-primary-500', {
|
||||
'text-primary-500': isActive,
|
||||
})}
|
||||
/>
|
||||
</span>
|
||||
|
||||
<Text weight='semibold' theme='inherit'>{text}</Text>
|
||||
<HStack space={2} alignItems='center'>
|
||||
<Text weight='semibold' theme='inherit'>{text}</Text>
|
||||
|
||||
{count ? (
|
||||
<Counter count={count} countMax={countMax} />
|
||||
) : null}
|
||||
</HStack>
|
||||
</NavLink>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -116,6 +116,7 @@ const SidebarNavigation = () => {
|
|||
to='/chats'
|
||||
icon={require('@tabler/icons/mail.svg')}
|
||||
count={unreadChatsCount}
|
||||
countMax={20}
|
||||
text={<FormattedMessage id='navigation.direct_messages' defaultMessage='Messages' />}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -7,6 +7,7 @@ import { Icon, Text } from 'soapbox/components/ui';
|
|||
|
||||
interface IThumbNavigationLink {
|
||||
count?: number,
|
||||
countMax?: number,
|
||||
src: string,
|
||||
text: string | React.ReactElement,
|
||||
to: string,
|
||||
|
@ -14,7 +15,7 @@ interface IThumbNavigationLink {
|
|||
paths?: Array<string>,
|
||||
}
|
||||
|
||||
const ThumbNavigationLink: React.FC<IThumbNavigationLink> = ({ count, src, text, to, exact, paths }): JSX.Element => {
|
||||
const ThumbNavigationLink: React.FC<IThumbNavigationLink> = ({ count, countMax, src, text, to, exact, paths }): JSX.Element => {
|
||||
const { pathname } = useLocation();
|
||||
|
||||
const isActive = (): boolean => {
|
||||
|
@ -38,6 +39,7 @@ const ThumbNavigationLink: React.FC<IThumbNavigationLink> = ({ count, src, text,
|
|||
'text-primary-500': active,
|
||||
})}
|
||||
count={count}
|
||||
countMax={countMax}
|
||||
/>
|
||||
) : (
|
||||
<Icon
|
||||
|
|
|
@ -24,6 +24,7 @@ const ThumbNavigation: React.FC = (): JSX.Element => {
|
|||
to='/chats'
|
||||
exact
|
||||
count={unreadChatsCount}
|
||||
countMax={20}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,13 +5,15 @@ import { shortNumberFormat } from 'soapbox/utils/numbers';
|
|||
interface ICounter {
|
||||
/** Number this counter should display. */
|
||||
count: number,
|
||||
/** Optional max number (ie: N+) */
|
||||
countMax?: number
|
||||
}
|
||||
|
||||
/** A simple counter for notifications, etc. */
|
||||
const Counter: React.FC<ICounter> = ({ count }) => {
|
||||
const Counter: React.FC<ICounter> = ({ count, countMax }) => {
|
||||
return (
|
||||
<span className='block px-1.5 py-0.5 bg-secondary-500 text-xs text-white rounded-full ring-2 ring-white dark:ring-gray-800'>
|
||||
{shortNumberFormat(count)}
|
||||
<span className='block px-1.5 py-0.5 bg-secondary-500 text-xs font-semibold text-white rounded-full ring-2 ring-white dark:ring-gray-800'>
|
||||
{shortNumberFormat(count, countMax)}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -27,6 +27,11 @@ describe('shortNumberFormat', () => {
|
|||
expect(screen.getByTestId('num')).toHaveTextContent('•');
|
||||
});
|
||||
|
||||
test('handles max argument', () => {
|
||||
render(<div data-testid='num'>{shortNumberFormat(25, 20)}</div>, undefined, null);
|
||||
expect(screen.getByTestId('num')).toHaveTextContent('20+');
|
||||
});
|
||||
|
||||
test('formats numbers under 1,000', () => {
|
||||
render(<div data-testid='num'>{shortNumberFormat(555)}</div>, undefined, null);
|
||||
expect(screen.getByTestId('num')).toHaveTextContent('555');
|
||||
|
|
|
@ -16,7 +16,7 @@ const roundDown = (num: number) => {
|
|||
};
|
||||
|
||||
/** Display a number nicely for the UI, eg 1000 becomes 1K. */
|
||||
export const shortNumberFormat = (number: any): React.ReactNode => {
|
||||
export const shortNumberFormat = (number: any, max?: number): React.ReactNode => {
|
||||
if (!isNumber(number)) return '•';
|
||||
|
||||
let value = number;
|
||||
|
@ -29,6 +29,10 @@ export const shortNumberFormat = (number: any): React.ReactNode => {
|
|||
value = roundDown(value / 1000000);
|
||||
}
|
||||
|
||||
if (max && value > max) {
|
||||
return <span>{max}+</span>;
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
<FormattedNumber
|
||||
|
|
Loading…
Reference in a new issue