Refactor: Replace sidebar with horizontal navigation bar
- Remove sidebar and toggle functionality - Add Bootstrap navbar with dropdown menus - Move navigation to top between header and content - Update menu rendering for Bootstrap dropdowns - Clean up unused files (header.mustache, sidebar.mustache, sidebar.js) - Add guide link with book icon in footer - Simplify layout structure - Remove duplicate code and fix syntax errors - Add .gitignore for node_modules and other temp files
This commit is contained in:
26
engine/templates/assets/footer.mustache
Normal file
26
engine/templates/assets/footer.mustache
Normal file
@@ -0,0 +1,26 @@
|
||||
<footer class="bg-light border-top py-3">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="file-info">
|
||||
<i class="bi bi-file-text"></i>
|
||||
<span class="page-title" title="{{page_title}}">{{page_title}}</span>
|
||||
{{#file_info}}
|
||||
<span class="file-details"> | {{{file_info}}}</span>
|
||||
{{/file_info}}
|
||||
</div>
|
||||
<div class="site-info">
|
||||
<small class="text-muted">
|
||||
<a href="?guide" class="guide-link" title="Handleiding">
|
||||
<i class="bi bi-book"></i>
|
||||
</a>
|
||||
<span class="ms-2">|</span>
|
||||
Powered by <a href="https://git.noorlander.info/E.Noorlander/CodePress.git" target="_blank" rel="noopener">CodePress CMS</a>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
23
engine/templates/assets/navigation.mustache
Normal file
23
engine/templates/assets/navigation.mustache
Normal file
@@ -0,0 +1,23 @@
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="?page={{default_page}}">
|
||||
<img src="/assets/icon.svg" alt="CodePress Logo" width="32" height="32" class="me-2">
|
||||
{{site_title}}
|
||||
</a>
|
||||
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav me-auto">
|
||||
{{{menu}}}
|
||||
</ul>
|
||||
|
||||
<form class="d-flex" method="GET" action="">
|
||||
<input class="form-control me-2" type="search" name="search" placeholder="Search..." value="{{search_query}}">
|
||||
<button class="btn btn-outline-light" type="submit">Search</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -1,440 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{page_title}} - {{site_title}}</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/engine/assets/favicon.svg">
|
||||
<link href="/engine/assets/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="/engine/assets/css/bootstrap-icons.css" rel="stylesheet">
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.main-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: calc(100vh - 70px); /* Minus header height */
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 250px;
|
||||
background-color: #f8f9fa;
|
||||
border-right: 1px solid #dee2e6;
|
||||
overflow-y: auto;
|
||||
flex-shrink: 0;
|
||||
transition: transform 0.3s ease;
|
||||
position: fixed;
|
||||
top: 70px;
|
||||
left: 0;
|
||||
height: calc(100vh - 140px); /* 70px header + 70px footer */
|
||||
z-index: 999;
|
||||
transform: translateX(0);
|
||||
}
|
||||
.sidebar.collapsed {
|
||||
transform: translateX(-250px);
|
||||
}
|
||||
.sidebar-toggle {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
z-index: 1001;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
font-size: 20px;
|
||||
color: #6c757d;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.sidebar-toggle:hover {
|
||||
color: #0d6efd;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.sidebar-toggle-inner {
|
||||
/* Toggle inside sidebar */
|
||||
}
|
||||
.sidebar-toggle-outer {
|
||||
position: fixed;
|
||||
top: 90px;
|
||||
left: 20px;
|
||||
z-index: 1001;
|
||||
background-color: white;
|
||||
border: 1px solid #dee2e6;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
.sidebar.collapsed .sidebar-toggle-inner {
|
||||
right: auto;
|
||||
left: 15px;
|
||||
}
|
||||
.sidebar.collapsed ~ .main-content .sidebar-toggle-outer {
|
||||
display: block !important;
|
||||
}
|
||||
.sidebar:not(.collapsed) ~ .main-content .sidebar-toggle-outer {
|
||||
display: none !important;
|
||||
}
|
||||
.sidebar-toggle:hover {
|
||||
background-color: #0a58ca;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
.main-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
transition: all 0.3s ease;
|
||||
margin-left: 250px;
|
||||
}
|
||||
.sidebar.collapsed ~ .main-content {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
transition: margin-left 0.3s ease;
|
||||
}
|
||||
|
||||
.folder-toggle {
|
||||
font-weight: bold;
|
||||
color: #212529 !important;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.5rem 0.75rem;
|
||||
background-color: #f8f9fa !important;
|
||||
margin: 0.125rem 0;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
.folder-toggle:hover {
|
||||
background-color: #e9ecef !important;
|
||||
}
|
||||
.folder-toggle[aria-expanded="true"] {
|
||||
background-color: #dee2e6 !important;
|
||||
color: #212529 !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
/* Progressive background colors for nested folders */
|
||||
.nav .nav .folder-toggle {
|
||||
background-color: #f1f3f4 !important;
|
||||
}
|
||||
.nav .nav .nav .folder-toggle {
|
||||
background-color: #eaedee !important;
|
||||
}
|
||||
.nav .nav .nav .nav .folder-toggle {
|
||||
background-color: #e3e7e8 !important;
|
||||
}
|
||||
.nav .nav .nav .nav .nav .folder-toggle {
|
||||
background-color: #dce1e2 !important;
|
||||
}
|
||||
.nav .nav .nav .nav .nav .nav .folder-toggle {
|
||||
background-color: #d5dbdd !important;
|
||||
}
|
||||
.nav .nav .nav .nav .nav .nav .nav .folder-toggle {
|
||||
background-color: #ced5d8 !important;
|
||||
}
|
||||
.nav .nav .nav .nav .nav .nav .nav .nav .folder-toggle {
|
||||
background-color: #c7cfd3 !important;
|
||||
}
|
||||
.nav .nav .nav .nav .nav .nav .nav .nav .nav .folder-toggle {
|
||||
background-color: #c0c9ce !important;
|
||||
}
|
||||
.nav .nav .nav .nav .nav .nav .nav .nav .nav .nav .folder-toggle {
|
||||
background-color: #b9c3c9 !important;
|
||||
}
|
||||
.folder-toggle .arrow {
|
||||
margin-right: 8px;
|
||||
transition: transform 0.2s;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.folder-toggle[aria-expanded="true"] .arrow {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
.page-link {
|
||||
color: #495057 !important;
|
||||
font-weight: 500;
|
||||
padding: 0.5rem 0.75rem;
|
||||
padding-left: 2rem;
|
||||
background-color: #ffffff !important;
|
||||
margin: 0.125rem 0;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
/* Progressive background colors for nested pages */
|
||||
.nav .nav .page-link {
|
||||
background-color: #fafbfc !important;
|
||||
}
|
||||
.nav .nav .nav .page-link {
|
||||
background-color: #f5f7f8 !important;
|
||||
}
|
||||
.nav .nav .nav .nav .page-link {
|
||||
background-color: #f0f3f4 !important;
|
||||
}
|
||||
.nav .nav .nav .nav .nav .page-link {
|
||||
background-color: #ebefef !important;
|
||||
}
|
||||
.nav .nav .nav .nav .nav .nav .page-link {
|
||||
background-color: #e6eaea !important;
|
||||
}
|
||||
.nav .nav .nav .nav .nav .nav .nav .page-link {
|
||||
background-color: #e1e5e5 !important;
|
||||
}
|
||||
.nav .nav .nav .nav .nav .nav .nav .nav .page-link {
|
||||
background-color: #dce0e0 !important;
|
||||
}
|
||||
.nav .nav .nav .nav .nav .nav .nav .nav .nav .page-link {
|
||||
background-color: #d7dbdb !important;
|
||||
}
|
||||
.nav .nav .nav .nav .nav .nav .nav .nav .nav .nav .page-link {
|
||||
background-color: #d2d6d6 !important;
|
||||
}
|
||||
.page-link:hover {
|
||||
color: #212529 !important;
|
||||
background-color: #f8f9fa !important;
|
||||
}
|
||||
.nav-link.active {
|
||||
background-color: #0d6efd !important;
|
||||
color: #212529 !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
.file-info {
|
||||
font-size: 0.9rem;
|
||||
color: #6c757d;
|
||||
}
|
||||
.site-info a {
|
||||
color: #0d6efd;
|
||||
text-decoration: none;
|
||||
}
|
||||
.site-info a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.auto-link {
|
||||
color: #0d6efd;
|
||||
text-decoration: none;
|
||||
border-bottom: 2px dashed #0d6efd;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.auto-link:hover {
|
||||
color: #0a58ca;
|
||||
text-decoration: none;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-color: #0a58ca;
|
||||
}
|
||||
.search-form {
|
||||
max-width: 300px;
|
||||
}
|
||||
.card-title a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
.card-title a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.folder-disabled {
|
||||
font-weight: 500;
|
||||
color: #6c757d !important;
|
||||
cursor: not-allowed;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.5rem 0.75rem;
|
||||
background-color: #f8f9fa !important;
|
||||
margin: 0.125rem 0;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.folder-disabled .arrow {
|
||||
margin-right: 8px;
|
||||
font-size: 0.8em;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.sidebar {
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header class="bg-primary text-white py-3">
|
||||
<div class="container-fluid">
|
||||
<div class="row align-items-center">
|
||||
<div class="col">
|
||||
<div class="d-flex align-items-center">
|
||||
<img src="/engine/assets/icon.svg" alt="CodePress Logo" width="32" height="32" class="me-2">
|
||||
<h1 class="h3 mb-0">{{site_title}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<form class="d-flex" method="GET" action="">
|
||||
<input class="form-control me-2" type="search" name="search" placeholder="Search..." value="{{search_query}}">
|
||||
<button class="btn btn-outline-light" type="submit">Search</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main-wrapper">
|
||||
<div class="content-wrapper">
|
||||
<nav class="sidebar" id="sidebar">
|
||||
<div class="sidebar-toggle sidebar-toggle-inner" id="sidebarToggleInner">
|
||||
<i class="bi bi-list"></i>
|
||||
</div>
|
||||
<div class="pt-3">
|
||||
<ul class="nav flex-column">
|
||||
{{menu}}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="main-content">
|
||||
<div class="sidebar-toggle sidebar-toggle-outer" id="sidebarToggleOuter" style="display: none;">
|
||||
<i class="bi bi-list"></i>
|
||||
</div>
|
||||
<div>
|
||||
{{breadcrumb}}
|
||||
</div>
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h2>{{page_title}}</h2>
|
||||
</div>
|
||||
<div class="content">
|
||||
{{content}}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="bg-light border-top py-3" style="position: fixed; bottom: 0; left: 0; right: 0; z-index: 998;">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="file-info">
|
||||
{{file_info}}
|
||||
</div>
|
||||
<div class="site-info">
|
||||
<small class="text-muted">Powered by <a href="https://git.noorlander.info/E.Noorlander/CodePress.git" target="_blank" rel="noopener">CodePress CMS</a></small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="/engine/assets/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Sidebar toggle functionality
|
||||
const sidebarToggleInner = document.getElementById('sidebarToggleInner');
|
||||
const sidebarToggleOuter = document.getElementById('sidebarToggleOuter');
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
|
||||
// Initialize sidebar state (open by default)
|
||||
sidebar.classList.remove('collapsed');
|
||||
const innerIcon = sidebarToggleInner.querySelector('i');
|
||||
const outerIcon = sidebarToggleOuter.querySelector('i');
|
||||
innerIcon.classList.remove('bi-list');
|
||||
innerIcon.classList.add('bi-x');
|
||||
outerIcon.classList.remove('bi-list');
|
||||
outerIcon.classList.add('bi-x');
|
||||
|
||||
function toggleSidebar() {
|
||||
sidebar.classList.toggle('collapsed');
|
||||
|
||||
// Change icons
|
||||
if (sidebar.classList.contains('collapsed')) {
|
||||
innerIcon.classList.remove('bi-x');
|
||||
innerIcon.classList.add('bi-list');
|
||||
outerIcon.classList.remove('bi-x');
|
||||
outerIcon.classList.add('bi-list');
|
||||
} else {
|
||||
innerIcon.classList.remove('bi-list');
|
||||
innerIcon.classList.add('bi-x');
|
||||
outerIcon.classList.remove('bi-list');
|
||||
outerIcon.classList.add('bi-x');
|
||||
}
|
||||
}
|
||||
|
||||
sidebarToggleInner.addEventListener('click', toggleSidebar);
|
||||
sidebarToggleOuter.addEventListener('click', toggleSidebar);
|
||||
|
||||
// Folders are now automatically expanded by PHP if they contain the active page
|
||||
|
||||
// Close other folders when opening a new one
|
||||
const folderToggles = document.querySelectorAll('.folder-toggle');
|
||||
folderToggles.forEach(toggle => {
|
||||
toggle.addEventListener('click', function(e) {
|
||||
const targetId = this.getAttribute('data-bs-target');
|
||||
const targetCollapse = document.querySelector(targetId);
|
||||
const isExpanded = this.getAttribute('aria-expanded') === 'true';
|
||||
|
||||
if (!isExpanded && targetCollapse) {
|
||||
// Close all other folders first
|
||||
folderToggles.forEach(otherToggle => {
|
||||
if (otherToggle !== this) {
|
||||
const otherTargetId = otherToggle.getAttribute('data-bs-target');
|
||||
if (otherTargetId) {
|
||||
const otherCollapse = document.querySelector(otherTargetId);
|
||||
if (otherCollapse) {
|
||||
otherCollapse.classList.remove('show');
|
||||
otherToggle.setAttribute('aria-expanded', 'false');
|
||||
// Reset arrow
|
||||
const otherArrow = otherToggle.querySelector('.arrow');
|
||||
if (otherArrow) {
|
||||
otherArrow.style.transform = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Open this folder
|
||||
targetCollapse.classList.add('show');
|
||||
this.setAttribute('aria-expanded', 'true');
|
||||
// Rotate arrow
|
||||
const arrow = this.querySelector('.arrow');
|
||||
if (arrow) {
|
||||
arrow.style.transform = 'rotate(90deg)';
|
||||
}
|
||||
} else if (isExpanded && targetCollapse) {
|
||||
// Close this folder
|
||||
targetCollapse.classList.remove('show');
|
||||
this.setAttribute('aria-expanded', 'false');
|
||||
// Reset arrow
|
||||
const arrow = this.querySelector('.arrow');
|
||||
if (arrow) {
|
||||
arrow.style.transform = '';
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
39
engine/templates/layout.mustache
Normal file
39
engine/templates/layout.mustache
Normal file
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{page_title}} - {{site_title}}</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/assets/favicon.svg">
|
||||
<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">
|
||||
</head>
|
||||
<body>
|
||||
{{>header}}
|
||||
|
||||
<div class="main-wrapper">
|
||||
{{>navigation}}
|
||||
|
||||
<main class="main-content">
|
||||
<div class="content-inner">
|
||||
<div>
|
||||
{{{breadcrumb}}}
|
||||
</div>
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h2>{{page_title}}</h2>
|
||||
</div>
|
||||
<div class="content">
|
||||
{{{content}}}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
{{>footer}}
|
||||
|
||||
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="/assets/js/sidebar.js"></script>
|
||||
<script src="/assets/js/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
3
engine/templates/markdown_content.mustache
Normal file
3
engine/templates/markdown_content.mustache
Normal file
@@ -0,0 +1,3 @@
|
||||
{{#content}}
|
||||
<p>{{{.}}}</p>
|
||||
{{/content}}
|
||||
1
engine/templates/php_content.mustache
Normal file
1
engine/templates/php_content.mustache
Normal file
@@ -0,0 +1 @@
|
||||
{{{content}}}
|
||||
Reference in New Issue
Block a user