From c62d22ff46fec65d5a607f540aa2c67069c6dce3 Mon Sep 17 00:00:00 2001 From: b-xb <7443583+b-xb@users.noreply.github.com> Date: Sat, 7 Oct 2023 00:02:37 +0100 Subject: [PATCH] add status prepend for followed hashtags to home timeline --- app/javascript/mastodon/components/status.jsx | 36 ++++++++++++++++--- .../mastodon/containers/status_container.jsx | 22 ++++++++---- .../styles/mastodon/components.scss | 5 +++ app/serializers/rest/status_serializer.rb | 9 +++++ 4 files changed, 61 insertions(+), 11 deletions(-) diff --git a/app/javascript/mastodon/components/status.jsx b/app/javascript/mastodon/components/status.jsx index 4a5ad54a1c..b6802339f5 100644 --- a/app/javascript/mastodon/components/status.jsx +++ b/app/javascript/mastodon/components/status.jsx @@ -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 { }} /> ); + } else if (contextType==="home" && !followingAccount && followedTags.size > 0) { + + const followedTagsAsLinks = followedTags.map((tag, index) => { + const tagName = { __html: "#"+tag.get("name") }; + + return ( + + { !!index && , } + { } + + ) + }); + + prepend = ( +
+
+ { followedTagsAsLinks } }} /> +
+ ); } 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 = ; } else { - statusAvatar = ; + statusAvatar = ; } const visibilityIconInfo = { @@ -587,7 +613,7 @@ class Status extends ImmutablePureComponent { {expanded && hashtagBar} - + diff --git a/app/javascript/mastodon/containers/status_container.jsx b/app/javascript/mastodon/containers/status_container.jsx index 7a7cd9880f..7d5c633bd1 100644 --- a/app/javascript/mastodon/containers/status_container.jsx +++ b/app/javascript/mastodon/containers/status_container.jsx @@ -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), - nextInReplyToId: props.nextId ? state.getIn(['statuses', props.nextId, 'in_reply_to_id']) : null, - pictureInPicture: getPictureInPicture(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(); diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index f0380de5bf..e52e8e038b 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -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; diff --git a/app/serializers/rest/status_serializer.rb b/app/serializers/rest/status_serializer.rb index d32621541a..89c2c5aece 100644 --- a/app/serializers/rest/status_serializer.rb +++ b/app/serializers/rest/status_serializer.rb @@ -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