Status: Move old components (#40559)

This commit is contained in:
Echo
2026-09-17 09:13:30 +00:00
committed by GitHub
parent 48d1cf13eb
commit bcdcb04e85
42 changed files with 391 additions and 354 deletions

View File

@@ -67,10 +67,10 @@ import {
MenuList,
MenuTrigger,
} from '../menu';
import { RemoveQuoteHint } from '../status_action_bar/remove_quote_hint';
import { boostItemState, quoteItemState } from './boost_button_utils';
import { useStatusContext } from './hooks';
import { RemoveQuoteHint } from './legacy/action_bar/remove_quote_hint';
import classes from './styles.module.scss';
interface StatusActionBarProps {

View File

@@ -21,10 +21,10 @@ import { useAppDispatch, useAppSelector } from '@/mastodon/store';
import { compareUrls } from '@/mastodon/utils/compare_urls';
import { Card, CardBody, CardTitle } from '../card';
import { PictureInPicturePlaceholder } from '../picture_in_picture_placeholder';
import { RelativeTimestamp } from '../relative_timestamp';
import { useStatusContext } from './hooks';
import { PictureInPicturePlaceholder } from './legacy/picture_in_picture_placeholder';
import { StatusQuote } from './quote';
export const StatusAttachments: React.FC<{

View File

@@ -1,132 +1,108 @@
import type { FC, HTMLAttributes, MouseEventHandler, ReactNode } from 'react';
import { useId } from 'react';
import { defineMessage, useIntl } from 'react-intl';
import { FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import { Link } from 'react-router-dom';
import type { Account, AccountShapeFull } from '@/mastodon/models/account';
import { selectAccountStatus } from '@/mastodon/selectors/statuses';
import { useAppSelector } from '@/mastodon/store';
import type { AccountStatusShape } from '@/mastodon/models/status';
import { Avatar } from '../avatar';
import { AvatarOverlay } from '../avatar_overlay';
import type { DisplayNameProps } from '../display_name';
import { LinkedDisplayName } from '../display_name';
import { DisplayName } from '../display_name';
import { useAccountHandle } from '../display_name/default';
import { RelativeTimestamp } from '../relative_timestamp';
import { VisibilityIcon } from '../visibility_icon';
import { Skeleton } from '../skeleton';
export interface StatusHeaderProps {
statusId: string;
account?: Account | AccountShapeFull;
avatarSize?: number;
contentBeforeDate?: ReactNode;
contentAfterDate?: ReactNode;
wrapperProps?: HTMLAttributes<HTMLDivElement>;
displayNameProps?: DisplayNameProps;
onHeaderClick?: MouseEventHandler<HTMLDivElement>;
import classes from './header.module.scss';
import { statusLink } from './utils';
interface StatusRedesignHeaderProps {
status: Pick<
AccountStatusShape,
'id' | 'account' | 'created_at' | 'visibility'
>;
children?: React.ReactNode;
className?: string;
featured?: boolean;
}
export type StatusHeaderRenderFn = (args: StatusHeaderProps) => ReactNode;
export const StatusHeader: FC<StatusHeaderProps> = ({
statusId,
account,
export const StatusRedesignHeader: React.FC<StatusRedesignHeaderProps> = ({
status,
children,
className,
avatarSize = 48,
wrapperProps,
contentBeforeDate,
contentAfterDate,
onHeaderClick,
}) => {
const status = useAppSelector((state) =>
selectAccountStatus(state, statusId),
const account = status.account;
const handle = useAccountHandle(account);
const handleId = useId();
const accountLinkProps = {
to: {
pathname: `/@${account.acct}`,
state: { reference: 'status' },
},
title: `@${account.acct}`,
'data-id': account.id,
'data-hover-card-account': account.id,
'data-hover-card-reference': 'status',
};
let displayName = (
<Link
{...accountLinkProps}
className={classes.headerNameLink}
aria-describedby={handleId}
>
<DisplayName account={account} variant='noDomain' />
</Link>
);
if (!status) {
return null;
if (status.visibility === 'private') {
displayName = (
<FormattedMessage
id='status.header.to_followers'
defaultMessage='{displayName} to Followers'
tagName='span'
values={{ displayName }}
/>
);
}
const statusAccount = status.account;
const editedAt = status.edited_at;
return (
/* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
<div
onClick={onHeaderClick}
onAuxClick={onHeaderClick}
{...wrapperProps}
className={classNames('status__info', className)}
/* eslint-enable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
>
<StatusDisplayName
statusAccount={statusAccount}
friendAccount={account}
avatarSize={avatarSize}
/>
{contentBeforeDate}
<header className={classNames(className, classes.header)}>
<Link
to={`/@${statusAccount.acct}/${status.id}`}
className='status__relative-time'
{...accountLinkProps}
role='presentation'
tabIndex={-1}
className={classes.headerAvatar}
>
<span className='status__visibility-icon'>
<VisibilityIcon visibility={status.visibility} />
</span>
<RelativeTimestamp timestamp={status.created_at} />
{editedAt && <StatusEditedAt editedAt={editedAt} />}
<Avatar account={account} size={null} />
</Link>
{contentAfterDate}
</div>
);
};
<div>
<p className={classes.headerName}>
{displayName}
&bull;
<Link
to={{
pathname: statusLink(status),
state: { reference: 'status' },
}}
>
<RelativeTimestamp timestamp={status.created_at} />
</Link>
</p>
const editMessage = defineMessage({
id: 'status.edited',
defaultMessage: 'Edited {date}',
});
const StatusEditedAt: FC<{ editedAt: string }> = ({ editedAt }) => {
const intl = useIntl();
return (
<abbr
title={intl.formatMessage(editMessage, {
date: intl.formatDate(editedAt, {
year: 'numeric',
month: 'short',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
}),
})}
>
{' '}
*
</abbr>
);
};
const StatusDisplayName: FC<{
statusAccount?: AccountShapeFull;
friendAccount?: Account | AccountShapeFull;
avatarSize: number;
}> = ({ statusAccount, friendAccount, avatarSize }) => {
const AccountComponent = friendAccount ? AvatarOverlay : Avatar;
return (
<LinkedDisplayName
displayProps={{ account: statusAccount }}
className='status__display-name'
reference='status'
>
<div className='status__avatar'>
<AccountComponent
account={statusAccount}
friend={friendAccount}
size={avatarSize}
/>
<p className={classes.headerHandle}>
<Link
{...accountLinkProps}
role='presentation'
tabIndex={-1}
id={handleId}
>
{handle ?? <Skeleton width='7ch' />}
</Link>
</p>
</div>
</LinkedDisplayName>
{children}
</header>
);
};

View File

@@ -0,0 +1,24 @@
import { lazy, Suspense } from 'react';
import { isRedesignStatusEnabled } from '@/mastodon/utils/environment';
import { LoadingIndicator } from '../loading_indicator';
import { StatusQuoteManager } from './legacy/quoted';
import type { StatusContainerProps } from './types';
const LazyStatusRedesign = lazy(() =>
import('./status').then(({ StatusRedesign }) => ({
default: StatusRedesign,
})),
);
const StatusRedesign = (props: StatusContainerProps) => (
<Suspense fallback={<LoadingIndicator />}>
<LazyStatusRedesign {...props} />
</Suspense>
);
export const Status = isRedesignStatusEnabled()
? StatusRedesign
: StatusQuoteManager;

View File

@@ -19,14 +19,14 @@ import { identityContextPropShape, withIdentity } from 'mastodon/identity_contex
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
import { Dropdown } from 'mastodon/components/dropdown_menu';
import { me, quickBoosting } from '../../initial_state';
import { Dropdown } from '@/mastodon/components/dropdown_menu';
import { me, quickBoosting } from '@/mastodon/initial_state';
import { IconButton } from '../icon_button';
import { injectIntl } from '../intl';
import { BoostButton } from '../status/boost_button';
import { IconButton } from '@/mastodon/components/icon_button';
import { injectIntl } from '@/mastodon/components/intl';
import { BoostButton } from '../boost_button';
import { RemoveQuoteHint } from './remove_quote_hint';
import { quoteItemState } from '../status/boost_button_utils';
import { quoteItemState } from '../../boost_button_utils';
import { selectStatusConditions } from '@/mastodon/selectors/statuses';

View File

@@ -4,13 +4,12 @@ import { FormattedMessage, useIntl } from 'react-intl';
import classNames from 'classnames';
import { Button } from '@/mastodon/components/button';
import { Icon } from '@/mastodon/components/icon';
import { Popover } from '@/mastodon/components/popover';
import { useDismissible } from '@/mastodon/hooks/useDismissible';
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
import { Button } from '../button';
import { Icon } from '../icon';
import { Popover } from '../popover';
import classes from './remove_quote_hint.module.css';
const DISMISSIBLE_BANNER_ID = 'notifications/remove_quote_hint';

View File

@@ -3,7 +3,7 @@ import { useCallback, useRef, useId } from 'react';
import { FormattedMessage } from 'react-intl';
import { AnimateEmojiProvider } from './emoji/context';
import { AnimateEmojiProvider } from '../../emoji/context';
export enum BannerVariant {
Warning = 'warning',

View File

@@ -11,17 +11,23 @@ import { quoteComposeById } from '@/mastodon/actions/compose_typed';
import { toggleReblog } from '@/mastodon/actions/interactions';
import { openModal } from '@/mastodon/actions/modal';
import { fetchStatus } from '@/mastodon/actions/statuses';
import type { RenderItemFn } from '@/mastodon/components/dropdown_menu';
import {
Dropdown,
DropdownMenuItemContent,
} from '@/mastodon/components/dropdown_menu';
import { IconButton } from '@/mastodon/components/icon_button';
import { useStatus } from '@/mastodon/hooks/useStatus';
import { quickBoosting } from '@/mastodon/initial_state';
import type { ActionMenuItem } from '@/mastodon/models/dropdown_menu';
import { selectStatusConditions } from '@/mastodon/selectors/statuses';
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
import type { RenderItemFn } from '../dropdown_menu';
import { Dropdown, DropdownMenuItemContent } from '../dropdown_menu';
import { IconButton } from '../icon_button';
import { boostItemState, messages, quoteItemState } from './boost_button_utils';
import {
boostItemState,
messages,
quoteItemState,
} from '../boost_button_utils';
const StandaloneBoostButton: FC<ReblogButtonProps> = ({
statusId,

View File

@@ -3,21 +3,21 @@ import { connect } from 'react-redux';
import {
unmuteAccount,
unblockAccount,
} from '../actions/accounts';
import { initBlockModal } from '../actions/blocks';
} from '@/mastodon/actions/accounts';
import { initBlockModal } from '@/mastodon/actions/blocks';
import {
replyCompose,
mentionCompose,
directCompose,
} from '../actions/compose';
import { quoteComposeById } from '../actions/compose_typed';
} from '@/mastodon/actions/compose';
import { quoteComposeById } from '@/mastodon/actions/compose_typed';
import {
initDomainBlockModal,
unblockDomain,
} from '../actions/domain_blocks';
} from '@/mastodon/actions/domain_blocks';
import {
initAddFilter,
} from '../actions/filters';
} from '@/mastodon/actions/filters';
import {
toggleReblog,
toggleFavourite,
@@ -25,11 +25,11 @@ import {
unbookmark,
pin,
unpin,
} from '../actions/interactions';
import { openModal } from '../actions/modal';
import { initMuteModal } from '../actions/mutes';
import { deployPictureInPicture } from '../actions/picture_in_picture';
import { initReport } from '../actions/reports';
} from '@/mastodon/actions/interactions';
import { openModal } from '@/mastodon/actions/modal';
import { initMuteModal } from '@/mastodon/actions/mutes';
import { deployPictureInPicture } from '@/mastodon/actions/picture_in_picture';
import { initReport } from '@/mastodon/actions/reports';
import {
muteStatus,
unmuteStatus,
@@ -39,12 +39,13 @@ import {
editStatus,
translateStatus,
undoStatusTranslation,
} from '../actions/statuses';
import { setStatusQuotePolicy } from '../actions/statuses_typed';
import { injectIntl } from '../components/intl';
import Status from '../components/status';
import { deleteModal } from '../initial_state';
import { makeGetStatus, makeGetPictureInPicture } from '../selectors';
} from '@/mastodon/actions/statuses';
import { setStatusQuotePolicy } from '@/mastodon/actions/statuses_typed';
import { injectIntl } from '@/mastodon/components/intl';
import { deleteModal } from '@/mastodon/initial_state';
import { makeGetStatus, makeGetPictureInPicture } from '@/mastodon/selectors';
import Status from './status';
const makeMapStateToProps = () => {
const getStatus = makeGetStatus();

View File

@@ -10,15 +10,15 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
import { Icon } from 'mastodon/components/icon';
import { Poll } from 'mastodon/components/poll';
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
import { languages as preloadedLanguages } from 'mastodon/initial_state';
import { Icon } from '@/mastodon/components/icon';
import { Poll } from '@/mastodon/components/poll';
import { identityContextPropShape, withIdentity } from '@/mastodon/identity_context';
import { languages as preloadedLanguages } from '@/mastodon/initial_state';
import { EmojiHTML } from '@/mastodon/components/emoji/html';
import { injectIntl } from '@/mastodon/components/intl';
import { compareUrls } from '@/mastodon/utils/compare_urls';
import { EmojiHTML } from './emoji/html';
import { injectIntl } from './intl';
import { HandledLink } from './status/handled_link';
import { compareUrls } from '../utils/compare_urls';
import { HandledLink } from '../handled_link';
const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top)

View File

@@ -1,7 +1,7 @@
import { useStatus } from '../hooks/useStatus';
import { EmojiHTML } from '@/mastodon/components/emoji/html';
import { useStatus } from '@/mastodon/hooks/useStatus';
import { EmojiHTML } from './emoji/html';
import { StatusBanner, BannerVariant } from './status_banner';
import { StatusBanner, BannerVariant } from './banner';
export const ContentWarning: React.FC<{
statusId: string;

View File

@@ -1,6 +1,6 @@
import { FormattedMessage } from 'react-intl';
import { StatusBanner, BannerVariant } from './status_banner';
import { StatusBanner, BannerVariant } from './banner';
export const FilterWarning: React.FC<{
title: string;

View File

@@ -1,6 +1,6 @@
import { mediaAttachmentFactoryAPI } from '@/testing/factories';
import { computeHashtagBarForStatus } from '../hashtag_bar';
import { computeHashtagBarForStatus } from './hashtag_bar';
function createStatus(
content: string,

View File

@@ -8,12 +8,12 @@ import type { List, Record } from 'immutable';
import { groupBy, minBy } from 'lodash';
import type { ApiTagJSON } from '../api_types/statuses';
import type { ApiTagJSON } from '../../../api_types/statuses';
import type {
MediaAttachmentShape,
StatusShape,
StatusTranslation,
} from '../models/status';
} from '../../../models/status';
// Fit on a single line on desktop
const VISIBLE_HASHTAGS = 3;

View File

@@ -0,0 +1,131 @@
import type { FC, HTMLAttributes, MouseEventHandler, ReactNode } from 'react';
import { defineMessage, useIntl } from 'react-intl';
import classNames from 'classnames';
import { Link } from 'react-router-dom';
import { Avatar } from '@/mastodon/components/avatar';
import { AvatarOverlay } from '@/mastodon/components/avatar_overlay';
import type { DisplayNameProps } from '@/mastodon/components/display_name';
import { LinkedDisplayName } from '@/mastodon/components/display_name';
import { RelativeTimestamp } from '@/mastodon/components/relative_timestamp';
import { VisibilityIcon } from '@/mastodon/components/visibility_icon';
import type { Account, AccountShapeFull } from '@/mastodon/models/account';
import { selectAccountStatus } from '@/mastodon/selectors/statuses';
import { useAppSelector } from '@/mastodon/store';
export interface StatusHeaderProps {
statusId: string;
account?: Account | AccountShapeFull;
avatarSize?: number;
contentBeforeDate?: ReactNode;
contentAfterDate?: ReactNode;
wrapperProps?: HTMLAttributes<HTMLDivElement>;
displayNameProps?: DisplayNameProps;
onHeaderClick?: MouseEventHandler<HTMLDivElement>;
className?: string;
featured?: boolean;
}
export type StatusHeaderRenderFn = (args: StatusHeaderProps) => ReactNode;
export const StatusHeader: FC<StatusHeaderProps> = ({
statusId,
account,
className,
avatarSize = 48,
wrapperProps,
contentBeforeDate,
contentAfterDate,
onHeaderClick,
}) => {
const status = useAppSelector((state) =>
selectAccountStatus(state, statusId),
);
if (!status) {
return null;
}
const statusAccount = status.account;
const editedAt = status.edited_at;
return (
/* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
<div
onClick={onHeaderClick}
onAuxClick={onHeaderClick}
{...wrapperProps}
className={classNames('status__info', className)}
/* eslint-enable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
>
<StatusDisplayName
statusAccount={statusAccount}
friendAccount={account}
avatarSize={avatarSize}
/>
{contentBeforeDate}
<Link
to={`/@${statusAccount.acct}/${status.id}`}
className='status__relative-time'
>
<span className='status__visibility-icon'>
<VisibilityIcon visibility={status.visibility} />
</span>
<RelativeTimestamp timestamp={status.created_at} />
{editedAt && <StatusEditedAt editedAt={editedAt} />}
</Link>
{contentAfterDate}
</div>
);
};
const editMessage = defineMessage({
id: 'status.edited',
defaultMessage: 'Edited {date}',
});
const StatusEditedAt: FC<{ editedAt: string }> = ({ editedAt }) => {
const intl = useIntl();
return (
<abbr
title={intl.formatMessage(editMessage, {
date: intl.formatDate(editedAt, {
year: 'numeric',
month: 'short',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
}),
})}
>
{' '}
*
</abbr>
);
};
const StatusDisplayName: FC<{
statusAccount?: AccountShapeFull;
friendAccount?: Account | AccountShapeFull;
avatarSize: number;
}> = ({ statusAccount, friendAccount, avatarSize }) => {
const AccountComponent = friendAccount ? AvatarOverlay : Avatar;
return (
<LinkedDisplayName
displayProps={{ account: statusAccount }}
className='status__display-name'
reference='status'
>
<div className='status__avatar'>
<AccountComponent
account={statusAccount}
friend={friendAccount}
size={avatarSize}
/>
</div>
</LinkedDisplayName>
);
};

View File

@@ -6,8 +6,8 @@ import {
statusQuotedFactoryAPI,
} from '@/testing/factories';
import type { StatusQuoteManagerProps } from './status_quoted';
import { StatusQuoteManager } from './status_quoted';
import type { StatusQuoteManagerProps } from './quoted';
import { StatusQuoteManager } from './quoted';
const meta = {
title: 'Components/Status/StatusQuoteManager',

View File

@@ -27,15 +27,15 @@ import { getAccountHidden } from 'mastodon/selectors/accounts';
import type { RootState } from 'mastodon/store';
import { useAppDispatch, useAppSelector } from 'mastodon/store';
import { isRedesignStatusEnabled } from '../utils/environment';
import { isRedesignStatusEnabled } from '../../../utils/environment';
import { Button } from '../../button';
import { IconButton } from '../../icon_button';
import { LoadingIndicator } from '../../loading_indicator';
import { TypedStatusContainer } from '../types';
import type { StatusContainerProps, StatusContextType } from '../types';
import { Button } from './button';
import { IconButton } from './icon_button';
import { LoadingIndicator } from './loading_indicator';
import type { StatusHeaderRenderFn } from './status/header';
import { StatusHeader } from './status/header';
import { TypedStatusContainer } from './status/types';
import type { StatusContainerProps, StatusContextType } from './status/types';
import type { StatusHeaderRenderFn } from './header';
import { StatusHeader } from './header';
const MAX_QUOTE_POSTS_NESTING_LEVEL = 1;
@@ -420,7 +420,7 @@ export const StatusQuoteManager = (props: StatusQuoteManagerProps) => {
};
const LazyStatusRedesign = lazy(() =>
import('./status/status').then(({ StatusRedesign }) => ({
import('../status').then(({ StatusRedesign }) => ({
default: StatusRedesign,
})),
);

View File

@@ -9,31 +9,31 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
import { Hotkeys } from 'mastodon/components/hotkeys';
import { ContentWarning } from 'mastodon/components/content_warning';
import { FilterWarning } from 'mastodon/components/filter_warning';
import { Icon } from 'mastodon/components/icon';
import { PictureInPicturePlaceholder } from 'mastodon/components/picture_in_picture_placeholder';
import { withOptionalRouter, WithOptionalRouterPropTypes } from 'mastodon/utils/react_router';
import { Hotkeys } from '@/mastodon/components/hotkeys';
import { Icon } from '@/mastodon/components/icon';
import { PictureInPicturePlaceholder } from './picture_in_picture_placeholder';
import { withOptionalRouter, WithOptionalRouterPropTypes } from '@/mastodon/utils/react_router';
import Card from '../features/status/components/card';
import Card from '@/mastodon/features/status/components/card';
// We use the component (and not the container) since we do not want
// to use the progress bar to show download progress
import Bundle from '../features/ui/components/bundle';
import { MediaGallery, Video, Audio } from '../features/ui/util/async-components';
import { SensitiveMediaContext } from '../features/ui/util/sensitive_media_context';
import { displayMedia } from '../initial_state';
import Bundle from '@/mastodon/features/ui/components/bundle';
import { MediaGallery, Video, Audio } from '@/mastodon/features/ui/util/async-components';
import { SensitiveMediaContext } from '@/mastodon/features/ui/util/sensitive_media_context';
import { displayMedia } from '@/mastodon/initial_state';
import { CollectionPreviewCard } from '@/mastodon/features/collections/components/collection_preview_card';
import { compareUrls } from '@/mastodon/utils/compare_urls';
import { FOCUS_TARGET } from '@/mastodon/components/navigation_focus_target';
import { LinkedDisplayName } from '@/mastodon/components/display_name';
import { injectIntl } from './intl';
import { StatusHeader } from './status/header'
import { LinkedDisplayName } from './display_name';
import { injectIntl } from '../../intl';
import { ContentWarning } from './content_warning';
import { FilterWarning } from './filter_warning';
import { StatusHeader } from './header'
import { getHashtagBarForStatus } from './hashtag_bar';
import StatusActionBar from './status_action_bar';
import StatusContent from './status_content';
import { StatusThreadLabel } from './status_thread_label';
import { CollectionPreviewCard } from '../features/collections/components/collection_preview_card';
import { compareUrls } from '../utils/compare_urls';
import { FOCUS_TARGET } from './navigation_focus_target';
import StatusActionBar from './action_bar';
import StatusContent from './content';
import { StatusThreadLabel } from './thread_label';
const domParser = new DOMParser();

View File

@@ -4,7 +4,7 @@ import ReplyIcon from '@/material-icons/400-24px/reply.svg?react';
import { Icon } from 'mastodon/components/icon';
import { useAppSelector } from 'mastodon/store';
import { LinkedDisplayName } from './display_name';
import { LinkedDisplayName } from '../../display_name';
export const StatusThreadLabel: React.FC<{
accountId: string;

View File

@@ -1,108 +0,0 @@
import { useId } from 'react';
import { FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import { Link } from 'react-router-dom';
import type { AccountStatusShape } from '@/mastodon/models/status';
import { Avatar } from '../../avatar';
import { DisplayName } from '../../display_name';
import { useAccountHandle } from '../../display_name/default';
import { RelativeTimestamp } from '../../relative_timestamp';
import { Skeleton } from '../../skeleton';
import { statusLink } from '../utils';
import classes from './styles.module.scss';
interface StatusRedesignHeaderProps {
status: Pick<
AccountStatusShape,
'id' | 'account' | 'created_at' | 'visibility'
>;
children?: React.ReactNode;
className?: string;
}
export const StatusRedesignHeader: React.FC<StatusRedesignHeaderProps> = ({
status,
children,
className,
}) => {
const account = status.account;
const handle = useAccountHandle(account);
const handleId = useId();
const accountLinkProps = {
to: {
pathname: `/@${account.acct}`,
state: { reference: 'status' },
},
title: `@${account.acct}`,
'data-id': account.id,
'data-hover-card-account': account.id,
'data-hover-card-reference': 'status',
};
let displayName = (
<Link
{...accountLinkProps}
className={classes.headerNameLink}
aria-describedby={handleId}
>
<DisplayName account={account} variant='noDomain' />
</Link>
);
if (status.visibility === 'private') {
displayName = (
<FormattedMessage
id='status.header.to_followers'
defaultMessage='{displayName} to Followers'
tagName='span'
values={{ displayName }}
/>
);
}
return (
<header className={classNames(className, classes.header)}>
<Link
{...accountLinkProps}
role='presentation'
tabIndex={-1}
className={classes.headerAvatar}
>
<Avatar account={account} size={null} />
</Link>
<div>
<p className={classes.headerName}>
{displayName}
&bull;
<Link
to={{
pathname: statusLink(status),
state: { reference: 'status' },
}}
>
<RelativeTimestamp timestamp={status.created_at} />
</Link>
</p>
<p className={classes.headerHandle}>
<Link
{...accountLinkProps}
role='presentation'
tabIndex={-1}
id={handleId}
>
{handle ?? <Skeleton width='7ch' />}
</Link>
</p>
</div>
{children}
</header>
);
};

View File

@@ -7,7 +7,6 @@ import type { Merge } from 'type-fest';
import { selectExpandedStatus } from '@/mastodon/selectors/statuses';
import { createAppSelector, useAppSelector } from '@/mastodon/store';
import { computeHashtagBarForStatus } from '../hashtag_bar';
import { Hotkeys } from '../hotkeys';
import { Poll } from '../poll';
@@ -15,15 +14,16 @@ import { StatusActionBar } from './action_bar';
import { StatusAttachments } from './attachments';
import { StatusContent } from './content';
import { StatusHashtagBar } from './hashtag_bar';
import { StatusRedesignHeader } from './header';
import type { StatusHandlers } from './hooks';
import {
StatusContext,
useStatusHandlers,
useTextForScreenReader,
} from './hooks';
import { computeHashtagBarForStatus } from './legacy/hashtag_bar';
import { StatusMeta } from './meta';
import { StatusPrepend } from './prepend';
import { StatusRedesignHeader } from './redesign/header';
import classes from './styles.module.scss';
import { TranslateButton } from './translate';
import type { StatusContainerProps, StatusContextType } from './types';

View File

@@ -217,6 +217,15 @@
@include mixins.type-micro;
color: var(--color-text-secondary);
a {
color: inherit;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
.actions {

View File

@@ -1,12 +1,11 @@
import type { ComponentType, ReactNode } from 'react';
import StatusContainer from '@/mastodon/containers/status_container';
import StatusContainer from '@/mastodon/components/status/legacy/container';
import type { Account as TAccount } from '@/mastodon/models/account';
import type { Status as TStatus } from '@/mastodon/models/status';
import Status from '../status';
import type { StatusHeaderRenderFn } from './header';
import type { StatusHeaderRenderFn } from './legacy/header';
import Status from './legacy/status';
export type StatusContextType =
| 'account'

View File

@@ -11,7 +11,7 @@ import { RegenerationIndicator } from 'mastodon/components/regeneration_indicato
import { InlineFollowSuggestions } from 'mastodon/features/home_timeline/components/inline_follow_suggestions';
import { PinnedShowAllButton } from '@/mastodon/features/account_timeline/components/pinned_statuses';
import { StatusQuoteManager } from '../components/status_quoted';
import { Status } from './status';
import { LoadGap } from './load_gap';
import ScrollableList from './scrollable_list';
@@ -79,7 +79,7 @@ export default class StatusList extends ImmutablePureComponent {
);
default:
return (
<StatusQuoteManager
<Status
key={statusId}
id={statusId}
contextType={timelineId}
@@ -99,7 +99,7 @@ export default class StatusList extends ImmutablePureComponent {
return <PinnedShowAllButton key={TIMELINE_PINNED_VIEW_ALL} />
}
return (
<StatusQuoteManager
<Status
key={`f-${statusId}`}
id={statusId}
featured

View File

@@ -8,8 +8,8 @@ import IconPinned from '@/images/icons/icon_pinned.svg?react';
import { Badge } from '@/mastodon/components/badge';
import { Button } from '@/mastodon/components/button';
import { Icon } from '@/mastodon/components/icon';
import { StatusHeader } from '@/mastodon/components/status/header';
import type { StatusHeaderRenderFn } from '@/mastodon/components/status/header';
import { StatusHeader } from '@/mastodon/components/status/legacy/header';
import type { StatusHeaderRenderFn } from '@/mastodon/components/status/legacy/header';
import { useAccountContext } from '../hooks/useAccountContext';
import classes from '../styles.module.scss';

View File

@@ -11,8 +11,8 @@ import { FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import { Status } from 'mastodon/components/status';
import { InterceptStatusClicks } from 'mastodon/components/status/intercept_status_clicks';
import { StatusQuoteManager } from 'mastodon/components/status_quoted';
import type { TopStatuses } from 'mastodon/models/annual_report';
import { makeGetStatus } from 'mastodon/selectors';
import { useAppSelector } from 'mastodon/store';
@@ -95,7 +95,7 @@ export const HighlightedPost: React.FC<{
</div>
<InterceptStatusClicks onPreventedClick={handleClick}>
<StatusQuoteManager showActions={false} id={statusId} />
<Status showActions={false} id={statusId} />
</InterceptStatusClicks>
</div>
);

View File

@@ -4,7 +4,7 @@ import type { FC } from 'react';
import { Map } from 'immutable';
import { quoteComposeCancel } from '@/mastodon/actions/compose_typed';
import { QuotedStatus } from '@/mastodon/components/status_quoted';
import { QuotedStatus } from '@/mastodon/components/status/legacy/quoted';
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
import { QuotePlaceholder } from './quote_placeholder';

View File

@@ -13,6 +13,7 @@ import type {
import { LinkedDisplayName } from '@/mastodon/components/display_name';
import { AnimateEmojiProvider } from '@/mastodon/components/emoji/context';
import StatusContent from '@/mastodon/components/status/legacy/content';
import type { Account } from '@/mastodon/models/account';
import type { StatusShape } from '@/mastodon/models/status';
import {
@@ -39,7 +40,6 @@ import { Dropdown } from 'mastodon/components/dropdown_menu';
import { Hotkeys } from 'mastodon/components/hotkeys';
import { IconButton } from 'mastodon/components/icon_button';
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
import StatusContent from 'mastodon/components/status_content';
import { makeGetStatus } from 'mastodon/selectors';
const messages = defineMessages({

View File

@@ -22,7 +22,7 @@ import { LinkedDisplayName } from '@/mastodon/components/display_name';
import { Icon } from 'mastodon/components/icon';
import { injectIntl } from '@/mastodon/components/intl';
import { Hotkeys } from 'mastodon/components/hotkeys';
import { StatusQuoteManager } from 'mastodon/components/status_quoted';
import { Status } from 'mastodon/components/status';
import { me } from 'mastodon/initial_state';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
@@ -165,7 +165,7 @@ class Notification extends ImmutablePureComponent {
renderMention (notification) {
return (
<StatusQuoteManager
<Status
id={notification.get('status')}
withDismiss
hidden={this.props.hidden}
@@ -193,7 +193,7 @@ class Notification extends ImmutablePureComponent {
</span>
</div>
<StatusQuoteManager
<Status
id={notification.get('status')}
account={notification.get('account')}
muted
@@ -223,7 +223,7 @@ class Notification extends ImmutablePureComponent {
</span>
</div>
<StatusQuoteManager
<Status
id={notification.get('status')}
account={notification.get('account')}
muted
@@ -253,7 +253,7 @@ class Notification extends ImmutablePureComponent {
</span>
</div>
<StatusQuoteManager
<Status
id={notification.get('status')}
account={notification.get('account')}
muted
@@ -287,7 +287,7 @@ class Notification extends ImmutablePureComponent {
</span>
</div>
<StatusQuoteManager
<Status
id={notification.get('status')}
account={notification.get('account')}
contextType='notifications'
@@ -322,7 +322,7 @@ class Notification extends ImmutablePureComponent {
</span>
</div>
<StatusQuoteManager
<Status
id={notification.get('status')}
account={notification.get('account')}
contextType='notifications'
@@ -357,7 +357,7 @@ class Notification extends ImmutablePureComponent {
</span>
</div>
<StatusQuoteManager
<Status
id={notification.get('status')}
account={notification.get('account')}
contextType='notifications'
@@ -398,7 +398,7 @@ class Notification extends ImmutablePureComponent {
</span>
</div>
<StatusQuoteManager
<Status
id={notification.get('status')}
account={account}
contextType='notifications'

View File

@@ -9,11 +9,11 @@ import type { List as ImmutableList, RecordOf } from 'immutable';
import type { ApiMentionJSON } from '@/mastodon/api_types/statuses';
import { AnimateEmojiProvider } from '@/mastodon/components/emoji/context';
import { FOCUS_TARGET } from '@/mastodon/components/navigation_focus_target';
import { ContentWarning } from '@/mastodon/components/status/legacy/content_warning';
import BarChart4BarsIcon from '@/material-icons/400-24px/bar_chart_4_bars.svg?react';
import PhotoLibraryIcon from '@/material-icons/400-24px/photo_library.svg?react';
import { toggleStatusSpoilers } from 'mastodon/actions/statuses';
import { Avatar } from 'mastodon/components/avatar';
import { ContentWarning } from 'mastodon/components/content_warning';
import { DisplayName } from 'mastodon/components/display_name';
import { Icon } from 'mastodon/components/icon';
import { useAppSelector, useAppDispatch } from 'mastodon/store';

View File

@@ -12,7 +12,7 @@ import {
import { Hotkeys } from 'mastodon/components/hotkeys';
import type { IconProp } from 'mastodon/components/icon';
import { Icon } from 'mastodon/components/icon';
import { StatusQuoteManager } from 'mastodon/components/status_quoted';
import { Status } from 'mastodon/components/status';
import { getStatusHidden } from 'mastodon/selectors/filters';
import { useAppSelector, useAppDispatch } from 'mastodon/store';
@@ -108,7 +108,7 @@ export const NotificationWithStatus: React.FC<{
<span>{label}</span>
</h2>
<StatusQuoteManager
<Status
id={statusId}
contextType='notifications'
withDismiss

View File

@@ -4,6 +4,7 @@ import { defineMessages, useIntl } from 'react-intl';
import { useHistory } from 'react-router-dom';
import { BoostButton } from '@/mastodon/components/status/legacy/boost_button';
import OpenInNewIcon from '@/material-icons/400-24px/open_in_new.svg?react';
import ReplyIcon from '@/material-icons/400-24px/reply.svg?react';
import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react';
@@ -13,7 +14,6 @@ import { replyCompose } from 'mastodon/actions/compose';
import { toggleFavourite } from 'mastodon/actions/interactions';
import { openModal } from 'mastodon/actions/modal';
import { IconButton } from 'mastodon/components/icon_button';
import { BoostButton } from 'mastodon/components/status/boost_button';
import { useIdentity } from 'mastodon/identity_context';
import type { Account } from 'mastodon/models/account';
import type { Status } from 'mastodon/models/status';

View File

@@ -7,7 +7,7 @@ import { Avatar } from 'mastodon/components/avatar';
import { DisplayName } from 'mastodon/components/display_name';
import MediaAttachments from 'mastodon/components/media_attachments';
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
import StatusContent from 'mastodon/components/status_content';
import StatusContent from '@/mastodon/components/status/legacy/content';
import { VisibilityIcon } from 'mastodon/components/visibility_icon';
import Option from './option';

View File

@@ -19,7 +19,7 @@ import { Account } from 'mastodon/components/account';
import { CompatibilityHashtag as Hashtag } from 'mastodon/components/hashtag';
import { Icon } from 'mastodon/components/icon';
import ScrollableList from 'mastodon/components/scrollable_list';
import { StatusQuoteManager } from 'mastodon/components/status_quoted';
import { Status } from 'mastodon/components/status';
import { Search } from 'mastodon/features/compose/components/search';
import { useSearchParam } from 'mastodon/hooks/useSearchParam';
import type { Hashtag as HashtagType } from 'mastodon/models/tags';
@@ -59,7 +59,7 @@ const renderHashtags = (hashtags: HashtagType[]) =>
const renderStatuses = (statusIds: string[]) =>
hidePeek<string>(statusIds).map((id) => (
<StatusQuoteManager contextType='search' key={id} id={id} />
<Status contextType='search' key={id} id={id} />
));
type SearchType = 'all' | ApiSearchType;
@@ -217,7 +217,7 @@ export const SearchResults: React.FC<{ multiColumn: boolean }> = ({
onClickMore={handleSelectStatuses}
>
{results.statuses.slice(0, INITIAL_DISPLAY).map((id) => (
<StatusQuoteManager contextType='search' key={id} id={id} />
<Status contextType='search' key={id} id={id} />
))}
</SearchSection>
)}

View File

@@ -17,10 +17,10 @@ import { injectIntl } from '@/mastodon/components/intl';
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
import { IconButton } from '../../../components/icon_button';
import { IconButton } from '@/mastodon/components/icon_button';
import { Dropdown } from 'mastodon/components/dropdown_menu';
import { me, quickBoosting } from '../../../initial_state';
import { BoostButton } from '@/mastodon/components/status/boost_button';
import { me, quickBoosting } from '@/mastodon/initial_state';
import { BoostButton } from '@/mastodon/components/status/legacy/boost_button';
import { quoteItemState } from '@/mastodon/components/status/boost_button_utils';
import { selectStatusConditions } from '@/mastodon/selectors/statuses';

View File

@@ -11,22 +11,22 @@ import { FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import { Link } from 'react-router-dom';
import StatusContent from '@/mastodon/components/status/legacy/content';
import { ContentWarning } from '@/mastodon/components/status/legacy/content_warning';
import { FilterWarning } from '@/mastodon/components/status/legacy/filter_warning';
import type { StatusLike } from '@/mastodon/components/status/legacy/hashtag_bar';
import { getHashtagBarForStatus } from '@/mastodon/components/status/legacy/hashtag_bar';
import { PictureInPicturePlaceholder } from '@/mastodon/components/status/legacy/picture_in_picture_placeholder';
import { QuotedStatus } from '@/mastodon/components/status/legacy/quoted';
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
import { AnimatedNumber } from 'mastodon/components/animated_number';
import { Avatar } from 'mastodon/components/avatar';
import { ContentWarning } from 'mastodon/components/content_warning';
import { DisplayName } from 'mastodon/components/display_name';
import { EditedTimestamp } from 'mastodon/components/edited_timestamp';
import { FilterWarning } from 'mastodon/components/filter_warning';
import { FormattedDateWrapper } from 'mastodon/components/formatted_date';
import type { StatusLike } from 'mastodon/components/hashtag_bar';
import { getHashtagBarForStatus } from 'mastodon/components/hashtag_bar';
import { Icon } from 'mastodon/components/icon';
import { IconLogo } from 'mastodon/components/logo';
import MediaGallery from 'mastodon/components/media_gallery';
import { PictureInPicturePlaceholder } from 'mastodon/components/picture_in_picture_placeholder';
import StatusContent from 'mastodon/components/status_content';
import { QuotedStatus } from 'mastodon/components/status_quoted';
import { VisibilityIcon } from 'mastodon/components/visibility_icon';
import { Audio } from 'mastodon/features/audio';
import { CollectionPreviewCard } from 'mastodon/features/collections/components/collection_preview_card';

View File

@@ -29,17 +29,17 @@ import { WithRouterPropTypes } from 'mastodon/utils/react_router';
import {
unblockAccount,
unmuteAccount,
} from '../../actions/accounts';
import { initBlockModal } from '../../actions/blocks';
} from '@/mastodon/actions/accounts';
import { initBlockModal } from '@/mastodon/actions/blocks';
import {
replyCompose,
mentionCompose,
directCompose,
} from '../../actions/compose';
} from '@/mastodon/actions/compose';
import {
initDomainBlockModal,
unblockDomain,
} from '../../actions/domain_blocks';
} from '@/mastodon/actions/domain_blocks';
import {
toggleFavourite,
bookmark,
@@ -47,10 +47,10 @@ import {
toggleReblog,
pin,
unpin,
} from '../../actions/interactions';
import { openModal } from '../../actions/modal';
import { initMuteModal } from '../../actions/mutes';
import { initReport } from '../../actions/reports';
} from '@/mastodon/actions/interactions';
import { openModal } from '@/mastodon/actions/modal';
import { initMuteModal } from '@/mastodon/actions/mutes';
import { initReport } from '@/mastodon/actions/reports';
import {
fetchStatus,
muteStatus,
@@ -61,12 +61,12 @@ import {
revealStatus,
translateStatus,
undoStatusTranslation,
} from '../../actions/statuses';
import { setStatusQuotePolicy } from '../../actions/statuses_typed';
import { textForScreenReader, defaultMediaVisibility } from '../../components/status';
import { StatusQuoteManager } from '../../components/status_quoted';
import { deleteModal } from '../../initial_state';
import { makeGetStatus, makeGetPictureInPicture } from '../../selectors';
} from '@/mastodon/actions/statuses';
import { setStatusQuotePolicy } from '@/mastodon/actions/statuses_typed';
import { textForScreenReader, defaultMediaVisibility } from '@/mastodon/components/status/legacy/status';
import { Status as StatusComponent } from '@/mastodon/components/status';
import { deleteModal } from '@/mastodon/initial_state';
import { makeGetStatus, makeGetPictureInPicture } from '@/mastodon/selectors';
import { getAncestorsIds, getDescendantsIds } from 'mastodon/selectors/contexts';
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../ui/util/fullscreen';
@@ -465,7 +465,7 @@ class Status extends ImmutablePureComponent {
const { params: { statusId } } = this.props;
return list.map((id, i) => (
<StatusQuoteManager
<StatusComponent
key={id}
id={id}
contextType='thread'

View File

@@ -92,7 +92,7 @@ import { CustomHomepage } from 'mastodon/features/custom_homepage';
// Dummy import, to make sure that <Status /> ends up in the application bundle.
// Without this it ends up in ~8 very commonly used bundles.
import '../../components/status';
import '../../components/status/legacy/status';
import { getNavigationSkipLinkId, SkipLinks } from './components/skip_links';
const messages = defineMessages({