mirror of
https://github.com/mastodon/mastodon.git
synced 2026-09-12 18:25:55 -05:00
Redesign: Update column header on many pages (#40362)
This commit is contained in:
@@ -35,9 +35,16 @@ export const WithBackButton: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const WithUnreadMarker: Story = {
|
||||
args: {
|
||||
withUnreadMarker: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithButtons: Story = {
|
||||
args: {
|
||||
withBackButton: true,
|
||||
withUnreadMarker: false,
|
||||
extraButtons: (
|
||||
<>
|
||||
<ColumnHeaderButton icon={DotsThreeIcon}>Options</ColumnHeaderButton>
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { DotsThreeIcon } from '@phosphor-icons/react';
|
||||
|
||||
import { ColumnHeaderButton } from '@/mastodon/components/column_header';
|
||||
import { Menu, MenuList, MenuTrigger } from '@/mastodon/components/menu';
|
||||
|
||||
import type { IconButtonProps } from '../button/redesign';
|
||||
|
||||
type ColumnSettingsMenuProps = {
|
||||
icon?: IconButtonProps['icon'];
|
||||
children: React.ReactNode;
|
||||
} & (
|
||||
| {
|
||||
labelPrefix?: never;
|
||||
label: React.ReactNode;
|
||||
}
|
||||
| {
|
||||
labelPrefix: React.ReactNode;
|
||||
label?: never;
|
||||
}
|
||||
);
|
||||
|
||||
export const ColumnSettingsMenu: React.FC<ColumnSettingsMenuProps> = ({
|
||||
label,
|
||||
labelPrefix,
|
||||
icon = DotsThreeIcon,
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<Menu>
|
||||
<MenuTrigger as={ColumnHeaderButton} icon={icon}>
|
||||
{labelPrefix}
|
||||
{label ?? (
|
||||
<FormattedMessage
|
||||
id='column.settings'
|
||||
defaultMessage='Column Settings'
|
||||
/>
|
||||
)}
|
||||
</MenuTrigger>
|
||||
<MenuList placement='bottom-end' strategy='absolute'>
|
||||
{children}
|
||||
</MenuList>
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
@@ -3,6 +3,7 @@ import { useCallback } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { useLocation } from 'react-router';
|
||||
|
||||
import { ArrowLeftIcon, ListIcon } from '@phosphor-icons/react';
|
||||
|
||||
@@ -17,13 +18,19 @@ import type { IconButtonProps } from '../button/redesign';
|
||||
import { Button, IconButton } from '../button/redesign';
|
||||
import { useColumn, useColumnIndexContext } from '../column/context';
|
||||
import { NavigationFocusTarget } from '../navigation_focus_target';
|
||||
import type { LocationState } from '../router';
|
||||
import { useAppHistory } from '../router';
|
||||
|
||||
import classes from './styles.module.scss';
|
||||
|
||||
export { ColumnSettingsMenu } from './column_settings_menu';
|
||||
|
||||
export interface ColumnHeaderProps {
|
||||
title: string;
|
||||
withBackButton?: boolean;
|
||||
// Set to auto to display the back button based on
|
||||
// the `fromMastodon` location state
|
||||
withBackButton?: boolean | 'auto';
|
||||
withUnreadMarker?: boolean;
|
||||
extraButtons?: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
@@ -31,17 +38,26 @@ export interface ColumnHeaderProps {
|
||||
export const ColumnHeader: React.FC<ColumnHeaderProps> = ({
|
||||
title,
|
||||
withBackButton,
|
||||
withUnreadMarker,
|
||||
extraButtons,
|
||||
className,
|
||||
...props
|
||||
}: ColumnHeaderProps) => {
|
||||
const { scrollTop } = useColumn();
|
||||
const columnIndex = useColumnIndexContext();
|
||||
const location = useLocation<LocationState>();
|
||||
const hasBackButton =
|
||||
withBackButton === true ||
|
||||
(withBackButton === 'auto' && location.state?.fromMastodon);
|
||||
|
||||
return (
|
||||
<RenderIntoTabsBarPortal>
|
||||
<header {...props} className={classNames(className, classes.root)}>
|
||||
{withBackButton ? <BackButton /> : <MobileMenuButton />}
|
||||
<header
|
||||
{...props}
|
||||
className={classNames(className, classes.root)}
|
||||
data-has-unread={withUnreadMarker}
|
||||
>
|
||||
{hasBackButton ? <BackButton /> : <MobileMenuButton />}
|
||||
<NavigationFocusTarget className={classes.title}>
|
||||
<button
|
||||
type='button'
|
||||
@@ -49,6 +65,15 @@ export const ColumnHeader: React.FC<ColumnHeaderProps> = ({
|
||||
id={getColumnSkipLinkId(columnIndex)}
|
||||
>
|
||||
{title}
|
||||
{withUnreadMarker && (
|
||||
<span className='sr-only'>
|
||||
{' '}
|
||||
<FormattedMessage
|
||||
id='column.has_unread_content'
|
||||
defaultMessage='(has unread content)'
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</NavigationFocusTarget>
|
||||
{hasReactChildren(extraButtons) && (
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { useHistory } from 'react-router';
|
||||
|
||||
import { MenuItem, MenuItemDivider } from '@/mastodon/components/menu';
|
||||
|
||||
interface MultiColumnMenuItemsProps {
|
||||
withDivider?: boolean;
|
||||
pinned: boolean;
|
||||
onPin: () => void;
|
||||
onMove?: (direction: number) => void;
|
||||
}
|
||||
|
||||
export const MultiColumnMenuItems: React.FC<MultiColumnMenuItemsProps> = ({
|
||||
withDivider = false,
|
||||
onPin,
|
||||
onMove,
|
||||
pinned,
|
||||
}) => {
|
||||
const history = useHistory();
|
||||
|
||||
const togglePin = useCallback(() => {
|
||||
if (!pinned) {
|
||||
history.replace('/');
|
||||
}
|
||||
|
||||
onPin();
|
||||
}, [history, pinned, onPin]);
|
||||
|
||||
const moveLeft = useCallback(() => {
|
||||
onMove?.(-1);
|
||||
}, [onMove]);
|
||||
|
||||
const moveRight = useCallback(() => {
|
||||
onMove?.(1);
|
||||
}, [onMove]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{withDivider && <MenuItemDivider />}
|
||||
<MenuItem onClick={togglePin} keepMenuOpenOnClick>
|
||||
{pinned ? (
|
||||
<FormattedMessage
|
||||
id='column_header.unpin_column'
|
||||
defaultMessage='Unpin column'
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id='column_header.pin_column'
|
||||
defaultMessage='Pin column'
|
||||
/>
|
||||
)}
|
||||
</MenuItem>
|
||||
{pinned && onMove && (
|
||||
<>
|
||||
<MenuItem onClick={moveLeft} keepMenuOpenOnClick>
|
||||
<FormattedMessage
|
||||
id='column_header.move_column_left'
|
||||
defaultMessage='Move column left'
|
||||
/>
|
||||
</MenuItem>
|
||||
<MenuItem onClick={moveRight} keepMenuOpenOnClick>
|
||||
<FormattedMessage
|
||||
id='column_header.move_column_right'
|
||||
defaultMessage='Move column right'
|
||||
/>
|
||||
</MenuItem>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
@use '@/styles/mastodon/mixins';
|
||||
@use '@/styles/mastodon/variables';
|
||||
|
||||
.root {
|
||||
position: relative;
|
||||
@@ -12,8 +13,6 @@
|
||||
align-items: center;
|
||||
min-height: 40px;
|
||||
padding: var(--space-sm);
|
||||
border-top-left-radius: var(--radius-xl);
|
||||
border-top-right-radius: var(--radius-xl);
|
||||
text-align: center;
|
||||
color: var(--color-text-primary);
|
||||
background: linear-gradient(
|
||||
@@ -21,12 +20,29 @@
|
||||
var(--color-bg-primary) var(--column-header-gradient-start, 55%),
|
||||
transparent
|
||||
);
|
||||
|
||||
@media (width >= variables.$mobile-menu-breakpoint) {
|
||||
border-top-left-radius: var(--radius-xl);
|
||||
border-top-right-radius: var(--radius-xl);
|
||||
}
|
||||
|
||||
&[data-has-unread='true']::after {
|
||||
content: '';
|
||||
grid-row: 1;
|
||||
grid-column: 2;
|
||||
width: var(--space-xs);
|
||||
height: var(--space-xs);
|
||||
background-color: var(--color-text-brand);
|
||||
border-radius: var(--radius-round);
|
||||
justify-self: center;
|
||||
align-self: end;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
@include mixins.type-heading-sm;
|
||||
|
||||
grid-column: 2;
|
||||
grid-area: 1 / 2;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
@@ -43,10 +59,12 @@
|
||||
}
|
||||
|
||||
.leftButton {
|
||||
grid-area: 1 / 1;
|
||||
justify-self: start;
|
||||
}
|
||||
|
||||
.rightButtons {
|
||||
grid-area: 1 / 3;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-self: end;
|
||||
|
||||
@@ -200,13 +200,15 @@ function useAssertMenuType(componentName: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export type MenuItemRadioChangeHandler = (change: { value: string }) => void;
|
||||
|
||||
interface MenuItemRadioProps extends Omit<
|
||||
MenuItemProps<'button'>,
|
||||
'as' | 'onChange' | 'icon'
|
||||
> {
|
||||
checked: boolean;
|
||||
value: string;
|
||||
onChange?: (change: { value: string }) => void;
|
||||
onChange?: MenuItemRadioChangeHandler;
|
||||
}
|
||||
|
||||
export const MenuItemRadio: React.FC<MenuItemRadioProps> = ({
|
||||
@@ -236,9 +238,14 @@ export const MenuItemRadio: React.FC<MenuItemRadioProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
export type MenuItemCheckboxChangeHandler = (change: {
|
||||
value: string;
|
||||
checked: boolean;
|
||||
}) => void;
|
||||
|
||||
interface MenuItemCheckboxProps extends Omit<MenuItemRadioProps, 'onChange'> {
|
||||
icon?: IconProp;
|
||||
onChange?: (change: { value: string; checked: boolean }) => void;
|
||||
onChange?: MenuItemCheckboxChangeHandler;
|
||||
}
|
||||
|
||||
export const MenuItemCheckbox: React.FC<MenuItemCheckboxProps> = ({
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
overflow: hidden;
|
||||
z-index: calc(infinity);
|
||||
max-width: var(--_max-card-width, 100vw);
|
||||
text-align: start;
|
||||
|
||||
&[data-elevation='2'] {
|
||||
@include mixins.elevation-2;
|
||||
|
||||
@@ -15,10 +15,14 @@ import { Account } from '@/mastodon/components/account';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
|
||||
import ScrollableList from '@/mastodon/components/scrollable_list';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { ColumnHeader as LegacyColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { isRedesignEnabled } from '@/mastodon/utils/environment';
|
||||
import { ColumnHeader } from '@/mastodon/components/column_header';
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.blocks', defaultMessage: 'Blocked users' },
|
||||
heading_redesign: { id: 'column.blocked_accounts', defaultMessage: 'Blocked Accounts' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
@@ -62,7 +66,11 @@ class Blocks extends ImmutablePureComponent {
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn}>
|
||||
<ColumnHeader icon='ban' iconComponent={BlockIcon} title={intl.formatMessage(messages.heading)} showBackButton />
|
||||
{isRedesignEnabled() ? (
|
||||
<ColumnHeader withBackButton={multiColumn && 'auto'} title={intl.formatMessage(messages.heading_redesign)} />
|
||||
) : (
|
||||
<LegacyColumnHeader icon='ban' iconComponent={BlockIcon} title={intl.formatMessage(messages.heading)} showBackButton />
|
||||
)}
|
||||
<ScrollableList
|
||||
scrollKey='blocks'
|
||||
onLoadMore={this.handleLoadMore}
|
||||
@@ -75,6 +83,13 @@ class Blocks extends ImmutablePureComponent {
|
||||
<Account key={id} id={id} defaultAction='block' />,
|
||||
)}
|
||||
</ScrollableList>
|
||||
|
||||
<Helmet>
|
||||
<title>
|
||||
{intl.formatMessage(isRedesignEnabled() ? messages.heading_redesign : messages.heading)}
|
||||
</title>
|
||||
<meta name='robots' content='noindex' />
|
||||
</Helmet>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,11 @@ import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader as LegacyColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { ColumnHeader } from '@/mastodon/components/column_header';
|
||||
import {
|
||||
ColumnHeader,
|
||||
ColumnSettingsMenu,
|
||||
} from '@/mastodon/components/column_header';
|
||||
import { MultiColumnMenuItems } from '@/mastodon/components/column_header/multicolumn_settings';
|
||||
import { isRedesignEnabled } from '@/mastodon/utils/environment';
|
||||
import BookmarksIcon from '@/material-icons/400-24px/bookmarks-fill.svg?react';
|
||||
import {
|
||||
@@ -20,7 +24,7 @@ import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.bookmarks', defaultMessage: 'Bookmarks' },
|
||||
headingRedesign: { id: 'column.saved_posts', defaultMessage: 'Saved Posts' },
|
||||
heading_redesign: { id: 'column.saved_posts', defaultMessage: 'Saved Posts' },
|
||||
});
|
||||
|
||||
const Bookmarks: React.FC<{
|
||||
@@ -78,7 +82,23 @@ const Bookmarks: React.FC<{
|
||||
label={intl.formatMessage(messages.heading)}
|
||||
>
|
||||
{isRedesignEnabled() ? (
|
||||
<ColumnHeader title={intl.formatMessage(messages.headingRedesign)} />
|
||||
<ColumnHeader
|
||||
title={intl.formatMessage(messages.heading_redesign)}
|
||||
withBackButton={multiColumn && !pinned && 'auto'}
|
||||
extraButtons={
|
||||
multiColumn && (
|
||||
<ColumnSettingsMenu
|
||||
labelPrefix={intl.formatMessage(messages.heading_redesign)}
|
||||
>
|
||||
<MultiColumnMenuItems
|
||||
pinned={pinned}
|
||||
onPin={handlePin}
|
||||
onMove={handleMove}
|
||||
/>
|
||||
</ColumnSettingsMenu>
|
||||
)
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<LegacyColumnHeader
|
||||
icon='bookmarks'
|
||||
@@ -107,7 +127,7 @@ const Bookmarks: React.FC<{
|
||||
<Helmet>
|
||||
<title>
|
||||
{isRedesignEnabled()
|
||||
? intl.formatMessage(messages.headingRedesign)
|
||||
? intl.formatMessage(messages.heading_redesign)
|
||||
: intl.formatMessage(messages.heading)}
|
||||
</title>
|
||||
<meta name='robots' content='noindex' />
|
||||
|
||||
@@ -5,8 +5,14 @@ import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { ColumnHeader as LegacyColumnHeader } from '@/mastodon/components/column/header';
|
||||
import {
|
||||
ColumnHeader,
|
||||
ColumnSettingsMenu,
|
||||
} from '@/mastodon/components/column_header';
|
||||
import { MultiColumnMenuItems } from '@/mastodon/components/column_header/multicolumn_settings';
|
||||
import { useAppDispatch } from '@/mastodon/store';
|
||||
import { isRedesignEnabled } from '@/mastodon/utils/environment';
|
||||
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
|
||||
import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
|
||||
import {
|
||||
@@ -20,6 +26,7 @@ import { ConversationsList } from './components/conversations_list';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column.direct', defaultMessage: 'Private mentions' },
|
||||
title_redesign: { id: 'tab_bar.messages', defaultMessage: 'Messages' },
|
||||
});
|
||||
|
||||
interface ColumnBase {
|
||||
@@ -64,16 +71,36 @@ const DirectTimeline: React.FC<ColumnBase> = ({ columnId, multiColumn }) => {
|
||||
bindToDocument={!multiColumn}
|
||||
label={intl.formatMessage(messages.title)}
|
||||
>
|
||||
<ColumnHeader
|
||||
icon='at'
|
||||
iconComponent={AlternateEmailIcon}
|
||||
title={intl.formatMessage(messages.title)}
|
||||
onPin={handlePin}
|
||||
onMove={handleMove}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
scrollTopOnClick
|
||||
/>
|
||||
{isRedesignEnabled() ? (
|
||||
<ColumnHeader
|
||||
title={intl.formatMessage(messages.title_redesign)}
|
||||
withBackButton={multiColumn && !pinned && 'auto'}
|
||||
extraButtons={
|
||||
multiColumn && (
|
||||
<ColumnSettingsMenu
|
||||
labelPrefix={intl.formatMessage(messages.title_redesign)}
|
||||
>
|
||||
<MultiColumnMenuItems
|
||||
onPin={handlePin}
|
||||
onMove={handleMove}
|
||||
pinned={pinned}
|
||||
/>
|
||||
</ColumnSettingsMenu>
|
||||
)
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<LegacyColumnHeader
|
||||
icon='at'
|
||||
iconComponent={AlternateEmailIcon}
|
||||
title={intl.formatMessage(messages.title)}
|
||||
onPin={handlePin}
|
||||
onMove={handleMove}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
scrollTopOnClick
|
||||
/>
|
||||
)}
|
||||
|
||||
<ConversationsList
|
||||
trackScroll={!pinned}
|
||||
@@ -109,7 +136,11 @@ const DirectTimeline: React.FC<ColumnBase> = ({ columnId, multiColumn }) => {
|
||||
/>
|
||||
|
||||
<Helmet>
|
||||
<title>{intl.formatMessage(messages.title)}</title>
|
||||
<title>
|
||||
{intl.formatMessage(
|
||||
isRedesignEnabled() ? messages.title_redesign : messages.title,
|
||||
)}
|
||||
</title>
|
||||
<meta name='robots' content='noindex' />
|
||||
</Helmet>
|
||||
</Column>
|
||||
|
||||
@@ -6,7 +6,8 @@ import { NavLink, Switch, Route } from 'react-router-dom';
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { ColumnHeader as LegacyColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { ColumnHeader } from '@/mastodon/components/column_header';
|
||||
import { isRedesignEnabled } from '@/mastodon/utils/environment';
|
||||
import TrendingUpIcon from '@/material-icons/400-24px/trending_up.svg?react';
|
||||
import { SymbolLogo } from 'mastodon/components/logo';
|
||||
@@ -22,6 +23,7 @@ import Tags from './tags';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'explore.title', defaultMessage: 'Trending' },
|
||||
titleRedesign: { id: 'tabs_bar.explore', defaultMessage: 'Explore' },
|
||||
});
|
||||
|
||||
const Explore: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
|
||||
@@ -34,13 +36,20 @@ const Explore: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
|
||||
bindToDocument={!multiColumn}
|
||||
label={intl.formatMessage(messages.title)}
|
||||
>
|
||||
<ColumnHeader
|
||||
icon={'explore'}
|
||||
iconComponent={logoRequired ? SymbolLogo : TrendingUpIcon}
|
||||
title={intl.formatMessage(messages.title)}
|
||||
multiColumn={multiColumn}
|
||||
scrollTopOnClick
|
||||
/>
|
||||
{isRedesignEnabled() ? (
|
||||
<ColumnHeader
|
||||
withBackButton={multiColumn && 'auto'}
|
||||
title={intl.formatMessage(messages.titleRedesign)}
|
||||
/>
|
||||
) : (
|
||||
<LegacyColumnHeader
|
||||
icon={'explore'}
|
||||
iconComponent={logoRequired ? SymbolLogo : TrendingUpIcon}
|
||||
title={intl.formatMessage(messages.title)}
|
||||
multiColumn={multiColumn}
|
||||
scrollTopOnClick
|
||||
/>
|
||||
)}
|
||||
|
||||
<div
|
||||
className={classNames(
|
||||
@@ -97,7 +106,11 @@ const Explore: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
|
||||
</Switch>
|
||||
|
||||
<Helmet>
|
||||
<title>{intl.formatMessage(messages.title)}</title>
|
||||
<title>
|
||||
{intl.formatMessage(
|
||||
isRedesignEnabled() ? messages.titleRedesign : messages.title,
|
||||
)}
|
||||
</title>
|
||||
<meta name='robots' content='all' />
|
||||
</Helmet>
|
||||
</Column>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
.searchHeader {
|
||||
display: flex !important;
|
||||
border-inline: none;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,13 @@ import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { ColumnHeader as LegacyColumnHeader } from '@/mastodon/components/column/header';
|
||||
import {
|
||||
ColumnHeader,
|
||||
ColumnSettingsMenu,
|
||||
} from '@/mastodon/components/column_header';
|
||||
import { MultiColumnMenuItems } from '@/mastodon/components/column_header/multicolumn_settings';
|
||||
import { isRedesignEnabled } from '@/mastodon/utils/environment';
|
||||
import StarIcon from '@/material-icons/400-24px/star-fill.svg?react';
|
||||
import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
|
||||
import {
|
||||
@@ -18,6 +24,10 @@ import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.favourites', defaultMessage: 'Favorites' },
|
||||
heading_redesign: {
|
||||
id: 'navigation_bar.liked_posts',
|
||||
defaultMessage: 'Liked Posts',
|
||||
},
|
||||
});
|
||||
|
||||
const Favourites: React.FC<{ columnId: string; multiColumn: boolean }> = ({
|
||||
@@ -74,16 +84,36 @@ const Favourites: React.FC<{ columnId: string; multiColumn: boolean }> = ({
|
||||
bindToDocument={!multiColumn}
|
||||
label={intl.formatMessage(messages.heading)}
|
||||
>
|
||||
<ColumnHeader
|
||||
icon='star'
|
||||
iconComponent={StarIcon}
|
||||
title={intl.formatMessage(messages.heading)}
|
||||
onPin={handlePin}
|
||||
onMove={handleMove}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
scrollTopOnClick
|
||||
/>
|
||||
{isRedesignEnabled() ? (
|
||||
<ColumnHeader
|
||||
title={intl.formatMessage(messages.heading_redesign)}
|
||||
withBackButton={multiColumn && !pinned && 'auto'}
|
||||
extraButtons={
|
||||
multiColumn && (
|
||||
<ColumnSettingsMenu
|
||||
labelPrefix={intl.formatMessage(messages.heading_redesign)}
|
||||
>
|
||||
<MultiColumnMenuItems
|
||||
onPin={handlePin}
|
||||
onMove={handleMove}
|
||||
pinned={pinned}
|
||||
/>
|
||||
</ColumnSettingsMenu>
|
||||
)
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<LegacyColumnHeader
|
||||
icon='star'
|
||||
iconComponent={StarIcon}
|
||||
title={intl.formatMessage(messages.heading)}
|
||||
onPin={handlePin}
|
||||
onMove={handleMove}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
scrollTopOnClick
|
||||
/>
|
||||
)}
|
||||
|
||||
<StatusList
|
||||
trackScroll={!pinned}
|
||||
|
||||
@@ -13,7 +13,7 @@ import { changeSetting } from 'mastodon/actions/settings';
|
||||
import { connectPublicStream, connectCommunityStream } from 'mastodon/actions/streaming';
|
||||
import { expandPublicTimeline, expandCommunityTimeline } from 'mastodon/actions/timelines';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { ColumnHeader as LegacyColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
|
||||
import { localLiveFeedAccess, remoteLiveFeedAccess, domain } from 'mastodon/initial_state';
|
||||
import { canViewFeed } from 'mastodon/permissions';
|
||||
@@ -21,6 +21,9 @@ import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
import SettingToggle from '../notifications/components/setting_toggle';
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
import { isRedesignEnabled } from '@/mastodon/utils/environment';
|
||||
import { ColumnHeader, ColumnSettingsMenu } from '@/mastodon/components/column_header';
|
||||
import { MultiColumnMenuItems } from '@/mastodon/components/column_header/multicolumn_settings';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column.firehose', defaultMessage: 'Live feeds' },
|
||||
@@ -32,6 +35,7 @@ const messages = defineMessages({
|
||||
id: 'column.firehose_singular',
|
||||
defaultMessage: 'Live feed',
|
||||
},
|
||||
title_redesign: { id: 'tabs_bar.fediverse_feeds', defaultMessage: 'Fediverse Feeds' },
|
||||
});
|
||||
|
||||
const ColumnSettings = () => {
|
||||
@@ -178,17 +182,30 @@ const Firehose = ({ feedType, multiColumn }) => {
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}>
|
||||
<ColumnHeader
|
||||
icon='globe'
|
||||
iconComponent={PublicIcon}
|
||||
active={hasUnread}
|
||||
title={intl.formatMessage(title)}
|
||||
onPin={handlePin}
|
||||
multiColumn={multiColumn}
|
||||
scrollTopOnClick
|
||||
>
|
||||
<ColumnSettings />
|
||||
</ColumnHeader>
|
||||
{isRedesignEnabled ? (
|
||||
<ColumnHeader
|
||||
title={intl.formatMessage(messages.title_redesign)}
|
||||
withBackButton={multiColumn && 'auto'}
|
||||
withUnreadMarker={hasUnread}
|
||||
extraButtons={multiColumn &&
|
||||
<ColumnSettingsMenu labelPrefix={intl.formatMessage(messages.title_redesign)}>
|
||||
<MultiColumnMenuItems onPin={handlePin} />
|
||||
</ColumnSettingsMenu>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<LegacyColumnHeader
|
||||
icon='globe'
|
||||
iconComponent={PublicIcon}
|
||||
active={hasUnread}
|
||||
title={intl.formatMessage(title)}
|
||||
onPin={handlePin}
|
||||
multiColumn={multiColumn}
|
||||
scrollTopOnClick
|
||||
>
|
||||
<ColumnSettings />
|
||||
</LegacyColumnHeader>
|
||||
)}
|
||||
|
||||
{(canViewFeed(signedIn, permissions, localLiveFeedAccess) && canViewFeed(signedIn, permissions, remoteLiveFeedAccess)) && (
|
||||
<div className='account__section-headline'>
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { SlidersHorizontalIcon } from '@phosphor-icons/react';
|
||||
|
||||
import { ColumnSettingsMenu } from '@/mastodon/components/column_header';
|
||||
import { MenuItemCheckbox } from '@/mastodon/components/menu';
|
||||
import type { MenuItemCheckboxChangeHandler } from '@/mastodon/components/menu/items';
|
||||
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||
|
||||
import { changeSetting } from '../../../actions/settings';
|
||||
|
||||
export const HomeColumnSettings: React.FC<{
|
||||
children?: React.ReactNode;
|
||||
}> = ({ children }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const settings = useAppSelector((state) => state.settings.get('home'));
|
||||
const onChange = useCallback<MenuItemCheckboxChangeHandler>(
|
||||
({ value, checked }) => {
|
||||
dispatch(changeSetting(['home', 'shows', value], checked));
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
// @ts-expect-error settings isn't typed yet
|
||||
const showBoosts = settings.getIn(['shows', 'reblog']) as boolean;
|
||||
// @ts-expect-error settings isn't typed yet
|
||||
const showQuotes = settings.getIn(['shows', 'quote']) as boolean;
|
||||
// @ts-expect-error settings isn't typed yet
|
||||
const showReplies = settings.getIn(['shows', 'reply']) as boolean;
|
||||
/* eslint-enable @typescript-eslint/no-unsafe-call */
|
||||
|
||||
return (
|
||||
<ColumnSettingsMenu
|
||||
icon={SlidersHorizontalIcon}
|
||||
label={
|
||||
<FormattedMessage id='home.settings' defaultMessage='Home Settings' />
|
||||
}
|
||||
>
|
||||
<MenuItemCheckbox
|
||||
value='reblog'
|
||||
checked={showBoosts}
|
||||
onChange={onChange}
|
||||
keepMenuOpenOnClick
|
||||
>
|
||||
<FormattedMessage
|
||||
id='home.column_settings.show_reblogs'
|
||||
defaultMessage='Show boosts'
|
||||
/>
|
||||
</MenuItemCheckbox>
|
||||
<MenuItemCheckbox
|
||||
value='quote'
|
||||
checked={showQuotes}
|
||||
onChange={onChange}
|
||||
keepMenuOpenOnClick
|
||||
>
|
||||
<FormattedMessage
|
||||
id='home.column_settings.show_quotes'
|
||||
defaultMessage='Show quotes'
|
||||
/>
|
||||
</MenuItemCheckbox>
|
||||
<MenuItemCheckbox
|
||||
value='reply'
|
||||
checked={showReplies}
|
||||
onChange={onChange}
|
||||
keepMenuOpenOnClick
|
||||
>
|
||||
<FormattedMessage
|
||||
id='home.column_settings.show_replies'
|
||||
defaultMessage='Show replies'
|
||||
/>
|
||||
</MenuItemCheckbox>
|
||||
{children}
|
||||
</ColumnSettingsMenu>
|
||||
);
|
||||
};
|
||||
@@ -11,7 +11,7 @@ import { connect } from 'react-redux';
|
||||
import CampaignIcon from '@/material-icons/400-24px/campaign.svg?react';
|
||||
import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { ColumnHeader as LegacyColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { injectIntl } from '@/mastodon/components/intl';
|
||||
import { SymbolLogo } from 'mastodon/components/logo';
|
||||
import { fetchAnnouncements, toggleShowAnnouncements } from 'mastodon/actions/announcements';
|
||||
@@ -28,6 +28,10 @@ import { ColumnSettings } from './components/column_settings';
|
||||
import { CriticalUpdateBanner } from './components/critical_update_banner';
|
||||
import { Announcements } from './components/announcements';
|
||||
import { AnnualReportTimeline } from '../annual_report/timeline';
|
||||
import { isRedesignEnabled } from '@/mastodon/utils/environment';
|
||||
import { ColumnHeader } from '@/mastodon/components/column_header';
|
||||
import { HomeColumnSettings } from './components/column_settings_redesign';
|
||||
import { MultiColumnMenuItems } from '@/mastodon/components/column_header/multicolumn_settings';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column.home', defaultMessage: 'Home' },
|
||||
@@ -143,21 +147,40 @@ class HomeTimeline extends PureComponent {
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}>
|
||||
<ColumnHeader
|
||||
icon='home'
|
||||
iconComponent={matchesBreakpoint ? SymbolLogo : HomeIcon}
|
||||
active={hasUnread}
|
||||
title={intl.formatMessage(messages.title)}
|
||||
onPin={this.handlePin}
|
||||
onMove={this.handleMove}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
extraButton={announcementsButton}
|
||||
appendContent={hasAnnouncements && showAnnouncements && <Announcements />}
|
||||
scrollTopOnClick
|
||||
>
|
||||
<ColumnSettings />
|
||||
</ColumnHeader>
|
||||
{isRedesignEnabled() ? (
|
||||
<ColumnHeader
|
||||
title={intl.formatMessage(messages.title)}
|
||||
withUnreadMarker={hasUnread}
|
||||
extraButtons={
|
||||
<HomeColumnSettings>
|
||||
{multiColumn &&
|
||||
<MultiColumnMenuItems
|
||||
withDivider
|
||||
onPin={this.handlePin}
|
||||
onMove={this.handleMove}
|
||||
pinned={pinned}
|
||||
/>
|
||||
}
|
||||
</HomeColumnSettings>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<LegacyColumnHeader
|
||||
icon='home'
|
||||
iconComponent={matchesBreakpoint ? SymbolLogo : HomeIcon}
|
||||
active={hasUnread}
|
||||
title={intl.formatMessage(messages.title)}
|
||||
onPin={this.handlePin}
|
||||
onMove={this.handleMove}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
extraButton={announcementsButton}
|
||||
appendContent={hasAnnouncements && showAnnouncements && <Announcements />}
|
||||
scrollTopOnClick
|
||||
>
|
||||
<ColumnSettings />
|
||||
</LegacyColumnHeader>
|
||||
)}
|
||||
|
||||
{signedIn ? (
|
||||
<StatusListContainer
|
||||
|
||||
@@ -100,7 +100,7 @@ export const NavigationAccountCardAndMenu: React.FC = () => {
|
||||
<MenuItemLink to='/favourites' icon={HeartIcon}>
|
||||
<FormattedMessage
|
||||
id='navigation_bar.liked_posts'
|
||||
defaultMessage='Liked posts'
|
||||
defaultMessage='Liked Posts'
|
||||
/>
|
||||
</MenuItemLink>
|
||||
|
||||
|
||||
@@ -449,6 +449,7 @@
|
||||
"collections.visibility_unlisted": "Unlisted",
|
||||
"collections.visibility_unlisted_hint": "Visible to anyone with a link. Hidden from search results and recommendations.",
|
||||
"column.about": "About",
|
||||
"column.blocked_accounts": "Blocked Accounts",
|
||||
"column.blocks": "Blocked users",
|
||||
"column.bookmarks": "Bookmarks",
|
||||
"column.community": "Local timeline",
|
||||
@@ -462,6 +463,7 @@
|
||||
"column.firehose_local": "Live feed for this server",
|
||||
"column.firehose_singular": "Live feed",
|
||||
"column.follow_requests": "Follow requests",
|
||||
"column.has_unread_content": "(has unread content)",
|
||||
"column.home": "Home",
|
||||
"column.list_members": "Manage list members",
|
||||
"column.lists": "Lists",
|
||||
@@ -471,14 +473,19 @@
|
||||
"column.pins": "Pinned posts",
|
||||
"column.public": "Federated timeline",
|
||||
"column.saved_posts": "Saved Posts",
|
||||
"column.settings": "Column Settings",
|
||||
"column.your_collections": "Your Collections",
|
||||
"column_back_button.label": "Back",
|
||||
"column_header.hide_settings": "Hide settings",
|
||||
"column_header.moveLeft_settings": "Move column to the left",
|
||||
"column_header.moveRight_settings": "Move column to the right",
|
||||
"column_header.move_column_left": "Move column left",
|
||||
"column_header.move_column_right": "Move column right",
|
||||
"column_header.pin": "Pin",
|
||||
"column_header.pin_column": "Pin column",
|
||||
"column_header.show_settings": "Show settings",
|
||||
"column_header.unpin": "Unpin",
|
||||
"column_header.unpin_column": "Unpin column",
|
||||
"column_search.cancel": "Cancel",
|
||||
"combobox.close_results": "Close results",
|
||||
"combobox.loading": "Loading",
|
||||
@@ -853,6 +860,7 @@
|
||||
"home.pending_critical_update.body": "Please update your Mastodon server as soon as possible!",
|
||||
"home.pending_critical_update.link": "See updates",
|
||||
"home.pending_critical_update.title": "Critical security update available!",
|
||||
"home.settings": "Home Settings",
|
||||
"home.show_announcements": "Show announcements",
|
||||
"ignore_notifications_modal.bots_title": "Ignore notifications from bots?",
|
||||
"ignore_notifications_modal.disclaimer": "Mastodon cannot inform users that you've ignored their notifications. Ignoring notifications will not stop the messages themselves from being sent.",
|
||||
@@ -979,7 +987,7 @@
|
||||
"navigation_bar.administration": "Administration",
|
||||
"navigation_bar.advanced_interface": "Open in advanced web interface",
|
||||
"navigation_bar.automated_deletion": "Automated post deletion",
|
||||
"navigation_bar.blocked_accounts": "Blocked accounts",
|
||||
"navigation_bar.blocked_accounts": "Blocked Accounts",
|
||||
"navigation_bar.blocks": "Blocked users",
|
||||
"navigation_bar.bookmarks": "Bookmarks",
|
||||
"navigation_bar.collections": "Collections",
|
||||
@@ -992,7 +1000,7 @@
|
||||
"navigation_bar.followers_and_following": "Followers & Following",
|
||||
"navigation_bar.follows_and_followers": "Follows and followers",
|
||||
"navigation_bar.import_export": "Import and export",
|
||||
"navigation_bar.liked_posts": "Liked posts",
|
||||
"navigation_bar.liked_posts": "Liked Posts",
|
||||
"navigation_bar.lists": "Lists",
|
||||
"navigation_bar.live_feed_local": "Live feed (local)",
|
||||
"navigation_bar.live_feed_public": "Live feed (public)",
|
||||
@@ -1403,6 +1411,7 @@
|
||||
"subscribed_languages.lead": "Only posts in selected languages will appear on your home and list timelines after the change. Select none to receive posts in all languages.",
|
||||
"subscribed_languages.save": "Save changes",
|
||||
"subscribed_languages.target": "Change subscribed languages for {target}",
|
||||
"tab_bar.messages": "Messages",
|
||||
"tabs_bar.create_custom_feed": "Create feed",
|
||||
"tabs_bar.custom_feeds": "Custom Feeds",
|
||||
"tabs_bar.custom_feeds_empty": "You have no custom feeds yet.",
|
||||
|
||||
@@ -8044,9 +8044,12 @@ a.status-card {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
|
||||
[data-redesign='true'] & {
|
||||
border-inline: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: ($no-gap-breakpoint - 1px)) {
|
||||
border-right: 0;
|
||||
border-left: 0;
|
||||
border-inline: none;
|
||||
}
|
||||
|
||||
button {
|
||||
|
||||
Reference in New Issue
Block a user