diff --git a/package.json b/package.json
index c0cc5de..200d5e8 100644
--- a/package.json
+++ b/package.json
@@ -13,8 +13,8 @@
},
"devDependencies": {
"@iconify/svelte": "^4.0.2",
- "@sveltejs/adapter-node": "^5.2.9",
"@sveltejs/adapter-auto": "^3.3.1",
+ "@sveltejs/adapter-node": "^5.2.9",
"@sveltejs/kit": "^2.9.0",
"@sveltejs/vite-plugin-svelte": "^4.0.2",
"prettier": "^3.4.1",
@@ -30,6 +30,8 @@
"@nostr-dev-kit/ndk": "^2.10.7",
"@nostr-dev-kit/ndk-cache-dexie": "^2.5.8",
"@nostr-dev-kit/ndk-svelte": "^2.3.2",
+ "dompurify": "^3.2.3",
+ "marked": "^15.0.4",
"qrcode": "^1.5.4"
}
}
diff --git a/src/components/LoginWithNostr.svelte b/src/components/LoginWithNostr.svelte
index 4fa02b0..f237ff9 100644
--- a/src/components/LoginWithNostr.svelte
+++ b/src/components/LoginWithNostr.svelte
@@ -169,8 +169,43 @@
Continue
{/if}
{:else}
+
+
+
+ A Better Way to Email
+
+
+
+ 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.
+
+
+
+
+
+ Ready to try a better kind of email? Join us and take control of your communications!
+
+
Login with Nostr Extension
- isLoggingIn = true}>Login with Nsec
+ (isLoggingIn = true)}>Login with Nsec
+
+
+
+
+
+ 👀 What's Next? Even Better Privacy
+
+
+ Want to see something really cool? Check out Eve - our upcoming Closed Community Networks project.
+ We can't say much yet, but if you're into maximum privacy and love having community, you'll want to watch this
+ space.
+ Take a peek at arx-ccn.com if you're curious.
+
+
+
+
+ Made by Arx - Making Privacy Simple
+
{/if}
diff --git a/src/lib/style/layout.css b/src/lib/style/layout.css
index 5353156..efe6aa9 100644
--- a/src/lib/style/layout.css
+++ b/src/lib/style/layout.css
@@ -138,30 +138,31 @@ h3 {
.section-title {
position: fixed;
display: flex;
- width: calc(100%);
+ width: 100%;
margin: calc(var(--spacing-md) * -1);
padding: var(--spacing-md);
- background: var(--ternary);
- border: 1px solid var(--accent);
z-index: 99999;
- border-top-left-radius: 16px;
- border-top-right-radius: 16px;
- place-content: center;
+ place-content: center;
align-items: center;
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 {
position: absolute;
top: var(--spacing-md);
- right: calc(
- var(--spacing-md) * 2 + 1.5rem
- );
+ right: calc(var(--spacing-md) * 2 + 1.5rem);
}
& + * {
- margin-top: calc(
- 1.5rem +
- var(--spacing-md) * 3
- );
+ margin-top: calc(1.5rem + var(--spacing-md) * 3);
}
}
diff --git a/src/lib/style/typography.css b/src/lib/style/typography.css
index ec6b470..b2a55b9 100644
--- a/src/lib/style/typography.css
+++ b/src/lib/style/typography.css
@@ -1,11 +1,50 @@
p.error {
- color: oklch(60% 50% 35);
- font-weight: 700;
- font-size: 0.9rem;
- text-align: center;
- text-shadow: -1.5px -1.5px 0 oklch(15% 10% 35),
- 1.5px -1.5px 0 oklch(15% 10% 35),
- -1.5px 1.5px 0 oklch(15% 10% 35),
- 1.5px 1.5px 0 oklch(15% 10% 35);
- letter-spacing: 1px;
+ color: oklch(60% 50% 35);
+ font-weight: 700;
+ font-size: 0.9rem;
+ text-align: center;
+ text-shadow: -1.5px -1.5px 0 oklch(15% 10% 35), 1.5px -1.5px 0
+ oklch(15% 10% 35), -1.5px 1.5px 0 oklch(15% 10% 35), 1.5px 1.5px 0
+ oklch(15% 10% 35);
+ 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);
+}
\ No newline at end of file
diff --git a/src/routes/letters/[id]/+page.svelte b/src/routes/letters/[id]/+page.svelte
index 482a5a4..f15add4 100644
--- a/src/routes/letters/[id]/+page.svelte
+++ b/src/routes/letters/[id]/+page.svelte
@@ -8,6 +8,8 @@
import { Letter } from '$lib/letter';
import Dialog from '../../../components/Dialog.svelte';
import AnimatedQRCode from '../../../components/AnimatedQRCode.svelte';
+ import DOMPurify from 'dompurify';
+ import * as marked from 'marked';
const { data } = $props();
const { id } = data;
@@ -18,7 +20,7 @@
let stampDialogOpen = $state(false);
onMount(async () => {
- let letterEvent = await $ndk.fetchEvent(id);
+ const letterEvent = await $ndk.fetchEvent(id);
if (!letterEvent) {
loading = false;
error = 'Error fetching letter';
@@ -28,12 +30,15 @@
if (!(letter instanceof Letter)) {
error = 'Message is not a letter';
loading = false;
+ return;
}
+ renderedContent = DOMPurify.sanitize(await marked.parse(letter.content, {
+ async: true
+ }));
loading = false;
});
$inspect(letter);
-
function handleReply() {
if (!letter) return;
const params = {
@@ -49,6 +54,8 @@
const url = `/compose?${queryString}`;
goto(url);
}
+
+ let renderedContent = $state('loading...');
{#if loading}
@@ -117,7 +124,7 @@
-
{letter.content}
+ {@html renderedContent}
{/if}