forked from coracle/flotilla
Rough out fetching DMs
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
import SecondaryNavItem from "@lib/components/SecondaryNavItem.svelte"
|
||||
import SecondaryNavHeader from "@lib/components/SecondaryNavHeader.svelte"
|
||||
import SecondaryNavSection from "@lib/components/SecondaryNavSection.svelte"
|
||||
import {channels} from '@app/state'
|
||||
</script>
|
||||
|
||||
<SecondaryNav>
|
||||
@@ -21,6 +22,11 @@
|
||||
</SecondaryNavItem>
|
||||
</div>
|
||||
<div in:fly={{delay: 100}}>
|
||||
<SecondaryNavItem href="/home/notes">
|
||||
<Icon icon="notes-minimalistic" /> Notes
|
||||
</SecondaryNavItem>
|
||||
</div>
|
||||
<div in:fly={{delay: 150}}>
|
||||
<SecondaryNavHeader>
|
||||
Chats
|
||||
<div class="cursor-pointer">
|
||||
@@ -28,6 +34,13 @@
|
||||
</div>
|
||||
</SecondaryNavHeader>
|
||||
</div>
|
||||
{#each $channels as {id, pubkeys}, i (id)}
|
||||
<div in:fly={{delay: 200 + i * 50}}>
|
||||
<SecondaryNavItem href="/home/{id}">
|
||||
{id}
|
||||
</SecondaryNavItem>
|
||||
</div>
|
||||
{/each}
|
||||
</SecondaryNavSection>
|
||||
</SecondaryNav>
|
||||
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
const createSpace = () => pushModal(SpaceCreateExternal)
|
||||
|
||||
const browseSpaces = () => goto("/discover")
|
||||
|
||||
const leaveFeedback = () => goto("/home/97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322")
|
||||
|
||||
const donate = () => window.open('https://geyser.fund/project/flotilla')
|
||||
</script>
|
||||
|
||||
<div class="hero min-h-screen bg-base-200">
|
||||
@@ -21,10 +25,10 @@
|
||||
<CardButton icon="compass" title="Discover spaces" class="h-24" on:click={browseSpaces}>
|
||||
Find a community based on your hobbies or interests.
|
||||
</CardButton>
|
||||
<CardButton icon="plain" title="Leave feedback" class="h-24">
|
||||
<CardButton icon="plain" title="Leave feedback" class="h-24" on:click={leaveFeedback}>
|
||||
Let us know how we can improve by giving us feedback.
|
||||
</CardButton>
|
||||
<CardButton icon="hand-pills" title="Donate to Flotilla" class="h-24">
|
||||
<CardButton icon="hand-pills" title="Donate to Flotilla" class="h-24" on:click={donate}>
|
||||
Support the project by donating to the developer.
|
||||
</CardButton>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<script lang="ts">
|
||||
import {onMount} from 'svelte'
|
||||
import {derived} from 'svelte/store'
|
||||
import {createScroller} from '@lib/html'
|
||||
import {shuffle, sortBy, sleep, ago, DAY, HOUR, pushToMapKey} from '@welshman/lib'
|
||||
import {getListValues, getAncestorTagValues, NOTE, REACTION} from '@welshman/util'
|
||||
import type {TrustedEvent} from '@welshman/util'
|
||||
import {deriveEvents} from '@welshman/store'
|
||||
import {profileSearch, repository, userFollows, load} from '@welshman/app'
|
||||
import Spinner from '@lib/components/Spinner.svelte'
|
||||
import NoteCard from '@app/components/NoteCard.svelte'
|
||||
import Content from '@app/components/Content.svelte'
|
||||
|
||||
let element: Element
|
||||
let loading = sleep(3000)
|
||||
let events: TrustedEvent[] = []
|
||||
|
||||
const since = ago(DAY)
|
||||
const authors = getListValues("p", $userFollows)
|
||||
const notesFilter = {kinds: [NOTE], authors, since}
|
||||
const notes = deriveEvents(repository, {filters: [notesFilter]})
|
||||
const reactionsFilter = {kinds: [REACTION], '#p': authors, since}
|
||||
const reactions = deriveEvents(repository, {filters: [reactionsFilter]})
|
||||
const reactionsByParent = derived(
|
||||
reactions,
|
||||
$reactions => {
|
||||
const $reactionsByParent = new Map<string, TrustedEvent[]>()
|
||||
|
||||
for (const event of $reactions) {
|
||||
const [parentId] = getAncestorTagValues(event.tags).replies
|
||||
|
||||
if (parentId) {
|
||||
pushToMapKey($reactionsByParent, parentId, event)
|
||||
}
|
||||
}
|
||||
|
||||
return $reactionsByParent
|
||||
}
|
||||
)
|
||||
|
||||
const isLike = (e: TrustedEvent) =>
|
||||
e.kind === REACTION && ["+", ""].includes(e.content)
|
||||
|
||||
const isReplyOf = (e: TrustedEvent, p: TrustedEvent) =>
|
||||
getAncestorTagValues(e.tags).replies.includes(e.id)
|
||||
|
||||
const scoreEvent = (e: TrustedEvent) => {
|
||||
const thisReactions = $reactionsByParent.get(e.id) || []
|
||||
const thisLikes = thisReactions.filter(r => isLike(r))
|
||||
const recency = Math.max(1, e.created_at - since) / HOUR
|
||||
const score = Math.max(1, thisReactions.length) * Math.max(1, thisLikes.length) * recency
|
||||
|
||||
return -score
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
load({filters: [notesFilter, reactionsFilter]})
|
||||
|
||||
const scroller = createScroller({
|
||||
element: element.closest('.max-h-screen')!,
|
||||
onScroll: () => {
|
||||
const seen = new Set(events.map(e => e.id))
|
||||
const eligible = sortBy(
|
||||
scoreEvent,
|
||||
$notes.filter(e => !seen.has(e.id) && getAncestorTagValues(e.tags).replies.length === 0)
|
||||
)
|
||||
|
||||
events = [...events, ...eligible.slice(0, 10)]
|
||||
},
|
||||
})
|
||||
|
||||
return () => scroller.stop()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
<div class="content column gap-4" bind:this={element}>
|
||||
{#await loading}
|
||||
<div class="center my-20">
|
||||
<Spinner loading>Loading notes...</Spinner>
|
||||
</div>
|
||||
{:then}
|
||||
<div class="flex flex-col gap-2">
|
||||
{#each events as event (event.id)}
|
||||
<NoteCard {event} class="card2 w-full">
|
||||
<div class="ml-12">
|
||||
<Content {event} />
|
||||
</div>
|
||||
</NoteCard>
|
||||
{/each}
|
||||
</div>
|
||||
{/await}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user