Rename chats/channels

This commit is contained in:
Jon Staab
2024-10-03 14:43:17 -07:00
parent eab4b35077
commit d956e5ac4a
7 changed files with 91 additions and 91 deletions
@@ -27,8 +27,8 @@
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Avatar from "@lib/components/Avatar.svelte" import Avatar from "@lib/components/Avatar.svelte"
import Content from "@app/components/Content.svelte" import Content from "@app/components/Content.svelte"
import ChatThread from '@app/components/ChatThread.svelte' import ChannelThread from '@app/components/ChannelThread.svelte'
import ChatMessageEmojiButton from "@app/components/ChatMessageEmojiButton.svelte" import ChannelMessageEmojiButton from "@app/components/ChannelMessageEmojiButton.svelte"
import {tagRoom, REPLY, deriveEvent, displayReaction} from "@app/state" import {tagRoom, REPLY, deriveEvent, displayReaction} from "@app/state"
import {publishDelete, publishReaction} from "@app/commands" import {publishDelete, publishReaction} from "@app/commands"
import {pushModal} from '@app/modal' import {pushModal} from '@app/modal'
@@ -78,7 +78,7 @@
const openThread = () => { const openThread = () => {
const root = $rootEvent || event const root = $rootEvent || event
pushModal(ChatThread, {url, room, event: root}, {drawer: true}) pushModal(ChannelThread, {url, room, event: root}, {drawer: true})
} }
const onReactionClick = (content: string, events: TrustedEvent[]) => { const onReactionClick = (content: string, events: TrustedEvent[]) => {
@@ -175,7 +175,7 @@
<button <button
class="join absolute -top-2 right-0 border border-solid border-neutral text-xs opacity-0 transition-all group-hover:opacity-100" class="join absolute -top-2 right-0 border border-solid border-neutral text-xs opacity-0 transition-all group-hover:opacity-100"
on:click|stopPropagation> on:click|stopPropagation>
<ChatMessageEmojiButton {url} {room} {event} /> <ChannelMessageEmojiButton {url} {room} {event} />
<button class="btn join-item btn-xs"> <button class="btn join-item btn-xs">
<Icon icon="menu-dots" size={4} /> <Icon icon="menu-dots" size={4} />
</button> </button>
@@ -4,8 +4,8 @@
import type {EventContent, TrustedEvent} from '@welshman/util' import type {EventContent, TrustedEvent} from '@welshman/util'
import {repository, makeThunk, publishThunk} from '@welshman/app' import {repository, makeThunk, publishThunk} from '@welshman/app'
import {deriveEvents} from '@welshman/store' import {deriveEvents} from '@welshman/store'
import ChatMessage from '@app/components/ChatMessage.svelte' import ChannelMessage from '@app/components/ChannelMessage.svelte'
import ChatCompose from '@app/components/ChatCompose.svelte' import ChannelCompose from '@app/components/ChannelCompose.svelte'
import {tagRoom, REPLY} from '@app/state' import {tagRoom, REPLY} from '@app/state'
export let url, room, event: TrustedEvent export let url, room, event: TrustedEvent
@@ -45,12 +45,12 @@
<div class="fixed flex flex-col max-h-screen w-full gap-2"> <div class="fixed flex flex-col max-h-screen w-full gap-2">
<div class="overflow-auto pt-3"> <div class="overflow-auto pt-3">
<ChatMessage {url} {room} {event} showPubkey /> <ChannelMessage {url} {room} {event} showPubkey />
{#each sortBy(e => e.created_at, $replies) as reply (reply.id)} {#each sortBy(e => e.created_at, $replies) as reply (reply.id)}
<ChatMessage {url} {room} event={reply} showPubkey hideParent /> <ChannelMessage {url} {room} event={reply} showPubkey hideParent />
{/each} {/each}
</div> </div>
<div class="bottom-0 left-0 right-0"> <div class="bottom-0 left-0 right-0">
<ChatCompose {onSubmit} /> <ChannelCompose {onSubmit} />
</div> </div>
</div> </div>
+73 -73
View File
@@ -155,12 +155,12 @@ export const {
// Messages // Messages
export type ChatMessage = { export type ChannelMessage = {
room: string room: string
event: TrustedEvent event: TrustedEvent
} }
export const readMessage = (event: TrustedEvent): Maybe<ChatMessage> => { export const readMessage = (event: TrustedEvent): Maybe<ChannelMessage> => {
const rooms = event.tags.filter(nthEq(0, ROOM)).map(nth(1)) const rooms = event.tags.filter(nthEq(0, ROOM)).map(nth(1))
if (rooms.length > 1) return undefined if (rooms.length > 1) return undefined
@@ -168,88 +168,40 @@ export const readMessage = (event: TrustedEvent): Maybe<ChatMessage> => {
return {room: rooms[0] || "", event} return {room: rooms[0] || "", event}
} }
export const chatMessages = deriveEventsMapped<ChatMessage>(repository, { export const channelMessages = deriveEventsMapped<ChannelMessage>(repository, {
filters: [{kinds: [MESSAGE, REPLY]}], filters: [{kinds: [MESSAGE, REPLY]}],
eventToItem: readMessage, eventToItem: readMessage,
itemToEvent: item => item.event, itemToEvent: item => item.event,
}) })
// Chats
export type Chat = {
id: string
url: string
room: string
messages: ChatMessage[]
}
export const makeChatId = (url: string, room: string) => `${url}'${room}`
export const splitChatId = (id: string) => id.split("'")
export const chats = derived([trackerStore, chatMessages], ([$tracker, $chatMessages]) => {
const messagesByChatId = new Map<string, ChatMessage[]>()
for (const message of $chatMessages) {
for (const url of $tracker.getRelays(message.event.id)) {
const chatId = makeChatId(url, message.room)
pushToMapKey(messagesByChatId, chatId, message)
}
}
return Array.from(messagesByChatId.entries()).map(([id, messages]) => {
const [url, room] = splitChatId(id)
return {id, url, room, messages}
})
})
export const {
indexStore: chatsById,
deriveItem: deriveChat,
loadItem: loadChat,
} = collection({
name: "chats",
store: chats,
getKey: chat => chat.id,
load: (id: string, request: Partial<SubscribeRequestWithHandlers> = {}) => {
const [url, room] = splitChatId(id)
const chat = get(chatsById).get(id)
const timestamps = chat?.messages.map(m => m.event.created_at) || []
const since = Math.max(0, max(timestamps) - 3600)
return load({...request, relays: [url], filters: [{"#~": [room], since}]})
},
})
// Channels // Channels
export const channelMessages = deriveEvents(repository, {filters: [{kinds: [DIRECT_MESSAGE]}]})
export type Channel = { export type Channel = {
id: string id: string
pubkeys: string[] url: string
messages: TrustedEvent[] room: string
messages: ChannelMessage[]
} }
export const makeChannelId = (pubkeys: string[]) => sort(uniq(pubkeys)).join(",") export const makeChannelId = (url: string, room: string) => `${url}'${room}`
export const splitChannelId = (id: string) => id.split(",") export const splitChannelId = (id: string) => id.split("'")
export const channels = derived(channelMessages, $messages => { export const channels = derived([trackerStore, channelMessages], ([$tracker, $channelMessages]) => {
const messagesByChannelId = new Map<string, TrustedEvent[]>() const messagesByChannelId = new Map<string, ChannelMessage[]>()
for (const message of $messages) { for (const message of $channelMessages) {
const channelId = makeChannelId(getPubkeyTagValues(message.tags)) for (const url of $tracker.getRelays(message.event.id)) {
const channelId = makeChannelId(url, message.room)
pushToMapKey(messagesByChannelId, channelId, message) pushToMapKey(messagesByChannelId, channelId, message)
}
} }
return Array.from(messagesByChannelId.entries()).map(([id, messages]): Channel => { return Array.from(messagesByChannelId.entries()).map(([id, messages]) => {
const pubkeys = splitChannelId(id) const [url, room] = splitChannelId(id)
return {id, pubkeys, messages} return {id, url, room, messages}
}) })
}) })
@@ -261,11 +213,59 @@ export const {
name: "channels", name: "channels",
store: channels, store: channels,
getKey: channel => channel.id, getKey: channel => channel.id,
load: async (id: string, request: Partial<SubscribeRequestWithHandlers> = {}) => { load: (id: string, request: Partial<SubscribeRequestWithHandlers> = {}) => {
const $pubkey = pubkey.get()
const [url, room] = splitChannelId(id) const [url, room] = splitChannelId(id)
const channel = get(channelsById).get(id) const channel = get(channelsById).get(id)
const timestamps = channel?.messages.map(e => e.created_at) || [] const timestamps = channel?.messages.map(m => m.event.created_at) || []
const since = Math.max(0, max(timestamps) - 3600)
return load({...request, relays: [url], filters: [{"#~": [room], since}]})
},
})
// Encrypted Chats
export const chatMessages = deriveEvents(repository, {filters: [{kinds: [DIRECT_MESSAGE]}]})
export type Chat = {
id: string
pubkeys: string[]
messages: TrustedEvent[]
}
export const makeChatId = (pubkeys: string[]) => sort(uniq(pubkeys)).join(",")
export const splitChatId = (id: string) => id.split(",")
export const chats = derived(chatMessages, $messages => {
const messagesByChatId = new Map<string, TrustedEvent[]>()
for (const message of $messages) {
const chatId = makeChatId(getPubkeyTagValues(message.tags))
pushToMapKey(messagesByChatId, chatId, message)
}
return Array.from(messagesByChatId.entries()).map(([id, messages]): Chat => {
const pubkeys = splitChatId(id)
return {id, pubkeys, messages}
})
})
export const {
indexStore: chatsById,
deriveItem: deriveChat,
loadItem: loadChat,
} = collection({
name: "chats",
store: chats,
getKey: chat => chat.id,
load: async (id: string, request: Partial<SubscribeRequestWithHandlers> = {}) => {
const $pubkey = pubkey.get()
const [url, room] = splitChatId(id)
const chat = get(chatsById).get(id)
const timestamps = chat?.messages.map(e => e.created_at) || []
const since = Math.max(0, max(timestamps) - 3600) const since = Math.max(0, max(timestamps) - 3600)
if ($pubkey) { if ($pubkey) {
@@ -329,12 +329,12 @@ export const threadsByUrl = derived([trackerStore, notes], ([$tracker, $notes])
// Rooms // Rooms
export const roomsByUrl = derived(chats, $chats => { export const roomsByUrl = derived(channels, $channels => {
const $roomsByUrl = new Map<string, string[]>() const $roomsByUrl = new Map<string, string[]>()
for (const chat of $chats) { for (const channel of $channels) {
if (chat.room) { if (channel.room) {
pushToMapKey($roomsByUrl, chat.url, chat.room) pushToMapKey($roomsByUrl, channel.url, channel.room)
} }
} }
+2 -2
View File
@@ -6,7 +6,7 @@
import SecondaryNavItem from "@lib/components/SecondaryNavItem.svelte" import SecondaryNavItem from "@lib/components/SecondaryNavItem.svelte"
import SecondaryNavHeader from "@lib/components/SecondaryNavHeader.svelte" import SecondaryNavHeader from "@lib/components/SecondaryNavHeader.svelte"
import SecondaryNavSection from "@lib/components/SecondaryNavSection.svelte" import SecondaryNavSection from "@lib/components/SecondaryNavSection.svelte"
import {channels} from '@app/state' import {chats} from '@app/state'
</script> </script>
<SecondaryNav> <SecondaryNav>
@@ -34,7 +34,7 @@
</div> </div>
</SecondaryNavHeader> </SecondaryNavHeader>
</div> </div>
{#each $channels as {id, pubkeys}, i (id)} {#each $chats as {id, pubkeys}, i (id)}
<div in:fly={{delay: 200 + i * 50}}> <div in:fly={{delay: 200 + i * 50}}>
<SecondaryNavItem href="/home/{id}"> <SecondaryNavItem href="/home/{id}">
{id} {id}
@@ -18,14 +18,14 @@
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Spinner from "@lib/components/Spinner.svelte" import Spinner from "@lib/components/Spinner.svelte"
import Divider from "@lib/components/Divider.svelte" import Divider from "@lib/components/Divider.svelte"
import ChatMessage from "@app/components/ChatMessage.svelte" import ChannelMessage from "@app/components/ChannelMessage.svelte"
import ChatCompose from "@app/components/ChatCompose.svelte" import ChannelCompose from "@app/components/ChannelCompose.svelte"
import {userMembership, decodeNRelay, makeChatId, deriveChat, GENERAL, tagRoom, MESSAGE} from "@app/state" import {userMembership, decodeNRelay, makeChannelId, deriveChannel, GENERAL, tagRoom, MESSAGE} from "@app/state"
import {addRoomMembership, removeRoomMembership} from "@app/commands" import {addRoomMembership, removeRoomMembership} from "@app/commands"
const {nrelay, room = GENERAL} = $page.params const {nrelay, room = GENERAL} = $page.params
const url = decodeNRelay(nrelay) const url = decodeNRelay(nrelay)
const chat = deriveChat(makeChatId(url, room)) const channel = deriveChannel(makeChannelId(url, room))
const assertEvent = (e: any) => e as TrustedEvent const assertEvent = (e: any) => e as TrustedEvent
@@ -46,7 +46,7 @@
let previousDate let previousDate
let previousPubkey let previousPubkey
for (const {event} of sortBy(m => m.event.created_at, $chat?.messages || [])) { for (const {event} of sortBy(m => m.event.created_at, $channel?.messages || [])) {
const {id, pubkey, created_at} = event const {id, pubkey, created_at} = event
const date = formatTimestampAsDate(created_at) const date = formatTimestampAsDate(created_at)
@@ -102,7 +102,7 @@
<Divider>{value}</Divider> <Divider>{value}</Divider>
{:else} {:else}
<div in:fly> <div in:fly>
<ChatMessage {url} {room} event={assertEvent(value)} {showPubkey} /> <ChannelMessage {url} {room} event={assertEvent(value)} {showPubkey} />
</div> </div>
{/if} {/if}
{/each} {/each}
@@ -117,6 +117,6 @@
</p> </p>
</div> </div>
<div class="shadow-top-xl border-t border-solid border-base-100 bg-base-100"> <div class="shadow-top-xl border-t border-solid border-base-100 bg-base-100">
<ChatCompose {onSubmit} /> <ChannelCompose {onSubmit} />
</div> </div>
</div> </div>