190 lines
9.0 KiB
HTML
190 lines
9.0 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
<title>Signature Manager — Template Editor</title>
|
|
<style>
|
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
body { font-family: Arial, sans-serif; background: #1a1a1a; color: #eee; }
|
|
header { background: #111; border-bottom: 2px solid #C9A84C; padding: 14px 24px; display: flex; align-items: center; gap: 16px; }
|
|
header h1 { font-size: 18px; color: #C9A84C; }
|
|
nav a { color: #ccc; text-decoration: none; margin-left: 16px; font-size: 14px; }
|
|
nav a:hover { color: #C9A84C; }
|
|
main { padding: 24px; max-width: 1200px; margin: auto; }
|
|
.layout { display: flex; gap: 20px; flex-wrap: wrap; }
|
|
.panel { flex: 1; min-width: 300px; }
|
|
.panel h2 { font-size: 14px; color: #C9A84C; margin-bottom: 10px; }
|
|
textarea { width: 100%; height: 380px; background: #222; color: #eee; border: 1px solid #444; border-radius: 6px; padding: 12px; font-family: monospace; font-size: 12px; resize: vertical; }
|
|
.preview-box { background: #fff; border-radius: 6px; padding: 20px; min-height: 120px; border: 1px solid #444; }
|
|
.actions { display: flex; gap: 10px; margin-top: 16px; flex-wrap: wrap; }
|
|
button { background: #C9A84C; color: #111; border: none; padding: 10px 20px; border-radius: 6px; font-weight: bold; cursor: pointer; font-size: 14px; }
|
|
button:hover { background: #e0bc5c; }
|
|
button.secondary { background: #333; color: #eee; border: 1px solid #555; }
|
|
button.secondary:hover { background: #444; }
|
|
#status-msg { margin-top: 12px; padding: 10px 14px; border-radius: 6px; display: none; }
|
|
#status-msg.ok { background: #1a4a1a; color: #4caf50; display: block; }
|
|
#status-msg.err { background: #4a1a1a; color: #f44336; display: block; }
|
|
.test-fields { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
|
|
.test-fields input { background: #2a2a2a; border: 1px solid #444; color: #eee; padding: 6px 10px; border-radius: 4px; font-size: 12px; width: calc(50% - 4px); }
|
|
.logo-row { display: flex; gap: 8px; align-items: center; margin-bottom: 12px; }
|
|
.logo-row input { flex: 1; background: #2a2a2a; border: 1px solid #444; color: #eee; padding: 6px 10px; border-radius: 4px; font-size: 12px; }
|
|
.logo-row label { font-size: 12px; color: #aaa; white-space: nowrap; }
|
|
|
|
.version-panel { background: #222; border: 1px solid #444; border-radius: 6px; padding: 16px; margin-bottom: 20px; }
|
|
.version-list { margin-top: 10px; max-height: 200px; overflow-y: auto; }
|
|
.version-item { display: flex; justify-content: space-between; align-items: center; padding: 8px; border-bottom: 1px solid #333; font-size: 13px; }
|
|
.version-item:hover { background: #2a2a2a; }
|
|
.version-info { flex: 1; cursor: pointer; }
|
|
.version-name { font-weight: bold; color: #C9A84C; }
|
|
.version-date { font-size: 11px; color: #777; margin-top: 2px; }
|
|
.version-actions { display: flex; gap: 8px; }
|
|
.v-btn { padding: 4px 8px; font-size: 11px; }
|
|
.save-form { display: flex; gap: 8px; margin-top: 10px; }
|
|
.save-form input { flex: 1; background: #333; border: 1px solid #444; color: #eee; padding: 8px; border-radius: 4px; font-size: 13px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<header>
|
|
<h1>✉ Email Signature Manager</h1>
|
|
<nav>
|
|
<a href="/dashboard">Dashboard</a>
|
|
<a href="/editor">Template Editor</a>
|
|
</nav>
|
|
</header>
|
|
<main>
|
|
<div class="layout">
|
|
<div class="panel">
|
|
<div class="version-panel">
|
|
<h2>Saved Versions</h2>
|
|
<div class="save-form">
|
|
<input id="v-name" placeholder="Version Name (e.g. Holiday 2026)"/>
|
|
<button onclick="saveVersion()" class="v-btn">Save As Version</button>
|
|
</div>
|
|
<div class="version-list" id="version-list">
|
|
<div style="color:#777; padding: 10px;">Loading versions...</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h2>Handlebars Template (HTML)</h2>
|
|
<textarea id="template-editor" spellcheck="false"></textarea>
|
|
<div class="actions">
|
|
<button onclick="saveTemplate()">💾 Save Template</button>
|
|
<button class="secondary" onclick="loadTemplate()">↻ Reset</button>
|
|
</div>
|
|
</div>
|
|
<div class="panel">
|
|
<h2>Live Preview</h2>
|
|
<div class="test-fields">
|
|
<input id="p-name" placeholder="Full Name" value="Jason Stedwell" oninput="updatePreview()"/>
|
|
<input id="p-title" placeholder="Job Title" value="Director of Technical Services" oninput="updatePreview()"/>
|
|
<input id="p-email" placeholder="Email" value="jason@messagepoint.tv" oninput="updatePreview()"/>
|
|
<input id="p-phone" placeholder="Office Phone" value="205-719-5000" oninput="updatePreview()"/>
|
|
<input id="p-cell" placeholder="Cell (optional)" value="334-707-2550" oninput="updatePreview()"/>
|
|
</div>
|
|
<div class="logo-row">
|
|
<label>Logo URL:</label>
|
|
<input id="p-logo" value="https://alwisp.com/uploads/logo.png" oninput="updatePreview()"/>
|
|
</div>
|
|
<div class="preview-box" id="preview-frame">Loading preview...</div>
|
|
<div class="actions">
|
|
<button class="secondary" onclick="updatePreview()">↻ Refresh Preview</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="status-msg"></div>
|
|
</main>
|
|
<script>
|
|
async function loadTemplate() {
|
|
const res = await fetch('/api/admin/template').then(r=>r.json());
|
|
document.getElementById('template-editor').value = res.content;
|
|
updatePreview();
|
|
}
|
|
async function saveTemplate() {
|
|
const content = document.getElementById('template-editor').value;
|
|
const res = await fetch('/api/admin/template',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({content})}).then(r=>r.json());
|
|
showStatus(res.ok ? 'Template deployed! A .bak backup was created.' : 'Error: '+res.error, res.ok);
|
|
updatePreview();
|
|
}
|
|
|
|
async function loadVersions() {
|
|
const versions = await fetch('/api/admin/versions').then(r=>r.json()).catch(()=>[]);
|
|
const list = document.getElementById('version-list');
|
|
if (!versions.length) {
|
|
list.innerHTML = '<div style="color:#777; padding:10px;">No saved versions yet.</div>';
|
|
return;
|
|
}
|
|
list.innerHTML = versions.map(v => `
|
|
<div class="version-item">
|
|
<div class="version-info" onclick="loadVersionData(${v.id})">
|
|
<div class="version-name">${v.name}</div>
|
|
<div class="version-date">${new Date(v.updated_at).toLocaleString()}</div>
|
|
</div>
|
|
<div class="version-actions">
|
|
<button class="secondary v-btn" onclick="deployVersion(${v.id})">Deploy</button>
|
|
</div>
|
|
</div>
|
|
`).join('');
|
|
}
|
|
|
|
async function saveVersion() {
|
|
const name = document.getElementById('v-name').value.trim();
|
|
const content = document.getElementById('template-editor').value;
|
|
if (!name) return alert('Enter a version name.');
|
|
|
|
const res = await fetch('/api/admin/versions', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ name, content })
|
|
}).then(r=>r.json());
|
|
|
|
if (res.ok) {
|
|
showStatus('Version saved!', true);
|
|
document.getElementById('v-name').value = '';
|
|
loadVersions();
|
|
} else {
|
|
showStatus('Error: '+res.error, false);
|
|
}
|
|
}
|
|
|
|
async function loadVersionData(id) {
|
|
const v = await fetch(`/api/admin/versions/${id}`).then(r=>r.json());
|
|
document.getElementById('template-editor').value = v.content;
|
|
document.getElementById('v-name').value = v.name;
|
|
updatePreview();
|
|
}
|
|
|
|
async function deployVersion(id) {
|
|
if (!confirm('Set this version as the ACTIVE template?')) return;
|
|
const res = await fetch(`/api/admin/versions/${id}/deploy`, { method: 'POST' }).then(r=>r.json());
|
|
if (res.ok) {
|
|
showStatus('Version deployed and active!', true);
|
|
} else {
|
|
showStatus('Error: '+res.error, false);
|
|
}
|
|
}
|
|
|
|
async function updatePreview() {
|
|
const templateHtml = document.getElementById('template-editor').value;
|
|
const userData = {
|
|
fullName: document.getElementById('p-name').value,
|
|
title: document.getElementById('p-title').value,
|
|
email: document.getElementById('p-email').value,
|
|
phone: document.getElementById('p-phone').value,
|
|
cellPhone: document.getElementById('p-cell').value,
|
|
logoUrl: document.getElementById('p-logo').value
|
|
};
|
|
const res = await fetch('/api/admin/preview',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({templateHtml,userData})}).then(r=>r.json()).catch(()=>({error:'Preview failed'}));
|
|
document.getElementById('preview-frame').innerHTML = res.html || `<span style="color:red">${res.error}</span>`;
|
|
}
|
|
function showStatus(msg, ok) {
|
|
const el = document.getElementById('status-msg');
|
|
el.textContent = msg; el.className = ok ? 'ok' : 'err'; el.style.display = 'block';
|
|
setTimeout(()=>{ el.style.display='none'; }, 5000);
|
|
}
|
|
loadTemplate();
|
|
loadVersions();
|
|
</script>
|
|
</body>
|
|
</html>
|