From 0f5aa7194f2d533e64c025ee95c7d9860e524eb4 Mon Sep 17 00:00:00 2001 From: diondiondion Date: Fri, 25 Sep 2026 14:23:28 +0000 Subject: [PATCH] Redesign: Re-add "mark all as read" button to notifications page (#40667) --- .../components/column_settings.jsx | 11 +-- .../filtered_notifications_banner.module.scss | 6 ++ .../filtered_notifications_banner.tsx | 78 ++++++++++++---- .../notifications_permission_banner.tsx | 35 +++++--- .../components/show_announcements_button.tsx | 45 ---------- .../components/follow_requests_banner.tsx | 43 ++++----- .../features/notifications_v2/index.tsx | 89 ++++++++++++++++--- .../notifications_v2/styles.module.scss | 11 +++ app/javascript/mastodon/locales/en.json | 2 + 9 files changed, 202 insertions(+), 118 deletions(-) create mode 100644 app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.module.scss delete mode 100644 app/javascript/mastodon/features/notifications/components/show_announcements_button.tsx create mode 100644 app/javascript/mastodon/features/notifications_v2/styles.module.scss diff --git a/app/javascript/mastodon/features/notifications/components/column_settings.jsx b/app/javascript/mastodon/features/notifications/components/column_settings.jsx index e0d4e6ff73b..cd9f4f18f68 100644 --- a/app/javascript/mastodon/features/notifications/components/column_settings.jsx +++ b/app/javascript/mastodon/features/notifications/components/column_settings.jsx @@ -13,7 +13,7 @@ import GrantPermissionButton from './grant_permission_button'; import { PolicyControls } from './policy_controls'; import SettingToggle from './setting_toggle'; import { ColumnSettingsGroup } from './column_settings_group'; -import { ShowAnnouncementsButton } from './show_announcements_button'; +import { isRedesignEnabled } from '@/mastodon/utils/environment'; class ColumnSettings extends PureComponent { static propTypes = { @@ -47,10 +47,11 @@ class ColumnSettings extends PureComponent { return (
-
- - -
+ {!isRedesignEnabled() && +
+ +
+ } {alertsEnabled && browserSupport && browserPermission === 'denied' && (
diff --git a/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.module.scss b/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.module.scss new file mode 100644 index 00000000000..57d32a3089e --- /dev/null +++ b/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.module.scss @@ -0,0 +1,6 @@ +.lockup { + --lockup-padding-block: var(--space-3); + + background: var(--color-bg-secondary); + border-radius: var(--radius-3); +} diff --git a/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.tsx b/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.tsx index a1192867f5b..cec601ca042 100644 --- a/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.tsx +++ b/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.tsx @@ -4,12 +4,19 @@ import { FormattedMessage, useIntl, defineMessages } from 'react-intl'; import { Link, useHistory } from 'react-router-dom'; +import { TrayIcon } from '@phosphor-icons/react'; + +import { LockupLink, LockupWrapper } from '@/mastodon/components/lockup'; +import type { MastodonLocationDescriptor } from '@/mastodon/components/router'; +import { isRedesignEnabled } from '@/mastodon/utils/environment'; import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react'; import { fetchNotificationPolicy } from 'mastodon/actions/notification_policies'; import { Icon } from 'mastodon/components/icon'; import { selectSettingsNotificationsMinimizeFilteredBanner } from 'mastodon/selectors/settings'; import { useAppSelector, useAppDispatch } from 'mastodon/store'; +import classes from './filtered_notifications_banner.module.scss'; + const messages = defineMessages({ filteredNotifications: { id: 'notification_requests.title', @@ -80,28 +87,61 @@ export const FilteredNotificationsBanner: React.FC = () => { } return ( - -
- -
+ icon={ + isRedesignEnabled() ? ( + + ) : ( + + ) + } + title={ + + } + subtitle={ + + } + /> + ); +}; + +interface LinkBannerProps { + to: MastodonLocationDescriptor; + icon: React.ReactNode; + title: React.ReactNode; + subtitle: React.ReactNode; +} + +export const LinkBanner: React.FC = ({ + to, + icon, + title, + subtitle, +}) => { + if (isRedesignEnabled()) { + return ( + + + {title} + + + ); + } + return ( + +
{icon}
- - - - - - + {title} + {subtitle}
); diff --git a/app/javascript/mastodon/features/notifications/components/notifications_permission_banner.tsx b/app/javascript/mastodon/features/notifications/components/notifications_permission_banner.tsx index 4bdee2567a4..906572a726b 100644 --- a/app/javascript/mastodon/features/notifications/components/notifications_permission_banner.tsx +++ b/app/javascript/mastodon/features/notifications/components/notifications_permission_banner.tsx @@ -2,13 +2,16 @@ import { useCallback } from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; -import { messages as columnHeaderMessages } from '@/mastodon/components/column/header'; +import { GearIcon } from '@phosphor-icons/react'; + +import { Button } from '@/mastodon/components/button/redesign'; import { useAppDispatch } from '@/mastodon/store'; +import { isRedesignEnabled } from '@/mastodon/utils/environment'; import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import UnfoldMoreIcon from '@/material-icons/400-24px/unfold_more.svg?react'; import { requestBrowserPermission } from 'mastodon/actions/notifications'; import { changeSetting } from 'mastodon/actions/settings'; -import { Button } from 'mastodon/components/button'; +import { Button as LegacyButton } from 'mastodon/components/button'; import { Icon } from 'mastodon/components/icon'; import { IconButton } from 'mastodon/components/icon_button'; @@ -53,19 +56,31 @@ const NotificationsPermissionBanner: React.FC = () => { icon: ( ), }} />

- + {isRedesignEnabled() ? ( + + ) : ( + + + + )}
); }; diff --git a/app/javascript/mastodon/features/notifications/components/show_announcements_button.tsx b/app/javascript/mastodon/features/notifications/components/show_announcements_button.tsx deleted file mode 100644 index 4bf7661f0ff..00000000000 --- a/app/javascript/mastodon/features/notifications/components/show_announcements_button.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { useCallback } from 'react'; - -import { FormattedMessage } from 'react-intl'; - -import { NewspaperIcon } from '@phosphor-icons/react'; - -import { showAnnouncements } from '@/mastodon/actions/announcements'; -import { closeModal } from '@/mastodon/actions/modal'; -import { Button } from '@/mastodon/components/button/redesign'; -import { useAppDispatch } from '@/mastodon/store'; -import { isRedesignEnabled } from '@/mastodon/utils/environment'; - -import { useHasAnnouncements } from '../../announcements/hooks'; - -export const ShowAnnouncementsButton: React.FC = () => { - const dispatch = useAppDispatch(); - const { hasAnnouncements, shouldShowAnnouncements } = useHasAnnouncements({ - fetch: false, - }); - - const handleClick = useCallback(() => { - dispatch(showAnnouncements()); - dispatch( - closeModal({ modalType: 'NOTIFICATION_SETTINGS', ignoreFocus: false }), - ); - }, [dispatch]); - - if (!isRedesignEnabled() || !hasAnnouncements || shouldShowAnnouncements) { - return null; - } - - return ( - - ); -}; diff --git a/app/javascript/mastodon/features/notifications_v2/components/follow_requests_banner.tsx b/app/javascript/mastodon/features/notifications_v2/components/follow_requests_banner.tsx index c20fa7587b2..a76f12772ad 100644 --- a/app/javascript/mastodon/features/notifications_v2/components/follow_requests_banner.tsx +++ b/app/javascript/mastodon/features/notifications_v2/components/follow_requests_banner.tsx @@ -1,12 +1,9 @@ import { FormattedMessage } from 'react-intl'; -import { Link } from 'react-router-dom'; - import { UserPlusIcon } from '@phosphor-icons/react'; -import { Icon } from 'mastodon/components/icon'; - import { useFollowRequestsCount } from '../../navigation_panel/redesign'; +import { LinkBanner } from '../../notifications/components/filtered_notifications_banner'; /** * This banner is only shown to users whose notification policy filters @@ -21,26 +18,22 @@ export const FollowRequestsBanner: React.FC = () => { } return ( - -
- -
- -
- - - - - - -
- + } + title={ + + } + subtitle={ + + } + /> ); }; diff --git a/app/javascript/mastodon/features/notifications_v2/index.tsx b/app/javascript/mastodon/features/notifications_v2/index.tsx index 6ec3ccb45c5..9c5fc43a7ff 100644 --- a/app/javascript/mastodon/features/notifications_v2/index.tsx +++ b/app/javascript/mastodon/features/notifications_v2/index.tsx @@ -2,11 +2,17 @@ import { useCallback, useEffect, useMemo } from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; -import { GearIcon } from '@phosphor-icons/react'; +import { + ChecksIcon, + GearIcon, + NewspaperIcon, + TrashIcon, +} from '@phosphor-icons/react'; import { Helmet } from '@unhead/react/helmet'; import { isEqual } from 'lodash'; import { useDebouncedCallback } from 'use-debounce'; +import { toggleShowAnnouncements } from '@/mastodon/actions/announcements'; import { addColumn, removeColumn, @@ -23,6 +29,7 @@ import { } from '@/mastodon/components/column_header'; import { MultiColumnMenuItems } from '@/mastodon/components/column_header/multicolumn_settings'; import { LoadGap } from '@/mastodon/components/load_gap'; +import { MenuItem, MenuItemDivider } from '@/mastodon/components/menu'; import ScrollableList from '@/mastodon/components/scrollable_list'; import { isRedesignEnabled } from '@/mastodon/utils/environment'; import DoneAllIcon from '@/material-icons/400-24px/done_all.svg?react'; @@ -64,6 +71,7 @@ import ColumnSettingsContainer from '../notifications/containers/column_settings import { FollowRequestsBanner } from './components/follow_requests_banner'; import { NotificationGroup } from './components/notification_group'; import { FilterBar } from './filter_bar'; +import classes from './styles.module.scss'; const messages = defineMessages({ title: { id: 'column.notifications', defaultMessage: 'Notifications' }, @@ -71,6 +79,10 @@ const messages = defineMessages({ id: 'notifications.mark_as_read', defaultMessage: 'Mark every notification as read', }, + markAsReadRedesign: { + id: 'notifications.mark_all_as_read', + defaultMessage: 'Mark all as read', + }, }); export const Notifications: React.FC<{ @@ -172,11 +184,6 @@ export const Notifications: React.FC<{ [dispatch, columnId], ); - const handleMarkAsRead = useCallback(() => { - dispatch(markNotificationsAsRead()); - void dispatch(submitMarkers({ immediate: true })); - }, [dispatch]); - const openSettingsModal = useCallback(() => { dispatch( openModal({ @@ -186,6 +193,21 @@ export const Notifications: React.FC<{ ); }, [dispatch]); + const handleMarkAsRead = useCallback(() => { + dispatch(markNotificationsAsRead()); + void dispatch(submitMarkers({ immediate: true })); + }, [dispatch]); + + const handleToggleAnnouncements = useCallback(() => { + dispatch(toggleShowAnnouncements()); + }, [dispatch]); + + const handleClearNotifications = useCallback(() => { + dispatch( + openModal({ modalType: 'CONFIRM_CLEAR_NOTIFICATIONS', modalProps: {} }), + ); + }, [dispatch]); + const pinned = !!columnId; const emptyMessage = ( {needsNotificationPermission && } {shouldShowAnnouncements && } - - +
+ {isRedesignEnabled() && } + +
); @@ -292,17 +316,54 @@ export const Notifications: React.FC<{ defaultMessage='Notification Settings' /> - {multiColumn && ( - + + {intl.formatMessage(messages.markAsReadRedesign)} + + {hasAnnouncements && ( + + {shouldShowAnnouncements ? ( + + ) : ( + + )} + + )} + + + + + {multiColumn && ( - - )} + )} + } extraStickyContent={filterBar} diff --git a/app/javascript/mastodon/features/notifications_v2/styles.module.scss b/app/javascript/mastodon/features/notifications_v2/styles.module.scss new file mode 100644 index 00000000000..716add389bf --- /dev/null +++ b/app/javascript/mastodon/features/notifications_v2/styles.module.scss @@ -0,0 +1,11 @@ +.topLinks { + display: flex; + flex-wrap: wrap; + gap: var(--space-4); + margin: var(--space-4) var(--space-4) var(--space-2); + + > * { + min-width: 250px; + flex: 1 1 0; + } +} diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index af5835a4e8b..2d2249a9b25 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -1183,6 +1183,8 @@ "notifications.filter.statuses": "Updates from people you follow", "notifications.grant_permission": "Grant permission.", "notifications.group": "{count} notifications", + "notifications.hide_server_announcements": "Hide server announcements", + "notifications.mark_all_as_read": "Mark all as read", "notifications.mark_as_read": "Mark every notification as read", "notifications.permission_denied": "Desktop notifications are unavailable due to previously denied browser permissions request", "notifications.permission_denied_alert": "Desktop notifications can't be enabled, as browser permission has been denied before",