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
+13 -6
View File
@@ -4,6 +4,7 @@
import type {TrustedEvent} from "@welshman/util"
import {deriveProfile, deriveProfileDisplay, formatTimestampAsTime, pubkey} from "@welshman/app"
import type {Thunk} from "@welshman/app"
import {isMobile} from "@lib/html"
import {slideAndFade, conditionalTransition} from "@lib/transition"
import Delay from "@lib/components/Delay.svelte"
import Avatar from "@lib/components/Avatar.svelte"
@@ -15,9 +16,10 @@
import ChannelThread from "@app/components/ChannelThread.svelte"
import ChannelMessageEmojiButton from "@app/components/ChannelMessageEmojiButton.svelte"
import ChannelMessageMenuButton from "@app/components/ChannelMessageMenuButton.svelte"
import ChannelMessageMenuMobile from "@app/components/ChannelMessageMenuMobile.svelte"
import {colors, tagRoom, deriveEvent, pubkeyLink} from "@app/state"
import {publishDelete, publishReaction} from "@app/commands"
import {pushDrawer} from "@app/modal"
import {pushDrawer, pushModal} from "@app/modal"
export let url, room
export let event: TrustedEvent
@@ -35,10 +37,14 @@
const transition = conditionalTransition(thunk, slideAndFade)
const openThread = () => {
const root = $rootEvent || event
const onClick = () => {
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[]) => {
@@ -60,7 +66,7 @@
<Delay>
<button
in:transition
on:click={openThread}
on:click={onClick}
type="button"
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">
@@ -102,7 +108,8 @@
<ReactionSummary {event} {onReactionClick} />
</div>
<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>
<ChannelMessageEmojiButton {url} {room} {event} />
<ChannelMessageMenuButton {url} {event} />
@@ -1,6 +1,7 @@
<script lang="ts">
import type {NativeEmoji} from "emoji-picker-element/shared"
import EmojiButton from "@lib/components/EmojiButton.svelte"
import Icon from "@lib/components/Icon.svelte"
import {tagRoom} from "@app/state"
import {publishReaction} from "@app/commands"
@@ -15,4 +16,6 @@
})
</script>
<EmojiButton {onEmoji} class="join-item" />
<EmojiButton {onEmoji} class="btn join-item btn-xs">
<Icon icon="smile-circle" size={4} />
</EmojiButton>
+2 -14
View File
@@ -2,9 +2,8 @@
import {pubkey} from "@welshman/app"
import Button from "@lib/components/Button.svelte"
import Icon from "@lib/components/Icon.svelte"
import Confirm from "@lib/components/Confirm.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"
export let url
@@ -18,18 +17,7 @@
const showDelete = () => {
onClick()
pushModal(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.`,
confirm: async () => {
await publishDelete({event, relays: [url]})
history.back()
},
})
pushModal(ConfirmDelete, {url, event})
}
</script>
@@ -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>
@@ -1,6 +1,7 @@
<script lang="ts">
import type {NativeEmoji} from "emoji-picker-element/shared"
import type {TrustedEvent} from "@welshman/util"
import Icon from "@lib/components/Icon.svelte"
import EmojiButton from "@lib/components/EmojiButton.svelte"
import {makeReaction, sendWrapped} from "@app/commands"
@@ -11,4 +12,6 @@
sendWrapped({template: makeReaction({event, content: emoji.unicode}), pubkeys})
</script>
<EmojiButton {onEmoji} class="join-item" />
<EmojiButton {onEmoji} class="btn join-item btn-xs">
<Icon icon="smile-circle" size={4} />
</EmojiButton>
+19
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." />
+19 -6
View File
@@ -2,11 +2,11 @@
import {nip19} from "nostr-tools"
import {nthEq} from "@welshman/lib"
import {Address} from "@welshman/util"
import {trackerStore} from "@welshman/app"
import type {TrustedEvent} from "@welshman/util"
import Link from "@lib/components/Link.svelte"
import Spinner from "@lib/components/Spinner.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"
export let value
@@ -18,13 +18,26 @@
const event = deriveEvent(idOrAddress, relays)
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
$: url = getMembershipUrls($userMembership).find(url => $trackerStore.hasRelay($event?.id, url))
$: root = $event?.kind === COMMENT ? $event.tags.find(nthEq(0, "E"))?.[1] : $event?.id
$: href = url && root ? makeThreadPath(url, root) : entityLink(entity)
$: localHref = getLocalHref($event)
$: href = localHref || entityLink(entity)
</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}
<NoteCard event={$event} class="bg-alt rounded-box p-4">
<slot name="note-content" event={$event} {depth} />
+2 -2
View File
@@ -41,7 +41,7 @@
pushModal(
ProfileList,
{pubkeys: members, title: `Members of`, subtitle: displayRelayUrl(url)},
{replaceState}
{replaceState},
)
const createInvite = () => pushModal(SpaceInvite, {url}, {replaceState})
@@ -72,7 +72,7 @@
$: members = $memberships.filter(l => hasMembershipUrl(l, url)).map(l => l.event.pubkey)
onMount(async () => {
replaceState = Boolean(element.closest('.drawer'))
replaceState = Boolean(element.closest(".drawer"))
const error = (await checkRelayConnection(url)) || (await checkRelayAuth(url))
+1 -1
View File
@@ -25,7 +25,7 @@
class:border={isOwn}
class:border-solid={isOwn}
class:border-primary={isOwn}
on:click={onClick}>
on:click|stopPropagation={onClick}>
<span>{displayReaction(content)}</span>
{#if events.length > 1}
<span>{events.length}</span>
+3 -1
View File
@@ -62,7 +62,9 @@
</div>
{/if}
<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
bind:popover
component={ThreadMenu}
+6 -4
View File
@@ -3,14 +3,16 @@
import type {Readable} from "svelte/store"
import {writable} from "svelte/store"
import {createEditor, type Editor, EditorContent} from "svelte-tiptap"
import {append} from "@welshman/lib"
import {createEvent} from "@welshman/util"
import {publishThunk} from "@welshman/app"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
import ModalHeader from "@lib/components/ModalHeader.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte"
import {pushToast} from '@app/toast'
import {THREAD} from "@app/state"
import {pushToast} from "@app/toast"
import {THREAD, GENERAL, tagRoom} from "@app/state"
import {getPubkeyHints} from "@app/commands"
import {getEditorOptions, addFile, uploadFiles, getEditorTags} from "@lib/editor"
@@ -24,11 +26,11 @@
const submit = () => {
const content = $editor.getText()
const tags = getEditorTags($editor)
const tags = append(tagRoom(GENERAL, url), getEditorTags($editor))
if (!content.trim()) {
return pushToast({
theme: 'error',
theme: "error",
message: "Please provide a message for your thread.",
})
}
+2 -14
View File
@@ -2,10 +2,9 @@
import {pubkey} from "@welshman/app"
import Button from "@lib/components/Button.svelte"
import Icon from "@lib/components/Icon.svelte"
import Confirm from "@lib/components/Confirm.svelte"
import EventInfo from "@app/components/EventInfo.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 {COMMENT} from "@app/state"
@@ -27,18 +26,7 @@
const showDelete = () => {
onClick()
pushModal(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.`,
confirm: async () => {
await publishDelete({event, relays: [url]})
history.back()
},
})
pushModal(ConfirmDelete, {url, event})
}
</script>
+6 -4
View File
@@ -3,13 +3,15 @@
import type {Readable} from "svelte/store"
import {writable} from "svelte/store"
import {createEditor, type Editor, EditorContent} from "svelte-tiptap"
import {append} from "@welshman/lib"
import {fly, slideAndFade} from "@lib/transition"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte"
import {getPubkeyHints, publishComment} from "@app/commands"
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 event
@@ -22,11 +24,11 @@
const submit = () => {
const content = $editor.getText()
const tags = getEditorTags($editor)
const tags = append(tagRoom(GENERAL, url), getEditorTags($editor))
if (!content.trim()) {
return pushToast({
theme: 'error',
theme: "error",
message: "Please provide a message for your reply.",
})
}
+1 -1
View File
@@ -20,7 +20,7 @@
const back = () => history.back()
const onSubmit = () => {
setKey('content', toNostrURI(nevent))
setKey("content", toNostrURI(nevent))
goto(makeRoomPath(url, selection), {replaceState: true})
}