diff --git a/app/controllers/api/v1/accounts/statuses_controller.rb b/app/controllers/api/v1/accounts/statuses_controller.rb index 381bb2eb9..6a6c93dfa 100644 --- a/app/controllers/api/v1/accounts/statuses_controller.rb +++ b/app/controllers/api/v1/accounts/statuses_controller.rb @@ -8,9 +8,9 @@ class Api::V1::Accounts::StatusesController < Api::BaseController def index cache_if_unauthenticated! - @statuses = load_statuses + @statuses = load_statuses + accounts = @statuses.filter_map { |status| status.quote&.account }.uniq account_ids = @statuses.filter(&:quote?).map { |status| status.quote.account_id }.uniq - accounts = Account.where(id: account_ids) render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id), account_relationships: AccountRelationshipsPresenter.new(accounts, current_user&.account_id) diff --git a/app/controllers/api/v1/bookmarks_controller.rb b/app/controllers/api/v1/bookmarks_controller.rb index 2d3c0a561..803013eeb 100644 --- a/app/controllers/api/v1/bookmarks_controller.rb +++ b/app/controllers/api/v1/bookmarks_controller.rb @@ -6,9 +6,9 @@ class Api::V1::BookmarksController < Api::BaseController after_action :insert_pagination_headers def index - @statuses = load_statuses + @statuses = load_statuses + accounts = @statuses.filter_map { |status| status.quote&.account }.uniq account_ids = @statuses.filter(&:quote?).map { |status| status.quote.account_id }.uniq - accounts = Account.where(id: account_ids) render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id), account_relationships: AccountRelationshipsPresenter.new(accounts, current_user&.account_id) diff --git a/app/controllers/api/v1/favourites_controller.rb b/app/controllers/api/v1/favourites_controller.rb index 4c34445eb..5e0c9d3e6 100644 --- a/app/controllers/api/v1/favourites_controller.rb +++ b/app/controllers/api/v1/favourites_controller.rb @@ -6,9 +6,9 @@ class Api::V1::FavouritesController < Api::BaseController after_action :insert_pagination_headers def index - @statuses = load_statuses + @statuses = load_statuses + accounts = @statuses.filter_map { |status| status.quote&.account }.uniq account_ids = @statuses.filter(&:quote?).map { |status| status.quote.account_id }.uniq - accounts = Account.where(id: account_ids) render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id), account_relationships: AccountRelationshipsPresenter.new(accounts, current_user&.account_id) diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb index bc7d7076b..0ba548e98 100644 --- a/app/controllers/api/v1/statuses_controller.rb +++ b/app/controllers/api/v1/statuses_controller.rb @@ -47,10 +47,10 @@ class Api::V1::StatusesController < Api::BaseController loaded_ancestors = cache_collection(ancestors_results, Status) loaded_descendants = cache_collection(descendants_results, Status) - @context = Context.new(ancestors: loaded_ancestors, descendants: loaded_descendants) - statuses = [@status] + @context.ancestors + @context.descendants + @context = Context.new(ancestors: loaded_ancestors, descendants: loaded_descendants) + statuses = [@status] + @context.ancestors + @context.descendants + accounts = statuses.filter_map { |status| status.quote&.account }.uniq account_ids = statuses.filter(&:quote?).map { |status| status.quote.account_id }.uniq - accounts = Account.where(id: account_ids) render json: @context, serializer: REST::ContextSerializer, relationships: StatusRelationshipsPresenter.new(statuses, current_user&.account_id), diff --git a/app/controllers/api/v1/timelines/home_controller.rb b/app/controllers/api/v1/timelines/home_controller.rb index 199d04e16..bd89382f6 100644 --- a/app/controllers/api/v1/timelines/home_controller.rb +++ b/app/controllers/api/v1/timelines/home_controller.rb @@ -10,8 +10,8 @@ class Api::V1::Timelines::HomeController < Api::V1::Timelines::BaseController with_read_replica do @statuses = load_statuses @relationships = StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) + accounts = @statuses.filter_map { |status| status.quote&.account }.uniq account_ids = @statuses.filter(&:quote?).map { |status| status.quote.account_id }.uniq - accounts = Account.where(id: account_ids) @account_relationships = AccountRelationshipsPresenter.new(accounts, current_user&.account_id) end diff --git a/app/controllers/api/v1/timelines/list_controller.rb b/app/controllers/api/v1/timelines/list_controller.rb index 7e42e6490..3faac2f16 100644 --- a/app/controllers/api/v1/timelines/list_controller.rb +++ b/app/controllers/api/v1/timelines/list_controller.rb @@ -9,8 +9,8 @@ class Api::V1::Timelines::ListController < Api::V1::Timelines::BaseController PERMITTED_PARAMS = %i(limit).freeze def show + accounts = @statuses.filter_map { |status| status.quote&.account }.uniq account_ids = @statuses.filter(&:quote?).map { |status| status.quote.account_id }.uniq - accounts = Account.where(id: account_ids) render json: @statuses, each_serializer: REST::StatusSerializer, diff --git a/app/controllers/api/v1/timelines/public_controller.rb b/app/controllers/api/v1/timelines/public_controller.rb index a37b56110..a47c9c696 100644 --- a/app/controllers/api/v1/timelines/public_controller.rb +++ b/app/controllers/api/v1/timelines/public_controller.rb @@ -7,9 +7,9 @@ class Api::V1::Timelines::PublicController < Api::V1::Timelines::BaseController def show cache_if_unauthenticated! - @statuses = load_statuses + @statuses = load_statuses + accounts = @statuses.filter_map { |status| status.quote&.account }.uniq account_ids = @statuses.filter(&:quote?).map { |status| status.quote.account_id }.uniq - accounts = Account.where(id: account_ids) render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id), diff --git a/app/controllers/api/v1/timelines/tag_controller.rb b/app/controllers/api/v1/timelines/tag_controller.rb index 97e245b09..559dd7331 100644 --- a/app/controllers/api/v1/timelines/tag_controller.rb +++ b/app/controllers/api/v1/timelines/tag_controller.rb @@ -8,9 +8,9 @@ class Api::V1::Timelines::TagController < Api::V1::Timelines::BaseController def show cache_if_unauthenticated! - @statuses = load_statuses + @statuses = load_statuses + accounts = @statuses.filter_map { |status| status.quote&.account }.uniq account_ids = @statuses.filter(&:quote?).map { |status| status.quote.account_id }.uniq - accounts = Account.where(id: account_ids) render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id), diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js index cce3f46bb..46181a865 100644 --- a/app/javascript/mastodon/actions/compose.js +++ b/app/javascript/mastodon/actions/compose.js @@ -25,7 +25,6 @@ export const COMPOSE_SUBMIT_FAIL = 'COMPOSE_SUBMIT_FAIL'; export const COMPOSE_REPLY = 'COMPOSE_REPLY'; export const COMPOSE_REPLY_CANCEL = 'COMPOSE_REPLY_CANCEL'; export const COMPOSE_QUOTE = 'COMPOSE_QUOTE'; -export const COMPOSE_QUOTE_CANCEL = 'COMPOSE_QUOTE_CANCEL'; export const COMPOSE_DIRECT = 'COMPOSE_DIRECT'; export const COMPOSE_MENTION = 'COMPOSE_MENTION'; export const COMPOSE_RESET = 'COMPOSE_RESET'; @@ -137,13 +136,7 @@ export function quoteCompose(status, routerHistory) { ensureComposeIsVisible(getState, routerHistory); }; -}; - -export function cancelQuoteCompose() { - return { - type: COMPOSE_QUOTE_CANCEL, - }; -}; +} export function resetCompose() { return { diff --git a/app/javascript/mastodon/actions/statuses.js b/app/javascript/mastodon/actions/statuses.js index cc28df31f..f76303335 100644 --- a/app/javascript/mastodon/actions/statuses.js +++ b/app/javascript/mastodon/actions/statuses.js @@ -361,7 +361,7 @@ export function hideQuote(ids) { type: QUOTE_HIDE, ids, }; -}; +} export function revealQuote(ids) { if (!Array.isArray(ids)) { @@ -372,4 +372,4 @@ export function revealQuote(ids) { type: QUOTE_REVEAL, ids, }; -}; +} diff --git a/app/javascript/mastodon/components/status.jsx b/app/javascript/mastodon/components/status.jsx index 479f1f920..65441b7b9 100644 --- a/app/javascript/mastodon/components/status.jsx +++ b/app/javascript/mastodon/components/status.jsx @@ -134,7 +134,7 @@ export const quote = (status, muted, quoteMuted, handleQuoteClick, handleExpande return (
- {identity(quoteStatus, null, null, true)} + {identity(quoteStatus, null, true)}
{media(quoteStatus, true)} @@ -146,7 +146,6 @@ export const quote = (status, muted, quoteMuted, handleQuoteClick, handleExpande
{quoteInner}
@@ -238,7 +237,7 @@ class Status extends ImmutablePureComponent { handleToggleQuoteMediaVisibility = () => { this.setState({ showQuoteMedia: !this.state.showQuoteMedia }); - } + }; handleClick = e => { if (e && (e.button !== 0 || e.ctrlKey || e.metaKey)) { @@ -253,10 +252,6 @@ class Status extends ImmutablePureComponent { }; handlePrependAccountClick = e => { - this.handleAccountClick(e, false); - }; - - handleAccountClick = (e, proper = true) => { if (e && (e.button !== 0 || e.ctrlKey || e.metaKey)) { return; } @@ -266,17 +261,29 @@ class Status extends ImmutablePureComponent { e.stopPropagation(); } - this._openProfile(proper); + this._openProfile(false); }; - handleQuoteClick = () => { - if (!this.props) { + handleAccountClick = (e) => { + if (e && (e.button !== 0 || e.ctrlKey || e.metaKey)) { return; } - const { status } = this.props; - this.props.history.push(`/statuses/${status.getIn(['reblog', 'quote', 'id'], status.getIn(['quote', 'id']))}`); - } + if (e) { + e.preventDefault(); + e.stopPropagation(); + } + + const acct = e.currentTarget.getAttribute('data-acct'); + this.props.history.push(`/@${acct}`); + }; + + handleQuoteClick = () => { + if (this.props.history) { + const status = this._properStatus(); + this.props.history.push(`/@${status.getIn(['quote', 'account', 'acct'])}/${status.getIn(['quote', 'id'])}`); + } + }; handleQuoteUserClick = () =>{ if (!this.props) { @@ -301,7 +308,7 @@ class Status extends ImmutablePureComponent { handleExpandedQuoteToggle = () => { this.props.onQuoteToggleHidden(this._properStatus()); - } + }; getAttachmentAspectRatio () { const attachments = this._properStatus().get('media_attachments'); @@ -554,9 +561,10 @@ class Status extends ImmutablePureComponent {
); } + const media = (status, quote = false) => { if (pictureInPicture.get('inUse')) { - return ; + return ; } else if (status.get('media_attachments').size > 0) { const language = status.getIn(['translation', 'language']) || status.get('language'); @@ -655,9 +663,9 @@ class Status extends ImmutablePureComponent { return ; } }; - - const identity = (status, account, _0, quote = false) => ( - + + const identity = (status, account) => ( +
{statusAvatar(status, account)}
@@ -721,4 +729,4 @@ class Status extends ImmutablePureComponent { } -export default withOptionalRouter(injectIntl(Status)); \ No newline at end of file +export default connect(mapStateToProps)(withOptionalRouter(injectIntl(Status))); diff --git a/app/javascript/mastodon/components/status_action_bar.jsx b/app/javascript/mastodon/components/status_action_bar.jsx index 3a989ea42..0c2408c39 100644 --- a/app/javascript/mastodon/components/status_action_bar.jsx +++ b/app/javascript/mastodon/components/status_action_bar.jsx @@ -11,6 +11,7 @@ import { connect } from 'react-redux'; import BookmarkIcon from '@/material-icons/400-24px/bookmark-fill.svg'; import BookmarkBorderIcon from '@/material-icons/400-24px/bookmark.svg?react'; +import FormatQuoteIcon from '@/material-icons/400-24px/format_quote.svg?react'; import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; import ReplyIcon from '@/material-icons/400-24px/reply.svg?react'; @@ -160,8 +161,8 @@ class StatusActionBar extends ImmutablePureComponent { }; handleQuoteClick = () => { - this.props.onQuote(this.props.status, this.props.history); - } + this.props.onQuote(this.props.status); + }; handleBookmarkClick = () => { this.props.onBookmark(this.props.status); @@ -262,7 +263,7 @@ class StatusActionBar extends ImmutablePureComponent { } else { return intl.formatMessage(messages.cannot_quote); } - } + }; render () { const { status, relationship, intl, withDismiss, withCounters, scrollKey } = this.props; @@ -406,8 +407,8 @@ class StatusActionBar extends ImmutablePureComponent {
- - + + {filterButton} diff --git a/app/javascript/mastodon/components/status_content.jsx b/app/javascript/mastodon/components/status_content.jsx index ccbaf940c..c668ed989 100644 --- a/app/javascript/mastodon/components/status_content.jsx +++ b/app/javascript/mastodon/components/status_content.jsx @@ -241,7 +241,7 @@ class StatusContent extends PureComponent { }; render () { - const { status, intl, statusContent, quote } = this.props; + const { status, intl, quote, statusContent } = this.props; const hidden = this.props.onExpandedToggle ? !this.props.expanded : this.state.hidden; const renderReadMore = this.props.onClick && status.get('collapsed'); diff --git a/app/javascript/mastodon/features/compose/components/compose_form.jsx b/app/javascript/mastodon/features/compose/components/compose_form.jsx index bfd193708..28a34e77c 100644 --- a/app/javascript/mastodon/features/compose/components/compose_form.jsx +++ b/app/javascript/mastodon/features/compose/components/compose_form.jsx @@ -29,6 +29,7 @@ import { CharacterCounter } from './character_counter'; import { EditIndicator } from './edit_indicator'; import { NavigationBar } from './navigation_bar'; import { PollForm } from "./poll_form"; +import { QuoteIndicator } from './quote_indicator'; import { ReplyIndicator } from './reply_indicator'; const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d'; @@ -296,6 +297,8 @@ class ComposeForm extends ImmutablePureComponent { + +
diff --git a/app/javascript/mastodon/features/compose/components/quote_indicator.jsx b/app/javascript/mastodon/features/compose/components/quote_indicator.jsx new file mode 100644 index 000000000..12d8d57d1 --- /dev/null +++ b/app/javascript/mastodon/features/compose/components/quote_indicator.jsx @@ -0,0 +1,62 @@ +import { useCallback } from "react"; + +import { FormattedMessage, defineMessages, useIntl } from "react-intl"; + +import { Link } from "react-router-dom"; + +import { useDispatch, useSelector } from "react-redux"; + +import BarChart4BarsIcon from 'mastodon/../material-icons/400-24px/bar_chart_4_bars.svg?react'; +import CloseIcon from 'mastodon/../material-icons/400-24px/close.svg?react'; +import PhotoLibraryIcon from 'mastodon/../material-icons/400-24px/photo_library.svg?react'; +import { cancelReplyCompose } from "mastodon/actions/compose"; +import { Avatar } from "mastodon/components/avatar"; +import { DisplayName } from "mastodon/components/display_name"; +import { Icon } from "mastodon/components/icon"; +import { IconButton } from "mastodon/components/icon_button"; + +const messages = defineMessages({ + cancel: { id: 'reply_indicator.cancel', defaultMessage: 'Cancel' }, +}); + +export const QuoteIndicator = () => { + const intl = useIntl(); + const dispatch = useDispatch(); + const id = useSelector(state => state.getIn(['compose', 'quote_from'])); + const status = useSelector(state => state.getIn(['statuses', id])); + const account = useSelector(state => state.getIn(['accounts', status?.get('account')])); + + const handleCancelClick = useCallback(() => { + dispatch(cancelReplyCompose()); + }, [dispatch]); + + if (!status) { + return null; + } + + const content = { __html: status.get('contentHtml') }; + + return ( +
+
+ + + + + +
+ +
+
+ +
+ + {(status.get('poll') || status.get('media_attachments').size > 0) && ( +
+ {status.get('poll') && <>} + {status.get('media_attachments').size > 0 && <>} +
+ )} +
+ ); +}; diff --git a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx index 191133d05..91fe9729a 100644 --- a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx +++ b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx @@ -167,7 +167,7 @@ class Footer extends ImmutablePureComponent { } dispatch(quoteCompose(status, router.history)); - } + }; handleQuoteClick = () => { const { dispatch, askReplyConfirmation, intl } = this.props; @@ -181,7 +181,7 @@ class Footer extends ImmutablePureComponent { } else { this._performQuote(); } - } + }; handleOpenClick = e => { if (e.button !== 0 || !history) { diff --git a/app/javascript/mastodon/features/status/components/action_bar.jsx b/app/javascript/mastodon/features/status/components/action_bar.jsx index 8530f8976..7bc6e7429 100644 --- a/app/javascript/mastodon/features/status/components/action_bar.jsx +++ b/app/javascript/mastodon/features/status/components/action_bar.jsx @@ -11,6 +11,7 @@ import { connect } from 'react-redux'; import BookmarkIcon from '@/material-icons/400-24px/bookmark-fill.svg?react'; import BookmarkBorderIcon from '@/material-icons/400-24px/bookmark.svg?react'; +import FormatQuoteIcon from '@/material-icons/400-24px/format_quote.svg?react'; import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; import ReplyIcon from '@/material-icons/400-24px/reply.svg?react'; @@ -111,8 +112,8 @@ class ActionBar extends PureComponent { }; handleQuoteClick = () => { - this.props.onQuote(this.props.status, this.props.history); - } + this.props.onQuote(this.props.status); + }; handleFavouriteClick = () => { this.props.onFavourite(this.props.status); @@ -324,7 +325,7 @@ class ActionBar extends PureComponent {
-
+
diff --git a/app/javascript/mastodon/features/status/components/card.jsx b/app/javascript/mastodon/features/status/components/card.jsx index f64d489bb..100f54f60 100644 --- a/app/javascript/mastodon/features/status/components/card.jsx +++ b/app/javascript/mastodon/features/status/components/card.jsx @@ -152,9 +152,9 @@ export default class Card extends PureComponent { }; if (largeImage && card.get('type') === 'video') { - thumbnailStyle.aspectRatio = `16 / 9`; + thumbnailStyle.aspectRatio = `${quote ? 8 : 16} / 9`; } else if (largeImage) { - thumbnailStyle.aspectRatio = '1.91 / 1'; + thumbnailStyle.aspectRatio = `1.91 / ${quote ? 2 : 1}`; } else { thumbnailStyle.aspectRatio = 1; } diff --git a/app/javascript/mastodon/features/status/components/detailed_status.jsx b/app/javascript/mastodon/features/status/components/detailed_status.jsx index 259f9864b..feeed1079 100644 --- a/app/javascript/mastodon/features/status/components/detailed_status.jsx +++ b/app/javascript/mastodon/features/status/components/detailed_status.jsx @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; -import { FormattedDate, FormattedMessage } from 'react-intl'; +import { FormattedDate, FormattedMessage, injectIntl } from 'react-intl'; import classNames from 'classnames'; import { Link, withRouter } from 'react-router-dom'; @@ -62,7 +62,8 @@ class DetailedStatus extends ImmutablePureComponent { handleAccountClick = (e) => { if (e.button === 0 && !(e.ctrlKey || e.metaKey) && this.props.history) { e.preventDefault(); - this.props.history.push(`/@${this.props.status.getIn(['account', 'acct'])}`); + const acct = e.currentTarget.getAttribute('data-acct'); + this.props.history.push(`/@${acct}`); } e.stopPropagation(); @@ -78,17 +79,15 @@ class DetailedStatus extends ImmutablePureComponent { handleExpandedQuoteToggle = () => { this.props.onQuoteToggleHidden(this.props.status); - } + }; handleQuoteClick = () => { - if (!this.props) { - return; + if (this.props.history) { + const status = this._properStatus(); + this.props.history.push(`/@${status.getIn(['quote', 'account', 'acct'])}/${status.getIn(['quote', 'id'])}`); } + }; - const { status } = this.props; - this.props.history.push(`/statuses/${status.getIn(['quote', 'id'])}`); - } - handleQuoteUserClick = () =>{ if (!this.props) { return; @@ -161,7 +160,7 @@ class DetailedStatus extends ImmutablePureComponent { render () { const status = this._properStatus(); const outerStyle = { boxSizing: 'border-box' }; - const { compact, pictureInPicture, quoteMuted } = this.props; + const { compact, pictureInPicture, quoteMuted } = this.props; if (!status) { return null; @@ -180,11 +179,19 @@ class DetailedStatus extends ImmutablePureComponent { const language = status.getIn(['translation', 'language']) || status.get('language'); - const identity = (status, _0, _1, quote = false) => ( - -
- -
+ const identity = (status, _, quote) => ( + <> + {status.get('visibility') === 'direct' && ( +
+
+ +
+ )} + +
+ +
+ ); const media = (status, quote = false) => { @@ -251,7 +258,8 @@ class DetailedStatus extends ImmutablePureComponent { ); } } else if (status.get('spoiler_text').length === 0) { - return ; + return (); } } @@ -331,10 +339,7 @@ class DetailedStatus extends ImmutablePureComponent {
)} - -
- -
+ {identity(status, null, false)} { this.setState({ showQuoteMedia: !this.state.showQuoteMedia }); - } + }; handleFavouriteClick = (status) => { const { dispatch } = this.props; @@ -327,7 +327,7 @@ class Status extends ImmutablePureComponent { } else { dispatch(quoteCompose(status, this.props.history)); } - } + }; handleModalReblog = (status, privacy) => { this.props.dispatch(reblog(status, privacy)); @@ -450,7 +450,7 @@ class Status extends ImmutablePureComponent { } else { this.props.dispatch(hideQuote(status.get('id'))); } - } + }; handleToggleAll = () => { const { status, ancestorsIds, descendantsIds } = this.props; diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index 36f8b5584..761c7a1d1 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -683,6 +683,7 @@ "status.translate": "翻訳", "status.translated_from_with": "{provider}を使って{lang}から翻訳", "status.uncached_media_warning": "プレビューは使用できません", + "status.unlisted_quote": "未収載の引用", "status.unmute_conversation": "会話のミュートを解除", "status.unpin": "プロフィールへの固定を解除", "subscribed_languages.lead": "選択した言語のトゥートだけがホームとリストのタイムラインに表示されます。全ての言語のトゥートを受け取る場合は全てのチェックを外して下さい。", diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js index 9f00e7cc5..7540bf81a 100644 --- a/app/javascript/mastodon/reducers/compose.js +++ b/app/javascript/mastodon/reducers/compose.js @@ -7,7 +7,6 @@ import { COMPOSE_REPLY, COMPOSE_REPLY_CANCEL, COMPOSE_QUOTE, - COMPOSE_QUOTE_CANCEL, COMPOSE_DIRECT, COMPOSE_MENTION, COMPOSE_SUBMIT_REQUEST, @@ -397,7 +396,6 @@ export default function compose(state = initialState, action) { case COMPOSE_UPLOAD_CHANGE_REQUEST: return state.set('is_changing_upload', true); case COMPOSE_REPLY_CANCEL: - case COMPOSE_QUOTE_CANCEL: case COMPOSE_RESET: case COMPOSE_SUBMIT_SUCCESS: return clearAll(state); @@ -530,6 +528,8 @@ export default function compose(state = initialState, action) { map.set('id', action.status.get('id')); map.set('text', action.text); map.set('in_reply_to', action.status.get('in_reply_to_id')); + map.set('quote_from', action.status.getIn(['quote', 'id'])); + map.set('quote_from_url', action.status.getIn(['quote', 'url'])); map.set('privacy', action.status.get('visibility')); map.set('media_attachments', action.status.get('media_attachments')); map.set('focusDate', new Date()); diff --git a/app/javascript/material-icons/400-24px/format_quote-fill.svg b/app/javascript/material-icons/400-24px/format_quote-fill.svg new file mode 100644 index 000000000..f4afa3ed1 --- /dev/null +++ b/app/javascript/material-icons/400-24px/format_quote-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/format_quote.svg b/app/javascript/material-icons/400-24px/format_quote.svg new file mode 100644 index 000000000..c354385ea --- /dev/null +++ b/app/javascript/material-icons/400-24px/format_quote.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 3a4226af5..998a0b548 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -1105,6 +1105,10 @@ body > [data-popper-placement] { grid-template-rows: 46px max-content; gap: 0 10px; + &.quote-indicator { + background: $success-green; + } + .detailed-status__display-name { margin-bottom: 4px; } @@ -1422,17 +1426,6 @@ body > [data-popper-placement] { appearance: none; } - .status__avatar, - .detailed-status__display-avatar { - position: absolute; - top: 5px !important; - left: 5px !important; - } - - .display-name { - padding-left: 56px; - } - .detailed-status__display-name { margin-bottom: 0; line-height: unset; @@ -1630,7 +1623,8 @@ body > [data-popper-placement] { color: $dark-text-color; } -.status__info .status__display-name { +.status__info .status__display-name, +.edit-indicator .status__display-name { max-width: 100%; display: flex; font-size: 15px; diff --git a/app/views/statuses/_author.html.haml b/app/views/statuses/_author.html.haml index c700d70a8..60ace1e1d 100644 --- a/app/views/statuses/_author.html.haml +++ b/app/views/statuses/_author.html.haml @@ -13,7 +13,7 @@ %span.display-name %bdi %strong.display-name__html.p-name.emojify= display_name(author, custom_emojify: true, autoplay: prefers_autoplay?) - +   %span.display-name__account = acct(author) - if !inline && author.locked? diff --git a/app/views/statuses/_simple_status.html.haml b/app/views/statuses/_simple_status.html.haml index ddc38f48d..419723fca 100644 --- a/app/views/statuses/_simple_status.html.haml +++ b/app/views/statuses/_simple_status.html.haml @@ -12,21 +12,8 @@ * %data.dt-published{ value: status.created_at.to_time.iso8601 } - .p-author.h-card - = link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'status__display-name u-url', target: stream_link_target, rel: 'noopener noreferrer' do - .status__avatar - %div - - if prefers_autoplay? - = image_tag status.account.avatar_original_url, alt: '', class: 'u-photo account__avatar' - - else - = image_tag status.account.avatar_static_url, alt: '', class: 'u-photo account__avatar' - %span.display-name - %bdi - %strong.display-name__html.p-name.emojify= display_name(status.account, custom_emojify: true, autoplay: prefers_autoplay?) -   - %span.display-name__account - = acct(status.account) - = fa_icon('lock') if status.account.locked? + = render 'statuses/author', author: status.account + .status__content.emojify{ data: ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?) }< - if status.spoiler_text? %p<