Add footer asset selector for email customization

- New /api/assets endpoint to list available icons from assets folder
- Dynamic footer generation with multiple selectable icons
- Thumbnail grid UI for asset selection in the mail form
- Selected icons are embedded as CID attachments in emails

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-16 22:34:11 +00:00
parent 6299d4e815
commit 96bc2286a5
5 changed files with 155 additions and 28 deletions

View File

@@ -4,21 +4,28 @@ document.addEventListener('DOMContentLoaded', () => {
const submitBtn = document.getElementById('submitBtn');
const historyList = document.getElementById('historyList');
const clearHistoryBtn = document.getElementById('clearHistory');
const assetGrid = document.getElementById('assetGrid');
// Load history on page load
// Load history and assets on page load
loadHistory();
loadAssets();
// Form submission
form.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(form);
const selectedAssets = Array.from(
document.querySelectorAll('input[name="footerAssets"]:checked')
).map(cb => cb.value);
const data = {
to: formData.get('to'),
cc: formData.get('cc') || undefined,
subject: formData.get('subject'),
body: formData.get('body'),
isHtml: formData.get('format') === 'html'
isHtml: formData.get('format') === 'html',
footerAssets: selectedAssets
};
submitBtn.disabled = true;
@@ -80,6 +87,42 @@ document.addEventListener('DOMContentLoaded', () => {
}
}
// Load assets from server
async function loadAssets() {
try {
const response = await fetch('/api/assets');
const result = await response.json();
if (result.success) {
renderAssetGrid(result.assets);
} else {
assetGrid.innerHTML = '<p class="empty-message">Fehler beim Laden der Assets</p>';
}
} catch (error) {
console.error('Error loading assets:', error);
assetGrid.innerHTML = '<p class="empty-message">Fehler beim Laden der Assets</p>';
}
}
// Render asset grid
function renderAssetGrid(assets) {
if (!assets || assets.length === 0) {
assetGrid.innerHTML = '<p class="empty-message">Keine Assets verfügbar</p>';
return;
}
assetGrid.innerHTML = assets.map(filename => {
const name = filename.replace(/\.[^.]+$/, '');
return `
<label class="asset-item">
<input type="checkbox" name="footerAssets" value="${filename}">
<img src="/assets/${filename}" alt="${name}">
<span class="asset-name">${name}</span>
</label>
`;
}).join('');
}
// Render history list
function renderHistory(history) {
if (!history || history.length === 0) {