[Style]: CSS update

This commit is contained in:
ClaraCrazy 2025-12-26 00:58:57 +01:00
parent 1f45db1886
commit 2f9491aeee
No known key found for this signature in database
GPG key ID: EBBC896ACB497011
6 changed files with 434 additions and 89 deletions

View file

@ -359,7 +359,25 @@ class ImapService extends EventEmitter {
return false return false
} else if (!raw) { } else if (!raw) {
const fullBody = await _.find(messages[0].parts, { which: '' }) const fullBody = await _.find(messages[0].parts, { which: '' })
return simpleParser(fullBody.body) if (!fullBody || !fullBody.body) {
throw new Error('Unable to find message body')
}
try {
// Try to parse the email, fallback to raw if parsing fails
const bodyString = fullBody.body.toString()
return await simpleParser(bodyString)
} catch (parseError) {
debug('Failed to parse email, returning raw data:', parseError.message)
// Return raw data as fallback
return {
subject: 'Unable to parse email',
text: fullBody.body.toString(),
html: `<pre>${fullBody.body.toString()}</pre>`,
from: { text: 'Unknown' },
to: { text: to },
date: new Date()
}
}
} else { } else {
return messages[0].parts[1].body return messages[0].parts[1].body
} }

View file

@ -1,7 +1,7 @@
body { body {
margin: 0; margin: 0;
min-height: 100vh; min-height: 100vh;
padding: 20px 20px 0; padding: 20px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background: linear-gradient( 135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.02)), #131516; background: linear-gradient( 135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.02)), #131516;
@ -21,6 +21,13 @@ main {
/* keep footer at the bottom */ /* keep footer at the bottom */
} }
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
a { a {
color: #cccccc; color: #cccccc;
} }
@ -52,9 +59,10 @@ p {
} }
iframe { iframe {
background-color: #1D2021; /* background-color: #1D2021; */
color: white; background-color: white;
width: 80%; min-width: 75%;
max-width: 1500px;
height: 60vh; height: 60vh;
margin: 2rem auto; margin: 2rem auto;
display: block; display: block;
@ -93,24 +101,42 @@ text-muted {
.action-links a { .action-links a {
display: inline-block; display: inline-block;
margin-bottom: 0.5rem; padding: 12px 24px;
padding: 10px 16px; border-radius: 15px;
border-radius: 16px; font-size: 1rem;
text-align: center; font-weight: 600;
background: rgba(155, 77, 202, 0.2); text-transform: uppercase;
border: 1px solid rgba(155, 77, 202, 0.35); letter-spacing: 0.5px;
color: #fff; transition: all 0.3s ease;
border: 1px solid rgba(255, 255, 255, 0.15);
backdrop-filter: blur(10px);
position: relative;
overflow: hidden;
text-decoration: none; text-decoration: none;
backdrop-filter: blur(12px) saturate(120%); color: #e0e0e0;
-webkit-backdrop-filter: blur(12px) saturate(120%); }
box-shadow: 0 5px 15px rgba(155, 77, 202, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.08);
transition: transform 0.2s ease, background 0.2s ease; .action-links a::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
transition: left 0.5s;
}
.action-links a:hover::before {
left: 100%;
} }
.action-links a:hover { .action-links a:hover {
background: rgba(155, 77, 202, 0.3); transform: translateY(-3px);
transform: translateY(-2px); box-shadow: 0 8px 25px rgba(155, 77, 202, 0.4);
box-shadow: 0 8px 20px rgba(155, 77, 202, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.12); border-color: rgba(155, 77, 202, 0.3);
text-decoration: none;
color: #ffffff;
} }
@ -233,4 +259,286 @@ select:hover {
label { label {
display: inline; display: inline;
}
/* Modern Inbox Styles */
.inbox-container {
min-width: 75%;
max-width: 1500px;
margin: 0 auto;
padding: 0 20px;
}
.inbox-header {
text-align: center;
margin-bottom: 30px;
}
.inbox-title {
background: linear-gradient(135deg, #9b4dca, #b366e6, #6c5ce7);
font-size: 2.8rem;
font-weight: 300;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin: 0;
text-shadow: 0 2px 10px rgba(155, 77, 202, 0.3);
}
.emails-container {
padding-top: 10px;
display: flex;
flex-direction: column;
gap: 20px;
max-height: 62vh;
overflow-y: auto;
overflow-x: hidden;
background: transparent;
border: 2px solid rgba(155, 77, 202, 0.3);
border-radius: 15px;
padding: 20px;
/* Hide scrollbar */
scrollbar-width: none;
-ms-overflow-style: none;
}
.emails-container::-webkit-scrollbar {
display: none;
}
.email-link {
text-decoration: none;
transition: all 0.3s ease;
display: block;
}
.email-link:hover {
transform: translateY(-4px);
}
.email-card {
backdrop-filter: blur(20px);
border-radius: 18px;
border: 1px solid rgba(255, 255, 255, 0.08);
padding: 24px;
transition: all 0.4s ease;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
position: relative;
overflow: hidden;
}
.email-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
opacity: 0;
transition: opacity 0.3s ease;
}
.email-card:hover::before {
opacity: 1;
}
.email-card:hover {
box-shadow: 0 15px 50px rgba(155, 77, 202, 0.15);
transform: translateY(-2px);
}
.email-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 16px;
}
.email-sender {
display: flex;
flex-direction: column;
gap: 6px;
}
.sender-name {
font-weight: 600;
font-size: 1.35rem;
color: #ffffff;
line-height: 1.2;
}
.sender-email {
font-size: 1rem;
color: #888;
opacity: 0.8;
}
.email-date {
font-size: 0.85rem;
color: #666;
white-space: nowrap;
opacity: 0.7;
}
.email-subject {
font-size: 1.25rem;
color: #e0e0e0;
line-height: 1.5;
font-weight: 400;
}
.empty-state {
display: flex;
justify-content: center;
align-items: center;
min-height: 400px;
}
.empty-card {
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(20px);
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.08);
padding: 50px;
text-align: center;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3);
max-width: 400px;
}
.empty-card h3 {
color: #9b4dca;
margin-bottom: 20px;
font-weight: 400;
font-size: 2.2rem;
}
.empty-card p {
color: #888;
font-size: 1.3rem;
opacity: 0.9;
line-height: 1.5;
}
/* Modern Mail View Styles */
.mail-container {
min-width: 75%;
max-width: 1500px;
margin: 0 auto;
padding: 20px 20px;
}
.mail-header {
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(20px);
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.08);
padding: 30px;
margin-bottom: 30px;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
}
.mail-subject {
font-size: 2.2rem;
font-weight: 300;
margin: 0 0 20px 0;
color: #ffffff;
line-height: 1.3;
}
.mail-meta {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 15px;
}
.mail-from {
font-size: 1.1rem;
color: #b366e6;
font-weight: 500;
}
.mail-date {
font-size: 0.95rem;
color: #888;
opacity: 0.8;
}
.mail-content {
background: rgba(255, 255, 255, 0.02);
backdrop-filter: blur(15px);
border-radius: 18px;
border: 1px solid rgba(255, 255, 255, 0.06);
padding: 30px;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
margin-bottom: 30px;
}
.mail-html-content iframe {
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
width: 100%;
height: 60vh;
backdrop-filter: blur(10px);
}
.mail-text-content {
color: #e0e0e0;
line-height: 1.6;
font-size: 1rem;
white-space: pre-wrap;
word-wrap: break-word;
}
.mail-empty-content {
text-align: center;
color: #888;
font-style: italic;
padding: 40px;
}
.mail-attachments {
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(20px);
border-radius: 18px;
border: 1px solid rgba(255, 255, 255, 0.08);
padding: 25px;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
}
.mail-attachments h4 {
color: #9b4dca;
margin: 0 0 20px 0;
font-weight: 400;
font-size: 1.4rem;
}
.attachments-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.attachment-link {
color: #b366e6;
text-decoration: none;
padding: 12px 16px;
border-radius: 12px;
background: rgba(155, 77, 202, 0.1);
border: 1px solid rgba(155, 77, 202, 0.2);
transition: all 0.3s ease;
display: inline-block;
max-width: fit-content;
}
.attachment-link:hover {
background: rgba(155, 77, 202, 0.15);
border-color: rgba(155, 77, 202, 0.3);
transform: translateX(5px);
text-decoration: none;
} }

View file

@ -1,34 +1,45 @@
{% extends 'layout.twig' %} {% extends 'layout.twig' %}
{% block body %} {% block header %}
<script src="/javascripts/inbox-init.js" defer data-address="{{ address }}"></script>
<div class="action-links"> <div class="action-links">
<a href="/inbox/{{ address }}/delete-all">Wipe Inbox</a> <a href="/inbox/{{ address }}/delete-all">Wipe Inbox</a>
<a href="/logout">Logout</a> <a href="/logout">Logout</a>
</div> </div>
<h1>{{ address }}</h1> {% endblock %}
{% for mail in mailSummaries %}
<a href="{{ mail.to[0] }}/{{ mail.uid }}" class="no-link-color"> {% block body %}
<blockquote class="email"> <script src="/javascripts/inbox-init.js" defer data-address="{{ address }}"></script>
<h6 class="list-group-item-heading">
{{ mail.from[0].name }} <div class="inbox-container">
<span class="text-muted">{{ mail.from[0].address }}</span> <div class="inbox-header">
<small class="float-right">{{ mail.date |date }}</small> <h1 class="inbox-title">{{ address }}</h1>
</h6> </div>
<p class="list-group-item-text text-truncate" style="width: 75%">
{{ mail.subject }} </p> <div class="emails-container">
{% for mail in mailSummaries %}
<a href="{{ mail.to[0] }}/{{ mail.uid }}" class="email-link">
<div class="email-card">
<div class="email-header">
<div class="email-sender">
<div class="sender-name">{{ mail.from[0].name }}</div>
<div class="sender-email">{{ mail.from[0].address }}</div>
</div>
<div class="email-date">{{ mail.date | date }}</div>
</div>
<div class="email-subject">{{ mail.subject }}</div>
</div>
</a>
{% endfor %}
{% if not mailSummaries %}
<div class="empty-state">
<div class="empty-card">
<h3>Inbox Empty</h3>
<p>Your emails will appear here once they arrive.</p>
</div>
</div> </div>
{% endif %}
</blockquote> </div>
</a> </div>
{% endfor %}
{% if not mailSummaries %}
<blockquote>
There are no mails yet.
</blockquote>
{% endif %}
{% endblock %} {% endblock %}

View file

@ -18,9 +18,12 @@
</head> </head>
<body> <body>
<main> <main>
<a href="/"> <div class="header">
<img src="/images/logo.png" class="logo" style="max-width: 75px"> <a href="/">
</a> <img src="/images/logo.png" class="logo" style="max-width: 75px">
</a>
{% block header %}{% endblock %}
</div>
{% block body %}{% endblock %} {% block body %}{% endblock %}
</main> </main>

View file

@ -1,10 +1,12 @@
{% extends 'layout.twig' %} {% extends 'layout.twig' %}
{% block body %} {% block header %}
<div class="action-links">
<a href="/inbox/{{ example }}">Example Inbox</a>
</div>
{% endblock %}
<div class="action-links"> {% block body %}
<a href="/inbox/{{ example }}">Example Inbox</a>
</div>
<div id="login"> <div id="login">
<h1>Welcome!</h1> <h1>Welcome!</h1>
<h4>Here you can either create a new Inbox, or access your old one</h4> <h4>Here you can either create a new Inbox, or access your old one</h4>

View file

@ -1,49 +1,52 @@
{% extends 'layout.twig' %} {% extends 'layout.twig' %}
{% block body %} {% block header %}
<div class="action-links"> <div class="action-links">
<a href="/inbox/{{ address }}">← Return to inbox</a> <a href="/inbox/{{ address }}">← Return to inbox</a>
<a href="/inbox/{{ address }}/{{ uid }}/delete">Delete Email</a> <a href="/inbox/{{ address }}/{{ uid }}/delete">Delete Email</a>
<a href="/inbox/{{ address }}/{{ uid }}/raw" target="_blank">View Raw</a> <a href="/inbox/{{ address }}/{{ uid }}/raw" target="_blank">View Raw</a>
<a href="/logout">Logout</a> <a href="/logout">Logout</a>
</div> </div>
<hr> {% endblock %}
<div class="mail_body" style="padding-left:10%;">
<h3 style="text-align:left;"> {% block body %}
{{ mail.subject }} <div class="mail-container">
<span style="float:right; padding-right:10vw;" > <div class="mail-header">
From: {{ mail.from.text }} at {{ mail.date| date }} <h1 class="mail-subject">{{ mail.subject }}</h1>
</span> <div class="mail-meta">
</h3> <div class="mail-from">From: {{ mail.from.text }}</div>
<div class="mail-date">{{ mail.date | date }}</div>
</div>
</div>
<div class="mail-content">
{% if mail.html %}
<div class="mail-html-content">
<iframe sandbox="allow-popups allow-popups-to-escape-sandbox" csp="script-src 'none'" srcdoc='{{ mail.html }}'></iframe>
</div>
{% elseif mail.textAsHtml %}
<div class="mail-text-content">
{{ mail.textAsHtml|raw }}
</div>
{% else %}
<div class="mail-empty-content">
<p>No content available</p>
</div>
{% endif %}
</div>
{% if mail.attachments %}
<div class="mail-attachments">
<h4>Attachments</h4>
<div class="attachments-list">
{% for attachment in mail.attachments %}
<a href="/inbox/{{ address }}/{{ uid }}/{{ attachment.checksum }}" class="attachment-link">
📎 {{ attachment.filename }}
</a>
{% endfor %}
</div>
</div>
{% endif %}
</div> </div>
{% if mail.html %}
<div>
{# TODO:
Find a better solution for this monstrocity.
Replaces clean html tag with styled one for readabbility.
Realistically, the entire iFrame or even website itself might be vulnerable.
srcdoc='html' seems like a very, very unsafe method to me, unfortunately I havent found a better solution.
#}
<iframe sandbox="allow-popups allow-popups-to-escape-sandbox" csp="script-src 'none'" srcdoc='{{ mail.html|replace({'<html>': '<html style="color: white"'}) }}'></iframe>
</div>
{% elseif mail.textAsHtml %}
<div class="mail_body">
{{ mail.textAsHtml|raw }}
</div>
{% else %}
<div class="mail_body"></div>
{% endif %}
{% if mail.attachments %}
<div class="mail_attachments" >
<p>
{% for attachment in mail.attachments %}
<a href="/inbox/{{ address }}/{{ uid }}/{{ attachment.checksum }}"><u>📎 {{ attachment.filename }}</u></a>
{% endfor %}
</p>
</div>
{% endif %}
{% endblock %} {% endblock %}