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

feat(v2): add TOC to blog posts #3274

Merged
merged 1 commit into from
Aug 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import React from 'react';
import Layout from '@theme/Layout';
import BlogPostItem from '@theme/BlogPostItem';
import BlogPostPaginator from '@theme/BlogPostPaginator';
import TOC from '@theme/TOC';

function BlogPostPage(props): JSX.Element {
const {content: BlogPostContents} = props;
const {frontMatter, metadata} = BlogPostContents;
const {title, description, nextItem, prevItem, editUrl} = metadata;
const {hide_table_of_contents: hideTableOfContents} = frontMatter;

return (
<Layout title={title} description={description}>
Expand Down Expand Up @@ -55,6 +57,11 @@ function BlogPostPage(props): JSX.Element {
</div>
)}
</div>
{!hideTableOfContents && BlogPostContents.rightToc && (
<div className="col col--2">
<TOC headings={BlogPostContents.rightToc} />
</div>
)}
</div>
</div>
)}
Expand Down
47 changes: 4 additions & 43 deletions packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,53 +11,12 @@ import Head from '@docusaurus/Head';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useBaseUrl from '@docusaurus/useBaseUrl';
import DocPaginator from '@theme/DocPaginator';
import useTOCHighlight from '@theme/hooks/useTOCHighlight';
import DocVersionSuggestions from '@theme/DocVersionSuggestions';
import TOC from '@theme/TOC';

import clsx from 'clsx';
import styles from './styles.module.css';

const LINK_CLASS_NAME = 'table-of-contents__link';
const ACTIVE_LINK_CLASS_NAME = 'table-of-contents__link--active';
const TOP_OFFSET = 100;

function DocTOC({headings}) {
useTOCHighlight(LINK_CLASS_NAME, ACTIVE_LINK_CLASS_NAME, TOP_OFFSET);
return (
<div className="col col--3">
<div className={styles.tableOfContents}>
<Headings headings={headings} />
</div>
</div>
);
}

/* eslint-disable jsx-a11y/control-has-associated-label */
function Headings({headings, isChild}: {headings; isChild?: boolean}) {
if (!headings.length) {
return null;
}
return (
<ul
className={
isChild ? '' : 'table-of-contents table-of-contents__left-border'
}>
{headings.map((heading) => (
<li key={heading.id}>
<a
href={`#${heading.id}`}
className={LINK_CLASS_NAME}
// Developer provided the HTML, so assume it's safe.
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{__html: heading.value}}
/>
<Headings isChild headings={heading.children} />
</li>
))}
</ul>
);
}

function DocItem(props): JSX.Element {
const {siteConfig = {}} = useDocusaurusContext();
const {url: siteUrl, title: siteTitle} = siteConfig;
Expand Down Expand Up @@ -202,7 +161,9 @@ function DocItem(props): JSX.Element {
</div>
</div>
{!hideTableOfContents && DocContent.rightToc && (
<DocTOC headings={DocContent.rightToc} />
<div className="col col--3">
<TOC headings={DocContent.rightToc} />
</div>
)}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,37 +29,7 @@
}
}

.tableOfContents {
display: inherit;
max-height: calc(100vh - (var(--ifm-navbar-height) + 2rem));
overflow-y: auto;
position: sticky;
top: calc(var(--ifm-navbar-height) + 2rem);
}

.tableOfContents::-webkit-scrollbar {
width: 7px;
}

.tableOfContents::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
}

.tableOfContents::-webkit-scrollbar-thumb {
background: #888;
border-radius: 10px;
}

.tableOfContents::-webkit-scrollbar-thumb:hover {
background: #555;
}

@media only screen and (max-width: 996px) {
.tableOfContents {
display: none;
}

.docItemContainer {
padding: 0 0.3rem;
}
Expand Down
52 changes: 52 additions & 0 deletions packages/docusaurus-theme-classic/src/theme/TOC/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import React from 'react';

import useTOCHighlight from '@theme/hooks/useTOCHighlight';
import styles from './styles.module.css';

const LINK_CLASS_NAME = 'table-of-contents__link';
const ACTIVE_LINK_CLASS_NAME = 'table-of-contents__link--active';
const TOP_OFFSET = 100;

/* eslint-disable jsx-a11y/control-has-associated-label */
function Headings({headings, isChild}: {headings; isChild?: boolean}) {
if (!headings.length) {
return null;
}
return (
<ul
className={
isChild ? '' : 'table-of-contents table-of-contents__left-border'
}>
{headings.map((heading) => (
<li key={heading.id}>
<a
href={`#${heading.id}`}
className={LINK_CLASS_NAME}
// Developer provided the HTML, so assume it's safe.
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{__html: heading.value}}
/>
<Headings isChild headings={heading.children} />
</li>
))}
</ul>
);
}

function TOC({headings}) {
useTOCHighlight(LINK_CLASS_NAME, ACTIVE_LINK_CLASS_NAME, TOP_OFFSET);
return (
<div className={styles.tableOfContents}>
<Headings headings={headings} />
</div>
);
}

export default TOC;
43 changes: 43 additions & 0 deletions packages/docusaurus-theme-classic/src/theme/TOC/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

.tableOfContents {
display: inherit;
max-height: calc(100vh - (var(--ifm-navbar-height) + 2rem));
overflow-y: auto;
position: sticky;
top: calc(var(--ifm-navbar-height) + 2rem);
}

.tableOfContents::-webkit-scrollbar {
width: 7px;
}

.tableOfContents::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
}

.tableOfContents::-webkit-scrollbar-thumb {
background: #888;
border-radius: 10px;
}

.tableOfContents::-webkit-scrollbar-thumb:hover {
background: #555;
}

@media only screen and (max-width: 996px) {
.tableOfContents {
display: none;
}

.docItemContainer {
padding: 0 0.3rem;
}
}

2 changes: 2 additions & 0 deletions website/docs/blog.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ author_image_url: https://graph.facebook.com/611217057/picture/?height=200&width
tags: [hello, docusaurus-v2]
description: This is my first post on Docusaurus 2.
image: https://i.imgur.com/mErPwqL.png
hide_table_of_contents: false
---
Welcome to this blog. This blog is created with [**Docusaurus 2 alpha**](https://v2.docusaurus.io/).

Expand All @@ -63,6 +64,7 @@ The only required field is `title`; however, we provide options to add author in
- `draft` - A boolean flag to indicate that the blog post is work in process and therefore should not be published yet. However, draft blog posts will be displayed during development.
- `description`: The description of your post, which will become the `<meta name="description" content="..."/>` and `<meta property="og:description" content="..."/>` in `<head>`, used by search engines. If this field is not present, it will default to the first line of the contents.
- `image`: Cover or thumbnail image that will be used when displaying the link to your post.
- `hide_table_of_contents`: Whether to hide the table of contents to the right. By default it is `false`.
amy-lei marked this conversation as resolved.
Show resolved Hide resolved

## Summary truncation

Expand Down