Media browser: recursive scan entire content/ tree, /-media/ URL prefix, editor change detection fix
- handleMediaList() now scans content/ recursively for all media files
- URLs use /-media/ prefix mapping directly to content/ (no special cases)
- index.php: added /-media/ route, kept /-assets/ for backward compat
- editor-toolbar.js: fixed editor.on('change') placement (was inside switchMode)
- content-edit.php and content-new.php: back-btn unsaved-changes detection
- Removed unused __editorCleanup global
This commit is contained in:
26
admin/templates/pages/content-dir-form.php
Normal file
26
admin/templates/pages/content-dir-form.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<h2 class="mb-4"><i class="bi bi-pencil"></i> Map hernoemen</h2>
|
||||
|
||||
<form method="post" class="card shadow-sm">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrf) ?>">
|
||||
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted">Huidige mapnaam</label>
|
||||
<p class="form-control-plaintext fw-bold"><?= htmlspecialchars(basename($fullPath)) ?></p>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="new_name" class="form-label">Nieuwe naam</label>
|
||||
<input type="text" class="form-control" id="new_name" name="new_name"
|
||||
value="<?= htmlspecialchars(basename($fullPath)) ?>" required autofocus>
|
||||
<div class="form-text">Alleen letters, cijfers, punten, underscores en streepjes.</div>
|
||||
</div>
|
||||
<?php if (!empty($message)): ?>
|
||||
<div class="alert alert-<?= $messageType ?>"><?= htmlspecialchars($message) ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="card-footer text-end">
|
||||
<a href="admin.php?route=content&dir=<?= urlencode(dirname($dir) === '.' ? '' : dirname($dir)) ?>" class="btn btn-secondary">Annuleren</a>
|
||||
<button type="submit" class="btn btn-primary"><i class="bi bi-check-lg"></i> Opslaan</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -1,27 +1,309 @@
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2><i class="bi bi-pencil"></i> <?= htmlspecialchars($fileName) ?></h2>
|
||||
<a href="admin.php?route=content&dir=<?= urlencode(dirname($_GET['file'] ?? '')) ?>" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="bi bi-arrow-left"></i> Terug
|
||||
</a>
|
||||
</div>
|
||||
<h2 class="mb-4"><i class="bi bi-pencil"></i> <?= htmlspecialchars($fileName) ?></h2>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<form method="POST" action="admin.php?route=content-edit&file=<?= urlencode($_GET['file'] ?? '') ?>">
|
||||
<form method="POST" action="admin.php?route=content-edit&file=<?= urlencode($file) ?>" id="editor-form">
|
||||
<input type="hidden" name="csrf_token" value="<?= $csrf ?>">
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<span class="badge bg-secondary"><?= strtoupper($fileExt) ?></span>
|
||||
<small class="text-muted"><?= htmlspecialchars($_GET['file'] ?? '') ?></small>
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-4">
|
||||
<label for="filename" class="form-label">Bestandsnaam</label>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" id="filename" name="filename"
|
||||
value="<?= htmlspecialchars(pathinfo($fileName, PATHINFO_FILENAME)) ?>" required>
|
||||
<span class="input-group-text">.<?= htmlspecialchars($fileExt) ?></span>
|
||||
</div>
|
||||
<small class="form-text text-muted">Alleen letters, cijfers, punten, underscores en streepjes.</small>
|
||||
</div>
|
||||
<textarea name="content" class="form-control font-monospace" rows="25" style="font-size: 0.9rem; tab-size: 4;"><?= htmlspecialchars($fileContent) ?></textarea>
|
||||
<?php if ($isEditable): ?>
|
||||
<div class="col-md-4">
|
||||
<label for="layout" class="form-label">Sjabloon / Layout</label>
|
||||
<select class="form-select" id="layout" name="layout">
|
||||
<option value="sidebar-content" <?= $currentLayout === 'sidebar-content' ? 'selected' : '' ?>>Sidebar + Inhoud (standaard)</option>
|
||||
<option value="content" <?= $currentLayout === 'content' ? 'selected' : '' ?>>Alleen inhoud (full-width)</option>
|
||||
<option value="sidebar" <?= $currentLayout === 'sidebar' ? 'selected' : '' ?>>Alleen sidebar (full-width)</option>
|
||||
<option value="content-sidebar" <?= $currentLayout === 'content-sidebar' ? 'selected' : '' ?>>Inhoud links + sidebar rechts</option>
|
||||
<option value="content-sidebar-reverse" <?= $currentLayout === 'content-sidebar-reverse' ? 'selected' : '' ?>>Inhoud rechts + sidebar links</option>
|
||||
</select>
|
||||
</div>
|
||||
<?php if (!empty($availablePlugins)): ?>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label d-block">Zichtbare plugins</label>
|
||||
<div class="d-flex flex-wrap gap-1">
|
||||
<?php foreach ($availablePlugins as $plugin): ?>
|
||||
<input type="checkbox" class="btn-check" id="plugin-<?= $plugin ?>" name="plugins[]" value="<?= htmlspecialchars($plugin) ?>" autocomplete="off" <?= in_array($plugin, $selectedPlugins) ? 'checked' : '' ?>>
|
||||
<label class="btn btn-outline-primary btn-sm" for="plugin-<?= $plugin ?>"><?= htmlspecialchars($plugin) ?></label>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<?php if ($isEditable): ?>
|
||||
<div class="editor-toolbar" id="editor-toolbar"></div>
|
||||
<div class="editor-wrapper">
|
||||
<textarea name="content" id="editor-textarea" data-ext="<?= $fileExt ?>"><?= htmlspecialchars($fileContent) ?></textarea>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="d-flex gap-2 mt-3">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check-lg"></i> Opslaan
|
||||
</button>
|
||||
<a href="admin.php?route=content&dir=<?= urlencode(dirname($_GET['file'] ?? '')) ?>" class="btn btn-outline-secondary">Annuleren</a>
|
||||
<a href="admin.php?route=content&dir=<?= urlencode(dirname($file)) ?>" class="btn btn-outline-secondary" id="back-btn">Terug</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var backBtn = document.getElementById('back-btn');
|
||||
var filenameInput = document.getElementById('filename');
|
||||
if (!backBtn) return;
|
||||
|
||||
var changed = false;
|
||||
|
||||
function markChanged() {
|
||||
if (changed) return;
|
||||
changed = true;
|
||||
backBtn.innerHTML = '<i class="bi bi-x-circle"></i> Annuleren';
|
||||
backBtn.classList.remove('btn-outline-secondary');
|
||||
backBtn.classList.add('btn-outline-danger');
|
||||
}
|
||||
|
||||
if (filenameInput) {
|
||||
filenameInput.addEventListener('input', markChanged);
|
||||
}
|
||||
|
||||
window.__onContentChange = markChanged;
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php if ($isEditable): ?>
|
||||
<!-- Media Modal -->
|
||||
<div class="modal fade" id="mediaModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><i class="bi bi-images"></i> Media</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="collapse mb-3" id="mediaUploadForm">
|
||||
<div class="card card-body">
|
||||
<form id="media-upload-form" enctype="multipart/form-data">
|
||||
<input type="hidden" name="csrf_token" value="<?= $csrf ?>">
|
||||
<div class="mb-2">
|
||||
<input type="file" class="form-control" name="file[]" multiple accept="image/jpeg,image/png,image/gif,image/webp,image/svg+xml,video/mp4,video/webm,audio/mpeg,audio/wav" id="media-file-input">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success btn-sm" id="media-upload-btn" disabled>
|
||||
<i class="bi bi-cloud-upload"></i> Uploaden
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<button type="button" class="btn btn-outline-primary btn-sm" data-bs-toggle="collapse" data-bs-target="#mediaUploadForm">
|
||||
<i class="bi bi-cloud-upload"></i> Uploaden
|
||||
</button>
|
||||
<small class="text-muted" id="media-count"></small>
|
||||
</div>
|
||||
|
||||
<!-- Media grid -->
|
||||
<div id="media-grid" class="row g-2">
|
||||
<div class="col-12 text-center text-muted py-4">
|
||||
<div class="spinner-border spinner-border-sm me-2"></div> Laden...
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Size form (shown when clicking an image) -->
|
||||
<div id="media-size-form" class="d-none">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center gap-3 mb-3">
|
||||
<img id="size-preview" src="" alt="" style="width:80px;height:60px;object-fit:cover;border-radius:4px;">
|
||||
<div>
|
||||
<strong id="size-filename" class="d-block"></strong>
|
||||
<small class="text-muted">Geef de gewenste afmetingen (optioneel)</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-2 mb-3">
|
||||
<div class="col-4">
|
||||
<label class="form-label small">Breedte (px)</label>
|
||||
<input type="number" class="form-control form-control-sm" id="size-width" placeholder="auto" min="1">
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<label class="form-label small">Hoogte (px)</label>
|
||||
<input type="number" class="form-control form-control-sm" id="size-height" placeholder="auto" min="1">
|
||||
</div>
|
||||
<div class="col-4 d-flex align-items-end gap-1">
|
||||
<button type="button" class="btn btn-primary btn-sm" id="size-insert-btn">
|
||||
<i class="bi bi-check-lg"></i> Invoegen
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" id="size-cancel-btn">
|
||||
Annuleren
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var mediaModal = document.getElementById('mediaModal');
|
||||
if (!mediaModal) return;
|
||||
|
||||
var ext = document.getElementById('editor-textarea').dataset.ext || 'md';
|
||||
var mode = ext === 'md' ? 'markdown' : 'html';
|
||||
var pendingFile = null;
|
||||
|
||||
function getCurrentMode() {
|
||||
var ta = document.getElementById('editor-textarea');
|
||||
if (!ta) return 'html';
|
||||
var ext = ta.dataset.ext || 'md';
|
||||
return ext === 'md' ? 'markdown' : 'html';
|
||||
}
|
||||
|
||||
mediaModal.addEventListener('show.bs.modal', function () {
|
||||
document.getElementById('media-size-form').classList.add('d-none');
|
||||
document.getElementById('media-grid').classList.remove('d-none');
|
||||
pendingFile = null;
|
||||
fetch('admin.php?route=media-list')
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (files) {
|
||||
var grid = document.getElementById('media-grid');
|
||||
document.getElementById('media-count').textContent = files.length + ' bestand(en)';
|
||||
if (files.length === 0) {
|
||||
grid.innerHTML = '<div class="col-12 text-center text-muted py-4">Geen media bestanden gevonden.</div>';
|
||||
return;
|
||||
}
|
||||
grid.innerHTML = '';
|
||||
files.forEach(function (f) {
|
||||
var col = document.createElement('div');
|
||||
col.className = 'col-6 col-md-4 col-lg-3';
|
||||
var card = document.createElement('div');
|
||||
card.className = 'card card-media-item';
|
||||
card.style.cursor = 'pointer';
|
||||
card.title = 'Klik om in te voegen';
|
||||
|
||||
var preview;
|
||||
if (f.is_image) {
|
||||
preview = '<img src="' + f.url + '" alt="' + f.name + '" class="card-img-top" style="height:100px;object-fit:cover;">';
|
||||
} else if (f.is_video) {
|
||||
preview = '<div class="d-flex align-items-center justify-content-center" style="height:100px;background:#f8f9fa;"><i class="bi bi-film fs-1 text-muted"></i></div>';
|
||||
} else if (f.is_audio) {
|
||||
preview = '<div class="d-flex align-items-center justify-content-center" style="height:100px;background:#f8f9fa;"><i class="bi bi-music-note-beamed fs-1 text-muted"></i></div>';
|
||||
} else {
|
||||
preview = '<div class="d-flex align-items-center justify-content-center" style="height:100px;background:#f8f9fa;"><span class="badge bg-secondary fs-5">' + f.ext.toUpperCase() + '</span></div>';
|
||||
}
|
||||
|
||||
card.innerHTML = preview +
|
||||
'<div class="card-body p-2"><small class="text-truncate d-block">' + f.name + '</small></div>';
|
||||
|
||||
card.addEventListener('click', function () {
|
||||
var m = getCurrentMode();
|
||||
if (f.is_image && m !== 'markdown') {
|
||||
showSizeForm(f);
|
||||
} else {
|
||||
insertMedia(f, m);
|
||||
}
|
||||
});
|
||||
col.appendChild(card);
|
||||
grid.appendChild(col);
|
||||
});
|
||||
})
|
||||
.catch(function () {
|
||||
document.getElementById('media-grid').innerHTML = '<div class="col-12 text-center text-danger py-4">Fout bij laden van media.</div>';
|
||||
});
|
||||
});
|
||||
|
||||
function showSizeForm(f) {
|
||||
pendingFile = f;
|
||||
document.getElementById('media-grid').classList.add('d-none');
|
||||
document.getElementById('media-size-form').classList.remove('d-none');
|
||||
document.getElementById('size-preview').src = f.url;
|
||||
document.getElementById('size-filename').textContent = f.name;
|
||||
document.getElementById('size-width').value = '';
|
||||
document.getElementById('size-height').value = '';
|
||||
}
|
||||
|
||||
document.getElementById('size-insert-btn').addEventListener('click', function () {
|
||||
if (!pendingFile) return;
|
||||
var w = document.getElementById('size-width').value;
|
||||
var h = document.getElementById('size-height').value;
|
||||
insertMedia(pendingFile, getCurrentMode(), w, h);
|
||||
});
|
||||
|
||||
document.getElementById('size-cancel-btn').addEventListener('click', function () {
|
||||
document.getElementById('media-size-form').classList.add('d-none');
|
||||
document.getElementById('media-grid').classList.remove('d-none');
|
||||
pendingFile = null;
|
||||
});
|
||||
|
||||
function insertMedia(f, mode, w, h) {
|
||||
var editorEl = document.querySelector('.CodeMirror');
|
||||
if (!editorEl || typeof CodeMirror === 'undefined') return;
|
||||
var cm = editorEl.CodeMirror;
|
||||
if (!cm) return;
|
||||
|
||||
var sizeAttr = '';
|
||||
if (w || h) {
|
||||
if (w) sizeAttr += ' width="' + parseInt(w) + '"';
|
||||
if (h) sizeAttr += ' height="' + parseInt(h) + '"';
|
||||
}
|
||||
|
||||
var tag;
|
||||
if (mode === 'markdown') {
|
||||
if (f.is_image) {
|
||||
tag = '';
|
||||
} else {
|
||||
tag = '[' + f.name + '](' + f.url + ')';
|
||||
}
|
||||
} else {
|
||||
if (f.is_image) {
|
||||
tag = '<img src="' + f.url + '" alt="' + f.name + '"' + sizeAttr + '>';
|
||||
} else if (f.is_video) {
|
||||
tag = '<video controls src="' + f.url + '" style="max-width:100%;"></video>';
|
||||
} else if (f.is_audio) {
|
||||
tag = '<audio controls src="' + f.url + '"></audio>';
|
||||
} else {
|
||||
tag = '<a href="' + f.url + '">' + f.name + '</a>';
|
||||
}
|
||||
}
|
||||
cm.replaceSelection(tag);
|
||||
cm.focus();
|
||||
|
||||
var modal = bootstrap.Modal.getInstance(mediaModal);
|
||||
if (modal) modal.hide();
|
||||
}
|
||||
|
||||
// Handle upload
|
||||
document.getElementById('media-upload-form').addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
var form = this;
|
||||
var formData = new FormData(form);
|
||||
formData.append('csrf_token', '<?= $csrf ?>');
|
||||
|
||||
fetch('admin.php?route=media', { method: 'POST', body: formData })
|
||||
.then(function () {
|
||||
form.reset();
|
||||
document.getElementById('media-upload-btn').disabled = true;
|
||||
var modal = bootstrap.Modal.getInstance(mediaModal);
|
||||
if (modal) modal.hide();
|
||||
setTimeout(function () { modal.show(); }, 100);
|
||||
})
|
||||
.catch(function () {
|
||||
alert('Upload mislukt.');
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('media-file-input').addEventListener('change', function () {
|
||||
document.getElementById('media-upload-btn').disabled = this.files.length === 0;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
34
admin/templates/pages/content-move-form.php
Normal file
34
admin/templates/pages/content-move-form.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<h2 class="mb-4"><i class="bi bi-arrows-move"></i> <?= is_file($fullPath) ? 'Bestand' : 'Map' ?> verplaatsen</h2>
|
||||
|
||||
<form method="post" class="card shadow-sm">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrf) ?>">
|
||||
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted">Te verplaatsen item</label>
|
||||
<p class="form-control-plaintext fw-bold">
|
||||
<i class="bi <?= is_file($fullPath) ? 'bi-file' : 'bi-folder' ?>"></i>
|
||||
<?= htmlspecialchars(basename($fullPath)) ?>
|
||||
</p>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="target_dir" class="form-label">Doelmap</label>
|
||||
<select class="form-select" id="target_dir" name="target_dir" required>
|
||||
<option value="">-- Selecteer doelmap --</option>
|
||||
<option value="">/ (hoofdmap)</option>
|
||||
<?php foreach ($dirs as $d): ?>
|
||||
<option value="<?= htmlspecialchars($d) ?>"><?= htmlspecialchars($d) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<div class="form-text">Selecteer de map waar het item naartoe verplaatst moet worden.</div>
|
||||
</div>
|
||||
<?php if (!empty($message)): ?>
|
||||
<div class="alert alert-<?= $messageType ?>"><?= htmlspecialchars($message) ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="card-footer text-end">
|
||||
<a href="admin.php?route=content&dir=<?= urlencode(dirname($item) === '.' ? '' : dirname($item)) ?>" class="btn btn-secondary">Annuleren</a>
|
||||
<button type="submit" class="btn btn-primary"><i class="bi bi-check-lg"></i> Verplaatsen</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -1,13 +1,8 @@
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2><i class="bi bi-plus-lg"></i> Nieuwe pagina</h2>
|
||||
<a href="admin.php?route=content&dir=<?= urlencode($dir ?? '') ?>" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="bi bi-arrow-left"></i> Terug
|
||||
</a>
|
||||
</div>
|
||||
<h2 class="mb-4"><i class="bi bi-plus-lg"></i> Nieuwe pagina</h2>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<form method="POST" action="admin.php?route=content-new&dir=<?= urlencode($dir ?? '') ?>">
|
||||
<form method="POST" action="admin.php?route=content-new&dir=<?= urlencode($dir ?? '') ?>" id="editor-form" data-new-page>
|
||||
<input type="hidden" name="csrf_token" value="<?= $csrf ?>">
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-8">
|
||||
@@ -17,7 +12,7 @@
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="type" class="form-label">Type</label>
|
||||
<select class="form-select" id="type" name="type">
|
||||
<select class="form-select" id="type" name="type" data-editor-mode>
|
||||
<option value="md" selected>Markdown (.md)</option>
|
||||
<option value="php">PHP (.php)</option>
|
||||
<option value="html">HTML (.html)</option>
|
||||
@@ -29,18 +24,286 @@
|
||||
<small class="text-muted">Map: <?= htmlspecialchars($dir) ?></small>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="mb-3">
|
||||
<label for="content" class="form-label">Inhoud</label>
|
||||
<textarea name="content" id="content" class="form-control font-monospace" rows="20" style="font-size: 0.9rem; tab-size: 4;" placeholder="# Mijn nieuwe pagina
|
||||
|
||||
Schrijf hier je inhoud..."></textarea>
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="layout" class="form-label">Sjabloon / Layout</label>
|
||||
<select class="form-select" id="layout" name="layout">
|
||||
<option value="sidebar-content">Sidebar + Inhoud (standaard)</option>
|
||||
<option value="content">Alleen inhoud (full-width)</option>
|
||||
<option value="sidebar">Alleen sidebar (full-width)</option>
|
||||
<option value="content-sidebar">Inhoud links + sidebar rechts</option>
|
||||
<option value="content-sidebar-reverse">Inhoud rechts + sidebar links</option>
|
||||
</select>
|
||||
</div>
|
||||
<?php if (!empty($availablePlugins)): ?>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label d-block">Zichtbare plugins</label>
|
||||
<div class="d-flex flex-wrap gap-1">
|
||||
<?php foreach ($availablePlugins as $plugin): ?>
|
||||
<input type="checkbox" class="btn-check" id="plugin-<?= $plugin ?>" name="plugins[]" value="<?= htmlspecialchars($plugin) ?>" autocomplete="off" checked>
|
||||
<label class="btn btn-outline-primary btn-sm" for="plugin-<?= $plugin ?>"><?= htmlspecialchars($plugin) ?></label>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<div class="editor-toolbar" id="editor-toolbar"></div>
|
||||
<div class="editor-wrapper">
|
||||
<textarea name="content" id="editor-textarea" data-ext="md"></textarea>
|
||||
</div>
|
||||
<div class="d-flex gap-2 mt-3">
|
||||
<button type="submit" class="btn btn-primary" id="content-create-btn" disabled>
|
||||
<i class="bi bi-check-lg"></i> Aanmaken
|
||||
</button>
|
||||
<a href="admin.php?route=content&dir=<?= urlencode($dir ?? '') ?>" class="btn btn-outline-secondary">Annuleren</a>
|
||||
<a href="admin.php?route=content&dir=<?= urlencode($dir ?? '') ?>" class="btn btn-outline-secondary" id="back-btn">Terug</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Media Modal -->
|
||||
<div class="modal fade" id="mediaModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><i class="bi bi-images"></i> Media</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="collapse mb-3" id="mediaUploadForm">
|
||||
<div class="card card-body">
|
||||
<form id="media-upload-form" enctype="multipart/form-data">
|
||||
<input type="hidden" name="csrf_token" value="<?= $csrf ?>">
|
||||
<div class="mb-2">
|
||||
<input type="file" class="form-control" name="file[]" multiple accept="image/jpeg,image/png,image/gif,image/webp,image/svg+xml,video/mp4,video/webm,audio/mpeg,audio/wav" id="media-file-input">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success btn-sm" id="media-upload-btn" disabled>
|
||||
<i class="bi bi-cloud-upload"></i> Uploaden
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<button type="button" class="btn btn-outline-primary btn-sm" data-bs-toggle="collapse" data-bs-target="#mediaUploadForm">
|
||||
<i class="bi bi-cloud-upload"></i> Uploaden
|
||||
</button>
|
||||
<small class="text-muted" id="media-count"></small>
|
||||
</div>
|
||||
<div id="media-grid" class="row g-2">
|
||||
<div class="col-12 text-center text-muted py-4">
|
||||
<div class="spinner-border spinner-border-sm me-2"></div> Laden...
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Size form (shown when clicking an image) -->
|
||||
<div id="media-size-form" class="d-none">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center gap-3 mb-3">
|
||||
<img id="size-preview" src="" alt="" style="width:80px;height:60px;object-fit:cover;border-radius:4px;">
|
||||
<div>
|
||||
<strong id="size-filename" class="d-block"></strong>
|
||||
<small class="text-muted">Geef de gewenste afmetingen (optioneel)</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-2 mb-3">
|
||||
<div class="col-4">
|
||||
<label class="form-label small">Breedte (px)</label>
|
||||
<input type="number" class="form-control form-control-sm" id="size-width" placeholder="auto" min="1">
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<label class="form-label small">Hoogte (px)</label>
|
||||
<input type="number" class="form-control form-control-sm" id="size-height" placeholder="auto" min="1">
|
||||
</div>
|
||||
<div class="col-4 d-flex align-items-end gap-1">
|
||||
<button type="button" class="btn btn-primary btn-sm" id="size-insert-btn">
|
||||
<i class="bi bi-check-lg"></i> Invoegen
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" id="size-cancel-btn">
|
||||
Annuleren
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var backBtn = document.getElementById('back-btn');
|
||||
var filenameInput = document.getElementById('filename');
|
||||
var createBtn = document.getElementById('content-create-btn');
|
||||
|
||||
if (backBtn) {
|
||||
var changed = false;
|
||||
function markChanged() {
|
||||
if (changed) return;
|
||||
changed = true;
|
||||
backBtn.innerHTML = '<i class="bi bi-x-circle"></i> Annuleren';
|
||||
backBtn.classList.remove('btn-outline-secondary');
|
||||
backBtn.classList.add('btn-outline-danger');
|
||||
}
|
||||
if (filenameInput) {
|
||||
filenameInput.addEventListener('input', markChanged);
|
||||
}
|
||||
window.__onContentChange = markChanged;
|
||||
}
|
||||
|
||||
if (filenameInput && createBtn) {
|
||||
filenameInput.addEventListener('input', function () {
|
||||
createBtn.disabled = this.value.trim() === '';
|
||||
});
|
||||
}
|
||||
|
||||
var mediaModal = document.getElementById('mediaModal');
|
||||
if (!mediaModal) return;
|
||||
|
||||
function getCurrentMode() {
|
||||
var ta = document.getElementById('editor-textarea');
|
||||
var ext = ta ? ta.dataset.ext || 'md' : 'md';
|
||||
return ext === 'md' ? 'markdown' : 'html';
|
||||
}
|
||||
|
||||
var pendingFile = null;
|
||||
|
||||
mediaModal.addEventListener('show.bs.modal', function () {
|
||||
document.getElementById('media-size-form').classList.add('d-none');
|
||||
document.getElementById('media-grid').classList.remove('d-none');
|
||||
pendingFile = null;
|
||||
fetch('admin.php?route=media-list')
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (files) {
|
||||
var grid = document.getElementById('media-grid');
|
||||
document.getElementById('media-count').textContent = files.length + ' bestand(en)';
|
||||
if (files.length === 0) {
|
||||
grid.innerHTML = '<div class="col-12 text-center text-muted py-4">Geen media bestanden gevonden.</div>';
|
||||
return;
|
||||
}
|
||||
grid.innerHTML = '';
|
||||
files.forEach(function (f) {
|
||||
var col = document.createElement('div');
|
||||
col.className = 'col-6 col-md-4 col-lg-3';
|
||||
var card = document.createElement('div');
|
||||
card.className = 'card card-media-item';
|
||||
card.style.cursor = 'pointer';
|
||||
card.title = 'Klik om in te voegen';
|
||||
|
||||
var preview;
|
||||
if (f.is_image) {
|
||||
preview = '<img src="' + f.url + '" alt="' + f.name + '" class="card-img-top" style="height:100px;object-fit:cover;">';
|
||||
} else if (f.is_video) {
|
||||
preview = '<div class="d-flex align-items-center justify-content-center" style="height:100px;background:#f8f9fa;"><i class="bi bi-film fs-1 text-muted"></i></div>';
|
||||
} else if (f.is_audio) {
|
||||
preview = '<div class="d-flex align-items-center justify-content-center" style="height:100px;background:#f8f9fa;"><i class="bi bi-music-note-beamed fs-1 text-muted"></i></div>';
|
||||
} else {
|
||||
preview = '<div class="d-flex align-items-center justify-content-center" style="height:100px;background:#f8f9fa;"><span class="badge bg-secondary fs-5">' + f.ext.toUpperCase() + '</span></div>';
|
||||
}
|
||||
|
||||
card.innerHTML = preview +
|
||||
'<div class="card-body p-2"><small class="text-truncate d-block">' + f.name + '</small></div>';
|
||||
|
||||
card.addEventListener('click', function () {
|
||||
var mode = getCurrentMode();
|
||||
if (f.is_image && mode !== 'markdown') {
|
||||
showSizeForm(f);
|
||||
} else {
|
||||
insertMedia(f, mode);
|
||||
}
|
||||
});
|
||||
col.appendChild(card);
|
||||
grid.appendChild(col);
|
||||
});
|
||||
})
|
||||
.catch(function () {
|
||||
document.getElementById('media-grid').innerHTML = '<div class="col-12 text-center text-danger py-4">Fout bij laden van media.</div>';
|
||||
});
|
||||
});
|
||||
|
||||
function showSizeForm(f) {
|
||||
pendingFile = f;
|
||||
document.getElementById('media-grid').classList.add('d-none');
|
||||
document.getElementById('media-size-form').classList.remove('d-none');
|
||||
document.getElementById('size-preview').src = f.url;
|
||||
document.getElementById('size-filename').textContent = f.name;
|
||||
document.getElementById('size-width').value = '';
|
||||
document.getElementById('size-height').value = '';
|
||||
}
|
||||
|
||||
document.getElementById('size-insert-btn').addEventListener('click', function () {
|
||||
if (!pendingFile) return;
|
||||
var w = document.getElementById('size-width').value;
|
||||
var h = document.getElementById('size-height').value;
|
||||
insertMedia(pendingFile, getCurrentMode(), w, h);
|
||||
});
|
||||
|
||||
document.getElementById('size-cancel-btn').addEventListener('click', function () {
|
||||
document.getElementById('media-size-form').classList.add('d-none');
|
||||
document.getElementById('media-grid').classList.remove('d-none');
|
||||
pendingFile = null;
|
||||
});
|
||||
|
||||
function insertMedia(f, mode, w, h) {
|
||||
var editorEl = document.querySelector('.CodeMirror');
|
||||
if (!editorEl || typeof CodeMirror === 'undefined') return;
|
||||
var cm = editorEl.CodeMirror;
|
||||
if (!cm) return;
|
||||
|
||||
var sizeAttr = '';
|
||||
if (w || h) {
|
||||
if (w) sizeAttr += ' width="' + parseInt(w) + '"';
|
||||
if (h) sizeAttr += ' height="' + parseInt(h) + '"';
|
||||
}
|
||||
|
||||
var tag;
|
||||
if (mode === 'markdown') {
|
||||
if (f.is_image) {
|
||||
tag = '';
|
||||
} else {
|
||||
tag = '[' + f.name + '](' + f.url + ')';
|
||||
}
|
||||
} else {
|
||||
if (f.is_image) {
|
||||
tag = '<img src="' + f.url + '" alt="' + f.name + '"' + sizeAttr + '>';
|
||||
} else if (f.is_video) {
|
||||
tag = '<video controls src="' + f.url + '" style="max-width:100%;"></video>';
|
||||
} else if (f.is_audio) {
|
||||
tag = '<audio controls src="' + f.url + '"></audio>';
|
||||
} else {
|
||||
tag = '<a href="' + f.url + '">' + f.name + '</a>';
|
||||
}
|
||||
}
|
||||
cm.replaceSelection(tag);
|
||||
cm.focus();
|
||||
|
||||
var modal = bootstrap.Modal.getInstance(mediaModal);
|
||||
if (modal) modal.hide();
|
||||
}
|
||||
|
||||
document.getElementById('media-upload-form').addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
var form = this;
|
||||
var formData = new FormData(form);
|
||||
formData.append('csrf_token', '<?= $csrf ?>');
|
||||
|
||||
fetch('admin.php?route=media', { method: 'POST', body: formData })
|
||||
.then(function () {
|
||||
form.reset();
|
||||
document.getElementById('media-upload-btn').disabled = true;
|
||||
var modal = bootstrap.Modal.getInstance(mediaModal);
|
||||
if (modal) modal.hide();
|
||||
setTimeout(function () { modal.show(); }, 100);
|
||||
})
|
||||
.catch(function () {
|
||||
alert('Upload mislukt.');
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('media-file-input').addEventListener('change', function () {
|
||||
document.getElementById('media-upload-btn').disabled = this.files.length === 0;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,8 +1,34 @@
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2><i class="bi bi-file-earmark-text"></i> Content</h2>
|
||||
<a href="admin.php?route=content-new&dir=<?= urlencode($subdir) ?>" class="btn btn-primary btn-sm">
|
||||
<i class="bi bi-plus-lg"></i> Nieuw bestand
|
||||
</a>
|
||||
<div>
|
||||
<button type="button" class="btn btn-outline-success btn-sm me-1" data-bs-toggle="collapse" data-bs-target="#uploadForm">
|
||||
<i class="bi bi-cloud-upload"></i> Upload
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm me-1" data-bs-toggle="modal" data-bs-target="#createDirModal">
|
||||
<i class="bi bi-folder-plus"></i> Nieuwe map
|
||||
</button>
|
||||
<a href="admin.php?route=content-new&dir=<?= urlencode($subdir) ?>" class="btn btn-primary btn-sm">
|
||||
<i class="bi bi-plus-lg"></i> Nieuw bestand
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="collapse mb-4" id="uploadForm">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<form method="POST" action="admin.php?route=content&dir=<?= urlencode($subdir) ?>" enctype="multipart/form-data">
|
||||
<input type="hidden" name="csrf_token" value="<?= $csrf ?>">
|
||||
<div class="mb-3">
|
||||
<label for="file" class="form-label">Bestanden selecteren</label>
|
||||
<input type="file" class="form-control" id="file" name="file[]" multiple accept="image/jpeg,image/png,image/gif,image/webp,image/svg+xml,application/pdf,application/zip,video/mp4,video/webm,audio/mpeg,audio/wav">
|
||||
<small class="form-text text-muted">Toegestaan: JPG, PNG, GIF, WebP, SVG, PDF, ZIP, MP4, WebM, MP3, WAV</small>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success">
|
||||
<i class="bi bi-cloud-upload"></i> Uploaden naar deze map
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($subdir)): ?>
|
||||
@@ -39,7 +65,7 @@
|
||||
<th>Type</th>
|
||||
<th>Grootte</th>
|
||||
<th>Gewijzigd</th>
|
||||
<th style="width: 120px;">Acties</th>
|
||||
<th style="width: 200px;">Acties</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -77,10 +103,26 @@
|
||||
<td class="text-muted"><?= $item['size'] ?></td>
|
||||
<td class="text-muted"><?= $item['modified'] ?></td>
|
||||
<td>
|
||||
<?php if (!$item['is_dir']): ?>
|
||||
<?php if ($item['is_dir']): ?>
|
||||
<a href="admin.php?route=content-dir-rename&dir=<?= urlencode($item['path']) ?>" class="btn btn-sm btn-outline-secondary" title="Hernoemen">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
<a href="admin.php?route=content-move&item=<?= urlencode($item['path']) ?>" class="btn btn-sm btn-outline-info" title="Verplaatsen">
|
||||
<i class="bi bi-arrows-move"></i>
|
||||
</a>
|
||||
<form method="POST" action="admin.php?route=content-dir-delete&dir=<?= urlencode($item['path']) ?>" class="d-inline" onsubmit="return confirm('Weet je zeker dat je deze map wilt verwijderen? De map moet leeg zijn.')">
|
||||
<input type="hidden" name="csrf_token" value="<?= $csrf ?>">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" title="Verwijderen">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<a href="admin.php?route=content-edit&file=<?= urlencode($item['path']) ?>" class="btn btn-sm btn-outline-primary" title="Bewerken">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
<a href="admin.php?route=content-move&item=<?= urlencode($item['path']) ?>" class="btn btn-sm btn-outline-info" title="Verplaatsen">
|
||||
<i class="bi bi-arrows-move"></i>
|
||||
</a>
|
||||
<form method="POST" action="admin.php?route=content-delete&file=<?= urlencode($item['path']) ?>" class="d-inline" onsubmit="return confirm('Weet je zeker dat je dit bestand wilt verwijderen?')">
|
||||
<input type="hidden" name="csrf_token" value="<?= $csrf ?>">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" title="Verwijderen">
|
||||
@@ -96,3 +138,29 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Create Directory Modal -->
|
||||
<div class="modal fade" id="createDirModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<form method="POST" action="admin.php?route=content-dir-create&dir=<?= urlencode($subdir) ?>">
|
||||
<input type="hidden" name="csrf_token" value="<?= $csrf ?>">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><i class="bi bi-folder-plus"></i> Nieuwe map aanmaken</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label for="dirname" class="form-label">Mapnaam</label>
|
||||
<input type="text" class="form-control" id="dirname" name="dirname" required autofocus>
|
||||
<div class="form-text">Alleen letters, cijfers, punten, underscores en streepjes.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuleren</button>
|
||||
<button type="submit" class="btn btn-primary"><i class="bi bi-check-lg"></i> Aanmaken</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
74
admin/templates/pages/plugin-config.php
Normal file
74
admin/templates/pages/plugin-config.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<h2 class="mb-4"><i class="bi bi-plug"></i> Plugin Configuratie: <?= htmlspecialchars($pluginName) ?></h2>
|
||||
|
||||
<form method="post" class="card shadow-sm">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrf) ?>">
|
||||
|
||||
<div class="card-body">
|
||||
<?php if (empty($pluginConfig)): ?>
|
||||
<div class="alert alert-info">Deze plugin heeft geen configureerbare instellingen.</div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($pluginConfig as $key => $value): ?>
|
||||
<?= renderConfigField($key, $value) ?>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($pluginConfig)): ?>
|
||||
<div class="card-footer text-end">
|
||||
<a href="admin.php?route=plugins" class="btn btn-secondary">Annuleren</a>
|
||||
<button type="submit" class="btn btn-primary"><i class="bi bi-check-lg"></i> Opslaan</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
|
||||
<div class="mt-3">
|
||||
<a href="admin.php?route=plugins" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="bi bi-arrow-left"></i> Terug naar plugins
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
function renderConfigField(string $key, $value, string $prefix = ''): string
|
||||
{
|
||||
$name = $prefix ? $prefix . '[' . $key . ']' : 'config[' . $key . ']';
|
||||
$id = 'cfg_' . str_replace(['.', '['], '_', rtrim($name, ']'));
|
||||
$label = ucwords(str_replace('_', ' ', $key));
|
||||
$html = '';
|
||||
|
||||
if (is_bool($value)) {
|
||||
$checked = $value ? 'checked' : '';
|
||||
$html .= '<div class="mb-3 form-check form-switch">';
|
||||
$html .= '<input type="hidden" name="' . htmlspecialchars($name) . '" value="0">';
|
||||
$html .= '<input class="form-check-input" type="checkbox" id="' . htmlspecialchars($id) . '" name="' . htmlspecialchars($name) . '" value="1" ' . $checked . '>';
|
||||
$html .= '<label class="form-check-label" for="' . htmlspecialchars($id) . '">' . htmlspecialchars($label) . '</label>';
|
||||
$html .= '</div>';
|
||||
} elseif (is_numeric($value)) {
|
||||
$step = is_float($value) ? 'step="0.01"' : 'step="1"';
|
||||
$html .= '<div class="mb-3">';
|
||||
$html .= '<label for="' . htmlspecialchars($id) . '" class="form-label">' . htmlspecialchars($label) . '</label>';
|
||||
$html .= '<input type="number" class="form-control" id="' . htmlspecialchars($id) . '" name="' . htmlspecialchars($name) . '" value="' . htmlspecialchars($value) . '" ' . $step . '>';
|
||||
$html .= '</div>';
|
||||
} elseif (is_array($value)) {
|
||||
$html .= '<div class="mb-3">';
|
||||
$html .= '<label class="form-label fw-bold">' . htmlspecialchars($label) . '</label>';
|
||||
$html .= '<div class="card bg-light">';
|
||||
$html .= '<div class="card-body">';
|
||||
foreach ($value as $subKey => $subValue) {
|
||||
$html .= renderConfigField($subKey, $subValue, $name);
|
||||
}
|
||||
$html .= '</div></div></div>';
|
||||
} else {
|
||||
$html .= '<div class="mb-3">';
|
||||
$html .= '<label for="' . htmlspecialchars($id) . '" class="form-label">' . htmlspecialchars($label) . '</label>';
|
||||
|
||||
if (strlen($value) > 80 || str_contains($value, "\n")) {
|
||||
$html .= '<textarea class="form-control font-monospace" id="' . htmlspecialchars($id) . '" name="' . htmlspecialchars($name) . '" rows="4">' . htmlspecialchars($value) . '</textarea>';
|
||||
} else {
|
||||
$html .= '<input type="text" class="form-control" id="' . htmlspecialchars($id) . '" name="' . htmlspecialchars($name) . '" value="' . htmlspecialchars($value) . '">';
|
||||
}
|
||||
|
||||
$html .= '</div>';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
28
admin/templates/pages/plugins-edit.php
Normal file
28
admin/templates/pages/plugins-edit.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2><i class="bi bi-pencil"></i> Plugin bewerken: <?= htmlspecialchars($pluginName) ?></h2>
|
||||
<a href="admin.php?route=plugins" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="bi bi-arrow-left"></i> Terug
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<form method="POST" action="admin.php?route=plugins-edit&plugin=<?= urlencode($pluginName) ?>" id="editor-form">
|
||||
<input type="hidden" name="csrf_token" value="<?= $csrf ?>">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<span class="badge bg-secondary">PHP</span>
|
||||
<small class="text-muted"><?= htmlspecialchars($pluginName) ?>/<?= htmlspecialchars($pluginName) ?>.php</small>
|
||||
</div>
|
||||
<div class="editor-toolbar" id="editor-toolbar"></div>
|
||||
<div class="editor-wrapper">
|
||||
<textarea name="content" id="editor-textarea" data-ext="php"><?= htmlspecialchars($fileContent) ?></textarea>
|
||||
</div>
|
||||
<div class="d-flex gap-2 mt-3">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check-lg"></i> Opslaan
|
||||
</button>
|
||||
<a href="admin.php?route=plugins" class="btn btn-outline-secondary">Annuleren</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
40
admin/templates/pages/plugins-new.php
Normal file
40
admin/templates/pages/plugins-new.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<h2 class="mb-4"><i class="bi bi-plug"></i> Nieuwe plugin aanmaken</h2>
|
||||
|
||||
<form method="post" class="card shadow-sm">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrf) ?>">
|
||||
|
||||
<div class="card-body">
|
||||
<?php if (!empty($message)): ?>
|
||||
<div class="alert alert-<?= $messageType ?>"><?= htmlspecialchars($message) ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="plugin_name" class="form-label">Plugin naam</label>
|
||||
<input type="text" class="form-control font-monospace" id="plugin_name" name="plugin_name"
|
||||
value="<?= htmlspecialchars($_POST['plugin_name'] ?? '') ?>" required
|
||||
placeholder="bijv. MijnPlugin">
|
||||
<div class="form-text">Alleen letters, cijfers en underscores. Begin met een hoofdletter. Wordt gebruikt als <strong>mapnaam</strong>, <strong>bestandsnaam</strong> en <strong>class naam</strong>.</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="plugin_desc" class="form-label">Omschrijving <small class="text-muted">(optioneel)</small></label>
|
||||
<textarea class="form-control" id="plugin_desc" name="plugin_desc" rows="3"
|
||||
placeholder="Korte omschrijving van wat de plugin doet..."><?= htmlspecialchars($_POST['plugin_desc'] ?? '') ?></textarea>
|
||||
<div class="form-text">Wordt opgeslagen als README.md bij de plugin.</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info mb-0">
|
||||
<strong><i class="bi bi-lightbulb"></i> Wat wordt er aangemaakt?</strong>
|
||||
<ul class="mb-0 mt-2">
|
||||
<li><code>plugins/PluginNaam/PluginNaam.php</code> — Hoofdbestand met boilerplate</li>
|
||||
<li><code>plugins/PluginNaam/config.json</code> — Configuratiebestand</li>
|
||||
<li><code>plugins/PluginNaam/README.md</code> — Documentatie (alleen bij omschrijving)</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-footer text-end">
|
||||
<a href="admin.php?route=plugins" class="btn btn-secondary">Annuleren</a>
|
||||
<button type="submit" class="btn btn-primary"><i class="bi bi-check-lg"></i> Aanmaken</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -1,4 +1,78 @@
|
||||
<h2 class="mb-4"><i class="bi bi-plug"></i> Plugins</h2>
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2><i class="bi bi-plug"></i> Plugins</h2>
|
||||
<a href="admin.php?route=plugins-new" class="btn btn-primary btn-sm">
|
||||
<i class="bi bi-plus-lg"></i> Nieuwe plugin
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-info-circle"></i> Plugin Ontwikkelaarshandleiding</h5>
|
||||
<p class="text-muted mb-2">Een plugin moet aan de volgende eisen voldoen om correct te werken:</p>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-4">
|
||||
<div class="d-flex align-items-start">
|
||||
<i class="bi bi-folder2-open text-primary me-2 mt-1"></i>
|
||||
<div>
|
||||
<strong>Mapstructuur</strong><br>
|
||||
<code class="small">plugins/Naam/Naam.php</code>
|
||||
<small class="text-muted d-block">Mapnaam en bestandsnaam moeten identiek zijn.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="d-flex align-items-start">
|
||||
<i class="bi bi-code-square text-primary me-2 mt-1"></i>
|
||||
<div>
|
||||
<strong>Class naam</strong><br>
|
||||
<code class="small">class PluginNaam</code>
|
||||
<small class="text-muted d-block">De class moet exact dezelfde naam hebben als de map.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="d-flex align-items-start">
|
||||
<i class="bi bi-puzzle text-primary me-2 mt-1"></i>
|
||||
<div>
|
||||
<strong>Optionele hooks</strong><br>
|
||||
<code class="small">setAPI(CMSAPI)</code> · <code class="small">getSidebarContent()</code>
|
||||
<small class="text-muted d-block">Voor CMS-toegang en sidebar-weergave.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="d-flex align-items-start">
|
||||
<i class="bi bi-gear-wide text-primary me-2 mt-1"></i>
|
||||
<div>
|
||||
<strong>Configuratie (optioneel)</strong><br>
|
||||
<code class="small">config.json</code>
|
||||
<small class="text-muted d-block">Wordt getoond met een configuratieformulier in de admin.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="d-flex align-items-start">
|
||||
<i class="bi bi-shield-check text-primary me-2 mt-1"></i>
|
||||
<div>
|
||||
<strong>Beveiliging</strong><br>
|
||||
<code class="small">htmlspecialchars()</code>
|
||||
<small class="text-muted d-block">Altijd output escapen. Volg PSR-12.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="d-flex align-items-start">
|
||||
<i class="bi bi-book text-primary me-2 mt-1"></i>
|
||||
<div>
|
||||
<strong>Documentatie (optioneel)</strong><br>
|
||||
<code class="small">README.md</code>
|
||||
<small class="text-muted d-block">Aangeraden voor uitleg over de plugin.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (empty($plugins)): ?>
|
||||
<div class="alert alert-info">Geen plugins gevonden in de plugins map.</div>
|
||||
@@ -9,10 +83,10 @@
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<strong><i class="bi bi-plug"></i> <?= htmlspecialchars($plugin['name']) ?></strong>
|
||||
<?php if ($plugin['enabled']): ?>
|
||||
<span class="badge bg-success">Actief</span>
|
||||
<?php if ($plugin['viewable']): ?>
|
||||
<span class="badge bg-success">Zichtbaar</span>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-secondary">Inactief</span>
|
||||
<span class="badge bg-secondary">Systeem</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@@ -36,6 +110,32 @@
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="mt-3 d-flex justify-content-between align-items-center">
|
||||
<div class="btn-group btn-group-sm">
|
||||
<?php if ($plugin['has_main']): ?>
|
||||
<a href="admin.php?route=plugins-edit&plugin=<?= urlencode($plugin['name']) ?>" class="btn btn-outline-secondary" title="Bewerken">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<form method="POST" action="admin.php?route=plugins-toggle&plugin=<?= urlencode($plugin['name']) ?>" class="d-inline">
|
||||
<input type="hidden" name="csrf_token" value="<?= $csrf ?>">
|
||||
<button type="submit" class="btn btn-sm <?= $plugin['viewable'] ? 'btn-outline-warning' : 'btn-outline-success' ?>" title="<?= $plugin['viewable'] ? 'Verbergen' : 'Tonen' ?>">
|
||||
<i class="bi <?= $plugin['viewable'] ? 'bi-eye-slash' : 'bi-eye' ?>"></i> <?= $plugin['viewable'] ? 'Verberg' : 'Toon' ?>
|
||||
</button>
|
||||
</form>
|
||||
<?php if ($plugin['has_config']): ?>
|
||||
<a href="admin.php?route=plugins-config&plugin=<?= urlencode($plugin['name']) ?>" class="btn btn-outline-primary" title="Configureren">
|
||||
<i class="bi bi-gear"></i>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<form method="POST" action="admin.php?route=plugins-delete&plugin=<?= urlencode($plugin['name']) ?>" class="d-inline" onsubmit="return confirm('Weet je zeker dat je de plugin '<?= htmlspecialchars($plugin['name']) ?>' wilt verwijderen? Alle bestanden worden permanent verwijderd.')">
|
||||
<input type="hidden" name="csrf_token" value="<?= $csrf ?>">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" title="Verwijderen">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
283
admin/templates/pages/theme.php
Normal file
283
admin/templates/pages/theme.php
Normal file
@@ -0,0 +1,283 @@
|
||||
<?php if ($editTheme): ?>
|
||||
|
||||
<!-- Edit theme -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2><i class="bi bi-palette"></i> Bewerk thema: <?= htmlspecialchars($editTheme['name'] ?? $editThemeName) ?></h2>
|
||||
<a href="admin.php?route=theme" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="bi bi-arrow-left"></i> Terug
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<form method="POST" action="admin.php?route=theme" enctype="multipart/form-data">
|
||||
<input type="hidden" name="csrf_token" value="<?= $csrf ?>">
|
||||
<input type="hidden" name="action" value="save">
|
||||
<input type="hidden" name="theme" value="<?= htmlspecialchars($editThemeName) ?>">
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="theme_name" class="form-label">Themanaam</label>
|
||||
<input type="text" class="form-control" id="theme_name" name="theme_name" value="<?= htmlspecialchars($editTheme['name'] ?? $editThemeName) ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header">Header</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label for="header_color" class="form-label">Achtergrond</label>
|
||||
<div class="input-group">
|
||||
<input type="color" class="form-control form-control-color" id="header_color" name="header_color" value="<?= htmlspecialchars($editTheme['header_color'] ?? '#0a369d') ?>">
|
||||
<input type="text" class="form-control form-control-color-value" value="<?= htmlspecialchars($editTheme['header_color'] ?? '#0a369d') ?>" maxlength="7" data-target="header_color">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-0">
|
||||
<label for="header_font_color" class="form-label">Tekst</label>
|
||||
<div class="input-group">
|
||||
<input type="color" class="form-control form-control-color" id="header_font_color" name="header_font_color" value="<?= htmlspecialchars($editTheme['header_font_color'] ?? '#ffffff') ?>">
|
||||
<input type="text" class="form-control form-control-color-value" value="<?= htmlspecialchars($editTheme['header_font_color'] ?? '#ffffff') ?>" maxlength="7" data-target="header_font_color">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header">Navigatie</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label for="navigation_color" class="form-label">Achtergrond</label>
|
||||
<div class="input-group">
|
||||
<input type="color" class="form-control form-control-color" id="navigation_color" name="navigation_color" value="<?= htmlspecialchars($editTheme['navigation_color'] ?? '#2754b4') ?>">
|
||||
<input type="text" class="form-control form-control-color-value" value="<?= htmlspecialchars($editTheme['navigation_color'] ?? '#2754b4') ?>" maxlength="7" data-target="navigation_color">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-0">
|
||||
<label for="navigation_font_color" class="form-label">Tekst</label>
|
||||
<div class="input-group">
|
||||
<input type="color" class="form-control form-control-color" id="navigation_font_color" name="navigation_font_color" value="<?= htmlspecialchars($editTheme['navigation_font_color'] ?? '#ffffff') ?>">
|
||||
<input type="text" class="form-control form-control-color-value" value="<?= htmlspecialchars($editTheme['navigation_font_color'] ?? '#ffffff') ?>" maxlength="7" data-target="navigation_font_color">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header">Sidebar</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label for="sidebar_background" class="form-label">Achtergrond</label>
|
||||
<div class="input-group">
|
||||
<input type="color" class="form-control form-control-color" id="sidebar_background" name="sidebar_background" value="<?= htmlspecialchars($editTheme['sidebar_background'] ?? '#f8f9fa') ?>">
|
||||
<input type="text" class="form-control form-control-color-value" value="<?= htmlspecialchars($editTheme['sidebar_background'] ?? '#f8f9fa') ?>" maxlength="7" data-target="sidebar_background">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-0">
|
||||
<label for="sidebar_border" class="form-label">Rand</label>
|
||||
<div class="input-group">
|
||||
<input type="color" class="form-control form-control-color" id="sidebar_border" name="sidebar_border" value="<?= htmlspecialchars($editTheme['sidebar_border'] ?? '#dee2e6') ?>">
|
||||
<input type="text" class="form-control form-control-color-value" value="<?= htmlspecialchars($editTheme['sidebar_border'] ?? '#dee2e6') ?>" maxlength="7" data-target="sidebar_border">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4 mt-2">
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header"><i class="bi bi-arrows-vertical"></i> Hoogte balken</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label for="header_height" class="form-label">Header hoogte (px)</label>
|
||||
<input type="number" class="form-control" id="header_height" name="header_height" value="<?= htmlspecialchars($editTheme['header_height'] ?? '56') ?>" min="32" max="200">
|
||||
</div>
|
||||
<div class="mb-0">
|
||||
<label for="nav_height" class="form-label">Navigatie hoogte (px)</label>
|
||||
<input type="number" class="form-control" id="nav_height" name="nav_height" value="<?= htmlspecialchars($editTheme['nav_height'] ?? '42') ?>" min="24" max="200">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header"><i class="bi bi-image"></i> Header achtergrond afbeelding</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label for="bg_image" class="form-label">Upload afbeelding</label>
|
||||
<input type="file" class="form-control" id="bg_image" name="bg_image" accept="image/jpeg,image/png,image/gif,image/webp,image/svg+xml">
|
||||
<small class="form-text text-muted">Toegestaan: JPG, PNG, GIF, WebP, SVG</small>
|
||||
</div>
|
||||
<div class="mb-0">
|
||||
<label for="background_image_url" class="form-label">Of URL naar afbeelding</label>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" id="background_image_url" name="background_image_url" placeholder="https://..." value="<?= htmlspecialchars(str_starts_with($editTheme['background_image'] ?? '', 'http') ? $editTheme['background_image'] : '') ?>">
|
||||
</div>
|
||||
<?php if (!empty($editTheme['background_image'])): ?>
|
||||
<div class="mt-2 d-flex align-items-center gap-3">
|
||||
<div>
|
||||
<small class="text-muted">Huidig:</small>
|
||||
<img src="<?= htmlspecialchars(str_starts_with($editTheme['background_image'], 'http') ? $editTheme['background_image'] : '/themes/' . $editTheme['background_image']) ?>" style="max-height: 60px; max-width: 200px;" class="img-thumbnail mt-1 d-block">
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="btn-check" type="checkbox" id="bg_image_remove" name="bg_image_remove" value="1" autocomplete="off">
|
||||
<label class="btn btn-outline-danger btn-sm" for="bg_image_remove">
|
||||
<i class="bi bi-trash3"></i> Verwijder afbeelding
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="mb-3 mt-3">
|
||||
<label for="background_image_opacity" class="form-label">Doorzichtigheid (%)</label>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<input type="range" class="form-range" style="max-width: 200px;" id="background_image_opacity" name="background_image_opacity" min="0" max="100" value="<?= htmlspecialchars($editTheme['background_image_opacity'] ?? '100') ?>" oninput="this.nextElementSibling.textContent=this.value+'%'">
|
||||
<span class="badge bg-secondary"><?= htmlspecialchars($editTheme['background_image_opacity'] ?? '100') ?>%</span>
|
||||
</div>
|
||||
<small class="form-text text-muted">100% = volledig zichtbaar, 50% = half doorzichtig, 0% = onzichtbaar</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check-lg"></i> Opslaan
|
||||
</button>
|
||||
<a href="admin.php?route=theme" class="btn btn-outline-secondary">Annuleren</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php else: ?>
|
||||
|
||||
<!-- Theme list -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2><i class="bi bi-palette"></i> Thema's</h2>
|
||||
<button type="button" class="btn btn-primary btn-sm" data-bs-toggle="collapse" data-bs-target="#newThemeForm">
|
||||
<i class="bi bi-plus-lg"></i> Nieuw thema
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="collapse mb-4" id="newThemeForm">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<form method="POST" action="admin.php?route=theme" class="row g-3 align-items-end">
|
||||
<input type="hidden" name="csrf_token" value="<?= $csrf ?>">
|
||||
<input type="hidden" name="action" value="create">
|
||||
<div class="col-md-6">
|
||||
<label for="new_name" class="form-label">Naam nieuw thema</label>
|
||||
<input type="text" class="form-control" id="new_name" name="new_name" placeholder="bijv. donker" required>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button type="submit" class="btn btn-success w-100">
|
||||
<i class="bi bi-plus-lg"></i> Aanmaken
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4">
|
||||
<?php foreach ($themes as $themeName => $themeData): ?>
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-start mb-3">
|
||||
<h5 class="card-title mb-0"><?= htmlspecialchars($themeData['name'] ?? $themeName) ?></h5>
|
||||
<?php if ($themeName === $activeTheme): ?>
|
||||
<span class="badge bg-success">Actief</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Color preview swatches -->
|
||||
<div class="mb-3">
|
||||
<div class="d-flex align-items-center gap-1 mb-2">
|
||||
<span class="small text-muted" style="width: 70px;">Header:</span>
|
||||
<span class="d-inline-block rounded" style="width: 24px; height: 24px; background: <?= htmlspecialchars($themeData['header_color'] ?? '#0a369d') ?>; border: 1px solid #dee2e6;"></span>
|
||||
<span class="small text-muted"><?= htmlspecialchars($themeData['header_color'] ?? '#0a369d') ?></span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-1 mb-2">
|
||||
<span class="small text-muted" style="width: 70px;">Navigatie:</span>
|
||||
<span class="d-inline-block rounded" style="width: 24px; height: 24px; background: <?= htmlspecialchars($themeData['navigation_color'] ?? '#2754b4') ?>; border: 1px solid #dee2e6;"></span>
|
||||
<span class="small text-muted"><?= htmlspecialchars($themeData['navigation_color'] ?? '#2754b4') ?></span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-1">
|
||||
<span class="small text-muted" style="width: 70px;">Sidebar:</span>
|
||||
<span class="d-inline-block rounded" style="width: 24px; height: 24px; background: <?= htmlspecialchars($themeData['sidebar_background'] ?? '#f8f9fa') ?>; border: 1px solid #dee2e6;"></span>
|
||||
<span class="small text-muted"><?= htmlspecialchars($themeData['sidebar_background'] ?? '#f8f9fa') ?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Heights and background image -->
|
||||
<div class="mb-3 small">
|
||||
<div class="text-muted mb-1">
|
||||
<i class="bi bi-arrows-vertical"></i> Header: <?= htmlspecialchars($themeData['header_height'] ?? '56') ?>px · Navigatie: <?= htmlspecialchars($themeData['nav_height'] ?? '42') ?>px
|
||||
</div>
|
||||
<?php if (!empty($themeData['background_image'])): ?>
|
||||
<div class="text-muted">
|
||||
<i class="bi bi-image"></i> Achtergrond: <?= htmlspecialchars($themeData['background_image_opacity'] ?? '100') ?>% zichtbaar
|
||||
<?php if (!str_starts_with($themeData['background_image'], 'http')): ?>
|
||||
<img src="/themes/<?= htmlspecialchars($themeData['background_image']) ?>" style="max-height: 30px; max-width: 80px;" class="img-thumbnail ms-1 align-middle">
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<a href="admin.php?route=theme&edit=<?= urlencode($themeName) ?>" class="btn btn-outline-primary btn-sm">
|
||||
<i class="bi bi-pencil"></i> Bewerken
|
||||
</a>
|
||||
<?php if ($themeName !== $activeTheme): ?>
|
||||
<form method="POST" action="admin.php?route=theme">
|
||||
<input type="hidden" name="csrf_token" value="<?= $csrf ?>">
|
||||
<input type="hidden" name="action" value="activate">
|
||||
<input type="hidden" name="theme" value="<?= htmlspecialchars($themeName) ?>">
|
||||
<button type="submit" class="btn btn-outline-success btn-sm">
|
||||
<i class="bi bi-check-circle"></i> Activeren
|
||||
</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
<?php if ($themeName !== 'default'): ?>
|
||||
<form method="POST" action="admin.php?route=theme">
|
||||
<input type="hidden" name="csrf_token" value="<?= $csrf ?>">
|
||||
<input type="hidden" name="action" value="delete">
|
||||
<input type="hidden" name="theme" value="<?= htmlspecialchars($themeName) ?>">
|
||||
<button type="submit" class="btn btn-outline-danger btn-sm" onclick="return confirm('Weet je zeker dat je thema '<?= htmlspecialchars($themeData['name'] ?? $themeName) ?>' wilt verwijderen?')">
|
||||
<i class="bi bi-trash"></i> Verwijderen
|
||||
</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<script>
|
||||
document.querySelectorAll('.form-control-color-value').forEach(function(input) {
|
||||
input.addEventListener('input', function() {
|
||||
var target = document.getElementById(this.dataset.target);
|
||||
if (target && /^#[0-9a-fA-F]{6}$/.test(this.value)) {
|
||||
target.value = this.value;
|
||||
}
|
||||
});
|
||||
});
|
||||
document.querySelectorAll('.form-control-color').forEach(function(input) {
|
||||
input.addEventListener('input', function() {
|
||||
var target = document.querySelector('[data-target="' + this.id + '"]');
|
||||
if (target) target.value = this.value;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user