Improve permalinks
This commit is contained in:
parent
4b8fcdf196
commit
2b26c033f6
5 changed files with 26 additions and 27 deletions
|
|
@ -6,7 +6,7 @@
|
|||
import type {Readable} from "svelte/store"
|
||||
import {debounce} from "throttle-debounce"
|
||||
import cx from "classnames"
|
||||
import {now, ifLet, ago, MINUTE} from "@welshman/lib"
|
||||
import {now, ifLet, ago, spec, MINUTE} from "@welshman/lib"
|
||||
import type {Maybe} from "@welshman/lib"
|
||||
import type {TrustedEvent, EventContent} from "@welshman/util"
|
||||
import {relay, stamp, MESSAGE, RELAY_ADD_MEMBER, ROOM_ADD_MEMBER} from "@welshman/util"
|
||||
|
|
@ -47,7 +47,7 @@
|
|||
import {isFeedLoading, makeFeed, makeFeedContext, makeScrollLoader} from "@app/feeds"
|
||||
import {pageLoading} from "@app/loading"
|
||||
import {checked, deferredRoomPath, setChecked} from "@app/notifications"
|
||||
import {highlightedEvent, makeRoomPath} from "@app/routes"
|
||||
import {getPermalinkTarget, highlightedEvent, makeRoomPath} from "@app/routes"
|
||||
import {pendingShare, type Share} from "@app/share"
|
||||
import {pushToast} from "@app/toast"
|
||||
|
||||
|
|
@ -117,6 +117,7 @@
|
|||
: readable(MembershipStatus.Granted)
|
||||
const at = $derived(parseInt($page.url.searchParams.get("at")!))
|
||||
const inviteCode = $derived($page.url.searchParams.get("code") || "")
|
||||
const target = $derived(getPermalinkTarget($page.url))
|
||||
|
||||
const join = async () => {
|
||||
if (h) {
|
||||
|
|
@ -334,7 +335,9 @@
|
|||
}
|
||||
|
||||
if (!released && !pinned && !isNaN(at)) {
|
||||
const targetEvent = $events.find(event => event.created_at >= at)
|
||||
// The pointer only helps once that message has arrived, so the anchor still carries the jump.
|
||||
const pointedAt = target ? $events.find(spec({id: target})) : undefined
|
||||
const targetEvent = pointedAt ?? $events.find(event => event.created_at >= at)
|
||||
|
||||
if (targetEvent) {
|
||||
scrollToRow(targetEvent.id, {highlight: true, pin: true})
|
||||
|
|
@ -697,6 +700,8 @@
|
|||
<p class="flex h-10 items-center justify-center py-20">
|
||||
{#if reachedStartOfHistory}
|
||||
End of message history
|
||||
{:else}
|
||||
<Spinner loading>Looking for messages...</Spinner>
|
||||
{/if}
|
||||
</p>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import {get, writable} from "svelte/store"
|
||||
import * as nip19 from "nostr-tools/nip19"
|
||||
import {page} from "$app/stores"
|
||||
import {identity} from "@welshman/lib"
|
||||
import {identity, tryCatch} from "@welshman/lib"
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import {
|
||||
CLASSIFIED,
|
||||
|
|
@ -32,8 +32,7 @@ export let lastChatUrl: string | undefined = undefined
|
|||
|
||||
export const lastPageBySpaceUrl = new Map<string, string>()
|
||||
|
||||
// The event a link pointed at. A store rather than a class set on the node, because each row owns
|
||||
// its own class attribute and drops anything written behind its back on the next render.
|
||||
// A store rather than a class on the node, which each row's class attribute would overwrite.
|
||||
export const highlightedEvent = writable<string | undefined>(undefined)
|
||||
|
||||
// The space the user was in most recently, so the space menu can be opened from a page that isn't
|
||||
|
|
@ -237,7 +236,16 @@ export const makeEventPermalink = (event: TrustedEvent, url?: string) => {
|
|||
return path
|
||||
}
|
||||
|
||||
return `${PLATFORM_URL}${path}#${nip19.neventEncode({id: event.id, relays: urls})}`
|
||||
const pointer = nip19.neventEncode({id: event.id, relays: urls})
|
||||
|
||||
return `${PLATFORM_URL}${path}${path.includes("?") ? "&" : "?"}event=${pointer}`
|
||||
}
|
||||
|
||||
export const getPermalinkTarget = (url: URL) => {
|
||||
const pointer = url.searchParams.get("event")
|
||||
const decoded = pointer ? tryCatch(() => nip19.decode(pointer)) : undefined
|
||||
|
||||
return decoded?.type === "nevent" ? decoded.data.id : undefined
|
||||
}
|
||||
|
||||
export const scrollToEvent = (id: string) => {
|
||||
|
|
|
|||
|
|
@ -129,9 +129,7 @@
|
|||
width: var(--rule-bleed-r, 100vw);
|
||||
}
|
||||
}
|
||||
/* Marks the event a link pointed at. The mark stays until another link is followed, so the reader
|
||||
can scroll away and still find their place. The wash is a spread inset shadow rather than a
|
||||
background because a row's hover rule sets its own background and would paint over it. */
|
||||
/* The wash is an inset shadow because a row's hover rule sets a background that would cover it. */
|
||||
@utility highlight-target {
|
||||
box-shadow:
|
||||
inset 3px 0 0 var(--primary),
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@
|
|||
const {children}: Props = $props()
|
||||
</script>
|
||||
|
||||
{#key $page.url.searchParams.get("at")}
|
||||
{#key [$page.url.searchParams.get("at"), $page.url.searchParams.get("event")].join()}
|
||||
{@render children?.()}
|
||||
{/key}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import {onDestroy} from "svelte"
|
||||
import * as nip19 from "nostr-tools/nip19"
|
||||
import {call, sleep, spec, tryCatch} from "@welshman/lib"
|
||||
import {page} from "$app/state"
|
||||
import {sleep, spec} from "@welshman/lib"
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import {deriveEventsAsc} from "@welshman/store"
|
||||
import {getCommentFiltersForRoot, tagValue, tagSpec} from "@welshman/util"
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
import {network} from "@app/core"
|
||||
import {makeFeedContext} from "@app/feeds"
|
||||
import {decodeRelay} from "@app/relays"
|
||||
import {makeSpacePath, scrollToEvent} from "@app/routes"
|
||||
import {getPermalinkTarget, makeSpacePath, scrollToEvent} from "@app/routes"
|
||||
import type {PageProps} from "./$types"
|
||||
|
||||
const REPLY_BATCH_SIZE = 20
|
||||
|
|
@ -42,19 +42,7 @@
|
|||
// A permalink's target. Replies stream in newest first, so the post it names is usually here
|
||||
// long before the ones above it — its position is only right once the thread has finished
|
||||
// arriving, so this is kept and re-read rather than acted on the first time it shows up.
|
||||
let target: string | undefined = $state(
|
||||
call(() => {
|
||||
const hash = window.location.hash.replace(/^#/, "")
|
||||
|
||||
if (hash.startsWith("nevent1")) {
|
||||
const decoded = tryCatch(() => nip19.decode(hash))
|
||||
|
||||
if (decoded?.type === "nevent") {
|
||||
return decoded.data.id
|
||||
}
|
||||
}
|
||||
}),
|
||||
)
|
||||
let target: string | undefined = $state(getPermalinkTarget(page.url))
|
||||
|
||||
let revealed = $state(REPLY_BATCH_SIZE)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue