logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe git clone https://hacktivis.me/git/pleroma-fe.git
commit: e560fbc9352f9f8754451f38c5e3ecef6da96686
parent 4adffb483579108c0bfe7593157e9bed3571903f
Author: Tusooa Zhu <tusooa@kazv.moe>
Date:   Tue, 10 Aug 2021 23:58:27 -0400

Implement Misskey-style tree view

Now the tree will be always rooted at the highlighted status, and
all its ancestors shown linearly on the top.

Enhancement: If an ancestor has more
than one reply (i.e. it has a child that is not on current status's
ancestor chain), we are given a link to root the thread at that status.

Diffstat:

Msrc/components/conversation/conversation.js61+++++++++++++++++++++++++++----------------------------------
Msrc/components/conversation/conversation.vue118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
2 files changed, 124 insertions(+), 55 deletions(-)

diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js @@ -55,7 +55,7 @@ const conversation = { expanded: false, threadDisplayStatusObject: {}, // id => 'showing' | 'hidden' statusContentPropertiesObject: {}, - diveHistory: [] + inlineDivePosition: null } }, props: [ @@ -231,7 +231,10 @@ const conversation = { return this.topLevel }, diveRoot () { - return this.diveHistory[this.diveHistory.length - 1] + (() => {})(this.conversation) + const statusId = this.inlineDivePosition || this.statusId + const isTopLevel = !this.parentOf(statusId) + return isTopLevel ? null : statusId }, diveDepth () { return this.canDive && this.diveRoot ? this.depths[this.diveRoot] : 0 @@ -332,7 +335,6 @@ const conversation = { this.fetchConversation() } else { // if we collapse it, we should reset the dive - this._diven = false this.undive() } }, @@ -348,19 +350,6 @@ const conversation = { if (!this.isExpanded) { return } - - if (!this._diven) { - if (!this.threadDisplayStatus[this.statusId]) { - return - } - this._diven = true - const parentOrSelf = this.parentOrSelf(this.originalStatusId) - // If current status is not visible - if (this.threadDisplayStatus[parentOrSelf] === 'hidden') { - this.diveIntoStatus(parentOrSelf, /* preventScroll */ true) - this.tryScrollTo(this.statusId) - } - } }, fetchConversation () { if (this.status) { @@ -449,26 +438,15 @@ const conversation = { return this.topLevel[0] ? this.topLevel[0].id : undefined }, diveIntoStatus (id, preventScroll) { - this.diveHistory = [...this.diveHistory, id] - if (!preventScroll) { - this.goToCurrent() - } + this.tryScrollTo(id) }, - diveBack () { - const oldHighlight = this.highlight - this.diveHistory = [...this.diveHistory.slice(0, this.diveHistory.length - 1)] - if (oldHighlight) { - this.tryScrollTo(this.leastVisibleAncestor(oldHighlight)) - } + diveToTopLevel () { + this.tryScrollTo(this.topLevel[0].id) }, + // only used when we are not on a page undive () { - const oldHighlight = this.highlight - this.diveHistory = [] - if (oldHighlight) { - this.tryScrollTo(this.leastVisibleAncestor(oldHighlight)) - } else { - this.goToCurrent() - } + this.inlineDivePosition = null + this.setHighlight(this.statusId) }, tryScrollTo (id) { if (!id) { @@ -477,8 +455,9 @@ const conversation = { if (this.isPage) { // set statusId this.$router.push({ name: 'conversation', params: { id } }) + } else { + this.inlineDivePosition = id } - this.setHighlight(id) }, goToCurrent () { @@ -493,10 +472,24 @@ const conversation = { return undefined } const { in_reply_to_status_id: parentId } = status + if (!this.statusMap[parentId]) { + return undefined + } return parentId }, parentOrSelf (id) { return this.parentOf(id) || id + }, + // Ancestors of some status, from top to bottom + ancestorsOf (id) { + const ancestors = [] + let cur = this.parentOf(id) + while (cur) { + ancestors.unshift(this.statusMap[cur]) + cur = this.parentOf(cur) + } + // console.log('ancestors = ', ancestors, 'conversation = ', this.conversation.map(k => k.id), 'statusContentProperties=', this.statusContentProperties) + return ancestors } } } diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue @@ -21,34 +21,88 @@ <div class="conversation-body panel-body"> <div v-if="diveMode" - class="conversation-undive-box" + class="conversation-dive-to-top-level-box" > <i18n path="status.show_all_conversation" tag="button" class="button-unstyled -link" - @click.prevent="undive" + @click.prevent="diveToTopLevel" > <FAIcon icon="angle-double-left" /> </i18n> </div> <div - v-if="diveMode" - class="conversation-undive-box" - > - <i18n - path="status.return_to_last_showing" - tag="button" - class="button-unstyled -link" - @click.prevent="diveBack" - > - <FAIcon icon="chevron-left" /> - </i18n> - </div> - <div v-if="isTreeView" class="thread-body" > + <div + v-if="ancestorsOf(diveRoot).length" + class="thread-ancestors" + > + <div + v-for="status in ancestorsOf(diveRoot)" + :key="status.id" + class="thread-ancestor" + :class="{'thread-ancestor-has-other-replies': getReplies(status.id).length > 1}" + > + <status + ref="statusComponent" + :inline-expanded="collapsable && isExpanded" + :statusoid="status" + :expandable="!isExpanded" + :show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]" + :focused="focused(status.id)" + :in-conversation="isExpanded" + :highlight="getHighlight()" + :replies="getReplies(status.id)" + :in-profile="inProfile" + :profile-user-id="profileUserId" + class="conversation-status status-fadein panel-body" + + :simple="treeViewIsSimple" + :toggle-thread-display="toggleThreadDisplay" + :thread-display-status="threadDisplayStatus" + :show-thread-recursively="showThreadRecursively" + :total-reply-count="totalReplyCount" + :total-reply-depth="totalReplyDepth" + :dive="(!treeViewIsSimple) ? () => diveIntoStatus(status.id) : null" + + :controlled-showing-tall="statusContentProperties[status.id].showingTall" + :controlled-expanding-subject="statusContentProperties[status.id].expandingSubject" + :controlled-showing-long-subject="statusContentProperties[status.id].showingLongSubject" + :controlled-toggle-showing-tall="() => toggleStatusContentProperty(status.id, 'showingTall')" + :controlled-toggle-expanding-subject="() => toggleStatusContentProperty(status.id, 'expandingSubject')" + :controlled-toggle-showing-long-subject="() => toggleStatusContentProperty(status.id, 'showingLongSubject')" + + @goto="setHighlight" + @toggleExpanded="toggleExpanded" + /> + <div + v-if="getReplies(status.id).length > 1" + class="thread-ancestor-dive-box" + > + <div + class="thread-ancestor-dive-box-inner" + > + <i18n + tag="button" + path="status.ancestor_follow_with_icon" + class="button-unstyled -link thread-tree-show-replies-button" + @click.prevent="diveIntoStatus(status.id)" + > + <FAIcon + place="icon" + icon="angle-double-right" + /> + <span place="text"> + {{ $tc('status.ancestor_follow', getReplies(status.id).length - 1, { numReplies: getReplies(status.id).length - 1 }) }} + </span> + </i18n> + </div> + </div> + </div> + </div> <thread-tree v-for="status in showingTopLevel" :key="status.id" @@ -128,7 +182,7 @@ @import '../../_variables.scss'; .Conversation { - .conversation-undive-box { + .conversation-dive-to-top-level-box { padding: $status-margin; border-bottom-width: 1px; border-bottom-style: solid; @@ -140,6 +194,27 @@ flex-direction: column; } + .thread-ancestor { + --link: var(--faintLink); + --text: var(--faint); + color: var(--text); + } + .thread-ancestor-dive-box { + padding-left: $status-margin; + border-bottom-width: 1px; + border-bottom-style: solid; + border-bottom-color: var(--border, $fallback--border); + border-radius: 0; + /* Make the button stretch along the whole row */ + display: flex; + align-items: stretch; + flex-direction: column; + } + .thread-ancestor-dive-box-inner { + padding: $status-margin; + //border-left: 2px solid var(--border, $fallback--border); + } + /* HACK: we want the border width to scale with the status *below it* */ .conversation-status { border-bottom-width: 1px; @@ -148,6 +223,7 @@ border-radius: 0; } + .thread-ancestor-has-other-replies .conversation-status, &.-expanded .thread-tree .conversation-status { border-bottom: none; } @@ -162,10 +238,10 @@ border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius); border-bottom: 1px solid var(--border, $fallback--border); } - &.-expanded { - .conversation-status:last-child { - border-bottom: none; - } - } + /* &.-expanded { */ + /* .conversation-status:last-child { */ + /* border-bottom: none; */ + /* } */ + /* } */ } </style>