cleanup and organization
This commit is contained in:
parent
6ef8b36c73
commit
06d3c41b63
2 changed files with 164 additions and 151 deletions
|
|
@ -18,7 +18,7 @@ import { useStreamingStore } from 'src/stores/streaming.js'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
fetchConversation as apiFetchConversation,
|
fetchConversation as apiFetchConversation,
|
||||||
fetchStatus,
|
fetchStatus as apiFetchStatus,
|
||||||
} from 'src/api/public.js'
|
} from 'src/api/public.js'
|
||||||
import { WSConnectionStatus } from 'src/api/websocket.js'
|
import { WSConnectionStatus } from 'src/api/websocket.js'
|
||||||
|
|
||||||
|
|
@ -83,6 +83,27 @@ export default {
|
||||||
mastoUserSocketStatus === WSConnectionStatus.JOINED,
|
mastoUserSocketStatus === WSConnectionStatus.JOINED,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// # Misc
|
||||||
|
const loadStatusError = ref(null)
|
||||||
|
const { layoutType } = storeToRefs(useInterfaceStore())
|
||||||
|
const mobileLayout = computed(() => layoutType.value === 'mobile')
|
||||||
|
|
||||||
|
// # Focus
|
||||||
|
const focusedId = ref(statusId.value)
|
||||||
|
const focused = computed(() => (isExpanded.value ? focusedId.value : null))
|
||||||
|
const setFocused = (id) => {
|
||||||
|
if (!id) return
|
||||||
|
focusedId.value = id
|
||||||
|
|
||||||
|
if (!streamingEnabled.value) {
|
||||||
|
useStatusesStore().fetchStatus(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
useStatusesStore().fetchFavsAndRepeats(id)
|
||||||
|
useStatusesStore().fetchEmojiReactions(id)
|
||||||
|
}
|
||||||
|
provide('focused', focused)
|
||||||
|
|
||||||
// # Main things
|
// # Main things
|
||||||
const getStatusObject = (id) => useStatusesStore().allStatuses.get(id)
|
const getStatusObject = (id) => useStatusesStore().allStatuses.get(id)
|
||||||
const getConversationId = (statusId) => {
|
const getConversationId = (statusId) => {
|
||||||
|
|
@ -93,13 +114,56 @@ export default {
|
||||||
get(status, 'statusnet_conversation_id'),
|
get(status, 'statusnet_conversation_id'),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
const status = computed(() => getStatusObject(focusedId.value))
|
||||||
|
|
||||||
const status = computed(() => getStatusObject(statusId.value))
|
const fetchConversation = async () => {
|
||||||
const mainStatusId = computed(() => {
|
if (status.value) {
|
||||||
if (status.value.retweeted_status) {
|
const {
|
||||||
return status.value.retweeted_status.id
|
data: { ancestors, descendants },
|
||||||
|
timestamp,
|
||||||
|
} = await apiFetchConversation({
|
||||||
|
id: statusId.value,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
})
|
||||||
|
|
||||||
|
useStatusesStore().addNewStatuses({ statuses: ancestors, timestamp })
|
||||||
|
useStatusesStore().addNewStatuses({
|
||||||
|
statuses: descendants,
|
||||||
|
timestamp,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
return statusId.value
|
try {
|
||||||
|
loadStatusError.value = null
|
||||||
|
|
||||||
|
const { data: status } = await apiFetchStatus({
|
||||||
|
id: statusId.value,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
})
|
||||||
|
|
||||||
|
useStatusesStore().addNewStatuses({ statuses: [status] })
|
||||||
|
fetchConversation()
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
loadStatusError.value = error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const resetDisplayState = () => {
|
||||||
|
setFocused(statusId.value)
|
||||||
|
threadDisplay.value = new Map()
|
||||||
|
}
|
||||||
|
watch(statusId, (newVal, oldVal) => {
|
||||||
|
const newConversationId = getConversationId(newVal)
|
||||||
|
const oldConversationId = getConversationId(oldVal)
|
||||||
|
if (
|
||||||
|
newConversationId &&
|
||||||
|
oldConversationId &&
|
||||||
|
newConversationId === oldConversationId
|
||||||
|
) {
|
||||||
|
setFocused(newVal)
|
||||||
|
} else {
|
||||||
|
resetDisplayState()
|
||||||
|
fetchConversation()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -157,74 +221,13 @@ export default {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
const getReplies = (id) => replies.value.get(id) ?? new Set()
|
const getReplies = (id) => replies.value.get(id) ?? new Set()
|
||||||
|
const statusReplies = computed(() => {
|
||||||
|
return getReplies(status.value.id)
|
||||||
|
})
|
||||||
|
|
||||||
provide('conversation', conversation)
|
provide('conversation', conversation)
|
||||||
provide('replies', replies)
|
provide('replies', replies)
|
||||||
|
|
||||||
const fetchConversation = async () => {
|
|
||||||
if (status.value) {
|
|
||||||
const {
|
|
||||||
data: { ancestors, descendants },
|
|
||||||
timestamp,
|
|
||||||
} = await apiFetchConversation({
|
|
||||||
id: statusId.value,
|
|
||||||
credentials: useOAuthStore().token,
|
|
||||||
})
|
|
||||||
|
|
||||||
useStatusesStore().addNewStatuses({ statuses: ancestors, timestamp })
|
|
||||||
useStatusesStore().addNewStatuses({
|
|
||||||
statuses: descendants,
|
|
||||||
timestamp,
|
|
||||||
})
|
|
||||||
setFocused(mainStatusId.value)
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
loadStatusError.value = null
|
|
||||||
|
|
||||||
const { data: status } = await fetchStatus({
|
|
||||||
id: statusId.value,
|
|
||||||
credentials: useOAuthStore().token,
|
|
||||||
})
|
|
||||||
|
|
||||||
useStatusesStore().addNewStatuses({ statuses: [status] })
|
|
||||||
fetchConversation()
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
loadStatusError.value = error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const resetDisplayState = () => {
|
|
||||||
setFocused(statusId.value)
|
|
||||||
threadDisplay.value = new Map()
|
|
||||||
}
|
|
||||||
|
|
||||||
// # Virtual scrolling stuff
|
|
||||||
const { virtualHidden } = toRefs(props)
|
|
||||||
const unsuspendibleIds = ref(new Set())
|
|
||||||
const suspendable = computed(() => unsuspendibleIds.value.size === 0)
|
|
||||||
const hide = computed(() => virtualHidden.value && suspendable.value)
|
|
||||||
const onStatusSuspendStateChange = ({ id, suspend }) => {
|
|
||||||
if (!suspend) {
|
|
||||||
unsuspendibleIds.value.add(id)
|
|
||||||
} else {
|
|
||||||
unsuspendibleIds.value.delete(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// # Misc UI things
|
|
||||||
const loadStatusError = ref(null)
|
|
||||||
const { layoutType } = storeToRefs(useInterfaceStore())
|
|
||||||
const mobileLayout = computed(() => layoutType.value === 'mobile')
|
|
||||||
const firstStatus = computed(() => conversation.value[0])
|
|
||||||
const lastStatus = computed(
|
|
||||||
() => conversation.value[conversation.value.legnth - 1],
|
|
||||||
)
|
|
||||||
const getStatusClasses = (status, active) => ({
|
|
||||||
'-first': status.id === firstStatus.value?.id,
|
|
||||||
'-last': status.id === lastStatus.value?.id,
|
|
||||||
})
|
|
||||||
|
|
||||||
// # Conversation Expansion
|
// # Conversation Expansion
|
||||||
const expanded = ref(false)
|
const expanded = ref(false)
|
||||||
const { isPage } = toRefs(props)
|
const { isPage } = toRefs(props)
|
||||||
|
|
@ -242,65 +245,41 @@ export default {
|
||||||
provide('isExpanded', isExpanded)
|
provide('isExpanded', isExpanded)
|
||||||
provide('isPage', isPage)
|
provide('isPage', isPage)
|
||||||
|
|
||||||
// # Focus
|
|
||||||
const focusedId = ref(statusId.value)
|
|
||||||
const focused = computed(() => (isExpanded.value ? focusedId.value : null))
|
|
||||||
const setFocused = (id) => {
|
|
||||||
if (!id) return
|
|
||||||
focusedId.value = id
|
|
||||||
|
|
||||||
if (!streamingEnabled.value) {
|
|
||||||
useStatusesStore().fetchStatus(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
useStatusesStore().fetchFavsAndRepeats(id)
|
|
||||||
useStatusesStore().fetchEmojiReactions(id)
|
|
||||||
}
|
|
||||||
watch(statusId, (newVal, oldVal) => {
|
|
||||||
const newConversationId = getConversationId(newVal)
|
|
||||||
const oldConversationId = getConversationId(oldVal)
|
|
||||||
if (
|
|
||||||
newConversationId &&
|
|
||||||
oldConversationId &&
|
|
||||||
newConversationId === oldConversationId
|
|
||||||
) {
|
|
||||||
setFocused(mainStatusId.value)
|
|
||||||
} else {
|
|
||||||
fetchConversation()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
provide('focused', focused)
|
|
||||||
|
|
||||||
// Component created
|
// Component created
|
||||||
if (isPage.value) {
|
if (isPage.value) {
|
||||||
fetchConversation()
|
fetchConversation()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// # Virtual scrolling stuff
|
||||||
|
const { virtualHidden } = toRefs(props)
|
||||||
|
const unsuspendibleIds = ref(new Set())
|
||||||
|
const suspendable = computed(() => unsuspendibleIds.value.size === 0)
|
||||||
|
const hide = computed(() => virtualHidden.value && suspendable.value)
|
||||||
|
const onStatusSuspendStateChange = ({ id, suspend }) => {
|
||||||
|
if (!suspend) {
|
||||||
|
unsuspendibleIds.value.add(id)
|
||||||
|
} else {
|
||||||
|
unsuspendibleIds.value.delete(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// # Misc UI things
|
||||||
|
const firstStatus = computed(() => conversation.value[0])
|
||||||
|
const lastStatus = computed(
|
||||||
|
() => conversation.value[conversation.value.legnth - 1],
|
||||||
|
)
|
||||||
|
const getStatusClasses = (status, active) => ({
|
||||||
|
'-first': status.id === firstStatus.value?.id,
|
||||||
|
'-last': status.id === lastStatus.value?.id,
|
||||||
|
})
|
||||||
|
|
||||||
// # Linear style stuff
|
// # Linear style stuff
|
||||||
const isLinearView = computed(() => displayStyle.value !== 'tree')
|
const isLinearView = computed(() => displayStyle.value !== 'tree')
|
||||||
|
|
||||||
// # Tree style stuff
|
// # Tree style stuff
|
||||||
const isTreeView = computed(() => displayStyle.value === 'tree')
|
const isTreeView = computed(() => displayStyle.value === 'tree')
|
||||||
|
|
||||||
// ## Tree view settings
|
// ## Tree state
|
||||||
const treeViewIsSimple = computed(
|
|
||||||
() => !mergedConfig.value.conversationTreeAdvanced,
|
|
||||||
)
|
|
||||||
const shouldFadeAncestors = computed(
|
|
||||||
() => mergedConfig.value.conversationTreeFadeAncestors,
|
|
||||||
)
|
|
||||||
const showOtherRepliesButtonBelowStatus = computed(
|
|
||||||
() => mergedConfig.value.conversationOtherRepliesButton === 'below',
|
|
||||||
)
|
|
||||||
const maxDepthToShowByDefault = computed(() => {
|
|
||||||
// maxDepthInThread = max number of depths that is *visible*
|
|
||||||
// since our depth starts with 0 and "showing" means "showing children"
|
|
||||||
// there is a -2 here
|
|
||||||
const maxDepth = mergedConfig.value.maxDepthInThread - 2
|
|
||||||
return Math.min(1, maxDepth)
|
|
||||||
})
|
|
||||||
|
|
||||||
// ## Tree style state
|
|
||||||
// ### Topology
|
// ### Topology
|
||||||
const ancestors = computed(() => {
|
const ancestors = computed(() => {
|
||||||
// First we fill map with empty sets and add given id's parent
|
// First we fill map with empty sets and add given id's parent
|
||||||
|
|
@ -344,7 +323,6 @@ export default {
|
||||||
getAncestors(focusedId.value).reverse(),
|
getAncestors(focusedId.value).reverse(),
|
||||||
)
|
)
|
||||||
const currentDepth = computed(() => currentAncestors.value.length)
|
const currentDepth = computed(() => currentAncestors.value.length)
|
||||||
const currentStatus = computed(() => getStatusObject(focusedId.value))
|
|
||||||
|
|
||||||
// ### Thread Display
|
// ### Thread Display
|
||||||
const threadDisplay = ref(new Map()) // id => 'showing' | 'hidden'
|
const threadDisplay = ref(new Map()) // id => 'showing' | 'hidden'
|
||||||
|
|
@ -378,15 +356,31 @@ export default {
|
||||||
setThreadDisplayRecursively(id, 'showing')
|
setThreadDisplayRecursively(id, 'showing')
|
||||||
}
|
}
|
||||||
|
|
||||||
// ## Derived values
|
// ## Derived values and config
|
||||||
|
const treeViewIsSimple = computed(
|
||||||
|
() => !mergedConfig.value.conversationTreeAdvanced,
|
||||||
|
)
|
||||||
|
const maxDepthToShowByDefault = computed(() => {
|
||||||
|
// maxDepthInThread = max number of depths that is *visible*
|
||||||
|
// since our depth starts with 0 and "showing" means "showing children"
|
||||||
|
// there is a -2 here
|
||||||
|
const maxDepth = mergedConfig.value.maxDepthInThread - 2
|
||||||
|
return Math.min(1, maxDepth)
|
||||||
|
})
|
||||||
const shouldShowAllConversationButton = computed(
|
const shouldShowAllConversationButton = computed(
|
||||||
() => currentAncestors.value.length > 0 && topLevel.value.length > 1,
|
() => currentAncestors.value.length > 0 && topLevel.value.length > 1,
|
||||||
)
|
)
|
||||||
const shouldShowAncestors = computed(
|
const shouldShowAncestors = computed(
|
||||||
() => isExpanded.value && ancestors.value.get(focusedId.value) != null,
|
() => isExpanded.value && ancestors.value.get(focusedId.value) != null,
|
||||||
)
|
)
|
||||||
|
const shouldFadeAncestors = computed(
|
||||||
|
() => mergedConfig.value.conversationTreeFadeAncestors,
|
||||||
|
)
|
||||||
|
const shouldShowOtherRepliesButton = computed(
|
||||||
|
() => mergedConfig.value.conversationOtherRepliesButton === 'below',
|
||||||
|
)
|
||||||
|
|
||||||
// # Scrolling / diving
|
// # Scrolling
|
||||||
const tryScrollTo = (id) => {
|
const tryScrollTo = (id) => {
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return
|
return
|
||||||
|
|
@ -421,37 +415,56 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hide,
|
// # Misc
|
||||||
isLinearView,
|
|
||||||
isTreeView,
|
|
||||||
isExpanded,
|
|
||||||
conversation,
|
|
||||||
mobileLayout,
|
|
||||||
toggleExpanded,
|
|
||||||
isPage,
|
|
||||||
status,
|
|
||||||
loadStatusError,
|
loadStatusError,
|
||||||
|
mobileLayout,
|
||||||
|
|
||||||
|
// # Focus
|
||||||
focused,
|
focused,
|
||||||
setFocused,
|
setFocused,
|
||||||
showOtherRepliesButtonBelowStatus,
|
|
||||||
|
// # Main things
|
||||||
|
status,
|
||||||
|
statusReplies,
|
||||||
|
conversation,
|
||||||
|
|
||||||
|
// # Conversation Expansion
|
||||||
|
isPage,
|
||||||
|
isExpanded,
|
||||||
|
toggleExpanded,
|
||||||
|
|
||||||
|
// # Virtual scrolling stuff
|
||||||
|
hide,
|
||||||
onStatusSuspendStateChange,
|
onStatusSuspendStateChange,
|
||||||
getStatusClasses,
|
|
||||||
getReplies,
|
|
||||||
currentAncestors,
|
|
||||||
statusId,
|
|
||||||
virtualHidden,
|
virtualHidden,
|
||||||
shouldShowAncestors,
|
|
||||||
shouldShowAllConversationButton,
|
// # Misc UI things
|
||||||
|
getStatusClasses,
|
||||||
|
|
||||||
|
// # Linear style stuff
|
||||||
|
isLinearView,
|
||||||
|
|
||||||
|
// # Tree style stuff
|
||||||
|
isTreeView,
|
||||||
|
|
||||||
|
// ## Tree state
|
||||||
|
// ### Topology
|
||||||
topLevel,
|
topLevel,
|
||||||
shouldFadeAncestors,
|
currentAncestors,
|
||||||
currentStatus,
|
|
||||||
treeViewIsSimple,
|
// ### Thread Display
|
||||||
diveToTopLevel,
|
|
||||||
threadDisplay,
|
|
||||||
threadDisplayDefault,
|
|
||||||
replies,
|
|
||||||
diveIntoStatus,
|
|
||||||
showThreadRecursively,
|
showThreadRecursively,
|
||||||
|
|
||||||
|
// ## Derived values and config
|
||||||
|
treeViewIsSimple,
|
||||||
|
shouldShowAllConversationButton,
|
||||||
|
shouldShowAncestors,
|
||||||
|
shouldFadeAncestors,
|
||||||
|
shouldShowOtherRepliesButton,
|
||||||
|
|
||||||
|
// # Scrolling
|
||||||
|
diveToTopLevel,
|
||||||
|
diveIntoStatus,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,24 +93,24 @@
|
||||||
<article
|
<article
|
||||||
v-for="status in currentAncestors"
|
v-for="status in currentAncestors"
|
||||||
class="thread-ancestor"
|
class="thread-ancestor"
|
||||||
:class="{'thread-ancestor-has-other-replies': getReplies(status.id).length > 1, '-faded': shouldFadeAncestors}"
|
:class="{'thread-ancestor-has-other-replies': statusReplies.size > 1, '-faded': shouldFadeAncestors}"
|
||||||
>
|
>
|
||||||
<Status
|
<Status
|
||||||
class="conversation-status panel-body"
|
class="conversation-status panel-body"
|
||||||
:class="getStatusClasses(status)"
|
:class="getStatusClasses(status)"
|
||||||
|
|
||||||
:status-id="status.id"
|
:status-id="status.id"
|
||||||
:replies="getReplies(status.id)"
|
:replies="statusReplies"
|
||||||
|
|
||||||
:focused="focused === status.id"
|
:focused="focused === status.id"
|
||||||
can-dive
|
can-dive
|
||||||
|
|
||||||
@goto="setFocused"
|
@goto="setFocused"
|
||||||
@dive="() => diveIntoStatus(status.id)"
|
@dive="diveIntoStatus(status.id)"
|
||||||
@suspendable-state-change="onStatusSuspendStateChange"
|
@suspendable-state-change="onStatusSuspendStateChange"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
v-if="showOtherRepliesButtonBelowStatus && getReplies(status.id).size > 1"
|
v-if="shouldShowOtherRepliesButton && statusReplies.size > 1"
|
||||||
class="thread-ancestor-dive-box"
|
class="thread-ancestor-dive-box"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|
@ -130,7 +130,7 @@
|
||||||
</template>
|
</template>
|
||||||
<template #text>
|
<template #text>
|
||||||
<span>
|
<span>
|
||||||
{{ $t('status.ancestor_follow', { numReplies: getReplies(status.id, getReplies(status.id).size - 1).size - 1 }) }}
|
{{ $t('status.ancestor_follow', { numReplies: statusReplies.size - 1 }) }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
|
|
@ -139,7 +139,7 @@
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
<ThreadTree
|
<ThreadTree
|
||||||
:status-id="currentStatus.id"
|
:status-id="status.id"
|
||||||
:depth="0"
|
:depth="0"
|
||||||
|
|
||||||
@goto="setFocused"
|
@goto="setFocused"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue