add status prepend for followed hashtags to home timeline

This commit is contained in:
b-xb 2023-10-07 00:02:37 +01:00
parent 3262d1f1b6
commit c62d22ff46
4 changed files with 61 additions and 11 deletions

View File

@ -1,4 +1,6 @@
import PropTypes from 'prop-types';
import React from 'react';
import { injectIntl, defineMessages, FormattedMessage } from 'react-intl';
@ -77,6 +79,7 @@ class Status extends ImmutablePureComponent {
};
static propTypes = {
contextType: PropTypes.string,
status: ImmutablePropTypes.map,
account: ImmutablePropTypes.map,
previousId: PropTypes.string,
@ -347,7 +350,11 @@ class Status extends ImmutablePureComponent {
render () {
const { intl, hidden, featured, unread, showThread, scrollKey, pictureInPicture, previousId, nextInReplyToId, rootId } = this.props;
let { status, account, ...other } = this.props;
let { status, account, contextType, ...other } = this.props;
let reblog_account = null;
const followingAccount = account.getIn(['relationship','following']);
const followedTags = this.props.status.get('tags').filter((tag)=>tag.get('following'))
if (status === null) {
return null;
@ -423,7 +430,7 @@ class Status extends ImmutablePureComponent {
rebloggedByText = intl.formatMessage({ id: 'status.reblogged_by', defaultMessage: '{name} boosted' }, { name: status.getIn(['account', 'acct']) });
account = status.get('account');
reblog_account = status.get('account');
status = status.get('reblog');
} else if (status.get('visibility') === 'direct') {
prepend = (
@ -441,6 +448,25 @@ class Status extends ImmutablePureComponent {
<FormattedMessage id='status.replied_to' defaultMessage='Replied to {name}' values={{ name: <a onClick={this.handlePrependAccountClick} data-id={status.getIn(['account', 'id'])} href={`/@${status.getIn(['account', 'acct'])}`} className='status__display-name muted'><bdi><strong dangerouslySetInnerHTML={display_name_html} /></bdi></a> }} />
</div>
);
} else if (contextType==="home" && !followingAccount && followedTags.size > 0) {
const followedTagsAsLinks = followedTags.map((tag, index) => {
const tagName = { __html: "#"+tag.get("name") };
return (
<React.Fragment key={index} >
{ !!index && <span>, </span> }
{ <a href={tag.get("url")}><bdi><strong dangerouslySetInnerHTML={tagName} /></bdi></a> }
</React.Fragment>
)
});
prepend = (
<div className='status__prepend'>
<div className='status__prepend-icon-wrapper'><Icon id='hashtag' className='status__prepend-icon' fixedWidth /></div>
<FormattedMessage id='status.followed_hashtags' defaultMessage='Followed hashtag(s): {hashtags}' values={{ hashtags: <span>{ followedTagsAsLinks }</span> }} />
</div>
);
}
if (pictureInPicture.get('inUse')) {
@ -530,10 +556,10 @@ class Status extends ImmutablePureComponent {
);
}
if (account === undefined || account === null) {
if (reblog_account === undefined || reblog_account === null) {
statusAvatar = <Avatar account={status.get('account')} size={46} />;
} else {
statusAvatar = <AvatarOverlay account={status.get('account')} friend={account} />;
statusAvatar = <AvatarOverlay account={status.get('account')} friend={reblog_account} />;
}
const visibilityIconInfo = {
@ -587,7 +613,7 @@ class Status extends ImmutablePureComponent {
{expanded && hashtagBar}
<StatusActionBar scrollKey={scrollKey} status={status} account={account} onFilter={matchedFilters ? this.handleFilterClick : null} {...other} />
<StatusActionBar scrollKey={scrollKey} status={status} account={reblog_account} onFilter={matchedFilters ? this.handleFilterClick : null} {...other} />
</div>
</div>
</HotKeys>

View File

@ -48,7 +48,7 @@ import {
} from '../actions/statuses';
import Status from '../components/status';
import { boostModal, deleteModal } from '../initial_state';
import { makeGetStatus, makeGetPictureInPicture } from '../selectors';
import { makeGetStatus, makeGetPictureInPicture, makeGetAccount } from '../selectors';
const messages = defineMessages({
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
@ -66,17 +66,27 @@ const makeMapStateToProps = () => {
const getStatus = makeGetStatus();
const getPictureInPicture = makeGetPictureInPicture();
const mapStateToProps = (state, props) => ({
status: getStatus(state, props),
const getAccount = makeGetAccount();
const mapStateToProps = (state, props) => {
const status = getStatus(state, props);
const accountId = status.getIn(['account', 'id']);
const account = getAccount(state, accountId);
return {
status,
account,
nextInReplyToId: props.nextId ? state.getIn(['statuses', props.nextId, 'in_reply_to_id']) : null,
pictureInPicture: getPictureInPicture(state, props),
});
}
};
return mapStateToProps;
};
const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
contextType,
onReply (status, router) {
dispatch((_, getState) => {
let state = getState();

View File

@ -1270,6 +1270,11 @@ body > [data-popper-placement] {
color: $dark-text-color;
}
a {
color: $dark-text-color;
text-decoration: none;
}
> span {
display: block;
overflow: hidden;

View File

@ -190,9 +190,18 @@ class REST::StatusSerializer < ActiveModel::Serializer
include RoutingHelper
attributes :name, :url
attribute :following, if: :current_user?
def url
tag_url(object)
end
def following
TagFollow.exists?(tag_id: object.id, account_id: current_user.account_id)
end
def current_user?
!current_user.nil?
end
end
end