197 lines
No EOL
5.2 KiB
Svelte
197 lines
No EOL
5.2 KiB
Svelte
<script lang="ts">
|
|
import { ndk } from '$lib/stores.svelte';
|
|
import Icon from '@iconify/svelte';
|
|
import MailboxFolderItems from '../components/MailboxFolderItems.svelte';
|
|
import { createFolder, decryptSealedMessageIntoReadableType } from '$lib/utils.svelte';
|
|
import { Letter } from '$lib/letter';
|
|
import Dialog from '../components/Dialog.svelte';
|
|
import { FolderLabel } from '$lib/folderLabel';
|
|
import type { NDKEventId } from '@nostr-dev-kit/ndk';
|
|
import { LetterToFolderMapping } from '$lib/letterToFolderMapping';
|
|
|
|
let sidebarOpen = $state(false);
|
|
|
|
let messages = $ndk.storeSubscribe([{
|
|
kinds: [1059],
|
|
'#p': [$ndk.activeUser.pubkey]
|
|
}], {
|
|
closeOnEose: false,
|
|
groupable: false,
|
|
groupableDelay: 0
|
|
});
|
|
|
|
let letters = $state<Letter[]>([]);
|
|
let activeFolder = $state('inbox');
|
|
|
|
let folders = $state([
|
|
{ id: 'inbox', name: 'Inbox', icon: 'solar:inbox-bold-duotone' },
|
|
{ id: 'sent', name: 'Sent', icon: 'fa:send' },
|
|
{ id: 'trash', name: 'Trash', icon: 'eos-icons:trash' }
|
|
]);
|
|
|
|
async function decryptMessages(messages) {
|
|
const currentMessages = messages;
|
|
const decryptedFolders = [
|
|
{ id: 'inbox', name: 'Inbox', icon: 'solar:inbox-bold-duotone' },
|
|
{ id: 'sent', name: 'Sent', icon: 'fa:send' },
|
|
{ id: 'trash', name: 'Trash', icon: 'formkit:trash' }
|
|
];
|
|
const allLetters = [];
|
|
let allLettersInFolders: NDKEventId[] = [];
|
|
const letterLabels = new Map<string, NDKEventId[]>();
|
|
for (const message of currentMessages) {
|
|
const msg = await decryptSealedMessageIntoReadableType(message);
|
|
if ((msg instanceof Letter)) {
|
|
allLetters.push(msg);
|
|
} else if (msg instanceof FolderLabel) {
|
|
decryptedFolders.push(msg);
|
|
} else if (msg instanceof LetterToFolderMapping) {
|
|
if (!letterLabels.has(msg.folder))
|
|
letterLabels.set(msg.folder, []);
|
|
for (const folderId of letterLabels.keys()) {
|
|
// check if letter is in a folder, if so remove it and move it to the new folder
|
|
if (letterLabels.get(folderId)!.includes(msg.message)) {
|
|
letterLabels.get(folderId)!.splice(letterLabels.get(folderId)!.indexOf(msg.message), 1);
|
|
break;
|
|
}
|
|
}
|
|
allLettersInFolders.push(msg.message);
|
|
letterLabels.set(msg.folder, letterLabels.get(msg.folder)!.concat(msg.message));
|
|
}
|
|
}
|
|
|
|
letters = allLetters.filter(letter => {
|
|
if (activeFolder === 'sent')
|
|
return letter.from.pubkey === $ndk.activeUser.pubkey;
|
|
if (activeFolder === 'inbox' && letter.from.pubkey !== $ndk.activeUser.pubkey)
|
|
return !allLettersInFolders.includes(letter.id);
|
|
if (!letterLabels.has(activeFolder))
|
|
return false;
|
|
return letterLabels.get(activeFolder).includes(letter.id);
|
|
});
|
|
folders = decryptedFolders;
|
|
}
|
|
|
|
messages.subscribe(m => decryptMessages(m));
|
|
|
|
function changeFolder(newFolder) {
|
|
letters = [];
|
|
activeFolder = newFolder;
|
|
decryptMessages($messages);
|
|
}
|
|
|
|
async function addNewFolderPressed() {
|
|
const newFolder = await createFolder(newFolderName, '');
|
|
if (!newFolder) return;
|
|
await newFolder.publish();
|
|
folders = [...folders, { id: newFolder.id, name: newFolderName, icon: 'eos-icons:plus' }];
|
|
newFolderName = '';
|
|
isAddingFolder = false;
|
|
}
|
|
|
|
function newFolderDialogClosed() {
|
|
isAddingFolder = false;
|
|
newFolderName = '';
|
|
}
|
|
|
|
let isAddingFolder = $state(false);
|
|
let newFolderName = $state('');
|
|
</script>
|
|
|
|
<button class="sidebar-button" onclick={() => sidebarOpen = !sidebarOpen}>
|
|
<Icon icon="mynaui:sidebar-solid" />
|
|
</button>
|
|
|
|
<Dialog
|
|
bind:open={isAddingFolder}
|
|
onClose={newFolderDialogClosed}
|
|
>
|
|
<div class="title">
|
|
<h3>Create Folder</h3>
|
|
</div>
|
|
<p class="text-secondary">Please enter a name for the new folder:</p>
|
|
|
|
<form onsubmit={addNewFolderPressed}>
|
|
<input
|
|
autofocus
|
|
bind:value={newFolderName}
|
|
placeholder="Folder name"
|
|
type="text"
|
|
/>
|
|
|
|
<div class="button-group">
|
|
<button onclick={newFolderDialogClosed} type="button">Cancel</button>
|
|
<button type="submit">OK</button>
|
|
</div>
|
|
</form>
|
|
</Dialog>
|
|
|
|
<div class="content">
|
|
<div class="sidebar-container" class:open={sidebarOpen}>
|
|
<div class="glass sidebar">
|
|
{#each folders as folder}
|
|
<button class="folder-item" onclick={() => changeFolder(folder.id)}>
|
|
<Icon icon={folder.icon} />
|
|
{folder.name}
|
|
</button>
|
|
{/each}
|
|
<hr />
|
|
<button class="folder-item" onclick={() => isAddingFolder = true}>
|
|
<Icon icon="eos-icons:plus" />
|
|
Add Folder
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="folder-view">
|
|
{#if letters.length === 0}
|
|
<Icon icon="eos-icons:loading" width="5em" />
|
|
<br />
|
|
<p>
|
|
If you have letters, they will appear here, please wait...
|
|
</p>
|
|
{:else}
|
|
<MailboxFolderItems foldersList={folders} folder={folders.find(f => f.id === activeFolder)} {letters} />
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.folder-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--spacing-sm);
|
|
}
|
|
|
|
.sidebar-button {
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
}
|
|
|
|
.content {
|
|
display: flex;
|
|
gap: var(--spacing-sm);
|
|
}
|
|
|
|
.sidebar-container {
|
|
width: 0;
|
|
overflow: hidden;
|
|
transition: width 0.3s ease-in-out;
|
|
|
|
&.open {
|
|
width: clamp(16rem, 20vw, 20rem);
|
|
}
|
|
}
|
|
|
|
.folder-view {
|
|
flex-grow: 1;
|
|
}
|
|
|
|
.sidebar {
|
|
display: flex;
|
|
gap: var(--spacing-sm);
|
|
flex-direction: column;
|
|
height: 100%;
|
|
}
|
|
</style> |