Apply layout changes to chat
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
* Fix nevent hints for url-specific stuff
|
* Fix nevent hints for url-specific stuff
|
||||||
* Add alerts via Anchor
|
* Add alerts via Anchor
|
||||||
* Fix confirm and reactions on mobile
|
* Fix confirm and reactions on mobile
|
||||||
|
* Add reply to chat on mobile
|
||||||
|
|
||||||
# 0.2.11
|
# 0.2.11
|
||||||
|
|
||||||
|
|||||||
@@ -99,6 +99,7 @@
|
|||||||
<div class="row-2 ml-10 mt-1">
|
<div class="row-2 ml-10 mt-1">
|
||||||
<ReactionSummary {url} {event} {onReactionClick} reactionClass="tooltip-right" />
|
<ReactionSummary {url} {event} {onReactionClick} reactionClass="tooltip-right" />
|
||||||
</div>
|
</div>
|
||||||
|
{#if !isMobile}
|
||||||
<button
|
<button
|
||||||
class="join absolute right-1 top-1 border border-solid border-neutral text-xs opacity-0 transition-all"
|
class="join absolute right-1 top-1 border border-solid border-neutral text-xs opacity-0 transition-all"
|
||||||
class:group-hover:opacity-100={!isMobile}>
|
class:group-hover:opacity-100={!isMobile}>
|
||||||
@@ -110,4 +111,5 @@
|
|||||||
{/if}
|
{/if}
|
||||||
<ChannelMessageMenuButton {url} {event} />
|
<ChannelMessageMenuButton {url} {event} />
|
||||||
</button>
|
</button>
|
||||||
|
{/if}
|
||||||
</TapTarget>
|
</TapTarget>
|
||||||
|
|||||||
@@ -70,6 +70,8 @@
|
|||||||
let loading = $state(true)
|
let loading = $state(true)
|
||||||
let compose: ChatCompose | undefined = $state()
|
let compose: ChatCompose | undefined = $state()
|
||||||
let parent: TrustedEvent | undefined = $state()
|
let parent: TrustedEvent | undefined = $state()
|
||||||
|
let parentPreview: HTMLElement | undefined = $state()
|
||||||
|
let dynamicPadding: HTMLElement | undefined = $state()
|
||||||
|
|
||||||
const elements = $derived.by(() => {
|
const elements = $derived.by(() => {
|
||||||
const elements = []
|
const elements = []
|
||||||
@@ -104,6 +106,16 @@
|
|||||||
onMount(() => {
|
onMount(() => {
|
||||||
// Don't use loadInboxRelaySelection because we want to force reload
|
// Don't use loadInboxRelaySelection because we want to force reload
|
||||||
load({filters: [{kinds: [INBOX_RELAYS], authors: others}]})
|
load({filters: [{kinds: [INBOX_RELAYS], authors: others}]})
|
||||||
|
|
||||||
|
const observer = new ResizeObserver(() => {
|
||||||
|
dynamicPadding!.style.minHeight = `${parentPreview!.offsetHeight}px`
|
||||||
|
})
|
||||||
|
|
||||||
|
observer.observe(parentPreview!)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
observer.unobserve(parentPreview!)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -111,9 +123,8 @@
|
|||||||
}, 5000)
|
}, 5000)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="relative flex h-full w-full flex-col">
|
|
||||||
{#if others.length > 0}
|
{#if others.length > 0}
|
||||||
<PageBar>
|
<PageBar class="chat__page-bar">
|
||||||
{#snippet title()}
|
{#snippet title()}
|
||||||
<div class="flex flex-col gap-1 sm:flex-row sm:gap-2">
|
<div class="flex flex-col gap-1 sm:flex-row sm:gap-2">
|
||||||
{#if others.length === 1}
|
{#if others.length === 1}
|
||||||
@@ -160,7 +171,9 @@
|
|||||||
{/snippet}
|
{/snippet}
|
||||||
</PageBar>
|
</PageBar>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="-mt-2 flex flex-grow flex-col-reverse overflow-auto py-2">
|
|
||||||
|
<div class="chat__messages scroll-container">
|
||||||
|
<div bind:this={dynamicPadding}></div>
|
||||||
{#if missingInboxes.includes($pubkey!)}
|
{#if missingInboxes.includes($pubkey!)}
|
||||||
<div class="py-12">
|
<div class="py-12">
|
||||||
<div class="card2 col-2 m-auto max-w-md items-center text-center">
|
<div class="card2 col-2 m-auto max-w-md items-center text-center">
|
||||||
@@ -170,8 +183,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
In order to deliver messages, {PLATFORM_NAME} needs to know where to send them. Please visit
|
In order to deliver messages, {PLATFORM_NAME} needs to know where to send them. Please visit
|
||||||
your <Link class="link" href="/settings/relays">relay settings page</Link> to set up your
|
your <Link class="link" href="/settings/relays">relay settings page</Link> to set up your inbox.
|
||||||
inbox.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -201,8 +213,7 @@
|
|||||||
{replyTo} />
|
{replyTo} />
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
<p
|
<p class="m-auto flex h-10 max-w-sm flex-col items-center justify-center gap-4 py-20 text-center">
|
||||||
class="m-auto flex h-10 max-w-sm flex-col items-center justify-center gap-4 py-20 text-center">
|
|
||||||
<Spinner {loading}>
|
<Spinner {loading}>
|
||||||
{#if loading}
|
{#if loading}
|
||||||
Looking for messages...
|
Looking for messages...
|
||||||
@@ -213,8 +224,12 @@
|
|||||||
{@render info?.()}
|
{@render info?.()}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="chat__compose bg-base-200">
|
||||||
|
<div bind:this={parentPreview}>
|
||||||
{#if parent}
|
{#if parent}
|
||||||
<ChatComposeParent event={parent} clear={clearParent} verb="Replying to" />
|
<ChatComposeParent event={parent} clear={clearParent} verb="Replying to" />
|
||||||
{/if}
|
{/if}
|
||||||
|
</div>
|
||||||
<ChatCompose bind:this={compose} {onSubmit} />
|
<ChatCompose bind:this={compose} {onSubmit} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -27,12 +27,12 @@
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
event: TrustedEvent
|
event: TrustedEvent
|
||||||
replyTo?: any
|
replyTo: (event: TrustedEvent) => void
|
||||||
pubkeys: string[]
|
pubkeys: string[]
|
||||||
showPubkey?: boolean
|
showPubkey?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const {event, replyTo = undefined, pubkeys, showPubkey = false}: Props = $props()
|
const {event, replyTo, pubkeys, showPubkey = false}: Props = $props()
|
||||||
|
|
||||||
const thunk = $thunks[event.id]
|
const thunk = $thunks[event.id]
|
||||||
const isOwn = event.pubkey === $pubkey
|
const isOwn = event.pubkey === $pubkey
|
||||||
@@ -40,6 +40,8 @@
|
|||||||
const profileDisplay = deriveProfileDisplay(event.pubkey)
|
const profileDisplay = deriveProfileDisplay(event.pubkey)
|
||||||
const [_, colorValue] = colors[parseInt(hash(event.pubkey)) % colors.length]
|
const [_, colorValue] = colors[parseInt(hash(event.pubkey)) % colors.length]
|
||||||
|
|
||||||
|
const reply = () => replyTo(event)
|
||||||
|
|
||||||
const onReactionClick = async (content: string, events: TrustedEvent[]) => {
|
const onReactionClick = async (content: string, events: TrustedEvent[]) => {
|
||||||
const reaction = events.find(e => e.pubkey === $pubkey)
|
const reaction = events.find(e => e.pubkey === $pubkey)
|
||||||
const template = reaction ? makeDelete({event: reaction}) : makeReaction({event, content})
|
const template = reaction ? makeDelete({event: reaction}) : makeReaction({event, content})
|
||||||
@@ -49,7 +51,7 @@
|
|||||||
|
|
||||||
const openProfile = () => pushModal(ProfileDetail, {pubkey: event.pubkey})
|
const openProfile = () => pushModal(ProfileDetail, {pubkey: event.pubkey})
|
||||||
|
|
||||||
const showMobileMenu = () => pushModal(ChatMessageMenuMobile, {event, pubkeys})
|
const showMobileMenu = () => pushModal(ChatMessageMenuMobile, {event, pubkeys, reply})
|
||||||
|
|
||||||
const togglePopover = () => {
|
const togglePopover = () => {
|
||||||
if (popoverIsVisible) {
|
if (popoverIsVisible) {
|
||||||
@@ -72,6 +74,7 @@
|
|||||||
class:chat-start={!isOwn}
|
class:chat-start={!isOwn}
|
||||||
class:flex-row-reverse={!isOwn}
|
class:flex-row-reverse={!isOwn}
|
||||||
class:chat-end={isOwn}>
|
class:chat-end={isOwn}>
|
||||||
|
{#if !isMobile}
|
||||||
<Tippy
|
<Tippy
|
||||||
bind:popover
|
bind:popover
|
||||||
component={ChatMessageMenu}
|
component={ChatMessageMenu}
|
||||||
@@ -94,9 +97,10 @@
|
|||||||
<Icon icon="menu-dots" size={4} />
|
<Icon icon="menu-dots" size={4} />
|
||||||
</button>
|
</button>
|
||||||
</Tippy>
|
</Tippy>
|
||||||
|
{/if}
|
||||||
<div class="flex min-w-0 flex-col" class:items-end={isOwn}>
|
<div class="flex min-w-0 flex-col" class:items-end={isOwn}>
|
||||||
<TapTarget
|
<TapTarget
|
||||||
class="bg-alt chat-bubble mx-1 flex cursor-auto flex-col gap-1 text-left lg:max-w-2xl"
|
class="bg-alt chat-bubble mx-1 mb-2 flex cursor-auto flex-col gap-1 text-left lg:max-w-2xl"
|
||||||
onTap={showMobileMenu}>
|
onTap={showMobileMenu}>
|
||||||
{#if showPubkey}
|
{#if showPubkey}
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
|
|||||||
@@ -9,7 +9,13 @@
|
|||||||
import {pushModal} from "@app/modal"
|
import {pushModal} from "@app/modal"
|
||||||
import {clip} from "@app/toast"
|
import {clip} from "@app/toast"
|
||||||
|
|
||||||
const {event, pubkeys} = $props()
|
type Props = {
|
||||||
|
pubkeys: string[]
|
||||||
|
event: TrustedEvent
|
||||||
|
reply: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const {event, pubkeys, reply}: Props = $props()
|
||||||
|
|
||||||
const onEmoji = ((event: TrustedEvent, emoji: NativeEmoji) => {
|
const onEmoji = ((event: TrustedEvent, emoji: NativeEmoji) => {
|
||||||
history.back()
|
history.back()
|
||||||
@@ -18,6 +24,11 @@
|
|||||||
|
|
||||||
const showEmojiPicker = () => pushModal(EmojiPicker, {onClick: onEmoji}, {replaceState: true})
|
const showEmojiPicker = () => pushModal(EmojiPicker, {onClick: onEmoji}, {replaceState: true})
|
||||||
|
|
||||||
|
const sendReply = () => {
|
||||||
|
history.back()
|
||||||
|
reply()
|
||||||
|
}
|
||||||
|
|
||||||
const copyText = () => {
|
const copyText = () => {
|
||||||
history.back()
|
history.back()
|
||||||
clip(event.content)
|
clip(event.content)
|
||||||
@@ -31,6 +42,10 @@
|
|||||||
<Icon size={4} icon="smile-circle" />
|
<Icon size={4} icon="smile-circle" />
|
||||||
Send Reaction
|
Send Reaction
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button class="btn btn-neutral w-full" onclick={sendReply}>
|
||||||
|
<Icon size={4} icon="reply" />
|
||||||
|
Send Reply
|
||||||
|
</Button>
|
||||||
<Button class="btn btn-neutral w-full" onclick={copyText}>
|
<Button class="btn btn-neutral w-full" onclick={copyText}>
|
||||||
<Icon size={4} icon="copy" />
|
<Icon size={4} icon="copy" />
|
||||||
Copy Text
|
Copy Text
|
||||||
|
|||||||
Reference in New Issue
Block a user