Refactor code structure for improved readability and maintainability

This commit is contained in:
interlope committed 2026-06-03 00:10:14 +02:00
1 parent 3b31711b49
commit fa211d243f
14 files changed
+428 -11

No files matched your search

+190
View File
@@ -3,6 +3,38 @@
Monochrome palette with light & dark modes Monochrome palette with light & dark modes
======================================== */ ======================================== */
/* ----------------------------------------
INTER — self-hosted (no third-party font request)
---------------------------------------- */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('../fonts/inter-400.woff2') format('woff2');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('../fonts/inter-500.woff2') format('woff2');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url('../fonts/inter-600.woff2') format('woff2');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('../fonts/inter-700.woff2') format('woff2');
}
/* ---------------------------------------- /* ----------------------------------------
THEME TOKENS — Light Mode (default) THEME TOKENS — Light Mode (default)
---------------------------------------- */ ---------------------------------------- */
@@ -2212,6 +2244,164 @@ button:focus:not(:focus-visible) {
.toc-drawer { display: none !important; } .toc-drawer { display: none !important; }
} }
/* ========================================
SEARCH OVERLAY
======================================== */
.search-overlay {
position: fixed;
inset: 0;
z-index: 2500;
display: flex;
justify-content: center;
align-items: flex-start;
padding: 12vh 1rem 1rem;
background: rgba(0, 0, 0, 0.5);
opacity: 0;
visibility: hidden;
transition: opacity 0.15s ease, visibility 0s linear 0.15s;
}
.search-overlay.is-open {
opacity: 1;
visibility: visible;
transition: opacity 0.15s ease;
}
.search-box {
width: 100%;
max-width: 560px;
overflow: hidden;
background: var(--bg-surface);
border: 1px solid var(--border-color);
border-radius: var(--radius-md);
box-shadow: var(--shadow-lg);
}
.search-input {
width: 100%;
padding: 1rem 1.2rem;
border: none;
border-bottom: 1px solid var(--border-color);
background: transparent;
color: var(--text-primary);
font-family: var(--font-sans);
font-size: 1.05rem;
outline: none;
}
.search-input::placeholder { color: var(--text-muted); }
.search-results {
list-style: none;
margin: 0;
padding: 0.4rem;
max-height: 50vh;
overflow-y: auto;
}
.search-result a {
display: flex;
align-items: baseline;
gap: 0.6rem;
padding: 0.55rem 0.8rem;
border-radius: var(--radius-sm);
color: var(--text-primary);
}
.search-result a:hover,
.search-result.is-active a {
background: var(--bg-hover);
text-decoration: none;
}
.search-result-title { font-weight: 600; }
.search-result-meta {
margin-left: auto;
font-size: var(--font-size-xs);
color: var(--text-muted);
white-space: nowrap;
}
.search-empty { padding: 1rem 1.2rem; color: var(--text-muted); }
/* ========================================
SERIES BOX
======================================== */
.series-box {
margin: 0 0 var(--space-lg);
padding: var(--space-sm) var(--space-md);
border: 1px solid var(--border-color);
border-left: 4px solid var(--accent);
border-radius: var(--radius-sm);
background: var(--bg-subtle);
}
.series-box-title {
display: flex;
align-items: center;
gap: 0.45rem;
margin-bottom: 0.4rem;
font-weight: 700;
color: var(--text-primary);
}
.series-box-title .bd-icon { color: var(--accent); flex: 0 0 auto; }
.series-list { margin: 0; padding-left: 1.5rem; }
.series-item { padding: 0.12rem 0; color: var(--text-secondary); }
.series-item a { color: var(--text-secondary); }
.series-item a:hover { color: var(--accent); }
.series-item.is-current span { color: var(--accent); font-weight: 600; }
/* ========================================
CONTENT EXTRAS (kbd, mark, task lists, footnotes, external links)
======================================== */
.content kbd {
display: inline-block;
padding: 0.1em 0.45em;
font-family: var(--font-sans);
font-size: 0.8em;
line-height: 1.4;
color: var(--text-primary);
background: var(--bg-subtle);
border: 1px solid var(--border-color);
border-bottom-width: 2px;
border-radius: 5px;
white-space: nowrap;
}
.content mark {
padding: 0.05em 0.2em;
border-radius: 3px;
background: rgba(245, 200, 66, 0.35);
color: inherit;
}
/* Small ↗ after outbound links (JS adds target=_blank to external links) */
.content a[target="_blank"]::after {
content: "↗";
margin-left: 0.15em;
font-size: 0.8em;
color: var(--text-muted);
}
/* Task lists (- [ ] / - [x]) — rendered by JS into real checkboxes */
.content ul.task-list { list-style: none; padding-left: 0.2rem; }
.content .task-list-item { display: flex; align-items: flex-start; gap: 0.5rem; }
.content .task-list-item input[type="checkbox"] { margin-top: 0.35em; flex: 0 0 auto; }
/* Footnotes (when the parser emits them) */
.content .footnotes {
margin-top: var(--space-lg);
padding-top: var(--space-md);
border-top: 1px solid var(--border-subtle);
font-size: var(--font-size-sm);
color: var(--text-secondary);
}
/* Definition lists */
.content dt { font-weight: 700; }
.content dd { margin: 0 0 0.6rem; color: var(--text-secondary); }
/* ======================================== /* ========================================
RESPONSIVE RESPONSIVE
======================================== */ ======================================== */
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+6 -1
View File
@@ -191,6 +191,7 @@
// Theme directory URL, so the deferred bundle can load self-hosted assets // Theme directory URL, so the deferred bundle can load self-hosted assets
// (highlight.js + its theme CSS) relative to the theme. // (highlight.js + its theme CSS) relative to the theme.
window.BLOWDIT_THEME_URL = <?php echo json_encode(DOMAIN_THEME); ?>; window.BLOWDIT_THEME_URL = <?php echo json_encode(DOMAIN_THEME); ?>;
window.BLOWDIT_HOME = <?php echo json_encode(Theme::siteUrl()); ?>;
// Localised UI strings for the deferred bundle. $L->get() falls back to // Localised UI strings for the deferred bundle. $L->get() falls back to
// the key itself when a translation is missing, so this is safe in any language. // the key itself when a translation is missing, so this is safe in any language.
window.BLOWDIT_I18N = { window.BLOWDIT_I18N = {
@@ -203,7 +204,11 @@
goToSlide: <?php echo json_encode($L->get('Go to slide')); ?>, goToSlide: <?php echo json_encode($L->get('Go to slide')); ?>,
prevImage: <?php echo json_encode($L->get('Previous image')); ?>, prevImage: <?php echo json_encode($L->get('Previous image')); ?>,
nextImage: <?php echo json_encode($L->get('Next image')); ?>, nextImage: <?php echo json_encode($L->get('Next image')); ?>,
imageViewer: <?php echo json_encode($L->get('Image viewer')); ?> imageViewer: <?php echo json_encode($L->get('Image viewer')); ?>,
onThisPage: <?php echo json_encode($L->get('On this page')); ?>,
search: <?php echo json_encode($L->get('Search')); ?>,
searchPlaceholder: <?php echo json_encode($L->get('Search posts…')); ?>,
noResults: <?php echo json_encode($L->get('No results')); ?>
}; };
</script> </script>
<?php <?php
+152 -1
View File
@@ -23,7 +23,10 @@
prevImage: I18N.prevImage || 'Previous image', prevImage: I18N.prevImage || 'Previous image',
nextImage: I18N.nextImage || 'Next image', nextImage: I18N.nextImage || 'Next image',
imageViewer: I18N.imageViewer || 'Image viewer', imageViewer: I18N.imageViewer || 'Image viewer',
onThisPage: I18N.onThisPage || 'On this page' onThisPage: I18N.onThisPage || 'On this page',
search: I18N.search || 'Search',
searchPlaceholder: I18N.searchPlaceholder || 'Search posts…',
noResults: I18N.noResults || 'No results'
}; };
// Clipboard helper (Clipboard API with a legacy fallback). // Clipboard helper (Clipboard API with a legacy fallback).
@@ -1144,4 +1147,152 @@
}); });
})(); })();
/* --------------------------------------------------------
Task lists — turn "- [ ] / - [x]" list items into real checkboxes.
-------------------------------------------------------- */
(function () {
var content = document.querySelector('.content');
if (!content) return;
Array.prototype.forEach.call(content.querySelectorAll('li'), function (li) {
var m = li.innerHTML.match(/^\s*\[([ xX])\]\s+/);
if (!m) return;
var checked = m[1].toLowerCase() === 'x';
li.innerHTML = li.innerHTML.replace(m[0], '');
li.classList.add('task-list-item');
if (li.parentNode && li.parentNode.tagName === 'UL') {
li.parentNode.classList.add('task-list');
}
var box = document.createElement('input');
box.type = 'checkbox';
box.disabled = true;
box.checked = checked;
li.insertBefore(box, li.firstChild);
});
})();
/* --------------------------------------------------------
Search overlay — client-side fuzzy search over a JSON index of posts
(embedded in the footer). Opened by the navbar button or the "/" key.
-------------------------------------------------------- */
(function () {
var data = [];
var el = document.getElementById('blowdit-search-index');
if (el) { try { data = JSON.parse(el.textContent) || []; } catch (e) { data = []; } }
var overlay = document.createElement('div');
overlay.className = 'search-overlay';
overlay.innerHTML =
'<div class="search-box" role="dialog" aria-modal="true" aria-label="' + T.search + '">' +
'<input type="text" class="search-input" autocomplete="off" spellcheck="false" placeholder="' + T.searchPlaceholder + '" aria-label="' + T.search + '">' +
'<ul class="search-results"></ul>' +
'<div class="search-empty" hidden>' + T.noResults + '</div>' +
'</div>';
document.body.appendChild(overlay);
var input = overlay.querySelector('.search-input');
var results = overlay.querySelector('.search-results');
var empty = overlay.querySelector('.search-empty');
var active = -1;
var current = [];
function open() {
overlay.classList.add('is-open');
document.body.style.overflow = 'hidden';
input.value = '';
render([]);
setTimeout(function () { input.focus(); }, 30);
}
function close() {
overlay.classList.remove('is-open');
document.body.style.overflow = '';
}
function isOpen() { return overlay.classList.contains('is-open'); }
function score(item, q) {
var hay = (item.t + ' ' + (item.c || '') + ' ' + (item.g || []).join(' ') + ' ' + (item.d || '')).toLowerCase();
return hay.indexOf(q) !== -1;
}
function render(list) {
current = list;
active = list.length ? 0 : -1;
results.innerHTML = '';
empty.hidden = !(input.value.trim() && list.length === 0);
list.forEach(function (item, i) {
var li = document.createElement('li');
li.className = 'search-result' + (i === 0 ? ' is-active' : '');
li.innerHTML = '<a href="' + item.u + '"><span class="search-result-title"></span>' +
(item.c ? '<span class="search-result-meta"></span>' : '') + '</a>';
li.querySelector('.search-result-title').textContent = item.t;
if (item.c) li.querySelector('.search-result-meta').textContent = item.c;
results.appendChild(li);
});
}
function update() {
var q = input.value.trim().toLowerCase();
if (!q) { render([]); return; }
render(data.filter(function (item) { return score(item, q); }).slice(0, 8));
}
function move(delta) {
var items = results.querySelectorAll('.search-result');
if (!items.length) return;
items[active] && items[active].classList.remove('is-active');
active = (active + delta + items.length) % items.length;
items[active].classList.add('is-active');
items[active].scrollIntoView({ block: 'nearest' });
}
function go() {
var items = results.querySelectorAll('.search-result');
if (items[active]) { var a = items[active].querySelector('a'); if (a) window.location.href = a.href; }
}
input.addEventListener('input', update);
input.addEventListener('keydown', function (e) {
if (e.key === 'ArrowDown') { e.preventDefault(); move(1); }
else if (e.key === 'ArrowUp') { e.preventDefault(); move(-1); }
else if (e.key === 'Enter') { e.preventDefault(); go(); }
});
overlay.addEventListener('click', function (e) { if (e.target === overlay) close(); });
Array.prototype.forEach.call(document.querySelectorAll('.js-search-open'), function (b) {
b.addEventListener('click', function (e) { e.preventDefault(); open(); });
});
// Expose for the keyboard-shortcuts handler.
window.BLOWDIT_SEARCH = { open: open, close: close, isOpen: isOpen };
})();
/* --------------------------------------------------------
Keyboard shortcuts: / search · g h home · t top · Esc close.
-------------------------------------------------------- */
(function () {
var lastG = 0;
function typing(t) {
return t && (t.tagName === 'INPUT' || t.tagName === 'TEXTAREA' || t.isContentEditable);
}
document.addEventListener('keydown', function (e) {
var s = window.BLOWDIT_SEARCH;
if (e.key === 'Escape' || e.key === 'Esc') {
if (s && s.isOpen()) s.close();
return;
}
if (typing(e.target) || e.metaKey || e.ctrlKey || e.altKey) return;
if (e.key === '/') { e.preventDefault(); if (s) s.open(); return; }
if (e.key === 't' || e.key === 'T') {
var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
window.scrollTo({ top: 0, behavior: reduce ? 'auto' : 'smooth' });
return;
}
// "g" then "h" -> home
if (e.key === 'g' || e.key === 'G') { lastG = Date.now(); return; }
if ((e.key === 'h' || e.key === 'H') && Date.now() - lastG < 600) {
window.location.href = (window.BLOWDIT_HOME || '/');
}
});
})();
})(); })();
+4
View File
@@ -18,6 +18,10 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied": "Link copied", "Link copied": "Link copied",
"Related posts": "Related posts", "Related posts": "Related posts",
"Search": "Search",
"Search posts…": "Search posts…",
"No results": "No results",
"Part of a series": "Part of a series",
"Home": "Home", "Home": "Home",
"On this page": "On this page", "On this page": "On this page",
"Page not found": "Page not found", "Page not found": "Page not found",
+3 -3
View File
@@ -2,9 +2,9 @@
"author": "spleenftw", "author": "spleenftw",
"email": "", "email": "",
"website": "https://github.com/Spleenftw/blowdit", "website": "https://github.com/Spleenftw/blowdit",
"version": "1.5.0", "version": "1.6.0",
"releaseDate": "2026-06-02", "releaseDate": "2026-06-03",
"license": "MIT", "license": "MIT",
"compatible": "3.22.0", "compatible": "3.22.0",
"notes": "A Bludit theme inspired by the Blowfish Hugo theme. Five-theme swatch picker (Light/Dark/Nord/Dracula/Catppuccin), sticky ToC sidebar on articles, image lightbox with zoom, image carousel (```carousel fence), tabbed code blocks (```tabs fence), smart sidebar per page type, and clean responsive typography. v1.3.0: SEO (Open Graph, Twitter Card, JSON-LD, theme-color, cover preload), per-theme syntax highlighting (self-hosted highlight.js), copy-to-clipboard on code blocks, numbered pagination, inline-SVG icons (dropped the Bootstrap Icons webfont), removed jQuery/Bootstrap JS, deferred cached JS bundle, reading progress bar, back-to-top, randomised sidebar selection, lazy-loaded images, accessibility (skip link, ARIA, :focus-visible) and a print stylesheet. v1.4.0: canonical URL, WebSite + BreadcrumbList + author sameAs JSON-LD, og:image:alt / twitter:site+creator, cover-image aspect-ratio (CLS), heading anchor links, prev/next article nav, related posts, share buttons (X/LinkedIn/copy-link), mailto social icon, PWA web app manifest, 'updated on' date, and outbound-link hardening (noopener noreferrer). v1.5.0: callout/admonition boxes (> [!NOTE]/[!TIP]/[!WARNING]/...), code-block header bar with language label + copy button, visual breadcrumbs, custom 404 page, image figure/figcaption from the markdown title, a mobile table-of-contents drawer, and third-party resource hints." "notes": "A Bludit theme inspired by the Blowfish Hugo theme. Five-theme swatch picker (Light/Dark/Nord/Dracula/Catppuccin), sticky ToC sidebar on articles, image lightbox with zoom, image carousel (```carousel fence), tabbed code blocks (```tabs fence), smart sidebar per page type, and clean responsive typography. v1.3.0: SEO (Open Graph, Twitter Card, JSON-LD, theme-color, cover preload), per-theme syntax highlighting (self-hosted highlight.js), copy-to-clipboard on code blocks, numbered pagination, inline-SVG icons (dropped the Bootstrap Icons webfont), removed jQuery/Bootstrap JS, deferred cached JS bundle, reading progress bar, back-to-top, randomised sidebar selection, lazy-loaded images, accessibility (skip link, ARIA, :focus-visible) and a print stylesheet. v1.4.0: canonical URL, WebSite + BreadcrumbList + author sameAs JSON-LD, og:image:alt / twitter:site+creator, cover-image aspect-ratio (CLS), heading anchor links, prev/next article nav, related posts, share buttons (X/LinkedIn/copy-link), mailto social icon, PWA web app manifest, 'updated on' date, and outbound-link hardening (noopener noreferrer). v1.5.0: callout/admonition boxes (> [!NOTE]/[!TIP]/[!WARNING]/...), code-block header bar with language label + copy button, visual breadcrumbs, custom 404 page, image figure/figcaption from the markdown title, a mobile table-of-contents drawer, and third-party resource hints. v1.6.0: self-hosted Inter (no Google Fonts), client-side search overlay (\"/\" key + navbar button), keyboard shortcuts (/ , g h, t, Esc), a tabbed-code copy button, series navigation (series-* tag), and content typography (keycaps, task-list checkboxes, <mark>, external-link icon, footnote/definition-list styling)."
} }
+25
View File
@@ -18,3 +18,28 @@
</div> </div>
</div> </div>
</footer> </footer>
<?php
// Client-side search index (all published posts) for the search overlay.
// Guarded so any Pages-API difference degrades to an empty index, not an error.
try {
global $pages;
$bdSearchIndex = array();
if (isset($pages) && method_exists($pages, 'getList')) {
foreach ($pages->getList(1, 1000, true) as $bdSk) {
$bdSp = new Page($bdSk);
if ($bdSp->isStatic()) { continue; } // posts only
$bdSearchIndex[] = array(
't' => blowdit_plain($bdSp->title()),
'u' => $bdSp->permalink(),
'd' => blowdit_plain($bdSp->description()),
'c' => blowdit_plain($bdSp->category()),
'g' => array_values(array_map('blowdit_plain', $bdSp->tags(true))),
);
}
}
echo '<script type="application/json" id="blowdit-search-index">'
. json_encode($bdSearchIndex, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
. '</script>';
} catch (\Throwable $e) {}
?>
+3 -6
View File
@@ -244,12 +244,9 @@
<link rel="manifest" href="<?php echo DOMAIN_THEME . 'manifest.webmanifest'; ?>"> <link rel="manifest" href="<?php echo DOMAIN_THEME . 'manifest.webmanifest'; ?>">
<link rel="apple-touch-icon" href="<?php echo DOMAIN_THEME . 'img/favicon.png'; ?>"> <link rel="apple-touch-icon" href="<?php echo DOMAIN_THEME . 'img/favicon.png'; ?>">
<!-- Inter typeface (Blowfish-like typography) — loaded non-render-blocking: <!-- Inter typeface — self-hosted (see @font-face in style.css). No third-party
fetched as print media, then flipped to all once it arrives. --> request; preload the body weight for a faster first text paint. -->
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preload" as="font" type="font/woff2" href="<?php echo DOMAIN_THEME . 'fonts/inter-400.woff2'; ?>" crossorigin>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"></noscript>
<!-- Include Bootstrap CSS file bootstrap.css --> <!-- Include Bootstrap CSS file bootstrap.css -->
<?php echo Theme::cssBootstrap(); ?> <?php echo Theme::cssBootstrap(); ?>
+1
View File
@@ -21,6 +21,7 @@ if (!function_exists('blowdit_icon')) {
'chevron-right' => '<path d="M9 18l6-6-6-6"/>', 'chevron-right' => '<path d="M9 18l6-6-6-6"/>',
'house' => '<path d="M3 10.5 12 3l9 7.5"/><path d="M5 9.5V21h14V9.5"/>', 'house' => '<path d="M3 10.5 12 3l9 7.5"/><path d="M5 9.5V21h14V9.5"/>',
'link' => '<path d="M9 17H7A5 5 0 0 1 7 7h2"/><path d="M15 7h2a5 5 0 0 1 0 10h-2"/><path d="M8 12h8"/>', 'link' => '<path d="M9 17H7A5 5 0 0 1 7 7h2"/><path d="M15 7h2a5 5 0 0 1 0 10h-2"/><path d="M8 12h8"/>',
'search' => '<circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/>',
'share' => '<circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><path d="M8.6 13.5l6.8 4M15.4 6.5l-6.8 4"/>', 'share' => '<circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><path d="M8.6 13.5l6.8 4M15.4 6.5l-6.8 4"/>',
// --- Theme picker (mirror in blowdit.js) --- // --- Theme picker (mirror in blowdit.js) ---
'sun' => '<circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/>', 'sun' => '<circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/>',
+7
View File
@@ -59,6 +59,13 @@
<?php endif; ?> <?php endif; ?>
<?php endif; ?> <?php endif; ?>
<!-- Search (opens the overlay; also bound to the "/" key) -->
<li class="nav-item ml-md-2 mt-2 mt-md-0">
<button type="button" class="theme-toggle js-search-open" aria-label="<?php echo $L->get('Search'); ?>" title="<?php echo $L->get('Search'); ?> (/)">
<?php echo blowdit_icon('search'); ?>
</button>
</li>
<!-- Theme picker --> <!-- Theme picker -->
<li class="nav-item ml-md-2 mt-2 mt-md-0 theme-picker-wrap"> <li class="nav-item ml-md-2 mt-2 mt-md-0 theme-picker-wrap">
<button type="button" id="theme-toggle" class="theme-toggle" aria-label="<?php echo $L->get('Toggle theme') ?>" title="<?php echo $L->get('Toggle theme') ?>" aria-haspopup="true" aria-expanded="false"> <button type="button" id="theme-toggle" class="theme-toggle" aria-label="<?php echo $L->get('Toggle theme') ?>" title="<?php echo $L->get('Toggle theme') ?>" aria-haspopup="true" aria-expanded="false">
+37
View File
@@ -54,6 +54,43 @@
</div> </div>
<?php endif ?> <?php endif ?>
<!-- Series box: posts sharing a tag whose key starts with "series-"
(e.g. tag "Series: Homelab" -> key "series-homelab"), ordered oldest-first. -->
<?php if (!$page->isStatic() && !$url->notFound()) :
$bdSeriesTag = ''; $bdSeriesName = '';
foreach ($page->tags(true) as $bdTk => $bdTn) {
if (preg_match('/^series[-_]/i', $bdTk)) { $bdSeriesTag = $bdTk; $bdSeriesName = $bdTn; break; }
}
$bdSeriesPosts = array();
if ($bdSeriesTag) {
try {
global $pages;
if (isset($pages) && method_exists($pages, 'getList')) {
foreach ($pages->getList(1, 1000, true) as $bdSk) {
$bdSp = new Page($bdSk);
if (in_array($bdSeriesTag, array_keys($bdSp->tags(true)), true)) { $bdSeriesPosts[] = $bdSp; }
}
usort($bdSeriesPosts, function ($a, $b) { return strcmp($a->getValue('date'), $b->getValue('date')); });
}
} catch (\Throwable $e) { $bdSeriesPosts = array(); }
}
$bdSeriesLabel = trim(preg_replace('/^series\s*[:\-_]?\s*/i', '', blowdit_plain($bdSeriesName)));
?>
<?php if (count($bdSeriesPosts) > 1) : ?>
<aside class="series-box">
<div class="series-box-title"><?php echo blowdit_icon('folder'); ?><span><?php echo $L->get('Part of a series'); ?><?php echo $bdSeriesLabel !== '' ? ': ' . htmlspecialchars($bdSeriesLabel, ENT_QUOTES, 'UTF-8') : ''; ?></span></div>
<ol class="series-list">
<?php foreach ($bdSeriesPosts as $bdSp) : $bdIsCur = ($bdSp->key() === $page->key()); ?>
<li class="series-item<?php echo $bdIsCur ? ' is-current' : ''; ?>">
<?php if ($bdIsCur) : ?><span><?php echo blowdit_text($bdSp->title()); ?></span>
<?php else : ?><a href="<?php echo $bdSp->permalink(); ?>"><?php echo blowdit_text($bdSp->title()); ?></a><?php endif ?>
</li>
<?php endforeach ?>
</ol>
</aside>
<?php endif ?>
<?php endif ?>
<!-- Full content --> <!-- Full content -->
<div class="content"> <div class="content">
<?php <?php