v2.5.1: Admin theme refactor, Navigation plugin, user roles, guide restructure

- Reorganize admin into admin/theme/default/ (views + assets)
- Rename GuideNav to Navigation plugin (essential, protected)
- Plugin assets support (SCSS/CSS) loaded after theme CSS
- User roles: Admin, Content Manager, BI Manager, Site Admin
- Role-based access control (RBAC) for admin routes and sidebar
- Guide restructure: sub-topics in separate folders with sidebar nav
- Dynamic breadcrumb for homepage and subdirectories
- Fix theme path traversal (../../ -> ../) in admin.php
- Fix CodeMirror mode load order (xml -> css -> js -> htmlmixed -> php)
- Fix editor-toolbar.js null checks for plugin edit pages
- Layout select from theme.json with live frontmatter update
- Footer sticky at bottom of viewport (min-height: 100vh)
- Breadcrumb color fix (var(--nav-font) -> var(--header-bg))
- Remove language switcher from guide pages
- Update README.md and README.en.md
- Bump version to 2.5.1
This commit is contained in:
2026-08-10 15:36:29 +02:00
parent 7fc3847bbb
commit 3a55ea4db6
210 changed files with 11033 additions and 9140 deletions
@@ -0,0 +1,182 @@
<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}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> CodePress Admin
</div>
<ul class="nav flex-column mt-2">
<li class="nav-section">Algemeen</li>
<li class="nav-item">
<a class="nav-link {{ route == 'dashboard' or route == '' ? 'active' : '' }}" href="/admin/dashboard">
<i class="bi bi-speedometer2"></i> Dashboard
</a>
</li>
{% if has_permission('content') %}
<li class="nav-section">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
</a>
</li>
{% endif %}
{% if has_permission('config') or has_permission('theme') or has_permission('security') %}
<li class="nav-section">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
</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
</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
</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>
{% 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
</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
</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
</a>
</li>
{% endif %}
{% endif %}
{% if has_permission('guide') %}
<li class="nav-section">Help</li>
<li class="nav-item">
<a class="nav-link {{ route == 'guide' ? 'active' : '' }}" href="/admin/guide">
<i class="bi bi-book"></i> 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> 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
</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>