You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
93 lines
3.2 KiB
93 lines
3.2 KiB
<script lang="ts"> |
|
import type { NDKEvent } from '@nostr-dev-kit/ndk' |
|
import { writable } from 'svelte/store' |
|
import type { ThreadTreeNode } from '$lib/components/events/type' |
|
import ThreadTree from './ThreadTree.svelte' |
|
|
|
export let event: NDKEvent |
|
export let type: 'proposal' | 'issue' = 'proposal' |
|
export let show_compose = true |
|
|
|
export let replies: NDKEvent[] | undefined = undefined |
|
|
|
const getParentId = (reply: NDKEvent): string | undefined => { |
|
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 |
|
} |
|
|
|
const createThreadTree = (replies: NDKEvent[]): ThreadTreeNode[] => { |
|
const hashTable: { [key: string]: ThreadTreeNode } = Object.create(null) |
|
replies.forEach( |
|
(reply) => (hashTable[reply.id] = { event: reply, child_nodes: [] }) |
|
) |
|
const thread_tree: ThreadTreeNode[] = [] |
|
replies.forEach((reply) => { |
|
let reply_parent_id = getParentId(reply) |
|
if (reply_parent_id && hashTable[reply_parent_id]) { |
|
hashTable[reply_parent_id].child_nodes.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 |
|
} |
|
|
|
const splitIntoRevisionThreadTrees = ( |
|
tree: ThreadTreeNode |
|
): ThreadTreeNode[] => { |
|
let thread_revision_trees: ThreadTreeNode[] = [ |
|
{ |
|
...tree, |
|
child_nodes: [...tree?.child_nodes], |
|
}, |
|
] |
|
thread_revision_trees[0].child_nodes = |
|
thread_revision_trees[0].child_nodes.filter((n) => { |
|
if ( |
|
n.event.tags.some((t) => t.length > 1 && t[1] === 'revision-root') |
|
) { |
|
thread_revision_trees.push(n) |
|
return false |
|
} |
|
return true |
|
}) |
|
return thread_revision_trees.sort( |
|
(a, b) => (a.event.created_at || 0) - (b.event.created_at || 0) |
|
) |
|
} |
|
|
|
let thread_tree_store = writable( |
|
createThreadTree(replies ? [event, ...replies] : [event]) |
|
) |
|
let thread_tree_root: ThreadTreeNode | undefined |
|
let thread_revision_trees: 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([event, ...replies])) |
|
thread_tree_root = $thread_tree_store.find((t) => t.event.id === event.id) |
|
if (type === 'proposal' && thread_tree_root) |
|
thread_revision_trees = splitIntoRevisionThreadTrees(thread_tree_root) |
|
} |
|
</script> |
|
|
|
{#if type === 'issue' && thread_tree_root} |
|
<ThreadTree {type} tree={thread_tree_root} {show_compose} /> |
|
{/if} |
|
{#if thread_revision_trees} |
|
{#each thread_revision_trees as tree, i} |
|
{#if i > 0} |
|
<div class="divider">new revision</div> |
|
{/if} |
|
<ThreadTree |
|
{type} |
|
{tree} |
|
show_compose={show_compose && thread_revision_trees.length - 1 === i} |
|
/> |
|
{/each} |
|
{/if}
|
|
|