✨ 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:
parent
4966a3ac45
commit
77a9a6842b
6 changed files with 127 additions and 43 deletions
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
place-content: center;
|
||||||
border-top-right-radius: 16px;
|
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue