Improve home page and letters functionality

- 📝 Add better product descriptions on the home page
- 🎨 Improve styles: fix title that looked "like a button" (reference #7)
- 🛠️ Render markdown for letters (fix #8)
- ⬆️ Update dependencies
This commit is contained in:
Danny Morabito 2024-12-21 21:27:38 +01:00
parent 4966a3ac45
commit 77a9a6842b
Signed by: dannym
GPG key ID: 7CC8056A5A04557E
6 changed files with 127 additions and 43 deletions

View file

@ -13,8 +13,8 @@
}, },
"devDependencies": { "devDependencies": {
"@iconify/svelte": "^4.0.2", "@iconify/svelte": "^4.0.2",
"@sveltejs/adapter-node": "^5.2.9",
"@sveltejs/adapter-auto": "^3.3.1", "@sveltejs/adapter-auto": "^3.3.1",
"@sveltejs/adapter-node": "^5.2.9",
"@sveltejs/kit": "^2.9.0", "@sveltejs/kit": "^2.9.0",
"@sveltejs/vite-plugin-svelte": "^4.0.2", "@sveltejs/vite-plugin-svelte": "^4.0.2",
"prettier": "^3.4.1", "prettier": "^3.4.1",
@ -30,6 +30,8 @@
"@nostr-dev-kit/ndk": "^2.10.7", "@nostr-dev-kit/ndk": "^2.10.7",
"@nostr-dev-kit/ndk-cache-dexie": "^2.5.8", "@nostr-dev-kit/ndk-cache-dexie": "^2.5.8",
"@nostr-dev-kit/ndk-svelte": "^2.3.2", "@nostr-dev-kit/ndk-svelte": "^2.3.2",
"dompurify": "^3.2.3",
"marked": "^15.0.4",
"qrcode": "^1.5.4" "qrcode": "^1.5.4"
} }
} }

View file

@ -169,8 +169,43 @@
<button onclick={nsecOk}>Continue</button> <button onclick={nsecOk}>Continue</button>
{/if} {/if}
{:else} {:else}
<section>
<h3>
<Icon icon="mdi:email-lock" width="32" />
A Better Way to Email
</h3>
<p>
Welcome to npub.email! We've created a new kind of email service that puts your privacy first.
Think of it like regular email, but with extra security and cool features built in.
</p>
</section>
<section>
<h3>Ready to try a better kind of email? Join us and take control of your communications!</h3>
<br />
<div class="button-group">
<button onclick={login}>Login with Nostr Extension</button> <button onclick={login}>Login with Nostr Extension</button>
<button onclick={() => isLoggingIn = true}>Login with Nsec</button> <button onclick={() => (isLoggingIn = true)}>Login with Nsec</button>
</div>
</section>
<section class="center">
<h3>
👀 What's Next? Even Better Privacy
</h3>
<p>
Want to see something really cool? Check out Eve - our upcoming Closed Community Networks project.<br />
We can't say much yet, but if you're into maximum privacy and love having community, you'll want to watch this
space.<br />
Take a peek at <a href="https://arx-ccn.com/">arx-ccn.com</a> if you're curious.
</p>
</section>
<section class="center">
<i>Made by Arx - Making Privacy Simple</i><br />
</section>
{/if} {/if}
<style> <style>

View file

@ -7,27 +7,27 @@
<NostrIdentifier user={recipient}> <NostrIdentifier user={recipient}>
{#snippet extraButtons()} {#snippet extraButtons()}
<span class="remove" on:click={onRemove}> <span class="remove" onclick={onRemove}>
<Icon icon="ph:x" /> <Icon icon="ph:x" />
</span> </span>
{/snippet} {/snippet}
</NostrIdentifier> </NostrIdentifier>
<style> <style>
.remove { .remove {
cursor: pointer; cursor: pointer;
opacity: 0.7; opacity: 0.7;
transition: opacity 0.2s ease; transition: opacity 0.2s ease;
width: 18px; width: 18px;
height: 18px; height: 18px;
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
border-radius: 50%; border-radius: 50%;
} }
.remove:hover { .remove:hover {
opacity: 1; opacity: 1;
background: rgba(255, 255, 255, 0.1); background: rgba(255, 255, 255, 0.1);
} }
</style> </style>

View file

@ -138,30 +138,31 @@ h3 {
.section-title { .section-title {
position: fixed; position: fixed;
display: flex; display: flex;
width: calc(100%); width: 100%;
margin: calc(var(--spacing-md) * -1); margin: calc(var(--spacing-md) * -1);
padding: var(--spacing-md); padding: var(--spacing-md);
background: var(--ternary);
border: 1px solid var(--accent);
z-index: 99999; z-index: 99999;
border-top-left-radius: 16px;
border-top-right-radius: 16px;
place-content: center; place-content: center;
align-items: center; align-items: center;
gap: var(--spacing-xs); gap: var(--spacing-xs);
font-size: 1.25rem;
font-weight: bold;
&:is(.dialog-content .section-title) {
background: var(--ternary);
border: 1px solid var(--accent);
border-top-left-radius: 16px;
border-bottom-left-radius: 16px;
}
> .close-button { > .close-button {
position: absolute; position: absolute;
top: var(--spacing-md); top: var(--spacing-md);
right: calc( right: calc(var(--spacing-md) * 2 + 1.5rem);
var(--spacing-md) * 2 + 1.5rem
);
} }
& + * { & + * {
margin-top: calc( margin-top: calc(1.5rem + var(--spacing-md) * 3);
1.5rem +
var(--spacing-md) * 3
);
} }
} }

View file

@ -1,11 +1,50 @@
p.error { p.error {
color: oklch(60% 50% 35); color: oklch(60% 50% 35);
font-weight: 700; font-weight: 700;
font-size: 0.9rem; font-size: 0.9rem;
text-align: center; text-align: center;
text-shadow: -1.5px -1.5px 0 oklch(15% 10% 35), text-shadow: -1.5px -1.5px 0 oklch(15% 10% 35), 1.5px -1.5px 0
1.5px -1.5px 0 oklch(15% 10% 35), oklch(15% 10% 35), -1.5px 1.5px 0 oklch(15% 10% 35), 1.5px 1.5px 0
-1.5px 1.5px 0 oklch(15% 10% 35), oklch(15% 10% 35);
1.5px 1.5px 0 oklch(15% 10% 35); letter-spacing: 1px;
letter-spacing: 1px; }
blockquote {
--hue: calc(var(--base-hue));
border-left: 2px solid oklch(50% 0.2 var(--hue));
margin: 0;
padding: 0;
padding-left: 1em;
}
:is(blockquote blockquote) {
--hue: calc(var(--base-hue) + 45);
}
:is(blockquote blockquote blockquote) {
--hue: calc(var(--base-hue) + 90);
}
:is(blockquote blockquote blockquote blockquote) {
--hue: calc(var(--base-hue) + 135);
}
:is(blockquote blockquote blockquote blockquote blockquote) {
--hue: calc(var(--base-hue) + 180);
}
:is(blockquote blockquote blockquote blockquote blockquote blockquote) {
--hue: calc(var(--base-hue) + 225);
}
:is(blockquote blockquote blockquote blockquote blockquote blockquote blockquote) {
--hue: calc(var(--base-hue) + 270);
}
:is(blockquote blockquote blockquote blockquote blockquote blockquote blockquote blockquote) {
--hue: calc(var(--base-hue) + 315);
}
:is(blockquote blockquote blockquote blockquote blockquote blockquote blockquote blockquote blockquote) {
--hue: var(--base-hue);
} }

View file

@ -8,6 +8,8 @@
import { Letter } from '$lib/letter'; import { Letter } from '$lib/letter';
import Dialog from '../../../components/Dialog.svelte'; import Dialog from '../../../components/Dialog.svelte';
import AnimatedQRCode from '../../../components/AnimatedQRCode.svelte'; import AnimatedQRCode from '../../../components/AnimatedQRCode.svelte';
import DOMPurify from 'dompurify';
import * as marked from 'marked';
const { data } = $props(); const { data } = $props();
const { id } = data; const { id } = data;
@ -18,7 +20,7 @@
let stampDialogOpen = $state(false); let stampDialogOpen = $state(false);
onMount(async () => { onMount(async () => {
let letterEvent = await $ndk.fetchEvent(id); const letterEvent = await $ndk.fetchEvent(id);
if (!letterEvent) { if (!letterEvent) {
loading = false; loading = false;
error = 'Error fetching letter'; error = 'Error fetching letter';
@ -28,12 +30,15 @@
if (!(letter instanceof Letter)) { if (!(letter instanceof Letter)) {
error = 'Message is not a letter'; error = 'Message is not a letter';
loading = false; loading = false;
return;
} }
renderedContent = DOMPurify.sanitize(await marked.parse(letter.content, {
async: true
}));
loading = false; loading = false;
}); });
$inspect(letter); $inspect(letter);
function handleReply() { function handleReply() {
if (!letter) return; if (!letter) return;
const params = { const params = {
@ -49,6 +54,8 @@
const url = `/compose?${queryString}`; const url = `/compose?${queryString}`;
goto(url); goto(url);
} }
let renderedContent = $state('loading...');
</script> </script>
{#if loading} {#if loading}
@ -117,7 +124,7 @@
</div> </div>
</div> </div>
<pre class="content">{letter.content}</pre> <pre class="content">{@html renderedContent}</pre>
</div> </div>
{/if} {/if}