diff options
| author | Adrien Hopkins <[email protected]> | 2026-01-09 09:00:32 -0500 |
|---|---|---|
| committer | Adrien Hopkins <[email protected]> | 2026-01-09 09:00:32 -0500 |
| commit | 9175c76d7f03c0c62323202fdab3e4ab35854855 (patch) | |
| tree | 6195dc3eac3c55fbd84cd32f34077dab10ec7ac5 | |
| parent | 4bc94247c382898c0e0d76439fe0bdce68755d69 (diff) | |
| download | coinos-ui-9175c76d7f03c0c62323202fdab3e4ab35854855.tar.gz coinos-ui-9175c76d7f03c0c62323202fdab3e4ab35854855.zip | |
Hide muted chats
| -rw-r--r-- | src/lib/nip51.ts | 47 | ||||
| -rw-r--r-- | src/locales/en.json | 2 | ||||
| -rw-r--r-- | src/routes/(app)/dm/+page.svelte | 24 |
3 files changed, 69 insertions, 4 deletions
diff --git a/src/lib/nip51.ts b/src/lib/nip51.ts new file mode 100644 index 00000000..142f0bbf --- /dev/null +++ b/src/lib/nip51.ts @@ -0,0 +1,47 @@ +import { SimplePool } from 'nostr-tools/pool'; +const pool = new SimplePool(); + +import { PUBLIC_DM_RELAYS } from '$env/static/public'; +const DM_RELAYS_LIST = PUBLIC_DM_RELAYS.split(','); + +// export const mute = async (pubkey: string, hidden: bool) => { + +// } + +// export const unmute = async (pubkey: string) => { + +// } + +export const mutedAccounts = async (user: object): Set<string> => { + const { shown, hidden } = await getMuteLists(user); + let muted = new Set<string>(); + for (const pubkey of shown) { + muted.add(pubkey); + } + for (const pubkey of hidden) { + muted.add(pubkey); + } + return muted; +} + +const getMuteLists = async (user: object): object => { + const listEvents = await pool.querySync( + DM_RELAYS_LIST, { kinds: [10000], "authors": [user.pubkey], limit: 1 } + ); + if (listEvents.length == 0) { + return { shown: [], hidden: [] }; + } + + let shown = []; + for (const tag of listEvents[0].tags) { + if (tag.length >= 2 && tag[0] == "p") { + shown.push(tag[1]); + } + } + + return { shown, hidden: [] }; +} + +// const publishMuteList = async (shown: Array<string>, hidden: Array<string>) => { + +// } diff --git a/src/locales/en.json b/src/locales/en.json index e7b8a90f..16e60d1f 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -102,6 +102,8 @@ "findByPubkey": "Find by pubkey", "recipientMsg": "You are sending nostr messages to [R].", "sendMessage": "Send Message", + "mute": "Mute", + "unmute": "Unmute", "expiry": "Enable message expiry", "cantSendExpiring": "None of [R]'s DM relays support message expiry. You can't send expiring messages to them.", "fadedWarning": "To avoid metadata leaks, messages expire at a random time up to 2 days after you specify; each message has its own random expiry time. Messages which appear faded are close to expiring; nearby messages may be missing.", diff --git a/src/routes/(app)/dm/+page.svelte b/src/routes/(app)/dm/+page.svelte index 32b39def..336733e0 100644 --- a/src/routes/(app)/dm/+page.svelte +++ b/src/routes/(app)/dm/+page.svelte @@ -10,6 +10,7 @@ import { getMessageRumours } from '$lib/nip17'; import * as libnip17 from '$lib/nip17'; import { npubEncode, decode } from 'nostr-tools/nip19'; + import { mutedAccounts } from '$lib/nip51'; import { sign, getPrivateKey, pTagKeys } from '$lib/nostr'; import { t } from "$lib/translations"; import { theme } from "$lib/store"; @@ -17,6 +18,9 @@ let { data } = $props(); const { user } = data; + let muted = $state(new Set<string>()); + mutedAccounts(user).then((m) => muted = m); + /// chat selection const usernameFromPubkey = async (pubkey: string): string => { const response = await fetch(`/api/users/${pubkey}`); @@ -129,9 +133,18 @@ let canSendExpiring = $state(false); let nostrUserInfo = $state({}); + const includesPubkey = (chats: object[], pubkey: string) => { + for (const c of chats) { + if (c.pubkey === pubkey) { + return true; + } + } + return false; + } + const selectChat = (c: object) => { selectedChat = c; - if (!chats.includes(c)) { + if (!includesPubkey(chats, c.pubkey)) { chats.unshift(c); } userInfo(selectedChat.pubkey).then(info => nostrUserInfo = info); @@ -394,9 +407,11 @@ {/if} {#if !creatingNewChat} {#each chats as c} - <button class={"chat-btn tall-btn " + ($theme === "light" ? "light-chat-btn" : "dark-chat-btn") + (selectedChat && selectedChat.pubkey == c.pubkey ? ($theme === "light" ? " light-selected" : " dark-selected") : "")} on:click={() => selectChat(c)}> - <span class="text-xl">{name(c)}</span> <span class={(idValid(c) ? "" : "invalid ") + "secondary text-xs"}>{id(c)}</span> - </button> + {#if (selectedChat && selectedChat.pubkey === c.pubkey) || !(muted && muted.has(c.pubkey))} + <button class={"chat-btn tall-btn " + ($theme === "light" ? "light-chat-btn" : "dark-chat-btn") + (selectedChat && selectedChat.pubkey == c.pubkey ? ($theme === "light" ? " light-selected" : " dark-selected") : "")} on:click={() => selectChat(c)}> + <span class="{"text-xl" + (muted && muted.has(c.pubkey) ? " secondary" : "")}">{name(c)}</span> <span class={(idValid(c) ? "" : "invalid ") + "secondary text-xs"}>{id(c)}</span> + </button> + {/if} {/each} {:else if searchQuery !== ""} <button class={"chat-btn tall-btn " + ($theme === "light" ? "light-chat-btn" : "dark-chat-btn")} on:click={() => selectChatUsername(searchQuery)}> @@ -427,6 +442,7 @@ <span class="text-3xl">{name(selectedChat)}</span> {/if} <span class={"secondary timestamp text-small" + (idValid(selectedChat) ? "" : " invalid")} title="{npubEncode(selectedChat.pubkey)}">{id(selectedChat)}</span> + <!-- <button class="push-right">{$t(muted && muted.has(selectedChat.pubkey) ? "dm.unmute" : "dm.mute")}</button> --> </h1> <div id="messages" style="overflow-y: scroll; max-height: 600px;"> |
