diff --git a/app/config/sculpin_kernel.yml b/app/config/sculpin_kernel.yml index 1329f059..23eb7aa2 100644 --- a/app/config/sculpin_kernel.yml +++ b/app/config/sculpin_kernel.yml @@ -40,6 +40,13 @@ services: tags: - { name: twig.extension } + fig.website.markdown_toc_extension: + class: Fig\Website\TwigMarkdownTOCExtension + arguments: + $environment: '@League\CommonMark\EnvironmentInterface' + tags: + - { name: twig.extension } + aptoma.twig.markdown_extension: class: Aptoma\Twig\Extension\MarkdownExtension arguments: @@ -47,5 +54,10 @@ services: tags: - { name: twig.extension } + League\CommonMark\EnvironmentInterface: + factory: ['Fig\Website\CommonMarkEnvironmentFactory', 'create'] + Aptoma\Twig\Extension\MarkdownEngineInterface: factory: ['Fig\Website\CommonMarkEngineFactory', 'create'] + arguments: + $environment: '@League\CommonMark\EnvironmentInterface' diff --git a/app/lib/CommonMarkEngineFactory.php b/app/lib/CommonMarkEngineFactory.php index 5aee4508..bbd7ed7a 100644 --- a/app/lib/CommonMarkEngineFactory.php +++ b/app/lib/CommonMarkEngineFactory.php @@ -4,41 +4,14 @@ use Aptoma\Twig\Extension\MarkdownEngine\PHPLeagueCommonMarkEngine; use Aptoma\Twig\Extension\MarkdownEngineInterface; -use League\CommonMark\Block\Element\FencedCode; -use League\CommonMark\Block\Element\IndentedCode; -use League\CommonMark\Environment; -use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension; -use League\CommonMark\Extension\Table\TableExtension; +use League\CommonMark\EnvironmentInterface; use League\CommonMark\GithubFlavoredMarkdownConverter; -use Spatie\CommonMarkHighlighter\FencedCodeRenderer; -use Spatie\CommonMarkHighlighter\IndentedCodeRenderer; class CommonMarkEngineFactory { - public static function create(): MarkdownEngineInterface - { - $supportedLanguages = [ - 'php', - 'http', # inside PSR-7 - ]; - - $config = [ - 'heading_permalink' => [ - 'id_prefix' => '', - 'fragment_prefix' => '', - 'insert' => 'after', - ], - ]; - - $environment = Environment::createCommonMarkEnvironment(); - $environment->mergeConfig($config); - $environment - ->addExtension(new TableExtension()) - ->addExtension(new HeadingPermalinkExtension()) - ->addBlockRenderer(FencedCode::class, new FencedCodeRenderer($supportedLanguages)) - ->addBlockRenderer(IndentedCode::class, new IndentedCodeRenderer($supportedLanguages)) - ; - + public static function create( + EnvironmentInterface $environment, + ): MarkdownEngineInterface { return new NullSafeCommonMarkEngine( new PHPLeagueCommonMarkEngine( new GithubFlavoredMarkdownConverter([], $environment) diff --git a/app/lib/CommonMarkEnvironmentFactory.php b/app/lib/CommonMarkEnvironmentFactory.php new file mode 100644 index 00000000..cf26584b --- /dev/null +++ b/app/lib/CommonMarkEnvironmentFactory.php @@ -0,0 +1,42 @@ + [ + 'id_prefix' => '', + 'fragment_prefix' => '', + 'insert' => 'after', + ], + ]; + + $environment = Environment::createCommonMarkEnvironment(); + $environment->mergeConfig($config); + $environment + ->addExtension(new TableExtension()) + ->addExtension(new HeadingPermalinkExtension()) + ->addBlockRenderer(FencedCode::class, new FencedCodeRenderer($supportedLanguages)) + ->addBlockRenderer(IndentedCode::class, new IndentedCodeRenderer($supportedLanguages)) + ; + + return $environment; + } +} diff --git a/app/lib/TwigMarkdownTOCExtension.php b/app/lib/TwigMarkdownTOCExtension.php new file mode 100644 index 00000000..931f1829 --- /dev/null +++ b/app/lib/TwigMarkdownTOCExtension.php @@ -0,0 +1,50 @@ +docParser = new DocParser($environment); + $this->htmlRenderer = new HtmlRenderer($environment); + } + + public function getFilters() + { + return [ + new TwigFilter('markdown_toc', function(string $markdown): string { + return $this->renderTOC($markdown); + }), + ]; + } + + private function renderTOC(string $markdown): string + { + $generator = new TableOfContentsGenerator( + TableOfContentsGenerator::STYLE_ORDERED, + TableOfContentsGenerator::NORMALIZE_RELATIVE, + minHeadingLevel: 2, + maxHeadingLevel: 3, + ); + + $toc = $generator->generate($this->docParser->parse($markdown)); + + return $toc === null + ? '' + : $this->htmlRenderer->renderBlock($toc, inTightList: true); + } +} diff --git a/source/_layouts/psr.twig b/source/_layouts/psr.twig index 99071245..2ece4eb8 100644 --- a/source/_layouts/psr.twig +++ b/source/_layouts/psr.twig @@ -19,6 +19,13 @@ {% endfor %} diff --git a/source/_sass/all.scss b/source/_sass/all.scss index 98b2451e..59934597 100644 --- a/source/_sass/all.scss +++ b/source/_sass/all.scss @@ -21,6 +21,7 @@ @import "blocks/home_banner"; @import "blocks/home_features"; @import "blocks/markdown"; +@import "blocks/markdown_toc"; @import "blocks/get_involved_links"; @import "blocks/faqs"; @import "blocks/bylaws"; diff --git a/source/_sass/blocks/markdown_toc.scss b/source/_sass/blocks/markdown_toc.scss new file mode 100644 index 00000000..4493e373 --- /dev/null +++ b/source/_sass/blocks/markdown_toc.scss @@ -0,0 +1,18 @@ +.markdown.sidebar_toc { + ol { + list-style-type: none; + margin-top: 0; + + li { + margin: 0; + } + } + + & > ol { + padding-left: 15px; + } + + p { + margin-bottom: 0; + } +}