Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fdb604e350 | |||
| 3c66dfd83c | |||
| 81633b0a1e | |||
| 4a967de184 | |||
| 59961cbdb5 |
@@ -42,7 +42,7 @@
|
|||||||
let popover: Instance | undefined = $state()
|
let popover: Instance | undefined = $state()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Button class="join rounded-full">
|
<div class="join items-center rounded-full">
|
||||||
{#if ENABLE_ZAPS && !hideZap}
|
{#if ENABLE_ZAPS && !hideZap}
|
||||||
<ZapButton {url} {event} class="btn join-item btn-neutral btn-xs">
|
<ZapButton {url} {event} class="btn join-item btn-neutral btn-xs">
|
||||||
<Icon icon={Bolt} size={4} />
|
<Icon icon={Bolt} size={4} />
|
||||||
@@ -52,6 +52,7 @@
|
|||||||
<Icon icon={SmileCircle} size={4} />
|
<Icon icon={SmileCircle} size={4} />
|
||||||
</EmojiButton>
|
</EmojiButton>
|
||||||
<Tippy
|
<Tippy
|
||||||
|
class="flex"
|
||||||
bind:popover
|
bind:popover
|
||||||
component={EventMenu}
|
component={EventMenu}
|
||||||
props={{url, noun, event, customActions, onClick: hidePopover}}
|
props={{url, noun, event, customActions, onClick: hidePopover}}
|
||||||
@@ -60,4 +61,4 @@
|
|||||||
<Icon icon={MenuDots} size={4} />
|
<Icon icon={MenuDots} size={4} />
|
||||||
</Button>
|
</Button>
|
||||||
</Tippy>
|
</Tippy>
|
||||||
</Button>
|
</div>
|
||||||
|
|||||||
@@ -90,7 +90,7 @@
|
|||||||
{#snippet input()}
|
{#snippet input()}
|
||||||
<label class="input input-bordered flex w-full items-center gap-2">
|
<label class="input input-bordered flex w-full items-center gap-2">
|
||||||
<Icon icon={Letter} />
|
<Icon icon={Letter} />
|
||||||
<input bind:value={email} />
|
<input type="email" bind:value={email} />
|
||||||
</label>
|
</label>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</FieldInline>
|
</FieldInline>
|
||||||
|
|||||||
@@ -61,7 +61,7 @@
|
|||||||
{#snippet input()}
|
{#snippet input()}
|
||||||
<label class="input input-bordered flex w-full items-center gap-2">
|
<label class="input input-bordered flex w-full items-center gap-2">
|
||||||
<Icon icon={Letter} />
|
<Icon icon={Letter} />
|
||||||
<input bind:value={email} />
|
<input type="email" bind:value={email} />
|
||||||
</label>
|
</label>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</FieldInline>
|
</FieldInline>
|
||||||
|
|||||||
@@ -120,7 +120,7 @@
|
|||||||
{#snippet input()}
|
{#snippet input()}
|
||||||
<label class="input input-bordered flex w-full items-center gap-2">
|
<label class="input input-bordered flex w-full items-center gap-2">
|
||||||
<Icon icon={Letter} />
|
<Icon icon={Letter} />
|
||||||
<input bind:value={email} />
|
<input type="email" bind:value={email} />
|
||||||
</label>
|
</label>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</FieldInline>
|
</FieldInline>
|
||||||
|
|||||||
@@ -25,6 +25,16 @@
|
|||||||
const {url} = $props()
|
const {url} = $props()
|
||||||
|
|
||||||
const authError = deriveRelayAuthError(url)
|
const authError = deriveRelayAuthError(url)
|
||||||
|
let networkError = $state(false)
|
||||||
|
const isExplicitAuthError = $derived(
|
||||||
|
$authError &&
|
||||||
|
!(
|
||||||
|
$authError.toLowerCase().includes("failed") ||
|
||||||
|
$authError.toLowerCase().includes("timeout") ||
|
||||||
|
$authError.toLowerCase().includes("network")
|
||||||
|
),
|
||||||
|
)
|
||||||
|
const isGenericError = $derived(networkError || ($authError && !isExplicitAuthError))
|
||||||
|
|
||||||
const back = () => history.back()
|
const back = () => history.back()
|
||||||
const copyInvite = () => clip(invite)
|
const copyInvite = () => clip(invite)
|
||||||
@@ -70,8 +80,14 @@
|
|||||||
])
|
])
|
||||||
|
|
||||||
claim = getTagValue("claim", event?.tags || []) || ""
|
claim = getTagValue("claim", event?.tags || []) || ""
|
||||||
} catch {
|
} catch (err) {
|
||||||
claim = ""
|
claim = ""
|
||||||
|
if (
|
||||||
|
(err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError")) ||
|
||||||
|
!navigator.onLine
|
||||||
|
) {
|
||||||
|
networkError = true
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
loading = false
|
loading = false
|
||||||
}
|
}
|
||||||
@@ -92,7 +108,11 @@
|
|||||||
<p class="center">
|
<p class="center">
|
||||||
<Spinner {loading}>Requesting an invite link...</Spinner>
|
<Spinner {loading}>Requesting an invite link...</Spinner>
|
||||||
</p>
|
</p>
|
||||||
{:else if $authError}
|
{:else if isGenericError}
|
||||||
|
<p class="center text-center">
|
||||||
|
Unable to reach the relay. Please check your connection and try again.
|
||||||
|
</p>
|
||||||
|
{:else if isExplicitAuthError}
|
||||||
<p class="center">Oops! It looks like you're not a member of this relay.</p>
|
<p class="center">Oops! It looks like you're not a member of this relay.</p>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex flex-col items-center gap-6">
|
<div class="flex flex-col items-center gap-6">
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if Array.isArray(supported_nips)}
|
{#if Array.isArray(supported_nips)}
|
||||||
<p class="badge badge-neutral">
|
<p class="badge badge-neutral text-wrap h-auto">
|
||||||
<span class="ellipsize">Supported NIPs: {supported_nips.join(", ")}</span>
|
<span class="ellipsize">Supported NIPs: {supported_nips.join(", ")}</span>
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
<svelte:document onmousemove={onMouseMove} />
|
<svelte:document onmousemove={onMouseMove} />
|
||||||
|
|
||||||
<Tippy
|
<Tippy
|
||||||
|
class="flex"
|
||||||
bind:popover
|
bind:popover
|
||||||
component={EmojiPicker}
|
component={EmojiPicker}
|
||||||
props={{onClick}}
|
props={{onClick}}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
import {page} from "$app/stores"
|
import {page} from "$app/stores"
|
||||||
import {goto} from "$app/navigation"
|
import {goto} from "$app/navigation"
|
||||||
import type {Readable} from "svelte/store"
|
import type {Readable} from "svelte/store"
|
||||||
|
import {debounce} from "throttle-debounce"
|
||||||
import {pubkey, publishThunk, waitForThunkError, joinRoom, leaveRoom} from "@welshman/app"
|
import {pubkey, publishThunk, waitForThunkError, joinRoom, leaveRoom} from "@welshman/app"
|
||||||
import {now, ifLet, int, formatTimestampAsDate, ago, MINUTE} from "@welshman/lib"
|
import {now, ifLet, int, formatTimestampAsDate, ago, MINUTE} from "@welshman/lib"
|
||||||
import type {MakeNonOptional} from "@welshman/lib"
|
import type {MakeNonOptional} from "@welshman/lib"
|
||||||
@@ -244,6 +245,8 @@
|
|||||||
const onScroll = () => {
|
const onScroll = () => {
|
||||||
if (!isProgrammaticScroll) {
|
if (!isProgrammaticScroll) {
|
||||||
userHasScrolled = true
|
userHasScrolled = true
|
||||||
|
isUserScrolling = true
|
||||||
|
clearIsUserScrolling()
|
||||||
manageScrollPosition()
|
manageScrollPosition()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,6 +268,7 @@
|
|||||||
let leaving = $state(false)
|
let leaving = $state(false)
|
||||||
let userHasScrolled = $state(false)
|
let userHasScrolled = $state(false)
|
||||||
let isProgrammaticScroll = $state(false)
|
let isProgrammaticScroll = $state(false)
|
||||||
|
let isUserScrolling = $state(false)
|
||||||
let loadingBackward = $state(true)
|
let loadingBackward = $state(true)
|
||||||
let loadingForward = $state(true)
|
let loadingForward = $state(true)
|
||||||
let share = $state(popKey<TrustedEvent | undefined>("share"))
|
let share = $state(popKey<TrustedEvent | undefined>("share"))
|
||||||
@@ -278,6 +282,10 @@
|
|||||||
let compose: RoomCompose | undefined = $state()
|
let compose: RoomCompose | undefined = $state()
|
||||||
let eventToEdit: TrustedEvent | undefined = $state()
|
let eventToEdit: TrustedEvent | undefined = $state()
|
||||||
|
|
||||||
|
const clearIsUserScrolling = debounce(150, () => {
|
||||||
|
isUserScrolling = false
|
||||||
|
})
|
||||||
|
|
||||||
const elements = $derived.by(() => {
|
const elements = $derived.by(() => {
|
||||||
const elements = []
|
const elements = []
|
||||||
const seen = new Set()
|
const seen = new Set()
|
||||||
@@ -351,7 +359,7 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (elements.length > 0) {
|
if (elements.length > 0 && !isUserScrolling) {
|
||||||
requestAnimationFrame(manageScrollPosition)
|
requestAnimationFrame(manageScrollPosition)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
import {goto} from "$app/navigation"
|
import {goto} from "$app/navigation"
|
||||||
import type {Readable} from "svelte/store"
|
import type {Readable} from "svelte/store"
|
||||||
import {readable} from "svelte/store"
|
import {readable} from "svelte/store"
|
||||||
|
import {debounce} from "throttle-debounce"
|
||||||
import {now, int, ifLet, formatTimestampAsDate, MINUTE, ago} from "@welshman/lib"
|
import {now, int, ifLet, formatTimestampAsDate, MINUTE, ago} from "@welshman/lib"
|
||||||
import type {TrustedEvent, EventContent} from "@welshman/util"
|
import type {TrustedEvent, EventContent} from "@welshman/util"
|
||||||
import {makeEvent, MESSAGE, RELAY_ADD_MEMBER} from "@welshman/util"
|
import {makeEvent, MESSAGE, RELAY_ADD_MEMBER} from "@welshman/util"
|
||||||
@@ -139,6 +140,8 @@
|
|||||||
const onScroll = () => {
|
const onScroll = () => {
|
||||||
if (!isProgrammaticScroll) {
|
if (!isProgrammaticScroll) {
|
||||||
userHasScrolled = true
|
userHasScrolled = true
|
||||||
|
isUserScrolling = true
|
||||||
|
clearIsUserScrolling()
|
||||||
manageScrollPosition()
|
manageScrollPosition()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,6 +163,7 @@
|
|||||||
let loadingForward = $state(true)
|
let loadingForward = $state(true)
|
||||||
let userHasScrolled = $state(false)
|
let userHasScrolled = $state(false)
|
||||||
let isProgrammaticScroll = $state(false)
|
let isProgrammaticScroll = $state(false)
|
||||||
|
let isUserScrolling = $state(false)
|
||||||
let share = $state(popKey<TrustedEvent | undefined>("share"))
|
let share = $state(popKey<TrustedEvent | undefined>("share"))
|
||||||
let parent: TrustedEvent | undefined = $state()
|
let parent: TrustedEvent | undefined = $state()
|
||||||
let element: HTMLElement | undefined = $state()
|
let element: HTMLElement | undefined = $state()
|
||||||
@@ -171,6 +175,10 @@
|
|||||||
let compose: RoomCompose | undefined = $state()
|
let compose: RoomCompose | undefined = $state()
|
||||||
let eventToEdit: TrustedEvent | undefined = $state()
|
let eventToEdit: TrustedEvent | undefined = $state()
|
||||||
|
|
||||||
|
const clearIsUserScrolling = debounce(150, () => {
|
||||||
|
isUserScrolling = false
|
||||||
|
})
|
||||||
|
|
||||||
const elements = $derived.by(() => {
|
const elements = $derived.by(() => {
|
||||||
const elements = []
|
const elements = []
|
||||||
const seen = new Set()
|
const seen = new Set()
|
||||||
@@ -244,7 +252,7 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (elements.length > 0) {
|
if (elements.length > 0 && !isUserScrolling) {
|
||||||
requestAnimationFrame(manageScrollPosition)
|
requestAnimationFrame(manageScrollPosition)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user