mirror of
https://github.com/glitch-soc/mastodon.git
synced 2026-03-29 11:11:11 +02:00
[Glitch] Refactors header from Status component
Port 7f53a77fa3 to glitch-soc
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
@@ -7,7 +7,6 @@ import classNames from 'classnames';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
import CancelFillIcon from '@/material-icons/400-24px/cancel-fill.svg?react';
|
||||
import { Hotkeys } from 'flavours/glitch/components/hotkeys';
|
||||
import { ContentWarning } from 'flavours/glitch/components/content_warning';
|
||||
import { PictureInPicturePlaceholder } from 'flavours/glitch/components/picture_in_picture_placeholder';
|
||||
@@ -23,16 +22,13 @@ import { SensitiveMediaContext } from '../features/ui/util/sensitive_media_conte
|
||||
import { displayMedia } from '../initial_state';
|
||||
|
||||
import AttachmentList from './attachment_list';
|
||||
import { Avatar } from './avatar';
|
||||
import { AvatarOverlay } from './avatar_overlay';
|
||||
import { LinkedDisplayName } from './display_name';
|
||||
import { StatusHeader } from './status/header'
|
||||
import { getHashtagBarForStatus } from './hashtag_bar';
|
||||
import { MentionsPlaceholder } from './mentions_placeholder';
|
||||
import StatusActionBar from './status_action_bar';
|
||||
import StatusContent from './status_content';
|
||||
import StatusIcons from './status_icons';
|
||||
import StatusPrepend from './status_prepend';
|
||||
import { IconButton } from './icon_button';
|
||||
|
||||
const domParser = new DOMParser();
|
||||
|
||||
@@ -111,7 +107,6 @@ class Status extends ImmutablePureComponent {
|
||||
onToggleCollapsed: PropTypes.func,
|
||||
onTranslate: PropTypes.func,
|
||||
onInteractionModal: PropTypes.func,
|
||||
onQuoteCancel: PropTypes.func,
|
||||
muted: PropTypes.bool,
|
||||
hidden: PropTypes.bool,
|
||||
unread: PropTypes.bool,
|
||||
@@ -130,6 +125,8 @@ class Status extends ImmutablePureComponent {
|
||||
skipPrepend: PropTypes.bool,
|
||||
avatarSize: PropTypes.number,
|
||||
deployPictureInPicture: PropTypes.func,
|
||||
unfocusable: PropTypes.bool,
|
||||
headerRenderFn: PropTypes.func,
|
||||
settings: ImmutablePropTypes.map.isRequired,
|
||||
pictureInPicture: ImmutablePropTypes.contains({
|
||||
inUse: PropTypes.bool,
|
||||
@@ -160,7 +157,6 @@ class Status extends ImmutablePureComponent {
|
||||
'expanded',
|
||||
'unread',
|
||||
'pictureInPicture',
|
||||
'onQuoteCancel',
|
||||
'previousId',
|
||||
'nextInReplyToId',
|
||||
'rootId',
|
||||
@@ -342,10 +338,6 @@ class Status extends ImmutablePureComponent {
|
||||
deployPictureInPicture(status, type, mediaProps);
|
||||
};
|
||||
|
||||
handleQuoteCancel = () => {
|
||||
this.props.onQuoteCancel?.();
|
||||
}
|
||||
|
||||
handleHotkeyReply = e => {
|
||||
e.preventDefault();
|
||||
this.props.onReply(this.props.status);
|
||||
@@ -455,27 +447,39 @@ class Status extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { intl, hidden, featured, unfocusable, unread, pictureInPicture, previousId, nextInReplyToId, rootId, skipPrepend, avatarSize = 46, children } = this.props;
|
||||
const {
|
||||
intl,
|
||||
hidden,
|
||||
featured,
|
||||
unfocusable,
|
||||
unread,
|
||||
showActions = true,
|
||||
isQuotedPost = false,
|
||||
pictureInPicture,
|
||||
previousId,
|
||||
nextInReplyToId,
|
||||
rootId,
|
||||
skipPrepend,
|
||||
avatarSize = 46,
|
||||
children,
|
||||
} = this.props;
|
||||
|
||||
// glitch-soc-specific
|
||||
const {
|
||||
status,
|
||||
account,
|
||||
settings,
|
||||
muted,
|
||||
intersectionObserverWrapper,
|
||||
onOpenVideo,
|
||||
onOpenMedia,
|
||||
notification,
|
||||
history,
|
||||
showActions = true,
|
||||
isQuotedPost = false,
|
||||
...other
|
||||
} = this.props;
|
||||
let attachments = null;
|
||||
|
||||
let media = [];
|
||||
let mediaIcons = [];
|
||||
let statusAvatar;
|
||||
|
||||
if (status === null) {
|
||||
return null;
|
||||
@@ -678,14 +682,25 @@ class Status extends ImmutablePureComponent {
|
||||
rebloggedByText = intl.formatMessage({ id: 'status.reblogged_by', defaultMessage: '{name} boosted' }, { name: account.get('acct') });
|
||||
}
|
||||
|
||||
if (account === undefined || account === null) {
|
||||
statusAvatar = <Avatar account={status.get('account')} size={avatarSize} />;
|
||||
} else {
|
||||
statusAvatar = <AvatarOverlay account={status.get('account')} friend={account} />;
|
||||
}
|
||||
|
||||
const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
|
||||
|
||||
const header = this.props.headerRenderFn
|
||||
? this.props.headerRenderFn({ status, account, avatarSize, messages, onHeaderClick: this.handleHeaderClick })
|
||||
: (
|
||||
<StatusHeader
|
||||
status={status}
|
||||
account={account}
|
||||
avatarSize={avatarSize}
|
||||
onHeaderClick={this.handleHeaderClick}
|
||||
>
|
||||
<StatusIcons
|
||||
status={status}
|
||||
mediaIcons={mediaIcons}
|
||||
settings={settings.get('status_icons')}
|
||||
/>
|
||||
</StatusHeader>
|
||||
);
|
||||
|
||||
return (
|
||||
<Hotkeys handlers={handlers} focusable={!unfocusable}>
|
||||
<div
|
||||
@@ -716,31 +731,7 @@ class Status extends ImmutablePureComponent {
|
||||
>
|
||||
{(connectReply || connectUp || connectToRoot) && <div className={classNames('status__line', { 'status__line--full': connectReply, 'status__line--first': !status.get('in_reply_to_id') && !connectToRoot })} />}
|
||||
|
||||
{(!muted) && (
|
||||
<header onClick={this.handleHeaderClick} onAuxClick={this.handleHeaderClick} className='status__info'>
|
||||
<LinkedDisplayName displayProps={{account: status.get('account')}} className='status__display-name'>
|
||||
<div className='status__avatar'>
|
||||
{statusAvatar}
|
||||
</div>
|
||||
</LinkedDisplayName>
|
||||
|
||||
{isQuotedPost && !!this.props.onQuoteCancel ? (
|
||||
<IconButton
|
||||
onClick={this.handleQuoteCancel}
|
||||
className='status__quote-cancel'
|
||||
title={intl.formatMessage(messages.quote_cancel)}
|
||||
icon="cancel-fill"
|
||||
iconComponent={CancelFillIcon}
|
||||
/>
|
||||
) : (
|
||||
<StatusIcons
|
||||
status={status}
|
||||
mediaIcons={mediaIcons}
|
||||
settings={settings.get('status_icons')}
|
||||
/>
|
||||
)}
|
||||
</header>
|
||||
)}
|
||||
{(!muted) && header}
|
||||
|
||||
<ContentWarning status={status} expanded={expanded} onClick={this.handleExpandedToggle} icons={mediaIcons} />
|
||||
|
||||
|
||||
115
app/javascript/flavours/glitch/components/status/header.tsx
Normal file
115
app/javascript/flavours/glitch/components/status/header.tsx
Normal file
@@ -0,0 +1,115 @@
|
||||
import type { FC, HTMLAttributes, MouseEventHandler, ReactNode } from 'react';
|
||||
|
||||
import { defineMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { isStatusVisibility } from '@/flavours/glitch/api_types/statuses';
|
||||
import type { Account } from '@/flavours/glitch/models/account';
|
||||
import type { Status } from '@/flavours/glitch/models/status';
|
||||
|
||||
import { Avatar } from '../avatar';
|
||||
import { AvatarOverlay } from '../avatar_overlay';
|
||||
import type { DisplayNameProps } from '../display_name';
|
||||
import { LinkedDisplayName } from '../display_name';
|
||||
import { VisibilityIcon } from '../visibility_icon';
|
||||
|
||||
export interface StatusHeaderProps {
|
||||
status: Status;
|
||||
account?: Account;
|
||||
avatarSize?: number;
|
||||
children?: ReactNode;
|
||||
wrapperProps?: HTMLAttributes<HTMLDivElement>;
|
||||
displayNameProps?: DisplayNameProps;
|
||||
onHeaderClick?: MouseEventHandler<HTMLDivElement>;
|
||||
}
|
||||
|
||||
export type StatusHeaderRenderFn = (args: StatusHeaderProps) => ReactNode;
|
||||
|
||||
export const StatusHeader: FC<StatusHeaderProps> = ({
|
||||
status,
|
||||
account,
|
||||
children,
|
||||
avatarSize = 48,
|
||||
wrapperProps,
|
||||
onHeaderClick,
|
||||
}) => {
|
||||
const statusAccount = status.get('account') as Account | undefined;
|
||||
|
||||
return (
|
||||
/* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
|
||||
<header
|
||||
onClick={onHeaderClick}
|
||||
onAuxClick={onHeaderClick}
|
||||
{...wrapperProps}
|
||||
className='status__info'
|
||||
/* eslint-enable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
|
||||
>
|
||||
<StatusDisplayName
|
||||
statusAccount={statusAccount}
|
||||
friendAccount={account}
|
||||
avatarSize={avatarSize}
|
||||
/>
|
||||
|
||||
{children}
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
export const StatusVisibility: FC<{ visibility: unknown }> = ({
|
||||
visibility,
|
||||
}) => {
|
||||
if (typeof visibility !== 'string' || !isStatusVisibility(visibility)) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<span className='status__visibility-icon'>
|
||||
<VisibilityIcon visibility={visibility} />
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
const editMessage = defineMessage({
|
||||
id: 'status.edited',
|
||||
defaultMessage: 'Edited {date}',
|
||||
});
|
||||
|
||||
export 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>
|
||||
);
|
||||
};
|
||||
|
||||
export const StatusDisplayName: FC<{
|
||||
statusAccount?: Account;
|
||||
friendAccount?: Account;
|
||||
avatarSize: number;
|
||||
}> = ({ statusAccount, friendAccount, avatarSize }) => {
|
||||
const AccountComponent = friendAccount ? AvatarOverlay : Avatar;
|
||||
return (
|
||||
<LinkedDisplayName
|
||||
displayProps={{ account: statusAccount }}
|
||||
className='status__display-name'
|
||||
>
|
||||
<div className='status__avatar'>
|
||||
<AccountComponent
|
||||
account={statusAccount}
|
||||
friend={friendAccount}
|
||||
size={avatarSize}
|
||||
/>
|
||||
</div>
|
||||
</LinkedDisplayName>
|
||||
);
|
||||
};
|
||||
@@ -1,9 +1,10 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { defineMessage, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import type { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
import CancelFillIcon from '@/material-icons/400-24px/cancel-fill.svg?react';
|
||||
import { LearnMoreLink } from 'flavours/glitch/components/learn_more_link';
|
||||
import StatusContainer from 'flavours/glitch/containers/status_container';
|
||||
import { domain } from 'flavours/glitch/initial_state';
|
||||
@@ -19,6 +20,9 @@ import { makeGetStatusWithExtraInfo } from '../selectors';
|
||||
import { getAccountHidden } from '../selectors/accounts';
|
||||
|
||||
import { Button } from './button';
|
||||
import { IconButton } from './icon_button';
|
||||
import type { StatusHeaderRenderFn } from './status/header';
|
||||
import { StatusHeader } from './status/header';
|
||||
|
||||
const MAX_QUOTE_POSTS_NESTING_LEVEL = 1;
|
||||
|
||||
@@ -148,6 +152,11 @@ interface QuotedStatusProps {
|
||||
onQuoteCancel?: () => void; // Used for composer.
|
||||
}
|
||||
|
||||
const quoteCancelMessage = defineMessage({
|
||||
id: 'status.quote.cancel',
|
||||
defaultMessage: 'Cancel quote',
|
||||
});
|
||||
|
||||
export const QuotedStatus: React.FC<QuotedStatusProps> = ({
|
||||
quote,
|
||||
contextType,
|
||||
@@ -214,6 +223,22 @@ export const QuotedStatus: React.FC<QuotedStatusProps> = ({
|
||||
if (accountId && hiddenAccount) dispatch(fetchRelationships([accountId]));
|
||||
}, [accountId, hiddenAccount, dispatch]);
|
||||
|
||||
const intl = useIntl();
|
||||
const headerRenderFn: StatusHeaderRenderFn = useCallback(
|
||||
(props) => (
|
||||
<StatusHeader {...props}>
|
||||
<IconButton
|
||||
onClick={onQuoteCancel}
|
||||
className='status__quote-cancel'
|
||||
title={intl.formatMessage(quoteCancelMessage)}
|
||||
icon='cancel-fill'
|
||||
iconComponent={CancelFillIcon}
|
||||
/>
|
||||
</StatusHeader>
|
||||
),
|
||||
[intl, onQuoteCancel],
|
||||
);
|
||||
|
||||
const isFilteredAndHidden = loadingState === 'filtered';
|
||||
|
||||
let quoteError: React.ReactNode = null;
|
||||
@@ -315,7 +340,7 @@ export const QuotedStatus: React.FC<QuotedStatusProps> = ({
|
||||
id={quotedStatusId}
|
||||
contextType={contextType}
|
||||
avatarSize={32}
|
||||
onQuoteCancel={onQuoteCancel}
|
||||
headerRenderFn={headerRenderFn}
|
||||
>
|
||||
{canRenderChildQuote && (
|
||||
<QuotedStatus
|
||||
|
||||
Reference in New Issue
Block a user