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:
@@ -2,6 +2,52 @@
|
||||
|
||||
require_once 'config.php';
|
||||
|
||||
// Simple template rendering without Mustache for now
|
||||
class SimpleTemplate {
|
||||
public static function render($template, $data) {
|
||||
// Handle conditional blocks first
|
||||
foreach ($data as $key => $value) {
|
||||
if (is_array($value) || (is_string($value) && !empty($value))) {
|
||||
// Handle {{#key}}...{{/key}} blocks
|
||||
$pattern = '/{{#' . preg_quote($key, '/') . '}}(.*?){{\/' . preg_quote($key, '/') . '}}/s';
|
||||
if (preg_match($pattern, $template, $matches)) {
|
||||
$replacement = $matches[1];
|
||||
$template = preg_replace($pattern, $replacement, $template);
|
||||
}
|
||||
|
||||
// Handle {{^key}}...{{/key}} blocks (negative condition)
|
||||
$pattern = '/{{\^' . preg_quote($key, '/') . '}}(.*?){{\/' . preg_quote($key, '/') . '}}/s';
|
||||
$template = preg_replace($pattern, '', $template);
|
||||
} else {
|
||||
// Handle empty blocks
|
||||
$pattern = '/{{#' . preg_quote($key, '/') . '}}.*?{{\/' . preg_quote($key, '/') . '}}/s';
|
||||
$template = preg_replace($pattern, '', $template);
|
||||
|
||||
// Handle {{^key}}...{{/key}} blocks (show when empty)
|
||||
$pattern = '/{{\^' . preg_quote($key, '/') . '}}(.*?){{\/' . preg_quote($key, '/') . '}}/s';
|
||||
if (preg_match_all($pattern, $template, $matches)) {
|
||||
foreach ($matches[1] as $match) {
|
||||
$template = preg_replace('/{{\^' . preg_quote($key, '/') . '}}.*?{{\/' . preg_quote($key, '/') . '}}/s', $match, $template, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle variable replacements
|
||||
foreach ($data as $key => $value) {
|
||||
// Handle triple braces for unescaped HTML content
|
||||
if (strpos($template, '{{{' . $key . '}}}') !== false) {
|
||||
$template = str_replace('{{{' . $key . '}}}', $value, $template);
|
||||
}
|
||||
// Handle double braces for escaped content
|
||||
elseif (strpos($template, '{{' . $key . '}}') !== false) {
|
||||
$template = str_replace('{{' . $key . '}}', htmlspecialchars($value, ENT_QUOTES, 'UTF-8'), $template);
|
||||
}
|
||||
}
|
||||
return $template;
|
||||
}
|
||||
}
|
||||
|
||||
$config = include 'config.php';
|
||||
|
||||
class CodePressCMS {
|
||||
@@ -104,6 +150,16 @@ class CodePressCMS {
|
||||
return $this->getSearchResults();
|
||||
}
|
||||
|
||||
// Check if guide is requested
|
||||
if (isset($_GET['guide'])) {
|
||||
return $this->getGuidePage();
|
||||
}
|
||||
|
||||
// Check if content directory is empty
|
||||
if ($this->isContentDirEmpty()) {
|
||||
return $this->getGuidePage();
|
||||
}
|
||||
|
||||
$page = $_GET['page'] ?? $this->config['default_page'];
|
||||
$page = preg_replace('/\.[^.]+$/', '', $page);
|
||||
|
||||
@@ -348,6 +404,46 @@ private function autoLinkPageTitles($content) {
|
||||
];
|
||||
}
|
||||
|
||||
private function isContentDirEmpty() {
|
||||
$contentDir = $this->config['content_dir'];
|
||||
if (!is_dir($contentDir)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$files = scandir($contentDir);
|
||||
$files = array_diff($files, ['.', '..']);
|
||||
|
||||
return empty($files);
|
||||
}
|
||||
|
||||
private function getGuidePage() {
|
||||
$lang = $this->detectLanguage();
|
||||
$guideFile = __DIR__ . '/../../guide/' . $lang . '.md';
|
||||
|
||||
if (!file_exists($guideFile)) {
|
||||
$guideFile = __DIR__ . '/../../guide/en.md'; // Fallback to English
|
||||
}
|
||||
|
||||
$content = file_get_contents($guideFile);
|
||||
$result = $this->parseMarkdown($content);
|
||||
|
||||
// Set special title for guide
|
||||
$result['title'] = 'Handleiding - CodePress CMS';
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function detectLanguage() {
|
||||
// Simple language detection based on browser Accept-Language header
|
||||
$acceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '';
|
||||
|
||||
if (strpos($acceptLanguage, 'nl') !== false) {
|
||||
return 'nl';
|
||||
}
|
||||
|
||||
return 'en'; // Default to English
|
||||
}
|
||||
|
||||
private function getError404() {
|
||||
return [
|
||||
'title' => 'Page Not Found',
|
||||
@@ -364,27 +460,59 @@ private function autoLinkPageTitles($content) {
|
||||
$menu = $this->getMenu();
|
||||
$breadcrumb = $this->getBreadcrumb();
|
||||
|
||||
$template = file_get_contents($this->config['templates_dir'] . '/layout.html');
|
||||
|
||||
$template = str_replace('{{site_title}}', $this->config['site_title'], $template);
|
||||
$template = str_replace('{{page_title}}', $page['title'], $template);
|
||||
$template = str_replace('{{content}}', $page['content'], $template);
|
||||
$template = str_replace('{{search_query}}', isset($_GET['search']) ? htmlspecialchars($_GET['search']) : '', $template);
|
||||
$template = str_replace('{{breadcrumb}}', $breadcrumb, $template);
|
||||
// Prepare template data
|
||||
$templateData = [
|
||||
'site_title' => $this->config['site_title'],
|
||||
'page_title' => htmlspecialchars($page['title']),
|
||||
'content' => $page['content'],
|
||||
'search_query' => isset($_GET['search']) ? htmlspecialchars($_GET['search']) : '',
|
||||
'menu' => $this->renderMenu($menu),
|
||||
'breadcrumb' => $breadcrumb,
|
||||
'default_page' => $this->config['default_page']
|
||||
];
|
||||
|
||||
// File info for footer
|
||||
$fileInfo = '';
|
||||
if (isset($page['file_info'])) {
|
||||
$fileInfo = '<i class="bi bi-file-text"></i> Created: ' . htmlspecialchars($page['file_info']['created']) .
|
||||
' | Modified: ' . htmlspecialchars($page['file_info']['modified']);
|
||||
$templateData['file_info'] = 'Created: ' . htmlspecialchars($page['file_info']['created']) .
|
||||
' | Modified: ' . htmlspecialchars($page['file_info']['modified']);
|
||||
} else {
|
||||
$templateData['file_info'] = '';
|
||||
}
|
||||
$template = str_replace('{{file_info}}', $fileInfo, $template);
|
||||
|
||||
$menuHtml = $this->renderMenu($menu);
|
||||
// Check if content exists for guide link
|
||||
$hasContent = !$this->isContentDirEmpty();
|
||||
$templateData['has_content'] = $hasContent;
|
||||
|
||||
$template = str_replace('{{menu}}', $menuHtml, $template);
|
||||
// Don't show site title link on guide page
|
||||
$templateData['show_site_link'] = !$this->isContentDirEmpty() && !isset($_GET['guide']);
|
||||
|
||||
echo $template;
|
||||
// Load partials manually
|
||||
$hasContent = !$this->isContentDirEmpty() && !isset($_GET['guide']);
|
||||
|
||||
$headerContent = file_get_contents($this->config['templates_dir'] . '/assets/header.mustache');
|
||||
if (!$hasContent) {
|
||||
// Remove the link from header when no content
|
||||
$headerContent = preg_replace('/<a href="[^"]*" class="site-title-link">\s*<h1[^>]*>(.*?)<\/h1>\s*<\/a>/', '<h1 class="h3 mb-0">$1</h1>', $headerContent);
|
||||
}
|
||||
|
||||
$footerContent = file_get_contents($this->config['templates_dir'] . '/assets/footer.mustache');
|
||||
if (!$hasContent) {
|
||||
// Remove guide link from footer when no content
|
||||
$footerContent = preg_replace('/<span class="file-details">\s*\|\s*<a href="\?guide"[^>]*>Handleiding<\/a><\/span>/', '', $footerContent);
|
||||
}
|
||||
|
||||
$partials = [
|
||||
'navigation' => file_get_contents($this->config['templates_dir'] . '/assets/navigation.mustache'),
|
||||
'footer' => file_get_contents($this->config['templates_dir'] . '/assets/footer.mustache')
|
||||
];
|
||||
|
||||
// Replace partials in template
|
||||
$template = file_get_contents($this->config['templates_dir'] . '/layout.mustache');
|
||||
$template = str_replace('{{>navigation}}', $partials['navigation'], $template);
|
||||
$template = str_replace('{{>footer}}', $partials['footer'], $template);
|
||||
|
||||
// Render template with data
|
||||
echo SimpleTemplate::render($template, $templateData);
|
||||
}
|
||||
|
||||
private function getBreadcrumb() {
|
||||
@@ -423,33 +551,27 @@ private function autoLinkPageTitles($content) {
|
||||
foreach ($items as $item) {
|
||||
if ($item['type'] === 'folder') {
|
||||
$hasChildren = !empty($item['children']);
|
||||
$html .= '<li class="nav-item">';
|
||||
|
||||
if ($hasChildren) {
|
||||
$folderId = 'folder-' . str_replace('/', '-', $item['path']);
|
||||
|
||||
// Check if this folder contains the active page
|
||||
$containsActive = $this->folderContainsActivePage($item['children']);
|
||||
$ariaExpanded = $containsActive ? 'true' : 'false';
|
||||
$collapseClass = $containsActive ? 'collapse show' : 'collapse';
|
||||
|
||||
$html .= '<span class="nav-link folder-toggle" data-bs-toggle="collapse" data-bs-target="#' . $folderId . '" aria-expanded="' . $ariaExpanded . '">';
|
||||
$html .= '<i class="arrow bi bi-chevron-right"></i> ' . htmlspecialchars($item['title']);
|
||||
$html .= '</span>';
|
||||
$html .= '<ul class="nav flex-column ms-2 ' . $collapseClass . '" id="' . $folderId . '">';
|
||||
$isExpanded = $this->folderContainsActivePage($item['children']);
|
||||
$html .= '<li class="nav-item dropdown">';
|
||||
$html .= '<a class="nav-link dropdown-toggle" href="#" id="' . $folderId . '" role="button" data-bs-toggle="dropdown" aria-expanded="' . ($isExpanded ? 'true' : 'false') . '">';
|
||||
$html .= htmlspecialchars($item['title']);
|
||||
$html .= '</a>';
|
||||
$html .= '<ul class="dropdown-menu" aria-labelledby="' . $folderId . '">';
|
||||
$html .= $this->renderMenu($item['children'], $level + 1);
|
||||
$html .= '</ul>';
|
||||
$html .= '</li>';
|
||||
} else {
|
||||
$html .= '<span class="nav-link folder-disabled" disabled>';
|
||||
$html .= '<i class="arrow bi bi-chevron-right"></i> ' . htmlspecialchars($item['title']);
|
||||
$html .= '</span>';
|
||||
$html .= '<li class="nav-item">';
|
||||
$html .= '<span class="nav-link text-muted">' . htmlspecialchars($item['title']) . '</span>';
|
||||
$html .= '</li>';
|
||||
}
|
||||
|
||||
$html .= '</li>';
|
||||
} else {
|
||||
$active = (isset($_GET['page']) && $_GET['page'] === $item['path']) ? 'active' : '';
|
||||
$html .= '<li class="nav-item">';
|
||||
$html .= '<a class="nav-link page-link ' . $active . '" href="' . htmlspecialchars($item['url']) . '">' . htmlspecialchars($item['title']) . '</a>';
|
||||
$html .= '<a class="nav-link ' . $active . '" href="' . htmlspecialchars($item['url']) . '">' . htmlspecialchars($item['title']) . '</a>';
|
||||
$html .= '</li>';
|
||||
}
|
||||
}
|
||||
@@ -470,7 +592,4 @@ private function autoLinkPageTitles($content) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$cms = new CodePressCMS($config);
|
||||
$cms->render();
|
||||
}
|
||||
Reference in New Issue
Block a user