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