Redesign: Improve logged-out UX of main navigation, implement Fediverse Feeds display logic (#40780)

This commit is contained in:
diondiondion
2026-09-30 15:44:45 +00:00
committed by GitHub
parent 6e12a96231
commit 1d67e7de96
7 changed files with 115 additions and 58 deletions

View File

@@ -35,7 +35,8 @@ const messages = defineMessages({
id: 'column.firehose_singular',
defaultMessage: 'Live feed',
},
title_redesign: { id: 'tabs_bar.fediverse_feeds', defaultMessage: 'Fediverse Feeds' },
title_redesign: { id: 'tabs_bar.public_feeds', defaultMessage: 'Public Feeds' },
title_singular_redesign: { id: 'tabs_bar.public_feed', defaultMessage: 'Public Feed' },
});
const ColumnSettings = () => {
@@ -170,21 +171,31 @@ const Firehose = ({ feedType, multiColumn }) => {
/>
);
let title;
const canViewLocalFeed = canViewFeed(signedIn, permissions, localLiveFeedAccess);
const canViewRemoteFeed = canViewFeed(signedIn, permissions, remoteLiveFeedAccess);
if (canViewFeed(signedIn, permissions, localLiveFeedAccess) && canViewFeed(signedIn, permissions, remoteLiveFeedAccess)) {
let title;
if (canViewLocalFeed && canViewRemoteFeed) {
title = messages.title;
} else if (canViewFeed(signedIn, permissions, localLiveFeedAccess)) {
} else if (canViewLocalFeed) {
title = messages.title_local;
} else {
title = messages.title_singular;
}
if (isRedesignEnabled()) {
const canOnlyViewSingleFeed = canViewLocalFeed !== canViewRemoteFeed;
title = canOnlyViewSingleFeed
? intl.formatMessage(messages.title_singular_redesign)
: intl.formatMessage(messages.title_redesign);
}
return (
<Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}>
{isRedesignEnabled() ? (
<ColumnHeader
title={intl.formatMessage(messages.title_redesign)}
title={title}
withBackButton={multiColumn && 'auto'}
withUnreadMarker={hasUnread}
extraButtons={multiColumn &&

View File

@@ -13,6 +13,7 @@ import {
ChatCircleDotsIcon,
BookmarkSimpleIcon,
PlusIcon,
InfoIcon,
} from '@phosphor-icons/react';
import FediIcon from '@/images/icons/icon_fediverse.svg?react';
@@ -25,8 +26,13 @@ import { Callout } from '@/mastodon/components/callout/redesign';
import { FOCUS_TARGET } from '@/mastodon/components/navigation_focus_target';
import { useScrollSensor } from '@/mastodon/hooks/useScrollSensor';
import { useIdentity } from '@/mastodon/identity_context';
import { disabledAccountId } from '@/mastodon/initial_state';
import {
disabledAccountId,
localLiveFeedAccess,
remoteLiveFeedAccess,
} from '@/mastodon/initial_state';
import { transientSingleColumn } from '@/mastodon/is_mobile';
import { canViewFeed } from '@/mastodon/permissions';
import { openNewComposer } from '@/mastodon/reducers/slices/composer';
import { getOrderedLists } from '@/mastodon/selectors/lists';
import { selectUnreadNotificationGroupsCount } from '@/mastodon/selectors/notifications';
@@ -189,30 +195,8 @@ export const RedesignNavigationPanel: React.FC<{
<NavigationLink to='/home' iconComponent={HouseIcon}>
<FormattedMessage id='tabs_bar.home' defaultMessage='Home' />
</NavigationLink>
<NavigationLink
to={{
pathname: '/explore',
state: { focusTarget: FOCUS_TARGET.SEARCH },
}}
iconComponent={MagnifyingGlassIcon}
onClick={invokeVirtualIosKeyboard}
>
<FormattedMessage
id='tabs_bar.explore'
defaultMessage='Explore'
/>
</NavigationLink>
<NavigationLink
withSpaceAfter
to='/public/local'
iconComponent={FediIcon}
isActive={isFediverseFeedsLinkActive}
>
<FormattedMessage
id='tabs_bar.fediverse_feeds'
defaultMessage='Fediverse Feeds'
/>
</NavigationLink>
<ExploreLink />
<PublicFeedsLink />
<ListSection
id='custom-feeds'
title={
@@ -317,19 +301,87 @@ export const RedesignNavigationPanel: React.FC<{
</>
)}
{!signedIn && (
<footer className={classes.footer} data-stuck={!isScrolledToBottom}>
{disabledAccountId ? <DisabledAccountBanner /> : <LoggedOutInfo />}
<NavigationFooterLinks
multiColumn={multiColumn}
siteName={siteName}
/>
</footer>
<>
<ul className={classes.list}>
<NavigationLink to='/about' iconComponent={InfoIcon}>
<FormattedMessage
id='footer.about_this_server'
defaultMessage='About'
/>
</NavigationLink>
<ExploreLink />
<PublicFeedsLink />
</ul>
<footer className={classes.footer} data-stuck={!isScrolledToBottom}>
{disabledAccountId ? <DisabledAccountBanner /> : <LoggedOutInfo />}
<NavigationFooterLinks
multiColumn={multiColumn}
siteName={siteName}
/>
</footer>
</>
)}
{bottomSensor}
</nav>
);
};
const ExploreLink: React.FC = () => {
return (
<NavigationLink
to={{
pathname: '/explore',
state: { focusTarget: FOCUS_TARGET.SEARCH },
}}
iconComponent={MagnifyingGlassIcon}
onClick={invokeVirtualIosKeyboard}
>
<FormattedMessage id='tabs_bar.explore' defaultMessage='Explore' />
</NavigationLink>
);
};
const PublicFeedsLink: React.FC = () => {
const { signedIn, permissions } = useIdentity();
const canViewLocalFeed = canViewFeed(
signedIn,
permissions,
localLiveFeedAccess,
);
const canViewRemoteFeed = canViewFeed(
signedIn,
permissions,
remoteLiveFeedAccess,
);
if (!canViewLocalFeed && !canViewRemoteFeed) {
return null;
}
const canViewOnlyOneFeed = canViewLocalFeed !== canViewRemoteFeed;
return (
<NavigationLink
to={canViewLocalFeed ? '/public/local' : '/public/remote'}
iconComponent={FediIcon}
isActive={isFediverseFeedsLinkActive}
>
{canViewOnlyOneFeed ? (
<FormattedMessage
id='tabs_bar.public_feed'
defaultMessage='Public Feed'
/>
) : (
<FormattedMessage
id='tabs_bar.public_feeds'
defaultMessage='Public Feeds'
/>
)}
</NavigationLink>
);
};
const TransientSingleColumnCallout: React.FC = () => (
<Callout className={classes.callout}>
<FormattedMessage

View File

@@ -3,9 +3,7 @@
@use './navigation_link.module.scss' as navigation-link;
.root {
&:not(:last-child) {
margin-bottom: var(--space-4);
}
padding-top: var(--space-4);
:any-link {
color: inherit;

View File

@@ -58,13 +58,19 @@ export const LoggedOutInfo: React.FC = () => {
description={<p>{serverItem?.description ?? ''}</p>}
isLoading={isLoading}
>
<Button as='a' href='/auth/sign_up' variant='solid'>
<Button
as='a'
href='/auth/sign_up'
size='lg'
variant='solid'
color='accent'
>
<FormattedMessage
id='server_banner.create_account'
defaultMessage='Create an account'
/>
</Button>
<Button as='a' href='/auth/sign_in'>
<Button as='a' href='/auth/sign_in' size='lg'>
<FormattedMessage id='server_banner.log_in' defaultMessage='Log in' />
</Button>
</NavigationFooterLayout>
@@ -129,7 +135,7 @@ export const DisabledAccountBanner: React.FC = () => {
</Callout>
}
>
<Button as='a' href='/auth/edit' variant='solid'>
<Button as='a' href='/auth/edit' variant='solid' color='accent'>
<FormattedMessage
id='disabled_account_banner.account_settings'
defaultMessage='Account settings'

View File

@@ -5,10 +5,6 @@
padding-bottom: var(--space-half);
}
.wrapperWithSpace {
padding-bottom: var(--space-4);
}
@mixin link-base {
--icon-size: 20px;
--border-radius: var(--radius-3);
@@ -49,14 +45,14 @@
@include link-base;
min-height: 40px;
@include mixins.type-body;
@include mixins.type-body-compact;
@media (width < variables.$mobile-menu-breakpoint) {
min-height: 48px;
}
&[aria-current='page']:not(:where(.linkStacked, .linkMobile)) {
@include mixins.type-body-strong;
font-weight: bold;
}
}

View File

@@ -15,7 +15,6 @@ type NavigationLinkProps = {
stacked?: boolean;
iconComponent?: Icon | React.FC<SVGProps<SVGSVGElement>>;
badgeCount?: number;
withSpaceAfter?: boolean;
} & (
| ({ as?: 'button' } & React.ComponentPropsWithRef<'button'>)
| ({ as?: 'link' } & NavLinkProps)
@@ -26,7 +25,6 @@ export const NavigationLink: React.FC<NavigationLinkProps> = ({
as = 'link',
iconComponent: IconComp,
badgeCount = 0,
withSpaceAfter,
children,
...otherProps
}) => {
@@ -40,12 +38,7 @@ export const NavigationLink: React.FC<NavigationLinkProps> = ({
);
return (
<li
className={classNames(
classes.wrapper,
withSpaceAfter && classes.wrapperWithSpace,
)}
>
<li className={classes.wrapper}>
<Comp
{...otherProps}
type={as === 'button' ? 'button' : undefined}

View File

@@ -1507,13 +1507,14 @@
"tabs_bar.create_custom_feed": "Create Feed",
"tabs_bar.custom_feeds": "Custom Feeds",
"tabs_bar.explore": "Explore",
"tabs_bar.fediverse_feeds": "Fediverse Feeds",
"tabs_bar.followed_hashtags": "Followed Hashtags",
"tabs_bar.followed_tags_view_all": "View all",
"tabs_bar.home": "Home",
"tabs_bar.menu": "Menu",
"tabs_bar.messages": "Messages",
"tabs_bar.notifications": "Notifications",
"tabs_bar.public_feed": "Public Feed",
"tabs_bar.public_feeds": "Public Feeds",
"tabs_bar.publish": "New Post",
"tabs_bar.quick_links": "Quick links",
"tabs_bar.saved": "Saved",