Improve the list selection UI for notification requests (#31457)
This commit is contained in:
		
					parent
					
						
							
								a7a2ff6c1d
							
						
					
				
			
			
				commit
				
					
						98bf2fc27c
					
				
			
		
					 5 changed files with 70 additions and 101 deletions
				
			
		|  | @ -7,6 +7,7 @@ import { Helmet } from 'react-helmet'; | ||||||
| 
 | 
 | ||||||
| import { useSelector, useDispatch } from 'react-redux'; | import { useSelector, useDispatch } from 'react-redux'; | ||||||
| 
 | 
 | ||||||
|  | import ArrowDropDownIcon from '@/material-icons/400-24px/arrow_drop_down.svg?react'; | ||||||
| import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react'; | import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react'; | ||||||
| import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; | import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; | ||||||
| import { openModal } from 'mastodon/actions/modal'; | import { openModal } from 'mastodon/actions/modal'; | ||||||
|  | @ -15,6 +16,7 @@ import { changeSetting } from 'mastodon/actions/settings'; | ||||||
| import { CheckBox } from 'mastodon/components/check_box'; | import { CheckBox } from 'mastodon/components/check_box'; | ||||||
| import Column from 'mastodon/components/column'; | import Column from 'mastodon/components/column'; | ||||||
| import ColumnHeader from 'mastodon/components/column_header'; | import ColumnHeader from 'mastodon/components/column_header'; | ||||||
|  | import { Icon } from 'mastodon/components/icon'; | ||||||
| import ScrollableList from 'mastodon/components/scrollable_list'; | import ScrollableList from 'mastodon/components/scrollable_list'; | ||||||
| import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container'; | import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container'; | ||||||
| 
 | 
 | ||||||
|  | @ -26,16 +28,14 @@ const messages = defineMessages({ | ||||||
|   title: { id: 'notification_requests.title', defaultMessage: 'Filtered notifications' }, |   title: { id: 'notification_requests.title', defaultMessage: 'Filtered notifications' }, | ||||||
|   maximize: { id: 'notification_requests.maximize', defaultMessage: 'Maximize' }, |   maximize: { id: 'notification_requests.maximize', defaultMessage: 'Maximize' }, | ||||||
|   more: { id: 'status.more', defaultMessage: 'More' }, |   more: { id: 'status.more', defaultMessage: 'More' }, | ||||||
|   acceptAll: { id: 'notification_requests.accept_all', defaultMessage: 'Accept all' }, |   acceptMultiple: { id: 'notification_requests.accept_multiple', defaultMessage: '{count, plural, one {Accept # request…} other {Accept # requests…}}' }, | ||||||
|   dismissAll: { id: 'notification_requests.dismiss_all', defaultMessage: 'Dismiss all' }, |   dismissMultiple: { id: 'notification_requests.dismiss_multiple', defaultMessage: '{count, plural, one {Dismiss # request…} other {Dismiss # requests…}}' }, | ||||||
|   acceptMultiple: { id: 'notification_requests.accept_multiple', defaultMessage: '{count, plural, one {Accept # request} other {Accept # requests}}' }, |   confirmAcceptMultipleTitle: { id: 'notification_requests.confirm_accept_multiple.title', defaultMessage: 'Accept notification requests?' }, | ||||||
|   dismissMultiple: { id: 'notification_requests.dismiss_multiple', defaultMessage: '{count, plural, one {Dismiss # request} other {Dismiss # requests}}' }, |   confirmAcceptMultipleMessage: { id: 'notification_requests.confirm_accept_multiple.message', defaultMessage: 'You are about to accept {count, plural, one {one notification request} other {# notification requests}}. Are you sure you want to proceed?' }, | ||||||
|   confirmAcceptAllTitle: { id: 'notification_requests.confirm_accept_all.title', defaultMessage: 'Accept notification requests?' }, |   confirmAcceptMultipleButton: { id: 'notification_requests.confirm_accept_multiple.button', defaultMessage: '{count, plural, one {Accept request} other {Accept requests}}' }, | ||||||
|   confirmAcceptAllMessage: { id: 'notification_requests.confirm_accept_all.message', defaultMessage: 'You are about to accept {count, plural, one {one notification request} other {# notification requests}}. Are you sure you want to proceed?' }, |   confirmDismissMultipleTitle: { id: 'notification_requests.confirm_dismiss_multiple.title', defaultMessage: 'Dismiss notification requests?' }, | ||||||
|   confirmAcceptAllButton: { id: 'notification_requests.confirm_accept_all.button', defaultMessage: 'Accept all' }, |   confirmDismissMultipleMessage: { id: 'notification_requests.confirm_dismiss_multiple.message', defaultMessage: "You are about to dismiss {count, plural, one {one notification request} other {# notification requests}}. You won't be able to easily access {count, plural, one {it} other {them}} again. Are you sure you want to proceed?" }, | ||||||
|   confirmDismissAllTitle: { id: 'notification_requests.confirm_dismiss_all.title', defaultMessage: 'Dismiss notification requests?' }, |   confirmDismissMultipleButton: { id: 'notification_requests.confirm_dismiss_multiple.button', defaultMessage: '{count, plural, one {Dismiss request} other {Dismiss requests}}' }, | ||||||
|   confirmDismissAllMessage: { id: 'notification_requests.confirm_dismiss_all.message', defaultMessage: "You are about to dismiss {count, plural, one {one notification request} other {# notification requests}}. You won't be able to easily access {count, plural, one {it} other {them}} again. Are you sure you want to proceed?" }, |  | ||||||
|   confirmDismissAllButton: { id: 'notification_requests.confirm_dismiss_all.button', defaultMessage: 'Dismiss all' }, |  | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| const ColumnSettings = () => { | const ColumnSettings = () => { | ||||||
|  | @ -74,45 +74,15 @@ const SelectRow = ({selectAllChecked, toggleSelectAll, selectedItems, selectionM | ||||||
|   const intl = useIntl(); |   const intl = useIntl(); | ||||||
|   const dispatch = useDispatch(); |   const dispatch = useDispatch(); | ||||||
| 
 | 
 | ||||||
|   const notificationRequests = useSelector(state => state.getIn(['notificationRequests', 'items'])); |  | ||||||
| 
 |  | ||||||
|   const selectedCount = selectedItems.length; |   const selectedCount = selectedItems.length; | ||||||
| 
 | 
 | ||||||
|   const handleAcceptAll = useCallback(() => { |  | ||||||
|     const items = notificationRequests.map(request => request.get('id')).toArray(); |  | ||||||
|     dispatch(openModal({ |  | ||||||
|       modalType: 'CONFIRM', |  | ||||||
|       modalProps: { |  | ||||||
|         title: intl.formatMessage(messages.confirmAcceptAllTitle), |  | ||||||
|         message: intl.formatMessage(messages.confirmAcceptAllMessage, { count: items.length }), |  | ||||||
|         confirm: intl.formatMessage(messages.confirmAcceptAllButton), |  | ||||||
|         onConfirm: () => |  | ||||||
|           dispatch(acceptNotificationRequests(items)), |  | ||||||
|       }, |  | ||||||
|     })); |  | ||||||
|   }, [dispatch, intl, notificationRequests]); |  | ||||||
| 
 |  | ||||||
|   const handleDismissAll = useCallback(() => { |  | ||||||
|     const items = notificationRequests.map(request => request.get('id')).toArray(); |  | ||||||
|     dispatch(openModal({ |  | ||||||
|       modalType: 'CONFIRM', |  | ||||||
|       modalProps: { |  | ||||||
|         title: intl.formatMessage(messages.confirmDismissAllTitle), |  | ||||||
|         message: intl.formatMessage(messages.confirmDismissAllMessage, { count: items.length }), |  | ||||||
|         confirm: intl.formatMessage(messages.confirmDismissAllButton), |  | ||||||
|         onConfirm: () => |  | ||||||
|           dispatch(dismissNotificationRequests(items)), |  | ||||||
|       }, |  | ||||||
|     })); |  | ||||||
|   }, [dispatch, intl, notificationRequests]); |  | ||||||
| 
 |  | ||||||
|   const handleAcceptMultiple = useCallback(() => { |   const handleAcceptMultiple = useCallback(() => { | ||||||
|     dispatch(openModal({ |     dispatch(openModal({ | ||||||
|       modalType: 'CONFIRM', |       modalType: 'CONFIRM', | ||||||
|       modalProps: { |       modalProps: { | ||||||
|         title: intl.formatMessage(messages.confirmAcceptAllTitle), |         title: intl.formatMessage(messages.confirmAcceptMultipleTitle), | ||||||
|         message: intl.formatMessage(messages.confirmAcceptAllMessage, { count: selectedItems.length }), |         message: intl.formatMessage(messages.confirmAcceptMultipleMessage, { count: selectedItems.length }), | ||||||
|         confirm: intl.formatMessage(messages.confirmAcceptAllButton), |         confirm: intl.formatMessage(messages.confirmAcceptMultipleButton, { count: selectedItems.length}), | ||||||
|         onConfirm: () => |         onConfirm: () => | ||||||
|           dispatch(acceptNotificationRequests(selectedItems)), |           dispatch(acceptNotificationRequests(selectedItems)), | ||||||
|       }, |       }, | ||||||
|  | @ -123,9 +93,9 @@ const SelectRow = ({selectAllChecked, toggleSelectAll, selectedItems, selectionM | ||||||
|     dispatch(openModal({ |     dispatch(openModal({ | ||||||
|       modalType: 'CONFIRM', |       modalType: 'CONFIRM', | ||||||
|       modalProps: { |       modalProps: { | ||||||
|         title: intl.formatMessage(messages.confirmDismissAllTitle), |         title: intl.formatMessage(messages.confirmDismissMultipleTitle), | ||||||
|         message: intl.formatMessage(messages.confirmDismissAllMessage, { count: selectedItems.length }), |         message: intl.formatMessage(messages.confirmDismissMultipleMessage, { count: selectedItems.length }), | ||||||
|         confirm: intl.formatMessage(messages.confirmDismissAllButton), |         confirm: intl.formatMessage(messages.confirmDismissMultipleButton, { count: selectedItems.length}), | ||||||
|         onConfirm: () => |         onConfirm: () => | ||||||
|           dispatch(dismissNotificationRequests(selectedItems)), |           dispatch(dismissNotificationRequests(selectedItems)), | ||||||
|       }, |       }, | ||||||
|  | @ -136,46 +106,45 @@ const SelectRow = ({selectAllChecked, toggleSelectAll, selectedItems, selectionM | ||||||
|     setSelectionMode((mode) => !mode); |     setSelectionMode((mode) => !mode); | ||||||
|   }, [setSelectionMode]); |   }, [setSelectionMode]); | ||||||
| 
 | 
 | ||||||
|   const menu = selectedCount === 0 ? |   const menu = [ | ||||||
|     [ |     { text: intl.formatMessage(messages.acceptMultiple, { count: selectedCount }), action: handleAcceptMultiple }, | ||||||
|       { text: intl.formatMessage(messages.acceptAll), action: handleAcceptAll }, |     { text: intl.formatMessage(messages.dismissMultiple, { count: selectedCount }), action: handleDismissMultiple }, | ||||||
|       { text: intl.formatMessage(messages.dismissAll), action: handleDismissAll }, |   ]; | ||||||
|     ] : [ | 
 | ||||||
|       { text: intl.formatMessage(messages.acceptMultiple, { count: selectedCount }), action: handleAcceptMultiple }, |   const handleSelectAll = useCallback(() => { | ||||||
|       { text: intl.formatMessage(messages.dismissMultiple, { count: selectedCount }), action: handleDismissMultiple }, |     setSelectionMode(true); | ||||||
|     ]; |     toggleSelectAll(); | ||||||
|  |   }, [setSelectionMode, toggleSelectAll]); | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div className='column-header__select-row'> |     <div className='column-header__select-row'> | ||||||
|       {selectionMode && ( |       <div className='column-header__select-row__checkbox'> | ||||||
|         <div className='column-header__select-row__checkbox'> |         <CheckBox checked={selectAllChecked} indeterminate={selectedCount > 0 && !selectAllChecked} onChange={handleSelectAll} /> | ||||||
|           <CheckBox checked={selectAllChecked} indeterminate={selectedCount > 0 && !selectAllChecked} onChange={toggleSelectAll} /> |       </div> | ||||||
|         </div> |       <DropdownMenuContainer | ||||||
|       )} |         items={menu} | ||||||
|       <div className='column-header__select-row__selection-mode'> |         icons='ellipsis-h' | ||||||
|  |         iconComponent={MoreHorizIcon} | ||||||
|  |         direction='right' | ||||||
|  |         title={intl.formatMessage(messages.more)} | ||||||
|  |       > | ||||||
|  |         <button className='dropdown-button column-header__select-row__select-menu' disabled={selectedItems.length === 0}> | ||||||
|  |           <span className='dropdown-button__label'> | ||||||
|  |             {selectedCount} selected | ||||||
|  |           </span> | ||||||
|  |           <Icon id='down' icon={ArrowDropDownIcon} /> | ||||||
|  |         </button> | ||||||
|  |       </DropdownMenuContainer> | ||||||
|  |       <div className='column-header__select-row__mode-button'> | ||||||
|         <button className='text-btn' tabIndex={0} onClick={handleToggleSelectionMode}> |         <button className='text-btn' tabIndex={0} onClick={handleToggleSelectionMode}> | ||||||
|           {selectionMode ? ( |           {selectionMode ? ( | ||||||
|             <FormattedMessage id='notification_requests.exit_selection_mode' defaultMessage='Cancel' /> |             <FormattedMessage id='notification_requests.exit_selection' defaultMessage='Done' /> | ||||||
|           ) : |           ) : | ||||||
|             ( |             ( | ||||||
|               <FormattedMessage id='notification_requests.enter_selection_mode' defaultMessage='Select' /> |               <FormattedMessage id='notification_requests.edit_selection' defaultMessage='Edit' /> | ||||||
|             )} |             )} | ||||||
|         </button> |         </button> | ||||||
|       </div> |       </div> | ||||||
|       {selectedCount > 0 && |  | ||||||
|         <div className='column-header__select-row__selected-count'> |  | ||||||
|           {selectedCount} selected |  | ||||||
|         </div> |  | ||||||
|       } |  | ||||||
|       <div className='column-header__select-row__actions'> |  | ||||||
|         <DropdownMenuContainer |  | ||||||
|           items={menu} |  | ||||||
|           icons='ellipsis-h' |  | ||||||
|           iconComponent={MoreHorizIcon} |  | ||||||
|           direction='right' |  | ||||||
|           title={intl.formatMessage(messages.more)} |  | ||||||
|         /> |  | ||||||
|       </div> |  | ||||||
|     </div> |     </div> | ||||||
|   ); |   ); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -518,19 +518,17 @@ | ||||||
|   "notification.status": "{name} just posted", |   "notification.status": "{name} just posted", | ||||||
|   "notification.update": "{name} edited a post", |   "notification.update": "{name} edited a post", | ||||||
|   "notification_requests.accept": "Accept", |   "notification_requests.accept": "Accept", | ||||||
|   "notification_requests.accept_all": "Accept all", |   "notification_requests.accept_multiple": "{count, plural, one {Accept # request…} other {Accept # requests…}}", | ||||||
|   "notification_requests.accept_multiple": "{count, plural, one {Accept # request} other {Accept # requests}}", |   "notification_requests.confirm_accept_multiple.button": "{count, plural, one {Accept request} other {Accept requests}}", | ||||||
|   "notification_requests.confirm_accept_all.button": "Accept all", |   "notification_requests.confirm_accept_multiple.message": "You are about to accept {count, plural, one {one notification request} other {# notification requests}}. Are you sure you want to proceed?", | ||||||
|   "notification_requests.confirm_accept_all.message": "You are about to accept {count, plural, one {one notification request} other {# notification requests}}. Are you sure you want to proceed?", |   "notification_requests.confirm_accept_multiple.title": "Accept notification requests?", | ||||||
|   "notification_requests.confirm_accept_all.title": "Accept notification requests?", |   "notification_requests.confirm_dismiss_multiple.button": "{count, plural, one {Dismiss request} other {Dismiss requests}}", | ||||||
|   "notification_requests.confirm_dismiss_all.button": "Dismiss all", |   "notification_requests.confirm_dismiss_multiple.message": "You are about to dismiss {count, plural, one {one notification request} other {# notification requests}}. You won't be able to easily access {count, plural, one {it} other {them}} again. Are you sure you want to proceed?", | ||||||
|   "notification_requests.confirm_dismiss_all.message": "You are about to dismiss {count, plural, one {one notification request} other {# notification requests}}. You won't be able to easily access {count, plural, one {it} other {them}} again. Are you sure you want to proceed?", |   "notification_requests.confirm_dismiss_multiple.title": "Dismiss notification requests?", | ||||||
|   "notification_requests.confirm_dismiss_all.title": "Dismiss notification requests?", |  | ||||||
|   "notification_requests.dismiss": "Dismiss", |   "notification_requests.dismiss": "Dismiss", | ||||||
|   "notification_requests.dismiss_all": "Dismiss all", |   "notification_requests.dismiss_multiple": "{count, plural, one {Dismiss # request…} other {Dismiss # requests…}}", | ||||||
|   "notification_requests.dismiss_multiple": "{count, plural, one {Dismiss # request} other {Dismiss # requests}}", |   "notification_requests.edit_selection": "Edit", | ||||||
|   "notification_requests.enter_selection_mode": "Select", |   "notification_requests.exit_selection": "Done", | ||||||
|   "notification_requests.exit_selection_mode": "Cancel", |  | ||||||
|   "notification_requests.explainer_for_limited_account": "Notifications from this account have been filtered because the account has been limited by a moderator.", |   "notification_requests.explainer_for_limited_account": "Notifications from this account have been filtered because the account has been limited by a moderator.", | ||||||
|   "notification_requests.explainer_for_limited_remote_account": "Notifications from this account have been filtered because the account or its server has been limited by a moderator.", |   "notification_requests.explainer_for_limited_remote_account": "Notifications from this account have been filtered because the account or its server has been limited by a moderator.", | ||||||
|   "notification_requests.maximize": "Maximize", |   "notification_requests.maximize": "Maximize", | ||||||
|  |  | ||||||
|  | @ -65,4 +65,5 @@ body { | ||||||
|   --background-color: #fff; |   --background-color: #fff; | ||||||
|   --background-color-tint: rgba(255, 255, 255, 80%); |   --background-color-tint: rgba(255, 255, 255, 80%); | ||||||
|   --background-filter: blur(10px); |   --background-filter: blur(10px); | ||||||
|  |   --on-surface-color: #{transparentize($ui-base-color, 0.65)}; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -4217,7 +4217,7 @@ a.status-card { | ||||||
|   text-decoration: none; |   text-decoration: none; | ||||||
| 
 | 
 | ||||||
|   &:hover { |   &:hover { | ||||||
|     background: lighten($ui-base-color, 2%); |     background: var(--on-surface-color); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -4346,19 +4346,18 @@ a.status-card { | ||||||
|     display: flex; |     display: flex; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   &__selection-mode { |   &__select-menu:disabled { | ||||||
|     flex-grow: 1; |     visibility: hidden; | ||||||
| 
 |  | ||||||
|     .text-btn:hover { |  | ||||||
|       text-decoration: underline; |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   &__actions { |   &__mode-button { | ||||||
|     .icon-button { |     margin-left: auto; | ||||||
|       border-radius: 4px; |     color: $highlight-text-color; | ||||||
|       border: 1px solid var(--background-border-color); |     font-weight: bold; | ||||||
|       padding: 5px; |     font-size: 14px; | ||||||
|  | 
 | ||||||
|  |     &:hover { | ||||||
|  |       color: lighten($highlight-text-color, 6%); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | @ -4566,6 +4565,7 @@ a.status-card { | ||||||
|   padding: 0; |   padding: 0; | ||||||
|   font-family: inherit; |   font-family: inherit; | ||||||
|   font-size: inherit; |   font-size: inherit; | ||||||
|  |   font-weight: inherit; | ||||||
|   color: inherit; |   color: inherit; | ||||||
|   border: 0; |   border: 0; | ||||||
|   background: transparent; |   background: transparent; | ||||||
|  | @ -10366,7 +10366,7 @@ noscript { | ||||||
|     cursor: pointer; |     cursor: pointer; | ||||||
| 
 | 
 | ||||||
|     &:hover { |     &:hover { | ||||||
|       background: lighten($ui-base-color, 1%); |       background: var(--on-surface-color); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .notification-request__checkbox { |     .notification-request__checkbox { | ||||||
|  |  | ||||||
|  | @ -109,5 +109,6 @@ $font-monospace: 'mastodon-font-monospace' !default; | ||||||
|   --surface-background-color: #{darken($ui-base-color, 4%)}; |   --surface-background-color: #{darken($ui-base-color, 4%)}; | ||||||
|   --surface-variant-background-color: #{$ui-base-color}; |   --surface-variant-background-color: #{$ui-base-color}; | ||||||
|   --surface-variant-active-background-color: #{lighten($ui-base-color, 4%)}; |   --surface-variant-active-background-color: #{lighten($ui-base-color, 4%)}; | ||||||
|  |   --on-surface-color: #{transparentize($ui-base-color, 0.5)}; | ||||||
|   --avatar-border-radius: 8px; |   --avatar-border-radius: 8px; | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue