clean up code and ui

- IconButton component
- make FoldersListSidebar a separate component from the index page
- make move letter to folder better looking
- clean up code on index page
This commit is contained in:
Danny Morabito 2024-11-29 14:09:41 +01:00
parent 4b528e07a6
commit 6ee0809661
Signed by: dannym
GPG key ID: 7CC8056A5A04557E
6 changed files with 204 additions and 102 deletions

View file

@ -0,0 +1,93 @@
<script lang="ts">
import Icon from '@iconify/svelte';
import IconButton from './IconButton.svelte';
import Dialog from './Dialog.svelte';
import { createFolder } from '$lib/utils.svelte';
let { sidebarOpen = $bindable(), folders = $bindable(), changeFolder } = $props<{
sidebarOpen: boolean;
folders: { id: string; name: string; icon: string }[];
changeFolder: (folder: string) => void;
}>();
let isAddingFolder = $state(false);
let newFolderName = $state('');
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 = '';
}
</script>
<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="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>
{#if folder.id === 'trash'}
<hr />
{/if}
{/each}
<IconButton icon="eos-icons:plus" onclick={() => isAddingFolder = true} text="Add Folder" />
</div>
</div>
<style>
.sidebar-container {
width: 0;
overflow: hidden;
transition: width 0.3s ease-in-out;
&.open {
width: clamp(16rem, 20vw, 20rem);
}
}
.folder-item {
display: flex;
align-items: center;
gap: var(--spacing-sm);
}
.sidebar {
display: flex;
gap: var(--spacing-sm);
flex-direction: column;
height: 100%;
}
</style>

View file

@ -0,0 +1,30 @@
<script lang="ts">
import Icon from '@iconify/svelte';
import { goto } from '$app/navigation';
let { icon, text, href, onclick } = $props<{
icon: string;
text: string;
onclick?: () => void;
href?: string;
}>();
if (href)
onclick = () => {
goto(href);
};
</script>
<button class="button" onclick={onclick}>
<Icon icon={icon} />
{text}
</button>
<style>
.button {
display: flex;
align-items: center;
gap: var(--spacing-sm);
cursor: pointer;
}
</style>

View file

@ -7,6 +7,7 @@
import Select from './Select.svelte';
import type { Letter } from '$lib/letter';
import { slide } from 'svelte/transition';
import IconButton from './IconButton.svelte';
let {
letters,
@ -117,7 +118,10 @@
<a in:slide out:slide class="letter-item" href="/letters/{letter.id}">
<div class="subject-line">
<div class="letter-subject">
<Icon icon="mdi:letter-outline" /> {letter.subject}
{#if !letter.emailAddress}
<img src="/nostr-lock.svg" width="32" />
{/if}
{letter.subject}
</div>
{#if letter.stamps}
<div class="stamps-count">
@ -152,7 +156,9 @@
<Dialog
bind:open={moveFolderDialogOpen}
>
<div class="title">
<h3>Move Letters to Folder</h3>
</div>
<p class="text-secondary">Select a folder to move the selected letters to:</p>
<Select bind:value={moveFolderName} label="Select folder" options={
@ -200,9 +206,7 @@
</h2>
<div class="actions">
<button onclick={() => moveFolderDialogOpen = true}>
<Icon icon="mdi:folder-move-outline" />
</button>
<IconButton icon="mdi:folder-move-outline" onclick={() => moveFolderDialogOpen = true} text="Move Letters" />
</div>
<main class="letter-list">

View file

@ -3,6 +3,7 @@
import LoginWithNostr from '../components/LoginWithNostr.svelte';
import { onMount } from 'svelte';
import { NDKNip07Signer } from '@nostr-dev-kit/ndk';
import IconButton from '../components/IconButton.svelte';
onMount(async () => {
if (localStorage.getItem('useNip07')) {
@ -20,7 +21,7 @@
<header id="header">
<nav class="actions">
{#if $activeUser}
<a class="button" href="/compose">Compose</a>
<IconButton icon="proicons:compose" text="Compose" href="/compose" />
{/if}
</nav>
@ -28,7 +29,7 @@
<nav class="actions">
{#if $activeUser}
<a class="button" href="/settings">Settings</a>
<IconButton icon="si:settings-cute-line" text="Settings" href="/settings" />
{/if}
</nav>
</header>

View file

@ -2,12 +2,13 @@
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 { 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 type { NDKEvent, NDKEventId } from '@nostr-dev-kit/ndk';
import { LetterToFolderMapping } from '$lib/letterToFolderMapping';
import IconButton from '../components/IconButton.svelte';
import FoldersListSidebar from '../components/FoldersListSidebar.svelte';
let sidebarOpen = $state(false);
@ -29,7 +30,7 @@
{ id: 'trash', name: 'Trash', icon: 'eos-icons:trash' }
]);
async function decryptMessages(messages) {
async function decryptMessages(messages: NDKEvent[]) {
const currentMessages = messages;
const decryptedFolders = [
{ id: 'inbox', name: 'Inbox', icon: 'solar:inbox-bold-duotone' },
@ -67,81 +68,24 @@
return !allLettersInFolders.includes(letter.id);
if (!letterLabels.has(activeFolder))
return false;
return letterLabels.get(activeFolder).includes(letter.id);
return letterLabels.get(activeFolder)!.includes(letter.id);
});
folders = decryptedFolders;
}
messages.subscribe(m => decryptMessages(m));
messages.subscribe((m: NDKEvent) => decryptMessages(m));
function changeFolder(newFolder) {
function changeFolder(newFolder: string) {
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>
<IconButton icon="mynaui:sidebar-solid" onclick={() => sidebarOpen = !sidebarOpen} text="Sidebar" />
<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>
<FoldersListSidebar bind:folders bind:sidebarOpen {changeFolder} />
<div class="folder-view">
{#if letters.length === 0}
@ -157,41 +101,12 @@
</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>

59
static/nostr-lock.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.2 KiB