experimentation

This commit is contained in:
Henry Jameson 2026-09-07 18:07:01 +03:00
commit 78e40e4ce2
7 changed files with 124 additions and 117 deletions

View file

@ -495,6 +495,13 @@ const conversation = {
[id]: nextStatus, [id]: nextStatus,
} }
}, },
getStatusClasses(status, active) {
return {
'-virtual-active': active,
'-last': status.id === this.conversation[this.conversation.length - 1].id,
'-first': status.id === this.conversation[0].id,
}
},
toggleThreadDisplay(id) { toggleThreadDisplay(id) {
const curStatus = this.threadDisplayStatus[id] const curStatus = this.threadDisplayStatus[id]
const nextStatus = curStatus === 'showing' ? 'hidden' : 'showing' const nextStatus = curStatus === 'showing' ? 'hidden' : 'showing'

View file

@ -6,6 +6,15 @@
backdrop-filter: var(--__panel-backdrop-filter); backdrop-filter: var(--__panel-backdrop-filter);
} }
.conversation-status:not(.-last) {
border-bottom: 1px solid var(--border);
}
.conversation-status:not(.-last)
.conversation-status:not(.-first) {
border-radius: 0;
}
.conversation-dive-to-top-level-box { .conversation-dive-to-top-level-box {
padding: var(--status-margin); padding: var(--status-margin);
border-bottom: 1px solid var(--border); border-bottom: 1px solid var(--border);
@ -49,26 +58,12 @@
padding: var(--status-margin); padding: var(--status-margin);
} }
.conversation-status {
border-bottom: 1px solid var(--border);
border-radius: 0;
}
.thread-ancestor-has-other-replies .conversation-status,
&:last-child:not(.-expanded) .conversation-status,
&.-expanded .conversation-status:last-child,
.thread-ancestor:last-child .conversation-status,
.thread-ancestor:last-child .thread-ancestor-dive-box,
&.-expanded .thread-tree .conversation-status {
border-bottom: none;
}
.thread-ancestors + .thread-tree > .conversation-status { .thread-ancestors + .thread-tree > .conversation-status {
border-top: 1px solid var(--border); border-top: 1px solid var(--border);
} }
/* expanded conversation in timeline */ /* expanded conversation in timeline */
&.status-fadein.-expanded .thread-body { &.-expanded .thread-body {
border-left: 4px solid var(--cRed); border-left: 4px solid var(--cRed);
border-radius: var(--roundness); border-radius: var(--roundness);
border-top-left-radius: 0; border-top-left-radius: 0;
@ -76,7 +71,7 @@
border-bottom: 1px solid var(--border); border-bottom: 1px solid var(--border);
} }
&.-expanded.status-fadein { &.-expanded:not(.-page) {
--___margin: calc(var(--status-margin) / 2); --___margin: calc(var(--status-margin) / 2);
background: var(--background); background: var(--background);

View file

@ -2,7 +2,7 @@
<div <div
v-if="!hide" v-if="!hide"
class="Conversation" class="Conversation"
:class="{ '-expanded' : isExpanded, 'panel' : isExpanded }" :class="{ '-expanded' : isExpanded, '-page': isPage, 'panel' : isExpanded }"
> >
<div <div
v-if="isExpanded" v-if="isExpanded"
@ -86,68 +86,78 @@
</template> </template>
</i18n-t> </i18n-t>
</div> </div>
<div <DynamicScroller
v-if="shouldShowAncestors" v-if="shouldShowAncestors"
class="thread-ancestors" class="thread-ancestors"
:min-item-size="15"
:buffer="500"
:items="ancestorsOf(diveRoot)"
role="feed"
list-tag="article"
item-tag="article"
:item-class="{'thread-ancestor-has-other-replies': getReplies(status.id).length > 1, '-faded': shouldFadeAncestors, 'thread-ancestor': true }"
flow-mode
page-mode
> >
<article <template #default="{ item: status, active }">
v-for="status in ancestorsOf(diveRoot)" <DynamicScrollerItem
:key="status.id" :item="status"
class="thread-ancestor" :active="active"
:class="{'thread-ancestor-has-other-replies': getReplies(status.id).length > 1, '-faded': shouldFadeAncestors}"
>
<Status
ref="statusComponent"
class="conversation-status status-fadein panel-body"
:status-id="status.id"
:replies="getReplies(status.id)"
:expandable="!isExpanded"
:focused="maybeFocused === status.id"
:inline-expanded="collapsable && isExpanded"
:show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]"
:in-profile="inProfile"
:in-conversation="isExpanded"
:profile-user-id="profileUserId"
:simple-tree="treeViewIsSimple"
:show-other-replies-as-button="showOtherRepliesButtonInsideStatus"
can-dive
@goto="setFocused"
@dive="() => diveIntoStatus(status.id)"
@suspendable-state-change="onStatusSuspendStateChange"
@height-change="updateVirtualHeight"
/>
<div
v-if="showOtherRepliesButtonBelowStatus && getReplies(status.id).length > 1"
class="thread-ancestor-dive-box"
> >
<Status
ref="statusComponent"
class="conversation-status panel-body"
:class="getStatusClasses(status, active)"
:status-id="status.id"
:replies="getReplies(status.id)"
:expandable="!isExpanded"
:focused="maybeFocused === status.id"
:inline-expanded="collapsable && isExpanded"
:show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]"
:in-profile="inProfile"
:in-conversation="isExpanded"
:profile-user-id="profileUserId"
:simple-tree="treeViewIsSimple"
:show-other-replies-as-button="showOtherRepliesButtonInsideStatus"
can-dive
@goto="setFocused"
@dive="() => diveIntoStatus(status.id)"
@suspendable-state-change="onStatusSuspendStateChange"
@height-change="updateVirtualHeight"
/>
<div <div
class="thread-ancestor-dive-box-inner" v-if="showOtherRepliesButtonBelowStatus && getReplies(status.id).length > 1"
class="thread-ancestor-dive-box"
> >
<i18n-t <div
tag="button" class="thread-ancestor-dive-box-inner"
scope="global"
keypath="status.ancestor_follow_with_icon"
class="button-unstyled -link thread-tree-show-replies-button"
@click.prevent="diveIntoStatus(status.id)"
> >
<template #icon> <i18n-t
<FAIcon tag="button"
icon="angle-double-right" scope="global"
/> keypath="status.ancestor_follow_with_icon"
</template> class="button-unstyled -link thread-tree-show-replies-button"
<template #text> @click.prevent="diveIntoStatus(status.id)"
<span> >
{{ $t('status.ancestor_follow', { numReplies: getReplies(status.id, getReplies(status.id).length - 1).length - 1 }) }} <template #icon>
</span> <FAIcon
</template> icon="angle-double-right"
</i18n-t> />
</template>
<template #text>
<span>
{{ $t('status.ancestor_follow', { numReplies: getReplies(status.id, getReplies(status.id).length - 1).length - 1 }) }}
</span>
</template>
</i18n-t>
</div>
</div> </div>
</div> </DynamicScrollerItem>
</article> </template>
</div> </DynamicScroller>
<ThreadTree <ThreadTree
v-for="status in showingTopLevel" v-for="status in showingTopLevel"
:key="status.id" :key="status.id"
@ -179,34 +189,47 @@
@height-change="updateVirtualHeight" @height-change="updateVirtualHeight"
/> />
</div> </div>
<div <DynamicScroller
v-else-if="isLinearView" v-else-if="isLinearView"
class="thread-body" class="thread-body"
:min-item-size="15"
:buffer="500"
:items="conversation"
page-mode
flow-mode
role="feed"
item-tag="article"
item-class="panel-body"
> >
<article> <template #default="{ item: status, active }">
<Status <DynamicScrollerItem
v-for="status in conversation" :item="status"
:key="status.id" :active="active"
ref="statusComponent" >
class="conversation-status status-fadein panel-body" <Status
:status-id="status.id" :key="status.id"
:replies="getReplies(status.id)" ref="statusComponent"
class="conversation-status"
:class="getStatusClasses(status, active)"
:status-id="status.id"
:replies="getReplies(status.id)"
:expandable="!isExpanded" :expandable="!isExpanded"
:focused="maybeFocused === status.id || maybeFocused === status.retweeted_status?.id" :focused="maybeFocused === status.id || maybeFocused === status.retweeted_status?.id"
:inline-expanded="collapsable && isExpanded" :inline-expanded="collapsable && isExpanded"
:show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]" :show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]"
:in-profile="inProfile" :in-profile="inProfile"
:in-conversation="isExpanded" :in-conversation="isExpanded"
:profile-user-id="profileUserId" :profile-user-id="profileUserId"
@goto="setFocused" @goto="setFocused"
@toggle-expanded="toggleExpanded" @toggle-expanded="toggleExpanded"
@suspendable-state-change="onStatusSuspendStateChange" @suspendable-state-change="onStatusSuspendStateChange"
@height-change="updateVirtualHeight" @height-change="updateVirtualHeight"
/> />
</article> </DynamicScrollerItem>
</div> </template>
</DynamicScroller>
</div> </div>
</div> </div>
<div <div

View file

@ -271,21 +271,6 @@
} }
} }
.status-fadein {
animation-duration: 0.4s;
animation-name: fadein;
}
@keyframes fadein {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.status-actions { .status-actions {
position: relative; position: relative;
width: 100%; width: 100%;

View file

@ -20,7 +20,7 @@
:key="status.id" :key="status.id"
:statusoid="status" :statusoid="status"
:is-preview="true" :is-preview="true"
class="conversation-status status-fadein panel-body" class="conversation-status panel-body"
/> />
</div> </div>
</div> </div>

View file

@ -12,7 +12,7 @@
:focused="focused === statusId" :focused="focused === statusId"
:in-profile="inProfile" :in-profile="inProfile"
:profile-user-id="profileUserId" :profile-user-id="profileUserId"
class="conversation-status conversation-status-treeview status-fadein panel-body" class="conversation-status conversation-status-treeview panel-body"
:simple-tree="simple" :simple-tree="simple"
:thread-display-status="threadDisplayStatus[statusId]" :thread-display-status="threadDisplayStatus[statusId]"

View file

@ -80,24 +80,21 @@
<DynamicScroller <DynamicScroller
class="timeline" class="timeline"
ref="timeline" ref="timeline"
:min-item-size="120" :min-item-size="15"
:buffer="120" :buffer="120"
:items="filteredVisibleStatuses" :items="filteredVisibleStatuses"
:emit-update="true"
flow-mode flow-mode
page-mode
role="feed" role="feed"
> >
<template #default="{ item: status, index, active }"> <template #default="{ item: status, active }">
<DynamicScrollerItem <DynamicScrollerItem
:item="status" :item="status"
:active="active" :active="active"
:index="index"
:size-dependencies="[status.status]"
> >
<Conversation <Conversation
:key="status.id" :key="status.id"
role="listitem" role="listitem"
class="status-fadein"
:status-id="status.id" :status-id="status.id"
:in-profile="inProfile" :in-profile="inProfile"
:profile-user-id="timelineRef.argument" :profile-user-id="timelineRef.argument"