Coves frontend - a photon fork
1<script lang="ts">
2 import type { StrongRef } from '$lib/api/coves/types'
3 import type { DID } from '$lib/types/atproto'
4 import VirtualList from '$lib/app/render/VirtualList.svelte'
5 import { onMount } from 'svelte'
6 import { expoOut } from 'svelte/easing'
7 import { fly } from 'svelte/transition'
8 import type { CommentNodeI } from './comments.svelte'
9 import CommentTree from './CommentTree.svelte'
10
11 interface Props {
12 nodes: CommentNodeI[]
13 postRef: StrongRef
14 postAuthorDid?: DID
15 scrollTo?: string
16 }
17
18 onMount(() => {
19 if (scrollTo) {
20 const element = document?.getElementById(scrollTo)
21 setTimeout(() => {
22 element?.scrollIntoView({ behavior: 'smooth', block: 'start' })
23 }, 100)
24 }
25
26 const observer = new ResizeObserver((entries) => {
27 entries.forEach((entry) => {
28 if (offsetEl) {
29 initialOffset =
30 entry.target.getBoundingClientRect().top + window.scrollY
31 }
32 })
33 })
34
35 if (offsetEl) observer.observe(offsetEl)
36 return () => observer.disconnect()
37 })
38
39 let { nodes, postRef, postAuthorDid, scrollTo }: Props = $props()
40
41 let offsetEl = $state<HTMLElement>()
42 let initialOffset = $state<number | undefined>(undefined)
43
44 $effect(() => {
45 if (offsetEl) {
46 initialOffset = offsetEl.offsetTop
47 }
48 })
49</script>
50
51<div bind:this={offsetEl}>
52 {#if offsetEl}
53 <VirtualList
54 class="divide-y-2 divide-slate-100 dark:divide-zinc-900 -mx-3 sm:-mx-6"
55 overscan={5}
56 estimatedHeight={500}
57 items={nodes}
58 {initialOffset}
59 >
60 {#snippet item(row)}
61 <div
62 in:fly={row < 7
63 ? { duration: 800, easing: expoOut, y: 12, delay: row * 50 }
64 : { opacity: 1, duration: 0 }}
65 class="px-3 sm:px-6"
66 >
67 <CommentTree
68 bind:nodes={() => [nodes[row]], (v) => (nodes[row] = v[0])}
69 {postRef}
70 {postAuthorDid}
71 />
72 </div>
73 {/snippet}
74 </VirtualList>
75 {/if}
76</div>