hexojs / hexo-renderer-markdown-it

Markdown-it is a Markdown parser, done right. A faster and CommonMark compliant alternative for Hexo.
MIT License
343 stars 60 forks source link

Add TOC support #55

Closed noraj closed 3 years ago

noraj commented 6 years ago

Is that possible to add support for TOC (table of content) ?

The most suitable plugin for that seems to be https://github.com/Oktavilla/markdown-it-table-of-contents

My POV is that it is better to add a TOC on demand via a [[toc]] tag for example than generalize it and automatically add a toc to every post like https://www.npmjs.com/package/markdown-it-toc-and-anchor is doing.

PS : you can take a look at this issue too https://github.com/CHENXCHEN/hexo-renderer-markdown-it-plus/issues/13

noraj commented 6 years ago

Can this work just by doing

markdown:
  plugins:
    - markdown-it-table-of-contents

and npm i markdown-it-table-of-contents --save ?

Update: I tried and the answer is no.

oupala commented 6 years ago

I'd like to see this feature available!

curbengh commented 4 years ago

Alternatively, you could enable anchor links,

markdown:
  anchor:
    level: 2

Then in your theme layout, look for the following line in _partial/article.ejs file,

    <div class="article-entry" itemprop="articleBody">
      <%- post.content %>
    </div>

then add the built-in toc() helper:

    <div class="article-entry" itemprop="articleBody">
      <%- toc(post.content, {list_number: false}) %>
      <%- post.content %>
    </div>

Some themes have built-in support of toc(). Let me know if you need help, just tell me which theme you're using.

oupala commented 4 years ago

Thanks a lot for this suggestion @curbengh, and for proposing your help.

I'm using the theme bootstrap blog and anchors are already enabled as you mentioned it in your comment.

My problem is that I only want to enable table of content for long posts, the ones with many titles. For most of my blog post, a toc is useless.

That's why I would be free to enable table of content - or not - by adding a [[toc]] tag or not.

curbengh commented 4 years ago

My apology, previously I didn't fully understand this feature request. It is about on-demand toc.

If using the approach of my previous comment, toc can be toggled through front-matter,

foo.md
---
title: foo
toc: true
---

then in the theme layout,

    <div class="article-entry" itemprop="articleBody">
      <% if (post.toc) { %>
        <%- toc(post.content, {list_number: false}) %>
      <% } %>
      <%- post.content %>
    </div>

Custom plugin markdown-it-table-of-contents should work, have you tried installing the master branch?

package.json
-  "hexo-renderer-markdown-it": "^3.4.1",
+  "hexo-renderer-markdown-it": "hexojs/hexo-renderer-markdown-it",

Another approach is {% toc %} tag (as suggested by OP) which will work regardless of markdown renderer. It's being worked on https://github.com/hexojs/hexo-util/issues/136 https://github.com/hexojs/hexo-util/pull/137.

oupala commented 4 years ago

The solution proposed by @curbengh is working, but it requires a specific theme that manages the table of content, and a specific markdown renderer.

In addition, when you're using Automatic Headline ID's feature (see this issue), the added character is added to the table of content.

Here is the result:

title ¶ subtitle ¶ another subtitle

The ¶ should not appear in the table of content as it is not part of the title. It is just a link to ease the sharing of particular parts of the text.

curbengh commented 4 years ago

The ¶ should not appear in the table of content as it is not part of the title. It is just a link to ease the sharing of particular parts of the text.

That's currently the default option (<=3.4.1).

In v4 onwards (https://github.com/hexojs/hexo-renderer-markdown-it/pull/91 to be released soon), the default will no longer add , to be consistent with hexo-renderer-marked. (Ref: https://github.com/hexojs/hexo-renderer-markdown-it/pull/90 https://github.com/hexojs/hexo-renderer-markdown-it/pull/92)

For now, to disable ,

markdown:
  anchors:
    level: 2
    collisionSuffix: ''
curbengh commented 3 years ago

markdown-it-table-of-contents doesn't work by default because it defaults to first and second levels only, plus the slugify function is different.

Ever since https://github.com/hexojs/hexo-renderer-markdown-it/pull/121 (to be released in v5.0.0, it's now possible to specify function in plugin option (as requested by https://github.com/hexojs/hexo-renderer-markdown-it/issues/58 https://github.com/hexojs/hexo-renderer-markdown-it/issues/85):

const { slugize } = require('hexo-util');
const opts = hexo.config.markdown.anchors
const mdSlugize = (str) => {
  return slugize(str, { transform: opts.case, ...opts })
}

hexo.extend.filter.register('markdown-it:renderer', function(md) {
  md.use(require('markdown-it-table-of-contents'), {
    includeLevel: [2,3,4],
    slugify: mdSlugize
  })
});

Save the code above in a .js file in scripts/ folder.