Skip to content

Commit

Permalink
create different levels of TOC
Browse files Browse the repository at this point in the history
  • Loading branch information
shawnthompson committed Jul 11, 2024
1 parent f9cec1e commit 5a282b7
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 37 deletions.
59 changes: 55 additions & 4 deletions .eleventy.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,56 @@ module.exports = function (eleventyConfig) {

eleventyConfig.setLibrary("md", md);

eleventyConfig.addShortcode('extractHeadings', function (content, tocType) {
const tokens = md.parse(content, {});
const levels = tocType === 'tocSimple' ? 1 : 2; // tocSimple only includes level 2 headings
const validTags = Array.from({ length: levels + 1 }, (_, i) => `h${i + 2}`);
const headings = tokens.filter(token =>
validTags.includes(token.tag) && token.type === 'heading_open'
).map(token => {
const level = token.tag;
const rawText = tokens[tokens.indexOf(token) + 1].content;
const text = stripHtml(rawText).result; // Strip HTML tags from the heading text
const id = slugify(text, { lower: true, strict: true, locale: 'fr' });
return { level, text, id };
});

// Create TOC HTML
let tocHTML = '<aside><h2>{{ onThisPage[locale].heading }}</h2><ul>';
const levelsStack = [];

headings.forEach(heading => {
const levelIndex = parseInt(heading.level.substring(1)) - 1;

while (levelsStack.length && levelsStack[levelsStack.length - 1] > levelIndex) {
tocHTML += '</ul></li>';
levelsStack.pop();
}

if (levelsStack.length && levelsStack[levelsStack.length - 1] === levelIndex) {
tocHTML += '</li>';
}

if (!levelsStack.length || levelsStack[levelsStack.length - 1] < levelIndex) {
tocHTML += '<ul>';
levelsStack.push(levelIndex);
}

tocHTML += `<li><a href="#${heading.id}">${heading.text}</a>`;
});

while (levelsStack.length) {
tocHTML += '</ul></li>';
levelsStack.pop();
}

tocHTML += '</ul></aside>';

return tocHTML;
});

const slugifyFilter = eleventyConfig.javascriptFunctions.slugify;

eleventyConfig.addFilter("stripTagsSlugify", (str) => {
if (!str) return;
return slugify(stripHtml(str).result, { lower: true, strict: true, locale: 'fr' });
Expand Down Expand Up @@ -56,17 +106,18 @@ module.exports = function (eleventyConfig) {
eleventyConfig.addPassthroughCopy({ "./src/_images": "img" });
eleventyConfig.addPassthroughCopy({ "./src/CNAME": "CNAME" });

// Add headings to each page's data
eleventyConfig.addCollection("allHeadings", function (collectionApi) {
return collectionApi.getAll().map(item => {
if (item.data.toc) {
if (item.data.toc || item.data.tocSimple) {
const tokens = md.parse(item.template.frontMatter.content, {});
const validTags = ['h2', 'h3']; // Only h2 and h3 headings
const levels = item.data.tocSimple ? 1 : 2; // tocSimple only includes level 2 headings
const validTags = Array.from({ length: levels + 1 }, (_, i) => `h${i + 2}`);
const headings = tokens.filter(token =>
validTags.includes(token.tag) && token.type === 'heading_open'
).map(token => {
const level = token.tag;
const text = tokens[tokens.indexOf(token) + 1].content;
const rawText = tokens[tokens.indexOf(token) + 1].content;
const text = stripHtml(rawText).result; // Strip HTML tags from the heading text
const id = slugify(text, { lower: true, strict: true, locale: 'fr' });
return { level, text, id };
});
Expand Down
50 changes: 43 additions & 7 deletions .github/DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,18 +188,36 @@ To trigger the `internalLinks` variable in the front matter, you have to set its

If you don't include the `internalLinks` variable in the front matter of your Markdown file, then the "internalLinks" message will not be included in the alert message by default. This is because the `internalLinks` variable is used to control whether or not the "internalLinks" message is included, and if it is not specified in the front matter, it will default to `false`.

## On this page / Table of content (TOC)
## On this page / Table of Contents (TOC)

We have implemented an automatic generation of a "On this page" section for pages that have `toc: true` set in their front matter. This list includes headings at levels 2 and 3.
We have implemented an automatic generation of a "On this page" section for pages that have `toc: true` or `tocSimple: true` set in their front matter.

To enable the TOC on a specific page, add the following to the front matter of the Markdown file:
### Full TOC (`toc: true`)

``` yaml
If `toc: true` is set in the front matter, the table of contents will include headings at levels 2 and 3. This is useful for providing a detailed overview of the page content.

To enable the full TOC on a specific page, add the following to the front matter of the Markdown file:

```yaml
---
toc: true
---
```

#### Simple TOC (tocSimple: true)

If `tocSimple: true` is set in the front matter, the table of contents will only include headings at level 2. This is useful for a more concise overview without listing subheadings.

To enable the simple TOC on a specific page, add the following to the front matter of the Markdown file:

```yaml
---
tocSimple: true
---
```

This configuration will automatically generate a "On this page" section at the beginning of the content, listing the specified headings based on the toc or tocSimple setting.

## markdown-link-checker

### How to run markdown-link-checker to check for broken or dead links on the console
Expand Down Expand Up @@ -400,16 +418,34 @@ Si vous n'incluez pas la variable `internalLinks` dans l'avant-propos de votre f

## Sur cette page / Table des matières (TOC)

Nous avons mis en place une génération automatique d'une section "Sur cette page" pour les pages qui ont `toc: true` défini dans leur front matter. Cette liste inclut les titres des niveaux 2 et 3.
Nous avons mis en place une génération automatique d'une section "Sur cette page" pour les pages qui ont `toc: true` ou `tocSimple: true` définies dans leur front matter.

Pour activer la TOC sur une page spécifique, ajoutez ce qui suit au front matter du fichier Markdown :
### TOC complet (`toc: true`)

``` yaml
Si `toc: true` est défini dans le front matter, la table des matières inclura les titres aux niveaux 2 et 3. Cela est utile pour fournir un aperçu détaillé du contenu de la page.

Pour activer le TOC complet sur une page spécifique, ajoutez ce qui suit dans le front matter du fichier Markdown :

```yaml
---
toc: true
---
```

### TOC simple (`tocSimple: true`)

Si `tocSimple: true` est défini dans le front matter, la table des matières n'inclura que les titres de niveau 2. Cela est utile pour un aperçu plus concis sans lister les sous-titres.

Pour activer le TOC simple sur une page spécifique, ajoutez ce qui suit dans le front matter du fichier Markdown :

```yaml
---
tocSimple: true
---
```

Cette configuration générera automatiquement une section "Sur cette page" au début du contenu, listant les titres spécifiés en fonction du paramètre `toc` ou `tocSimple`.

## markdown-link-checker

### Comment exécuter markdown-link-checker pour vérifier les liens brisés ou morts sur la console ?
Expand Down
7 changes: 3 additions & 4 deletions src/_includes/layouts/base.njk
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,9 @@
{% include "partials/office365Notice.njk" %}
{% endif %}


{% include "partials/onThisPage.njk" %}


{% if toc or tocSimple %}
{% include "partials/onThisPage.njk" %}
{% endif %}

{{ content | safe }}
{% if officeTOC === true %}
Expand Down
26 changes: 4 additions & 22 deletions src/_includes/partials/onThisPage.njk
Original file line number Diff line number Diff line change
@@ -1,34 +1,16 @@
{#
The TOC generation is handled by a custom Nunjucks shortcode and rendered in the base.njk layout. Here's a brief overview of the implementation:
eleventy.js Configuration:
We use markdown-it with markdown-it-anchor and markdown-it-attrs to parse Markdown content and generate anchor links.
A custom shortcode extractHeadings is created to extract and format the headings from the Markdown content.
base.njk Layout:
The layout includes the toc.njk partial, which renders the TOC if toc is enabled in the front matter.
toc.njk Partial:
This partial handles the rendering of the TOC. It checks if toc is enabled and then generates the TOC based on the extracted headings.
#}

{% if toc %}
{% if headings %}
<aside>
<h2>{{ onThisPage[locale].heading }}</h2>
<ul>
{% set current_level = 2 %}
{% for heading in headings %}
{% if heading.level == 'h2' %}
{% if loop.index != 1 %}</ul>
</li>{% endif %}
{% if current_level > 2 %}</ul>
</li>{% else %}{% if loop.index != 1 %}</li>{% endif %}{% endif %}
<li><a href="#{{ heading.id }}">{{ heading.text }}</a>
{% set current_level = 2 %}
{% if loop.last %}</li>{% endif %}
{% elseif heading.level == 'h3' %}
{% elseif heading.level == 'h3' and not tocSimple %}
{% if current_level < 3 %}
<ul>
{% set current_level = 3 %}
Expand Down

0 comments on commit 5a282b7

Please sign in to comment.