- 左侧文件夹栏在小屏下变为底部导航条:收件箱/草稿箱/已发送/管理后台 + 居中「写信」悬浮圆钮(带未读角标) - 顶栏紧凑化:列表页搜索框自动下移为通栏第二行 - 邮件列表:隐藏正文摘要、缩小头像/时间列、行高加大便于触控,删除按钮常显 - 阅读页/写信页/设置页:内边距与字号收紧,配额条适配 - 管理后台:侧栏改为横向换行导航,表格横向滚动,统计卡两列排布 - 全部模板 viewport 增加 viewport-fit=cover(iOS 安全区),底部导航支持 env(safe-area-inset-bottom) - settings.html 内联样式改为 .settings-main 类以便响应式覆盖
155 lines
7.6 KiB
HTML
155 lines
7.6 KiB
HTML
{{define "drafts"}}
|
|
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
|
<title>草稿箱 - MailGo</title>
|
|
{{template "styles" .}}
|
|
</head>
|
|
<body class="page-list">
|
|
{{template "navbar" .}}
|
|
<div class="app-body">
|
|
{{template "sidebar" .}}
|
|
<main class="mail-main">
|
|
<div class="list-toolbar">
|
|
<label class="check-all" title="全选/取消全选">
|
|
<input type="checkbox" id="select-all">
|
|
全选
|
|
</label>
|
|
<button type="button" class="tb-btn" id="btn-refresh" title="刷新">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/></svg>
|
|
刷新
|
|
</button>
|
|
<button type="button" class="tb-btn danger" id="btn-delete" disabled>
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
|
删除
|
|
</button>
|
|
<div class="toolbar-spacer"></div>
|
|
<span class="page-info">共 {{.total}} 封</span>
|
|
</div>
|
|
|
|
{{if not .messages}}
|
|
<div class="mail-list">
|
|
<div class="empty-tip"><span class="empty-icon">📝</span>草稿箱暂无邮件</div>
|
|
</div>
|
|
{{else}}
|
|
<ul class="mail-list">
|
|
{{range .messages}}
|
|
<li class="mail-row" data-id="{{.ID}}">
|
|
<label class="cell-check" onclick="event.stopPropagation()">
|
|
<input type="checkbox" class="row-check" data-id="{{.ID}}">
|
|
</label>
|
|
<span class="cell-avatar">
|
|
<span class="avatar" style="{{avatarStyle .ToAddr}}">{{initial (mailName .ToAddr)}}</span>
|
|
</span>
|
|
<span class="cell-from" title="收件人:{{.ToAddr}}">致:{{mailName .ToAddr}}</span>
|
|
<span class="cell-subject-wrap">
|
|
<a class="cell-subject" href="/drafts/{{.ID}}">
|
|
{{if .Subject}}{{.Subject}}{{else}}(无主题){{end}}
|
|
</a>
|
|
</span>
|
|
<span class="cell-snippet">
|
|
{{if .TextBody}}{{truncate .TextBody 80}}{{else if .HtmlBody}}[HTML 邮件]{{end}}
|
|
</span>
|
|
<span class="cell-date">{{shortDate .Date}}</span>
|
|
<form method="POST" action="/mail/delete/{{.ID}}" class="row-del"
|
|
onsubmit="return confirm('确定要删除这封草稿吗?');">
|
|
<button type="submit" class="icon-btn" title="删除">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
|
</button>
|
|
</form>
|
|
</li>
|
|
{{end}}
|
|
</ul>
|
|
{{end}}
|
|
|
|
<div class="list-footer">
|
|
<span class="page-num">第 {{.page}} / {{if .totalPages}}{{.totalPages}}{{else}}1{{end}} 页</span>
|
|
<div class="pager">
|
|
{{if gt .page 1}}
|
|
<a class="page-btn" href="/drafts?page={{sub .page 1}}">
|
|
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
|
|
上一页
|
|
</a>
|
|
{{else}}
|
|
<span class="page-btn disabled">上一页</span>
|
|
{{end}}
|
|
{{if lt .page .totalPages}}
|
|
<a class="page-btn" href="/drafts?page={{add .page 1}}">
|
|
下一页
|
|
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
|
|
</a>
|
|
{{else}}
|
|
<span class="page-btn disabled">下一页</span>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
<script>
|
|
(function () {
|
|
var searchInput = document.getElementById('mail-search');
|
|
var rows = Array.prototype.slice.call(document.querySelectorAll('.mail-row'));
|
|
var selectAll = document.getElementById('select-all');
|
|
var btnDelete = document.getElementById('btn-delete');
|
|
|
|
rows.forEach(function (row) {
|
|
row.addEventListener('click', function (e) {
|
|
if (e.target.closest('.cell-check') || e.target.closest('.row-del')) return;
|
|
window.location.href = row.querySelector('.cell-subject').getAttribute('href');
|
|
});
|
|
});
|
|
|
|
selectAll && selectAll.addEventListener('change', function () {
|
|
rows.forEach(function (row) {
|
|
var cb = row.querySelector('.row-check');
|
|
cb.checked = selectAll.checked;
|
|
row.classList.toggle('selected', cb.checked);
|
|
});
|
|
updateDeleteState();
|
|
});
|
|
rows.forEach(function (row) {
|
|
var cb = row.querySelector('.row-check');
|
|
cb.addEventListener('change', function () {
|
|
row.classList.toggle('selected', cb.checked);
|
|
if (!cb.checked && selectAll) selectAll.checked = false;
|
|
updateDeleteState();
|
|
});
|
|
});
|
|
|
|
function updateDeleteState() {
|
|
if (!btnDelete) return;
|
|
var n = rows.filter(function (r) { return r.querySelector('.row-check').checked; }).length;
|
|
btnDelete.disabled = n === 0;
|
|
}
|
|
|
|
btnDelete && btnDelete.addEventListener('click', function () {
|
|
var ids = rows.filter(function (r) { return r.querySelector('.row-check').checked; })
|
|
.map(function (r) { return r.dataset.id; });
|
|
if (!ids.length) return;
|
|
if (!confirm('确定要删除选中的 ' + ids.length + ' 封邮件吗?')) return;
|
|
var done = 0;
|
|
ids.forEach(function (id) {
|
|
fetch('/mail/delete/' + id, { method: 'POST', body: new FormData() })
|
|
.then(function () { if (++done === ids.length) window.location.reload(); })
|
|
.catch(function () { if (++done === ids.length) window.location.reload(); });
|
|
});
|
|
});
|
|
|
|
var btnRefresh = document.getElementById('btn-refresh');
|
|
btnRefresh && btnRefresh.addEventListener('click', function () { window.location.reload(); });
|
|
|
|
searchInput && searchInput.addEventListener('input', function () {
|
|
var q = searchInput.value.trim().toLowerCase();
|
|
rows.forEach(function (row) {
|
|
var text = row.textContent.toLowerCase();
|
|
row.style.display = (!q || text.indexOf(q) !== -1) ? '' : 'none';
|
|
});
|
|
});
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|
|
{{end}}
|