aboutsummaryrefslogtreecommitdiff
path: root/src/components/status
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/status')
-rw-r--r--src/components/status/post.style.js42
-rw-r--r--src/components/status/status.js86
-rw-r--r--src/components/status/status.scss71
-rw-r--r--src/components/status/status.vue114
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">