forked from coracle/flotilla
Continue working on feed page
This commit is contained in:
@@ -1,131 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import {insertAt, lt, addToMapKey, parseJson} from "@welshman/lib"
|
|
||||||
import type {TrustedEvent} from "@welshman/util"
|
|
||||||
import {Router, addMaximalFallbacks} from "@welshman/router"
|
|
||||||
import {load} from "@welshman/net"
|
|
||||||
import {
|
|
||||||
getIdOrAddress,
|
|
||||||
getIdFilters,
|
|
||||||
getParentIdsAndAddrs,
|
|
||||||
getParentIdOrAddr,
|
|
||||||
verifyEvent,
|
|
||||||
ZAP_RESPONSE,
|
|
||||||
} from "@welshman/util"
|
|
||||||
import {repository, getValidZap} from "@welshman/app"
|
|
||||||
import {REPOST_KINDS, REACTION_KINDS, isEventMuted} from '@app/core/state'
|
|
||||||
|
|
||||||
export let events: TrustedEvent[]
|
|
||||||
export let depth = 0
|
|
||||||
export let showMuted = false
|
|
||||||
export let hideReplies = false
|
|
||||||
export let showDeleted = false
|
|
||||||
export let shouldSort = false
|
|
||||||
export let shouldAwait = false
|
|
||||||
export let items: TrustedEvent[] = []
|
|
||||||
|
|
||||||
const timestamps = new Map<string, number>()
|
|
||||||
const context = new Map<string, Set<TrustedEvent>>()
|
|
||||||
|
|
||||||
const shouldSkip = (event: TrustedEvent) => {
|
|
||||||
if (!showMuted && $isEventMuted(event)) return true
|
|
||||||
if (!showDeleted && repository.isDeleted(event)) return true
|
|
||||||
if (hideReplies && getParentIdOrAddr(event)) return true
|
|
||||||
if (timestamps.has(getIdOrAddress(event))) return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const getParent = async (event: TrustedEvent) => {
|
|
||||||
if (REPOST_KINDS.includes(event.kind)) {
|
|
||||||
const parent = parseJson(event.content)
|
|
||||||
|
|
||||||
if (parent && verifyEvent(parent)) {
|
|
||||||
return parent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const parentIds = getParentIdsAndAddrs(event)
|
|
||||||
|
|
||||||
if (parentIds.length > 0) {
|
|
||||||
const filters = getIdFilters(parentIds)
|
|
||||||
const [cached] = repository.query(filters)
|
|
||||||
|
|
||||||
if (cached) return cached
|
|
||||||
|
|
||||||
const relays = Router.get().EventParents(event).policy(addMaximalFallbacks).getUrls()
|
|
||||||
const [parent] = await load({filters, relays})
|
|
||||||
|
|
||||||
return parent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const addEvent = async (event: TrustedEvent) => {
|
|
||||||
const original = event
|
|
||||||
let currentDepth = depth
|
|
||||||
|
|
||||||
timestamps.set(getIdOrAddress(event), original.created_at)
|
|
||||||
|
|
||||||
while (currentDepth > 0) {
|
|
||||||
const parent = await getParent(event)
|
|
||||||
|
|
||||||
// Unable to get the parent? we're done traversing parents
|
|
||||||
if (!parent) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip zaps that fail our zapper check
|
|
||||||
if (event.kind === ZAP_RESPONSE && !(await getValidZap(event, parent))) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link the events, even if we end up skipping this one (since we deduplicate)
|
|
||||||
addToMapKey(context, getIdOrAddress(parent), event)
|
|
||||||
|
|
||||||
// Hide replies to deleted/muted parents, or parents we've already seen
|
|
||||||
if (shouldSkip(parent)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
timestamps.set(getIdOrAddress(parent), original.created_at)
|
|
||||||
currentDepth--
|
|
||||||
event = parent
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it's not displayable, skip it
|
|
||||||
if ([...REPOST_KINDS, ...REACTION_KINDS].includes(event.kind)) return
|
|
||||||
|
|
||||||
let inserted = false
|
|
||||||
|
|
||||||
if (shouldSort) {
|
|
||||||
for (let i = 0; i < items.length; i++) {
|
|
||||||
if (lt(timestamps.get(getIdOrAddress(items[i])), original.created_at)) {
|
|
||||||
items = insertAt(i, event, items)
|
|
||||||
inserted = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!inserted) {
|
|
||||||
items = [...items, event]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const addEvents = async (events: TrustedEvent[]) => {
|
|
||||||
for (const event of events) {
|
|
||||||
if (!shouldSkip(event)) {
|
|
||||||
const promise = addEvent(event)
|
|
||||||
|
|
||||||
if (shouldAwait) {
|
|
||||||
await promise
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$: addEvents(events)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#each items as event, i (event.id)}
|
|
||||||
{@render children({i, event})}
|
|
||||||
{/each}
|
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
import GoalItem from "@app/components/GoalItem.svelte"
|
import GoalItem from "@app/components/GoalItem.svelte"
|
||||||
import CalendarEventItem from "@app/components/CalendarEventItem.svelte"
|
import CalendarEventItem from "@app/components/CalendarEventItem.svelte"
|
||||||
import RecentConversation from "@app/components/RecentConversation.svelte"
|
import RecentConversation from "@app/components/RecentConversation.svelte"
|
||||||
import {makeRoomId, userSpaceUrls, loadUserGroupList, CONTENT_KINDS} from "@app/core/state"
|
import {makeRoomId, userSpaceUrls, loadUserGroupList, isEventMuted, CONTENT_KINDS} from "@app/core/state"
|
||||||
|
|
||||||
type Activity = {
|
type Activity = {
|
||||||
type: "message" | "content"
|
type: "message" | "content"
|
||||||
@@ -130,7 +130,14 @@
|
|||||||
makeIntersectionFeed(makeScopeFeed(Scope.Follows), makeKindFeed(NOTE)),
|
makeIntersectionFeed(makeScopeFeed(Scope.Follows), makeKindFeed(NOTE)),
|
||||||
),
|
),
|
||||||
onEvent: batch(100, (evts: TrustedEvent[]) => {
|
onEvent: batch(100, (evts: TrustedEvent[]) => {
|
||||||
events.update($events => [...$events, ...evts.filter(e => !getParentIdOrAddr(e))])
|
const keep = evts.filter(event => {
|
||||||
|
if ($isEventMuted(event)) return false
|
||||||
|
if (getParentIdOrAddr(event)) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
events.update($events => [...$events, ...keep])
|
||||||
}),
|
}),
|
||||||
onExhausted: () => {
|
onExhausted: () => {
|
||||||
loading = false
|
loading = false
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type {Snippet} from "svelte"
|
||||||
|
import {page} from "$app/stores"
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
children: Snippet
|
||||||
|
}
|
||||||
|
|
||||||
|
const {children}: Props = $props()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#key $page.params.addres}
|
||||||
|
{@render children()}
|
||||||
|
{/key}
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
import {deriveFeed} from "@app/core/state"
|
import {deriveFeed} from "@app/core/state"
|
||||||
|
|
||||||
const {address} = $page.params as MakeNonOptional<typeof $page.params>
|
const {address} = $page.params as MakeNonOptional<typeof $page.params>
|
||||||
|
console.log(address)
|
||||||
const events = writable<TrustedEvent[]>([])
|
const events = writable<TrustedEvent[]>([])
|
||||||
const controller = new AbortController()
|
const controller = new AbortController()
|
||||||
const feed = deriveFeed(address)
|
const feed = deriveFeed(address)
|
||||||
|
|||||||
Reference in New Issue
Block a user