diff options
Diffstat (limited to 'src/components/status')
| -rw-r--r-- | src/components/status/status.js | 225 | ||||
| -rw-r--r-- | src/components/status/status.scss | 107 | ||||
| -rw-r--r-- | src/components/status/status.vue | 236 |
3 files changed, 407 insertions, 161 deletions
diff --git a/src/components/status/status.js b/src/components/status/status.js index 470c01f1..9a9bca7a 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -4,14 +4,18 @@ import ReactButton from '../react_button/react_button.vue' import RetweetButton from '../retweet_button/retweet_button.vue' import ExtraButtons from '../extra_buttons/extra_buttons.vue' import PostStatusForm from '../post_status_form/post_status_form.vue' -import UserCard from '../user_card/user_card.vue' import UserAvatar from '../user_avatar/user_avatar.vue' import AvatarList from '../avatar_list/avatar_list.vue' import Timeago from '../timeago/timeago.vue' import StatusContent from '../status_content/status_content.vue' +import RichContent from 'src/components/rich_content/rich_content.jsx' import StatusPopover from '../status_popover/status_popover.vue' +import UserPopover from '../user_popover/user_popover.vue' import UserListPopover from '../user_list_popover/user_list_popover.vue' import EmojiReactions from '../emoji_reactions/emoji_reactions.vue' +import UserLink from '../user_link/user_link.vue' +import MentionsLine from 'src/components/mentions_line/mentions_line.vue' +import MentionLink from 'src/components/mention_link/mention_link.vue' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js' import { muteWordHits } from '../../services/status_parser/status_parser.js' @@ -32,7 +36,10 @@ import { faStar, faEyeSlash, faEye, - faThumbtack + faThumbtack, + faChevronUp, + faChevronDown, + faAngleDoubleRight } from '@fortawesome/free-solid-svg-icons' library.add( @@ -49,9 +56,47 @@ library.add( faEllipsisH, faEyeSlash, faEye, - faThumbtack + faThumbtack, + faChevronUp, + faChevronDown, + faAngleDoubleRight ) +const camelCase = name => name.charAt(0).toUpperCase() + name.slice(1) + +const controlledOrUncontrolledGetters = list => list.reduce((res, name) => { + const camelized = camelCase(name) + const toggle = `controlledToggle${camelized}` + const controlledName = `controlled${camelized}` + const uncontrolledName = `uncontrolled${camelized}` + res[name] = function () { + return ((this.$data[toggle] !== undefined || this.$props[toggle] !== undefined) && this[toggle]) ? this[controlledName] : this[uncontrolledName] + } + return res +}, {}) + +const controlledOrUncontrolledToggle = (obj, name) => { + const camelized = camelCase(name) + const toggle = `controlledToggle${camelized}` + const uncontrolledName = `uncontrolled${camelized}` + if (obj[toggle]) { + obj[toggle]() + } else { + obj[uncontrolledName] = !obj[uncontrolledName] + } +} + +const controlledOrUncontrolledSet = (obj, name, val) => { + const camelized = camelCase(name) + const set = `controlledSet${camelized}` + const uncontrolledName = `uncontrolled${camelized}` + if (obj[set]) { + obj[set](val) + } else { + obj[uncontrolledName] = val + } +} + const Status = { name: 'Status', components: { @@ -61,14 +106,18 @@ const Status = { RetweetButton, ExtraButtons, PostStatusForm, - UserCard, UserAvatar, AvatarList, Timeago, StatusPopover, UserListPopover, EmojiReactions, - StatusContent + StatusContent, + RichContent, + MentionLink, + MentionsLine, + UserPopover, + UserLink }, props: [ 'statusoid', @@ -83,19 +132,38 @@ const Status = { 'inlineExpanded', 'showPinned', 'inProfile', - 'profileUserId' + 'profileUserId', + + 'simpleTree', + 'controlledThreadDisplayStatus', + 'controlledToggleThreadDisplay', + 'showOtherRepliesAsButton', + + 'controlledShowingTall', + 'controlledToggleShowingTall', + 'controlledExpandingSubject', + 'controlledToggleExpandingSubject', + 'controlledShowingLongSubject', + 'controlledToggleShowingLongSubject', + 'controlledReplying', + 'controlledToggleReplying', + 'controlledMediaPlaying', + 'controlledSetMediaPlaying', + 'dive' ], data () { return { - replying: false, + uncontrolledReplying: false, unmuted: false, userExpanded: false, - mediaPlaying: [], + uncontrolledMediaPlaying: [], suspendable: true, - error: null + error: null, + headTailLinks: null } }, computed: { + ...controlledOrUncontrolledGetters(['replying', 'mediaPlaying']), muteWords () { return this.mergedConfig.muteWords }, @@ -132,12 +200,15 @@ const Status = { }, replyProfileLink () { if (this.isReply) { - return this.generateUserProfileLink(this.status.in_reply_to_user_id, this.replyToName) + const user = this.$store.getters.findUser(this.status.in_reply_to_user_id) + // FIXME Why user not found sometimes??? + return user ? user.statusnet_profile_url : 'NOT_FOUND' } }, retweet () { return !!this.statusoid.retweeted_status }, + retweeterUser () { return this.statusoid.user }, retweeter () { return this.statusoid.user.name || this.statusoid.user.screen_name_ui }, - retweeterHtml () { return this.statusoid.user.name_html }, + retweeterHtml () { return this.statusoid.user.name }, retweeterProfileLink () { return this.generateUserProfileLink(this.statusoid.user.id, this.statusoid.user.screen_name) }, status () { if (this.retweet) { @@ -156,27 +227,66 @@ const Status = { muteWordHits () { return muteWordHits(this.status, this.muteWords) }, + rtBotStatus () { + return this.statusoid.user.bot + }, + botStatus () { + return this.status.user.bot + }, + botIndicator () { + return this.botStatus && !this.hideBotIndication + }, + rtBotIndicator () { + return this.rtBotStatus && !this.hideBotIndication + }, + mentionsLine () { + if (!this.headTailLinks) return [] + const writtenSet = new Set(this.headTailLinks.writtenMentions.map(_ => _.url)) + return this.status.attentions.filter(attn => { + // no reply user + return attn.id !== this.status.in_reply_to_user_id && + // no self-replies + attn.statusnet_profile_url !== this.status.user.statusnet_profile_url && + // don't include if mentions is written + !writtenSet.has(attn.statusnet_profile_url) + }).map(attn => ({ + url: attn.statusnet_profile_url, + content: attn.screen_name, + userId: attn.id + })) + }, + hasMentionsLine () { + return this.mentionsLine.length > 0 + }, muted () { if (this.statusoid.user.id === this.currentUser.id) return false + const reasonsToMute = this.userIsMuted || + // Thread is muted + status.thread_muted || + // Wordfiltered + this.muteWordHits.length > 0 || + // bot status + (this.muteBotStatuses && this.botStatus && !this.compact) + return !this.unmuted && !this.shouldNotMute && reasonsToMute + }, + userIsMuted () { + if (this.statusoid.user.id === this.currentUser.id) return false const { status } = this const { reblog } = status const relationship = this.$store.getters.relationship(status.user.id) const relationshipReblog = reblog && this.$store.getters.relationship(reblog.user.id) - const reasonsToMute = ( - // Post is muted according to BE - status.muted || + return status.muted || // Reprööt of a muted post according to BE (reblog && reblog.muted) || // Muted user relationship.muting || // Muted user of a reprööt - (relationshipReblog && relationshipReblog.muting) || - // Thread is muted - status.thread_muted || - // Wordfiltered - this.muteWordHits.length > 0 - ) - const excusesNotToMute = ( + (relationshipReblog && relationshipReblog.muting) + }, + shouldNotMute () { + const { status } = this + const { reblog } = status + return ( ( this.inProfile && ( // Don't mute user's posts on user timeline (except reblogs) @@ -189,14 +299,26 @@ const Status = { (this.inConversation && status.thread_muted) // No excuses if post has muted words ) && !this.muteWordHits.length > 0 - - return !this.unmuted && !excusesNotToMute && reasonsToMute + }, + hideMutedUsers () { + return this.mergedConfig.hideMutedPosts + }, + hideMutedThreads () { + return this.mergedConfig.hideMutedThreads }, hideFilteredStatuses () { return this.mergedConfig.hideFilteredStatuses }, + hideWordFilteredPosts () { + return this.mergedConfig.hideWordFilteredPosts + }, hideStatus () { - return (this.muted && this.hideFilteredStatuses) || this.virtualHidden + return (!this.shouldNotMute) && ( + (this.muted && this.hideFilteredStatuses) || + (this.userIsMuted && this.hideMutedUsers) || + (this.status.thread_muted && this.hideMutedThreads) || + (this.muteWordHits.length > 0 && this.hideWordFilteredPosts) + ) }, isFocused () { // retweet or root of an expanded conversation @@ -241,11 +363,18 @@ const Status = { return uniqBy(combinedUsers, 'id') }, tags () { + // eslint-disable-next-line no-prototype-builtins return this.status.tags.filter(tagObj => tagObj.hasOwnProperty('name')).map(tagObj => tagObj.name).join(' ') }, hidePostStats () { return this.mergedConfig.hidePostStats }, + muteBotStatuses () { + return this.mergedConfig.muteBotStatuses + }, + hideBotIndication () { + return this.mergedConfig.hideBotIndication + }, currentUser () { return this.$store.state.users.currentUser }, @@ -257,6 +386,21 @@ const Status = { }, isSuspendable () { return !this.replying && this.mediaPlaying.length === 0 + }, + inThreadForest () { + return !!this.controlledThreadDisplayStatus + }, + threadShowing () { + return this.controlledThreadDisplayStatus === 'showing' + }, + visibilityLocalized () { + return this.$i18n.t('general.scope_in_timeline.' + this.status.visibility) + }, + isEdited () { + return this.status.edited_at !== null + }, + editingAvailable () { + return this.$store.state.instance.editingAvailable } }, methods: { @@ -279,7 +423,7 @@ const Status = { this.error = undefined }, toggleReplying () { - this.replying = !this.replying + controlledOrUncontrolledToggle(this, 'replying') }, gotoOriginal (id) { if (this.inConversation) { @@ -299,16 +443,21 @@ const Status = { return generateProfileLink(id, name, this.$store.state.instance.restrictedNicknames) }, addMediaPlaying (id) { - this.mediaPlaying.push(id) + controlledOrUncontrolledSet(this, 'mediaPlaying', this.mediaPlaying.concat(id)) }, removeMediaPlaying (id) { - this.mediaPlaying = this.mediaPlaying.filter(mediaId => mediaId !== id) - } - }, - watch: { - 'highlight': function (id) { + controlledOrUncontrolledSet(this, 'mediaPlaying', this.mediaPlaying.filter(mediaId => mediaId !== id)) + }, + setHeadTailLinks (headTailLinks) { + this.headTailLinks = headTailLinks + }, + toggleThreadDisplay () { + this.controlledToggleThreadDisplay() + }, + scrollIfHighlighted (highlightId) { + const id = highlightId if (this.status.id === id) { - let rect = this.$el.getBoundingClientRect() + const rect = this.$el.getBoundingClientRect() if (rect.top < 100) { // Post is above screen, match its top to screen top window.scrollBy(0, rect.top - 100) @@ -320,6 +469,11 @@ const Status = { window.scrollBy(0, rect.bottom - window.innerHeight + 50) } } + } + }, + watch: { + highlight: function (id) { + this.scrollIfHighlighted(id) }, 'status.repeat_num': function (num) { // refetch repeats when repeat_num is changed in any way @@ -333,14 +487,9 @@ const Status = { this.$store.dispatch('fetchFavs', this.status.id) } }, - 'isSuspendable': function (val) { + isSuspendable: function (val) { this.suspendable = val } - }, - filters: { - capitalize: function (str) { - return str.charAt(0).toUpperCase() + str.slice(1) - } } } diff --git a/src/components/status/status.scss b/src/components/status/status.scss index 58b55bc8..ada9841e 100644 --- a/src/components/status/status.scss +++ b/src/components/status/status.scss @@ -1,10 +1,10 @@ - @import '../../_variables.scss'; -$status-margin: 0.75em; - .Status { min-width: 0; + white-space: normal; + word-wrap: break-word; + word-break: break-word; &:hover { --_still-image-img-visibility: visible; @@ -26,15 +26,8 @@ $status-margin: 0.75em; --icon: var(--selectedPostIcon, $fallback--icon); } - &.-conversation { - border-left-width: 4px; - border-left-style: solid; - border-left-color: $fallback--cRed; - border-left-color: var(--cRed, $fallback--cRed); - } - .gravestone { - padding: $status-margin; + padding: var(--status-margin, $status-margin); color: $fallback--faint; color: var(--faint, $fallback--faint); display: flex; @@ -47,7 +40,11 @@ $status-margin: 0.75em; .status-container { display: flex; - padding: $status-margin; + padding: var(--status-margin, $status-margin); + + > * { + min-width: 0; + } &.-repeat { padding-top: 0; @@ -55,7 +52,7 @@ $status-margin: 0.75em; } .pin { - padding: $status-margin $status-margin 0; + padding: var(--status-margin, $status-margin) var(--status-margin, $status-margin) 0; display: flex; align-items: center; justify-content: flex-end; @@ -71,7 +68,7 @@ $status-margin: 0.75em; } .left-side { - margin-right: $status-margin; + margin-right: var(--status-margin, $status-margin); } .right-side { @@ -80,12 +77,11 @@ $status-margin: 0.75em; } .usercard { - margin-bottom: $status-margin; + margin-bottom: var(--status-margin, $status-margin); } .status-username { white-space: nowrap; - font-size: 14px; overflow: hidden; max-width: 85%; font-weight: bold; @@ -93,12 +89,8 @@ $status-margin: 0.75em; margin-right: 0.4em; text-overflow: ellipsis; - .emoji { - width: 14px; - height: 14px; - vertical-align: middle; - object-fit: contain; - } + --_still_image-label-scale: 0.25; + --emoji-size: 14px; } .status-favicon { @@ -114,7 +106,7 @@ $status-margin: 0.75em; .heading-name-row { display: flex; justify-content: space-between; - line-height: 18px; + line-height: 1.3; a { display: inline-block; @@ -155,42 +147,38 @@ $status-margin: 0.75em; } } + .glued-label { + display: inline-flex; + white-space: nowrap; + } + .timeago { margin-right: 0.2em; } - .heading-reply-row { + & .heading-reply-row, + & .heading-edited-row { position: relative; align-content: baseline; - font-size: 12px; - line-height: 18px; + font-size: 0.85em; + margin-top: 0.2em; + line-height: 130%; max-width: 100%; - display: flex; - flex-wrap: wrap; align-items: stretch; } - .reply-to-and-accountname { - display: flex; - height: 18px; - margin-right: 0.5em; - max-width: 100%; - - .reply-to-link { - white-space: nowrap; - word-break: break-word; - text-overflow: ellipsis; - overflow-x: hidden; - } - } - & .reply-to-popover, - & .reply-to-no-popover { + & .reply-to-no-popover, + & .mentions { min-width: 0; margin-right: 0.4em; flex-shrink: 0; } + .reply-glued-label { + margin-right: 0.5em; + } + .reply-to-popover { .reply-to:hover::before { content: ''; @@ -220,23 +208,28 @@ $status-margin: 0.75em; } } - .reply-to { + & .mentions, + & .reply-to { + white-space: nowrap; position: relative; } - .reply-to-text { + & .mentions-text, + & .reply-to-text { + color: var(--faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } - .replies-separator { - margin-left: 0.4em; + .mentions-line { + display: inline; } .replies { - line-height: 18px; - font-size: 12px; + margin-top: 0.25em; + line-height: 1.3; + font-size: 0.85em; display: flex; flex-wrap: wrap; @@ -250,7 +243,7 @@ $status-margin: 0.75em; } .repeat-info { - padding: 0.4em $status-margin; + padding: 0.4em var(--status-margin, $status-margin); .repeat-icon { color: $fallback--cGreen; @@ -296,7 +289,7 @@ $status-margin: 0.75em; position: relative; width: 100%; display: flex; - margin-top: $status-margin; + margin-top: var(--status-margin, $status-margin); > * { max-width: 4em; @@ -364,7 +357,7 @@ $status-margin: 0.75em; } .favs-repeated-users { - margin-top: $status-margin; + margin-top: var(--status-margin, $status-margin); } .stats { @@ -391,19 +384,19 @@ $status-margin: 0.75em; } .stat-count { - margin-right: $status-margin; + margin-right: var(--status-margin, $status-margin); user-select: none; .stat-title { color: var(--faint, $fallback--faint); - font-size: 12px; + font-size: 0.85em; text-transform: uppercase; position: relative; } .stat-number { font-weight: bolder; - font-size: 16px; + font-size: 1.1em; line-height: 1em; } @@ -417,13 +410,13 @@ $status-margin: 0.75em; margin-left: 20px; } - .avatar:not(.repeater-avatar) { + .post-avatar { width: 40px; height: 40px; // TODO define those other way somehow? // stylelint-disable rscss/class-format - &.avatar-compact { + &.-compact { width: 32px; height: 32px; } diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 00e962f3..82eb7ac6 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -1,7 +1,7 @@ <template> - <!-- eslint-disable vue/no-v-html --> <div v-if="!hideStatus" + ref="root" class="Status" :class="[{ '-focused': isFocused }, { '-conversation': inlineExpanded }]" > @@ -25,9 +25,10 @@ class="fa-scale-110 fa-old-padding repeat-icon" icon="retweet" /> - <router-link :to="userProfileLink"> - {{ status.user.screen_name_ui }} - </router-link> + <user-link + :user="status.user" + :at="false" + /> </small> <small v-if="showReasonMutedThread" @@ -78,6 +79,7 @@ <UserAvatar v-if="retweet" class="left-side repeater-avatar" + :bot="rtBotIndicator" :better-shadow="betterShadow" :user="statusoid.user" /> @@ -89,13 +91,18 @@ <router-link v-if="retweeterHtml" :to="retweeterProfileLink" - v-html="retweeterHtml" - /> + > + <RichContent + :html="retweeterHtml" + :emoji="retweeterUser.emoji" + /> + </router-link> <router-link v-else :to="retweeterProfileLink" >{{ retweeter }}</router-link> </span> + {{ ' ' }} <FAIcon icon="retweet" class="repeat-icon" @@ -116,25 +123,25 @@ v-if="!noHeading" class="left-side" > - <router-link - :to="userProfileLink" - @click.stop.prevent.capture.native="toggleUserExpanded" + <a + :href="$router.resolve(userProfileLink).href" + @click.prevent > - <UserAvatar - :compact="compact" - :better-shadow="betterShadow" - :user="status.user" - /> - </router-link> + <UserPopover + :user-id="status.user.id" + :overlay-centers="true" + > + <UserAvatar + class="post-avatar" + :bot="botIndicator" + :compact="compact" + :better-shadow="betterShadow" + :user="status.user" + /> + </UserPopover> + </a> </div> <div class="right-side"> - <UserCard - v-if="userExpanded" - :user-id="status.user.id" - :rounded="true" - :bordered="true" - class="usercard" - /> <div v-if="!noHeading" class="status-heading" @@ -145,8 +152,12 @@ v-if="status.user.name_html" class="status-username" :title="status.user.name" - v-html="status.user.name_html" - /> + > + <RichContent + :html="status.user.name" + :emoji="status.user.emoji" + /> + </h4> <h4 v-else class="status-username" @@ -154,13 +165,12 @@ > {{ status.user.name }} </h4> - <router-link + <user-link class="account-name" :title="status.user.screen_name_ui" - :to="userProfileLink" - > - {{ status.user.screen_name_ui }} - </router-link> + :user="status.user" + :at="false" + /> <img v-if="!!(status.user && status.user.favicon)" class="status-favicon" @@ -181,7 +191,7 @@ <span v-if="status.visibility" class="visibility-icon" - :title="status.visibility | capitalize" + :title="visibilityLocalized" > <FAIcon fixed-width @@ -212,13 +222,40 @@ class="fa-scale-110" /> </button> + <button + v-if="inThreadForest && replies && replies.length && !simpleTree" + class="button-unstyled" + :title="threadShowing ? $t('status.thread_hide') : $t('status.thread_show')" + :aria-expanded="threadShowing ? 'true' : 'false'" + @click.prevent="toggleThreadDisplay" + > + <FAIcon + fixed-width + class="fa-scale-110" + :icon="threadShowing ? 'chevron-up' : 'chevron-down'" + /> + </button> + <button + v-if="dive && !simpleTree" + class="button-unstyled" + :title="$t('status.show_only_conversation_under_this')" + @click.prevent="dive" + > + <FAIcon + fixed-width + class="fa-scale-110" + :icon="'angle-double-right'" + /> + </button> </span> </div> - - <div class="heading-reply-row"> - <div + <div + v-if="isReply || hasMentionsLine" + class="heading-reply-row" + > + <span v-if="isReply" - class="reply-to-and-accountname" + class="glued-label reply-glued-label" > <StatusPopover v-if="!isPreview" @@ -237,8 +274,9 @@ icon="reply" flip="horizontal" /> + {{ ' ' }} <span - class="faint-link reply-to-text" + class="reply-to-text" > {{ $t('status.reply_to') }} </span> @@ -251,50 +289,113 @@ > <span class="reply-to-text">{{ $t('status.reply_to') }}</span> </span> - <router-link - class="reply-to-link" - :title="replyToName" - :to="replyProfileLink" - > - {{ replyToName }} - </router-link> + <MentionLink + :content="replyToName" + :url="replyProfileLink" + :user-id="status.in_reply_to_user_id" + :user-screen-name="status.in_reply_to_screen_name" + /> + </span> + + <!-- This little wrapper is made for sole purpose of "gluing" --> + <!-- "Mentions" label to the first mention --> + <span + v-if="hasMentionsLine" + class="glued-label" + > <span - v-if="replies && replies.length" - class="faint replies-separator" + class="mentions" + :aria-label="$t('tool_tip.mentions')" + @click.prevent="gotoOriginal(status.in_reply_to_status_id)" > - - + <span + class="mentions-text" + > + {{ $t('status.mentions') }} + </span> </span> - </div> - <div - v-if="inConversation && !isPreview && replies && replies.length" - class="replies" + <MentionsLine + v-if="hasMentionsLine" + :mentions="mentionsLine.slice(0, 1)" + class="mentions-line-first" + /> + </span> + {{ ' ' }} + <MentionsLine + v-if="hasMentionsLine" + :mentions="mentionsLine.slice(1)" + class="mentions-line" + /> + </div> + <div + v-if="isEdited && editingAvailable && !isPreview" + class="heading-edited-row" + > + <i18n-t + keypath="status.edited_at" + tag="span" > - <span class="faint">{{ $t('status.replies_list') }}</span> - <StatusPopover - v-for="reply in replies" - :key="reply.id" - :status-id="reply.id" - > - <button - class="button-unstyled -link reply-link" - @click.prevent="gotoOriginal(reply.id)" - > - {{ reply.name }} - </button> - </StatusPopover> - </div> + <template #time> + <Timeago + template-key="time.in_past" + :time="status.edited_at" + :auto-update="60" + :long-format="true" + /> + </template> + </i18n-t> </div> </div> <StatusContent + ref="content" :status="status" :no-heading="noHeading" :highlight="highlight" :focused="isFocused" + :controlled-showing-tall="controlledShowingTall" + :controlled-expanding-subject="controlledExpandingSubject" + :controlled-showing-long-subject="controlledShowingLongSubject" + :controlled-toggle-showing-tall="controlledToggleShowingTall" + :controlled-toggle-expanding-subject="controlledToggleExpandingSubject" + :controlled-toggle-showing-long-subject="controlledToggleShowingLongSubject" @mediaplay="addMediaPlaying($event)" @mediapause="removeMediaPlaying($event)" + @parseReady="setHeadTailLinks" /> + <div + v-if="inConversation && !isPreview && replies && replies.length" + class="replies" + > + <button + v-if="showOtherRepliesAsButton && replies.length > 1" + class="button-unstyled -link faint" + :title="$tc('status.ancestor_follow', replies.length - 1, { numReplies: replies.length - 1 })" + @click.prevent="dive" + > + {{ $tc('status.replies_list_with_others', replies.length - 1, { numReplies: replies.length - 1 }) }} + </button> + <span + v-else + class="faint" + > + {{ $t('status.replies_list') }} + </span> + <StatusPopover + v-for="reply in replies" + :key="reply.id" + :status-id="reply.id" + > + <button + class="button-unstyled -link reply-link" + @click.prevent="gotoOriginal(reply.id)" + > + {{ reply.name }} + </button> + </StatusPopover> + </div> + <transition name="fade"> <div v-if="!hidePostStats && isFocused && combinedFavsAndRepeatsUsers.length > 0" @@ -372,7 +473,11 @@ class="gravestone" > <div class="left-side"> - <UserAvatar :compact="compact" /> + <UserAvatar + class="post-avatar" + :compact="compact" + :bot="botIndicator" + /> </div> <div class="right-side"> <div class="deleted-text"> @@ -402,9 +507,8 @@ </div> </template> </div> -<!-- eslint-enable vue/no-v-html --> </template> -<script src="./status.js" ></script> +<script src="./status.js"></script> <style src="./status.scss" lang="scss"></style> |
