Add long press for chat messages

This commit is contained in:
Jon Staab
2024-10-24 16:28:56 -07:00
parent 87df0eeeea
commit 81672080f5
6 changed files with 80 additions and 9 deletions
+17 -5
View File
@@ -1,12 +1,15 @@
<script lang="ts"> <script lang="ts">
import {onMount} from 'svelte'
import {type Instance} from "tippy.js" import {type Instance} from "tippy.js"
import {hash} from "@welshman/lib" import {hash} from "@welshman/lib"
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 {MergedThunk} from "@welshman/app" import type {MergedThunk} from "@welshman/app"
import {isMobile} from "@lib/html"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import Link from "@lib/components/Link.svelte" import Link from "@lib/components/Link.svelte"
import Tippy from "@lib/components/Tippy.svelte" import Tippy from "@lib/components/Tippy.svelte"
import LongPress from "@lib/components/LongPress.svelte"
import Avatar from "@lib/components/Avatar.svelte" import Avatar from "@lib/components/Avatar.svelte"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Content from "@app/components/Content.svelte" import Content from "@app/components/Content.svelte"
@@ -14,8 +17,10 @@
import ReactionSummary from "@app/components/ReactionSummary.svelte" import ReactionSummary from "@app/components/ReactionSummary.svelte"
import ThunkStatus from "@app/components/ThunkStatus.svelte" import ThunkStatus from "@app/components/ThunkStatus.svelte"
import ChatMessageMenu from "@app/components/ChatMessageMenu.svelte" import ChatMessageMenu from "@app/components/ChatMessageMenu.svelte"
import ChatMessageMenuMobile from "@app/components/ChatMessageMenuMobile.svelte"
import {colors, pubkeyLink} from "@app/state" import {colors, pubkeyLink} from "@app/state"
import {makeDelete, makeReaction, sendWrapped} from "@app/commands" import {makeDelete, makeReaction, sendWrapped} from "@app/commands"
import {pushModal} from "@app/modal"
export let event: TrustedEvent export let event: TrustedEvent
export let thunk: MergedThunk export let thunk: MergedThunk
@@ -33,6 +38,9 @@
await sendWrapped({template, pubkeys}) await sendWrapped({template, pubkeys})
} }
const showMobileMenu = () =>
pushModal(ChatMessageMenuMobile, {event})
const togglePopover = () => { const togglePopover = () => {
if (popoverIsVisible) { if (popoverIsVisible) {
popover.hide() popover.hide()
@@ -67,12 +75,16 @@
popoverIsVisible = false popoverIsVisible = false
}, },
}}> }}>
<Button class="opacity-0 transition-all group-hover:opacity-100" on:click={togglePopover}> <button
type="button"
class="opacity-0 transition-all"
class:group-hover:opacity-100={!isMobile}
on:click={togglePopover}>
<Icon icon="menu-dots" size={4} /> <Icon icon="menu-dots" size={4} />
</Button> </button>
</Tippy> </Tippy>
<div class="flex flex-col"> <div class="flex flex-col">
<div class="chat-bubble mx-1 max-w-sm"> <LongPress class="text-left chat-bubble mx-1 max-w-sm" onLongPress={showMobileMenu}>
<div class="flex w-full items-start gap-2"> <div class="flex w-full items-start gap-2">
{#if showPubkey} {#if showPubkey}
<Link external href={pubkeyLink(event.pubkey)}> <Link external href={pubkeyLink(event.pubkey)}>
@@ -100,8 +112,8 @@
</div> </div>
</div> </div>
</div> </div>
</div> </LongPress>
<div class="row-2 ml-12"> <div class="row-2 ml-4 -mt-1 z-feature">
<ReplySummary {event} /> <ReplySummary {event} />
<ReactionSummary {event} {onReactionClick} /> <ReactionSummary {event} {onReactionClick} />
</div> </div>
@@ -0,0 +1,43 @@
<script lang="ts">
import type {NativeEmoji} from "emoji-picker-element/shared"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
import EmojiPicker from "@lib/components/EmojiPicker.svelte"
import ChatMessageEmojiButton from "@app/components/ChatMessageEmojiButton.svelte"
import EventInfo from "@app/components/EventInfo.svelte"
import {makeReaction, sendWrapped} from "@app/commands"
import {pushModal} from "@app/modal"
import {clip} from "@app/toast"
export let event
export let pubkeys
const onEmoji = (emoji: NativeEmoji) => {
history.back()
sendWrapped({template: makeReaction({event, content: emoji.unicode}), pubkeys})
}
const showEmojiPicker = () => pushModal(EmojiPicker, {onClick: onEmoji}, {replaceState: true})
const copyText = () => {
history.back()
clip(event.content)
}
const showInfo = () => pushModal(EventInfo, {event}, {replaceState: true})
</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={copyText}>
<Icon size={4} icon="copy" />
Copy Text
</Button>
<Button class="btn btn-neutral" on:click={showInfo}>
<Icon size={4} icon="code-2" />
Message Details
</Button>
</div>
+3 -3
View File
@@ -25,7 +25,7 @@
<p slot="label">Event ID</p> <p slot="label">Event ID</p>
<label class="input input-bordered flex w-full items-center gap-2" slot="input"> <label class="input input-bordered flex w-full items-center gap-2" slot="input">
<Icon icon="file" /> <Icon icon="file" />
<input type="text" class="ellipsize grow" value={note1} /> <input type="text" class="ellipsize min-w-0 grow" value={note1} />
<Button on:click={copyId} class="flex items-center"> <Button on:click={copyId} class="flex items-center">
<Icon icon="copy" /> <Icon icon="copy" />
</Button> </Button>
@@ -35,14 +35,14 @@
<p slot="label">Author Pubkey</p> <p slot="label">Author Pubkey</p>
<label class="input input-bordered flex w-full items-center gap-2" slot="input"> <label class="input input-bordered flex w-full items-center gap-2" slot="input">
<Icon icon="user-circle" /> <Icon icon="user-circle" />
<input type="text" class="ellipsize grow" value={npub1} /> <input type="text" class="ellipsize min-w-0 grow" value={npub1} />
<Button on:click={copyPubkey} class="flex items-center"> <Button on:click={copyPubkey} class="flex items-center">
<Icon icon="copy" /> <Icon icon="copy" />
</Button> </Button>
</label> </label>
</FieldInline> </FieldInline>
<div class="relative"> <div class="relative">
<pre class="card2 card2-sm bg-alt overflow-auto"><code>{json}</code></pre> <pre class="card2 card2-sm bg-alt overflow-auto text-xs"><code>{json}</code></pre>
<p class="absolute right-2 top-2 flex flex-grow items-center justify-between"> <p class="absolute right-2 top-2 flex flex-grow items-center justify-between">
<Button on:click={copyJson} class="btn btn-neutral btn-sm flex items-center"> <Button on:click={copyJson} class="btn btn-neutral btn-sm flex items-center">
<Icon icon="copy" /> Copy <Icon icon="copy" /> Copy
+1 -1
View File
@@ -1,4 +1,4 @@
<div class="grid grid-cols-2 gap-2 {$$props.class}"> <div class="grid grid-cols-1 sm:grid-cols-2 gap-2 {$$props.class}">
<label class="flex items-center gap-2 font-bold"> <label class="flex items-center gap-2 font-bold">
<slot name="label" /> <slot name="label" />
</label> </label>
+15
View File
@@ -0,0 +1,15 @@
<script lang="ts">
export let onLongPress
const onTouchStart = () => {
timeout = setTimeout(onLongPress, 500)
}
const onTouchEnd = () => clearTimeout(timeout)
let timeout: number
</script>
<div on:touchstart={onTouchStart} on:touchend={onTouchEnd} {...$$props}>
<slot />
</div>
+1
View File
@@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import "@src/app.css" import "@src/app.css"
import 'long-press-event'
import {onMount} from "svelte" import {onMount} from "svelte"
import {get} from "svelte/store" import {get} from "svelte/store"
import {dev} from "$app/environment" import {dev} from "$app/environment"