mirror of
https://github.com/facebook/docusaurus.git
synced 2025-07-29 22:47:52 +02:00
feat(v2): add toc to blog posts (#3274)
* refactor TOC into own component * make layout consistent across blog pages
This commit is contained in:
parent
3ef965bae6
commit
473d263469
6 changed files with 108 additions and 73 deletions
|
@ -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}>
|
||||
|
@ -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>
|
||||
)}
|
||||
|
|
|
@ -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;
|
||||
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
52
packages/docusaurus-theme-classic/src/theme/TOC/index.tsx
Normal file
52
packages/docusaurus-theme-classic/src/theme/TOC/index.tsx
Normal file
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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/).
|
||||
|
||||
|
@ -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-progress 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`.
|
||||
|
||||
## Summary truncation
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue