Improve the list selection UI for notification requests (#31457)

This commit is contained in:
Renaud Chaput 2024-08-20 00:11:58 +02:00 committed by GitHub
parent a7a2ff6c1d
commit 98bf2fc27c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 70 additions and 101 deletions

View file

@ -7,6 +7,7 @@ import { Helmet } from 'react-helmet';
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 MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
import { openModal } from 'mastodon/actions/modal';
@ -15,6 +16,7 @@ import { changeSetting } from 'mastodon/actions/settings';
import { CheckBox } from 'mastodon/components/check_box';
import Column from 'mastodon/components/column';
import ColumnHeader from 'mastodon/components/column_header';
import { Icon } from 'mastodon/components/icon';
import ScrollableList from 'mastodon/components/scrollable_list';
import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container';
@ -26,16 +28,14 @@ const messages = defineMessages({
title: { id: 'notification_requests.title', defaultMessage: 'Filtered notifications' },
maximize: { id: 'notification_requests.maximize', defaultMessage: 'Maximize' },
more: { id: 'status.more', defaultMessage: 'More' },
acceptAll: { id: 'notification_requests.accept_all', defaultMessage: 'Accept all' },
dismissAll: { id: 'notification_requests.dismiss_all', defaultMessage: 'Dismiss all' },
acceptMultiple: { id: 'notification_requests.accept_multiple', defaultMessage: '{count, plural, one {Accept # request} other {Accept # requests}}' },
dismissMultiple: { id: 'notification_requests.dismiss_multiple', defaultMessage: '{count, plural, one {Dismiss # request} other {Dismiss # requests}}' },
confirmAcceptAllTitle: { id: 'notification_requests.confirm_accept_all.title', defaultMessage: 'Accept notification 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?' },
confirmAcceptAllButton: { id: 'notification_requests.confirm_accept_all.button', defaultMessage: 'Accept all' },
confirmDismissAllTitle: { id: 'notification_requests.confirm_dismiss_all.title', defaultMessage: 'Dismiss notification 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' },
acceptMultiple: { id: 'notification_requests.accept_multiple', defaultMessage: '{count, plural, one {Accept # request…} other {Accept # requests…}}' },
dismissMultiple: { id: 'notification_requests.dismiss_multiple', defaultMessage: '{count, plural, one {Dismiss # request…} other {Dismiss # requests…}}' },
confirmAcceptMultipleTitle: { id: 'notification_requests.confirm_accept_multiple.title', defaultMessage: 'Accept notification 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?' },
confirmAcceptMultipleButton: { id: 'notification_requests.confirm_accept_multiple.button', defaultMessage: '{count, plural, one {Accept request} other {Accept requests}}' },
confirmDismissMultipleTitle: { id: 'notification_requests.confirm_dismiss_multiple.title', defaultMessage: 'Dismiss notification requests?' },
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?" },
confirmDismissMultipleButton: { id: 'notification_requests.confirm_dismiss_multiple.button', defaultMessage: '{count, plural, one {Dismiss request} other {Dismiss requests}}' },
});
const ColumnSettings = () => {
@ -74,45 +74,15 @@ const SelectRow = ({selectAllChecked, toggleSelectAll, selectedItems, selectionM
const intl = useIntl();
const dispatch = useDispatch();
const notificationRequests = useSelector(state => state.getIn(['notificationRequests', 'items']));
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(() => {
dispatch(openModal({
modalType: 'CONFIRM',
modalProps: {
title: intl.formatMessage(messages.confirmAcceptAllTitle),
message: intl.formatMessage(messages.confirmAcceptAllMessage, { count: selectedItems.length }),
confirm: intl.formatMessage(messages.confirmAcceptAllButton),
title: intl.formatMessage(messages.confirmAcceptMultipleTitle),
message: intl.formatMessage(messages.confirmAcceptMultipleMessage, { count: selectedItems.length }),
confirm: intl.formatMessage(messages.confirmAcceptMultipleButton, { count: selectedItems.length}),
onConfirm: () =>
dispatch(acceptNotificationRequests(selectedItems)),
},
@ -123,9 +93,9 @@ const SelectRow = ({selectAllChecked, toggleSelectAll, selectedItems, selectionM
dispatch(openModal({
modalType: 'CONFIRM',
modalProps: {
title: intl.formatMessage(messages.confirmDismissAllTitle),
message: intl.formatMessage(messages.confirmDismissAllMessage, { count: selectedItems.length }),
confirm: intl.formatMessage(messages.confirmDismissAllButton),
title: intl.formatMessage(messages.confirmDismissMultipleTitle),
message: intl.formatMessage(messages.confirmDismissMultipleMessage, { count: selectedItems.length }),
confirm: intl.formatMessage(messages.confirmDismissMultipleButton, { count: selectedItems.length}),
onConfirm: () =>
dispatch(dismissNotificationRequests(selectedItems)),
},
@ -136,46 +106,45 @@ const SelectRow = ({selectAllChecked, toggleSelectAll, selectedItems, selectionM
setSelectionMode((mode) => !mode);
}, [setSelectionMode]);
const menu = selectedCount === 0 ?
[
{ text: intl.formatMessage(messages.acceptAll), action: handleAcceptAll },
{ text: intl.formatMessage(messages.dismissAll), action: handleDismissAll },
] : [
{ text: intl.formatMessage(messages.acceptMultiple, { count: selectedCount }), action: handleAcceptMultiple },
{ text: intl.formatMessage(messages.dismissMultiple, { count: selectedCount }), action: handleDismissMultiple },
];
const menu = [
{ text: intl.formatMessage(messages.acceptMultiple, { count: selectedCount }), action: handleAcceptMultiple },
{ text: intl.formatMessage(messages.dismissMultiple, { count: selectedCount }), action: handleDismissMultiple },
];
const handleSelectAll = useCallback(() => {
setSelectionMode(true);
toggleSelectAll();
}, [setSelectionMode, toggleSelectAll]);
return (
<div className='column-header__select-row'>
{selectionMode && (
<div className='column-header__select-row__checkbox'>
<CheckBox checked={selectAllChecked} indeterminate={selectedCount > 0 && !selectAllChecked} onChange={toggleSelectAll} />
</div>
)}
<div className='column-header__select-row__selection-mode'>
<div className='column-header__select-row__checkbox'>
<CheckBox checked={selectAllChecked} indeterminate={selectedCount > 0 && !selectAllChecked} onChange={handleSelectAll} />
</div>
<DropdownMenuContainer
items={menu}
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}>
{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>
</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>
);
};

View file

@ -518,19 +518,17 @@
"notification.status": "{name} just posted",
"notification.update": "{name} edited a post",
"notification_requests.accept": "Accept",
"notification_requests.accept_all": "Accept all",
"notification_requests.accept_multiple": "{count, plural, one {Accept # request} other {Accept # requests}}",
"notification_requests.confirm_accept_all.button": "Accept all",
"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_all.title": "Accept notification requests?",
"notification_requests.confirm_dismiss_all.button": "Dismiss all",
"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_all.title": "Dismiss notification 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_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_multiple.title": "Accept notification requests?",
"notification_requests.confirm_dismiss_multiple.button": "{count, plural, one {Dismiss request} other {Dismiss requests}}",
"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_multiple.title": "Dismiss notification requests?",
"notification_requests.dismiss": "Dismiss",
"notification_requests.dismiss_all": "Dismiss all",
"notification_requests.dismiss_multiple": "{count, plural, one {Dismiss # request} other {Dismiss # requests}}",
"notification_requests.enter_selection_mode": "Select",
"notification_requests.exit_selection_mode": "Cancel",
"notification_requests.dismiss_multiple": "{count, plural, one {Dismiss # request…} other {Dismiss # requests…}}",
"notification_requests.edit_selection": "Edit",
"notification_requests.exit_selection": "Done",
"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.maximize": "Maximize",

View file

@ -65,4 +65,5 @@ body {
--background-color: #fff;
--background-color-tint: rgba(255, 255, 255, 80%);
--background-filter: blur(10px);
--on-surface-color: #{transparentize($ui-base-color, 0.65)};
}

View file

@ -4217,7 +4217,7 @@ a.status-card {
text-decoration: none;
&:hover {
background: lighten($ui-base-color, 2%);
background: var(--on-surface-color);
}
}
@ -4346,19 +4346,18 @@ a.status-card {
display: flex;
}
&__selection-mode {
flex-grow: 1;
.text-btn:hover {
text-decoration: underline;
}
&__select-menu:disabled {
visibility: hidden;
}
&__actions {
.icon-button {
border-radius: 4px;
border: 1px solid var(--background-border-color);
padding: 5px;
&__mode-button {
margin-left: auto;
color: $highlight-text-color;
font-weight: bold;
font-size: 14px;
&:hover {
color: lighten($highlight-text-color, 6%);
}
}
}
@ -4566,6 +4565,7 @@ a.status-card {
padding: 0;
font-family: inherit;
font-size: inherit;
font-weight: inherit;
color: inherit;
border: 0;
background: transparent;
@ -10366,7 +10366,7 @@ noscript {
cursor: pointer;
&:hover {
background: lighten($ui-base-color, 1%);
background: var(--on-surface-color);
}
.notification-request__checkbox {

View file

@ -109,5 +109,6 @@ $font-monospace: 'mastodon-font-monospace' !default;
--surface-background-color: #{darken($ui-base-color, 4%)};
--surface-variant-background-color: #{$ui-base-color};
--surface-variant-active-background-color: #{lighten($ui-base-color, 4%)};
--on-surface-color: #{transparentize($ui-base-color, 0.5)};
--avatar-border-radius: 8px;
}