mirror of
https://github.com/mastodon/mastodon.git
synced 2026-09-28 01:59:55 -05:00
Redesign: Re-add navigation callouts for forced-single-column mode and moved account (#40589)
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
.rootLarge,
|
||||
.rootSmall {
|
||||
align-items: center;
|
||||
color: var(--color-text-primary);
|
||||
background-color: var(--color-bg-highlight);
|
||||
border-radius: var(--radius-3);
|
||||
box-sizing: border-box;
|
||||
@@ -20,6 +21,15 @@
|
||||
|
||||
.textWrapper {
|
||||
flex-grow: 1;
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
|
||||
&:hover,
|
||||
&:focus-visible {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
|
||||
@@ -19,9 +19,12 @@ import FediIcon from '@/images/icons/icon_fediverse.svg?react';
|
||||
import { fetchLists } from '@/mastodon/actions/lists';
|
||||
import { closeNavigation } from '@/mastodon/actions/navigation';
|
||||
import { fetchFollowedHashtags } from '@/mastodon/actions/tags_typed';
|
||||
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 { transientSingleColumn } from '@/mastodon/is_mobile';
|
||||
import { openNewComposer } from '@/mastodon/reducers/slices/composer';
|
||||
import { getOrderedLists } from '@/mastodon/selectors/lists';
|
||||
import { selectUnreadNotificationGroupsCount } from '@/mastodon/selectors/notifications';
|
||||
@@ -31,7 +34,7 @@ import { NavigationAccountCardAndMenu } from './account_card_and_menu';
|
||||
import { NavigationFooterLinks } from './footer_links';
|
||||
import { NavigationHeader } from './header';
|
||||
import { ListSection } from './list_section';
|
||||
import { LoggedOutInfo } from './logged_out_info';
|
||||
import { DisabledAccountBanner, LoggedOutInfo } from './logged_out_info';
|
||||
import { NavigationLink } from './navigation_link';
|
||||
import classes from './styles.module.scss';
|
||||
|
||||
@@ -74,6 +77,13 @@ function useFollowedHashtags() {
|
||||
return { followedHashtags: tags };
|
||||
}
|
||||
|
||||
const isFediverseFeedsLinkActive = (
|
||||
match: unknown,
|
||||
{ pathname }: { pathname: string },
|
||||
) => {
|
||||
return !!match || pathname.startsWith('/public');
|
||||
};
|
||||
|
||||
const MAX_HASHTAG_COUNT = 5;
|
||||
|
||||
export const RedesignNavigationPanel: React.FC<{
|
||||
@@ -121,6 +131,7 @@ export const RedesignNavigationPanel: React.FC<{
|
||||
<NavigationHeader siteName={siteName} isStuck={!isScrolledToTop} />
|
||||
{signedIn && (
|
||||
<>
|
||||
{transientSingleColumn && <TransientSingleColumnCallout />}
|
||||
<ul className={classes.list}>
|
||||
<NavigationLink
|
||||
withSpaceAfter
|
||||
@@ -152,6 +163,7 @@ export const RedesignNavigationPanel: React.FC<{
|
||||
withSpaceAfter
|
||||
to='/public/local'
|
||||
iconComponent={FediIcon}
|
||||
isActive={isFediverseFeedsLinkActive}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='tabs_bar.fediverse_feeds'
|
||||
@@ -281,7 +293,7 @@ export const RedesignNavigationPanel: React.FC<{
|
||||
)}
|
||||
{!signedIn && (
|
||||
<footer className={classes.footer} data-stuck={!isScrolledToBottom}>
|
||||
<LoggedOutInfo />
|
||||
{disabledAccountId ? <DisabledAccountBanner /> : <LoggedOutInfo />}
|
||||
<NavigationFooterLinks
|
||||
multiColumn={multiColumn}
|
||||
siteName={siteName}
|
||||
@@ -292,3 +304,19 @@ export const RedesignNavigationPanel: React.FC<{
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
const TransientSingleColumnCallout: React.FC = () => (
|
||||
<Callout className={classes.callout}>
|
||||
<FormattedMessage
|
||||
id='navigation_bar.opened_in_single_column_layout'
|
||||
defaultMessage='Posts, profiles, and other pages are opened in the single-column layout by default.'
|
||||
/>
|
||||
<br />
|
||||
<a href={`/deck${location.pathname}`}>
|
||||
<FormattedMessage
|
||||
id='navigation_bar.advanced_interface'
|
||||
defaultMessage='Open in advanced web interface'
|
||||
/>
|
||||
</a>
|
||||
</Callout>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@use '@/styles/mastodon/mixins';
|
||||
@use '@/styles/mastodon/variables';
|
||||
@use './navigation_link.module.scss' as navigation-link;
|
||||
|
||||
.root {
|
||||
@@ -26,6 +27,10 @@
|
||||
@include mixins.type-meta;
|
||||
|
||||
color: var(--color-text-secondary);
|
||||
|
||||
@media (width < variables.$mobile-menu-breakpoint) {
|
||||
min-height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.toggleIcon {
|
||||
|
||||
@@ -1,14 +1,48 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { WarningIcon } from '@phosphor-icons/react';
|
||||
|
||||
import { openModal } from '@/mastodon/actions/modal';
|
||||
import { fetchServer } from '@/mastodon/actions/server';
|
||||
import { Button } from '@/mastodon/components/button/redesign';
|
||||
import { Callout } from '@/mastodon/components/callout/redesign';
|
||||
import { Skeleton } from '@/mastodon/components/skeleton';
|
||||
import {
|
||||
disabledAccountId,
|
||||
domain,
|
||||
movedToAccountId,
|
||||
} from '@/mastodon/initial_state';
|
||||
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
|
||||
|
||||
import classes from './logged_out_info.module.scss';
|
||||
|
||||
const NavigationFooterLayout: React.FC<{
|
||||
isLoading?: boolean;
|
||||
description: React.ReactNode;
|
||||
children: React.ReactNode;
|
||||
}> = ({ description, isLoading, children }) => (
|
||||
<>
|
||||
<div className={classes.description}>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<Skeleton width='100%' />
|
||||
<br />
|
||||
<Skeleton width='100%' />
|
||||
<br />
|
||||
<Skeleton width='70%' />
|
||||
</>
|
||||
) : (
|
||||
description
|
||||
)}
|
||||
</div>
|
||||
<div className={classes.buttons}>{children}</div>
|
||||
</>
|
||||
);
|
||||
|
||||
export const LoggedOutInfo: React.FC = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { item: serverItem, isLoading } = useAppSelector(
|
||||
@@ -20,31 +54,93 @@ export const LoggedOutInfo: React.FC = () => {
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<p className={classes.description}>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<Skeleton width='100%' />
|
||||
<br />
|
||||
<Skeleton width='100%' />
|
||||
<br />
|
||||
<Skeleton width='70%' />
|
||||
</>
|
||||
) : (
|
||||
serverItem?.description
|
||||
)}
|
||||
</p>
|
||||
<div className={classes.buttons}>
|
||||
<Button as='a' href='/auth/sign_up' variant='solid'>
|
||||
<FormattedMessage
|
||||
id='server_banner.create_account'
|
||||
defaultMessage='Create an account'
|
||||
/>
|
||||
</Button>
|
||||
<Button as='a' href='/auth/sign_in'>
|
||||
<FormattedMessage id='server_banner.log_in' defaultMessage='Log in' />
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
<NavigationFooterLayout
|
||||
description={<p>{serverItem?.description ?? ''}</p>}
|
||||
isLoading={isLoading}
|
||||
>
|
||||
<Button as='a' href='/auth/sign_up' variant='solid'>
|
||||
<FormattedMessage
|
||||
id='server_banner.create_account'
|
||||
defaultMessage='Create an account'
|
||||
/>
|
||||
</Button>
|
||||
<Button as='a' href='/auth/sign_in'>
|
||||
<FormattedMessage id='server_banner.log_in' defaultMessage='Log in' />
|
||||
</Button>
|
||||
</NavigationFooterLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export const DisabledAccountBanner: React.FC = () => {
|
||||
const disabledAccount = useAppSelector((state) =>
|
||||
disabledAccountId ? state.accounts.get(disabledAccountId) : undefined,
|
||||
);
|
||||
const movedToAccount = useAppSelector((state) =>
|
||||
movedToAccountId ? state.accounts.get(movedToAccountId) : undefined,
|
||||
);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleLogOutClick = useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
dispatch(openModal({ modalType: 'CONFIRM_LOG_OUT', modalProps: {} }));
|
||||
|
||||
return false;
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
const disabledAccountLink = (
|
||||
<Link to={`/@${disabledAccount?.acct}`}>
|
||||
{disabledAccount?.acct}@{domain}
|
||||
</Link>
|
||||
);
|
||||
|
||||
return (
|
||||
<NavigationFooterLayout
|
||||
description={
|
||||
<Callout icon={WarningIcon}>
|
||||
{movedToAccount ? (
|
||||
<FormattedMessage
|
||||
id='moved_to_account_banner.text'
|
||||
defaultMessage='Your account {disabledAccount} is currently disabled because you moved to {movedToAccount}.'
|
||||
values={{
|
||||
disabledAccount: disabledAccountLink,
|
||||
movedToAccount: (
|
||||
<Link to={`/@${movedToAccount.acct}`}>
|
||||
{movedToAccount.acct.includes('@')
|
||||
? movedToAccount.acct
|
||||
: `${movedToAccount.acct}@${domain}`}
|
||||
</Link>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id='disabled_account_banner.text'
|
||||
defaultMessage='Your account {disabledAccount} is currently disabled.'
|
||||
values={{
|
||||
disabledAccount: disabledAccountLink,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Callout>
|
||||
}
|
||||
>
|
||||
<Button as='a' href='/auth/edit' variant='solid'>
|
||||
<FormattedMessage
|
||||
id='disabled_account_banner.account_settings'
|
||||
defaultMessage='Account settings'
|
||||
/>
|
||||
</Button>
|
||||
<Button onClick={handleLogOutClick}>
|
||||
<FormattedMessage
|
||||
id='confirmations.logout.confirm'
|
||||
defaultMessage='Log out'
|
||||
/>
|
||||
</Button>
|
||||
</NavigationFooterLayout>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -54,3 +54,7 @@
|
||||
gap: var(--space-1);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.callout {
|
||||
margin-inline: var(--space-4);
|
||||
}
|
||||
|
||||
@@ -1048,6 +1048,7 @@
|
||||
"navigation_bar.more": "More",
|
||||
"navigation_bar.mutes": "Muted users",
|
||||
"navigation_bar.opened_in_classic_interface": "Posts, accounts, and other specific pages are opened by default in the classic web interface.",
|
||||
"navigation_bar.opened_in_single_column_layout": "Posts, profiles, and other pages are opened in the single-column layout by default.",
|
||||
"navigation_bar.powered_by_mastodon": "powered by {logo}Mastodon",
|
||||
"navigation_bar.preferences": "Preferences",
|
||||
"navigation_bar.privacy_and_reach": "Privacy and reach",
|
||||
|
||||
Reference in New Issue
Block a user