Add drawer, start working on replies
This commit is contained in:
+31
-1
@@ -1,5 +1,6 @@
|
||||
import {uniqBy, sleep, chunk, equals, choice} from "@welshman/lib"
|
||||
import {getPubkeyTagValues, createEvent, displayProfile} from "@welshman/util"
|
||||
import {DELETE, REACTION, getPubkeyTagValues, createEvent, displayProfile} from "@welshman/util"
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import type {SubscribeRequestWithHandlers} from "@welshman/net"
|
||||
import {
|
||||
pubkey,
|
||||
@@ -13,6 +14,8 @@ import {
|
||||
loadFollows,
|
||||
loadMutes,
|
||||
getFollows,
|
||||
tagEvent,
|
||||
tagReactionTo,
|
||||
} from "@welshman/app"
|
||||
import {ROOM, MEMBERSHIPS, INDEXER_RELAYS} from "@app/state"
|
||||
|
||||
@@ -106,3 +109,30 @@ export const removeSpaceMembership = (url: string) =>
|
||||
|
||||
export const removeRoomMembership = (url: string, room: string) =>
|
||||
updateList(MEMBERSHIPS, (tags: string[][]) => tags.filter(t => !equals([ROOM, room, url], t)))
|
||||
|
||||
// Actions
|
||||
|
||||
export const publishReaction = ({relays, event, content, tags = []}: {
|
||||
relays: string[]
|
||||
event: TrustedEvent,
|
||||
content: string,
|
||||
tags?: string[][]
|
||||
}) => {
|
||||
const reaction = createEvent(REACTION, {
|
||||
content,
|
||||
tags: [
|
||||
...tags,
|
||||
...tagReactionTo(event),
|
||||
],
|
||||
})
|
||||
|
||||
publishThunk(makeThunk({event: reaction, relays}))
|
||||
}
|
||||
|
||||
export const publishDelete = ({relays, event}: {relays: string[], event: TrustedEvent}) => {
|
||||
const deleteEvent = createEvent(DELETE, {
|
||||
tags: [["k", String(event.kind)], ...tagEvent(event)],
|
||||
})
|
||||
|
||||
publishThunk(makeThunk({event: deleteEvent, relays}))
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import {onMount} from "svelte"
|
||||
import type {SvelteComponent} from "svelte"
|
||||
import type {NativeEmoji} from 'emoji-picker-element/shared'
|
||||
import twColors from "tailwindcss/colors"
|
||||
import type {Readable} from "svelte/store"
|
||||
@@ -26,14 +27,19 @@
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import Avatar from "@lib/components/Avatar.svelte"
|
||||
import Drawer from "@lib/components/Drawer.svelte"
|
||||
import Content from "@app/components/Content.svelte"
|
||||
import ChatMessageEmojiButton from "@app/components/ChatMessageEmojiButton.svelte"
|
||||
import ChatMessageReplies from "@app/components/ChatMessageReplies.svelte"
|
||||
import ChatMessageReply from "@app/components/ChatMessageReply.svelte"
|
||||
import {ROOM, REPLY, deriveEvent, displayReaction} from "@app/state"
|
||||
import {publishDelete, publishReaction} from "@app/commands"
|
||||
|
||||
export let url
|
||||
export let room
|
||||
export let event: TrustedEvent
|
||||
export let showPubkey: boolean
|
||||
export let isReply = false
|
||||
|
||||
const colors = [
|
||||
["amber", twColors.amber[600]],
|
||||
@@ -71,33 +77,23 @@
|
||||
const findStatus = ($ps: PublishStatusData[], statuses: PublishStatus[]) =>
|
||||
$ps.find(({status}) => statuses.includes(status))
|
||||
|
||||
const createReaction = (content: string) => {
|
||||
const reaction = createEvent(REACTION, {
|
||||
content,
|
||||
tags: [
|
||||
[ROOM, room, url],
|
||||
...tagReactionTo(event),
|
||||
],
|
||||
})
|
||||
|
||||
publishThunk(makeThunk({event: reaction, relays: [url]}))
|
||||
}
|
||||
|
||||
const onReactionClick = (content: string, events: TrustedEvent[]) => {
|
||||
const reaction = events.find(e => e.pubkey === $pubkey)
|
||||
|
||||
if (reaction) {
|
||||
const deleteEvent = createEvent(DELETE, {
|
||||
tags: [["k", String(reaction.kind)], ...tagEvent(reaction)],
|
||||
})
|
||||
|
||||
publishThunk(makeThunk({event: deleteEvent, relays: [url]}))
|
||||
publishDelete({relays: [url], event: reaction})
|
||||
} else {
|
||||
createReaction(content)
|
||||
publishReaction({
|
||||
event,
|
||||
content,
|
||||
relays: [url],
|
||||
tags: [[ROOM, room, url]],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const onEmoji = (emoji: NativeEmoji) => createReaction(emoji.unicode)
|
||||
let drawer: SvelteComponent
|
||||
|
||||
$: parentPubkey = $parentEvent?.pubkey || replies[0]?.[4]
|
||||
$: parentProfile = deriveProfile(parentPubkey || "")
|
||||
@@ -108,7 +104,11 @@
|
||||
!isPending && !isPublished && findStatus($ps, [PublishStatus.Failure, PublishStatus.Timeout])
|
||||
</script>
|
||||
|
||||
<div in:fly class="group relative flex flex-col gap-1 p-2 transition-colors hover:bg-base-300">
|
||||
<div
|
||||
in:fly
|
||||
class="group relative flex flex-col gap-1 p-2 transition-colors"
|
||||
class:hover:bg-base-300={!isReply}
|
||||
class:mt-4={isReply}>
|
||||
{#if event.kind === REPLY}
|
||||
<div class="flex items-center gap-1 pl-12 text-xs">
|
||||
<Icon icon="arrow-right" />
|
||||
@@ -168,12 +168,22 @@
|
||||
{/if}
|
||||
<div
|
||||
class="join absolute -top-2 right-0 border border-solid border-neutral text-xs opacity-0 transition-all group-hover:opacity-100">
|
||||
<button class="btn join-item btn-xs">
|
||||
<Icon icon="reply" size={4} />
|
||||
</button>
|
||||
<ChatMessageEmojiButton onEmoji={onEmoji} />
|
||||
{#if !isReply}
|
||||
<button class="btn join-item btn-xs" on:click={() => drawer.open()}>
|
||||
<Icon icon="reply" size={4} />
|
||||
</button>
|
||||
{/if}
|
||||
<ChatMessageEmojiButton {url} {room} {event} />
|
||||
<button class="btn join-item btn-xs">
|
||||
<Icon icon="menu-dots" size={4} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if !isReply}
|
||||
<Drawer bind:this={drawer}>
|
||||
<svelte:self {...$$props} isReply />
|
||||
<ChatMessageReplies {url} {room} {event} />
|
||||
<ChatMessageReply {url} {room} {event} />
|
||||
</Drawer>
|
||||
{/if}
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
<script lang="ts">
|
||||
import tippy, {type Instance} from "tippy.js"
|
||||
import type {Emoji} from 'emoji-picker-element/shared'
|
||||
import type {NativeEmoji} from 'emoji-picker-element/shared'
|
||||
import {between} from '@welshman/lib'
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import Tippy from "@lib/components/Tippy.svelte"
|
||||
import EmojiPicker from "@lib/components/EmojiPicker.svelte"
|
||||
import {ROOM} from '@app/state'
|
||||
import {publishReaction} from '@app/commands'
|
||||
|
||||
export let onEmoji
|
||||
export let url, room, event
|
||||
|
||||
const open = () => popover.show()
|
||||
|
||||
const onClick = (emoji: Emoji) => {
|
||||
onEmoji(emoji)
|
||||
const onClick = (emoji: NativeEmoji) => {
|
||||
publishReaction({
|
||||
event,
|
||||
relays: [url],
|
||||
content: emoji.unicode,
|
||||
tags: [[ROOM, room, url]],
|
||||
})
|
||||
|
||||
popover.hide()
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
hi
|
||||
@@ -0,0 +1 @@
|
||||
hi
|
||||
@@ -0,0 +1,38 @@
|
||||
<script lang="ts">
|
||||
import {randomId} from '@welshman/lib'
|
||||
import Icon from '@lib/components/Icon.svelte'
|
||||
|
||||
const id = randomId()
|
||||
|
||||
let input: any
|
||||
let label: any
|
||||
|
||||
export const open = () => {
|
||||
if (!input.checked) {
|
||||
label.click()
|
||||
}
|
||||
}
|
||||
|
||||
export const close = () => {
|
||||
if (input.checked) {
|
||||
label.click()
|
||||
}
|
||||
}
|
||||
|
||||
export const toggle = () => {
|
||||
label.click()
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="drawer drawer-end">
|
||||
<input {id} type="checkbox" class="drawer-toggle" bind:this={input} />
|
||||
<div class="drawer-content">
|
||||
<label for={id} bind:this={label} />
|
||||
</div>
|
||||
<div class="drawer-side z-modal">
|
||||
<label for={id} aria-label="close sidebar" class="drawer-overlay"></label>
|
||||
<div class="menu bg-base-200 text-base-content min-h-full w-80">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user