Zwischenstand vom 29.05.2026

This commit is contained in:
khaccount committed 2026-05-29 11:14:02 +02:00
1 parent b6d2142214
commit dba154e572
36 files changed
+5113 -649

No files matched your search

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<rect x="1.5" y="2.5" width="13" height="11" rx="1" fill="none" stroke="#000" stroke-width="1.2"/>
<rect x="3.5" y="4.5" width="9" height="2.2" rx="0.3" fill="#000" opacity="0.55"/>
<rect x="3.5" y="7.6" width="9" height="2.2" rx="0.3" fill="#000" opacity="0.35"/>
<rect x="3.5" y="10.7" width="9" height="1.6" rx="0.3" fill="#000" opacity="0.2"/>
</svg>

After

Width:  |  Height:  |  Size: 447 B

@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none">
<rect x="1" y="3" width="14" height="10" rx="1.5" fill="#e63946"/>
<rect x="1" y="3" width="14" height="10" rx="1.5" stroke="#c1121f" stroke-width="0.5"/>
<text x="2" y="10.5" font-size="4.5" font-family="sans-serif" fill="#fff" font-weight="bold">OG</text>
<circle cx="11.5" cy="6.5" r="2" fill="#fff" opacity="0.9"/>
<polyline points="1,11 5,7 8,9.5 11,6 15,10" stroke="#fff" stroke-width="1" fill="none" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 523 B

@@ -0,0 +1,173 @@
/**
* OG Image Backend Module – live preview via AJAX
* EXT:vitec/Resources/Public/Javascript/og-image-preview.js
*/
(function () {
'use strict';
/** Debounce helper */
function debounce(fn, ms) {
let t;
return function (...args) {
clearTimeout(t);
t = setTimeout(() => fn.apply(this, args), ms);
};
}
/** Collect all form values into a FormData-compatible plain object */
function collectFormData() {
const form = document.getElementById('vitecOgForm');
if (!form) return {};
const fd = new FormData(form);
const out = {};
for (const [key, val] of fd.entries()) {
// key looks like "ogimage[something]"
const match = key.match(/^ogimage\[(.+)]$/);
if (match) {
out[key] = val;
}
}
return out;
}
/** POST to the preview endpoint, update the <img> */
async function requestPreview() {
const form = document.getElementById('vitecOgForm');
const spinner = document.getElementById('previewSpinner');
const img = document.getElementById('ogPreviewImg');
const placeholder = document.getElementById('ogPreviewPlaceholder');
const dl = document.getElementById('previewDownload');
if (!form) return;
if (spinner) spinner.classList.remove('d-none');
try {
const body = new URLSearchParams(collectFormData());
const previewUrl = form.dataset.previewUrl || window.location.href;
const resp = await fetch(previewUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: body.toString(),
});
if (!resp.ok) throw new Error('Server error ' + resp.status);
const json = await resp.json();
if (json.success && json.dataUri) {
img.src = json.dataUri;
img.style.display = 'block';
if (placeholder) placeholder.style.display = 'none';
if (dl) {
dl.href = json.dataUri;
dl.classList.remove('d-none');
}
} else {
console.warn('[OG Preview]', json.message);
}
} catch (e) {
console.error('[OG Preview] fetch failed:', e);
} finally {
if (spinner) spinner.classList.add('d-none');
}
}
const debouncedPreview = debounce(requestPreview, 600);
// ── Wire up events once DOM is ready ──────────────────────────────
document.addEventListener('DOMContentLoaded', function () {
// Manual preview button
const btn = document.getElementById('btnPreview');
if (btn) {
btn.addEventListener('click', requestPreview);
}
// Auto-preview on any .js-live input change
document.querySelectorAll('.js-live').forEach(function (el) {
el.addEventListener('input', debouncedPreview);
el.addEventListener('change', debouncedPreview);
});
// Background type toggle (show colour vs image picker)
function syncBgType() {
const colorWrap = document.getElementById('bg-color-wrap');
const imageWrap = document.getElementById('bg-image-wrap');
const selected = document.querySelector('input.js-bg-type:checked');
if (!selected) return;
if (selected.value === 'image') {
colorWrap && (colorWrap.style.display = 'none');
imageWrap && (imageWrap.style.display = 'block');
} else {
colorWrap && (colorWrap.style.display = 'block');
imageWrap && (imageWrap.style.display = 'none');
}
}
document.querySelectorAll('input.js-bg-type').forEach(function (el) {
el.addEventListener('change', function () {
syncBgType();
debouncedPreview();
});
});
const bgImageSelect = document.querySelector('select[name="ogimage[bg_image]"]');
if (bgImageSelect) {
bgImageSelect.addEventListener('change', function () {
const imageTypeRadio = document.querySelector('input.js-bg-type[value="image"]');
if (imageTypeRadio) {
imageTypeRadio.checked = true;
}
syncBgType();
requestPreview();
});
}
syncBgType(); // initialise on load
// Hex text ↔ colour picker sync
document.querySelectorAll('.js-hex-sync').forEach(function (hexInput) {
const targetId = hexInput.dataset.target;
const picker = document.getElementById(targetId);
if (!picker) return;
picker.addEventListener('input', function () {
hexInput.value = picker.value;
});
hexInput.addEventListener('input', function () {
const val = hexInput.value.trim();
if (/^#[0-9a-fA-F]{6}$/.test(val)) {
picker.value = val;
picker.dispatchEvent(new Event('input', { bubbles: true }));
}
});
});
// Preset buttons
document.querySelectorAll('.js-preset').forEach(function (btn) {
btn.addEventListener('click', function () {
const bg = btn.dataset.bg;
const tc = btn.dataset.titleColor;
const sc = btn.dataset.subtitleColor;
const bgInput = document.getElementById('bgColor');
if (bgInput && bg) { bgInput.value = bg; bgInput.dispatchEvent(new Event('input', {bubbles:true})); }
const tInput = document.getElementById('titleColor');
if (tInput && tc) { tInput.value = tc; tInput.dispatchEvent(new Event('input', {bubbles:true})); }
const sInput = document.getElementById('subtitleColor');
if (sInput && sc) { sInput.value = sc; sInput.dispatchEvent(new Event('input', {bubbles:true})); }
debouncedPreview();
});
});
});
})();