diff options
Diffstat (limited to 'src/components/status')
| -rw-r--r-- | src/components/status/post.style.js | 42 | ||||
| -rw-r--r-- | src/components/status/status.js | 86 | ||||
| -rw-r--r-- | src/components/status/status.scss | 71 | ||||
| -rw-r--r-- | src/components/status/status.vue | 114 |
4 files changed, 257 insertions, 56 deletions
diff --git a/src/components/status/post.style.js b/src/components/status/post.style.js new file mode 100644 index 00000000..d0038424 --- /dev/null +++ b/src/components/status/post.style.js @@ -0,0 +1,42 @@ +export default { + name: 'Post', + selector: '.Status', + states: { + selected: '.-focused' + }, + validInnerComponents: [ + 'Text', + 'Link', + 'Icon', + 'Border', + 'Button', + 'ButtonUnstyled', + 'RichContent', + 'Input', + 'Avatar', + 'Attachment', + 'PollGraph' + ], + validInnerComponentsLite: [ + 'Text', + 'Link', + 'Icon', + 'Border', + 'ButtonUnstyled', + 'RichContent', + 'Avatar' + ], + defaultRules: [ + { + directives: { + background: '--bg' + } + }, + { + state: ['selected'], + directives: { + background: '--inheritedBackground, 10' + } + } + ] +} diff --git a/src/components/status/status.js b/src/components/status/status.js index 9a9bca7a..bf4e4275 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -39,7 +39,8 @@ import { faThumbtack, faChevronUp, faChevronDown, - faAngleDoubleRight + faAngleDoubleRight, + faPlay } from '@fortawesome/free-solid-svg-icons' library.add( @@ -59,7 +60,8 @@ library.add( faThumbtack, faChevronUp, faChevronDown, - faAngleDoubleRight + faAngleDoubleRight, + faPlay ) const camelCase = name => name.charAt(0).toUpperCase() + name.slice(1) @@ -133,6 +135,7 @@ const Status = { 'showPinned', 'inProfile', 'profileUserId', + 'inQuote', 'simpleTree', 'controlledThreadDisplayStatus', @@ -151,6 +154,7 @@ const Status = { 'controlledSetMediaPlaying', 'dive' ], + emits: ['interacted'], data () { return { uncontrolledReplying: false, @@ -159,7 +163,8 @@ const Status = { uncontrolledMediaPlaying: [], suspendable: true, error: null, - headTailLinks: null + headTailLinks: null, + displayQuote: !this.inQuote } }, computed: { @@ -227,17 +232,14 @@ const Status = { muteWordHits () { return muteWordHits(this.status, this.muteWords) }, - rtBotStatus () { - return this.statusoid.user.bot - }, botStatus () { - return this.status.user.bot + return this.status.user.actor_type === 'Service' }, - botIndicator () { - return this.botStatus && !this.hideBotIndication + showActorTypeIndicator () { + return !this.hideBotIndication }, - rtBotIndicator () { - return this.rtBotStatus && !this.hideBotIndication + sensitiveStatus () { + return this.status.nsfw }, mentionsLine () { if (!this.headTailLinks) return [] @@ -266,7 +268,9 @@ const Status = { // Wordfiltered this.muteWordHits.length > 0 || // bot status - (this.muteBotStatuses && this.botStatus && !this.compact) + (this.muteBotStatuses && this.botStatus && !this.compact) || + // sensitive status + (this.muteSensitiveStatuses && this.sensitiveStatus && !this.compact) return !this.unmuted && !this.shouldNotMute && reasonsToMute }, userIsMuted () { @@ -369,9 +373,15 @@ const Status = { hidePostStats () { return this.mergedConfig.hidePostStats }, + shouldDisplayFavsAndRepeats () { + return !this.hidePostStats && this.isFocused && (this.combinedFavsAndRepeatsUsers.length > 0 || this.statusFromGlobalRepository.quotes_count) + }, muteBotStatuses () { return this.mergedConfig.muteBotStatuses }, + muteSensitiveStatuses () { + return this.mergedConfig.muteSensitiveStatuses + }, hideBotIndication () { return this.mergedConfig.hideBotIndication }, @@ -401,6 +411,44 @@ const Status = { }, editingAvailable () { return this.$store.state.instance.editingAvailable + }, + hasVisibleQuote () { + return this.status.quote_url && this.status.quote_visible + }, + hasInvisibleQuote () { + return this.status.quote_url && !this.status.quote_visible + }, + quotedStatus () { + return this.status.quote_id ? this.$store.state.statuses.allStatusesObject[this.status.quote_id] : undefined + }, + shouldDisplayQuote () { + return this.quotedStatus && this.displayQuote + }, + scrobblePresent () { + if (this.mergedConfig.hideScrobbles) return false + if (!this.status.user.latestScrobble) return false + const value = this.mergedConfig.hideScrobblesAfter.match(/\d+/gs)[0] + const unit = this.mergedConfig.hideScrobblesAfter.match(/\D+/gs)[0] + let multiplier = 60 * 1000 // minutes is smallest unit + switch (unit) { + case 'm': + break + case 'h': + multiplier *= 60 // hour + break + case 'd': + multiplier *= 60 // hour + multiplier *= 24 // day + break + } + const maxAge = Number(value) * multiplier + const createdAt = Date.parse(this.status.user.latestScrobble.created_at) + const age = Date.now() - createdAt + if (age > maxAge) return false + return this.status.user.latestScrobble.artist + }, + scrobble () { + return this.status.user.latestScrobble } }, methods: { @@ -420,9 +468,11 @@ const Status = { this.error = error }, clearError () { + this.$emit('interacted') this.error = undefined }, toggleReplying () { + this.$emit('interacted') controlledOrUncontrolledToggle(this, 'replying') }, gotoOriginal (id) { @@ -469,6 +519,18 @@ const Status = { window.scrollBy(0, rect.bottom - window.innerHeight + 50) } } + }, + toggleDisplayQuote () { + if (this.shouldDisplayQuote) { + this.displayQuote = false + } else if (!this.quotedStatus) { + this.$store.dispatch('fetchStatus', this.status.quote_id) + .then(() => { + this.displayQuote = true + }) + } else { + this.displayQuote = true + } } }, watch: { diff --git a/src/components/status/status.scss b/src/components/status/status.scss index 44812867..63809ff2 100644 --- a/src/components/status/status.scss +++ b/src/components/status/status.scss @@ -1,5 +1,3 @@ -@import "../../variables"; - .Status { min-width: 0; white-space: normal; @@ -12,24 +10,8 @@ --_still-image-label-visibility: hidden; } - &.-focused { - background-color: $fallback--lightBg; - background-color: var(--selectedPost, $fallback--lightBg); - color: $fallback--text; - color: var(--selectedPostText, $fallback--text); - - --lightText: var(--selectedPostLightText, $fallback--light); - --faint: var(--selectedPostFaintText, $fallback--faint); - --faintLink: var(--selectedPostFaintLink, $fallback--faint); - --postLink: var(--selectedPostPostLink, $fallback--faint); - --postFaintLink: var(--selectedPostFaintPostLink, $fallback--faint); - --icon: var(--selectedPostIcon, $fallback--icon); - } - .gravestone { - padding: var(--status-margin, $status-margin); - color: $fallback--faint; - color: var(--faint, $fallback--faint); + padding: var(--status-margin); display: flex; .deleted-text { @@ -40,7 +22,7 @@ .status-container { display: flex; - padding: var(--status-margin, $status-margin); + padding: var(--status-margin); > * { min-width: 0; @@ -52,7 +34,7 @@ } .pin { - padding: var(--status-margin, $status-margin) var(--status-margin, $status-margin) 0; + padding: var(--status-margin) var(--status-margin) 0; display: flex; align-items: center; justify-content: flex-end; @@ -68,7 +50,7 @@ } .left-side { - margin-right: var(--status-margin, $status-margin); + margin-right: var(--status-margin); } .right-side { @@ -77,7 +59,7 @@ } .usercard { - margin-bottom: var(--status-margin, $status-margin); + margin-bottom: var(--status-margin); } .status-username { @@ -135,11 +117,6 @@ .button-unstyled { padding: 5px; margin: -5px; - - &:hover svg { - color: $fallback--lightText; - color: var(--lightText, $fallback--lightText); - } } .svg-inline--fa { @@ -243,16 +220,15 @@ } .repeat-info { - padding: 0.4em var(--status-margin, $status-margin); + padding: 0.4em var(--status-margin); .repeat-icon { - color: $fallback--cGreen; - color: var(--cGreen, $fallback--cGreen); + color: var(--cGreen); } } .repeater-avatar { - border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); + border-radius: var(--roundness); margin-left: 28px; width: 20px; height: 20px; @@ -289,7 +265,7 @@ position: relative; width: 100%; display: flex; - margin-top: var(--status-margin, $status-margin); + margin-top: var(--status-margin); > * { max-width: 4em; @@ -357,7 +333,7 @@ } .favs-repeated-users { - margin-top: var(--status-margin, $status-margin); + margin-top: var(--status-margin); } .stats { @@ -368,10 +344,10 @@ .avatar-row { flex: 1; - overflow: hidden; position: relative; display: flex; align-items: center; + overflow: hidden; &::before { content: ""; @@ -379,16 +355,16 @@ height: 100%; width: 1px; left: 0; - background-color: var(--faint, $fallback--faint); + background-color: var(--textFaint); } } .stat-count { - margin-right: var(--status-margin, $status-margin); + margin-right: var(--status-margin); user-select: none; .stat-title { - color: var(--faint, $fallback--faint); + color: var(--textFaint); font-size: 0.85em; text-transform: uppercase; position: relative; @@ -398,6 +374,7 @@ font-weight: bolder; font-size: 1.1em; line-height: 1em; + color: var(--text); } &:hover .stat-title { @@ -422,4 +399,22 @@ } } } + + .quoted-status { + margin-top: 0.5em; + border: 1px solid var(--border); + border-radius: var(--roundness); + + &.-unavailable-prompt { + padding: 0.5em; + } + } + + .display-quoted-status-button { + margin: 0.5em; + + &-icon { + color: inherit; + } + } } diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 35b15362..61a58cda 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -31,6 +31,12 @@ /> </small> <small + v-if="muteSensitiveStatuses && status.nsfw" + class="mute-thread" + > + {{ $t('status.sensitive_muted') }} + </small> + <small v-if="showReasonMutedThread" class="mute-thread" > @@ -79,7 +85,7 @@ <UserAvatar v-if="retweet" class="left-side repeater-avatar" - :bot="rtBotIndicator" + :show-actor-type-indicator="showActorTypeIndicator" :better-shadow="betterShadow" :user="statusoid.user" /> @@ -133,7 +139,7 @@ > <UserAvatar class="post-avatar" - :bot="botIndicator" + :show-actor-type-indicator="showActorTypeIndicator" :compact="compact" :better-shadow="betterShadow" :user="status.user" @@ -180,7 +186,7 @@ <span class="heading-right"> <router-link - class="timeago faint-link" + class="timeago faint" :to="{ name: 'conversation', params: { id: status.id } }" > <Timeago @@ -250,6 +256,47 @@ </span> </div> <div + v-if="scrobblePresent" + class="status-rich-presence" + > + <a + v-if="scrobble.externalLink" + :href="scrobble.externalLink" + target="_blank" + > + {{ scrobble.artist }} — {{ scrobble.title }} + <FAIcon + class="fa-scale-110 fa-old-padding" + icon="play" + /> + <span class="status-rich-presence-time"> + <Timeago + template-key="time.in_past" + :time="scrobble.created_at" + :auto-update="60" + /> + </span> + </a> + <span v-if="!scrobble.externalLink"> + <FAIcon + class="fa-scale-110 fa-old-padding" + icon="music" + /> + {{ scrobble.artist }} — {{ scrobble.title }} + <FAIcon + class="fa-scale-110 fa-old-padding" + icon="play" + /> + <span class="status-rich-presence-time"> + <Timeago + template-key="time.in_past" + :time="scrobble.created_at" + :auto-update="60" + /> + </span> + </span> + </div> + <div v-if="isReply || hasMentionsLine" class="heading-reply-row" > @@ -364,13 +411,52 @@ @parseReady="setHeadTailLinks" /> + <article + v-if="hasVisibleQuote" + class="quoted-status" + > + <button + class="button-unstyled -link display-quoted-status-button" + :aria-expanded="shouldDisplayQuote" + @click="toggleDisplayQuote" + > + {{ shouldDisplayQuote ? $t('status.hide_quote') : $t('status.display_quote') }} + <FAIcon + class="display-quoted-status-button-icon" + :icon="shouldDisplayQuote ? 'chevron-up' : 'chevron-down'" + /> + </button> + <Status + v-if="shouldDisplayQuote" + :statusoid="quotedStatus" + :in-quote="true" + /> + </article> + <p + v-else-if="hasInvisibleQuote" + class="quoted-status -unavailable-prompt" + > + <i18n-t keypath="status.invisible_quote"> + <template #link> + <bdi> + <a + :href="status.quote_url" + target="_blank" + > + {{ status.quote_url }} + </a> + </bdi> + </template> + </i18n-t> + </p> + <div v-if="inConversation && !isPreview && replies && replies.length" class="replies" > <button v-if="showOtherRepliesAsButton && replies.length > 1" - class="button-unstyled -link faint" + class="button-unstyled -link" :title="$tc('status.ancestor_follow', replies.length - 1, { numReplies: replies.length - 1 })" @click.prevent="dive" > @@ -398,7 +484,7 @@ <transition name="fade"> <div - v-if="!hidePostStats && isFocused && combinedFavsAndRepeatsUsers.length > 0" + v-if="shouldDisplayFavsAndRepeats" class="favs-repeated-users" > <div class="stats"> @@ -426,6 +512,19 @@ </div> </div> </UserListPopover> + <router-link + v-if="statusFromGlobalRepository.quotes_count > 0" + :to="{ name: 'quotes', params: { id: status.id } }" + > + <div + class="stat-count" + > + <a class="stat-title">{{ $t('status.quotes') }}</a> + <div class="stat-number"> + {{ statusFromGlobalRepository.quotes_count }} + </div> + </div> + </router-link> <div class="avatar-row"> <AvatarList :users="combinedFavsAndRepeatsUsers" /> </div> @@ -451,14 +550,17 @@ :visibility="status.visibility" :logged-in="loggedIn" :status="status" + @click="$emit('interacted')" /> <favorite-button :logged-in="loggedIn" :status="status" + @click="$emit('interacted')" /> <ReactButton v-if="loggedIn" :status="status" + @click="$emit('interacted')" /> <extra-buttons :status="status" @@ -476,7 +578,7 @@ <UserAvatar class="post-avatar" :compact="compact" - :bot="botIndicator" + :show-actor-type-indicator="showActorTypeIndicator" /> </div> <div class="right-side"> |
