apropos: dynamic TOC via extractToc, HeadingPermalinkExtension, debug logging for TOC diagnosis

This commit is contained in:
Pontoporeia
2026-07-10 15:07:14 +02:00
parent 2461f526bf
commit 018d699ebd
6 changed files with 52 additions and 8 deletions
+2 -1
View File
@@ -68,7 +68,8 @@
background: var(--bg-tertiary);
position: relative;
margin: 0; /* reset <figure> default margin */
border-radius: 7px 7px 0 0;
/* border-radius: 7px 7px 0 0; */
border-radius: var(--radius);
}
.home-body figure img,
+21 -2
View File
@@ -3,8 +3,10 @@
require_once APP_ROOT . '/src/Database.php';
require_once APP_ROOT . '/src/ErrorHandler.php';
require_once APP_ROOT . '/src/EmailObfuscator.php';
require_once APP_ROOT . '/src/MarkdownHelper.php';
use League\CommonMark\CommonMarkConverter;
use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
class AboutController
{
@@ -21,8 +23,10 @@ class AboutController
$db = Database::getInstance();
$aboutPage = $db->getPage('about');
$rawContent = $aboutPage ? $aboutPage['content'] : '';
error_log('[TOC-DEBUG] Apropos: dbPage found=' . ($aboutPage ? 'yes' : 'NO') . ' content_len=' . strlen($rawContent));
if (empty(trim($rawContent)) || trim($rawContent) === 'Contenu à venir') {
$rawContent = $this->defaultContent;
error_log('[TOC-DEBUG] Apropos: using defaultContent instead');
}
$contacts = $db->getAproposContent('contacts');
$contacts = is_array($contacts) && !empty($contacts) ? $contacts : null;
@@ -44,13 +48,28 @@ class AboutController
$rawContent = $this->defaultContent;
$contacts = null;
$sidebarLinks = [];
error_log('[TOC-DEBUG] Apropos: EXCEPTION ' . $e->getMessage());
}
$converter = new CommonMarkConverter(['html_input' => 'strip']);
$converter = new CommonMarkConverter([
'html_input' => 'strip',
'heading_permalink' => [
'apply_id_to_heading' => true,
'id_prefix' => '',
'insert' => 'before',
'aria_hidden' => true,
],
]);
$converter->getEnvironment()->addExtension(new HeadingPermalinkExtension());
$html = EmailObfuscator::obfuscateHtml($converter->convert($rawContent)->getContent());
$tocItems = MarkdownHelper::extractToc($rawContent);
error_log('[TOC-DEBUG] Apropos: extractToc returned ' . count($tocItems) . ' items');
return [
'currentNav' => 'apropos',
'aboutHtml' => EmailObfuscator::obfuscateHtml($converter->convert($rawContent)->getContent()),
'aboutHtml' => $html,
'tocItems' => $tocItems,
'contacts' => $contacts,
'sidebarLinks' => $sidebarLinks,
'pageTitle' => 'À Propos XAMXAM',
+4
View File
@@ -22,10 +22,12 @@ class CharteController
$dbPage = $db->getPage('charte');
$content = $dbPage ? $dbPage['content'] : '';
$pageTitle = $dbPage ? $dbPage['title'] : 'Charte';
error_log('[TOC-DEBUG] Charte: dbPage found=' . ($dbPage ? 'yes' : 'NO') . ' content_len=' . strlen($content));
} catch (Exception $e) {
ErrorHandler::log('charte_page', $e);
$content = '';
$pageTitle = 'Charte';
error_log('[TOC-DEBUG] Charte: EXCEPTION ' . $e->getMessage());
}
$converter = new CommonMarkConverter([
@@ -40,7 +42,9 @@ class CharteController
$converter->getEnvironment()->addExtension(new HeadingPermalinkExtension());
$html = EmailObfuscator::obfuscateHtml($converter->convert($content)->getContent());
error_log('[TOC-DEBUG] Charte: calling extractToc with content_len=' . strlen($content));
$tocItems = MarkdownHelper::extractToc($content);
error_log('[TOC-DEBUG] Charte: extractToc returned ' . count($tocItems) . ' items');
return [
'content' => $content,
@@ -22,10 +22,12 @@ class LicenceController
$dbPage = $db->getPage('licenses');
$content = $dbPage ? $dbPage['content'] : '';
$pageTitle = $dbPage ? $dbPage['title'] : 'Licences';
error_log('[TOC-DEBUG] Licence: dbPage found=' . ($dbPage ? 'yes' : 'NO') . ' content_len=' . strlen($content));
} catch (Exception $e) {
ErrorHandler::log('licence_page', $e);
$content = '';
$pageTitle = 'Licences';
error_log('[TOC-DEBUG] Licence: EXCEPTION ' . $e->getMessage());
}
$converter = new CommonMarkConverter([
@@ -40,7 +42,9 @@ class LicenceController
$converter->getEnvironment()->addExtension(new HeadingPermalinkExtension());
$html = EmailObfuscator::obfuscateHtml($converter->convert($content)->getContent());
error_log('[TOC-DEBUG] Licence: calling extractToc with content_len=' . strlen($content));
$tocItems = MarkdownHelper::extractToc($content);
error_log('[TOC-DEBUG] Licence: extractToc returned ' . count($tocItems) . ' items');
return [
'content' => $content,
+16
View File
@@ -18,6 +18,20 @@ class MarkdownHelper
$items = [];
$lines = explode("\n", $content);
// ── DEBUG: temporary TOC diagnostics ──────────────────────────
error_log('[TOC-DEBUG] content length: ' . strlen($content));
error_log('[TOC-DEBUG] line count: ' . count($lines));
foreach (array_slice($lines, 0, 8) as $i => $line) {
if ($line === '') {
error_log('[TOC-DEBUG] line[' . $i . '] (empty)');
} else {
$hex = bin2hex($line);
$preview = mb_substr($line, 0, 60);
error_log('[TOC-DEBUG] line[' . $i . '] hex=' . $hex . ' raw=' . $preview);
}
}
// ── END DEBUG ─────────────────────────────────────────────────
// Use CommonMark's own SlugNormalizer so TOC links match the rendered heading IDs exactly.
$normalizer = new \League\CommonMark\Normalizer\SlugNormalizer();
@@ -27,8 +41,10 @@ class MarkdownHelper
$label = trim($m[2]);
$id = $normalizer->normalize($label);
$items[] = ['label' => $label, 'href' => '#' . $id, 'level' => $level];
error_log('[TOC-DEBUG] MATCH: h' . $level . ' "' . $label . '" -> #' . $id);
}
}
error_log('[TOC-DEBUG] total items found: ' . count($items));
return $items;
}
}
+5 -5
View File
@@ -34,14 +34,13 @@ function renderEntries(array $entries): string
<main class="page-content" id="main-content">
<!-- Table of contents: collapsible on mobile, force-open on desktop -->
<?php if (!empty($tocItems)): ?>
<details class="toc">
<summary><?= icon('caret-down', 0, 'toc-caret') ?> PARTIES</summary>
<ul class="toc-list">
<li><a href="#apropos-intro">À propos</a></li>
<?php if (!empty($contacts)): ?>
<li><a href="#apropos-contacts">Contacts</a></li>
<?php endif; ?>
<li><a href="#apropos-credits">Crédits</a></li>
<?php foreach ($tocItems as $item): ?>
<li class="toc-level-<?= $item['level'] ?? 1 ?>"><a href="<?= htmlspecialchars($item['href']) ?>"><?= htmlspecialchars($item['label']) ?></a></li>
<?php endforeach; ?>
</ul>
<?php if (!empty($sidebarLinks)): ?>
<?php foreach ($sidebarLinks as $sl): ?>
@@ -53,6 +52,7 @@ function renderEntries(array $entries): string
<?php endforeach; ?>
<?php endif; ?>
</details>
<?php endif; ?>
<article>
<!-- Intro text from DB -->