mirror of
https://github.com/mastodon/mastodon.git
synced 2025-05-16 06:31:12 +00:00
Refactor <Footer>
into TypeScript
This commit is contained in:
parent
9b6846c5ae
commit
01090ff7ad
|
@ -13,7 +13,6 @@ import { Avatar } from 'mastodon/components/avatar';
|
||||||
import { ContentWarning } from 'mastodon/components/content_warning';
|
import { ContentWarning } from 'mastodon/components/content_warning';
|
||||||
import { DisplayName } from 'mastodon/components/display_name';
|
import { DisplayName } from 'mastodon/components/display_name';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import type { Status } from 'mastodon/models/status';
|
|
||||||
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||||
|
|
||||||
import { EmbeddedStatusContent } from './embedded_status_content';
|
import { EmbeddedStatusContent } from './embedded_status_content';
|
||||||
|
@ -27,9 +26,7 @@ export const EmbeddedStatus: React.FC<{ statusId: string }> = ({
|
||||||
const clickCoordinatesRef = useRef<[number, number] | null>();
|
const clickCoordinatesRef = useRef<[number, number] | null>();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const status = useAppSelector(
|
const status = useAppSelector((state) => state.statuses.get(statusId));
|
||||||
(state) => state.statuses.get(statusId) as Status | undefined,
|
|
||||||
);
|
|
||||||
|
|
||||||
const account = useAppSelector((state) =>
|
const account = useAppSelector((state) =>
|
||||||
state.accounts.get(status?.get('account') as string),
|
state.accounts.get(status?.get('account') as string),
|
||||||
|
|
|
@ -1,195 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
|
||||||
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import { withRouter } from 'react-router-dom';
|
|
||||||
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
import OpenInNewIcon from '@/material-icons/400-24px/open_in_new.svg?react';
|
|
||||||
import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
|
|
||||||
import ReplyIcon from '@/material-icons/400-24px/reply.svg?react';
|
|
||||||
import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react';
|
|
||||||
import StarIcon from '@/material-icons/400-24px/star.svg?react';
|
|
||||||
import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg?react';
|
|
||||||
import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react';
|
|
||||||
import { replyCompose } from 'mastodon/actions/compose';
|
|
||||||
import { toggleReblog, toggleFavourite } from 'mastodon/actions/interactions';
|
|
||||||
import { openModal } from 'mastodon/actions/modal';
|
|
||||||
import { IconButton } from 'mastodon/components/icon_button';
|
|
||||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
|
||||||
import { me } from 'mastodon/initial_state';
|
|
||||||
import { makeGetStatus } from 'mastodon/selectors';
|
|
||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
reply: { id: 'status.reply', defaultMessage: 'Reply' },
|
|
||||||
replyAll: { id: 'status.replyAll', defaultMessage: 'Reply to thread' },
|
|
||||||
reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
|
|
||||||
reblog_private: { id: 'status.reblog_private', defaultMessage: 'Boost with original visibility' },
|
|
||||||
cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
|
|
||||||
cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' },
|
|
||||||
favourite: { id: 'status.favourite', defaultMessage: 'Favorite' },
|
|
||||||
removeFavourite: { id: 'status.remove_favourite', defaultMessage: 'Remove from favorites' },
|
|
||||||
open: { id: 'status.open', defaultMessage: 'Expand this status' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
|
||||||
const getStatus = makeGetStatus();
|
|
||||||
|
|
||||||
const mapStateToProps = (state, { statusId }) => ({
|
|
||||||
status: getStatus(state, { id: statusId }),
|
|
||||||
askReplyConfirmation: state.getIn(['compose', 'text']).trim().length !== 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
return mapStateToProps;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Footer extends ImmutablePureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
identity: identityContextPropShape,
|
|
||||||
statusId: PropTypes.string.isRequired,
|
|
||||||
status: ImmutablePropTypes.map.isRequired,
|
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
dispatch: PropTypes.func.isRequired,
|
|
||||||
askReplyConfirmation: PropTypes.bool,
|
|
||||||
withOpenButton: PropTypes.bool,
|
|
||||||
onClose: PropTypes.func,
|
|
||||||
...WithRouterPropTypes,
|
|
||||||
};
|
|
||||||
|
|
||||||
_performReply = () => {
|
|
||||||
const { dispatch, status, onClose } = this.props;
|
|
||||||
|
|
||||||
if (onClose) {
|
|
||||||
onClose(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(replyCompose(status));
|
|
||||||
};
|
|
||||||
|
|
||||||
handleReplyClick = () => {
|
|
||||||
const { dispatch, askReplyConfirmation, status, onClose } = this.props;
|
|
||||||
const { signedIn } = this.props.identity;
|
|
||||||
|
|
||||||
if (signedIn) {
|
|
||||||
if (askReplyConfirmation) {
|
|
||||||
onClose(true);
|
|
||||||
dispatch(openModal({ modalType: 'CONFIRM_REPLY', modalProps: { status } }));
|
|
||||||
} else {
|
|
||||||
this._performReply();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dispatch(openModal({
|
|
||||||
modalType: 'INTERACTION',
|
|
||||||
modalProps: {
|
|
||||||
type: 'reply',
|
|
||||||
accountId: status.getIn(['account', 'id']),
|
|
||||||
url: status.get('uri'),
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleFavouriteClick = () => {
|
|
||||||
const { dispatch, status } = this.props;
|
|
||||||
const { signedIn } = this.props.identity;
|
|
||||||
|
|
||||||
if (signedIn) {
|
|
||||||
dispatch(toggleFavourite(status.get('id')));
|
|
||||||
} else {
|
|
||||||
dispatch(openModal({
|
|
||||||
modalType: 'INTERACTION',
|
|
||||||
modalProps: {
|
|
||||||
type: 'favourite',
|
|
||||||
accountId: status.getIn(['account', 'id']),
|
|
||||||
url: status.get('uri'),
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleReblogClick = e => {
|
|
||||||
const { dispatch, status } = this.props;
|
|
||||||
const { signedIn } = this.props.identity;
|
|
||||||
|
|
||||||
if (signedIn) {
|
|
||||||
dispatch(toggleReblog(status.get('id'), e && e.shiftKey));
|
|
||||||
} else {
|
|
||||||
dispatch(openModal({
|
|
||||||
modalType: 'INTERACTION',
|
|
||||||
modalProps: {
|
|
||||||
type: 'reblog',
|
|
||||||
accountId: status.getIn(['account', 'id']),
|
|
||||||
url: status.get('uri'),
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleOpenClick = e => {
|
|
||||||
if (e.button !== 0 || !history) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { status, onClose } = this.props;
|
|
||||||
|
|
||||||
if (onClose) {
|
|
||||||
onClose();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.history.push(`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { status, intl, withOpenButton } = this.props;
|
|
||||||
|
|
||||||
const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
|
|
||||||
const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility') === 'private';
|
|
||||||
|
|
||||||
let replyIcon, replyIconComponent, replyTitle;
|
|
||||||
|
|
||||||
if (status.get('in_reply_to_id', null) === null) {
|
|
||||||
replyIcon = 'reply';
|
|
||||||
replyIconComponent = ReplyIcon;
|
|
||||||
replyTitle = intl.formatMessage(messages.reply);
|
|
||||||
} else {
|
|
||||||
replyIcon = 'reply-all';
|
|
||||||
replyIconComponent = ReplyAllIcon;
|
|
||||||
replyTitle = intl.formatMessage(messages.replyAll);
|
|
||||||
}
|
|
||||||
|
|
||||||
let reblogTitle, reblogIconComponent;
|
|
||||||
|
|
||||||
if (status.get('reblogged')) {
|
|
||||||
reblogTitle = intl.formatMessage(messages.cancel_reblog_private);
|
|
||||||
reblogIconComponent = publicStatus ? RepeatIcon : RepeatPrivateIcon;
|
|
||||||
} else if (publicStatus) {
|
|
||||||
reblogTitle = intl.formatMessage(messages.reblog);
|
|
||||||
reblogIconComponent = RepeatIcon;
|
|
||||||
} else if (reblogPrivate) {
|
|
||||||
reblogTitle = intl.formatMessage(messages.reblog_private);
|
|
||||||
reblogIconComponent = RepeatPrivateIcon;
|
|
||||||
} else {
|
|
||||||
reblogTitle = intl.formatMessage(messages.cannot_reblog);
|
|
||||||
reblogIconComponent = RepeatDisabledIcon;
|
|
||||||
}
|
|
||||||
|
|
||||||
const favouriteTitle = intl.formatMessage(status.get('favourited') ? messages.removeFavourite : messages.favourite);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='picture-in-picture__footer'>
|
|
||||||
<IconButton className='status__action-bar-button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} iconComponent={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? ReplyIcon : replyIconComponent} onClick={this.handleReplyClick} counter={status.get('replies_count')} />
|
|
||||||
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={reblogIconComponent} onClick={this.handleReblogClick} counter={status.get('reblogs_count')} />
|
|
||||||
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={favouriteTitle} icon='star' iconComponent={StarIcon} onClick={this.handleFavouriteClick} counter={status.get('favourites_count')} />
|
|
||||||
{withOpenButton && <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.open)} icon='external-link' iconComponent={OpenInNewIcon} onClick={this.handleOpenClick} href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} />}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(makeMapStateToProps)(withIdentity(withRouter(injectIntl(Footer))));
|
|
|
@ -0,0 +1,255 @@
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
|
import OpenInNewIcon from '@/material-icons/400-24px/open_in_new.svg?react';
|
||||||
|
import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
|
||||||
|
import ReplyIcon from '@/material-icons/400-24px/reply.svg?react';
|
||||||
|
import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react';
|
||||||
|
import StarIcon from '@/material-icons/400-24px/star-fill.svg?react';
|
||||||
|
import StarBorderIcon from '@/material-icons/400-24px/star.svg?react';
|
||||||
|
import RepeatActiveIcon from '@/svg-icons/repeat_active.svg?react';
|
||||||
|
import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg?react';
|
||||||
|
import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react';
|
||||||
|
import RepeatPrivateActiveIcon from '@/svg-icons/repeat_private_active.svg?react';
|
||||||
|
import { replyCompose } from 'mastodon/actions/compose';
|
||||||
|
import { toggleReblog, toggleFavourite } from 'mastodon/actions/interactions';
|
||||||
|
import { openModal } from 'mastodon/actions/modal';
|
||||||
|
import { IconButton } from 'mastodon/components/icon_button';
|
||||||
|
import { useIdentity } from 'mastodon/identity_context';
|
||||||
|
import { me } from 'mastodon/initial_state';
|
||||||
|
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
reply: { id: 'status.reply', defaultMessage: 'Reply' },
|
||||||
|
replyAll: { id: 'status.replyAll', defaultMessage: 'Reply to thread' },
|
||||||
|
reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
|
||||||
|
reblog_private: {
|
||||||
|
id: 'status.reblog_private',
|
||||||
|
defaultMessage: 'Boost with original visibility',
|
||||||
|
},
|
||||||
|
cancel_reblog_private: {
|
||||||
|
id: 'status.cancel_reblog_private',
|
||||||
|
defaultMessage: 'Unboost',
|
||||||
|
},
|
||||||
|
cannot_reblog: {
|
||||||
|
id: 'status.cannot_reblog',
|
||||||
|
defaultMessage: 'This post cannot be boosted',
|
||||||
|
},
|
||||||
|
favourite: { id: 'status.favourite', defaultMessage: 'Favorite' },
|
||||||
|
removeFavourite: {
|
||||||
|
id: 'status.remove_favourite',
|
||||||
|
defaultMessage: 'Remove from favorites',
|
||||||
|
},
|
||||||
|
open: { id: 'status.open', defaultMessage: 'Expand this status' },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const Footer: React.FC<{
|
||||||
|
statusId: string;
|
||||||
|
withOpenButton?: boolean;
|
||||||
|
onClose: (arg0?: boolean) => void;
|
||||||
|
}> = ({ statusId, withOpenButton, onClose }) => {
|
||||||
|
const { signedIn } = useIdentity();
|
||||||
|
const intl = useIntl();
|
||||||
|
const history = useHistory();
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const status = useAppSelector((state) => state.statuses.get(statusId));
|
||||||
|
const accountId = status?.get('account') as string | undefined;
|
||||||
|
const account = useAppSelector((state) =>
|
||||||
|
accountId ? state.accounts.get(accountId) : undefined,
|
||||||
|
);
|
||||||
|
const askReplyConfirmation = useAppSelector(
|
||||||
|
(state) => (state.compose.get('text') as string).trim().length !== 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleReplyClick = useCallback(() => {
|
||||||
|
if (!status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (signedIn) {
|
||||||
|
onClose(true);
|
||||||
|
|
||||||
|
if (askReplyConfirmation) {
|
||||||
|
dispatch(
|
||||||
|
openModal({ modalType: 'CONFIRM_REPLY', modalProps: { status } }),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
dispatch(replyCompose(status));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dispatch(
|
||||||
|
openModal({
|
||||||
|
modalType: 'INTERACTION',
|
||||||
|
modalProps: {
|
||||||
|
type: 'reply',
|
||||||
|
accountId: status.getIn(['account', 'id']),
|
||||||
|
url: status.get('uri'),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [dispatch, status, signedIn, askReplyConfirmation, onClose]);
|
||||||
|
|
||||||
|
const handleFavouriteClick = useCallback(() => {
|
||||||
|
if (!status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (signedIn) {
|
||||||
|
dispatch(toggleFavourite(status.get('id')));
|
||||||
|
} else {
|
||||||
|
dispatch(
|
||||||
|
openModal({
|
||||||
|
modalType: 'INTERACTION',
|
||||||
|
modalProps: {
|
||||||
|
type: 'favourite',
|
||||||
|
accountId: status.getIn(['account', 'id']),
|
||||||
|
url: status.get('uri'),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [dispatch, status, signedIn]);
|
||||||
|
|
||||||
|
const handleReblogClick = useCallback(
|
||||||
|
(e: React.MouseEvent) => {
|
||||||
|
if (!status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (signedIn) {
|
||||||
|
dispatch(toggleReblog(status.get('id'), e.shiftKey));
|
||||||
|
} else {
|
||||||
|
dispatch(
|
||||||
|
openModal({
|
||||||
|
modalType: 'INTERACTION',
|
||||||
|
modalProps: {
|
||||||
|
type: 'reblog',
|
||||||
|
accountId: status.getIn(['account', 'id']),
|
||||||
|
url: status.get('uri'),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[dispatch, status, signedIn],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleOpenClick = useCallback(
|
||||||
|
(e: React.MouseEvent) => {
|
||||||
|
if (e.button !== 0 || !status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
onClose();
|
||||||
|
|
||||||
|
history.push(`/@${account?.acct}/${status.get('id') as string}`);
|
||||||
|
},
|
||||||
|
[history, status, account, onClose],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!status) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const publicStatus = ['public', 'unlisted'].includes(
|
||||||
|
status.get('visibility') as string,
|
||||||
|
);
|
||||||
|
const reblogPrivate =
|
||||||
|
status.getIn(['account', 'id']) === me &&
|
||||||
|
status.get('visibility') === 'private';
|
||||||
|
|
||||||
|
let replyIcon, replyIconComponent, replyTitle;
|
||||||
|
|
||||||
|
if (status.get('in_reply_to_id', null) === null) {
|
||||||
|
replyIcon = 'reply';
|
||||||
|
replyIconComponent = ReplyIcon;
|
||||||
|
replyTitle = intl.formatMessage(messages.reply);
|
||||||
|
} else {
|
||||||
|
replyIcon = 'reply-all';
|
||||||
|
replyIconComponent = ReplyAllIcon;
|
||||||
|
replyTitle = intl.formatMessage(messages.replyAll);
|
||||||
|
}
|
||||||
|
|
||||||
|
let reblogTitle, reblogIconComponent;
|
||||||
|
|
||||||
|
if (status.get('reblogged')) {
|
||||||
|
reblogTitle = intl.formatMessage(messages.cancel_reblog_private);
|
||||||
|
reblogIconComponent = publicStatus
|
||||||
|
? RepeatActiveIcon
|
||||||
|
: RepeatPrivateActiveIcon;
|
||||||
|
} else if (publicStatus) {
|
||||||
|
reblogTitle = intl.formatMessage(messages.reblog);
|
||||||
|
reblogIconComponent = RepeatIcon;
|
||||||
|
} else if (reblogPrivate) {
|
||||||
|
reblogTitle = intl.formatMessage(messages.reblog_private);
|
||||||
|
reblogIconComponent = RepeatPrivateIcon;
|
||||||
|
} else {
|
||||||
|
reblogTitle = intl.formatMessage(messages.cannot_reblog);
|
||||||
|
reblogIconComponent = RepeatDisabledIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
const favouriteTitle = intl.formatMessage(
|
||||||
|
status.get('favourited') ? messages.removeFavourite : messages.favourite,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='picture-in-picture__footer'>
|
||||||
|
<IconButton
|
||||||
|
className='status__action-bar-button'
|
||||||
|
title={replyTitle}
|
||||||
|
icon={
|
||||||
|
status.get('in_reply_to_account_id') ===
|
||||||
|
status.getIn(['account', 'id'])
|
||||||
|
? 'reply'
|
||||||
|
: replyIcon
|
||||||
|
}
|
||||||
|
iconComponent={
|
||||||
|
status.get('in_reply_to_account_id') ===
|
||||||
|
status.getIn(['account', 'id'])
|
||||||
|
? ReplyIcon
|
||||||
|
: replyIconComponent
|
||||||
|
}
|
||||||
|
onClick={handleReplyClick}
|
||||||
|
counter={status.get('replies_count') as number}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<IconButton
|
||||||
|
className={classNames('status__action-bar-button', { reblogPrivate })}
|
||||||
|
disabled={!publicStatus && !reblogPrivate}
|
||||||
|
active={status.get('reblogged') as boolean}
|
||||||
|
title={reblogTitle}
|
||||||
|
icon='retweet'
|
||||||
|
iconComponent={reblogIconComponent}
|
||||||
|
onClick={handleReblogClick}
|
||||||
|
counter={status.get('reblogs_count') as number}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<IconButton
|
||||||
|
className='status__action-bar-button star-icon'
|
||||||
|
animate
|
||||||
|
active={status.get('favourited') as boolean}
|
||||||
|
title={favouriteTitle}
|
||||||
|
icon='star'
|
||||||
|
iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon}
|
||||||
|
onClick={handleFavouriteClick}
|
||||||
|
counter={status.get('favourites_count') as number}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{withOpenButton && (
|
||||||
|
<IconButton
|
||||||
|
className='status__action-bar-button'
|
||||||
|
title={intl.formatMessage(messages.open)}
|
||||||
|
icon='external-link'
|
||||||
|
iconComponent={OpenInNewIcon}
|
||||||
|
onClick={handleOpenClick}
|
||||||
|
href={`/@${account?.acct}/${status.get('id') as string}`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -5,7 +5,7 @@ import { Audio } from 'mastodon/features/audio';
|
||||||
import { Video } from 'mastodon/features/video';
|
import { Video } from 'mastodon/features/video';
|
||||||
import { useAppDispatch, useAppSelector } from 'mastodon/store/typed_functions';
|
import { useAppDispatch, useAppSelector } from 'mastodon/store/typed_functions';
|
||||||
|
|
||||||
import Footer from './components/footer';
|
import { Footer } from './components/footer';
|
||||||
import { Header } from './components/header';
|
import { Header } from './components/header';
|
||||||
|
|
||||||
export const PictureInPicture: React.FC = () => {
|
export const PictureInPicture: React.FC = () => {
|
||||||
|
@ -76,7 +76,7 @@ export const PictureInPicture: React.FC = () => {
|
||||||
|
|
||||||
{player}
|
{player}
|
||||||
|
|
||||||
<Footer statusId={statusId} />
|
<Footer statusId={statusId} onClose={handleClose} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { useEffect } from 'react';
|
||||||
import { getAverageFromBlurhash } from 'mastodon/blurhash';
|
import { getAverageFromBlurhash } from 'mastodon/blurhash';
|
||||||
import type { RGB } from 'mastodon/blurhash';
|
import type { RGB } from 'mastodon/blurhash';
|
||||||
import { Audio } from 'mastodon/features/audio';
|
import { Audio } from 'mastodon/features/audio';
|
||||||
import Footer from 'mastodon/features/picture_in_picture/components/footer';
|
import { Footer } from 'mastodon/features/picture_in_picture/components/footer';
|
||||||
import type { MediaAttachment } from 'mastodon/models/media_attachment';
|
import type { MediaAttachment } from 'mastodon/models/media_attachment';
|
||||||
import { useAppSelector } from 'mastodon/store';
|
import { useAppSelector } from 'mastodon/store';
|
||||||
|
|
||||||
|
@ -64,8 +64,7 @@ const AudioModal: React.FC<{
|
||||||
<div className='media-modal__overlay'>
|
<div className='media-modal__overlay'>
|
||||||
{status && (
|
{status && (
|
||||||
<Footer
|
<Footer
|
||||||
statusId={status.get('id')}
|
statusId={status.get('id') as string}
|
||||||
// @ts-expect-error Component needs to be refactored
|
|
||||||
withOpenButton
|
withOpenButton
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { getAverageFromBlurhash } from 'mastodon/blurhash';
|
||||||
import { GIFV } from 'mastodon/components/gifv';
|
import { GIFV } from 'mastodon/components/gifv';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import { IconButton } from 'mastodon/components/icon_button';
|
import { IconButton } from 'mastodon/components/icon_button';
|
||||||
import Footer from 'mastodon/features/picture_in_picture/components/footer';
|
import { Footer } from 'mastodon/features/picture_in_picture/components/footer';
|
||||||
import { Video } from 'mastodon/features/video';
|
import { Video } from 'mastodon/features/video';
|
||||||
import { disableSwiping } from 'mastodon/initial_state';
|
import { disableSwiping } from 'mastodon/initial_state';
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { getAverageFromBlurhash } from 'mastodon/blurhash';
|
import { getAverageFromBlurhash } from 'mastodon/blurhash';
|
||||||
import Footer from 'mastodon/features/picture_in_picture/components/footer';
|
import { Footer } from 'mastodon/features/picture_in_picture/components/footer';
|
||||||
import { Video } from 'mastodon/features/video';
|
import { Video } from 'mastodon/features/video';
|
||||||
|
|
||||||
const mapStateToProps = (state, { statusId }) => ({
|
const mapStateToProps = (state, { statusId }) => ({
|
||||||
|
|
|
@ -8542,23 +8542,33 @@ noscript {
|
||||||
bottom: 20px;
|
bottom: 20px;
|
||||||
inset-inline-end: 20px;
|
inset-inline-end: 20px;
|
||||||
width: 300px;
|
width: 300px;
|
||||||
|
box-shadow: var(--dropdown-shadow);
|
||||||
|
|
||||||
&__footer {
|
&__footer {
|
||||||
border-radius: 0 0 4px 4px;
|
border-radius: 0 0 4px 4px;
|
||||||
background: lighten($ui-base-color, 4%);
|
background: var(--modal-background-variant-color);
|
||||||
padding: 10px;
|
backdrop-filter: var(--background-filter);
|
||||||
padding-top: 12px;
|
border: 1px solid var(--modal-border-color);
|
||||||
|
border-top: 0;
|
||||||
|
padding: 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__header {
|
&__header {
|
||||||
border-radius: 4px 4px 0 0;
|
border-radius: 4px 4px 0 0;
|
||||||
background: lighten($ui-base-color, 4%);
|
background: var(--modal-background-variant-color);
|
||||||
padding: 10px;
|
backdrop-filter: var(--background-filter);
|
||||||
|
border: 1px solid var(--modal-border-color);
|
||||||
|
border-bottom: 0;
|
||||||
|
padding: 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.icon-button {
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
&__account {
|
&__account {
|
||||||
display: flex;
|
display: flex;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
@ -8566,7 +8576,7 @@ noscript {
|
||||||
}
|
}
|
||||||
|
|
||||||
.account__avatar {
|
.account__avatar {
|
||||||
margin-inline-end: 10px;
|
margin-inline-end: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.display-name {
|
.display-name {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user