v2.6.0: Content backup/git versioning, plugin type system, docs update
New features: - ContentBackup class with ZIP backup/restore and git versioning - Admin backup & restore page (content-backup.twig) with git init/commit/log/restore - Plugin type system: system (blue) vs content (green) with visual badges - PluginAPIInterface + AdminPluginAPI for plugin architecture - Essential plugin flag (cannot edit/deactivate/delete) Improvements: - Consolidated enabled_plugins config (removed plugins.enabled) - Removed Analytics/Logging toggles from admin config page - Fixed Dashboard plugin Twig comments rendered as text - Updated 20 guide files (NL+EN): configuratie, plugins, plugin-development, core-classes, theme-json, layouts, scss-styling, admin-beheerder, nieuw-thema, architectuur - Improved accessibility test script (grep -E, min/max checks) Cleanup: - Removed unused classes: ARIAComponents, AccessibilityManager, ContentSecurityPolicy, etc. - Removed vendor packages: mustache/mustache, php-mqtt/client - Removed old templates: logs.twig, statistics.twig (now plugins) - Moved language files to language/ directory Tests: - Pentest: 30/30 passed, 0 vulnerabilities - WCAG 2.1 AA: 25/25 passed, 100% compliance
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"users": [
|
||||
{
|
||||
"username": "admin",
|
||||
"password_hash": "$2y$12$CV2uORTIiie6s3jf9ANaneL7VLNqA5smXyrIzkcJFjlS2Vxfw1/HK",
|
||||
"role": "admin",
|
||||
"email": "",
|
||||
"author_name": "",
|
||||
"author_email": "",
|
||||
"created": "2025-01-01"
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"session_timeout": 1800,
|
||||
"max_login_attempts": 5,
|
||||
"lockout_duration": 900
|
||||
},
|
||||
"config": {
|
||||
"default_page": "auto"
|
||||
}
|
||||
}
|
||||
+39
-6
@@ -16,7 +16,7 @@ class AdminAuth
|
||||
*/
|
||||
public const ROLE_PERMISSIONS = [
|
||||
'admin' => ['*'],
|
||||
'content-manager' => ['dashboard', 'content', 'content-edit', 'content-new', 'content-delete', 'content-dir-create', 'content-dir-rename', 'content-dir-delete', 'content-move', 'guide', 'logout'],
|
||||
'content-manager' => ['dashboard', 'content', 'content-edit', 'content-new', 'content-delete', 'content-dir-create', 'content-dir-rename', 'content-dir-delete', 'content-move', 'content-backup', 'content-restore', 'content-git-init', 'content-git-commit', 'content-git-restore', 'guide', 'logout'],
|
||||
'bi-manager' => ['dashboard', 'statistics', 'logs', 'guide', 'logout'],
|
||||
'site-admin' => ['dashboard', 'theme', 'theme-new', 'plugins', 'plugins-new', 'plugins-edit', 'plugins-config', 'plugins-toggle', 'plugins-delete', 'statistics', 'logs', 'update', 'guide', 'logout'],
|
||||
];
|
||||
@@ -28,7 +28,7 @@ class AdminAuth
|
||||
'admin' => 'Admin',
|
||||
'content-manager' => 'Content Beheerder',
|
||||
'bi-manager' => 'BI Beheerder',
|
||||
'site-admin' => ' Site Admin',
|
||||
'site-admin' => 'Site Admin',
|
||||
];
|
||||
|
||||
public function __construct(array $appConfig)
|
||||
@@ -170,10 +170,19 @@ class AdminAuth
|
||||
if (!$this->isAuthenticated()) {
|
||||
return null;
|
||||
}
|
||||
return [
|
||||
'username' => $_SESSION['admin_user'],
|
||||
$username = $_SESSION['admin_user'];
|
||||
$userData = [
|
||||
'username' => $username,
|
||||
'role' => $_SESSION['admin_role'] ?? 'admin'
|
||||
];
|
||||
// Enrich with profile fields from admin.json
|
||||
$userEntry = $this->findUser($username);
|
||||
if ($userEntry) {
|
||||
$userData['email'] = $userEntry['email'] ?? '';
|
||||
$userData['author_name'] = $userEntry['author_name'] ?? '';
|
||||
$userData['author_email'] = $userEntry['author_email'] ?? '';
|
||||
}
|
||||
return $userData;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -244,13 +253,16 @@ class AdminAuth
|
||||
'username' => $u['username'],
|
||||
'role' => $role,
|
||||
'role_label' => self::getRoleLabel($role),
|
||||
'created' => $u['created'] ?? ''
|
||||
'created' => $u['created'] ?? '',
|
||||
'email' => $u['email'] ?? '',
|
||||
'author_name' => $u['author_name'] ?? '',
|
||||
'author_email' => $u['author_email'] ?? '',
|
||||
];
|
||||
}
|
||||
return $users;
|
||||
}
|
||||
|
||||
public function addUser(string $username, string $password, string $role = 'admin'): array
|
||||
public function addUser(string $username, string $password, string $role = 'admin', string $email = '', string $authorName = '', string $authorEmail = ''): array
|
||||
{
|
||||
if ($this->findUser($username)) {
|
||||
return ['success' => false, 'message' => 'Gebruiker bestaat al.'];
|
||||
@@ -266,6 +278,9 @@ class AdminAuth
|
||||
'username' => $username,
|
||||
'password_hash' => password_hash($password, PASSWORD_DEFAULT),
|
||||
'role' => $role,
|
||||
'email' => $email,
|
||||
'author_name' => $authorName,
|
||||
'author_email' => $authorEmail,
|
||||
'created' => date('Y-m-d')
|
||||
];
|
||||
$this->saveAdminConfig();
|
||||
@@ -273,6 +288,24 @@ class AdminAuth
|
||||
return ['success' => true, 'message' => 'Gebruiker aangemaakt.'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the profile (email, author_name, author_email) of a user.
|
||||
*/
|
||||
public function updateUserProfile(string $username, string $email = '', string $authorName = '', string $authorEmail = ''): array
|
||||
{
|
||||
foreach ($this->adminConfig['users'] as &$userEntry) {
|
||||
if ($userEntry['username'] === $username) {
|
||||
$userEntry['email'] = $email;
|
||||
$userEntry['author_name'] = $authorName;
|
||||
$userEntry['author_email'] = $authorEmail;
|
||||
$this->saveAdminConfig();
|
||||
$this->log('info', "Profiel bijgewerkt: {$username}");
|
||||
return ['success' => true, 'message' => 'Profiel opgeslagen.'];
|
||||
}
|
||||
}
|
||||
return ['success' => false, 'message' => 'Gebruiker niet gevonden.'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the role of an existing user.
|
||||
*/
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="nl">
|
||||
<html lang="{{ admin_lang|default('nl') }}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}CodePress Admin{% endblock %}</title>
|
||||
<title>{% block title %}{{ ta.admin_title|default('CodePress Admin') }}{% endblock %}</title>
|
||||
<link rel="stylesheet" href="/admin/assets/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/admin/assets/css/bootstrap-icons.css">
|
||||
<link rel="stylesheet" href="/admin/assets/css/style.css">
|
||||
@@ -37,98 +37,95 @@
|
||||
<body>
|
||||
<nav class="admin-sidebar d-flex flex-column">
|
||||
<div class="admin-brand">
|
||||
<i class="bi bi-gear-fill"></i> CodePress Admin
|
||||
<i class="bi bi-gear-fill"></i> {{ ta.admin_title|default('CodePress Admin') }}
|
||||
</div>
|
||||
<ul class="nav flex-column mt-2">
|
||||
<li class="nav-section">Algemeen</li>
|
||||
{# Algemene sectie: Dashboard (plugin) + plugin items met section=general #}
|
||||
{% set general_plugins = plugin_admin_menu|filter(item => (item.section|default('general')) == 'general') %}
|
||||
{% if general_plugins is not empty or has_permission('dashboard') or true %}
|
||||
<li class="nav-section">{{ ta.section_general|default('Algemeen') }}</li>
|
||||
{% for item in general_plugins %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ route == 'dashboard' or route == '' ? 'active' : '' }}" href="/admin/dashboard">
|
||||
<i class="bi bi-speedometer2"></i> Dashboard
|
||||
<a class="nav-link {{ route == item.route or route starts with item.route ~ '/' ? 'active' : '' }}" href="/admin/{{ item.route }}">
|
||||
<i class="bi {{ item.icon|default('bi-puzzle') }}"></i> {{ item.label|default(item.route) }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if has_permission('content') %}
|
||||
<li class="nav-section">Content</li>
|
||||
<li class="nav-section">{{ ta.section_content|default('Content') }}</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ route starts with 'content' ? 'active' : '' }}" href="/admin/content">
|
||||
<i class="bi bi-file-earmark-text"></i> Content
|
||||
<i class="bi bi-file-earmark-text"></i> {{ ta.content|default('Content') }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% if has_permission('config') or has_permission('theme') or has_permission('security') %}
|
||||
<li class="nav-section">Instellingen</li>
|
||||
<li class="nav-section">{{ ta.section_settings|default('Instellingen') }}</li>
|
||||
{% if has_permission('config') %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ route == 'config' ? 'active' : '' }}" href="/admin/config">
|
||||
<i class="bi bi-sliders"></i> Configuratie
|
||||
<i class="bi bi-sliders"></i> {{ ta.configuration|default('Configuratie') }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if has_permission('theme') %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ route == 'theme' ? 'active' : '' }}" href="/admin/theme">
|
||||
<i class="bi bi-palette"></i> Thema
|
||||
<i class="bi bi-palette"></i> {{ ta.theme|default('Thema') }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if has_permission('security') %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ route == 'security' ? 'active' : '' }}" href="/admin/security">
|
||||
<i class="bi bi-shield-check"></i> Beveiliging
|
||||
<i class="bi bi-shield-check"></i> {{ ta.security|default('Beveiliging') }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if has_permission('statistics') or has_permission('logs') %}
|
||||
<li class="nav-section">Gegevens</li>
|
||||
{% if has_permission('statistics') %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ route == 'statistics' ? 'active' : '' }}" href="/admin/statistics">
|
||||
<i class="bi bi-bar-chart"></i> Statistieken
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if has_permission('logs') %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ route == 'logs' ? 'active' : '' }}" href="/admin/logs">
|
||||
<i class="bi bi-journal-text"></i> Logs
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if has_permission('plugins') or has_permission('users') or has_permission('update') %}
|
||||
<li class="nav-section">Systeem</li>
|
||||
{# Systeem sectie: core admin items + plugin items met section=system #}
|
||||
{% set system_plugins = plugin_admin_menu|filter(item => (item.section|default('general')) == 'system') %}
|
||||
{% if has_permission('plugins') or has_permission('users') or has_permission('update') or system_plugins is not empty %}
|
||||
<li class="nav-section">{{ ta.section_system|default('Systeem') }}</li>
|
||||
{% if has_permission('plugins') %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ route == 'plugins' ? 'active' : '' }}" href="/admin/plugins">
|
||||
<i class="bi bi-plug"></i> Plugins
|
||||
<i class="bi bi-plug"></i> {{ ta.plugins|default('Plugins') }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if has_permission('users') %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ route == 'users' ? 'active' : '' }}" href="/admin/users">
|
||||
<i class="bi bi-people"></i> Gebruikers
|
||||
<i class="bi bi-people"></i> {{ ta.users|default('Gebruikers') }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if has_permission('update') %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ route == 'update' ? 'active' : '' }}" href="/admin/update">
|
||||
<i class="bi bi-cloud-arrow-down"></i> Update
|
||||
<i class="bi bi-cloud-arrow-down"></i> {{ ta.update|default('Update') }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% for item in system_plugins %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ route == item.route or route starts with item.route ~ '/' ? 'active' : '' }}" href="/admin/{{ item.route }}">
|
||||
<i class="bi {{ item.icon|default('bi-puzzle') }}"></i> {{ item.label|default(item.route) }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if has_permission('guide') %}
|
||||
<li class="nav-section">Help</li>
|
||||
<li class="nav-section">{{ ta.section_help|default('Help') }}</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ route == 'guide' ? 'active' : '' }}" href="/admin/guide">
|
||||
<i class="bi bi-book"></i> Handleiding
|
||||
<i class="bi bi-book"></i> {{ ta.guide|default('Handleiding') }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
@@ -137,12 +134,12 @@
|
||||
<ul class="nav flex-column mt-auto mb-5">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/" target="_blank">
|
||||
<i class="bi bi-box-arrow-up-right"></i> Website bekijken
|
||||
<i class="bi bi-box-arrow-up-right"></i> {{ ta.view_website|default('Website bekijken') }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-warning" href="/admin/logout">
|
||||
<i class="bi bi-box-arrow-left"></i> Uitloggen
|
||||
<i class="bi bi-box-arrow-left"></i> {{ ta.logout|default('Uitloggen') }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="nl">
|
||||
<html lang="{{ admin_lang|default('nl') }}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>CodePress Admin - Login</title>
|
||||
<title>{{ ta.login_title|default('CodePress Admin - Login') }}</title>
|
||||
<link rel="stylesheet" href="/admin/assets/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/admin/assets/css/bootstrap-icons.css">
|
||||
<link rel="stylesheet" href="/admin/assets/css/style.css">
|
||||
@@ -17,7 +17,7 @@
|
||||
<div class="container">
|
||||
<div class="login-card">
|
||||
<div class="login-header">
|
||||
<h4><i class="bi bi-shield-lock"></i> CodePress Admin</h4>
|
||||
<h4><i class="bi bi-shield-lock"></i> {{ ta.admin_title|default('CodePress Admin') }}</h4>
|
||||
</div>
|
||||
<div class="card border-0 shadow-sm" style="border-radius: 0 0 0.5rem 0.5rem;">
|
||||
<div class="card-body p-4">
|
||||
@@ -30,14 +30,14 @@
|
||||
<form method="POST" action="/admin/login">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">Gebruikersnaam</label>
|
||||
<label for="username" class="form-label">{{ ta.username_label|default('Gebruikersnaam') }}</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="bi bi-person"></i></span>
|
||||
<input type="text" class="form-control" id="username" name="username" required autofocus>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Wachtwoord</label>
|
||||
<label for="password" class="form-label">{{ ta.password_label|default('Wachtwoord') }}</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="bi bi-key"></i></span>
|
||||
<input type="password" class="form-control" id="password" name="password" required>
|
||||
@@ -45,17 +45,17 @@
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-box-arrow-in-right"></i> Inloggen
|
||||
<i class="bi bi-box-arrow-in-right"></i> {{ ta.login_btn|default('Inloggen') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-center text-muted mt-3 small">
|
||||
<a href="/" class="text-decoration-none"><i class="bi bi-arrow-left"></i> Terug naar website</a>
|
||||
<a href="/" class="text-decoration-none"><i class="bi bi-arrow-left"></i> {{ ta.back_to_website|default('Terug naar website') }}</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/admin/assets/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -1,63 +1,111 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}Configuratie - CodePress Admin{% endblock %}
|
||||
{% block title %}{{ ta.configuration|default('Configuratie') }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4"><i class="bi bi-sliders"></i> Configuratie</h2>
|
||||
<h2 class="mb-4"><i class="bi bi-sliders"></i> {{ ta.configuration|default('Configuratie') }}</h2>
|
||||
|
||||
<form method="POST" action="/admin/config">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header">Algemene instellingen</div>
|
||||
<div class="card-header">{{ ta.section_settings|default('Instellingen') }}</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label for="site_title" class="form-label">Site titel</label>
|
||||
<label for="site_title" class="form-label">{{ ta.site_title|default('Site titel') }}</label>
|
||||
<input type="text" class="form-control" id="site_title" name="site_title" value="{{ config.site_title|default('CodePress') }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="language_default" class="form-label">Standaard taal</label>
|
||||
<select class="form-select" id="language_default" name="language_default">
|
||||
<label for="admin_language" class="form-label">{{ ta.admin_language|default('Admin taal') }}</label>
|
||||
<select class="form-select" id="admin_language" name="admin_language">
|
||||
<option value="nl" {{ config.admin_language|default('nl') == 'nl' ? 'selected' : '' }}>Nederlands</option>
|
||||
<option value="en" {{ config.admin_language == 'en' ? 'selected' : '' }}>English</option>
|
||||
<option value="de" {{ config.admin_language == 'de' ? 'selected' : '' }}>Deutsch</option>
|
||||
</select>
|
||||
<div class="form-text">{{ ta.admin_language_help|default('Taal van het admin-paneel (menu, knoppen, labels).') }}</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="content_language" class="form-label">{{ ta.content_language|default('Content taal') }}</label>
|
||||
<select class="form-select" id="content_language" name="content_language">
|
||||
<option value="nl" {{ config.language.default|default('nl') == 'nl' ? 'selected' : '' }}>Nederlands</option>
|
||||
<option value="en" {{ config.language.default == 'en' ? 'selected' : '' }}>Engels</option>
|
||||
<option value="de" {{ config.language.default == 'de' ? 'selected' : '' }}>Duits</option>
|
||||
<option value="fr" {{ config.language.default == 'fr' ? 'selected' : '' }}>Frans</option>
|
||||
<option value="en" {{ config.language.default == 'en' ? 'selected' : '' }}>English</option>
|
||||
<option value="de" {{ config.language.default == 'de' ? 'selected' : '' }}>Deutsch</option>
|
||||
<option value="fr" {{ config.language.default == 'fr' ? 'selected' : '' }}>Français</option>
|
||||
</select>
|
||||
<div class="form-text">{{ ta.content_language_help|default('Standaardtaal van de website-content (fallback als er geen taal in de URL staat).') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header">{{ ta.homepage|default('Homepage') }}</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted small mb-3">{{ ta.homepage_help|default('Bepaal welke pagina getoond wordt op de homepage.') }}</p>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">{{ ta.homepage_mode|default('Homepage-modus') }}</label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="default_page" id="dp_auto" value="auto" {{ current_default_page == 'auto' ? 'checked' : '' }}>
|
||||
<label class="form-check-label" for="dp_auto">{{ ta.homepage_auto|default('Automatisch — eerste beschikbare pagina') }}</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="default_page" id="dp_newest" value="newest" {{ current_default_page == 'newest' ? 'checked' : '' }}>
|
||||
<label class="form-check-label" for="dp_newest">{{ ta.homepage_newest|default('Meest recent aangepaste pagina') }}</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="default_page" id="dp_specific" value="specific" {{ current_default_page not in ['auto', 'newest'] ? 'checked' : '' }}>
|
||||
<label class="form-check-label" for="dp_specific">{{ ta.homepage_specific|default('Specifieke pagina') }}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3" id="specific_page_wrapper" style="display: none;">
|
||||
<label for="default_page_specific" class="form-label">{{ ta.homepage_select|default('Selecteer pagina') }}</label>
|
||||
<select class="form-select" id="default_page_specific" name="default_page_specific">
|
||||
{% for pageKey, pageLabel in content_pages %}
|
||||
<option value="{{ pageKey }}" {{ current_default_page == pageKey ? 'selected' : '' }}>{{ pageLabel }}</option>
|
||||
{% else %}
|
||||
<option value="" disabled>{{ ta.no_pages_found|default('Geen pagina\'s gevonden in content/') }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header">Auteur</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label for="author_name" class="form-label">Naam</label>
|
||||
<input type="text" class="form-control" id="author_name" name="author_name" value="{{ config.author.name|default('') }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="author_email" class="form-label">E-mail</label>
|
||||
<input type="email" class="form-control" id="author_email" name="author_email" value="{{ config.author.email|default('') }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header">Analytics & Logging</div>
|
||||
<div class="card-body">
|
||||
<div class="form-check form-switch mb-3">
|
||||
<input class="form-check-input" type="checkbox" id="analytics_enabled" name="analytics_enabled" {{ config.analytics.enabled ? 'checked' : '' }}>
|
||||
<label class="form-check-label" for="analytics_enabled">Analytics ingeschakeld</label>
|
||||
</div>
|
||||
<div class="form-check form-switch mb-3">
|
||||
<input class="form-check-input" type="checkbox" id="logging_enabled" name="logging_enabled" {{ config.logging.enabled ? 'checked' : '' }}>
|
||||
<label class="form-check-label" for="logging_enabled">Logging ingeschakeld</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check-lg"></i> Opslaan
|
||||
<i class="bi bi-check-lg"></i> {{ ta.save|default('Opslaan') }}
|
||||
</button>
|
||||
<a href="/admin/dashboard" class="btn btn-outline-secondary">Annuleren</a>
|
||||
<a href="/admin/dashboard" class="btn btn-outline-secondary">{{ ta.cancel|default('Annuleren') }}</a>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var radios = document.querySelectorAll('input[name="default_page"]');
|
||||
var wrapper = document.getElementById('specific_page_wrapper');
|
||||
var specificSelect = document.getElementById('default_page_specific');
|
||||
|
||||
function toggleWrapper() {
|
||||
var checked = document.querySelector('input[name="default_page"]:checked');
|
||||
if (checked && checked.value === 'specific') {
|
||||
wrapper.style.display = '';
|
||||
} else {
|
||||
wrapper.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
radios.forEach(function (r) {
|
||||
r.addEventListener('change', toggleWrapper);
|
||||
});
|
||||
|
||||
// If the specific select changes but the radio isn't on "specific", switch to it
|
||||
if (specificSelect) {
|
||||
specificSelect.addEventListener('change', function () {
|
||||
var specRadio = document.getElementById('dp_specific');
|
||||
if (specRadio && !specRadio.checked) {
|
||||
specRadio.checked = true;
|
||||
toggleWrapper();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
toggleWrapper();
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}{{ ta.backup_restore|default('Backup & Restore') }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2><i class="bi bi-archive"></i> {{ ta.backup_restore|default('Backup & Restore') }}</h2>
|
||||
<a href="/admin/content" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="bi bi-arrow-left"></i> {{ ta.back_to_content|default('Terug naar content') }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% if message %}
|
||||
<div class="alert alert-{{ message_type }} alert-dismissible fade show" role="alert">
|
||||
{{ message }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header"><i class="bi bi-file-zip"></i> {{ ta.zip_backup|default('ZIP Backup') }}</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted">{{ ta.zip_backup_help|default('Download de volledige content-map als ZIP bestand.') }}</p>
|
||||
<form method="POST" action="/admin/content-backup">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<input type="hidden" name="action" value="download_zip">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-download"></i> {{ ta.download_zip|default('Download ZIP') }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header"><i class="bi bi-upload"></i> {{ ta.restore_from_zip|default('Herstellen uit ZIP') }}</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted">{{ ta.restore_help|default('Upload een eerder gedownloade ZIP bestand om content te herstellen. De huidige content wordt eerst geback-upt.') }}</p>
|
||||
<form method="POST" action="/admin/content-restore" enctype="multipart/form-data">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<div class="mb-3">
|
||||
<label for="zipfile" class="form-label">{{ ta.select_zip|default('ZIP bestand selecteren') }}</label>
|
||||
<input type="file" class="form-control" id="zipfile" name="zipfile" accept=".zip" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-warning" onclick="return confirm('{{ ta.confirm_restore|default('Weet je zeker dat je de content wilt herstellen? Huidige content wordt geback-upt.') }}')">
|
||||
<i class="bi bi-arrow-counterclockwise"></i> {{ ta.restore|default('Herstellen') }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="my-4">
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span><i class="bi bi-git"></i> {{ ta.git_versioning|default('Git Versioning') }}</span>
|
||||
{% if git_available and not has_git_repo %}
|
||||
<form method="POST" action="/admin/content-git-init" class="d-inline">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<button type="submit" class="btn btn-sm btn-outline-success">
|
||||
<i class="bi bi-check2-circle"></i> {{ ta.git_init|default('Git init') }}
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if not git_available %}
|
||||
<div class="alert alert-secondary mb-0">
|
||||
<i class="bi bi-info-circle"></i> {{ ta.git_not_available|default('Git is niet beschikbaar op deze server. Gebruik de ZIP backup/restore opties hierboven.') }}
|
||||
</div>
|
||||
{% elseif not has_git_repo %}
|
||||
<div class="alert alert-info mb-0">
|
||||
<i class="bi bi-info-circle"></i> {{ ta.git_not_initialized|default('Geen git repository in content/. Klik op "Git init" om versiebeheer te starten.') }}
|
||||
</div>
|
||||
{% else %}
|
||||
<form method="POST" action="/admin/content-git-commit" class="mb-4">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" name="commit_message" placeholder="{{ ta.commit_message_placeholder|default('Commit bericht...') }}" maxlength="200">
|
||||
<button type="submit" class="btn btn-success">
|
||||
<i class="bi bi-check-lg"></i> {{ ta.commit|default('Commit') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% if git_commits is empty %}
|
||||
<p class="text-muted">{{ ta.no_commits|default('Nog geen commits. Maak een eerste commit aan.') }}</p>
|
||||
{% else %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ ta.commit_short|default('Commit') }}</th>
|
||||
<th>{{ ta.date|default('Datum') }}</th>
|
||||
<th>{{ ta.message|default('Bericht') }}</th>
|
||||
<th>{{ ta.actions|default('Acties') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for commit in git_commits %}
|
||||
<tr>
|
||||
<td><code>{{ commit.short }}</code></td>
|
||||
<td class="text-muted small">{{ commit.date }}</td>
|
||||
<td>{{ commit.message }}</td>
|
||||
<td>
|
||||
<form method="POST" action="/admin/content-git-restore" class="d-inline" onsubmit="return confirm('{{ ta.confirm_git_restore|default('Weet je zeker dat je de content wilt herstellen naar deze commit?') }}')">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<input type="hidden" name="commit" value="{{ commit.hash }}">
|
||||
<button type="submit" class="btn btn-sm btn-outline-warning" title="{{ ta.restore_this|default('Herstellen naar deze commit') }}">
|
||||
<i class="bi bi-arrow-counterclockwise"></i>
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,23 +1,23 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}Map hernoemen - CodePress Admin{% endblock %}
|
||||
{% block title %}{{ ta.rename_folder|default('Map hernoemen') }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4"><i class="bi bi-pencil"></i> Map hernoemen</h2>
|
||||
<h2 class="mb-4"><i class="bi bi-pencil"></i> {{ ta.rename_folder|default('Map hernoemen') }}</h2>
|
||||
|
||||
<form method="post" class="card shadow-sm">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label for="newname" class="form-label">Nieuwe naam voor {{ currentName }}</label>
|
||||
<label for="newname" class="form-label">{{ ta.new_name_for|default('Nieuwe naam voor') }} {{ currentName }}</label>
|
||||
<input type="text" class="form-control" id="newname" name="newname" value="{{ currentName }}" required autofocus>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-white">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check-lg"></i> Hernoemen
|
||||
<i class="bi bi-check-lg"></i> {{ ta.rename|default('Hernoemen') }}
|
||||
</button>
|
||||
<a href="/admin/content?dir={{ dir|url_encode }}" class="btn btn-outline-secondary">Annuleren</a>
|
||||
<a href="/admin/content?dir={{ dir|url_encode }}" class="btn btn-outline-secondary">{{ ta.cancel|default('Annuleren') }}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -1,6 +1,6 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}{{ fileName }} - CodePress Admin{% endblock %}
|
||||
{% block title %}{{ fileName }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4"><i class="bi bi-pencil"></i> {{ fileName }}</h2>
|
||||
@@ -11,16 +11,16 @@
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-4">
|
||||
<label for="filename" class="form-label">Bestandsnaam</label>
|
||||
<label for="filename" class="form-label">{{ ta.filename|default('Bestandsnaam') }}</label>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" id="filename" name="filename" value="{{ fileName|replace({'.md': '', '.php': '', '.html': ''}) }}" required>
|
||||
<span class="input-group-text">.{{ fileExt }}</span>
|
||||
</div>
|
||||
<small class="form-text text-muted">Alleen letters, cijfers, punten, underscores en streepjes.</small>
|
||||
<small class="form-text text-muted">{{ ta.name_help|default('Alleen letters, cijfers, punten, underscores en streepjes.') }}</small>
|
||||
</div>
|
||||
{% if isEditable %}
|
||||
<div class="col-md-4">
|
||||
<label for="layout" class="form-label">Sjabloon / Layout <small class="text-muted">({{ activeThemeName|default('default') }} theme)</small></label>
|
||||
<label for="layout" class="form-label">{{ ta.template_layout|default('Sjabloon / Layout') }} <small class="text-muted">({{ activeThemeName|default('default') }} theme)</small></label>
|
||||
<select class="form-select" id="layout" name="layout">
|
||||
{% for key, layoutFile in themeLayouts %}
|
||||
<option value="{{ key }}" {{ currentLayout == key ? 'selected' : '' }}>{{ key|replace({'_': ' '})|capitalize }}{% if key == themeDefaultLayout %} (standaard){% endif %}</option>
|
||||
@@ -29,7 +29,7 @@
|
||||
</div>
|
||||
{% if availablePlugins is not empty %}
|
||||
<div class="col-md-4">
|
||||
<label class="form-label d-block">Zichtbare plugins</label>
|
||||
<label class="form-label d-block">{{ ta.visible_plugins|default('Zichtbare plugins') }}</label>
|
||||
<div class="d-flex flex-wrap gap-1">
|
||||
{% for plugin in availablePlugins %}
|
||||
<input type="checkbox" class="btn-check" id="plugin-{{ plugin }}" name="plugins[]" value="{{ plugin }}" autocomplete="off" {{ plugin in selectedPlugins ? 'checked' : '' }}>
|
||||
@@ -47,15 +47,15 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="d-flex gap-2 mt-3">
|
||||
<button type="submit" class="btn btn-primary" title="Opslaan (Ctrl+S)">
|
||||
<i class="bi bi-check-lg"></i> Opslaan
|
||||
<button type="submit" class="btn btn-primary" title="{{ ta.save_ctrl_s|default('Opslaan (Ctrl+S)') }}">
|
||||
<i class="bi bi-check-lg"></i> {{ ta.save|default('Opslaan') }}
|
||||
</button>
|
||||
{% if isEditable %}
|
||||
<a href="/{{ currentLang }}{% if fileDir %}/{{ fileDir }}{% endif %}/{{ fileName|replace({'.md': '', '.php': '', '.html': ''}) }}" target="_blank" class="btn btn-outline-info" title="Open in nieuw tabblad">
|
||||
<i class="bi bi-eye"></i> Preview
|
||||
<a href="/{{ currentLang }}{% if fileDir %}/{{ fileDir }}{% endif %}/{{ fileName|replace({'.md': '', '.php': '', '.html': ''}) }}" target="_blank" class="btn btn-outline-info" title="{{ ta.open_new_tab|default('Open in nieuw tabblad') }}">
|
||||
<i class="bi bi-eye"></i> {{ ta.preview|default('Preview') }}
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="/admin/content?dir={{ fileDir|url_encode }}" class="btn btn-outline-secondary" id="back-btn">Terug</a>
|
||||
<a href="/admin/content?dir={{ fileDir|url_encode }}" class="btn btn-outline-secondary" id="back-btn">{{ ta.back|default('Terug') }}</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -121,4 +121,4 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
window.__onContentChange = markChanged;
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -1,18 +1,18 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}{{ isDir ? 'Map' : 'Bestand' }} verplaatsen - CodePress Admin{% endblock %}
|
||||
{% block title %}{% if isDir %}{{ ta.folder|default('Map') }}{% else %}{{ ta.file|default('Bestand') }}{% endif %} {{ ta.move_suffix|default('verplaatsen') }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4"><i class="bi bi-arrows-move"></i> {{ isDir ? 'Map' : 'Bestand' }} verplaatsen</h2>
|
||||
<h2 class="mb-4"><i class="bi bi-arrows-move"></i> {% if isDir %}{{ ta.folder|default('Map') }}{% else %}{{ ta.file|default('Bestand') }}{% endif %} {{ ta.move_suffix|default('verplaatsen') }}</h2>
|
||||
|
||||
<form method="post" class="card shadow-sm">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<div class="card-body">
|
||||
<div class="alert alert-info">
|
||||
Verplaats <strong>{{ itemName }}</strong> naar:
|
||||
{{ ta.move_prefix|default('Verplaats') }} <strong>{{ itemName }}</strong> {{ ta.move_to|default('naar:') }}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="destination" class="form-label">Doelmap</label>
|
||||
<label for="destination" class="form-label">{{ ta.target_folder|default('Doelmap') }}</label>
|
||||
<select class="form-select" id="destination" name="destination" required>
|
||||
{% for directory in directories %}
|
||||
<option value="{{ directory }}">{{ directory }}</option>
|
||||
@@ -22,9 +22,9 @@
|
||||
</div>
|
||||
<div class="card-footer bg-white">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check-lg"></i> Verplaatsen
|
||||
<i class="bi bi-check-lg"></i> {{ ta.move|default('Verplaatsen') }}
|
||||
</button>
|
||||
<a href="/admin/content?dir={{ itemDir|url_encode }}" class="btn btn-outline-secondary">Annuleren</a>
|
||||
<a href="/admin/content?dir={{ itemDir|url_encode }}" class="btn btn-outline-secondary">{{ ta.cancel|default('Annuleren') }}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -1,21 +1,21 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}Nieuwe pagina - CodePress Admin{% endblock %}
|
||||
{% block title %}{{ ta.new_page|default('Nieuwe pagina') }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4"><i class="bi bi-plus-lg"></i> Nieuwe pagina</h2>
|
||||
<h2 class="mb-4"><i class="bi bi-plus-lg"></i> {{ ta.new_page|default('Nieuwe pagina') }}</h2>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<form method="POST" action="/admin/content-new?dir={{ dir|url_encode }}" id="editor-form" data-new-page>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<div class="mb-3">
|
||||
<label for="filename" class="form-label">Bestandsnaam</label>
|
||||
<label for="filename" class="form-label">{{ ta.filename|default('Bestandsnaam') }}</label>
|
||||
<input type="text" class="form-control" id="filename" name="filename" required autofocus>
|
||||
<small class="form-text text-muted">Alleen letters, cijfers, punten, underscores en streepjes.</small>
|
||||
<small class="form-text text-muted">{{ ta.name_help|default('Alleen letters, cijfers, punten, underscores en streepjes.') }}</small>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="extension" class="form-label">Bestandstype</label>
|
||||
<label for="extension" class="form-label">{{ ta.file_type|default('Bestandstype') }}</label>
|
||||
<select class="form-select" id="extension" name="extension">
|
||||
{% for ext, label in availableExtensions %}
|
||||
<option value="{{ ext }}">{{ label }}</option>
|
||||
@@ -23,7 +23,7 @@
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="layout" class="form-label">Sjabloon / Layout <small class="text-muted">({{ activeThemeName|default('default') }} theme)</small></label>
|
||||
<label for="layout" class="form-label">{{ ta.template_layout|default('Sjabloon / Layout') }} <small class="text-muted">({{ activeThemeName|default('default') }} theme)</small></label>
|
||||
<select class="form-select" id="layout" name="layout">
|
||||
{% for key, layoutFile in themeLayouts %}
|
||||
<option value="{{ key }}" {{ key == themeDefaultLayout ? 'selected' : '' }}>{{ key|replace({'_': ' '})|capitalize }}{% if key == themeDefaultLayout %} (standaard){% endif %}</option>
|
||||
@@ -32,11 +32,11 @@
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check-lg"></i> Aanmaken
|
||||
<i class="bi bi-check-lg"></i> {{ ta.create|default('Aanmaken') }}
|
||||
</button>
|
||||
<a href="/admin/content?dir={{ dir|url_encode }}" class="btn btn-outline-secondary">Annuleren</a>
|
||||
<a href="/admin/content?dir={{ dir|url_encode }}" class="btn btn-outline-secondary">{{ ta.cancel|default('Annuleren') }}</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -1,19 +1,22 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}Content - CodePress Admin{% endblock %}
|
||||
{% block title %}{{ ta.content|default('Content') }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2><i class="bi bi-file-earmark-text"></i> Content</h2>
|
||||
<h2><i class="bi bi-file-earmark-text"></i> {{ ta.content|default('Content') }}</h2>
|
||||
<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
|
||||
<i class="bi bi-cloud-upload"></i> {{ ta.upload|default('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
|
||||
<i class="bi bi-folder-plus"></i> {{ ta.new_folder|default('Nieuwe map') }}
|
||||
</button>
|
||||
<a href="/admin/content-backup" class="btn btn-outline-info btn-sm me-1">
|
||||
<i class="bi bi-archive"></i> {{ ta.backup|default('Backup') }}
|
||||
</a>
|
||||
<a href="/admin/content-new?dir={{ subdir|url_encode }}" class="btn btn-primary btn-sm">
|
||||
<i class="bi bi-plus-lg"></i> Nieuw bestand
|
||||
<i class="bi bi-plus-lg"></i> {{ ta.new_file|default('Nieuw bestand') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -24,12 +27,12 @@
|
||||
<form method="POST" action="/admin/content?dir={{ subdir|url_encode }}" enctype="multipart/form-data">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<div class="mb-3">
|
||||
<label for="file" class="form-label">Bestanden selecteren</label>
|
||||
<label for="file" class="form-label">{{ ta.select_files|default('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>
|
||||
<small class="form-text text-muted">{{ ta.allowed_types|default('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
|
||||
<i class="bi bi-cloud-upload"></i> {{ ta.upload_to_folder|default('Uploaden naar deze map') }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -60,7 +63,7 @@
|
||||
<div class="card-header bg-white py-2">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-text bg-white border-end-0"><i class="bi bi-search text-muted"></i></span>
|
||||
<input type="search" id="contentFilter" class="form-control border-start-0" placeholder="Filter op bestands- of mapnaam…" autocomplete="off" aria-label="Filter content">
|
||||
<input type="search" id="contentFilter" class="form-control border-start-0" placeholder="{{ ta.filter_placeholder|default('Filter op bestands- of mapnaam…') }}" autocomplete="off" aria-label="{{ ta.filter_content|default('Filter content') }}">
|
||||
<span class="input-group-text bg-white text-muted" id="contentFilterCount"></span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -68,16 +71,16 @@
|
||||
<table class="table table-hover mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Naam</th>
|
||||
<th>Type</th>
|
||||
<th>Grootte</th>
|
||||
<th>Gewijzigd</th>
|
||||
<th style="width: 200px;">Acties</th>
|
||||
<th>{{ ta.col_name|default('Naam') }}</th>
|
||||
<th>{{ ta.col_type|default('Type') }}</th>
|
||||
<th>{{ ta.col_size|default('Grootte') }}</th>
|
||||
<th>{{ ta.col_modified|default('Gewijzigd') }}</th>
|
||||
<th style="width: 200px;">{{ ta.col_actions|default('Acties') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if items is empty %}
|
||||
<tr><td colspan="5" class="text-muted text-center py-4">Geen bestanden gevonden.</td></tr>
|
||||
<tr><td colspan="5" class="text-muted text-center py-4">{{ ta.no_files_found|default('Geen bestanden gevonden.') }}</td></tr>
|
||||
{% else %}
|
||||
{% for item in items %}
|
||||
<tr data-name="{{ item.name|lower }}">
|
||||
@@ -95,7 +98,7 @@
|
||||
</td>
|
||||
<td>
|
||||
{% if item.is_dir %}
|
||||
<span class="badge bg-warning text-dark">Map</span>
|
||||
<span class="badge bg-warning text-dark">{{ ta.folder_badge|default('Map') }}</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ item.extension|upper }}</span>
|
||||
{% endif %}
|
||||
@@ -104,28 +107,28 @@
|
||||
<td class="text-muted">{{ item.modified }}</td>
|
||||
<td>
|
||||
{% if item.is_dir %}
|
||||
<a href="/admin/content-dir-rename?dir={{ item.path|url_encode }}" class="btn btn-sm btn-outline-secondary" title="Hernoemen">
|
||||
<a href="/admin/content-dir-rename?dir={{ item.path|url_encode }}" class="btn btn-sm btn-outline-secondary" title="{{ ta.rename|default('Hernoemen') }}">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
<a href="/admin/content-move?item={{ item.path|url_encode }}" class="btn btn-sm btn-outline-info" title="Verplaatsen">
|
||||
<a href="/admin/content-move?item={{ item.path|url_encode }}" class="btn btn-sm btn-outline-info" title="{{ ta.move|default('Verplaatsen') }}">
|
||||
<i class="bi bi-arrows-move"></i>
|
||||
</a>
|
||||
<form method="POST" action="/admin/content-dir-delete?dir={{ item.path|url_encode }}" class="d-inline" onsubmit="return confirm('Weet je zeker dat je deze map wilt verwijderen? De map moet leeg zijn.')">
|
||||
<form method="POST" action="/admin/content-dir-delete?dir={{ item.path|url_encode }}" class="d-inline" onsubmit="return confirm('{{ ta.confirm_delete_folder|default('Weet je zeker dat je deze map wilt verwijderen? De map moet leeg zijn.') }}')">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" title="Verwijderen">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" title="{{ ta.delete|default('Verwijderen') }}">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<a href="/admin/content-edit?file={{ item.path|url_encode }}" class="btn btn-sm btn-outline-primary" title="Bewerken">
|
||||
<a href="/admin/content-edit?file={{ item.path|url_encode }}" class="btn btn-sm btn-outline-primary" title="{{ ta.edit|default('Bewerken') }}">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
<a href="/admin/content-move?item={{ item.path|url_encode }}" class="btn btn-sm btn-outline-info" title="Verplaatsen">
|
||||
<a href="/admin/content-move?item={{ item.path|url_encode }}" class="btn btn-sm btn-outline-info" title="{{ ta.move|default('Verplaatsen') }}">
|
||||
<i class="bi bi-arrows-move"></i>
|
||||
</a>
|
||||
<form method="POST" action="/admin/content-delete?file={{ item.path|url_encode }}" class="d-inline" onsubmit="return confirm('Weet je zeker dat je dit bestand wilt verwijderen?')">
|
||||
<form method="POST" action="/admin/content-delete?file={{ item.path|url_encode }}" class="d-inline" onsubmit="return confirm('{{ ta.confirm_delete_file|default('Weet je zeker dat je dit bestand wilt verwijderen?') }}')">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" title="Verwijderen">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" title="{{ ta.delete|default('Verwijderen') }}">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
@@ -135,7 +138,7 @@
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<tr id="contentFilterEmpty" class="d-none">
|
||||
<td colspan="5" class="text-muted text-center py-4">Geen resultaten voor deze filter.</td>
|
||||
<td colspan="5" class="text-muted text-center py-4">{{ ta.no_filter_results|default('Geen resultaten voor deze filter.') }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -188,22 +191,22 @@
|
||||
<form method="POST" action="/admin/content-dir-create?dir={{ subdir|url_encode }}">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><i class="bi bi-folder-plus"></i> Nieuwe map aanmaken</h5>
|
||||
<h5 class="modal-title"><i class="bi bi-folder-plus"></i> {{ ta.new_folder_title|default('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>
|
||||
<label for="dirname" class="form-label">{{ ta.folder_name|default('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 class="form-text">{{ ta.name_help|default('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>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ ta.cancel|default('Annuleren') }}</button>
|
||||
<button type="submit" class="btn btn-primary"><i class="bi bi-check-lg"></i> {{ ta.create|default('Aanmaken') }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -1,219 +1,78 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}Dashboard - CodePress Admin{% endblock %}
|
||||
{% block title %}{{ ta.dashboard|default('Dashboard') }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4"><i class="bi bi-speedometer2"></i> Dashboard</h2>
|
||||
<h2 class="mb-4"><i class="bi bi-speedometer2"></i> {{ ta.dashboard|default('Dashboard') }}</h2>
|
||||
|
||||
<div class="alert alert-light border mb-4">
|
||||
<strong>Welkom, {{ user.username }}</strong> — Ingelogd als <span class="badge bg-{{ user_role == 'admin' ? 'danger' : (user_role == 'content-manager' ? 'primary' : (user_role == 'bi-manager' ? 'success' : 'warning')) }}">{{ role_label(user_role) }}</span>
|
||||
<strong>{{ ta.welcome|default('Welkom,') }} {{ user.username }}</strong> — {{ ta.logged_in_as|default('Ingelogd als') }} <span class="badge bg-{{ user_role == 'admin' ? 'danger' : (user_role == 'content-manager' ? 'primary' : (user_role == 'bi-manager' ? 'success' : 'warning')) }}">{{ role_label(user_role) }}</span>
|
||||
</div>
|
||||
|
||||
{# Analytics stats - only for roles with statistics permission #}
|
||||
{% if has_permission('statistics') %}
|
||||
<div class="row g-4 mb-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card stat-card shadow-sm">
|
||||
<div class="card-body d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1">Weergaven (30 dagen)</h6>
|
||||
<h3 class="mb-0">{{ (analytics_summary.totals.views ?? 0)|number_format(0, ',', '.') }}</h3>
|
||||
</div>
|
||||
<i class="bi bi-eye stat-icon text-primary"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card stat-card shadow-sm">
|
||||
<div class="card-body d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1">Unieke bezoekers (30 dagen)</h6>
|
||||
<h3 class="mb-0">{{ (analytics_summary.totals.uniques ?? 0)|number_format(0, ',', '.') }}</h3>
|
||||
</div>
|
||||
<i class="bi bi-people stat-icon text-success"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card stat-card shadow-sm">
|
||||
<div class="card-body d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1">Grootste land</h6>
|
||||
<h3 class="mb-0">
|
||||
{{ get_country_flag(analytics_summary.countries|keys|first) }}
|
||||
<span class="fs-5">{{ get_country_name(analytics_summary.countries|keys|first) }}</span>
|
||||
</h3>
|
||||
</div>
|
||||
<a href="/admin/statistics" class="btn btn-sm btn-outline-secondary">Statistieken →</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Content stats - only for roles with content permission #}
|
||||
{% if has_permission('content') %}
|
||||
<div class="row g-4 mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card stat-card shadow-sm">
|
||||
<div class="card-body d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1">Pagina's</h6>
|
||||
<h3 class="mb-0">{{ stats.pages }}</h3>
|
||||
</div>
|
||||
<i class="bi bi-file-earmark-text stat-icon text-primary"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card stat-card shadow-sm">
|
||||
<div class="card-body d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1">Mappen</h6>
|
||||
<h3 class="mb-0">{{ stats.directories }}</h3>
|
||||
</div>
|
||||
<i class="bi bi-folder stat-icon text-warning"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card stat-card shadow-sm">
|
||||
<div class="card-body d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1">Content grootte</h6>
|
||||
<h3 class="mb-0">{{ stats.content_size }}</h3>
|
||||
</div>
|
||||
<i class="bi bi-hdd stat-icon text-info"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# System stats - only for admin/site-admin #}
|
||||
{% if has_permission('plugins') or has_permission('config') %}
|
||||
<div class="row g-4 mb-4">
|
||||
{% if has_permission('plugins') %}
|
||||
<div class="col-md-3">
|
||||
<div class="card stat-card shadow-sm">
|
||||
<div class="card-body d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1">Plugins</h6>
|
||||
<h3 class="mb-0">{{ stats.plugins }}</h3>
|
||||
</div>
|
||||
<i class="bi bi-plug stat-icon text-success"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="row g-4">
|
||||
{# Site information - only for admin #}
|
||||
{% if has_permission('config') %}
|
||||
{# Site information #}
|
||||
<div class="col-md-6">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header"><i class="bi bi-info-circle"></i> Site informatie</div>
|
||||
<div class="card-header"><i class="bi bi-info-circle"></i> {{ ta.site_info|default('Site informatie') }}</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm mb-0">
|
||||
<tr><td class="text-muted">Site titel</td><td>{{ site_config.site_title|default('CodePress') }}</td></tr>
|
||||
<tr><td class="text-muted">Standaard taal</td><td>{{ site_config.language.default|default('nl') }}</td></tr>
|
||||
<tr><td class="text-muted">Auteur</td><td>{{ site_config.author.name|default('-') }}</td></tr>
|
||||
<tr><td class="text-muted">CodePress versie</td><td>{{ stats.cms_version }}</td></tr>
|
||||
<tr><td class="text-muted">PHP versie</td><td>{{ stats.php_version }}</td></tr>
|
||||
<tr><td class="text-muted">Besturingssysteem</td><td>{{ stats.os }}</td></tr>
|
||||
<tr><td class="text-muted">Config geladen</td><td>{% if stats.config_exists %}<span class="badge bg-success">Ja</span>{% else %}<span class="badge bg-danger">Nee</span>{% endif %}</td></tr>
|
||||
<tr><td class="text-muted">{{ ta.site_title|default('Site titel') }}</td><td>{{ site_config.site_title|default('CodePress') }}</td></tr>
|
||||
<tr><td class="text-muted">{{ ta.default_lang|default('Standaard taal') }}</td><td>{{ site_config.language.default|default('nl') }}</td></tr>
|
||||
<tr><td class="text-muted">{{ ta.cms_version|default('CodePress versie') }}</td><td>{{ stats.cms_version }}</td></tr>
|
||||
<tr><td class="text-muted">{{ ta.php_version|default('PHP versie') }}</td><td>{{ stats.php_version }}</td></tr>
|
||||
<tr><td class="text-muted">{{ ta.os|default('Besturingssysteem') }}</td><td>{{ stats.os }}</td></tr>
|
||||
<tr><td class="text-muted">{{ ta.config_loaded|default('Config geladen') }}</td><td>{% if stats.config_exists %}<span class="badge bg-success">{{ ta.yes|default('Ja') }}</span>{% else %}<span class="badge bg-danger">{{ ta.no|default('Nee') }}</span>{% endif %}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Content information #}
|
||||
{% if has_permission('content') %}
|
||||
<div class="col-md-6">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header"><i class="bi bi-folder2-open"></i> {{ ta.content_info|default('Content informatie') }}</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm mb-0">
|
||||
<tr><td class="text-muted">{{ ta.pages|default('Pagina\'s') }}</td><td><span class="badge bg-primary">{{ stats.pages }}</span></td></tr>
|
||||
<tr><td class="text-muted">{{ ta.folders|default('Mappen') }}</td><td><span class="badge bg-warning text-dark">{{ stats.directories }}</span></td></tr>
|
||||
<tr><td class="text-muted">{{ ta.content_size|default('Content grootte') }}</td><td>{{ stats.content_size }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Recent activity - only for roles with logs permission #}
|
||||
{% if has_permission('logs') %}
|
||||
{# Plugins overview #}
|
||||
{% if has_permission('plugins') %}
|
||||
<div class="col-md-6">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span><i class="bi bi-activity"></i> Recente activiteit</span>
|
||||
<a href="/admin/logs?tab=admin" class="btn btn-sm btn-outline-secondary">Bekijk alle →</a>
|
||||
<span><i class="bi bi-plug"></i> {{ ta.plugins|default('Plugins') }}</span>
|
||||
<a href="/admin/plugins" class="btn btn-sm btn-outline-secondary">{{ ta.manage|default('Beheren') }}</a>
|
||||
</div>
|
||||
<div class="card-body" style="max-height: 300px; overflow-y: auto;">
|
||||
{% if recent_logs is empty %}
|
||||
<p class="text-muted mb-0">Geen activiteit geregistreerd.</p>
|
||||
{% else %}
|
||||
<ul class="list-unstyled mb-0">
|
||||
{% for log in recent_logs %}
|
||||
<li class="mb-2 pb-2 border-bottom small">
|
||||
<span class="text-muted">{{ log.time }}</span>
|
||||
<span class="badge bg-{{ log.level == 'warning' ? 'warning text-dark' : (log.level == 'error' ? 'danger' : 'info') }} me-1">{{ log.level }}</span>
|
||||
<code class="text-muted">{{ log.ip }}</code>
|
||||
{{ log.message }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span><i class="bi bi-globe"></i> Recente requests</span>
|
||||
<a href="/admin/logs?tab=requests" class="btn btn-sm btn-outline-secondary">Bekijk alle →</a>
|
||||
</div>
|
||||
<div class="card-body" style="max-height: 300px; overflow-y: auto;">
|
||||
{% if recent_requests is empty %}
|
||||
<p class="text-muted mb-0">Geen requests geregistreerd.</p>
|
||||
{% else %}
|
||||
<ul class="list-unstyled mb-0">
|
||||
{% for log in recent_requests %}
|
||||
<li class="mb-2 pb-2 border-bottom small d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<span class="text-muted me-1">{{ log.time }}</span>
|
||||
<code class="text-muted me-1">{{ log.ip }}</code>
|
||||
<span class="fw-bold">{{ log.page }}</span>
|
||||
</div>
|
||||
{% if log.visitor_info is not empty %}
|
||||
<span class="badge bg-{{ log.visitor_info.badge }}" title="{{ log.ua }}">
|
||||
<i class="bi {{ log.visitor_info.icon }}"></i> {{ log.visitor_info.label }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
<div class="card-body">
|
||||
<table class="table table-sm mb-0">
|
||||
{% for pluginName, pluginInfo in plugin_overview %}
|
||||
<tr>
|
||||
<td>
|
||||
<i class="bi bi-plug-fill"></i> {{ pluginName }}
|
||||
</td>
|
||||
<td>
|
||||
{% if pluginInfo.enabled %}
|
||||
<span class="badge bg-success">{{ ta.active|default('Actief') }}</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ ta.inactive|default('Inactief') }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="2" class="text-muted text-center">{{ ta.no_plugins|default('Geen plugins gevonden.') }}</td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Quick actions - role-specific #}
|
||||
<div class="col-md-6">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header"><i class="bi bi-lightning"></i> Snelle acties</div>
|
||||
<div class="card-body">
|
||||
<div class="d-grid gap-2">
|
||||
{% if has_permission('content') %}
|
||||
<a href="/admin/content-new" class="btn btn-outline-primary"><i class="bi bi-plus-lg"></i> Nieuwe pagina</a>
|
||||
<a href="/admin/content" class="btn btn-outline-info"><i class="bi bi-folder2-open"></i> Content beheren</a>
|
||||
{% endif %}
|
||||
{% if has_permission('config') %}
|
||||
<a href="/admin/config" class="btn btn-outline-secondary"><i class="bi bi-sliders"></i> Configuratie bewerken</a>
|
||||
{% endif %}
|
||||
{% if has_permission('statistics') %}
|
||||
<a href="/admin/statistics" class="btn btn-outline-secondary"><i class="bi bi-bar-chart"></i> Statistieken bekijken</a>
|
||||
{% endif %}
|
||||
{% if has_permission('theme') %}
|
||||
<a href="/admin/theme" class="btn btn-outline-secondary"><i class="bi bi-palette"></i> Thema beheren</a>
|
||||
{% endif %}
|
||||
{% if has_permission('plugins') %}
|
||||
<a href="/admin/plugins" class="btn btn-outline-secondary"><i class="bi bi-plug"></i> Plugins beheren</a>
|
||||
{% endif %}
|
||||
<a href="/" target="_blank" class="btn btn-outline-success"><i class="bi bi-box-arrow-up-right"></i> Website bekijken</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -1,14 +1,14 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}{{ error_title|default('Fout') }} - CodePress Admin{% endblock %}
|
||||
{% block title %}{{ error_title|default(ta.error|default('Fout')) }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="text-center py-5">
|
||||
<h1 class="display-1 text-muted">{{ error_code|default('404') }}</h1>
|
||||
<h2 class="mb-3">{{ error_title|default('Pagina niet gevonden') }}</h2>
|
||||
<p class="text-muted mb-4">{{ error_message|default('De gevraagde pagina kon niet worden gevonden.') }}</p>
|
||||
<h2 class="mb-3">{{ error_title|default(ta.page_not_found|default('Pagina niet gevonden')) }}</h2>
|
||||
<p class="text-muted mb-4">{{ error_message|default(ta.page_not_found_msg|default('De gevraagde pagina kon niet worden gevonden.')) }}</p>
|
||||
<a href="/admin/dashboard" class="btn btn-primary">
|
||||
<i class="bi bi-house"></i> Naar dashboard
|
||||
<i class="bi bi-house"></i> {{ ta.to_dashboard|default('Naar dashboard') }}
|
||||
</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,6 +1,6 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}{{ guide_page ? 'Handleiding - ' : '' }}Handleiding{% endblock %}
|
||||
{% block title %}{{ guide_page ? (ta.guide|default('Handleiding')) ~ ' - ' : '' }}{{ ta.guide|default('Handleiding') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
@@ -8,7 +8,7 @@
|
||||
<aside class="col-md-3 mb-3">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0"><i class="bi bi-list-ul"></i> Navigatie</h5>
|
||||
<h5 class="mb-0"><i class="bi bi-list-ul"></i> {{ ta.navigation|default('Navigatie') }}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{ guide_nav|raw }}
|
||||
@@ -23,9 +23,9 @@
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item {{ not guide_page ? 'active' : '' }}">
|
||||
{% if guide_page %}
|
||||
<a href="/admin/guide{% if guide_lang %}?lang={{ guide_lang }}{% endif %}">Handleiding</a>
|
||||
<a href="/admin/guide{% if guide_lang %}?lang={{ guide_lang }}{% endif %}">{{ ta.guide|default('Handleiding') }}</a>
|
||||
{% else %}
|
||||
Handleidingen
|
||||
{{ ta.manuals|default('Handleidingen') }}
|
||||
{% endif %}
|
||||
</li>
|
||||
{% if guide_breadcrumbs %}
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}Logs - CodePress Admin{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4"><i class="bi bi-journal-text"></i> Logs</h2>
|
||||
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-body">
|
||||
<form method="GET" action="/admin/logs" class="row g-3 align-items-end">
|
||||
<div class="col-auto">
|
||||
<div class="btn-group" role="group">
|
||||
<a href="/admin/logs?tab=admin" class="btn btn-sm {{ tab == 'admin' ? 'btn-primary' : 'btn-outline-primary' }}">
|
||||
<i class="bi bi-shield-check"></i> Admin
|
||||
</a>
|
||||
<a href="/admin/logs?tab=requests" class="btn btn-sm {{ tab == 'requests' ? 'btn-primary' : 'btn-outline-primary' }}">
|
||||
<i class="bi bi-globe"></i> Requests
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<a href="/admin/logs?tab={{ tab }}&download=1" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-download"></i> Download
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body p-0" style="max-height: 600px; overflow-y: auto;">
|
||||
<table class="table table-sm table-hover mb-0">
|
||||
<thead class="sticky-top bg-white">
|
||||
<tr>
|
||||
<th>Tijd</th>
|
||||
<th>Level</th>
|
||||
<th>IP</th>
|
||||
<th>Bericht</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for log in logs %}
|
||||
<tr>
|
||||
<td class="text-muted">{{ log.time }}</td>
|
||||
<td>
|
||||
<span class="badge bg-{{ log.level == 'warning' ? 'warning text-dark' : (log.level == 'error' ? 'danger' : 'info') }}">
|
||||
{{ log.level }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-muted">{{ log.ip }}</td>
|
||||
<td><code class="text-muted">{{ log.message }}</code></td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4" class="text-muted text-center py-4">Geen logs gevonden.</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,12 +1,12 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}Media - CodePress Admin{% endblock %}
|
||||
{% block title %}{{ ta.media|default('Media') }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2><i class="bi bi-images"></i> Media</h2>
|
||||
<h2><i class="bi bi-images"></i> {{ ta.media|default('Media') }}</h2>
|
||||
<button type="button" class="btn btn-primary btn-sm" data-bs-toggle="collapse" data-bs-target="#uploadForm">
|
||||
<i class="bi bi-cloud-upload"></i> Uploaden
|
||||
<i class="bi bi-cloud-upload"></i> {{ ta.upload|default('Upload') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
<form method="POST" action="/admin/media?dir={{ subdir|url_encode }}" enctype="multipart/form-data">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<div class="mb-3">
|
||||
<label for="file" class="form-label">Bestanden selecteren</label>
|
||||
<label for="file" class="form-label">{{ ta.select_files|default('Bestanden selecteren') }}</label>
|
||||
<input type="file" class="form-control" id="file" name="file[]" multiple accept="image/*,video/*,audio/*">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success">
|
||||
<i class="bi bi-cloud-upload"></i> Uploaden
|
||||
<i class="bi bi-cloud-upload"></i> {{ ta.upload|default('Uploaden') }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -43,10 +43,10 @@
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="col-12">
|
||||
<p class="text-muted text-center">Geen media bestanden gevonden.</p>
|
||||
<p class="text-muted text-center">{{ ta.no_media|default('Geen media bestanden gevonden.') }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -1,9 +1,9 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}Plugin Configuratie: {{ pluginName }} - CodePress Admin{% endblock %}
|
||||
{% block title %}{{ ta.plugin_config|default('Plugin Configuratie: ') }}{{ pluginName }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4"><i class="bi bi-plug"></i> Plugin Configuratie: {{ pluginName }}</h2>
|
||||
<h2 class="mb-4"><i class="bi bi-plug"></i> {{ ta.plugin_config|default('Plugin Configuratie: ') }}{{ pluginName }}</h2>
|
||||
|
||||
<form method="post" class="card shadow-sm">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
@@ -12,9 +12,9 @@
|
||||
</div>
|
||||
<div class="card-footer bg-white">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check-lg"></i> Opslaan
|
||||
<i class="bi bi-check-lg"></i> {{ ta.save|default('Opslaan') }}
|
||||
</button>
|
||||
<a href="/admin/plugins" class="btn btn-outline-secondary">Annuleren</a>
|
||||
<a href="/admin/plugins" class="btn btn-outline-secondary">{{ ta.cancel|default('Annuleren') }}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,7 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}{{ plugin_title|default('Plugin') }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{{ plugin_content|raw }}
|
||||
{% endblock %}
|
||||
@@ -1,6 +1,6 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}Plugin bewerken: {{ pluginName }} - CodePress Admin{% endblock %}
|
||||
{% block title %}{{ ta.plugin_edit|default('Plugin bewerken: ') }}{{ pluginName }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="/admin/assets/codemirror/codemirror.min.css">
|
||||
@@ -9,9 +9,9 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2><i class="bi bi-pencil"></i> Plugin bewerken: {{ pluginName }}</h2>
|
||||
<h2><i class="bi bi-pencil"></i> {{ ta.plugin_edit|default('Plugin bewerken: ') }}{{ pluginName }}</h2>
|
||||
<a href="/admin/plugins" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="bi bi-arrow-left"></i> Terug
|
||||
<i class="bi bi-arrow-left"></i> {{ ta.back|default('Terug') }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
</div>
|
||||
<div class="d-flex gap-2 mt-3">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check-lg"></i> Opslaan
|
||||
<i class="bi bi-check-lg"></i> {{ ta.save|default('Opslaan') }}
|
||||
</button>
|
||||
<a href="/admin/plugins" class="btn btn-outline-secondary">Annuleren</a>
|
||||
<a href="/admin/plugins" class="btn btn-outline-secondary">{{ ta.cancel|default('Annuleren') }}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -1,24 +1,24 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}Nieuwe plugin - CodePress Admin{% endblock %}
|
||||
{% block title %}{{ ta.new_plugin|default('Nieuwe plugin') }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4"><i class="bi bi-plug"></i> Nieuwe plugin aanmaken</h2>
|
||||
<h2 class="mb-4"><i class="bi bi-plug"></i> {{ ta.new_plugin_title|default('Nieuwe plugin aanmaken') }}</h2>
|
||||
|
||||
<form method="post" class="card shadow-sm">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Plugin naam</label>
|
||||
<label for="name" class="form-label">{{ ta.plugin_name|default('Plugin naam') }}</label>
|
||||
<input type="text" class="form-control" id="name" name="name" required autofocus>
|
||||
<small class="form-text text-muted">Alleen letters, cijfers, underscores en streepjes.</small>
|
||||
<small class="form-text text-muted">{{ ta.plugin_name_help|default('Alleen letters, cijfers, underscores en streepjes.') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-white">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check-lg"></i> Aanmaken
|
||||
<i class="bi bi-check-lg"></i> {{ ta.create|default('Aanmaken') }}
|
||||
</button>
|
||||
<a href="/admin/plugins" class="btn btn-outline-secondary">Annuleren</a>
|
||||
<a href="/admin/plugins" class="btn btn-outline-secondary">{{ ta.cancel|default('Annuleren') }}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -1,25 +1,37 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}Plugins - CodePress Admin{% endblock %}
|
||||
{% block title %}{{ ta.plugins|default('Plugins') }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2><i class="bi bi-plug"></i> Plugins</h2>
|
||||
<h2><i class="bi bi-plug"></i> {{ ta.plugins|default('Plugins') }}</h2>
|
||||
<a href="/admin/plugins-new" class="btn btn-primary btn-sm">
|
||||
<i class="bi bi-plus-lg"></i> Nieuwe plugin
|
||||
<i class="bi bi-plus-lg"></i> {{ ta.new_plugin|default('Nieuwe plugin') }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="row g-4">
|
||||
{% for plugin in plugins %}
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card shadow-sm h-100 {% if plugin.type == 'system' %}border-primary{% elseif plugin.type == 'content' %}border-success{% endif %}">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span class="fw-bold">{{ plugin.name|default(plugin.name) }}</span>
|
||||
<span class="badge bg-{{ plugin.enabled ? 'success' : 'secondary' }}">{{ plugin.enabled ? 'Actief' : 'Inactief' }}</span>
|
||||
<span class="fw-bold">
|
||||
{% if plugin.type == 'system' %}<i class="bi bi-gear-fill text-primary"></i>
|
||||
{% elseif plugin.type == 'content' %}<i class="bi bi-puzzle-fill text-success"></i>
|
||||
{% else %}<i class="bi bi-plug-fill"></i>{% endif %}
|
||||
{{ plugin.name|default(plugin.name) }}
|
||||
</span>
|
||||
<div class="d-flex gap-1">
|
||||
{% if plugin.type == 'system' %}
|
||||
<span class="badge bg-primary">{{ ta.plugin_type_system|default('Systeem') }}</span>
|
||||
{% elseif plugin.type == 'content' %}
|
||||
<span class="badge bg-success">{{ ta.plugin_type_content|default('Content') }}</span>
|
||||
{% endif %}
|
||||
<span class="badge bg-{{ plugin.enabled ? 'success' : 'secondary' }}">{{ plugin.enabled ? ta.active|default('Actief') : ta.inactive|default('Inactief') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="card-text text-muted mb-2">{{ plugin.description|default('Geen beschrijving') }}</p>
|
||||
<p class="card-text text-muted mb-2">{{ plugin.description|default(ta.no_description|default('Geen beschrijving')) }}</p>
|
||||
<p class="small text-muted mb-3">
|
||||
{% if plugin.version %}<span class="badge bg-info">v{{ plugin.version }}</span>{% endif %}
|
||||
{% if plugin.author %}<span class="badge bg-secondary">{{ plugin.author }}</span>{% endif %}
|
||||
@@ -27,27 +39,27 @@
|
||||
</div>
|
||||
<div class="card-footer bg-white">
|
||||
<div class="btn-group w-100" role="group">
|
||||
{% if plugin.protected %}
|
||||
<span class="btn btn-sm btn-outline-secondary disabled" title="Essentiële plugin - kan niet worden bewerkt, gedeactiveerd of verwijderd">
|
||||
<i class="bi bi-shield-check"></i> Essentieel
|
||||
{% if plugin.protected or plugin.essential %}
|
||||
<span class="btn btn-sm btn-outline-secondary disabled" title="{{ ta.essential_title|default('Essentiële plugin - kan niet worden bewerkt, gedeactiveerd of verwijderd') }}">
|
||||
<i class="bi bi-shield-check"></i> {{ ta.essential|default('Essentieel') }}
|
||||
</span>
|
||||
{% else %}
|
||||
<a href="/admin/plugins-edit?plugin={{ plugin.name|url_encode }}" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-pencil"></i> Bewerken
|
||||
<i class="bi bi-pencil"></i> {{ ta.edit|default('Bewerken') }}
|
||||
</a>
|
||||
{% if plugin.hasConfig %}
|
||||
<a href="/admin/plugins-config?plugin={{ plugin.name|url_encode }}" class="btn btn-sm btn-outline-info">
|
||||
<i class="bi bi-gear"></i> Config
|
||||
<i class="bi bi-gear"></i> {{ ta.config|default('Config') }}
|
||||
</a>
|
||||
{% endif %}
|
||||
<form method="POST" action="/admin/plugins-toggle" class="d-inline">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<input type="hidden" name="plugin" value="{{ plugin.name }}">
|
||||
<button type="submit" class="btn btn-sm btn-{{ plugin.enabled ? 'outline-warning' : 'outline-success' }}">
|
||||
<i class="bi bi-{{ plugin.enabled ? 'pause' : 'play' }}"></i> {{ plugin.enabled ? 'Deactiveren' : 'Activeren' }}
|
||||
<i class="bi bi-{{ plugin.enabled ? 'pause' : 'play' }}"></i> {{ plugin.enabled ? ta.deactivate|default('Deactiveren') : ta.activate|default('Activeren') }}
|
||||
</button>
|
||||
</form>
|
||||
<form method="POST" action="/admin/plugins-delete" class="d-inline" onsubmit="return confirm('Weet je zeker dat je deze plugin wilt verwijderen?')">
|
||||
<form method="POST" action="/admin/plugins-delete" class="d-inline" onsubmit="return confirm('{{ ta.confirm_delete_plugin|default('Weet je zeker dat je deze plugin wilt verwijderen?') }}')">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<input type="hidden" name="plugin" value="{{ plugin.name }}">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger">
|
||||
@@ -62,9 +74,9 @@
|
||||
{% else %}
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle"></i> Geen plugins gevonden. Maak een nieuwe plugin aan om te beginnen.
|
||||
<i class="bi bi-info-circle"></i> {{ ta.no_plugins|default('Geen plugins gevonden. Maak een nieuwe plugin aan om te beginnen.') }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -1,44 +1,44 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}Beveiliging - CodePress Admin{% endblock %}
|
||||
{% block title %}{{ ta.security|default('Beveiliging') }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4"><i class="bi bi-shield-check"></i> Beveiliging & Bot Bescherming</h2>
|
||||
<h2 class="mb-4"><i class="bi bi-shield-check"></i> {{ ta.security_bots|default('Beveiliging & Bot Bescherming') }}</h2>
|
||||
|
||||
<form method="POST" action="/admin/security">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header">Bot Bescherming</div>
|
||||
<div class="card-header">{{ ta.bot_protection|default('Bot Bescherming') }}</div>
|
||||
<div class="card-body">
|
||||
<div class="form-check form-switch mb-3">
|
||||
<input class="form-check-input" type="checkbox" id="botguard_enabled" name="botguard_enabled" {{ config.security.botguard_enabled ?? true ? 'checked' : '' }}>
|
||||
<label class="form-check-label" for="botguard_enabled">BotGuard ingeschakeld</label>
|
||||
<label class="form-check-label" for="botguard_enabled">{{ ta.botguard_enabled|default('BotGuard ingeschakeld') }}</label>
|
||||
</div>
|
||||
<div class="form-check form-switch mb-3">
|
||||
<input class="form-check-input" type="checkbox" id="block_bad_bots" name="block_bad_bots" {{ config.security.block_bad_bots ?? true ? 'checked' : '' }}>
|
||||
<label class="form-check-label" for="block_bad_bots">Blokkeer slechte bots</label>
|
||||
<label class="form-check-label" for="block_bad_bots">{{ ta.block_bad_bots|default('Blokkeer slechte bots') }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header">Sessie Instellingen</div>
|
||||
<div class="card-header">{{ ta.session_settings|default('Sessie Instellingen') }}</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label for="session_timeout" class="form-label">Sessie timeout (seconden)</label>
|
||||
<label for="session_timeout" class="form-label">{{ ta.session_timeout|default('Sessie timeout (seconden)') }}</label>
|
||||
<input type="number" class="form-control" id="session_timeout" name="session_timeout" value="{{ config.security.session_timeout ?? 3600 }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="max_login_attempts" class="form-label">Maximale login pogingen</label>
|
||||
<label for="max_login_attempts" class="form-label">{{ ta.max_login_attempts|default('Maximale login pogingen') }}</label>
|
||||
<input type="number" class="form-control" id="max_login_attempts" name="max_login_attempts" value="{{ config.security.max_login_attempts ?? 5 }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check-lg"></i> Opslaan
|
||||
<i class="bi bi-check-lg"></i> {{ ta.save|default('Opslaan') }}
|
||||
</button>
|
||||
<a href="/admin/dashboard" class="btn btn-outline-secondary">Annuleren</a>
|
||||
<a href="/admin/dashboard" class="btn btn-outline-secondary">{{ ta.cancel|default('Annuleren') }}</a>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -1,80 +0,0 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}Statistieken - CodePress Admin{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4"><i class="bi bi-bar-chart"></i> Statistieken</h2>
|
||||
|
||||
<div class="row g-4 mb-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card stat-card shadow-sm">
|
||||
<div class="card-body d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1">Totaal aantal views</h6>
|
||||
<h3 class="mb-0">{{ (stats.totals.views ?? 0)|number_format(0, ',', '.') }}</h3>
|
||||
</div>
|
||||
<i class="bi bi-eye stat-icon text-primary"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card stat-card shadow-sm">
|
||||
<div class="card-body d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1">Unieke bezoekers</h6>
|
||||
<h3 class="mb-0">{{ (stats.totals.uniques ?? 0)|number_format(0, ',', '.') }}</h3>
|
||||
</div>
|
||||
<i class="bi bi-people stat-icon text-success"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card stat-card shadow-sm">
|
||||
<div class="card-body d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1">Pagina views</h6>
|
||||
<h3 class="mb-0">{{ (stats.pages|length ?? 0) }}</h3>
|
||||
</div>
|
||||
<i class="bi bi-file-earmark-text stat-icon text-info"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header"><i class="bi bi-globe"></i> Landen</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm mb-0">
|
||||
{% for country, count in stats.countries|slice(0, 10) %}
|
||||
<tr>
|
||||
<td>{{ get_country_flag(country) }} {{ get_country_name(country) }}</td>
|
||||
<td class="text-end">{{ count|number_format(0, ',', '.') }}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="2" class="text-muted">Geen data</td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header"><i class="bi bi-file-text"></i> Top pagina's</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm mb-0">
|
||||
{% for page, count in stats.pages|slice(0, 10) %}
|
||||
<tr>
|
||||
<td><code class="text-muted">{{ page }}</code></td>
|
||||
<td class="text-end">{{ count|number_format(0, ',', '.') }}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="2" class="text-muted">Geen data</td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,24 +1,24 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}Nieuw thema - CodePress Admin{% endblock %}
|
||||
{% block title %}{{ ta.new_theme|default('Nieuw thema') }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4"><i class="bi bi-palette"></i> Nieuw thema aanmaken</h2>
|
||||
<h2 class="mb-4"><i class="bi bi-palette"></i> {{ ta.new_theme_title|default('Nieuw thema aanmaken') }}</h2>
|
||||
|
||||
<form method="post" class="card shadow-sm">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Thema naam</label>
|
||||
<label for="name" class="form-label">{{ ta.theme_name|default('Thema naam') }}</label>
|
||||
<input type="text" class="form-control" id="name" name="name" required autofocus>
|
||||
<small class="form-text text-muted">Alleen letters, cijfers, underscores en streepjes.</small>
|
||||
<small class="form-text text-muted">{{ ta.theme_name_help|default('Alleen letters, cijfers, underscores en streepjes.') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-white">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check-lg"></i> Aanmaken
|
||||
<i class="bi bi-check-lg"></i> {{ ta.create|default('Aanmaken') }}
|
||||
</button>
|
||||
<a href="/admin/theme" class="btn btn-outline-secondary">Annuleren</a>
|
||||
<a href="/admin/theme" class="btn btn-outline-secondary">{{ ta.cancel|default('Annuleren') }}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -1,19 +1,19 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}Thema's - CodePress Admin{% endblock %}
|
||||
{% block title %}{{ ta.themes|default('Thema\'s') }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2><i class="bi bi-palette"></i> Thema's</h2>
|
||||
<h2><i class="bi bi-palette"></i> {{ ta.themes|default('Thema\'s') }}</h2>
|
||||
<div>
|
||||
<form method="POST" action="/admin/theme" class="d-inline">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<button type="submit" name="activate_default" class="btn btn-primary btn-sm">
|
||||
<i class="bi bi-check-lg"></i> Activeer Default
|
||||
<i class="bi bi-check-lg"></i> {{ ta.activate_default|default('Activeer Default') }}
|
||||
</button>
|
||||
</form>
|
||||
<a href="/admin/theme-new" class="btn btn-outline-primary btn-sm ms-2">
|
||||
<i class="bi bi-plus-lg"></i> Nieuw thema
|
||||
<i class="bi bi-plus-lg"></i> {{ ta.new_theme|default('Nieuw thema') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -25,13 +25,13 @@
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span class="fw-bold">{{ theme.title|default(theme.name) }}</span>
|
||||
{% if theme.active %}
|
||||
<span class="badge bg-success">Actief</span>
|
||||
<span class="badge bg-success">{{ ta.active|default('Actief') }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted small">Naam: {{ theme.name }}</p>
|
||||
<p class="text-muted small">{{ ta.name_label|default('Naam: ') }}{{ theme.name }}</p>
|
||||
{% if theme.default_layout %}
|
||||
<p class="text-muted small">Default layout: {{ theme.default_layout }}</p>
|
||||
<p class="text-muted small">{{ ta.default_layout_label|default('Default layout: ') }}{{ theme.default_layout }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-footer bg-white">
|
||||
@@ -40,7 +40,7 @@
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<input type="hidden" name="activate" value="{{ theme.name }}">
|
||||
<button type="submit" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-check-lg"></i> Activeren
|
||||
<i class="bi bi-check-lg"></i> {{ ta.activate|default('Activeren') }}
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
@@ -49,7 +49,7 @@
|
||||
<input type="hidden" name="compile_scss" value="1">
|
||||
<input type="hidden" name="theme" value="{{ theme.name }}">
|
||||
<button type="submit" class="btn btn-sm btn-outline-success">
|
||||
<i class="bi bi-palette"></i> SCSS compileren
|
||||
<i class="bi bi-palette"></i> {{ ta.compile_scss|default('SCSS compileren') }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -58,9 +58,9 @@
|
||||
{% else %}
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle"></i> Geen thema's gevonden.
|
||||
<i class="bi bi-info-circle"></i> {{ ta.no_themes|default('Geen thema\'s gevonden.') }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -1,35 +1,35 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}Update - CodePress Admin{% endblock %}
|
||||
{% block title %}{{ ta.update|default('Update') }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4"><i class="bi bi-cloud-arrow-down"></i> Systeem Update</h2>
|
||||
<h2 class="mb-4"><i class="bi bi-cloud-arrow-down"></i> {{ ta.system_update|default('Systeem Update') }}</h2>
|
||||
|
||||
{% if isGitWritable == false %}
|
||||
<div class="alert alert-warning mb-4">
|
||||
<i class="bi bi-exclamation-triangle-fill me-1"></i>
|
||||
De .git map is niet beschrijfbaar. Automatische updates zijn niet mogelijk.
|
||||
{{ ta.git_not_writable|default('De .git map is niet beschrijfbaar. Automatische updates zijn niet mogelijk.') }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header">Huidige versie</div>
|
||||
<div class="card-header">{{ ta.current_version|default('Huidige versie') }}</div>
|
||||
<div class="card-body">
|
||||
<p class="mb-0">CodePress versie: <strong>{{ version }}</strong></p>
|
||||
<p class="mb-0">{{ ta.cms_version_label|default('CodePress versie: ') }}<strong>{{ version }}</strong></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header">Update opties</div>
|
||||
<div class="card-header">{{ ta.update_options|default('Update opties') }}</div>
|
||||
<div class="card-body">
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-primary" {{ isGitWritable ? '' : 'disabled' }}>
|
||||
<i class="bi bi-cloud-arrow-down"></i> Controleer op updates
|
||||
<i class="bi bi-cloud-arrow-down"></i> {{ ta.check_updates|default('Controleer op updates') }}
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary" {{ isGitWritable ? '' : 'disabled' }}>
|
||||
<i class="bi bi-arrow-repeat"></i> Update uitvoeren
|
||||
<i class="bi bi-arrow-repeat"></i> {{ ta.run_update|default('Update uitvoeren') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -1,24 +1,24 @@
|
||||
{% extends "layouts/admin.twig" %}
|
||||
|
||||
{% block title %}Gebruikers - CodePress Admin{% endblock %}
|
||||
{% block title %}{{ ta.users|default('Gebruikers') }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4"><i class="bi bi-people"></i> Gebruikers</h2>
|
||||
<h2 class="mb-4"><i class="bi bi-people"></i> {{ ta.users|default('Gebruikers') }}</h2>
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-md-7">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header">
|
||||
<i class="bi bi-list"></i> Gebruikers
|
||||
<i class="bi bi-list"></i> {{ ta.users|default('Gebruikers') }}
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Gebruikersnaam</th>
|
||||
<th>Rol</th>
|
||||
<th>Aangemaakt</th>
|
||||
<th>Acties</th>
|
||||
<th>{{ ta.username|default('Gebruikersnaam') }}</th>
|
||||
<th>{{ ta.col_role|default('Rol') }}</th>
|
||||
<th>{{ ta.col_created|default('Aangemaakt') }}</th>
|
||||
<th>{{ ta.col_actions|default('Acties') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -28,7 +28,7 @@
|
||||
<i class="bi bi-person-circle"></i>
|
||||
{{ username }}
|
||||
{% if username == user.username %}
|
||||
<span class="badge bg-info">Jij</span>
|
||||
<span class="badge bg-info">{{ ta.you|default('Jij') }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
@@ -36,13 +36,13 @@
|
||||
{{ data.role_label|default(data.role) }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-muted">{{ data.created|default('Onbekend') }}</td>
|
||||
<td class="text-muted">{{ data.created|default(ta.unknown|default('Onbekend')) }}</td>
|
||||
<td>
|
||||
{% if username != user.username %}
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#roleModal-{{ username }}">
|
||||
<i class="bi bi-person-gear"></i> Rol
|
||||
<i class="bi bi-person-gear"></i> {{ ta.col_role|default('Rol') }}
|
||||
</button>
|
||||
<form method="POST" action="/admin/users" class="d-inline" onsubmit="return confirm('Weet je zeker dat je gebruiker {{ username }} wilt verwijderen?')">
|
||||
<form method="POST" action="/admin/users" class="d-inline" onsubmit="return confirm('{{ ta.confirm_delete_user|default('Weet je zeker dat je deze gebruiker wilt verwijderen?') }}')">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<input type="hidden" name="action" value="delete">
|
||||
<input type="hidden" name="delete_username" value="{{ username }}">
|
||||
@@ -60,16 +60,16 @@
|
||||
<input type="hidden" name="action" value="change_role">
|
||||
<input type="hidden" name="role_username" value="{{ username }}">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><i class="bi bi-person-gear"></i> Rol wijzigen: {{ username }}</h5>
|
||||
<h5 class="modal-title"><i class="bi bi-person-gear"></i> {{ ta.change_role|default('Rol wijzigen: ') }}{{ username }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Huidige rol</label>
|
||||
<label class="form-label">{{ ta.current_role|default('Huidige rol') }}</label>
|
||||
<p><span class="badge bg-secondary">{{ data.role_label|default(data.role) }}</span></p>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="new_role-{{ username }}" class="form-label">Nieuwe rol</label>
|
||||
<label for="new_role-{{ username }}" class="form-label">{{ ta.new_role|default('Nieuwe rol') }}</label>
|
||||
<select class="form-select" id="new_role-{{ username }}" name="new_role">
|
||||
{% for roleKey, roleLabel in roles %}
|
||||
<option value="{{ roleKey }}" {{ data.role == roleKey ? 'selected' : '' }}>{{ roleLabel }}</option>
|
||||
@@ -78,21 +78,23 @@
|
||||
</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> Wijzigen</button>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ ta.cancel|default('Annuleren') }}</button>
|
||||
<button type="submit" class="btn btn-primary"><i class="bi bi-check-lg"></i> {{ ta.change|default('Wijzigen') }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<span class="text-muted small">Eigen account</span>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#profileModal">
|
||||
<i class="bi bi-pencil"></i> {{ ta.edit_profile|default('Profiel bewerken') }}
|
||||
</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4" class="text-muted text-center py-4">Geen gebruikers gevonden.</td>
|
||||
<td colspan="4" class="text-muted text-center py-4">{{ ta.no_users|default('Geen gebruikers gevonden.') }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
@@ -102,25 +104,72 @@
|
||||
</div>
|
||||
|
||||
<div class="col-md-5">
|
||||
<!-- Profile edit card for current user -->
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header">
|
||||
<i class="bi bi-person-circle"></i> {{ ta.my_profile|default('Mijn profiel') }}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="/admin/users">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<input type="hidden" name="action" value="profile">
|
||||
<input type="hidden" name="profile_username" value="{{ user.username }}">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">{{ ta.username|default('Gebruikersnaam') }}</label>
|
||||
<input type="text" class="form-control" value="{{ user.username }}" disabled>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="profile_email" class="form-label">{{ ta.login_email|default('Login e-mail') }}</label>
|
||||
<input type="email" class="form-control" id="profile_email" name="profile_email" value="{{ user.email|default('') }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="profile_author_name" class="form-label">{{ ta.author_name|default('Auteur naam') }}</label>
|
||||
<input type="text" class="form-control" id="profile_author_name" name="profile_author_name" value="{{ user.author_name|default('') }}">
|
||||
<small class="form-text text-muted">{{ ta.author_name_help|default('Getoond als auteur op de website.') }}</small>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="profile_author_email" class="form-label">{{ ta.author_email|default('Auteur e-mail') }}</label>
|
||||
<input type="email" class="form-control" id="profile_author_email" name="profile_author_email" value="{{ user.author_email|default('') }}">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100">
|
||||
<i class="bi bi-check-lg"></i> {{ ta.save|default('Opslaan') }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- New user card -->
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header">
|
||||
<i class="bi bi-plus-circle"></i> Nieuwe gebruiker
|
||||
<i class="bi bi-plus-circle"></i> {{ ta.new_user|default('Nieuwe gebruiker') }}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="/admin/users">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<input type="hidden" name="action" value="add">
|
||||
<div class="mb-3">
|
||||
<label for="new_username" class="form-label">Gebruikersnaam</label>
|
||||
<label for="new_username" class="form-label">{{ ta.username|default('Gebruikersnaam') }}</label>
|
||||
<input type="text" class="form-control" id="new_username" name="new_username" required autofocus>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="new_password" class="form-label">Wachtwoord</label>
|
||||
<label for="new_password" class="form-label">{{ ta.password|default('Wachtwoord') }}</label>
|
||||
<input type="password" class="form-control" id="new_password" name="new_password" required>
|
||||
<small class="form-text text-muted">Minimaal 8 tekens.</small>
|
||||
<small class="form-text text-muted">{{ ta.password_help|default('Minimaal 8 tekens.') }}</small>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="new_role" class="form-label">Rol</label>
|
||||
<label for="new_email" class="form-label">{{ ta.login_email|default('Login e-mail') }}</label>
|
||||
<input type="email" class="form-control" id="new_email" name="new_email">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="new_author_name" class="form-label">{{ ta.author_name|default('Auteur naam') }}</label>
|
||||
<input type="text" class="form-control" id="new_author_name" name="new_author_name">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="new_author_email" class="form-label">{{ ta.author_email|default('Auteur e-mail') }}</label>
|
||||
<input type="email" class="form-control" id="new_author_email" name="new_author_email">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="new_role" class="form-label">{{ ta.col_role|default('Rol') }}</label>
|
||||
<select class="form-select" id="new_role" name="new_role">
|
||||
{% for roleKey, roleLabel in roles %}
|
||||
<option value="{{ roleKey }}" {{ roleKey == 'content-manager' ? 'selected' : '' }}>{{ roleLabel }}</option>
|
||||
@@ -128,7 +177,7 @@
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100">
|
||||
<i class="bi bi-check-lg"></i> Gebruiker toevoegen
|
||||
<i class="bi bi-check-lg"></i> {{ ta.add_user|default('Gebruiker toevoegen') }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user