aboutsummaryrefslogtreecommitdiff
path: root/src/components/status
diff options
context:
space:
mode:
authorHJ <30-hj@users.noreply.git.pleroma.social>2022-03-13 17:31:46 +0000
committerHJ <30-hj@users.noreply.git.pleroma.social>2022-03-13 17:31:46 +0000
commite34d71fc1f64fde73e435262979e5e93ebd37df2 (patch)
tree8b43c0e6f070c7f5a5fd72d1fcc986ca52524ed2 /src/components/status
parent89efb0d2f4ab41eb020e6a6b7bb14dbe20e53157 (diff)
parent551b8f3690bab1f53ec22ccf6963009a30fa45d0 (diff)
Merge branch 'from/develop/tusooa/tree-threading' into 'develop'
Add the option to display threads as trees See merge request pleroma/pleroma-fe!1407
Diffstat (limited to 'src/components/status')
-rw-r--r--src/components/status/status.js96
-rw-r--r--src/components/status/status.scss27
-rw-r--r--src/components/status/status.vue46
3 files changed, 138 insertions, 31 deletions
diff --git a/src/components/status/status.js b/src/components/status/status.js
index 2c3e079f..4c0ef3e0 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -35,7 +35,10 @@ import {
faStar,
faEyeSlash,
faEye,
- faThumbtack
+ faThumbtack,
+ faChevronUp,
+ faChevronDown,
+ faAngleDoubleRight
} from '@fortawesome/free-solid-svg-icons'
library.add(
@@ -52,9 +55,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[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: {
@@ -89,20 +130,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,
headTailLinks: null
}
},
computed: {
+ ...controlledOrUncontrolledGetters(['replying', 'mediaPlaying']),
muteWords () {
return this.mergedConfig.muteWords
},
@@ -318,6 +377,12 @@ const Status = {
},
isSuspendable () {
return !this.replying && this.mediaPlaying.length === 0
+ },
+ inThreadForest () {
+ return !!this.controlledThreadDisplayStatus
+ },
+ threadShowing () {
+ return this.controlledThreadDisplayStatus === 'showing'
}
},
methods: {
@@ -340,7 +405,7 @@ const Status = {
this.error = undefined
},
toggleReplying () {
- this.replying = !this.replying
+ controlledOrUncontrolledToggle(this, 'replying')
},
gotoOriginal (id) {
if (this.inConversation) {
@@ -360,17 +425,19 @@ 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)
+ controlledOrUncontrolledSet(this, 'mediaPlaying', this.mediaPlaying.filter(mediaId => mediaId !== id))
},
setHeadTailLinks (headTailLinks) {
this.headTailLinks = headTailLinks
- }
- },
- watch: {
- 'highlight': function (id) {
+ },
+ toggleThreadDisplay () {
+ this.controlledToggleThreadDisplay()
+ },
+ scrollIfHighlighted (highlightId) {
+ const id = highlightId
if (this.status.id === id) {
let rect = this.$el.getBoundingClientRect()
if (rect.top < 100) {
@@ -384,6 +451,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
diff --git a/src/components/status/status.scss b/src/components/status/status.scss
index 2028ade9..3f647b25 100644
--- a/src/components/status/status.scss
+++ b/src/components/status/status.scss
@@ -1,7 +1,5 @@
@import '../../_variables.scss';
-$status-margin: 0.75em;
-
.Status {
min-width: 0;
white-space: normal;
@@ -28,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;
@@ -49,7 +40,7 @@ $status-margin: 0.75em;
.status-container {
display: flex;
- padding: $status-margin;
+ padding: var(--status-margin, $status-margin);
&.-repeat {
padding-top: 0;
@@ -57,7 +48,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;
@@ -73,7 +64,7 @@ $status-margin: 0.75em;
}
.left-side {
- margin-right: $status-margin;
+ margin-right: var(--status-margin, $status-margin);
}
.right-side {
@@ -82,7 +73,7 @@ $status-margin: 0.75em;
}
.usercard {
- margin-bottom: $status-margin;
+ margin-bottom: var(--status-margin, $status-margin);
}
.status-username {
@@ -248,7 +239,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;
@@ -294,7 +285,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;
@@ -362,7 +353,7 @@ $status-margin: 0.75em;
}
.favs-repeated-users {
- margin-top: $status-margin;
+ margin-top: var(--status-margin, $status-margin);
}
.stats {
@@ -389,7 +380,7 @@ $status-margin: 0.75em;
}
.stat-count {
- margin-right: $status-margin;
+ margin-right: var(--status-margin, $status-margin);
user-select: none;
.stat-title {
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 8f51a778..1679834e 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -221,6 +221,31 @@
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
@@ -308,6 +333,12 @@
: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"
@@ -317,7 +348,20 @@
v-if="inConversation && !isPreview && replies && replies.length"
class="replies"
>
- <span class="faint">{{ $t('status.replies_list') }}</span>
+ <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"