Files
websitedev/scripts/cms-logo-page.js
T
Do Siki d2ee13bb91
CI Pipeline with Test Management / 🧪 Run Tests & Generate Reports (push) Waiting to run
CI Pipeline with Test Management / 🐳 Docker Integration Tests (push) Blocked by required conditions
CI Pipeline with Test Management / 🏗️ Build Docker Image (push) Blocked by required conditions
CI Pipeline with Test Management / 📊 Generate Test Summary (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / 🧪 Run Tests & Generate Reports (push) Waiting to run
Test Reporting & Gherkin Analysis / 📊 Analyze Test Coverage (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / 🔄 Sync with Linear (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / ⚡ Performance Monitoring (push) Blocked by required conditions
feat(cms): logo upload with preview, backup and audit
- 🎨 Logó page in the CMS bottom bar: replace the website header logo and
  the CMS login icon with a PNG upload (magic-byte validation, 1 MiB cap)
- the replaced logo gets a timestamped backup in .content-backups; every
  upload is audited (logo_updated)
- /logo.png?variant=header serves the header variant for the preview
- publish stages proto/public too, so logo changes ride the same
  commit+deploy pipeline as content
- route handling extracted to scripts/cms-logo.js to stay under the
  400-line limit
- integration test: upload+replace+backup, variant preview, 415/413/400,
  CSRF, auth

Closes MITHOME-65
2026-08-19 12:46:55 +02:00

107 lines
5.4 KiB
JavaScript

// Branding page for the Content Editor: upload/replace the two logos with
// client-side preview. Kept separate from cms-pages.js (file-size limits).
const { LOGO_TARGETS } = require('./cms-logo');
const LOGO_PAGE = (csrfToken) => `<!DOCTYPE html>
<html lang="hu">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>mozdIT — Logó kezelése</title>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #0f1117; color: #e2e8f0; line-height: 1.6; padding-bottom: 64px; }
header { background: linear-gradient(135deg,#1a1f2e,#252d40); border-bottom: 1px solid #2d3748; padding: 14px 32px; display: flex; align-items: center; gap: 12px; position: sticky; top: 0; z-index: 10; }
header h1 { font-size: 17px; font-weight: 700; background: linear-gradient(135deg,#60a5fa,#a78bfa); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
header a { color: #94a3b8; text-decoration: none; font-size: 14px; margin-left: auto; }
header a:hover { color: #e2e8f0; }
main { max-width: 720px; margin: 0 auto; padding: 28px 24px; }
.note { color: #94a3b8; font-size: 14px; margin-bottom: 22px; }
.card { background: #1a2035; border: 1px solid #2d3748; border-radius: 12px; padding: 20px 22px; margin-bottom: 18px; }
.card h2 { font-size: 16px; color: #93c5fd; margin-bottom: 4px; }
.card .where { color: #64748b; font-size: 13px; margin-bottom: 14px; }
.preview { background: repeating-conic-gradient(#1e293b 0% 25%, #0f1420 0% 50%) 50% / 22px 22px; border: 1px solid #2d3748; border-radius: 10px; padding: 16px; margin-bottom: 14px; text-align: center; min-height: 90px; }
.preview img { max-width: 100%; max-height: 72px; }
input[type=file] { color: #94a3b8; font-size: 14px; margin-bottom: 12px; width: 100%; }
.meta { font-size: 13px; color: #94a3b8; min-height: 20px; margin-bottom: 12px; }
button { background: linear-gradient(135deg,#3b82f6,#8b5cf6); color: #fff; border: none; border-radius: 8px; padding: 10px 22px; font-size: 14px; font-weight: 700; cursor: pointer; }
button:hover { filter: brightness(1.1); }
button:disabled { opacity: .5; cursor: wait; }
.msg { font-size: 14px; margin-top: 12px; min-height: 20px; }
.ok { color: #6ee7b7; } .err { color: #fca5a5; }
</style>
</head>
<body>
<header>
<h1>🎨 Logó kezelése</h1>
<a href="/">← Vissza a szerkesztőhöz</a>
</header>
<main>
<p class="note">Csak <strong>PNG</strong> fájl, max. 1 MB. A régi logó mentésre kerül (a 🕘 Verziókhoz hasonlóan visszavonható). A CMS-belei változás azonnal, a <strong>weboldalon a Publikálás (deploy) után</strong> jelenik meg. Ajánlott átlátszó háttérű PNG a sötét fejléchez.</p>
<div class="card">
<h2>Weboldal fejléc logója (szöveges)</h2>
<p class="where">Használat: weboldal fejléc — jelenlegi fájl: /${LOGO_TARGETS.header}</p>
<div class="preview"><img id="prev-header" src="/logo.png?variant=header&t=${Date.now()}" alt="fejléc logó előnézet"></div>
<input type="file" id="file-header" accept="image/png">
<div class="meta" id="meta-header"></div>
<button onclick="upload('header')">⬆ Fejléc logó cseréje</button>
<p class="msg" id="msg-header"></p>
</div>
<div class="card">
<h2>CMS logó (ikon)</h2>
<p class="where">Használat: CMS bejelentkező oldal — jelenlegi fájl: /${LOGO_TARGETS.icon}</p>
<div class="preview"><img id="prev-icon" src="/logo.png?t=${Date.now()}" alt="ikon logó előnézet"></div>
<input type="file" id="file-icon" accept="image/png">
<div class="meta" id="meta-icon"></div>
<button onclick="upload('icon')">⬆ Ikon logó cseréje</button>
<p class="msg" id="msg-icon"></p>
</div>
</main>
<script>
const CSRF_TOKEN = "${csrfToken}";
function setMsg(target, text, ok) {
const el = document.getElementById('msg-' + target);
el.textContent = text;
el.className = 'msg ' + (ok ? 'ok' : 'err');
}
async function upload(target) {
const file = document.getElementById('file-' + target).files[0];
const msg = t => setMsg(target, t, false);
if (!file) { msg('Először válassz PNG fájlt.'); return; }
if (file.type !== 'image/png') { msg('Csak PNG fájl tölthető fel.'); return; }
if (file.size > 1024 * 1024) { msg('A fájl nagyobb, mint 1 MB.'); return; }
const btn = event.target; btn.disabled = true;
try {
const bytes = new Uint8Array(await file.arrayBuffer());
const res = await fetch('/logo?target=' + target, {
method: 'POST',
headers: { 'Content-Type': 'image/png', 'X-CSRF-Token': CSRF_TOKEN },
body: bytes
});
if (res.status === 401) { location.href = '/login'; return; }
const json = await res.json();
if (json.ok) {
setMsg(target, '✅ Cserélve. (A weboldalon a Publikálás után jelenik meg.)', true);
document.getElementById('prev-' + target).src = '/logo.png?t=' + Date.now();
} else msg('❌ ' + json.error);
} catch (e) { msg('❌ Hálózati hiba'); }
btn.disabled = false;
}
document.querySelectorAll('input[type=file]').forEach(inp => {
inp.addEventListener('change', () => {
const f = inp.files[0];
const meta = document.getElementById('meta-' + inp.id.replace('file-', ''));
if (f) meta.textContent = f.name + ' — ' + (f.size / 1024).toFixed(1) + ' KB';
});
});
</script>
</body>
</html>`;
module.exports = { LOGO_PAGE };