From be136fe6cfba6be71954de5f251bb31e79bbc357 Mon Sep 17 00:00:00 2001 From: Chewbacca Date: Thu, 3 Nov 2022 12:13:45 -0400 Subject: [PATCH] Add max count to sidebar icons --- app/soapbox/components/icon_with_counter.tsx | 5 +++-- .../components/sidebar-navigation-link.tsx | 15 +++++++++++---- app/soapbox/components/sidebar-navigation.tsx | 1 + app/soapbox/components/thumb_navigation-link.tsx | 4 +++- app/soapbox/components/thumb_navigation.tsx | 1 + app/soapbox/components/ui/counter/counter.tsx | 8 +++++--- app/soapbox/utils/__tests__/numbers.test.tsx | 5 +++++ app/soapbox/utils/numbers.tsx | 6 +++++- 8 files changed, 34 insertions(+), 11 deletions(-) diff --git a/app/soapbox/components/icon_with_counter.tsx b/app/soapbox/components/icon_with_counter.tsx index 2d95cb9f9f..9944099427 100644 --- a/app/soapbox/components/icon_with_counter.tsx +++ b/app/soapbox/components/icon_with_counter.tsx @@ -5,18 +5,19 @@ import { Counter } from 'soapbox/components/ui'; interface IIconWithCounter extends React.HTMLAttributes { count: number, + countMax?: number icon?: string; src?: string; } -const IconWithCounter: React.FC = ({ icon, count, ...rest }) => { +const IconWithCounter: React.FC = ({ icon, count, countMax, ...rest }) => { return (
{count > 0 && ( - + )}
diff --git a/app/soapbox/components/sidebar-navigation-link.tsx b/app/soapbox/components/sidebar-navigation-link.tsx index 9a20ca4829..44d76707dc 100644 --- a/app/soapbox/components/sidebar-navigation-link.tsx +++ b/app/soapbox/components/sidebar-navigation-link.tsx @@ -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): 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 = (e) => { @@ -44,14 +46,19 @@ const SidebarNavigationLink = React.forwardRef((props: ISidebarNavigationLink, r - {text} + + {text} + + {count ? ( + + ) : null} + ); }); diff --git a/app/soapbox/components/sidebar-navigation.tsx b/app/soapbox/components/sidebar-navigation.tsx index df8c9697e6..593df75137 100644 --- a/app/soapbox/components/sidebar-navigation.tsx +++ b/app/soapbox/components/sidebar-navigation.tsx @@ -116,6 +116,7 @@ const SidebarNavigation = () => { to='/chats' icon={require('@tabler/icons/mail.svg')} count={unreadChatsCount} + countMax={20} text={} /> ); diff --git a/app/soapbox/components/thumb_navigation-link.tsx b/app/soapbox/components/thumb_navigation-link.tsx index 58a55e7e69..39c4141ff9 100644 --- a/app/soapbox/components/thumb_navigation-link.tsx +++ b/app/soapbox/components/thumb_navigation-link.tsx @@ -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, } -const ThumbNavigationLink: React.FC = ({ count, src, text, to, exact, paths }): JSX.Element => { +const ThumbNavigationLink: React.FC = ({ count, countMax, src, text, to, exact, paths }): JSX.Element => { const { pathname } = useLocation(); const isActive = (): boolean => { @@ -38,6 +39,7 @@ const ThumbNavigationLink: React.FC = ({ count, src, text, 'text-primary-500': active, })} count={count} + countMax={countMax} /> ) : ( { to='/chats' exact count={unreadChatsCount} + countMax={20} /> ); } diff --git a/app/soapbox/components/ui/counter/counter.tsx b/app/soapbox/components/ui/counter/counter.tsx index 65f1a83ce6..3ddbf00a62 100644 --- a/app/soapbox/components/ui/counter/counter.tsx +++ b/app/soapbox/components/ui/counter/counter.tsx @@ -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 = ({ count }) => { +const Counter: React.FC = ({ count, countMax }) => { return ( - - {shortNumberFormat(count)} + + {shortNumberFormat(count, countMax)} ); }; diff --git a/app/soapbox/utils/__tests__/numbers.test.tsx b/app/soapbox/utils/__tests__/numbers.test.tsx index 413cd35644..4dfbb577dd 100644 --- a/app/soapbox/utils/__tests__/numbers.test.tsx +++ b/app/soapbox/utils/__tests__/numbers.test.tsx @@ -27,6 +27,11 @@ describe('shortNumberFormat', () => { expect(screen.getByTestId('num')).toHaveTextContent('•'); }); + test('handles max argument', () => { + render(
{shortNumberFormat(25, 20)}
, undefined, null); + expect(screen.getByTestId('num')).toHaveTextContent('20+'); + }); + test('formats numbers under 1,000', () => { render(
{shortNumberFormat(555)}
, undefined, null); expect(screen.getByTestId('num')).toHaveTextContent('555'); diff --git a/app/soapbox/utils/numbers.tsx b/app/soapbox/utils/numbers.tsx index 752a2c7a0e..c4c6aaf758 100644 --- a/app/soapbox/utils/numbers.tsx +++ b/app/soapbox/utils/numbers.tsx @@ -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 {max}+; + } + return (