Migrate more stuff
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
<script lang="ts">
|
||||
import {page} from "$app/stores"
|
||||
interface Props {
|
||||
children?: import("svelte").Snippet
|
||||
}
|
||||
|
||||
let {children}: Props = $props()
|
||||
</script>
|
||||
|
||||
{#key $page.params.relay}
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
{/key}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import {run} from "svelte/legacy"
|
||||
|
||||
import {onMount} from "svelte"
|
||||
import {page} from "$app/stores"
|
||||
import {ago, MONTH} from "@welshman/lib"
|
||||
@@ -15,6 +17,11 @@
|
||||
import {decodeRelay, userRoomsByUrl} from "@app/state"
|
||||
import {pullConservatively} from "@app/requests"
|
||||
import {notifications} from "@app/notifications"
|
||||
interface Props {
|
||||
children?: import("svelte").Snippet
|
||||
}
|
||||
|
||||
let {children}: Props = $props()
|
||||
|
||||
const url = decodeRelay($page.params.relay)
|
||||
|
||||
@@ -37,11 +44,11 @@
|
||||
}
|
||||
|
||||
// We have to watch this one, since on mobile the badge will be visible when active
|
||||
$: {
|
||||
run(() => {
|
||||
if ($notifications.has($page.url.pathname)) {
|
||||
setChecked($page.url.pathname)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
onMount(() => {
|
||||
checkConnection()
|
||||
@@ -77,6 +84,6 @@
|
||||
</SecondaryNav>
|
||||
<Page>
|
||||
{#key $page.url.pathname}
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
{/key}
|
||||
</Page>
|
||||
|
||||
@@ -39,31 +39,37 @@
|
||||
|
||||
const addRoom = () => pushModal(RoomCreate, {url})
|
||||
|
||||
let relayAdminEvents: TrustedEvent[] = []
|
||||
let relayAdminEvents: TrustedEvent[] = $state([])
|
||||
|
||||
$: pubkey = $relay?.profile?.pubkey
|
||||
let pubkey = $derived($relay?.profile?.pubkey)
|
||||
</script>
|
||||
|
||||
<div class="relative flex flex-col">
|
||||
<PageBar>
|
||||
<div slot="icon" class="center">
|
||||
<Icon icon="home-smile" />
|
||||
</div>
|
||||
<strong slot="title">Home</strong>
|
||||
<div slot="action" class="row-2">
|
||||
{#if !$userRoomsByUrl.has(url)}
|
||||
<Button class="btn btn-primary btn-sm" on:click={joinSpace}>
|
||||
<Icon icon="login-2" />
|
||||
Join Space
|
||||
</Button>
|
||||
{:else if pubkey}
|
||||
<Link class="btn btn-primary btn-sm" href={makeChatPath([pubkey])}>
|
||||
<Icon icon="letter" />
|
||||
Contact Owner
|
||||
</Link>
|
||||
{/if}
|
||||
<MenuSpaceButton {url} />
|
||||
</div>
|
||||
{#snippet icon()}
|
||||
<div class="center">
|
||||
<Icon icon="home-smile" />
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet title()}
|
||||
<strong>Home</strong>
|
||||
{/snippet}
|
||||
{#snippet action()}
|
||||
<div class="row-2">
|
||||
{#if !$userRoomsByUrl.has(url)}
|
||||
<Button class="btn btn-primary btn-sm" on:click={joinSpace}>
|
||||
<Icon icon="login-2" />
|
||||
Join Space
|
||||
</Button>
|
||||
{:else if pubkey}
|
||||
<Link class="btn btn-primary btn-sm" href={makeChatPath([pubkey])}>
|
||||
<Icon icon="letter" />
|
||||
Contact Owner
|
||||
</Link>
|
||||
{/if}
|
||||
<MenuSpaceButton {url} />
|
||||
</div>
|
||||
{/snippet}
|
||||
</PageBar>
|
||||
<div class="col-2 p-2">
|
||||
<div class="card2 bg-alt col-4 text-left">
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import {readable} from "svelte/store"
|
||||
import {onMount, onDestroy} from "svelte"
|
||||
import {page} from "$app/stores"
|
||||
import type {Readable} from "svelte/store"
|
||||
@@ -70,7 +71,7 @@
|
||||
|
||||
const replyTo = (event: TrustedEvent) => {
|
||||
parent = event
|
||||
compose.focus()
|
||||
compose?.focus()
|
||||
}
|
||||
|
||||
const clearParent = () => {
|
||||
@@ -107,25 +108,23 @@
|
||||
}
|
||||
|
||||
const scrollToNewMessages = () =>
|
||||
newMessages.scrollIntoView({behavior: "smooth", block: "center"})
|
||||
newMessages?.scrollIntoView({behavior: "smooth", block: "center"})
|
||||
|
||||
const scrollToBottom = () => element.scrollTo({top: 0, behavior: "smooth"})
|
||||
const scrollToBottom = () => element?.scrollTo({top: 0, behavior: "smooth"})
|
||||
|
||||
let parent: TrustedEvent | undefined
|
||||
let loading = true
|
||||
let element: HTMLElement
|
||||
let newMessages: HTMLElement
|
||||
let loading = $state(true)
|
||||
let parent: TrustedEvent | undefined = $state()
|
||||
let element: HTMLElement | undefined = $state()
|
||||
let newMessages: HTMLElement | undefined = $state()
|
||||
let newMessagesSeen = false
|
||||
let showFixedNewMessages = false
|
||||
let showScrollButton = false
|
||||
let showFixedNewMessages = $state(false)
|
||||
let showScrollButton = $state(false)
|
||||
let cleanup: () => void
|
||||
let events: Readable<TrustedEvent[]>
|
||||
let compose: ChannelCompose
|
||||
let elements: any[] = []
|
||||
|
||||
$: {
|
||||
elements = []
|
||||
let events: Readable<TrustedEvent[]> = $state(readable([]))
|
||||
let compose: ChannelCompose | undefined = $state()
|
||||
|
||||
const elements = $derived.by(() => {
|
||||
const elements = []
|
||||
const seen = new Set()
|
||||
|
||||
let previousDate
|
||||
@@ -170,11 +169,13 @@
|
||||
elements.reverse()
|
||||
|
||||
setTimeout(onScroll, 100)
|
||||
}
|
||||
|
||||
return elements
|
||||
})
|
||||
|
||||
onMount(() => {
|
||||
;({events, cleanup} = makeFeed({
|
||||
element,
|
||||
element: element!,
|
||||
relays: [url],
|
||||
feedFilters: [filter],
|
||||
subscriptionFilters: [{kinds: [DELETE, REACTION, MESSAGE], "#h": [room], since: now()}],
|
||||
@@ -193,32 +194,38 @@
|
||||
|
||||
<div class="saib relative flex h-full flex-col">
|
||||
<PageBar>
|
||||
<div slot="icon" class="center">
|
||||
<Icon icon="hashtag" />
|
||||
</div>
|
||||
<strong slot="title">
|
||||
<ChannelName {url} {room} />
|
||||
</strong>
|
||||
<div slot="action" class="row-2">
|
||||
{#if room !== GENERAL}
|
||||
{#if $userRoomsByUrl.get(url)?.has(room)}
|
||||
<Button class="btn btn-neutral btn-sm" on:click={leaveRoom}>
|
||||
<Icon icon="arrows-a-logout-2" />
|
||||
Leave Room
|
||||
</Button>
|
||||
{:else}
|
||||
<Button class="btn btn-neutral btn-sm" on:click={joinRoom}>
|
||||
<Icon icon="login-2" />
|
||||
Join Room
|
||||
</Button>
|
||||
{#snippet icon()}
|
||||
<div class="center">
|
||||
<Icon icon="hashtag" />
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet title()}
|
||||
<strong>
|
||||
<ChannelName {url} {room} />
|
||||
</strong>
|
||||
{/snippet}
|
||||
{#snippet action()}
|
||||
<div class="row-2">
|
||||
{#if room !== GENERAL}
|
||||
{#if $userRoomsByUrl.get(url)?.has(room)}
|
||||
<Button class="btn btn-neutral btn-sm" on:click={leaveRoom}>
|
||||
<Icon icon="arrows-a-logout-2" />
|
||||
Leave Room
|
||||
</Button>
|
||||
{:else}
|
||||
<Button class="btn btn-neutral btn-sm" on:click={joinRoom}>
|
||||
<Icon icon="login-2" />
|
||||
Join Room
|
||||
</Button>
|
||||
{/if}
|
||||
{/if}
|
||||
{/if}
|
||||
<MenuSpaceButton {url} />
|
||||
</div>
|
||||
<MenuSpaceButton {url} />
|
||||
</div>
|
||||
{/snippet}
|
||||
</PageBar>
|
||||
<div
|
||||
class="scroll-container -mt-2 flex flex-grow flex-col-reverse overflow-y-auto overflow-x-hidden py-2"
|
||||
on:scroll={onScroll}
|
||||
onscroll={onScroll}
|
||||
bind:this={element}>
|
||||
{#each elements as { type, id, value, showPubkey } (id)}
|
||||
{#if type === "new-messages"}
|
||||
|
||||
@@ -30,28 +30,30 @@
|
||||
parseInt(event.tags.find(t => t[0] === "start")?.[1] || "")
|
||||
|
||||
const limit = 5
|
||||
let loading = true
|
||||
let loading = $state(true)
|
||||
|
||||
type Item = {
|
||||
event: TrustedEvent
|
||||
dateDisplay?: string
|
||||
}
|
||||
|
||||
$: items = sortBy(e => -getStart(e), $events)
|
||||
.reduce<Item[]>((r, event) => {
|
||||
const end = getEnd(event)
|
||||
const start = getStart(event)
|
||||
let items = $derived(
|
||||
sortBy(e => -getStart(e), $events)
|
||||
.reduce<Item[]>((r, event) => {
|
||||
const end = getEnd(event)
|
||||
const start = getStart(event)
|
||||
|
||||
if (isNaN(start) || isNaN(end)) return r
|
||||
if (isNaN(start) || isNaN(end)) return r
|
||||
|
||||
const prevDateDisplay =
|
||||
r.length > 0 ? formatTimestampAsDate(getStart(last(r).event)) : undefined
|
||||
const newDateDisplay = formatTimestampAsDate(start)
|
||||
const dateDisplay = prevDateDisplay === newDateDisplay ? undefined : newDateDisplay
|
||||
const prevDateDisplay =
|
||||
r.length > 0 ? formatTimestampAsDate(getStart(last(r).event)) : undefined
|
||||
const newDateDisplay = formatTimestampAsDate(start)
|
||||
const dateDisplay = prevDateDisplay === newDateDisplay ? undefined : newDateDisplay
|
||||
|
||||
return [...r, {event, dateDisplay}]
|
||||
}, [])
|
||||
.slice(0, limit)
|
||||
return [...r, {event, dateDisplay}]
|
||||
}, [])
|
||||
.slice(0, limit),
|
||||
)
|
||||
|
||||
onMount(() => {
|
||||
const sub = subscribe({filters: [{kinds, since: ago(30)}]})
|
||||
@@ -72,13 +74,19 @@
|
||||
|
||||
<div class="relative flex h-screen flex-col">
|
||||
<PageBar>
|
||||
<div slot="icon" class="center">
|
||||
<Icon icon="calendar-minimalistic" />
|
||||
</div>
|
||||
<strong slot="title">Calendar</strong>
|
||||
<div slot="action" class="md:hidden">
|
||||
<MenuSpaceButton {url} />
|
||||
</div>
|
||||
{#snippet icon()}
|
||||
<div class="center">
|
||||
<Icon icon="calendar-minimalistic" />
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet title()}
|
||||
<strong>Calendar</strong>
|
||||
{/snippet}
|
||||
{#snippet action()}
|
||||
<div class="md:hidden">
|
||||
<MenuSpaceButton {url} />
|
||||
</div>
|
||||
{/snippet}
|
||||
</PageBar>
|
||||
<div class="flex flex-grow flex-col gap-2 overflow-auto p-2">
|
||||
{#each items as { event, dateDisplay }, i (event.id)}
|
||||
|
||||
@@ -59,32 +59,25 @@
|
||||
})
|
||||
|
||||
let limit = 10
|
||||
let loading = true
|
||||
let unmounted = false
|
||||
let element: Element
|
||||
let loading = $state(true)
|
||||
let element: Element | undefined = $state()
|
||||
let scroller: Scroller
|
||||
|
||||
onMount(() => {
|
||||
// Element is frequently not defined. I don't know why
|
||||
sleep(1000).then(() => {
|
||||
if (!unmounted) {
|
||||
scroller = createScroller({
|
||||
element,
|
||||
delay: 300,
|
||||
threshold: 3000,
|
||||
onScroll: () => {
|
||||
limit += 10
|
||||
scroller = createScroller({
|
||||
element: element!,
|
||||
delay: 300,
|
||||
threshold: 3000,
|
||||
onScroll: () => {
|
||||
limit += 10
|
||||
|
||||
if ($events.length - limit < 10) {
|
||||
ctrl.load(50)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
if ($events.length - limit < 10) {
|
||||
ctrl.load(50)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
return () => {
|
||||
unmounted = true
|
||||
scroller?.stop()
|
||||
setChecked($page.url.pathname)
|
||||
}
|
||||
@@ -93,17 +86,23 @@
|
||||
|
||||
<div class="relative flex h-screen flex-col" bind:this={element}>
|
||||
<PageBar>
|
||||
<div slot="icon" class="center">
|
||||
<Icon icon="notes-minimalistic" />
|
||||
</div>
|
||||
<strong slot="title">Threads</strong>
|
||||
<div slot="action" class="row-2">
|
||||
<Button class="btn btn-primary btn-sm" on:click={createThread}>
|
||||
{#snippet icon()}
|
||||
<div class="center">
|
||||
<Icon icon="notes-minimalistic" />
|
||||
Create a Thread
|
||||
</Button>
|
||||
<MenuSpaceButton {url} />
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet title()}
|
||||
<strong>Threads</strong>
|
||||
{/snippet}
|
||||
{#snippet action()}
|
||||
<div class="row-2">
|
||||
<Button class="btn btn-primary btn-sm" on:click={createThread}>
|
||||
<Icon icon="notes-minimalistic" />
|
||||
Create a Thread
|
||||
</Button>
|
||||
<MenuSpaceButton {url} />
|
||||
</div>
|
||||
{/snippet}
|
||||
</PageBar>
|
||||
<div class="flex flex-grow flex-col gap-2 overflow-auto p-2">
|
||||
{#each $events as event (event.id)}
|
||||
|
||||
@@ -37,10 +37,10 @@
|
||||
showAll = true
|
||||
}
|
||||
|
||||
let showAll = false
|
||||
let showReply = false
|
||||
let showAll = $state(false)
|
||||
let showReply = $state(false)
|
||||
|
||||
$: title = $event?.tags.find(nthEq(0, "title"))?.[1] || ""
|
||||
let title = $derived($event?.tags.find(nthEq(0, "title"))?.[1] || "")
|
||||
|
||||
onMount(() => {
|
||||
const sub = subscribe({relays: [url], filters})
|
||||
@@ -93,16 +93,22 @@
|
||||
{/await}
|
||||
{/if}
|
||||
<PageBar class="mx-0">
|
||||
<div slot="icon">
|
||||
<Button class="btn btn-neutral btn-sm" on:click={back}>
|
||||
<Icon icon="alt-arrow-left" />
|
||||
Go back
|
||||
</Button>
|
||||
</div>
|
||||
<h1 slot="title" class="text-xl">{title}</h1>
|
||||
<div slot="action">
|
||||
<MenuSpaceButton {url} />
|
||||
</div>
|
||||
{#snippet icon()}
|
||||
<div>
|
||||
<Button class="btn btn-neutral btn-sm" on:click={back}>
|
||||
<Icon icon="alt-arrow-left" />
|
||||
Go back
|
||||
</Button>
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet title()}
|
||||
<h1 class="text-xl">{title}</h1>
|
||||
{/snippet}
|
||||
{#snippet action()}
|
||||
<div>
|
||||
<MenuSpaceButton {url} />
|
||||
</div>
|
||||
{/snippet}
|
||||
</PageBar>
|
||||
</div>
|
||||
{#if showReply}
|
||||
|
||||
Reference in New Issue
Block a user