Add ChannelMessageMenuMobile

This commit is contained in:
Jon Staab 2024-10-24 15:48:45 -07:00
parent 89e4367208
commit a5173df121
24 changed files with 170 additions and 76 deletions

View file

@ -4,6 +4,7 @@
import type {TrustedEvent} from "@welshman/util" import type {TrustedEvent} from "@welshman/util"
import {deriveProfile, deriveProfileDisplay, formatTimestampAsTime, pubkey} from "@welshman/app" import {deriveProfile, deriveProfileDisplay, formatTimestampAsTime, pubkey} from "@welshman/app"
import type {Thunk} from "@welshman/app" import type {Thunk} from "@welshman/app"
import {isMobile} from "@lib/html"
import {slideAndFade, conditionalTransition} from "@lib/transition" import {slideAndFade, conditionalTransition} from "@lib/transition"
import Delay from "@lib/components/Delay.svelte" import Delay from "@lib/components/Delay.svelte"
import Avatar from "@lib/components/Avatar.svelte" import Avatar from "@lib/components/Avatar.svelte"
@ -15,9 +16,10 @@
import ChannelThread from "@app/components/ChannelThread.svelte" import ChannelThread from "@app/components/ChannelThread.svelte"
import ChannelMessageEmojiButton from "@app/components/ChannelMessageEmojiButton.svelte" import ChannelMessageEmojiButton from "@app/components/ChannelMessageEmojiButton.svelte"
import ChannelMessageMenuButton from "@app/components/ChannelMessageMenuButton.svelte" import ChannelMessageMenuButton from "@app/components/ChannelMessageMenuButton.svelte"
import ChannelMessageMenuMobile from "@app/components/ChannelMessageMenuMobile.svelte"
import {colors, tagRoom, deriveEvent, pubkeyLink} from "@app/state" import {colors, tagRoom, deriveEvent, pubkeyLink} from "@app/state"
import {publishDelete, publishReaction} from "@app/commands" import {publishDelete, publishReaction} from "@app/commands"
import {pushDrawer} from "@app/modal" import {pushDrawer, pushModal} from "@app/modal"
export let url, room export let url, room
export let event: TrustedEvent export let event: TrustedEvent
@ -35,10 +37,14 @@
const transition = conditionalTransition(thunk, slideAndFade) const transition = conditionalTransition(thunk, slideAndFade)
const openThread = () => { const onClick = () => {
const root = $rootEvent || event if (isMobile) {
pushModal(ChannelMessageMenuMobile, {url, event})
} else {
const root = $rootEvent || event
pushDrawer(ChannelThread, {url, room, event: root}) pushDrawer(ChannelThread, {url, room, event: root})
}
} }
const onReactionClick = (content: string, events: TrustedEvent[]) => { const onReactionClick = (content: string, events: TrustedEvent[]) => {
@ -60,7 +66,7 @@
<Delay> <Delay>
<button <button
in:transition in:transition
on:click={openThread} on:click={onClick}
type="button" type="button"
class="group relative flex w-full flex-col gap-1 p-2 text-left transition-colors hover:bg-base-300"> class="group relative flex w-full flex-col gap-1 p-2 text-left transition-colors hover:bg-base-300">
<div class="flex w-full gap-3"> <div class="flex w-full gap-3">
@ -102,7 +108,8 @@
<ReactionSummary {event} {onReactionClick} /> <ReactionSummary {event} {onReactionClick} />
</div> </div>
<button <button
class="join absolute right-1 top-1 border border-solid border-neutral text-xs opacity-0 transition-all group-hover:opacity-100" class="join absolute right-1 top-1 border border-solid border-neutral text-xs opacity-0 transition-all"
class:group-hover:opacity-100={!isMobile}
on:click|stopPropagation> on:click|stopPropagation>
<ChannelMessageEmojiButton {url} {room} {event} /> <ChannelMessageEmojiButton {url} {room} {event} />
<ChannelMessageMenuButton {url} {event} /> <ChannelMessageMenuButton {url} {event} />

View file

@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import type {NativeEmoji} from "emoji-picker-element/shared" import type {NativeEmoji} from "emoji-picker-element/shared"
import EmojiButton from "@lib/components/EmojiButton.svelte" import EmojiButton from "@lib/components/EmojiButton.svelte"
import Icon from "@lib/components/Icon.svelte"
import {tagRoom} from "@app/state" import {tagRoom} from "@app/state"
import {publishReaction} from "@app/commands" import {publishReaction} from "@app/commands"
@ -15,4 +16,6 @@
}) })
</script> </script>
<EmojiButton {onEmoji} class="join-item" /> <EmojiButton {onEmoji} class="btn join-item btn-xs">
<Icon icon="smile-circle" size={4} />
</EmojiButton>

View file

@ -2,9 +2,8 @@
import {pubkey} from "@welshman/app" import {pubkey} from "@welshman/app"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import Confirm from "@lib/components/Confirm.svelte"
import EventInfo from "@app/components/EventInfo.svelte" import EventInfo from "@app/components/EventInfo.svelte"
import {publishDelete} from "@app/commands" import ConfirmDelete from "@app/components/ConfirmDelete.svelte"
import {pushModal} from "@app/modal" import {pushModal} from "@app/modal"
export let url export let url
@ -18,18 +17,7 @@
const showDelete = () => { const showDelete = () => {
onClick() onClick()
pushModal(Confirm, { pushModal(ConfirmDelete, {url, event})
title: "Delete Message",
subtitle: "Are you sure you want to delete this message?",
message: `
This will send a request to delete this message.
Be aware that not all relays may honor this request.`,
confirm: async () => {
await publishDelete({event, relays: [url]})
history.back()
},
})
} }
</script> </script>

View file

@ -0,0 +1,56 @@
<script lang="ts">
import type {NativeEmoji} from "emoji-picker-element/shared"
import {pubkey} from "@welshman/app"
import Button from "@lib/components/Button.svelte"
import Icon from "@lib/components/Icon.svelte"
import EmojiPicker from "@lib/components/EmojiPicker.svelte"
import EventInfo from "@app/components/EventInfo.svelte"
import ChannelThread from "@app/components/ChannelThread.svelte"
import ConfirmDelete from "@app/components/ConfirmDelete.svelte"
import {publishReaction} from "@app/commands"
import {pushModal, pushDrawer} from "@app/modal"
import {tagRoom} from "@app/state"
export let url
export let room
export let event
const onEmoji = (emoji: NativeEmoji) => {
history.back()
publishReaction({
event,
relays: [url],
content: emoji.unicode,
tags: [tagRoom(room, url)],
})
}
const showEmojiPicker = () => pushModal(EmojiPicker, {onClick: onEmoji}, {replaceState: true})
const showConversation = () => pushDrawer(ChannelThread, {url, room, event}, {replaceState: true})
const showInfo = () => pushModal(EventInfo, {event}, {replaceState: true})
const showDelete = () => pushModal(ConfirmDelete, {url, event})
</script>
<div class="col-2">
<Button class="btn btn-primary w-full" on:click={showEmojiPicker}>
<Icon size={4} icon="smile-circle" />
Send Reaction
</Button>
<Button class="btn btn-neutral w-full" on:click={showConversation}>
<Icon size={4} icon="reply" />
View Conversation
</Button>
<Button class="btn btn-neutral" on:click={showInfo}>
<Icon size={4} icon="code-2" />
Message Details
</Button>
{#if event.pubkey === $pubkey}
<Button class="btn btn-neutral text-error" on:click={showDelete}>
<Icon size={4} icon="trash-bin-2" />
Delete Message
</Button>
{/if}
</div>

View file

@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import type {NativeEmoji} from "emoji-picker-element/shared" import type {NativeEmoji} from "emoji-picker-element/shared"
import type {TrustedEvent} from "@welshman/util" import type {TrustedEvent} from "@welshman/util"
import Icon from "@lib/components/Icon.svelte"
import EmojiButton from "@lib/components/EmojiButton.svelte" import EmojiButton from "@lib/components/EmojiButton.svelte"
import {makeReaction, sendWrapped} from "@app/commands" import {makeReaction, sendWrapped} from "@app/commands"
@ -11,4 +12,6 @@
sendWrapped({template: makeReaction({event, content: emoji.unicode}), pubkeys}) sendWrapped({template: makeReaction({event, content: emoji.unicode}), pubkeys})
</script> </script>
<EmojiButton {onEmoji} class="join-item" /> <EmojiButton {onEmoji} class="btn join-item btn-xs">
<Icon icon="smile-circle" size={4} />
</EmojiButton>

View file

@ -0,0 +1,19 @@
<script lang="ts">
import Confirm from "@lib/components/Confirm.svelte"
import {publishDelete} from "@app/commands"
export let url
export let event
const confirm = async () => {
await publishDelete({event, relays: [url]})
history.back()
}
</script>
<Confirm
{confirm}
title="Delete Message"
subtitle="Are you sure you want to delete this message?"
message="This will send a request to delete this message. Be aware that not all relays may honor this request." />

View file

@ -2,11 +2,11 @@
import {nip19} from "nostr-tools" import {nip19} from "nostr-tools"
import {nthEq} from "@welshman/lib" import {nthEq} from "@welshman/lib"
import {Address} from "@welshman/util" import {Address} from "@welshman/util"
import {trackerStore} from "@welshman/app" import type {TrustedEvent} from "@welshman/util"
import Link from "@lib/components/Link.svelte" import Link from "@lib/components/Link.svelte"
import Spinner from "@lib/components/Spinner.svelte" import Spinner from "@lib/components/Spinner.svelte"
import NoteCard from "@app/components/NoteCard.svelte" import NoteCard from "@app/components/NoteCard.svelte"
import {deriveEvent, entityLink, userMembership, getMembershipUrls, COMMENT} from "@app/state" import {deriveEvent, entityLink, MESSAGE, THREAD} from "@app/state"
import {makeThreadPath} from "@app/routes" import {makeThreadPath} from "@app/routes"
export let value export let value
@ -18,13 +18,26 @@
const event = deriveEvent(idOrAddress, relays) const event = deriveEvent(idOrAddress, relays)
const entity = id ? nip19.neventEncode({id, relays}) : addr.toNaddr() const entity = id ? nip19.neventEncode({id, relays}) : addr.toNaddr()
const getLocalHref = (e: TrustedEvent) => {
const url = e.tags.find(nthEq(0, "~"))?.[2]
console.log(e, url)
if (!url) return
if ([MESSAGE, THREAD].includes(e.kind)) return makeThreadPath(url, e.id)
const kind = e.tags.find(nthEq(0, "K"))?.[1]
const id = e.tags.find(nthEq(0, "E"))?.[1]
if (!id || !kind) return
if ([MESSAGE, THREAD].includes(parseInt(kind))) return makeThreadPath(url, id)
}
// If we found this event on a relay that the user is a member of, redirect internally // If we found this event on a relay that the user is a member of, redirect internally
$: url = getMembershipUrls($userMembership).find(url => $trackerStore.hasRelay($event?.id, url)) $: localHref = getLocalHref($event)
$: root = $event?.kind === COMMENT ? $event.tags.find(nthEq(0, "E"))?.[1] : $event?.id $: href = localHref || entityLink(entity)
$: href = url && root ? makeThreadPath(url, root) : entityLink(entity)
</script> </script>
<Link external={!url} {href} class="my-2 block max-w-full text-left"> <Link external={!localHref} {href} class="my-2 block max-w-full text-left">
{#if $event} {#if $event}
<NoteCard event={$event} class="bg-alt rounded-box p-4"> <NoteCard event={$event} class="bg-alt rounded-box p-4">
<slot name="note-content" event={$event} {depth} /> <slot name="note-content" event={$event} {depth} />

View file

@ -41,7 +41,7 @@
pushModal( pushModal(
ProfileList, ProfileList,
{pubkeys: members, title: `Members of`, subtitle: displayRelayUrl(url)}, {pubkeys: members, title: `Members of`, subtitle: displayRelayUrl(url)},
{replaceState} {replaceState},
) )
const createInvite = () => pushModal(SpaceInvite, {url}, {replaceState}) const createInvite = () => pushModal(SpaceInvite, {url}, {replaceState})
@ -72,7 +72,7 @@
$: members = $memberships.filter(l => hasMembershipUrl(l, url)).map(l => l.event.pubkey) $: members = $memberships.filter(l => hasMembershipUrl(l, url)).map(l => l.event.pubkey)
onMount(async () => { onMount(async () => {
replaceState = Boolean(element.closest('.drawer')) replaceState = Boolean(element.closest(".drawer"))
const error = (await checkRelayConnection(url)) || (await checkRelayAuth(url)) const error = (await checkRelayConnection(url)) || (await checkRelayAuth(url))

View file

@ -25,7 +25,7 @@
class:border={isOwn} class:border={isOwn}
class:border-solid={isOwn} class:border-solid={isOwn}
class:border-primary={isOwn} class:border-primary={isOwn}
on:click={onClick}> on:click|stopPropagation={onClick}>
<span>{displayReaction(content)}</span> <span>{displayReaction(content)}</span>
{#if events.length > 1} {#if events.length > 1}
<span>{events.length}</span> <span>{events.length}</span>

View file

@ -62,7 +62,9 @@
</div> </div>
{/if} {/if}
<Button class="join rounded-full"> <Button class="join rounded-full">
<EmojiButton {onEmoji} class="join-item btn-neutral" /> <EmojiButton {onEmoji} class="btn join-item btn-neutral btn-xs">
<Icon icon="smile-circle" size={4} />
</EmojiButton>
<Tippy <Tippy
bind:popover bind:popover
component={ThreadMenu} component={ThreadMenu}

View file

@ -3,14 +3,16 @@
import type {Readable} from "svelte/store" import type {Readable} from "svelte/store"
import {writable} from "svelte/store" import {writable} from "svelte/store"
import {createEditor, type Editor, EditorContent} from "svelte-tiptap" import {createEditor, type Editor, EditorContent} from "svelte-tiptap"
import {append} from "@welshman/lib"
import {createEvent} from "@welshman/util" import {createEvent} from "@welshman/util"
import {publishThunk} from "@welshman/app" import {publishThunk} from "@welshman/app"
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 ModalHeader from "@lib/components/ModalHeader.svelte" import ModalHeader from "@lib/components/ModalHeader.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte"
import {pushToast} from '@app/toast' import {pushToast} from "@app/toast"
import {THREAD} from "@app/state" import {THREAD, GENERAL, tagRoom} from "@app/state"
import {getPubkeyHints} from "@app/commands" import {getPubkeyHints} from "@app/commands"
import {getEditorOptions, addFile, uploadFiles, getEditorTags} from "@lib/editor" import {getEditorOptions, addFile, uploadFiles, getEditorTags} from "@lib/editor"
@ -24,11 +26,11 @@
const submit = () => { const submit = () => {
const content = $editor.getText() const content = $editor.getText()
const tags = getEditorTags($editor) const tags = append(tagRoom(GENERAL, url), getEditorTags($editor))
if (!content.trim()) { if (!content.trim()) {
return pushToast({ return pushToast({
theme: 'error', theme: "error",
message: "Please provide a message for your thread.", message: "Please provide a message for your thread.",
}) })
} }

View file

@ -2,10 +2,9 @@
import {pubkey} from "@welshman/app" import {pubkey} from "@welshman/app"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import Confirm from "@lib/components/Confirm.svelte"
import EventInfo from "@app/components/EventInfo.svelte" import EventInfo from "@app/components/EventInfo.svelte"
import ThreadShare from "@app/components/ThreadShare.svelte" import ThreadShare from "@app/components/ThreadShare.svelte"
import {publishDelete} from "@app/commands" import ConfirmDelete from "@app/components/ConfirmDelete.svelte"
import {pushModal} from "@app/modal" import {pushModal} from "@app/modal"
import {COMMENT} from "@app/state" import {COMMENT} from "@app/state"
@ -27,18 +26,7 @@
const showDelete = () => { const showDelete = () => {
onClick() onClick()
pushModal(Confirm, { pushModal(ConfirmDelete, {url, event})
title: "Delete Message",
subtitle: "Are you sure you want to delete this message?",
message: `
This will send a request to delete this message.
Be aware that not all relays may honor this request.`,
confirm: async () => {
await publishDelete({event, relays: [url]})
history.back()
},
})
} }
</script> </script>

View file

@ -3,13 +3,15 @@
import type {Readable} from "svelte/store" import type {Readable} from "svelte/store"
import {writable} from "svelte/store" import {writable} from "svelte/store"
import {createEditor, type Editor, EditorContent} from "svelte-tiptap" import {createEditor, type Editor, EditorContent} from "svelte-tiptap"
import {append} from "@welshman/lib"
import {fly, slideAndFade} from "@lib/transition" import {fly, slideAndFade} from "@lib/transition"
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 ModalFooter from "@lib/components/ModalFooter.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte"
import {getPubkeyHints, publishComment} from "@app/commands"
import {getEditorOptions, addFile, uploadFiles, getEditorTags} from "@lib/editor" import {getEditorOptions, addFile, uploadFiles, getEditorTags} from "@lib/editor"
import {pushToast} from '@app/toast' import {getPubkeyHints, publishComment} from "@app/commands"
import {tagRoom, GENERAL} from "@app/state"
import {pushToast} from "@app/toast"
export let url export let url
export let event export let event
@ -22,11 +24,11 @@
const submit = () => { const submit = () => {
const content = $editor.getText() const content = $editor.getText()
const tags = getEditorTags($editor) const tags = append(tagRoom(GENERAL, url), getEditorTags($editor))
if (!content.trim()) { if (!content.trim()) {
return pushToast({ return pushToast({
theme: 'error', theme: "error",
message: "Please provide a message for your reply.", message: "Please provide a message for your reply.",
}) })
} }

View file

@ -20,7 +20,7 @@
const back = () => history.back() const back = () => history.back()
const onSubmit = () => { const onSubmit = () => {
setKey('content', toNostrURI(nevent)) setKey("content", toNostrURI(nevent))
goto(makeRoomPath(url, selection), {replaceState: true}) goto(makeRoomPath(url, selection), {replaceState: true})
} }

View file

@ -34,7 +34,7 @@ import {
hasValidSignature, hasValidSignature,
normalizeRelayUrl, normalizeRelayUrl,
} from "@welshman/util" } from "@welshman/util"
import type {TrustedEvent, SignedEvent, PublishedList, List} from "@welshman/util" import type {TrustedEvent, SignedEvent, PublishedList, List, Filter} from "@welshman/util"
import {Nip59} from "@welshman/signer" import {Nip59} from "@welshman/signer"
import { import {
pubkey, pubkey,
@ -45,7 +45,6 @@ import {
getDefaultAppContext, getDefaultAppContext,
getDefaultNetContext, getDefaultNetContext,
makeRouter, makeRouter,
trackerStore,
tracker, tracker,
relay, relay,
getSession, getSession,
@ -248,13 +247,11 @@ export const deriveEvent = (idOrAddress: string, hints: string[] = []) => {
) )
} }
export const deriveEventsForUrl = (url: string, kinds: number[]) => export const deriveEventsForUrl = (url: string, filters: Filter[]) =>
derived(trackerStore, $tracker => derived(deriveEvents(repository, {filters}), $events =>
sortBy( sortBy(
e => -e.created_at, e => -e.created_at,
Array.from($tracker.getIds(url)) $events.filter(e => e.tags.find(nthEq(0, "~"))?.[2] === url),
.map(id => repository.eventsById.get(id)!)
.filter(e => kinds.includes(e?.kind)),
), ),
) )

View file

@ -4,7 +4,7 @@
export let onClose export let onClose
</script> </script>
<div class="fixed inset-0 z-modal drawer"> <div class="drawer fixed inset-0 z-modal">
<button <button
class="absolute inset-0 cursor-pointer bg-black opacity-50" class="absolute inset-0 cursor-pointer bg-black opacity-50"
transition:fade transition:fade

View file

@ -3,7 +3,6 @@
import {type Instance} from "tippy.js" import {type Instance} from "tippy.js"
import type {NativeEmoji} from "emoji-picker-element/shared" import type {NativeEmoji} from "emoji-picker-element/shared"
import {between} from "@welshman/lib" import {between} from "@welshman/lib"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Tippy from "@lib/components/Tippy.svelte" import Tippy from "@lib/components/Tippy.svelte"
import EmojiPicker from "@lib/components/EmojiPicker.svelte" import EmojiPicker from "@lib/components/EmojiPicker.svelte"
@ -37,7 +36,7 @@
component={EmojiPicker} component={EmojiPicker}
props={{onClick}} props={{onClick}}
params={{trigger: "manual", interactive: true}}> params={{trigger: "manual", interactive: true}}>
<Button class="btn btn-xs {$$props.class}" on:click={open}> <Button on:click={open} class={$$props.class}>
<Icon icon="smile-circle" size={4} /> <slot />
</Button> </Button>
</Tippy> </Tippy>

View file

@ -1,3 +1,13 @@
<style>
@media (max-width: 450px) {
emoji-picker {
max-width: 100%;
--num-columns: 6;
--category-emoji-size: 1.125rem;
}
}
</style>
<script lang="ts"> <script lang="ts">
import "emoji-picker-element" import "emoji-picker-element"
import type {Emoji} from "emoji-picker-element/shared" import type {Emoji} from "emoji-picker-element/shared"

View file

@ -68,3 +68,5 @@ export const createScroller = ({
}, },
} }
} }
export const isMobile = "ontouchstart" in document.documentElement

View file

@ -31,10 +31,15 @@
<Page> <Page>
<ContentSearch> <ContentSearch>
<label slot="input" class="input input-bordered row-2"> <label slot="input" class="row-2 input input-bordered">
<Icon icon="magnifer" /> <Icon icon="magnifer" />
<!-- svelte-ignore a11y-autofocus --> <!-- svelte-ignore a11y-autofocus -->
<input autofocus bind:value={term} class="grow" type="text" placeholder="Search for people..." /> <input
autofocus
bind:value={term}
class="grow"
type="text"
placeholder="Search for people..." />
</label> </label>
<div slot="content" class="col-2" bind:this={element}> <div slot="content" class="col-2" bind:this={element}>
{#each pubkeys.slice(0, limit) as pubkey (pubkey)} {#each pubkeys.slice(0, limit) as pubkey (pubkey)}

View file

@ -18,9 +18,9 @@
import {pushModal, pushDrawer} from "@app/modal" import {pushModal, pushDrawer} from "@app/modal"
const url = decodeRelay($page.params.relay) const url = decodeRelay($page.params.relay)
const events = deriveEventsForUrl(url, [THREAD]) const events = deriveEventsForUrl(url, [{kinds: [THREAD]}])
const mutedPubkeys = getPubkeyTagValues(getListTags($userMutes)) const mutedPubkeys = getPubkeyTagValues(getListTags($userMutes))
const filters: Filter[] = [{kinds: [THREAD]}, {kinds: [COMMENT], '#k': [String(THREAD)]}] const filters: Filter[] = [{kinds: [THREAD]}, {kinds: [COMMENT], "#k": [String(THREAD)]}]
const feed = makeIntersectionFeed(makeRelayFeed(url), feedsFromFilters(filters)) const feed = makeIntersectionFeed(makeRelayFeed(url), feedsFromFilters(filters))
const loader = feedLoader.getLoader(feed, { const loader = feedLoader.getLoader(feed, {
onExhausted: () => { onExhausted: () => {

View file

@ -11,7 +11,7 @@
import {onMount} from "svelte" import {onMount} from "svelte"
import {page} from "$app/stores" import {page} from "$app/stores"
import {writable} from "svelte/store" import {writable} from "svelte/store"
import {sortBy, fromPairs, now, assoc, append} from "@welshman/lib" import {sortBy, now, assoc, append} from "@welshman/lib"
import type {TrustedEvent, EventContent} from "@welshman/util" import type {TrustedEvent, EventContent} from "@welshman/util"
import {createEvent} from "@welshman/util" import {createEvent} from "@welshman/util"
import {formatTimestampAsDate, subscribe, publishThunk} from "@welshman/app" import {formatTimestampAsDate, subscribe, publishThunk} from "@welshman/app"
@ -41,7 +41,7 @@
import {popKey} from "@app/implicit" import {popKey} from "@app/implicit"
const {room = GENERAL} = $page.params const {room = GENERAL} = $page.params
const content = popKey<string>('content') || "" const content = popKey<string>("content") || ""
const url = decodeRelay($page.params.relay) const url = decodeRelay($page.params.relay)
const channel = deriveChannel(makeChannelId(url, room)) const channel = deriveChannel(makeChannelId(url, room))
const thunks = writable({} as Record<string, Thunk>) const thunks = writable({} as Record<string, Thunk>)

View file

@ -18,7 +18,7 @@
const url = decodeRelay($page.params.relay) const url = decodeRelay($page.params.relay)
const kinds = [EVENT_DATE, EVENT_TIME] const kinds = [EVENT_DATE, EVENT_TIME]
const events = deriveEventsForUrl(url, kinds) const events = deriveEventsForUrl(url, [{kinds}])
const openMenu = () => pushDrawer(MenuSpace, {url}) const openMenu = () => pushDrawer(MenuSpace, {url})

View file

@ -1,11 +1,10 @@
<script lang="ts"> <script lang="ts">
import {onMount} from "svelte" import {onMount} from "svelte"
import {sortBy, displayUrl, sleep} from "@welshman/lib" import {sortBy, sleep} from "@welshman/lib"
import {page} from "$app/stores" import {page} from "$app/stores"
import {repository, subscribe} from "@welshman/app" import {repository, subscribe} from "@welshman/app"
import {deriveEvents} from "@welshman/store" import {deriveEvents} from "@welshman/store"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import Link from "@lib/components/Link.svelte"
import PageBar from "@lib/components/PageBar.svelte" import PageBar from "@lib/components/PageBar.svelte"
import Spinner from "@lib/components/Spinner.svelte" import Spinner from "@lib/components/Spinner.svelte"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
@ -16,7 +15,6 @@
import ThreadReply from "@app/components/ThreadReply.svelte" import ThreadReply from "@app/components/ThreadReply.svelte"
import {COMMENT, deriveEvent, decodeRelay} from "@app/state" import {COMMENT, deriveEvent, decodeRelay} from "@app/state"
import {pushDrawer} from "@app/modal" import {pushDrawer} from "@app/modal"
import {makeSpacePath} from "@app/routes"
const {relay, id} = $page.params const {relay, id} = $page.params
const url = decodeRelay(relay) const url = decodeRelay(relay)