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
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+54
View File
@@ -0,0 +1,54 @@
/* Mobile search improvements */
@media (max-width: 991.98px) {
.navbar {
position: relative;
}
/* Hide desktop elements on mobile */
.d-none.d-lg-flex {
display: none !important;
}
#mobileSearch {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: var(--header-bg);
z-index: 1030;
}
#mobileSearch.show {
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
/* Ensure navigation doesn't overlap with expanded search */
.navigation-section {
margin-top: 0;
border: none !important;
}
}
/* Desktop improvements */
@media (min-width: 992px) {
/* Hide mobile elements on desktop */
.d-lg-none {
display: none !important;
}
/* Hide mobile search on desktop */
#mobileSearch {
display: none !important;
}
}
/* Search form improvements */
.form-control[type="search"] {
min-width: 200px;
}
@media (max-width: 576px) {
.form-control[type="search"] {
min-width: 150px;
}
}
+11
View File
@@ -0,0 +1,11 @@
/* Search input fix - ensure clickable */
.search-input {
position: relative !important;
z-index: 10 !important;
pointer-events: auto !important;
}
/*!
* Bootstrap v5.3.8 (https://getbootstrap.com/)
* Copyright 2011-2025 The Bootstrap Authors
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+323
View File
@@ -0,0 +1,323 @@
#site-header .search-input {
background-color: #ffffff !important;
color: #212529 !important;
border: 2px solid #0a369d !important;
}
#site-header .search-input::placeholder {
color: #6c757d !important;
}
#site-header .search-input:focus {
background-color: #ffffff !important;
color: #212529 !important;
border-color: #2754b4 !important;
box-shadow: 0 0 0 0.2rem rgba(10, 54, 157, 0.25) !important;
}
:root {
--header-bg: #0a369d;
--header-font: #ffffff;
--header-height: 56px;
--nav-bg: #2754b4;
--nav-font: #ffffff;
--nav-height: 42px;
--sidebar-bg: #f8f9fa;
--sidebar-border: #dee2e6;
}
#site-header {
background-image: none;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
position: relative;
}
.navbar {
background-color: var(--header-bg) !important;
min-height: var(--header-height);
}
.navbar .navbar-brand,
.navbar .navbar-text,
.navbar .btn {
color: var(--header-font) !important;
}
.navbar .form-control {
color: var(--header-font) !important;
}
.navbar .form-control::placeholder {
color: rgba(255, 255, 255, 0.7) !important;
}
.navbar .search-input {
background-color: #ffffff !important;
color: #212529 !important;
border: 2px solid #0a369d !important;
}
.navbar .search-input::placeholder {
color: #6c757d !important;
opacity: 1 !important;
}
.navbar .search-input:focus {
background-color: #ffffff !important;
color: #212529 !important;
border-color: #2754b4 !important;
box-shadow: 0 0 0 0.2rem rgba(10, 54, 157, 0.25) !important;
}
.navbar .btn-outline-light {
border-color: var(--header-font) !important;
}
.dropdown-menu {
background-color: var(--header-bg) !important;
border: 1px solid var(--header-font) !important;
}
.dropdown-item {
color: var(--header-font) !important;
}
.dropdown-item:hover {
background-color: rgba(255, 255, 255, 0.1) !important;
color: var(--header-font) !important;
}
.dropdown-toggle::after {
display: none !important;
}
.btn-outline-light {
color: var(--header-font) !important;
border-color: var(--header-font) !important;
}
.btn-outline-light:hover {
background-color: rgba(255, 255, 255, 0.1) !important;
color: var(--header-font) !important;
}
.btn-outline-light:focus, .btn-outline-light:active, .show > .btn-outline-light.dropdown-toggle {
background-color: rgba(255, 255, 255, 0.1) !important;
color: var(--header-font) !important;
border-color: var(--header-font) !important;
box-shadow: none !important;
}
.bi-chevron-down {
font-size: 0.75em;
margin-left: 0.25rem;
}
.breadcrumb-item + .breadcrumb-item::before {
content: "" !important;
padding: 0 !important;
}
.breadcrumb {
--bs-breadcrumb-divider: "";
--bs-breadcrumb-margin-bottom: 0;
margin-bottom: 0;
}
.breadcrumb .breadcrumb-item {
color: var(--header-bg) !important;
}
.breadcrumb .breadcrumb-item a {
color: var(--header-bg) !important;
text-decoration: none;
}
.breadcrumb .breadcrumb-item a:hover {
text-decoration: underline;
}
.sidebar-toggle-item {
display: flex;
align-items: center;
margin-right: 0.5rem;
}
.sidebar-toggle-btn {
padding: 0;
line-height: 1;
font-size: 1.1rem;
color: var(--header-bg) !important;
border: none !important;
background: transparent !important;
box-shadow: none !important;
cursor: pointer;
}
.sidebar-toggle-btn:hover {
opacity: 0.7;
}
.sidebar-column {
transition: all 0.3s ease;
}
.sidebar-hidden {
display: none !important;
}
.navigation-section {
background-color: var(--nav-bg) !important;
color: var(--nav-font) !important;
min-height: var(--nav-height);
}
.focus-visible:focus,
.btn:focus,
.form-control:focus,
.nav-link:focus {
outline: 3px solid #0056b3 !important;
outline-offset: 2px !important;
box-shadow: 0 0 0 1px #ffffff, 0 0 0 4px #0056b3 !important;
}
@media (prefers-contrast: high) {
:root {
--text-color: #000000;
--bg-color: #ffffff;
--border-color: #000000;
--focus-color: #000000;
}
.btn-primary {
background-color: #000000 !important;
border-color: #000000 !important;
color: #ffffff !important;
}
.btn-outline-light {
color: #000000 !important;
border-color: #000000 !important;
}
.text-muted {
color: #000000 !important;
}
.navbar {
background-color: #ffffff !important;
border-bottom: 1px solid #000000 !important;
}
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
.nav-tabs {
background-color: transparent !important;
border: none !important;
}
.nav-tabs .nav-link {
background-color: transparent !important;
border: none !important;
color: var(--nav-font) !important;
}
.nav-tabs .nav-link:hover {
background-color: rgba(255, 255, 255, 0.1) !important;
}
.nav-tabs .nav-link.active {
background-color: rgba(255, 255, 255, 0.2) !important;
border-bottom: 2px solid var(--nav-font) !important;
}
.sidebar-column {
background-color: var(--sidebar-bg) !important;
border-right: 1px solid var(--sidebar-border) !important;
position: sticky;
top: 0;
min-height: calc(100vh - var(--header-height) - var(--nav-height) - 42px);
}
.sidebar {
padding: 1.5rem;
height: 100%;
overflow-y: auto;
}
.content-column {
background-color: #ffffff;
}
.content-wrapper {
padding: 2rem;
padding-bottom: 80px !important;
}
.main-content {
flex: 1;
min-height: auto;
}
@media (max-width: 767.98px) {
.sidebar-column {
border-right: none !important;
border-top: 1px solid var(--sidebar-border) !important;
min-height: auto;
margin-top: 1rem;
}
.content-column {
background-color: #ffffff;
}
.content-wrapper {
min-height: auto;
padding-bottom: 2rem !important;
}
}
@media (max-width: 991.98px) {
.sidebar-column {
order: 2 !important;
}
.content-column {
order: 1 !important;
}
}
pre {
background: #f8f9fa;
padding: 1rem;
border-radius: 6px;
overflow-x: auto;
border: 1px solid #dee2e6;
margin-bottom: 1rem;
}
pre code {
background: none;
padding: 0;
color: #333;
font-size: 0.85rem;
line-height: 1.5;
}
code {
background: #e8e8e8;
padding: 0.15rem 0.4rem;
border-radius: 3px;
font-size: 0.9em;
color: #d63384;
}
.footer-icon {
color: #6c757d;
text-decoration: none;
transition: all 0.2s ease-in-out;
display: inline-block;
padding: 2px;
}
.footer-icon:hover {
color: #0d6efd;
transform: translateY(-1px);
}
.footer-icon:active {
transform: translateY(0);
}
.footer-icon.guide:hover {
color: #198754;
}
.footer-icon.cms:hover {
color: #dc3545;
}
.footer-icon.git:hover {
color: #6f42c1;
}
.footer-icon.website:hover {
color: #fd7e14;
}
@@ -0,0 +1 @@
1786279979
@@ -0,0 +1,323 @@
#site-header .search-input {
background-color: #ffffff !important;
color: #212529 !important;
border: 2px solid #0a369d !important;
}
#site-header .search-input::placeholder {
color: #6c757d !important;
}
#site-header .search-input:focus {
background-color: #ffffff !important;
color: #212529 !important;
border-color: #2754b4 !important;
box-shadow: 0 0 0 0.2rem rgba(10, 54, 157, 0.25) !important;
}
:root {
--header-bg: #0a369d;
--header-font: #ffffff;
--header-height: 56px;
--nav-bg: #2754b4;
--nav-font: #ffffff;
--nav-height: 42px;
--sidebar-bg: #f8f9fa;
--sidebar-border: #dee2e6;
}
#site-header {
background-image: none;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
position: relative;
}
.navbar {
background-color: var(--header-bg) !important;
min-height: var(--header-height);
}
.navbar .navbar-brand,
.navbar .navbar-text,
.navbar .btn {
color: var(--header-font) !important;
}
.navbar .form-control {
color: var(--header-font) !important;
}
.navbar .form-control::placeholder {
color: rgba(255, 255, 255, 0.7) !important;
}
.navbar .search-input {
background-color: #ffffff !important;
color: #212529 !important;
border: 2px solid #0a369d !important;
}
.navbar .search-input::placeholder {
color: #6c757d !important;
opacity: 1 !important;
}
.navbar .search-input:focus {
background-color: #ffffff !important;
color: #212529 !important;
border-color: #2754b4 !important;
box-shadow: 0 0 0 0.2rem rgba(10, 54, 157, 0.25) !important;
}
.navbar .btn-outline-light {
border-color: var(--header-font) !important;
}
.dropdown-menu {
background-color: var(--header-bg) !important;
border: 1px solid var(--header-font) !important;
}
.dropdown-item {
color: var(--header-font) !important;
}
.dropdown-item:hover {
background-color: rgba(255, 255, 255, 0.1) !important;
color: var(--header-font) !important;
}
.dropdown-toggle::after {
display: none !important;
}
.btn-outline-light {
color: var(--header-font) !important;
border-color: var(--header-font) !important;
}
.btn-outline-light:hover {
background-color: rgba(255, 255, 255, 0.1) !important;
color: var(--header-font) !important;
}
.btn-outline-light:focus, .btn-outline-light:active, .show > .btn-outline-light.dropdown-toggle {
background-color: rgba(255, 255, 255, 0.1) !important;
color: var(--header-font) !important;
border-color: var(--header-font) !important;
box-shadow: none !important;
}
.bi-chevron-down {
font-size: 0.75em;
margin-left: 0.25rem;
}
.breadcrumb-item + .breadcrumb-item::before {
content: "" !important;
padding: 0 !important;
}
.breadcrumb {
--bs-breadcrumb-divider: "";
--bs-breadcrumb-margin-bottom: 0;
margin-bottom: 0;
}
.breadcrumb .breadcrumb-item {
color: var(--header-bg) !important;
}
.breadcrumb .breadcrumb-item a {
color: var(--header-bg) !important;
text-decoration: none;
}
.breadcrumb .breadcrumb-item a:hover {
text-decoration: underline;
}
.sidebar-toggle-item {
display: flex;
align-items: center;
margin-right: 0.5rem;
}
.sidebar-toggle-btn {
padding: 0;
line-height: 1;
font-size: 1.1rem;
color: var(--header-bg) !important;
border: none !important;
background: transparent !important;
box-shadow: none !important;
cursor: pointer;
}
.sidebar-toggle-btn:hover {
opacity: 0.7;
}
.sidebar-column {
transition: all 0.3s ease;
}
.sidebar-hidden {
display: none !important;
}
.navigation-section {
background-color: var(--nav-bg) !important;
color: var(--nav-font) !important;
min-height: var(--nav-height);
}
.focus-visible:focus,
.btn:focus,
.form-control:focus,
.nav-link:focus {
outline: 3px solid #0056b3 !important;
outline-offset: 2px !important;
box-shadow: 0 0 0 1px #ffffff, 0 0 0 4px #0056b3 !important;
}
@media (prefers-contrast: high) {
:root {
--text-color: #000000;
--bg-color: #ffffff;
--border-color: #000000;
--focus-color: #000000;
}
.btn-primary {
background-color: #000000 !important;
border-color: #000000 !important;
color: #ffffff !important;
}
.btn-outline-light {
color: #000000 !important;
border-color: #000000 !important;
}
.text-muted {
color: #000000 !important;
}
.navbar {
background-color: #ffffff !important;
border-bottom: 1px solid #000000 !important;
}
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
.nav-tabs {
background-color: transparent !important;
border: none !important;
}
.nav-tabs .nav-link {
background-color: transparent !important;
border: none !important;
color: var(--nav-font) !important;
}
.nav-tabs .nav-link:hover {
background-color: rgba(255, 255, 255, 0.1) !important;
}
.nav-tabs .nav-link.active {
background-color: rgba(255, 255, 255, 0.2) !important;
border-bottom: 2px solid var(--nav-font) !important;
}
.sidebar-column {
background-color: var(--sidebar-bg) !important;
border-right: 1px solid var(--sidebar-border) !important;
position: sticky;
top: 0;
min-height: calc(100vh - var(--header-height) - var(--nav-height) - 42px);
}
.sidebar {
padding: 1.5rem;
height: 100%;
overflow-y: auto;
}
.content-column {
background-color: #ffffff;
}
.content-wrapper {
padding: 2rem;
padding-bottom: 80px !important;
}
.main-content {
flex: 1;
min-height: auto;
}
@media (max-width: 767.98px) {
.sidebar-column {
border-right: none !important;
border-top: 1px solid var(--sidebar-border) !important;
min-height: auto;
margin-top: 1rem;
}
.content-column {
background-color: #ffffff;
}
.content-wrapper {
min-height: auto;
padding-bottom: 2rem !important;
}
}
@media (max-width: 991.98px) {
.sidebar-column {
order: 2 !important;
}
.content-column {
order: 1 !important;
}
}
pre {
background: #f8f9fa;
padding: 1rem;
border-radius: 6px;
overflow-x: auto;
border: 1px solid #dee2e6;
margin-bottom: 1rem;
}
pre code {
background: none;
padding: 0;
color: #333;
font-size: 0.85rem;
line-height: 1.5;
}
code {
background: #e8e8e8;
padding: 0.15rem 0.4rem;
border-radius: 3px;
font-size: 0.9em;
color: #d63384;
}
.footer-icon {
color: #6c757d;
text-decoration: none;
transition: all 0.2s ease-in-out;
display: inline-block;
padding: 2px;
}
.footer-icon:hover {
color: #0d6efd;
transform: translateY(-1px);
}
.footer-icon:active {
transform: translateY(0);
}
.footer-icon.guide:hover {
color: #198754;
}
.footer-icon.cms:hover {
color: #dc3545;
}
.footer-icon.git:hover {
color: #6f42c1;
}
.footer-icon.website:hover {
color: #fd7e14;
}
Binary file not shown.
Binary file not shown.
+11
View File
@@ -0,0 +1,11 @@
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<!-- < -->
<path d="M8 8 L3 16 L8 24" stroke="#ffffff" stroke-width="3" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
<!-- / -->
<path d="M12 24 L18 8" stroke="#ffffff" stroke-width="3" stroke-linecap="round"/>
<!-- .. -->
<circle cx="22" cy="20" r="2" fill="#ffffff"/>
<circle cx="28" cy="20" r="2" fill="#ffffff"/>
</svg>

After

Width:  |  Height:  |  Size: 442 B

+11
View File
@@ -0,0 +1,11 @@
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<!-- < -->
<path d="M8 8 L3 16 L8 24" stroke="#ffffff" stroke-width="3" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
<!-- / -->
<path d="M12 24 L18 8" stroke="#ffffff" stroke-width="3" stroke-linecap="round"/>
<!-- .. -->
<circle cx="22" cy="20" r="2" fill="#ffffff"/>
<circle cx="28" cy="20" r="2" fill="#ffffff"/>
</svg>

After

Width:  |  Height:  |  Size: 442 B

+126
View File
@@ -0,0 +1,126 @@
// Main application JavaScript
// This file contains general application functionality
/**
* Toggle sidebar visibility (open/close)
*/
function toggleSidebar() {
const sidebar = document.getElementById('site-sidebar');
const contentCol = sidebar ? sidebar.nextElementSibling || sidebar.parentElement.querySelector('.content-column') : null;
const btn = document.querySelector('.sidebar-toggle-btn');
const icon = btn ? btn.querySelector('i') : null;
if (!sidebar) return;
sidebar.classList.toggle('sidebar-hidden');
// Adjust content column width, toggle icon, and update aria-expanded
if (sidebar.classList.contains('sidebar-hidden')) {
if (contentCol) {
contentCol.classList.remove('col-lg-9', 'col-md-8');
contentCol.classList.add('col-12');
}
if (icon) {
icon.classList.remove('bi-layout-sidebar-inset');
icon.classList.add('bi-layout-sidebar');
}
if (btn) {
btn.setAttribute('aria-expanded', 'false');
}
sessionStorage.setItem('sidebarHidden', 'true');
} else {
if (contentCol) {
contentCol.classList.remove('col-12');
contentCol.classList.add('col-lg-9', 'col-md-8');
}
if (icon) {
icon.classList.remove('bi-layout-sidebar');
icon.classList.add('bi-layout-sidebar-inset');
}
if (btn) {
btn.setAttribute('aria-expanded', 'true');
}
sessionStorage.setItem('sidebarHidden', 'false');
}
}
/**
* Restore sidebar state from sessionStorage on page load
*/
function restoreSidebarState() {
if (sessionStorage.getItem('sidebarHidden') === 'true') {
const sidebar = document.getElementById('site-sidebar');
if (sidebar) {
toggleSidebar();
}
}
}
// Initialize application when DOM is ready
document.addEventListener('DOMContentLoaded', function() {
// Restore sidebar state
restoreSidebarState();
// Initialize search functionality
const searchInputs = document.querySelectorAll('.search-input');
const searchButtons = document.querySelectorAll('button[type="submit"]');
searchInputs.forEach(function(input) {
input.addEventListener('keydown', function(e) {
if (e.key === 'Enter') {
const query = this.value.trim();
if (query) {
// Submit the form
this.closest('form').submit();
} else {
e.preventDefault();
}
}
});
});
// Ensure search buttons submit the form
searchButtons.forEach(function(btn) {
btn.addEventListener('click', function(e) {
const form = this.closest('form');
if (form && form.getAttribute('role') === 'search') {
const input = form.querySelector('.search-input');
if (input && !input.value.trim()) {
e.preventDefault();
input.focus();
}
}
});
});
// Handle nested dropdowns for touch devices using event delegation
document.addEventListener('click', function(e) {
const toggle = e.target.closest('.dropdown-submenu .dropdown-toggle');
if (toggle) {
e.preventDefault();
e.stopPropagation();
const submenu = toggle.closest('.dropdown-submenu');
const dropdown = submenu.querySelector('.dropdown-menu');
// Close other submenus at the same level
const parent = submenu.parentElement;
parent.querySelectorAll('.dropdown-submenu').forEach(function(sibling) {
if (sibling !== submenu) {
var siblingMenu = sibling.querySelector('.dropdown-menu');
if (siblingMenu) siblingMenu.classList.remove('show');
}
});
// Toggle current submenu
if (dropdown) dropdown.classList.toggle('show');
return;
}
// Close all open submenus when clicking outside
document.querySelectorAll('.dropdown-submenu .dropdown-menu.show').forEach(function(menu) {
menu.classList.remove('show');
});
});
});
File diff suppressed because one or more lines are too long
@@ -11,6 +11,22 @@ $nav-height: 42px;
$sidebar-bg: #f8f9fa;
$sidebar-border: #dee2e6;
// Search input styling - override header white text
#site-header .search-input {
background-color: #ffffff !important;
color: #212529 !important;
border: 2px solid #0a369d !important;
}
#site-header .search-input::placeholder {
color: #6c757d !important;
}
#site-header .search-input:focus {
background-color: #ffffff !important;
color: #212529 !important;
border-color: #2754b4 !important;
box-shadow: 0 0 0 0.2rem rgba(10, 54, 157, 0.25) !important;
}
// Optional header background image and overlay opacity
$header-bg-image: none;
$header-bg-opacity: 1;
@@ -54,14 +70,36 @@ $header-bg-opacity: 1;
.navbar-brand,
.navbar-text,
.form-control,
.btn {
color: var(--header-font) !important;
}
.form-control {
color: var(--header-font) !important;
}
.form-control::placeholder {
color: rgba(255, 255, 255, 0.7) !important;
}
// Search input - override with dark text on white background
.search-input {
background-color: #ffffff !important;
color: #212529 !important;
border: 2px solid #0a369d !important;
}
.search-input::placeholder {
color: #6c757d !important;
opacity: 1 !important;
}
.search-input:focus {
background-color: #ffffff !important;
color: #212529 !important;
border-color: #2754b4 !important;
box-shadow: 0 0 0 0.2rem rgba(10, 54, 157, 0.25) !important;
}
.btn-outline-light {
border-color: var(--header-font) !important;
@@ -121,12 +159,14 @@ $header-bg-opacity: 1;
// Custom breadcrumb styling
.breadcrumb {
--bs-breadcrumb-divider: "";
--bs-breadcrumb-margin-bottom: 0;
margin-bottom: 0;
.breadcrumb-item {
color: var(--nav-font) !important;
color: var(--header-bg) !important;
a {
color: var(--nav-font) !important;
color: var(--header-bg) !important;
text-decoration: none;
&:hover {
@@ -271,9 +311,10 @@ $header-bg-opacity: 1;
padding-bottom: 80px !important;
}
// Ensure full height layout
// Ensure full height layout - footer stays at bottom
.main-content {
flex: 1;
min-height: auto;
}
// Mobile responsive
+24 -11
View File
@@ -30,20 +30,28 @@
<link rel="author" href="{{ author_website }}">
<link rel="me" href="{{ author_git }}">
<!-- Favicon and PWA -->
<link rel="icon" type="image/svg+xml" href="/assets/favicon.svg">
<!-- Favicon -->
<link rel="icon" href="{{ theme_base_url }}/assets/img/favicon.ico" sizes="any">
<link rel="icon" type="image/svg+xml" href="{{ theme_base_url }}/assets/img/favicon.svg">
<link rel="apple-touch-icon" href="{{ theme_base_url }}/assets/img/favicon.svg">
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="{{ theme_config.header_color|default('#0a369d') }}">
<!-- Styles -->
<link href="/assets/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/css/bootstrap-icons.css" rel="stylesheet">
<link href="/assets/css/style.css" rel="stylesheet">
<link href="/assets/css/mobile.css" rel="stylesheet">
<!-- Theme CSS -->
{% for cssFile in theme_css_files %}
<link href="{{ cssFile }}" rel="stylesheet">
{% endfor %}
<!-- Compiled theme CSS (if SCSS was used) -->
{% if theme_css_url %}
<link href="{{ theme_css_url }}" rel="stylesheet">
{% endif %}
<!-- Plugin CSS (loaded after theme so theme can override) -->
{% for cssUrl in plugin_css_urls|default([]) %}
<link href="{{ cssUrl }}" rel="stylesheet">
{% endfor %}
<!-- Accessibility styles -->
<style>
.skip-link {
@@ -86,11 +94,12 @@
<!-- Dynamic theme styles -->
<style>
html, body {
height: 100%;
html {
min-height: 100%;
}
body {
min-height: 100vh;
display: flex;
flex-direction: column;
}
@@ -127,8 +136,12 @@
{% include 'partials/footer.twig' %}
</footer>
<script src="/assets/js/bootstrap.bundle.min.js"></script>
<script src="/assets/js/app.js"></script>
<!-- Theme JS -->
{% for jsFile in theme_js_files %}
<script src="{{ jsFile }}"></script>
{% endfor %}
<!-- Theme-specific JS -->
{% if theme_js_url %}
<script src="{{ theme_js_url }}"></script>
{% endif %}
+32
View File
@@ -0,0 +1,32 @@
{% extends 'base.twig' %}
{% block title %}{{ page.title }}{% endblock %}
{% block content %}
{% if sidebar_content %}
<div class="row g-0">
<aside role="complementary" aria-label="Handleiding navigatie" id="site-sidebar" class="col-lg-3 col-md-4 sidebar-column order-2 order-md-1">
<div class="sidebar h-100">
{{ sidebar_content|raw }}
</div>
</aside>
<section id="site-content" class="col-lg-9 col-md-8 content-column order-1 order-md-2">
<div class="content-wrapper p-4">
<div class="guide-content">
{{ content|raw }}
</div>
</div>
</section>
</div>
{% else %}
<div class="container">
<section id="site-content" class="col-12">
<div class="content-wrapper p-4">
<div class="guide-content">
{{ content|raw }}
</div>
</div>
</section>
</div>
{% endif %}
{% endblock %}
-21
View File
@@ -1,21 +0,0 @@
// CodePress default theme JavaScript
// Loaded after the global app.js on every page.
(function () {
'use strict';
// Sidebar toggle (used by the breadcrumb toggle button)
function toggleSidebar() {
var sidebar = document.getElementById('site-sidebar');
if (!sidebar) return;
sidebar.classList.toggle('sidebar-hidden');
var btn = document.querySelector('.sidebar-toggle-btn');
if (btn) {
var hidden = sidebar.classList.contains('sidebar-hidden');
btn.setAttribute('aria-expanded', hidden ? 'false' : 'true');
}
}
// Expose for inline onclick handlers
window.toggleSidebar = toggleSidebar;
})();
+1 -1
View File
@@ -1,7 +1,7 @@
<header id="site-header" class="navbar navbar-expand-lg navbar-dark" style="background-color: transparent;">
<div class="container-fluid">
<a class="navbar-brand" href="/{{ current_lang }}">
<img src="/assets/icon.svg" alt="CodePress Logo" width="32" height="32" class="me-2">
<img src="{{ theme_base_url }}/assets/img/icon.svg" alt="CodePress Logo" width="32" height="32" class="me-2">
{{ site_title }}
</a>
+2 -1
View File
@@ -7,6 +7,7 @@
"full_content": "full_content.twig",
"left_sidebar": "left_sidebar.twig",
"right_sidebar": "right_sidebar.twig",
"custom1": "custom1.twig"
"custom1": "custom1.twig",
"guide": "guide.twig"
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+54
View File
@@ -0,0 +1,54 @@
/* Mobile search improvements */
@media (max-width: 991.98px) {
.navbar {
position: relative;
}
/* Hide desktop elements on mobile */
.d-none.d-lg-flex {
display: none !important;
}
#mobileSearch {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: var(--header-bg);
z-index: 1030;
}
#mobileSearch.show {
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
/* Ensure navigation doesn't overlap with expanded search */
.navigation-section {
margin-top: 0;
border: none !important;
}
}
/* Desktop improvements */
@media (min-width: 992px) {
/* Hide mobile elements on desktop */
.d-lg-none {
display: none !important;
}
/* Hide mobile search on desktop */
#mobileSearch {
display: none !important;
}
}
/* Search form improvements */
.form-control[type="search"] {
min-width: 200px;
}
@media (max-width: 576px) {
.form-control[type="search"] {
min-width: 150px;
}
}
+4
View File
@@ -0,0 +1,4 @@
/*!
* Bootstrap v5.3.8 (https://getbootstrap.com/)
* Copyright 2011-2025 The Bootstrap Authors
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+1
View File
@@ -0,0 +1 @@
1786274744
+266
View File
@@ -0,0 +1,266 @@
:root {
--header-bg: #613583;
--header-font: #ffffff;
--header-height: 120px;
--nav-bg: #813d9c;
--nav-font: #ffffff;
--nav-height: 50px;
--sidebar-bg: #f3e8f7;
--sidebar-border: #d8b4e0;
}
#site-header {
background-image: none;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
position: relative;
}
.navbar {
background-color: var(--header-bg) !important;
min-height: var(--header-height);
border-bottom: 4px solid var(--nav-bg) !important;
}
.navbar .navbar-brand,
.navbar .navbar-text,
.navbar .form-control,
.navbar .btn {
color: var(--header-font) !important;
}
.navbar .form-control::placeholder {
color: rgba(255, 255, 255, 0.7) !important;
}
.navbar .btn-outline-light {
border-color: var(--header-font) !important;
}
.dropdown-menu {
background-color: var(--header-bg) !important;
border: 1px solid var(--header-font) !important;
}
.dropdown-item {
color: var(--header-font) !important;
}
.dropdown-item:hover {
background-color: rgba(255, 255, 255, 0.1) !important;
color: var(--header-font) !important;
}
.dropdown-toggle::after {
display: none !important;
}
.btn-outline-light {
color: var(--header-font) !important;
border-color: var(--header-font) !important;
}
.btn-outline-light:hover {
background-color: rgba(255, 255, 255, 0.1) !important;
color: var(--header-font) !important;
}
.btn-outline-light:focus, .btn-outline-light:active, .show > .btn-outline-light.dropdown-toggle {
background-color: rgba(255, 255, 255, 0.1) !important;
color: var(--header-font) !important;
border-color: var(--header-font) !important;
box-shadow: none !important;
}
.bi-chevron-down {
font-size: 0.75em;
margin-left: 0.25rem;
}
.breadcrumb-item + .breadcrumb-item::before {
content: "" !important;
padding: 0 !important;
}
.breadcrumb {
--bs-breadcrumb-divider: "";
--bs-breadcrumb-margin-bottom: 0;
margin-bottom: 0;
}
.breadcrumb .breadcrumb-item {
color: var(--header-bg) !important;
}
.breadcrumb .breadcrumb-item a {
color: var(--header-bg) !important;
text-decoration: none;
}
.breadcrumb .breadcrumb-item a:hover {
text-decoration: underline;
}
.sidebar-toggle-item {
display: flex;
align-items: center;
margin-right: 0.5rem;
}
.sidebar-toggle-btn {
padding: 0;
line-height: 1;
font-size: 1.1rem;
color: var(--header-bg) !important;
border: none !important;
background: transparent !important;
box-shadow: none !important;
cursor: pointer;
}
.sidebar-toggle-btn:hover {
opacity: 0.7;
}
.sidebar-column {
transition: all 0.3s ease;
}
.sidebar-hidden {
display: none !important;
}
.navigation-section {
background-color: var(--nav-bg) !important;
color: var(--nav-font) !important;
min-height: var(--nav-height);
}
.focus-visible:focus,
.btn:focus,
.form-control:focus,
.nav-link:focus {
outline: 3px solid #0056b3 !important;
outline-offset: 2px !important;
box-shadow: 0 0 0 1px #ffffff, 0 0 0 4px #0056b3 !important;
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
.nav-tabs {
background-color: transparent !important;
border: none !important;
}
.nav-tabs .nav-link {
background-color: transparent !important;
border: none !important;
color: var(--nav-font) !important;
}
.nav-tabs .nav-link:hover {
background-color: rgba(255, 255, 255, 0.1) !important;
}
.nav-tabs .nav-link.active {
background-color: rgba(255, 255, 255, 0.2) !important;
border-bottom: 2px solid var(--nav-font) !important;
}
.sidebar-column {
background-color: var(--sidebar-bg) !important;
border-right: 1px solid var(--sidebar-border) !important;
position: sticky;
top: 0;
min-height: calc(100vh - var(--header-height) - var(--nav-height) - 42px);
}
.sidebar {
padding: 1.5rem;
height: 100%;
overflow-y: auto;
}
.sidebar .card {
border-radius: 1rem;
border: 1px solid var(--sidebar-border);
}
.content-column {
background-color: #ffffff;
}
.content-wrapper {
padding: 2rem;
padding-bottom: 80px !important;
}
.main-content {
flex: 1;
}
@media (max-width: 767.98px) {
.sidebar-column {
border-right: none !important;
border-top: 1px solid var(--sidebar-border) !important;
min-height: auto;
margin-top: 1rem;
}
.content-wrapper {
min-height: auto;
padding-bottom: 2rem !important;
}
}
@media (max-width: 991.98px) {
.sidebar-column {
order: 2 !important;
}
.content-column {
order: 1 !important;
}
}
pre {
background: #f8f9fa;
padding: 1rem;
border-radius: 6px;
overflow-x: auto;
border: 1px solid #dee2e6;
margin-bottom: 1rem;
}
pre code {
background: none;
padding: 0;
color: #333;
font-size: 0.85rem;
line-height: 1.5;
}
code {
background: #e8e8e8;
padding: 0.15rem 0.4rem;
border-radius: 3px;
font-size: 0.9em;
color: #d63384;
}
.footer-icon {
color: #6c757d;
text-decoration: none;
transition: all 0.2s ease-in-out;
display: inline-block;
padding: 2px;
}
.footer-icon:hover {
color: #0d6efd;
transform: translateY(-1px);
}
.footer-icon:active {
transform: translateY(0);
}
.footer-icon.guide:hover {
color: #198754;
}
.footer-icon.cms:hover {
color: #dc3545;
}
.footer-icon.git:hover {
color: #6f42c1;
}
.footer-icon.website:hover {
color: #fd7e14;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

+11
View File
@@ -0,0 +1,11 @@
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<!-- < -->
<path d="M8 8 L3 16 L8 24" stroke="#ffffff" stroke-width="3" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
<!-- / -->
<path d="M12 24 L18 8" stroke="#ffffff" stroke-width="3" stroke-linecap="round"/>
<!-- .. -->
<circle cx="22" cy="20" r="2" fill="#ffffff"/>
<circle cx="28" cy="20" r="2" fill="#ffffff"/>
</svg>

After

Width:  |  Height:  |  Size: 442 B

+11
View File
@@ -0,0 +1,11 @@
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<!-- < -->
<path d="M8 8 L3 16 L8 24" stroke="#ffffff" stroke-width="3" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
<!-- / -->
<path d="M12 24 L18 8" stroke="#ffffff" stroke-width="3" stroke-linecap="round"/>
<!-- .. -->
<circle cx="22" cy="20" r="2" fill="#ffffff"/>
<circle cx="28" cy="20" r="2" fill="#ffffff"/>
</svg>

After

Width:  |  Height:  |  Size: 442 B

+94
View File
@@ -0,0 +1,94 @@
// Main application JavaScript
// This file contains general application functionality
/**
* Toggle sidebar visibility (open/close)
*/
function toggleSidebar() {
const sidebar = document.getElementById('site-sidebar');
const contentCol = sidebar ? sidebar.nextElementSibling || sidebar.parentElement.querySelector('.content-column') : null;
const btn = document.querySelector('.sidebar-toggle-btn');
const icon = btn ? btn.querySelector('i') : null;
if (!sidebar) return;
sidebar.classList.toggle('sidebar-hidden');
// Adjust content column width, toggle icon, and update aria-expanded
if (sidebar.classList.contains('sidebar-hidden')) {
if (contentCol) {
contentCol.classList.remove('col-lg-9', 'col-md-8');
contentCol.classList.add('col-12');
}
if (icon) {
icon.classList.remove('bi-layout-sidebar-inset');
icon.classList.add('bi-layout-sidebar');
}
if (btn) {
btn.setAttribute('aria-expanded', 'false');
}
sessionStorage.setItem('sidebarHidden', 'true');
} else {
if (contentCol) {
contentCol.classList.remove('col-12');
contentCol.classList.add('col-lg-9', 'col-md-8');
}
if (icon) {
icon.classList.remove('bi-layout-sidebar');
icon.classList.add('bi-layout-sidebar-inset');
}
if (btn) {
btn.setAttribute('aria-expanded', 'true');
}
sessionStorage.setItem('sidebarHidden', 'false');
}
}
/**
* Restore sidebar state from sessionStorage on page load
*/
function restoreSidebarState() {
if (sessionStorage.getItem('sidebarHidden') === 'true') {
const sidebar = document.getElementById('site-sidebar');
if (sidebar) {
toggleSidebar();
}
}
}
// Initialize application when DOM is ready
document.addEventListener('DOMContentLoaded', function() {
// Restore sidebar state
restoreSidebarState();
// Handle nested dropdowns for touch devices using event delegation
document.addEventListener('click', function(e) {
const toggle = e.target.closest('.dropdown-submenu .dropdown-toggle');
if (toggle) {
e.preventDefault();
e.stopPropagation();
const submenu = toggle.closest('.dropdown-submenu');
const dropdown = submenu.querySelector('.dropdown-menu');
// Close other submenus at the same level
const parent = submenu.parentElement;
parent.querySelectorAll('.dropdown-submenu').forEach(function(sibling) {
if (sibling !== submenu) {
var siblingMenu = sibling.querySelector('.dropdown-menu');
if (siblingMenu) siblingMenu.classList.remove('show');
}
});
// Toggle current submenu
if (dropdown) dropdown.classList.toggle('show');
return;
}
// Close all open submenus when clicking outside
document.querySelectorAll('.dropdown-submenu .dropdown-menu.show').forEach(function(menu) {
menu.classList.remove('show');
});
});
});
File diff suppressed because one or more lines are too long
@@ -120,12 +120,14 @@ $header-bg-opacity: 1;
.breadcrumb {
--bs-breadcrumb-divider: "";
--bs-breadcrumb-margin-bottom: 0;
margin-bottom: 0;
.breadcrumb-item {
color: var(--nav-font) !important;
color: var(--header-bg) !important;
a {
color: var(--nav-font) !important;
color: var(--header-bg) !important;
text-decoration: none;
&:hover {
+16 -9
View File
@@ -30,16 +30,19 @@
<link rel="author" href="{{ author_website }}">
<link rel="me" href="{{ author_git }}">
<!-- Favicon and PWA -->
<link rel="icon" type="image/svg+xml" href="/assets/favicon.svg">
<!-- Favicon -->
<link rel="icon" href="{{ theme_base_url }}/assets/img/favicon.ico" sizes="any">
<link rel="icon" type="image/svg+xml" href="{{ theme_base_url }}/assets/img/favicon.svg">
<link rel="apple-touch-icon" href="{{ theme_base_url }}/assets/img/favicon.svg">
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="{{ theme_config.header_color|default('#613583') }}">
<!-- Styles -->
<link href="/assets/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/css/bootstrap-icons.css" rel="stylesheet">
<link href="/assets/css/style.css" rel="stylesheet">
<link href="/assets/css/mobile.css" rel="stylesheet">
<!-- Theme CSS -->
{% for cssFile in theme_css_files %}
<link href="{{ cssFile }}" rel="stylesheet">
{% endfor %}
<!-- Compiled theme CSS (if SCSS was used) -->
{% if theme_css_url %}
<link href="{{ theme_css_url }}" rel="stylesheet">
{% endif %}
@@ -127,8 +130,12 @@
{% include 'partials/footer.twig' %}
</footer>
<script src="/assets/js/bootstrap.bundle.min.js"></script>
<script src="/assets/js/app.js"></script>
<!-- Theme JS -->
{% for jsFile in theme_js_files %}
<script src="{{ jsFile }}"></script>
{% endfor %}
<!-- Theme-specific JS -->
{% if theme_js_url %}
<script src="{{ theme_js_url }}"></script>
{% endif %}
+32
View File
@@ -0,0 +1,32 @@
{% extends 'base.twig' %}
{% block title %}{{ page.title }}{% endblock %}
{% block content %}
{% if sidebar_content %}
<div class="row g-0">
<aside role="complementary" aria-label="Handleiding navigatie" id="site-sidebar" class="col-lg-3 col-md-4 sidebar-column order-2 order-md-1">
<div class="sidebar h-100">
{{ sidebar_content|raw }}
</div>
</aside>
<section id="site-content" class="col-lg-9 col-md-8 content-column order-1 order-md-2">
<div class="content-wrapper p-4">
<div class="guide-content">
{{ content|raw }}
</div>
</div>
</section>
</div>
{% else %}
<div class="container">
<section id="site-content" class="col-12">
<div class="content-wrapper p-4">
<div class="guide-content">
{{ content|raw }}
</div>
</div>
</section>
</div>
{% endif %}
{% endblock %}
-21
View File
@@ -1,21 +0,0 @@
// CodePress default theme JavaScript
// Loaded after the global app.js on every page.
(function () {
'use strict';
// Sidebar toggle (used by the breadcrumb toggle button)
function toggleSidebar() {
var sidebar = document.getElementById('site-sidebar');
if (!sidebar) return;
sidebar.classList.toggle('sidebar-hidden');
var btn = document.querySelector('.sidebar-toggle-btn');
if (btn) {
var hidden = sidebar.classList.contains('sidebar-hidden');
btn.setAttribute('aria-expanded', hidden ? 'false' : 'true');
}
}
// Expose for inline onclick handlers
window.toggleSidebar = toggleSidebar;
})();
+1 -1
View File
@@ -1,7 +1,7 @@
<header id="site-header" class="navbar navbar-expand-lg navbar-dark" style="background-color: transparent;">
<div class="container-fluid">
<a class="navbar-brand" href="/{{ current_lang }}">
<img src="/assets/icon.svg" alt="CodePress Logo" width="32" height="32" class="me-2">
<img src="{{ theme_base_url }}/assets/img/icon.svg" alt="CodePress Logo" width="32" height="32" class="me-2">
{{ site_title }}
</a>
+2 -1
View File
@@ -7,6 +7,7 @@
"full_content": "full_content.twig",
"left_sidebar": "left_sidebar.twig",
"right_sidebar": "right_sidebar.twig",
"custom1": "custom1.twig"
"custom1": "custom1.twig",
"guide": "guide.twig"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB