Browse Source

feat: sort thread oldest first

whilst maintaining sorting by youngest first in ProposalList

note: events that tag root event secondarily (eg. mention)
are no longer diplsayed
master
DanConwayDev 2 years ago
parent
commit
e65bc77842
No known key found for this signature in database
GPG Key ID: 68E15486D73F75E1
  1. 3
      src/lib/components/proposals/ProposalsList.svelte
  2. 4
      src/lib/stores/Issue.ts
  3. 2
      src/lib/stores/Issues.ts
  4. 4
      src/lib/stores/Proposal.ts
  5. 2
      src/lib/stores/Proposals.ts
  6. 38
      src/lib/wrappers/Thread.svelte
  7. 5
      src/lib/wrappers/ThreadTree.svelte

3
src/lib/components/proposals/ProposalsList.svelte

@ -9,6 +9,7 @@
export let show_repo: boolean = false export let show_repo: boolean = false
export let limit: number = 0 export let limit: number = 0
export let allow_more = true export let allow_more = true
export let sort_youngest_first = true
let current_limit = limit let current_limit = limit
</script> </script>
@ -22,7 +23,7 @@
<p class="prose">None</p> <p class="prose">None</p>
{/if} {/if}
<ul class=" divide-y divide-base-400"> <ul class=" divide-y divide-base-400">
{#each proposals_or_issues as proposal, index} {#each sort_youngest_first ? proposals_or_issues.sort((a, b) => (b.created_at || 0) - (a.created_at || 0)) : proposals_or_issues as proposal, index}
{#if current_limit === 0 || index + 1 <= current_limit} {#if current_limit === 0 || index + 1 <= current_limit}
<ProposalsListItem {...proposal} {show_repo} /> <ProposalsListItem {...proposal} {show_repo} />
{/if} {/if}

4
src/lib/stores/Issue.ts

@ -170,9 +170,7 @@ export const ensureIssueFull = (repo_identifier: string, issue_id: string) => {
}) })
} }
selected_issue_replies.update((replies) => { selected_issue_replies.update((replies) => {
return [...replies, event].sort( return [...replies, event]
(a, b) => (a.created_at || 0) - (b.created_at || 0)
)
}) })
} }

2
src/lib/stores/Issues.ts

@ -126,7 +126,7 @@ export const ensureIssueSummaries = async (repo_id: string | undefined) => {
}, },
loading: false, loading: false,
}, },
].sort((a, b) => (b.created_at || 0) - (a.created_at || 0)), ],
} }
}) })
} }

4
src/lib/stores/Proposal.ts

@ -179,9 +179,7 @@ export const ensureProposalFull = (
}) })
} }
selected_proposal_replies.update((replies) => { selected_proposal_replies.update((replies) => {
return [...replies, event].sort( return [...replies, event]
(a, b) => (a.created_at || 0) - (b.created_at || 0)
)
}) })
if (event.tags.some((t) => t.length > 1 && t[1] === 'revision-root')) { if (event.tags.some((t) => t.length > 1 && t[1] === 'revision-root')) {
const sub_revision_replies = ndk.subscribe( const sub_revision_replies = ndk.subscribe(

2
src/lib/stores/Proposals.ts

@ -143,7 +143,7 @@ export const ensureProposalSummaries = async (repo_id: string | undefined) => {
}, },
loading: false, loading: false,
}, },
].sort((a, b) => (b.created_at || 0) - (a.created_at || 0)), ],
} }
}) })
} }

38
src/lib/wrappers/Thread.svelte

@ -1,19 +1,21 @@
<script lang="ts"> <script lang="ts">
import type { NDKEvent } from '@nostr-dev-kit/ndk' import type { NDKEvent } from '@nostr-dev-kit/ndk'
import EventCard from './EventCard.svelte'
import ThreadWrapper from '$lib/components/events/ThreadWrapper.svelte'
import { writable } from 'svelte/store' import { writable } from 'svelte/store'
import ComposeReply from './ComposeReply.svelte'
import type { ThreadTreeNode } from '$lib/components/events/type' import type { ThreadTreeNode } from '$lib/components/events/type'
import ThreadTree from './ThreadTree.svelte' import ThreadTree from './ThreadTree.svelte'
export let event: NDKEvent export let event: NDKEvent
export let type: 'proposal' | 'issue' = 'proposal' export let type: 'proposal' | 'issue' = 'proposal'
export let show_compose = true
export let replies: NDKEvent[] | undefined = undefined export let replies: NDKEvent[] | undefined = undefined
const getParentId = (reply: NDKEvent): string | undefined => { const getParentId = (reply: NDKEvent): string | undefined => {
let t = reply.tags.find((tag) => tag.length === 4 && tag[3] === 'reply') let t =
reply.tags.find((tag) => tag.length === 4 && tag[3] === 'reply') ||
reply.tags.find((tag) => tag.length === 4 && tag[3] === 'root') ||
// include events that don't use nip 10 markers
reply.tags.find((tag) => tag.length < 4 && tag[0] === 'e')
return t ? t[1] : undefined return t ? t[1] : undefined
} }
@ -25,24 +27,28 @@
const thread_tree: ThreadTreeNode[] = [] const thread_tree: ThreadTreeNode[] = []
replies.forEach((reply) => { replies.forEach((reply) => {
let reply_parent_id = getParentId(reply) let reply_parent_id = getParentId(reply)
if (reply_parent_id && hashTable[reply_parent_id]) if (reply_parent_id && hashTable[reply_parent_id]) {
hashTable[reply_parent_id].child_nodes.push(hashTable[reply.id]) hashTable[reply_parent_id].child_nodes.push(hashTable[reply.id])
else thread_tree.push(hashTable[reply.id]) hashTable[reply_parent_id].child_nodes.sort(
(a, b) => (a.event.created_at || 0) - (b.event.created_at || 0)
)
} else thread_tree.push(hashTable[reply.id])
}) })
return thread_tree return thread_tree
} }
let thread_tree_store = writable(createThreadTree(replies ? replies : [])) let thread_tree_store = writable(
createThreadTree(replies ? [event, ...replies] : [event])
)
let thread_tree_root: ThreadTreeNode | undefined
// TODO: add 'mentions' and secondary references that fall outside of root childNodes
// they should appear in the UI as 'mentioned in' and be clear that replies ar enot incldued
$: { $: {
if (replies) thread_tree_store.set(createThreadTree(replies)) if (replies) thread_tree_store.set(createThreadTree([event, ...replies]))
thread_tree_root = $thread_tree_store.find((t) => t.event.id === event.id)
} }
</script> </script>
<EventCard {type} {event} /> {#if thread_tree_root}
<ThreadTree {type} tree={thread_tree_root} {show_compose} />
<ThreadWrapper num_replies={$thread_tree_store.length}> {/if}
{#each $thread_tree_store as tree}
<ThreadTree {type} {tree} />
{/each}
<ComposeReply {type} reply_to_event_id={event.id} />
</ThreadWrapper>

5
src/lib/wrappers/ThreadTree.svelte

@ -2,9 +2,11 @@
import EventCard from './EventCard.svelte' import EventCard from './EventCard.svelte'
import ThreadWrapper from '$lib/components/events/ThreadWrapper.svelte' import ThreadWrapper from '$lib/components/events/ThreadWrapper.svelte'
import type { ThreadTreeNode } from '$lib/components/events/type' import type { ThreadTreeNode } from '$lib/components/events/type'
import ComposeReply from './ComposeReply.svelte'
export let tree: ThreadTreeNode export let tree: ThreadTreeNode
export let type: 'proposal' | 'issue' = 'proposal' export let type: 'proposal' | 'issue' = 'proposal'
export let show_compose = false
const countReplies = (tree: ThreadTreeNode, starting: number = 0): number => { const countReplies = (tree: ThreadTreeNode, starting: number = 0): number => {
return ( return (
tree.child_nodes.length + tree.child_nodes.length +
@ -128,4 +130,7 @@
{/each} {/each}
</ThreadWrapper> </ThreadWrapper>
{/each} {/each}
{#if show_compose}
<ComposeReply {type} reply_to_event_id={tree.event.id} />
{/if}
</ThreadWrapper> </ThreadWrapper>

Loading…
Cancel
Save