view email html improvement
This commit is contained in:
parent
3baf8a5b81
commit
634083d3ae
1 changed files with 61 additions and 22 deletions
|
|
@ -29,27 +29,36 @@ else
|
|||
echo '<meta charset="utf-8">'
|
||||
echo "<script>if(window.matchMedia('(prefers-color-scheme:dark)').matches)document.documentElement.classList.add('dark');</script>"
|
||||
echo "<style>"
|
||||
echo ":root { --bg: #ffffff; --text: #000000; --header-bg: #f5f5f5; --link: #0066cc; }"
|
||||
echo ".dark { --bg: #1a1a1a; --text: #e0e0e0; --header-bg: #2d2d2d; --link: #6db3f2; }"
|
||||
echo "body { font-family: -apple-system, sans-serif; padding: 20px; max-width: 800px; margin: 0 auto; background: var(--bg); color: var(--text); transition: background 0.2s, color 0.2s; }"
|
||||
echo ":root { --bg: #fafafa; --text: #1a1a1a; --header-bg: #ffffff; --muted: #666666; --link: #0066cc; --border: #e0e0e0; --shadow: rgba(0,0,0,0.08); }"
|
||||
echo ".dark { --bg: #121212; --text: #e0e0e0; --header-bg: #1e1e1e; --muted: #999999; --link: #6db3f2; --border: #333333; --shadow: rgba(0,0,0,0.3); }"
|
||||
echo "body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; padding: 30px 20px; max-width: 800px; margin: 0 auto; background: var(--bg); color: var(--text); transition: all 0.2s ease; line-height: 1.5; }"
|
||||
echo "pre { white-space: pre-wrap; word-wrap: break-word; }"
|
||||
echo ".headers { background: var(--header-bg); padding: 15px; margin-bottom: 20px; border-radius: 5px; transition: background 0.2s; }"
|
||||
echo ".headers p { margin: 5px 0; }"
|
||||
echo ".headers ul { margin: 5px 0 10px 20px; padding: 0; }"
|
||||
echo ".headers li { margin: 2px 0; }"
|
||||
echo ".body { line-height: 1.6; white-space: pre-wrap; word-wrap: break-word; }"
|
||||
echo "code { background: var(--header-bg); padding: 2px 5px; border-radius: 3px; font-family: monospace; }"
|
||||
echo ".codeblock { background: var(--header-bg); padding: 15px; border-radius: 5px; overflow-x: auto; }"
|
||||
echo ".codeblock code { background: none; padding: 0; }"
|
||||
echo "img { max-width: 100%; height: auto; }"
|
||||
echo "a { color: var(--link); }"
|
||||
echo ".toggle { position: fixed; top: 10px; right: 10px; width: 40px; height: 40px; border: none; border-radius: 50%; cursor: pointer; background: var(--header-bg); color: var(--text); font-size: 20px; transition: background 0.2s; }"
|
||||
echo ".toggle:hover { opacity: 0.8; }"
|
||||
echo ".headers { background: var(--header-bg); padding: 20px 25px; margin-bottom: 25px; border-radius: 12px; border: 1px solid var(--border); box-shadow: 0 2px 8px var(--shadow); }"
|
||||
echo ".headers p { margin: 8px 0; display: grid; grid-template-columns: 70px 1fr; gap: 8px; align-items: baseline; }"
|
||||
echo ".headers strong { color: var(--muted); font-weight: 500; }"
|
||||
echo ".headers .addr-list { display: flex; flex-wrap: wrap; gap: 6px; }"
|
||||
echo ".headers .addr { padding: 4px 10px; background: var(--bg); border-radius: 6px; font-size: 0.95em; }"
|
||||
echo ".subject { font-weight: 600; color: var(--text); }"
|
||||
echo ".body { line-height: 1.7; white-space: pre-wrap; word-wrap: break-word; padding: 5px 0; }"
|
||||
echo ".quoted { margin: 10px 0; }"
|
||||
echo ".quoted-toggle { background: var(--bg); border: 1px solid var(--border); border-radius: 6px; padding: 6px 12px; cursor: pointer; font-size: 0.85em; color: var(--muted); display: inline-block; }"
|
||||
echo ".quoted-toggle:hover { background: var(--border); }"
|
||||
echo ".quoted-content { display: none; margin-top: 10px; padding: 10px 15px; border-left: 3px solid var(--border); color: var(--muted); font-size: 0.95em; white-space: pre-wrap; }"
|
||||
echo ".quoted-content.show { display: block; }"
|
||||
echo ".quote-line { color: var(--muted); }"
|
||||
echo "code { background: var(--header-bg); padding: 3px 7px; border-radius: 4px; font-family: 'SF Mono', Consolas, monospace; font-size: 0.9em; border: 1px solid var(--border); }"
|
||||
echo ".codeblock { background: var(--header-bg); padding: 18px; border-radius: 10px; overflow-x: auto; border: 1px solid var(--border); margin: 15px 0; }"
|
||||
echo ".codeblock code { background: none; padding: 0; border: none; }"
|
||||
echo "img { max-width: 100%; height: auto; border-radius: 8px; margin: 10px 0; box-shadow: 0 2px 12px var(--shadow); }"
|
||||
echo "a { color: var(--link); text-decoration: none; } a:hover { text-decoration: underline; }"
|
||||
echo ".toggle { position: fixed; top: 20px; right: 20px; width: 44px; height: 44px; border: 1px solid var(--border); border-radius: 50%; cursor: pointer; background: var(--header-bg); color: var(--text); font-size: 20px; transition: all 0.2s; box-shadow: 0 2px 8px var(--shadow); }"
|
||||
echo ".toggle:hover { transform: scale(1.05); box-shadow: 0 4px 12px var(--shadow); }"
|
||||
echo ".sun { display: none; } .dark .sun { display: inline; } .dark .moon { display: none; }"
|
||||
echo "</style></head><body>"
|
||||
echo '<button class="toggle" onclick="toggleTheme()" title="Toggle theme"><span class="moon">☾</span><span class="sun">☀</span></button>'
|
||||
echo "<script>"
|
||||
echo "function toggleTheme() { document.documentElement.classList.toggle('dark'); }"
|
||||
echo "function toggleQuote(el) { var c = el.nextElementSibling; c.classList.toggle('show'); el.textContent = c.classList.contains('show') ? '▼ Hide quoted text' : '▶ Show quoted text'; }"
|
||||
echo "</script>"
|
||||
|
||||
# Extract and display headers (handles multi-line headers)
|
||||
|
|
@ -108,13 +117,15 @@ else
|
|||
# Only split To, CC, Bcc addresses (not Date, Subject, From)
|
||||
if (tolower(header) ~ /^(to|cc|bcc)$/) {
|
||||
n = split_addresses(value, addrs)
|
||||
printf "<p><strong>" header ":</strong> <span class=\"addr-list\">"
|
||||
if (n > 1) {
|
||||
print "<p><strong>" header ":</strong></p><ul>"
|
||||
for (i=1; i<=n; i++) print "<li>" addrs[i] "</li>"
|
||||
print "</ul>"
|
||||
for (i=1; i<=n; i++) printf "<span class=\"addr\">" addrs[i] "</span>"
|
||||
} else {
|
||||
print "<p><strong>" header ":</strong> " value "</p>"
|
||||
printf "<span class=\"addr\">" value "</span>"
|
||||
}
|
||||
print "</span></p>"
|
||||
} else if (tolower(header) == "subject") {
|
||||
print "<p><strong>" header ":</strong> <span class=\"subject\">" value "</span></p>"
|
||||
} else {
|
||||
print "<p><strong>" header ":</strong> " value "</p>"
|
||||
}
|
||||
|
|
@ -150,15 +161,40 @@ else
|
|||
else
|
||||
body_content=$(sed '1,/^$/d' "$emlfile")
|
||||
fi
|
||||
# Process body: escape HTML, handle code blocks and inline code
|
||||
# Process body: escape HTML, handle code blocks, inline code, and quoted text
|
||||
# First pass: detect quote blocks (lines starting with > followed by more > lines)
|
||||
echo "$body_content" | awk '
|
||||
BEGIN { incode=0 }
|
||||
BEGIN { incode=0; inquote=0; quotebuf=""; quotecount=0 }
|
||||
function flush_quote() {
|
||||
if (quotebuf != "") {
|
||||
# Only make collapsible if we have 3+ quoted lines
|
||||
n = split(quotebuf, lines, "\n")
|
||||
if (n >= 3) {
|
||||
print "<div class=\"quoted\"><span class=\"quoted-toggle\" onclick=\"toggleQuote(this)\">▶ Show quoted text (" n " lines)</span><pre class=\"quoted-content\">"
|
||||
print quotebuf
|
||||
print "</pre></div>"
|
||||
} else {
|
||||
print "<span class=\"quote-line\">" quotebuf "</span>"
|
||||
}
|
||||
quotebuf = ""
|
||||
}
|
||||
}
|
||||
/^```/ {
|
||||
flush_quote()
|
||||
if (incode) { print "</code></pre>"; incode=0 }
|
||||
else { print "<pre class=\"codeblock\"><code>"; incode=1 }
|
||||
next
|
||||
}
|
||||
/^>/ {
|
||||
if (incode) { gsub(/</, "\\<"); gsub(/>/, "\\>"); print; next }
|
||||
gsub(/</, "\\<")
|
||||
gsub(/>/, "\\>")
|
||||
if (quotebuf != "") quotebuf = quotebuf "\n"
|
||||
quotebuf = quotebuf $0
|
||||
next
|
||||
}
|
||||
{
|
||||
flush_quote()
|
||||
gsub(/</, "\\<")
|
||||
gsub(/>/, "\\>")
|
||||
if (!incode) {
|
||||
|
|
@ -172,7 +208,10 @@ else
|
|||
}
|
||||
print
|
||||
}
|
||||
END { if (incode) print "</code></pre>" }
|
||||
END {
|
||||
flush_quote()
|
||||
if (incode) print "</code></pre>"
|
||||
}
|
||||
'
|
||||
echo "</div>"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue