'a','â' => 'a','ä' => 'a','á' => 'a','é' => 'e','è' => 'e','ê' => 'e','ë' => 'e', 'î' => 'i','ï' => 'i','í' => 'i','ô' => 'o','ö' => 'o','ó' => 'o','ù' => 'u','û' => 'u', 'ü' => 'u','ú' => 'u','ç' => 'c','ñ' => 'n','æ' => 'ae','œ' => 'oe', ]; $_tocItems = []; $_tocSeen = []; // Le titre H1 est déjà affiché par le template ; on le retire du rendu. $_rawForRender = preg_replace('/^\s*# [^\n]*\n*/u', '', $rawContent); $_renderedContent = preg_replace_callback( '/<(h[23])>(.+?)<\/h[23]>/i', function ($m) use (&$_tocItems, &$_tocSeen, $_accentMap) { $tag = $m[1]; $inner = $m[2]; $level = (int) substr($tag, 1); $plain = strip_tags($inner); $slug = trim(preg_replace( '/[^a-z0-9]+/', '-', mb_strtolower(strtr($plain, $_accentMap), 'UTF-8') ), '-') ?: 'section'; if (isset($_tocSeen[$slug])) { $_tocSeen[$slug]++; $id = $slug . '-' . $_tocSeen[$slug]; } else { $_tocSeen[$slug] = 0; $id = $slug; } $_tocItems[] = ['level' => $level, 'text' => $plain, 'id' => $id]; return "<{$tag} id=\"" . htmlspecialchars($id) . "\">{$inner}{$tag}>"; }, $Parsedown->text($_rawForRender) ); $_renderedContent = typographieHtml($_renderedContent ?? ''); ob_start(); $coverFile = $article['cover'] ?? ''; $ogImage = $coverFile !== '' ? url('file?uuid=' . rawurlencode($article['uuid']) . '&name=' . rawurlencode($coverFile)) : null; $category = trim((string)($article['category'] ?? '')); $gradient = coverGradient($category !== '' ? $category : $article['uuid'], $allCats ?? []); // Pièces jointes (hors fichiers intégrés, thumbs et cover) $attachments = []; if ($files) { $referenced = []; preg_match_all('/\(\/file\?uuid=[^&]+&name=([^)]+)\)/', $rawContent, $m); foreach ($m[1] as $encodedName) { $referenced[rawurldecode($encodedName)] = true; } $attachments = array_values(array_filter( $files, static fn ($f) => !isset($referenced[$f['name']]) && !str_starts_with($f['name'], '_thumb_') && $f['name'] !== $coverFile )); } $externalLinks = $article['external_links'] ?? []; ?>