using Markdig;
using Markdig.Extensions.Yaml;
using Markdig.Syntax;
namespace Elternbeirat.Web.Services;
///
/// Liest die statischen Inhaltsseiten aus Content/seiten/*.md ein,
/// rendert sie beim Start einmalig zu HTML und hält sie im Speicher.
/// Als Singleton registriert — Inhalte liegen im Image und ändern sich zur
/// Laufzeit nicht (plan.md AE-3).
///
public sealed class SeitenService
{
private readonly IReadOnlyDictionary _seitenNachSlug;
///
/// Liest alle Markdown-Seiten aus dem Verzeichnis Content/seiten
/// unterhalb des Anwendungsstamms ein und cached sie.
///
public SeitenService(IWebHostEnvironment umgebung)
{
var pipeline = new MarkdownPipelineBuilder()
.UseYamlFrontMatter()
.Build();
var verzeichnis = Path.Combine(umgebung.ContentRootPath, "Content", "seiten");
var seiten = new Dictionary(StringComparer.OrdinalIgnoreCase);
if (Directory.Exists(verzeichnis))
{
foreach (var pfad in Directory.EnumerateFiles(verzeichnis, "*.md"))
{
var seite = Lies(pfad, pipeline);
seiten[seite.Slug] = seite;
}
}
_seitenNachSlug = seiten;
}
///
/// Liefert die Seite zum angegebenen Slug oder null, wenn es keine
/// gibt. Groß-/Kleinschreibung wird ignoriert.
///
public Seite? Finde(string slug) =>
_seitenNachSlug.GetValueOrDefault(slug);
private static Seite Lies(string pfad, MarkdownPipeline pipeline)
{
var slug = Path.GetFileNameWithoutExtension(pfad);
var quelle = File.ReadAllText(pfad);
var dokument = Markdown.Parse(quelle, pipeline);
var titel = LiesTitel(dokument, quelle) ?? slug;
var html = Markdown.ToHtml(quelle, pipeline);
return new Seite { Slug = slug, Titel = titel, InhaltHtml = html };
}
///
/// Zieht den titel:-Wert aus dem YAML-Frontmatter. Bewusst simpel
/// gehalten (eine Zeile schlüssel: wert) — für strukturiertere
/// Metadaten kommt später YamlDotNet.
///
private static string? LiesTitel(MarkdownDocument dokument, string quelle)
{
var block = dokument.Descendants().FirstOrDefault();
if (block is null)
{
return null;
}
var frontmatter = quelle.Substring(block.Span.Start, block.Span.Length);
foreach (var zeile in frontmatter.Split('\n'))
{
var getrimmt = zeile.Trim();
if (getrimmt.StartsWith("titel:", StringComparison.OrdinalIgnoreCase))
{
return getrimmt["titel:".Length..].Trim().Trim('"');
}
}
return null;
}
}