Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How can I extract TableOfContents of each post and set this component in markdown file ? #24469

Closed
kinnikumegane opened this issue May 26, 2020 · 4 comments
Labels
type: question or discussion Issue discussing or asking a question about Gatsby

Comments

@kinnikumegane
Copy link

kinnikumegane commented May 26, 2020

Hello all,

I would like to show table of contents of each post in each post, by using Component in markdown file.
However, I can not extract specific "table of contents" for each post.

Can anybody support me to get the corresponding "table of contents" for each post ?

Current Result

In a post, I could display "table of contents", but this is the "table of contents" of 1st set under allMarkdownRemark/edges/node, and not the one from the post, which I would like to get the "table of contents" from.

Post
sorry that it's Japanese. Basically, the blue highlighted characters are the list from table of contents.

Screen Shot 2020-05-26 at 9 48 56 AM

Graphql
Screen Shot 2020-05-26 at 9 31 16 AM

What I would like to achieve

In this post example, I would like to show the below "table of contents" as this is the one which is the table of content of the post that I display.

"tableOfContents": "<ul>\n<li><a href=\"/posts/transformgatsbytowordpresslike5/#blog-list-templatejsx%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%E3%80%82\">blog-list-template.jsxを追加する。</a></li>\n<li><a href=\"/posts/transformgatsbytowordpresslike5/#gatsby-nodejs%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B%E3%80%82\">gatsby-node.jsを変更する。</a></li>\n<li>\n<p><a href=\"/posts/transformgatsbytowordpresslike5/#%E3%80%8C%E6%96%B0%E3%81%97%E3%81%84%E8%A8%98%E4%BA%8B%E3%80%8D%E3%80%81%E3%80%8C%E5%8F%A4%E3%81%84%E8%A8%98%E4%BA%8B%E3%80%8D%E3%81%AE%E3%83%AA%E3%83%B3%E3%82%AF%E8%A8%AD%E5%AE%9A\">「新しい記事」、「古い記事」のリンク設定</a></p>\n<ul>\n<li><a href=\"/posts/transformgatsbytowordpresslike5/#%E3%81%BE%E3%81%A8%E3%82%81\">まとめ</a></li>\n</ul>\n</li>\n</ul>"

Screen Shot 2020-05-26 at 9 48 45 AM

What I have done so far

  1. in src/templates/post-template.jsx, I added tableOfContents in graphql
  2. I created TableOfContents component under `src/components/TableOfContents, and use StaticQuery to get tableOfContents
  3. I imported TableOfContents component in src/components/PostTemplateDetails/index.jsx, and use renderAst to make it possible to be used in markdown file
  4. I embedded <tableofcontents></tableofcontents> in markdown file

Here are my codes

/src/templates/post-templates.jsx

import React from 'react'
import Helmet from 'react-helmet'
import { graphql } from 'gatsby'
import Layout from '../components/Layout'
import PostTemplateDetails from '../components/PostTemplateDetails'

class PostTemplate extends React.Component {
  render() {
    const { title, subtitle } = this.props.data.site.siteMetadata
    const post = this.props.data.markdownRemark
    const { title: postTitle, description: postDescription } = post.frontmatter
    const description = postDescription !== null ? postDescription : subtitle

    return (
      <Layout>
        <div>
          <Helmet>
            <title>{`${postTitle} - ${title}`}</title>
            <meta name="description" content={description} />
          </Helmet>
          <PostTemplateDetails {...this.props} />
          {/* kinniku added Sidebar 
          <Sidebar {...this.props} /> */}
        </div>
      </Layout>
    )
  }
}

export default PostTemplate

export const pageQuery = graphql`
  query PostBySlug($slug: String!) {
    site {
      siteMetadata {
        title
        subtitle
        copyright
        menu {
          label
          path
        }
        author {
          name
          twitter
        }
        disqusShortname
        url
      }
    }
    markdownRemark(fields: { slug: { eq: $slug } }) {
      id
      htmlAst
      fields {
        tagSlugs
        slug
      }
      tableOfContents
      frontmatter {
        title
        featuredImage {
          childImageSharp {
            sizes(maxWidth: 630) {
              ...GatsbyImageSharpSizes
            }
          }
        }
        tags
        date
        path
        description
      }
    }
  }
`

/src/components/TableOfContents/index.jsx

import React from 'react'
import { StaticQuery, graphql } from 'gatsby'

export default function TableOfContents() {
    return (
        <StaticQuery
            query={graphql`
                query MyQuery {
                    markdownRemark{
                        tableOfContents
                    }
                }
            `
            }
            render={data => (
                <div dangerouslySetInnerHTML={{ __html: data.markdownRemark.tableOfContents }}></div>
            )}
        />
    );
}

/src/components/PostTemplateDetails

import React from 'react'
import { Link } from 'gatsby'
...
import TableOfContents from '../TableOfContents'
import rehypeReact from 'rehype-react'
import Adsense from '../GoogleAdsense';

const renderAst = new rehypeReact({
  createElement: React.createElement,
  components: {
    'adsense': Adsense,
    'tableofcontents': TableOfContents,
  },
}).Compiler;
...
...

/src/pages/articles/2020-05-25--TableOfContents/index.md

そして、こちら今回実装した「目次」です。

<tableofcontents></tableofcontents>

それでは、進めていきましょう。

ポイントは「Markdown fileの好きなところに目次を表示させる。」

## post-template.jsxの変更
xxx

## TableOfContents componentの作成
xxx

## Embed TableOfContents component into markdown file
xxx

thanks a lot for your support and looking forward to hearing any advise !!!

@kinnikumegane kinnikumegane added the type: question or discussion Issue discussing or asking a question about Gatsby label May 26, 2020
@gatsbot gatsbot bot added the status: triage needed Issue or pull request that need to be triaged and assigned to a reviewer label May 26, 2020
@LekoArts LekoArts removed the status: triage needed Issue or pull request that need to be triaged and assigned to a reviewer label May 26, 2020
@LekoArts
Copy link
Contributor

Thank you for opening this!

The problem with your current approach is that your /src/components/TableOfContents/index.jsx component is a staticQuery - it can't take any variables. So it'll always fetch the same markdown post and output the same ToC. You need to pull this tableOfContents information in your /src/templates/post-templates.jsx. You're already doing that. When looking at https://using-remark.gatsbyjs.org/custom-components/ I don't see how you could pass in the information to your <tableofcontents></tableofcontents> component.

I think you have two options:

  1. Don't use react-rehype and place the ToC component above your MD content
  2. Use MDX as it can take the props.data from your page query. Example: https://johno.com/mdx-table-of-contents-components-in-gatsby/

We're marking this issue as answered and closing it for now but please feel free to comment here if you would like to continue this discussion. We also recommend heading over to our communities if you have questions that are not bug reports or feature requests. We hope we managed to help and thank you for using Gatsby!

@kinnikumegane
Copy link
Author

Hi @LekoArts
thank you so much for your quick reply !!!

Because I would like to insert ToC in any place I would like to have in markdown file, I guess I need to use MDX in that case. (Option1 that you mentioned looks good, but I think I can only show the ToC component above the other content of the post if I apply this method)

As per the page below, I created TableOfContents component and try to use it in mdx file.
https://johno.com/mdx-table-of-contents-components-in-gatsby/

But, now, I got another issue that I don't see mdx post in my blog's top page.

Would you please support me how to show mdx post in blog's top page ?

What I have done is here so far;

  1. installed gatsby-plugin-mdx @mdx-js/mdx @mdx-js/react
  2. added gatsby-plugin-mdxin gatsby-config.js file
  3. editted graphwl in post-template.jsx
  4. added MDXRenderer component in post-template.jsx
  5. created TableOfContents component
  6. changed last md file to mdx file, and embedded TableOfContents component

And here is my code

/src/templates/post-template.jsx

import React from 'react'
import Helmet from 'react-helmet'
import { graphql } from 'gatsby'
import Layout from '../components/Layout'
import PostTemplateDetails from '../components/PostTemplateDetails'
import { MDXRenderer } from 'gatsby-plugin-mdx'

class PostTemplate extends React.Component {
  render() {
    const { title, subtitle } = this.props.data.site.siteMetadata
    const post = this.props.data.markdownRemark
    const { title: postTitle, description: postDescription } = post.frontmatter
    const description = postDescription !== null ? postDescription : subtitle
    
    const tableofcontents = this.props.data.allMdx.edges.node

    return (
      <Layout>
        <div>
          <Helmet>
            <title>{`${postTitle} - ${title}`}</title>
            <meta name="description" content={description} />
          </Helmet>
          <PostTemplateDetails {...this.props} />
          {/* kinniku added Sidebar 
          <Sidebar {...this.props} /> */}
          <MDXRenderer headings={tableofcontents.headings}>
            {tableofcontents.body}
          </MDXRenderer>
        </div>
      </Layout>
    )
  }
}

export default PostTemplate

export const pageQuery = graphql`
  query PostBySlug($slug: String!) {
    site {
      siteMetadata {
        title
        subtitle
        copyright
        menu {
          label
          path
        }
        author {
          name
          twitter
        }
        disqusShortname
        url
      }
    }
    markdownRemark(fields: { slug: { eq: $slug } }) {
      id
      htmlAst
      fields {
        tagSlugs
        slug
      }
      tableOfContents
      frontmatter {
        title
        featuredImage {
          childImageSharp {
            sizes(maxWidth: 630) {
              ...GatsbyImageSharpSizes
            }
          }
        }
        tags
        date
        path
        description
      }
    }

    allMdx {
      edges{
        node {
          body
          headings {
            depth
            value
          }
        }
      }
    }

  }
`

/src/components/TableOfContents/index.jsx

import React from 'react'
import Slugger from 'github-slugger'
import {Link} from 'gatsby'

const slugger = new Slugger()

class TableOfContents extends React.Component {
    render() {
      const headings = this.headings
  
      const headingBlock = (
        <ul>
            {headings
            .filter(heading => heading.depth !== 1)
            .map(heading => (
            <li key={heading.value}>
                <Link
                to={'#' + slugger.slug(heading.value)}
                >
                {heading.value}
                </Link>
            </li>
            ))}
        </ul>
      )
  
      return <div>{headingBlock}</div>
    }
  }
  
  export default TableOfContents

/src/pages/articles/2020-05-25--TableOfContents/index.mdx

import TableOfContents from '../../../../src/components/TableOfContents/index'

---
title: 【連載】Gatsbyブログのデザインをワードプレスちっくにする手順(その6)Gatsbyブログに目次をつけました。
date: "2020-05-25T07:15:00.000Z"
layout: post
draft: false
path: "/posts/transformgatsbytowordpresslike6/"
category: "Gatsby"
tags:
  - "Gatsby"
  - "Table of contents"
featuredImage: ./featured-image.jpg
description: "このブログの各記事に「目次」をつけました。これまでは、「目次っぽいもの」をつけていたのですが、親愛なる読者の方から「目次」をつけたら更に良くなる、というアドバイスを頂きましたので、この機会に実装いたしました。"
---

![table](1.jpg)  

こんにちは、筋肉めがねです。  

先日、親愛なる読者の方から、ブログに目次をつけると良いのでは、というアドバイスをいただきました。これまでの記事でも、以下のような「目次」のようなもの、を各記事のはじめの方につけてはいたのですが、この機会に、きちんとした「目次」を実装しました。

### 目次っぽいもの
* post-template.jsxの変更
* TableOfContents componentの作成
* Embed TableOfContents component into markdown file

そして、こちら今回実装した「目次」です。

<TableOfContents headings={props.headings} />

それでは、進めていきましょう。

ポイントは「Markdown fileの好きなところに目次を表示させる。」

## post-template.jsxの変更
xxx

## TableOfContents componentの作成
xxx

## Embed TableOfContents component into markdown file
xxx

Thanks again for your support !

@kinnikumegane
Copy link
Author

And, I can see that graphql picks up Table of Contents.

Screen Shot 2020-05-26 at 5 54 03 PM

@kinnikumegane
Copy link
Author

Finally, I got it work in a way that I would like to achieve, showing "Table of Contents" in markdown file wherever I want.

Here are brief explanation.

  1. install “gatsby-remark-autolink-headers” plugin
  2. install “gatsby-remark-table-of-contents” plugin
  3. embed 'toc' in markdown file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: question or discussion Issue discussing or asking a question about Gatsby
Projects
None yet
Development

No branches or pull requests

2 participants