Open a note in a modal instead of on a page of its own (#628)

This commit is contained in:
Coracle-Bot 2026-09-23 03:48:52 +00:00 committed by hodlbod
parent cfc30803b4
commit 180ab5cb24
5 changed files with 56 additions and 47 deletions

View file

@ -6,8 +6,8 @@
import Reply from "@assets/icons/reply-2.svg?dataurl" import Reply from "@assets/icons/reply-2.svg?dataurl"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Page from "@lib/components/Page.svelte" import Modal from "@lib/components/Modal.svelte"
import PageContent from "@lib/components/PageContent.svelte" import ModalBody from "@lib/components/ModalBody.svelte"
import Spinner from "@lib/components/Spinner.svelte" import Spinner from "@lib/components/Spinner.svelte"
import CommentCompose from "@app/components/CommentCompose.svelte" import CommentCompose from "@app/components/CommentCompose.svelte"
import CommentTree from "@app/components/CommentTree.svelte" import CommentTree from "@app/components/CommentTree.svelte"
@ -38,38 +38,34 @@
onDestroy(context.cleanup) onDestroy(context.cleanup)
</script> </script>
<Page> <Modal label="Note">
<PageContent noPad class="flex flex-col"> <ModalBody>
{#if $event} {#if $event}
{@const note = $event} {@const note = $event}
{@const replyToNote = () => setReplyTo(note)} {@const replyToNote = () => setReplyTo(note)}
<div class="border-b border-line bg-surface px-4 py-4"> <div class="border-line flex flex-col gap-4 border-b pb-4">
<div class="mx-auto w-full max-w-[68ch]"> <NoteItem event={note} {context} card={false} showEntire>
<NoteItem event={note} {context} card={false} showEntire> {#if replyTo?.id !== note.id}
{#if replyTo?.id !== note.id} <Button class="button button-neutral button-xs" onclick={replyToNote}>
<Button class="button button-neutral button-xs" onclick={replyToNote}> <Icon icon={Reply} size={4} />
<Icon icon={Reply} size={4} /> Reply
Reply </Button>
</Button> {/if}
{/if} </NoteItem>
</NoteItem>
</div>
</div>
<div class="mx-auto w-full max-w-[68ch] px-4 pt-4">
{#if replyTo?.id === note.id} {#if replyTo?.id === note.id}
<div class="pb-4"> <CommentCompose
<CommentCompose event={note}
event={note} noun="Reply"
noun="Reply" onCancel={clearReplyTo}
onCancel={clearReplyTo} onSubmit={clearReplyTo} />
onSubmit={clearReplyTo} />
</div>
{/if} {/if}
</div>
<div class="flex flex-col">
{#each $replies as node (node.comment.id)} {#each $replies as node (node.comment.id)}
<CommentTree {node} root={note} {replyTo} {setReplyTo} {context} /> <CommentTree {node} root={note} {replyTo} {setReplyTo} {context} />
{/each} {/each}
{#if $replies.length === 0 && replyTo?.id !== note.id} {#if $replies.length === 0}
<p class="py-6 text-sm opacity-75">No replies yet.</p> <p class="py-2 text-sm opacity-75">No replies yet.</p>
{/if} {/if}
</div> </div>
{:else} {:else}
@ -81,5 +77,5 @@
{/await} {/await}
</div> </div>
{/if} {/if}
</PageContent> </ModalBody>
</Page> </Modal>

View file

@ -25,7 +25,9 @@ import {entityLink, PLATFORM_URL, PLATFORM_RELAYS} from "@app/env"
import {decodeRelay, encodeRelay} from "@app/relays" import {decodeRelay, encodeRelay} from "@app/relays"
import {DM_KINDS} from "@app/content" import {DM_KINDS} from "@app/content"
import {navigate, pushModal} from "@app/modal" import {navigate, pushModal} from "@app/modal"
import type {NotePointer} from "@app/social"
import ChatEnable from "@app/components/ChatEnable.svelte" import ChatEnable from "@app/components/ChatEnable.svelte"
import NoteDetail from "@app/components/NoteDetail.svelte"
// State // State
@ -267,8 +269,23 @@ export const scrollToEvent = (id: string) => {
return element instanceof HTMLElement return element instanceof HTMLElement
} }
// A note opens over whatever is on screen rather than on a page of its own.
export const pushNote = (pointer: NotePointer) => pushModal(NoteDetail, {pointer}, {size: "large"})
// A url resolving to a note has nothing on screen to open it over, so the app goes behind it.
export const goToNote = (pointer: NotePointer) => {
pushNote(pointer)
return goToHome()
}
export const goToEvent = (event: TrustedEvent, options: Record<string, any> = {}) => { export const goToEvent = (event: TrustedEvent, options: Record<string, any> = {}) => {
const urls = Array.from(app.get().tracker.getRelays(event.id)) const urls = Array.from(app.get().tracker.getRelays(event.id))
if (event.kind === NOTE) {
return pushNote({id: event.id, pubkey: event.pubkey, relays: urls})
}
const path = makeEventPath(event, urls) const path = makeEventPath(event, urls)
if (path.includes("://")) { if (path.includes("://")) {

View file

@ -2,13 +2,13 @@
import {onMount} from "svelte" import {onMount} from "svelte"
import * as nip19 from "nostr-tools/nip19" import * as nip19 from "nostr-tools/nip19"
import type {TrustedEvent} from "@welshman/util" import type {TrustedEvent} from "@welshman/util"
import {Address, getIdFilters} from "@welshman/util" import {Address, NOTE, getIdFilters} from "@welshman/util"
import {LOCAL_RELAY_URL} from "@welshman/net" import {LOCAL_RELAY_URL} from "@welshman/net"
import {goto} from "$app/navigation" import {goto} from "$app/navigation"
import {decodePubkey} from "@lib/util" import {decodePubkey} from "@lib/util"
import Spinner from "@lib/components/Spinner.svelte" import Spinner from "@lib/components/Spinner.svelte"
import {network} from "@app/core" import {network} from "@app/core"
import {goToEvent, makeProfilePath} from "@app/routes" import {goToEvent, goToNote, makeProfilePath} from "@app/routes"
import type {PageProps} from "./$types" import type {PageProps} from "./$types"
const {params}: PageProps = $props() const {params}: PageProps = $props()
@ -35,7 +35,12 @@
filters: getIdFilters([type === "nevent" ? data.id : Address.fromNaddr(bech32).toString()]), filters: getIdFilters([type === "nevent" ? data.id : Address.fromNaddr(bech32).toString()]),
onEvent: (event: TrustedEvent) => { onEvent: (event: TrustedEvent) => {
found = true found = true
goToEvent(event, {replaceState: true})
if (event.kind === NOTE) {
goToNote({id: event.id, pubkey: event.pubkey, relays: data.relays})
} else {
goToEvent(event, {replaceState: true})
}
}, },
onClose: () => { onClose: () => {
if (!found) { if (!found) {

View file

@ -1,9 +0,0 @@
<script lang="ts">
import type {LayoutProps} from "./$types"
const {children, params}: LayoutProps = $props()
</script>
{#key params.nevent}
{@render children?.()}
{/key}

View file

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import {onMount} from "svelte" import {onMount} from "svelte"
import NotePage from "@app/components/NotePage.svelte" import Spinner from "@lib/components/Spinner.svelte"
import {navigate} from "@app/modal" import {goToHome, goToNote} from "@app/routes"
import {decodeNotePointer} from "@app/social" import {decodeNotePointer} from "@app/social"
import type {PageProps} from "./$types" import type {PageProps} from "./$types"
@ -10,12 +10,12 @@
const pointer = decodeNotePointer(params.nevent) const pointer = decodeNotePointer(params.nevent)
onMount(() => { onMount(() => {
if (!pointer) { if (pointer) {
navigate("/", {replaceState: true}) goToNote(pointer)
} else {
goToHome()
} }
}) })
</script> </script>
{#if pointer} <Spinner />
<NotePage {pointer} />
{/if}