Compare commits
No commits in common. "d0b52d9c38d2b714b58ee19524b71ec70c186a97" and "e6dfd840c966acb1c2b9c305ef217221e82198e6" have entirely different histories.
d0b52d9c38
...
e6dfd840c9
2 changed files with 5 additions and 110 deletions
|
|
@ -54,32 +54,11 @@ else
|
||||||
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 { 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 ".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 ".sun { display: none; } .dark .sun { display: inline; } .dark .moon { display: none; }"
|
||||||
echo ".attachments { margin-top: 25px; border: 1px solid var(--border); border-radius: 12px; overflow: hidden; }"
|
|
||||||
echo ".attachments-header { padding: 12px 20px; background: var(--header-bg); cursor: pointer; font-weight: 500; color: var(--muted); }"
|
|
||||||
echo ".attachments-header:hover { background: var(--border); }"
|
|
||||||
echo ".attachments-content { display: none; padding: 15px; background: var(--bg); }"
|
|
||||||
echo ".attachments-content.show { display: flex; flex-wrap: wrap; gap: 15px; }"
|
|
||||||
echo ".attachment { background: var(--header-bg); border-radius: 8px; padding: 10px; text-align: center; min-width: 120px; border: 1px solid var(--border); }"
|
|
||||||
echo ".attachment img { max-width: 200px; max-height: 150px; object-fit: contain; margin: 0; }"
|
|
||||||
echo ".attachment-name { margin: 8px 0 0; font-size: 0.85em; color: var(--muted); word-break: break-all; }"
|
|
||||||
echo ".attachment-icon { font-size: 2em; display: block; margin-bottom: 5px; }"
|
|
||||||
echo ".attachment img { cursor: pointer; transition: transform 0.2s; }"
|
|
||||||
echo ".attachment img:hover { transform: scale(1.05); }"
|
|
||||||
echo ".lightbox { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.9); z-index: 1000; justify-content: center; align-items: center; cursor: zoom-out; }"
|
|
||||||
echo ".lightbox.show { display: flex; }"
|
|
||||||
echo ".lightbox img { max-width: 95%; max-height: 95%; object-fit: contain; border-radius: 8px; box-shadow: 0 4px 30px rgba(0,0,0,0.5); }"
|
|
||||||
echo ".lightbox-close { position: fixed; top: 20px; right: 20px; color: white; font-size: 30px; cursor: pointer; background: rgba(0,0,0,0.5); width: 44px; height: 44px; border-radius: 50%; display: flex; align-items: center; justify-content: center; }"
|
|
||||||
echo ".lightbox-close:hover { background: rgba(0,0,0,0.8); }"
|
|
||||||
echo "</style></head><body>"
|
echo "</style></head><body>"
|
||||||
echo '<div class="lightbox" onclick="closeLightbox()"><span class="lightbox-close">×</span><img id="lightbox-img" src="" alt=""></div>'
|
|
||||||
echo '<button class="toggle" onclick="toggleTheme()" title="Toggle theme"><span class="moon">☾</span><span class="sun">☀</span></button>'
|
echo '<button class="toggle" onclick="toggleTheme()" title="Toggle theme"><span class="moon">☾</span><span class="sun">☀</span></button>'
|
||||||
echo "<script>"
|
echo "<script>"
|
||||||
echo "function toggleTheme() { document.documentElement.classList.toggle('dark'); }"
|
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 "function toggleQuote(el) { var c = el.nextElementSibling; c.classList.toggle('show'); el.textContent = c.classList.contains('show') ? '▼ Hide quoted text' : '▶ Show quoted text'; }"
|
||||||
echo "function toggleAttachments(el) { var c = el.nextElementSibling; c.classList.toggle('show'); var n = el.textContent.match(/\\d+/)[0]; el.textContent = c.classList.contains('show') ? '▼ Attachments (' + n + ')' : '▶ Attachments (' + n + ')'; }"
|
|
||||||
echo "function openLightbox(src) { document.getElementById('lightbox-img').src = src; document.querySelector('.lightbox').classList.add('show'); document.body.style.overflow = 'hidden'; }"
|
|
||||||
echo "function closeLightbox() { document.querySelector('.lightbox').classList.remove('show'); document.body.style.overflow = ''; }"
|
|
||||||
echo "document.addEventListener('keydown', function(e) { if (e.key === 'Escape') closeLightbox(); });"
|
|
||||||
echo "</script>"
|
echo "</script>"
|
||||||
|
|
||||||
# Extract and display headers (handles multi-line headers)
|
# Extract and display headers (handles multi-line headers)
|
||||||
|
|
@ -214,72 +193,8 @@ else
|
||||||
quotebuf = quotebuf $0
|
quotebuf = quotebuf $0
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
function linkify(line, result, pos, url, email, before, after, linktext) {
|
|
||||||
result = line
|
|
||||||
# First: Handle email<mailto:email> pattern - keep only one email as link
|
|
||||||
while (match(result, /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}<mailto:[^&]*>/)) {
|
|
||||||
before = substr(result, 1, RSTART-1)
|
|
||||||
# Extract just the email part (before <mailto:)
|
|
||||||
pos = index(substr(result, RSTART), "<mailto:")
|
|
||||||
email = substr(result, RSTART, pos-1)
|
|
||||||
after = substr(result, RSTART+RLENGTH)
|
|
||||||
result = before "<a href=\"mailto:" email "\">" email "</a>" after
|
|
||||||
}
|
|
||||||
# Second: Handle standalone <mailto:email>
|
|
||||||
while (match(result, /<mailto:[^&]+>/)) {
|
|
||||||
before = substr(result, 1, RSTART-1)
|
|
||||||
email = substr(result, RSTART+11, RLENGTH-15)
|
|
||||||
after = substr(result, RSTART+RLENGTH)
|
|
||||||
result = before "<a href=\"mailto:" email "\">" email "</a>" after
|
|
||||||
}
|
|
||||||
# Third: Handle text<https://url> - text becomes link text
|
|
||||||
while (match(result, /[A-Za-z0-9_-]+<https?:\/\/[^&]+>/)) {
|
|
||||||
before = substr(result, 1, RSTART-1)
|
|
||||||
full = substr(result, RSTART, RLENGTH)
|
|
||||||
# Find where < starts
|
|
||||||
pos = index(full, "<")
|
|
||||||
linktext = substr(full, 1, pos-1)
|
|
||||||
# Extract URL: after < (4 chars) until > (4 chars at end)
|
|
||||||
url = substr(full, pos+4, length(full)-pos-7)
|
|
||||||
after = substr(result, RSTART+RLENGTH)
|
|
||||||
result = before "<a href=\"" url "\" target=\"_blank\">" linktext "</a>" after
|
|
||||||
}
|
|
||||||
# Fourth: Handle standalone <https://url>
|
|
||||||
while (match(result, /<https?:\/\/[^&]+>/)) {
|
|
||||||
before = substr(result, 1, RSTART-1)
|
|
||||||
url = substr(result, RSTART+4, RLENGTH-8)
|
|
||||||
after = substr(result, RSTART+RLENGTH)
|
|
||||||
result = before "<a href=\"" url "\" target=\"_blank\">" url "</a>" after
|
|
||||||
}
|
|
||||||
# Fifth: Handle plain URLs (not already in href)
|
|
||||||
while (match(result, /https?:\/\/[^ &<>"\n\t]+/)) {
|
|
||||||
before = substr(result, 1, RSTART-1)
|
|
||||||
if (before ~ /href="$/) break
|
|
||||||
url = substr(result, RSTART, RLENGTH)
|
|
||||||
after = substr(result, RSTART+RLENGTH)
|
|
||||||
# Clean trailing punctuation
|
|
||||||
sub(/[.,;:!?)]+$/, "", url)
|
|
||||||
result = before "<a href=\"" url "\" target=\"_blank\">" url "</a>" after
|
|
||||||
}
|
|
||||||
# Sixth: Handle [cid:image] inline images
|
|
||||||
while (match(result, /\[cid:[^\]]+\]/)) {
|
|
||||||
before = substr(result, 1, RSTART-1)
|
|
||||||
# Extract image name from cid reference
|
|
||||||
cid = substr(result, RSTART+5, RLENGTH-6)
|
|
||||||
after = substr(result, RSTART+RLENGTH)
|
|
||||||
# Extract just the filename part (before @)
|
|
||||||
if (match(cid, /@/)) {
|
|
||||||
imgname = substr(cid, 1, RSTART-1)
|
|
||||||
} else {
|
|
||||||
imgname = cid
|
|
||||||
}
|
|
||||||
result = before "<img src=\"" imgname "\" alt=\"" imgname "\" style=\"max-width:100%;height:auto;\">" after
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
flush_quote()
|
flush_quote()
|
||||||
# HTML escape first
|
|
||||||
gsub(/</, "\\<")
|
gsub(/</, "\\<")
|
||||||
gsub(/>/, "\\>")
|
gsub(/>/, "\\>")
|
||||||
if (!incode) {
|
if (!incode) {
|
||||||
|
|
@ -290,8 +205,6 @@ else
|
||||||
after = substr($0, RSTART+RLENGTH)
|
after = substr($0, RSTART+RLENGTH)
|
||||||
$0 = before "<code>" code "</code>" after
|
$0 = before "<code>" code "</code>" after
|
||||||
}
|
}
|
||||||
# Linkify URLs and emails
|
|
||||||
$0 = linkify($0)
|
|
||||||
}
|
}
|
||||||
print
|
print
|
||||||
}
|
}
|
||||||
|
|
@ -302,28 +215,10 @@ else
|
||||||
'
|
'
|
||||||
echo "</div>"
|
echo "</div>"
|
||||||
|
|
||||||
# Show attachments in collapsible section
|
# Show extracted images
|
||||||
attachments=$(find "$tmpdir" -maxdepth 1 -type f \( -iname "*.png" -o -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.gif" -o -iname "*.pdf" -o -iname "*.doc*" -o -iname "*.xls*" -o -iname "*.zip" -o -iname "*.tar*" \) 2>/dev/null)
|
find "$tmpdir" -maxdepth 1 -type f \( -iname "*.png" -o -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.gif" \) 2>/dev/null | while read -r img; do
|
||||||
if [[ -n $attachments ]]; then
|
echo "<p><img src=\"$(basename "$img")\"></p>"
|
||||||
count=$(echo "$attachments" | wc -l | tr -d ' ')
|
done
|
||||||
echo '<div class="attachments">'
|
|
||||||
echo "<div class=\"attachments-header\" onclick=\"toggleAttachments(this)\">▶ Attachments ($count)</div>"
|
|
||||||
echo '<div class="attachments-content">'
|
|
||||||
echo "$attachments" | while read -r file; do
|
|
||||||
basename=$(basename "$file")
|
|
||||||
ext="${basename##*.}"
|
|
||||||
ext_lower=$(echo "$ext" | tr '[:upper:]' '[:lower:]')
|
|
||||||
case "$ext_lower" in
|
|
||||||
png | jpg | jpeg | gif)
|
|
||||||
echo "<div class=\"attachment\"><img src=\"$basename\" alt=\"$basename\" onclick=\"openLightbox('$basename')\"><p class=\"attachment-name\">$basename</p></div>"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "<div class=\"attachment\"><span class=\"attachment-icon\">📎</span><p class=\"attachment-name\">$basename</p></div>"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
echo "</div></div>"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "</body></html>"
|
echo "</body></html>"
|
||||||
} >"$tmpfile"
|
} >"$tmpfile"
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ bind editor ^T complete
|
||||||
|
|
||||||
# Pager
|
# Pager
|
||||||
bind index,pager V edit-raw-message
|
bind index,pager V edit-raw-message
|
||||||
macro index,pager H "<pipe-message>~/dotfiles/bin/view-email-html<enter><clear-flag>N<sync-mailbox>" "View email in browser"
|
macro index,pager H "<pipe-message>~/dotfiles/bin/view-email-html<enter>" "View email in browser"
|
||||||
bind pager c imap-fetch-mail
|
bind pager c imap-fetch-mail
|
||||||
bind pager j next-line
|
bind pager j next-line
|
||||||
bind pager k previous-line
|
bind pager k previous-line
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue