Last time, we have successfully displayed a Markdown article on the website and automatically generated a catalogue

Now, we wanted to generate a more practical fixed sidebar navigation.

Solution 1:

We can use ‘markdown-navbar’. However, this plugin has requirements for the format of markdown files, if the format is not standardised, the recognition will be wrong, resulting in the content of the article or notes are also identified as the title.

yarn add markdown-navbar # or `npm i markdown-navbar --save` 

Here is a simple demo. Detailed usage please read this.

import React from 'react';
import ReactDOM from 'react-dom';
// One third-part component for render markdown documentation
import ReactMarkdown from 'react-markdown';
import MarkdownNavbar from 'markdown-navbar';
// The default style of markdown-navbar should be imported additionally
import 'markdown-navbar/dist/navbar.css';

const article = `# Markdown-Navbar Demo

## Chicken Chicken

Chicken Chicken Chicken Chicken Chicken.`;

function App() {
  return (
    <div className="App">
      <div className="article">
        <ReactMarkdown source={article} />
      </div>
      <div className="navigation">
        <MarkdownNavbar source={article} />
      </div>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('root')); 

Method 2:

The next step is a manual implementation. In this article, we implement the navigation with Antd‘s component Anchor, or you can choose your favourite components library.

First, iterated through all the contents of the markdown file, taking out all the h2-h4 tags and the text in the tags for the presentation of the catalogue.

const [titles, setTitles] = useState([])
  
const addAnchor = () => {
    const ele = document.getElementsByClassName('markdown-body')[0];
    let eid = 0;
    let titles = [];
    for (const e of ele.childNodes) {
        if (e.nodeName === 'H2' || e.nodeName === 'H3' || e.nodeName === 'H4') {
            let title = {
                type: e.nodeName,
                id: eid,
                name: e.innerText,
            };
            titles.push(title);
            eid++;
        }
    }
    setTitles(titles);
} 
import { Anchor } from 'antd';

const { Link } = Anchor;

const NavList = ({titles}) => {
    return(
        <>
            <Anchor>
                titles.map((t) => {
                    return(
                        <Link
                            href={`#${t.id}`}
                            title={t.name}
                            className={`title-${t.type}`}
                            key={t.id}
                        />
                    );
                })
            </Anchor>
        </>
    )
} 

Edit the CSS style, implementing indentations:

.ant-anchor-link .title-H2 {
    font-size: 16px;
}

.ant-anchor-link .title-H3 {
    font-size: 14px;
    padding-left: 16px;
}

.ant-anchor-link .title-H4 {
    font-size: 14px;
    padding-left: 32px;
} 

We can also modify the onClick parameter to optimise the jump effect.

  const handleClickFun = (e, link) => {
        e.preventDefault();
        if (link.href) {
            let element = document.getElementById(link.href);
            element && element.scrollIntoView({ block: 'start', behavior: 'smooth' });
        }
    } 

0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *