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
180 lines
9.4 KiB
Twig
180 lines
9.4 KiB
Twig
<!DOCTYPE html>
|
|
<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 %}{{ 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">
|
|
<link rel="stylesheet" href="/plugins/Navigation/assets/css/navigation.css">
|
|
<style>
|
|
body { background-color: #f5f6fa; min-height: 100vh; }
|
|
.admin-sidebar { background-color: {{ sidebar_color|default('#0a369d') }}; min-height: 100vh; width: 240px; position: fixed; top: 0; left: 0; z-index: 100; display: flex; flex-direction: column; }
|
|
.admin-sidebar .nav.flex-column:first-of-type { flex: 1; overflow-y: auto; }
|
|
.admin-sidebar .nav-link { color: rgba(255,255,255,0.8); padding: 0.75rem 1.25rem; border-radius: 0; }
|
|
.admin-sidebar .nav-link:hover { color: #fff; background-color: rgba(255,255,255,0.1); }
|
|
.admin-sidebar .nav-link.active { color: #fff; background-color: rgba(255,255,255,0.2); border-left: 3px solid #fff; }
|
|
.admin-sidebar .nav-link i { width: 24px; text-align: center; margin-right: 0.5rem; }
|
|
.admin-sidebar .nav-section { color: rgba(255,255,255,0.4); font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.08em; padding: 1rem 1.25rem 0.3rem 1.25rem; }
|
|
.admin-main { margin-left: 240px; padding: 2rem; }
|
|
.admin-brand { color: #fff; padding: 1.25rem; font-size: 1.1rem; border-bottom: 1px solid rgba(255,255,255,0.15); }
|
|
.admin-brand i { margin-right: 0.5rem; }
|
|
.stat-card { border: none; border-radius: 0.5rem; }
|
|
.stat-card .stat-icon { font-size: 2rem; opacity: 0.7; }
|
|
.admin-user { color: rgba(255,255,255,0.6); padding: 0.75rem 1.25rem; font-size: 0.85rem; border-top: 1px solid rgba(255,255,255,0.15); }
|
|
@media (max-width: 768px) {
|
|
.admin-sidebar { width: 100%; min-height: auto; position: relative; }
|
|
.admin-main { margin-left: 0; }
|
|
}
|
|
</style>
|
|
{% if needs_editor %}
|
|
<link rel="stylesheet" href="/admin/assets/codemirror/codemirror.min.css">
|
|
<link rel="stylesheet" href="/admin/assets/css/editor.css">
|
|
{% endif %}
|
|
{% block extra_css %}{% endblock %}
|
|
</head>
|
|
<body>
|
|
<nav class="admin-sidebar d-flex flex-column">
|
|
<div class="admin-brand">
|
|
<i class="bi bi-gear-fill"></i> {{ ta.admin_title|default('CodePress Admin') }}
|
|
</div>
|
|
<ul class="nav flex-column mt-2">
|
|
{# 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 == 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">{{ 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> {{ ta.content|default('Content') }}
|
|
</a>
|
|
</li>
|
|
{% endif %}
|
|
|
|
{% if has_permission('config') or has_permission('theme') or has_permission('security') %}
|
|
<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> {{ 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> {{ 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> {{ ta.security|default('Beveiliging') }}
|
|
</a>
|
|
</li>
|
|
{% endif %}
|
|
{% endif %}
|
|
|
|
{# 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> {{ 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> {{ 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> {{ 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">{{ 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> {{ ta.guide|default('Handleiding') }}
|
|
</a>
|
|
</li>
|
|
{% endif %}
|
|
</ul>
|
|
|
|
<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> {{ 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> {{ ta.logout|default('Uitloggen') }}
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
<div class="admin-user">
|
|
<i class="bi bi-person-circle"></i> {{ user.username|default('') }}
|
|
<br><small>{{ role_label(user_role)|default('') }}</small>
|
|
</div>
|
|
</nav>
|
|
|
|
<main class="admin-main">
|
|
{% if message is defined and message %}
|
|
<div class="alert alert-{{ message_type|default('info') }} alert-dismissible fade show" role="alert">
|
|
{{ message }}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% block content %}{% endblock %}
|
|
</main>
|
|
|
|
<script src="/admin/assets/js/bootstrap.bundle.min.js"></script>
|
|
{% if needs_editor %}
|
|
<script src="/admin/assets/codemirror/codemirror.min.js"></script>
|
|
<script src="/admin/assets/codemirror/mode/markdown.min.js"></script>
|
|
<script src="/admin/assets/codemirror/mode/xml.min.js"></script>
|
|
<script src="/admin/assets/codemirror/mode/css.min.js"></script>
|
|
<script src="/admin/assets/codemirror/mode/javascript.min.js"></script>
|
|
<script src="/admin/assets/codemirror/mode/htmlmixed.min.js"></script>
|
|
<script src="/admin/assets/codemirror/mode/php.min.js"></script>
|
|
<script src="/admin/assets/codemirror/mode/clike.min.js"></script>
|
|
<script src="/admin/assets/codemirror/addon/edit/closebrackets.min.js"></script>
|
|
<script src="/admin/assets/codemirror/addon/selection/active-line.min.js"></script>
|
|
<script src="/admin/assets/js/editor-toolbar.js"></script>
|
|
{% endif %}
|
|
{% block extra_js %}{% endblock %}
|
|
</body>
|
|
</html>
|