diff --git a/src/Generator/JsonGenerator.php b/src/Generator/JsonGenerator.php
index 988528a..6a087b6 100644
--- a/src/Generator/JsonGenerator.php
+++ b/src/Generator/JsonGenerator.php
@@ -20,6 +20,7 @@
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\Filesystem\Filesystem;
use SymfonyDocsBuilder\BuildConfig;
+use SymfonyDocsBuilder\Twig\TocExtension;
use function Symfony\Component\String\u;
class JsonGenerator
@@ -73,7 +74,8 @@ public function generateJson(string $masterDocument = 'index'): array
'title' => $metaEntry->getTitle(),
'parents' => $this->determineParents($parserFilename, $tocTreeHierarchy) ?: [],
'current_page_name' => $parserFilename,
- 'toc' => $this->generateToc($metaEntry, current($metaEntry->getTitles())[1]),
+ 'toc' => $toc = $this->generateToc($metaEntry, current($metaEntry->getTitles())[1]),
+ 'toc_options' => TocExtension::getOptions($toc),
'next' => $next,
'prev' => $prev,
'body' => $crawler->filter('body')->html(),
@@ -98,7 +100,7 @@ public function setOutput(SymfonyStyle $output)
$this->output = $output;
}
- private function generateToc(MetaEntry $metaEntry, ?array $titles): array
+ private function generateToc(MetaEntry $metaEntry, ?array $titles, int $level = 1): array
{
if (null === $titles) {
return [];
@@ -108,11 +110,12 @@ private function generateToc(MetaEntry $metaEntry, ?array $titles): array
foreach ($titles as $title) {
$tocTree[] = [
+ 'level' => $level,
'url' => sprintf('%s#%s', $metaEntry->getUrl(), Environment::slugify($title[0])),
'page' => u($metaEntry->getUrl())->beforeLast('.html'),
'fragment' => Environment::slugify($title[0]),
'title' => $title[0],
- 'children' => $this->generateToc($metaEntry, $title[1]),
+ 'children' => $this->generateToc($metaEntry, $title[1], $level + 1),
];
}
diff --git a/src/KernelFactory.php b/src/KernelFactory.php
index c878b6c..80230c0 100644
--- a/src/KernelFactory.php
+++ b/src/KernelFactory.php
@@ -17,6 +17,7 @@
use SymfonyDocsBuilder\Directive as SymfonyDirectives;
use SymfonyDocsBuilder\Reference as SymfonyReferences;
use SymfonyDocsBuilder\Twig\AssetsExtension;
+use SymfonyDocsBuilder\Twig\TocExtension;
use function Symfony\Component\String\u;
/**
@@ -55,6 +56,7 @@ static function (string $path) use ($parseSubPath): bool {
$twig = $configuration->getTemplateEngine();
$twig->addExtension(new AssetsExtension());
+ $twig->addExtension(new TocExtension());
return new DocsKernel(
$buildConfig,
diff --git a/src/Templates/default/html/toc.html.twig b/src/Templates/default/html/toc.html.twig
index cad7ccd..55b8737 100644
--- a/src/Templates/default/html/toc.html.twig
+++ b/src/Templates/default/html/toc.html.twig
@@ -1,5 +1,6 @@
{% apply spaceless %}
-
+ {% set toc_options = toc_options(tocItems) %}
+
{% include "toc-level.html.twig" %}
{% endapply %}
diff --git a/src/Twig/TocExtension.php b/src/Twig/TocExtension.php
new file mode 100644
index 0000000..ebea8c8
--- /dev/null
+++ b/src/Twig/TocExtension.php
@@ -0,0 +1,66 @@
+
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace SymfonyDocsBuilder\Twig;
+
+use Twig\Extension\AbstractExtension;
+use Twig\TwigFunction;
+
+class TocExtension extends AbstractExtension
+{
+ public function getFunctions(): array
+ {
+ return [
+ new TwigFunction('toc_options', [$this, 'getOptions']),
+ ];
+ }
+
+ public static function getOptions(array $toc): array
+ {
+ $flattendToc = self::flattenToc($toc);
+ $maxDepth = 0;
+ $numVisibleItems = 0;
+ foreach ($flattendToc as $tocItem) {
+ $maxDepth = max($maxDepth, $tocItem['level']);
+ $numVisibleItems++;
+ }
+
+ return [
+ 'maxDepth' => $maxDepth,
+ 'numVisibleItems' => $numVisibleItems,
+ 'size' => self::getTocSize($numVisibleItems),
+ ];
+ }
+
+ private static function flattenToc(array $toc, array &$flattenedToc = []): array
+ {
+ foreach ($toc as $item) {
+ $flattenedToc[] = $item;
+
+ if ([] !== $item['children']) {
+ self::flattenToc($item['children'], $flattenedToc);
+ }
+ }
+
+ return $flattenedToc;
+ }
+
+ private static function getTocSize(int $numVisibleItems): string
+ {
+ if ($numVisibleItems < 10) {
+ return 'md';
+ }
+
+ if ($numVisibleItems < 20) {
+ return 'lg';
+ }
+
+ return 'xl';
+ }
+}
diff --git a/tests/JsonIntegrationTest.php b/tests/JsonIntegrationTest.php
index 0ef094d..7d3d07b 100644
--- a/tests/JsonIntegrationTest.php
+++ b/tests/JsonIntegrationTest.php
@@ -74,7 +74,12 @@ public function getJsonTests()
'link' => 'crud.html',
],
'title' => 'Design',
- ]
+ 'toc_options' => [
+ 'maxDepth' => 2,
+ 'numVisibleItems' => 3,
+ 'size' => 'md'
+ ],
+ ],
];
yield 'crud' => [
diff --git a/tests/fixtures/expected/build-pdf/book.html b/tests/fixtures/expected/build-pdf/book.html
index deb53f8..a214463 100644
--- a/tests/fixtures/expected/build-pdf/book.html
+++ b/tests/fixtures/expected/build-pdf/book.html
@@ -6,7 +6,7 @@
Book
Here is a link to the main index
-
+
- First page
- Second page
diff --git a/tests/fixtures/expected/main/index.html b/tests/fixtures/expected/main/index.html
index 57fc68e..1346373 100644
--- a/tests/fixtures/expected/main/index.html
+++ b/tests/fixtures/expected/main/index.html
@@ -10,7 +10,7 @@

-
+
diff --git a/tests/fixtures/expected/toctree/index.html b/tests/fixtures/expected/toctree/index.html
index 68b4a2f..e07a28e 100644
--- a/tests/fixtures/expected/toctree/index.html
+++ b/tests/fixtures/expected/toctree/index.html
@@ -9,11 +9,11 @@
diff --git a/tests/fixtures/source/json/design.rst b/tests/fixtures/source/json/design.rst
index fd8feb9..b9a4537 100644
--- a/tests/fixtures/source/json/design.rst
+++ b/tests/fixtures/source/json/design.rst
@@ -4,10 +4,21 @@ Design
Something that should not be left to most programmers
to try to do.
+Section 1
+---------
+
The toctree below should affects the next/prev. The
-first entry is effectively ignored, as it wasa already
+first entry is effectively ignored, as it was already
included by the toctree in index.rst (which is parsed first).
+Subsection 1
+~~~~~~~~~~~~
+
+This is a subsection of the first section. That's all.
+
+Section 2
+---------
+
However, crud (which is ALSO included in the toctree in index.rst),
WILL be read here, as the "crud" in index.rst has not been read
yet (design comes first). Also, design/sub-page WILL be considered.