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): highlight items in the table of content #1896

Merged
merged 47 commits into from
Nov 5, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
19efb7c
feat(v2): highlight items in the table of content
Oct 27, 2019
4f44e36
refactor: move string to const
Oct 27, 2019
c23f981
refactor(v2): Convert sitemap plugin to TypeScript (#1894)
moozzyk Oct 27, 2019
fabaf77
perf(v2): significantly reduce bundle size & initial html payload (#1…
endiliey Oct 27, 2019
84462e2
fix(v2): align search icon on small width device (#1893)
endiliey Oct 27, 2019
01f4d9a
refactor(v2): refactor dark toggle into a hook (#1899)
wgao19 Oct 27, 2019
98679b5
perf(v2): reduce memory usage consumption (#1900)
endiliey Oct 27, 2019
f14b6ee
misc(v1): use primary color for hovered items in table of contents (#…
blitz137 Oct 27, 2019
421598e
fix(v1): mobile safari search input misalignment in header (#1895)
jsardev Oct 27, 2019
812a30b
misc(v2): v1 backward compatibility for USE_SSH env var (#1880)
yns88 Oct 27, 2019
9c69dfd
feat(v2): allow line highlighting (#1860)
lex111 Oct 27, 2019
3172602
docs(v1): remove user Vasern (#1901)
ikrydev Oct 28, 2019
3f4c805
misc: update URLs to non-HTML versions (#1902)
ikrydev Oct 28, 2019
b6667a0
misc(v2): improve index page SEO score
yangshun Oct 28, 2019
7714afb
fix(v2): accessing /docs or /docs/xxxx should not be empty (#1903)
endiliey Oct 28, 2019
f635f9a
docs(v2): code block line highlighting (#1904)
yangshun Oct 29, 2019
e6444c0
fix(v2): webpack modules resolve should prioritize @docusaurus/core o…
endiliey Oct 29, 2019
2e58e83
feat(v2): simplify blog metadata to minimize number of request (#1908)
endiliey Oct 29, 2019
31d17c9
feat(v2): add ability to set custom HTML in footer items (#1905)
lex111 Oct 29, 2019
ad22c9f
docs: update configcat user link (#1911)
mr-sige Oct 29, 2019
a8826b9
fix(v2): docs plugin stability improvement (100% test coverage) (#1912)
endiliey Oct 29, 2019
f853171
docs(v2): add windows batch instructions for publishing to gh pages (…
dylmye Oct 29, 2019
64871b7
fix(v2): custom searchbar should appear even if themeconfig.algolia i…
endiliey Oct 30, 2019
6fcee6d
fix(v2): missing/hidden algolia search suggestion result (#1915)
endiliey Oct 30, 2019
16f10dd
docs(v2): Redirect component for easy redirect (#1913)
endiliey Oct 30, 2019
5a2f539
refactor: changes after comments (use custom hooks, code changes, fix…
Oct 30, 2019
ca4efb6
fix(v2): regression from prioritizing core node_modules logic (#1917)
endiliey Oct 30, 2019
c7ff07c
chore: changelog
endiliey Oct 30, 2019
255584c
docs(v1): showcase user Reactive Interaction Gateway (#1918)
mmacai Oct 30, 2019
ab15205
chore: bump dependencies
endiliey Oct 31, 2019
472c8fc
docs(v2): fix typo in advanced plugins (#1926)
joelibaceta Nov 1, 2019
b8335fe
docs(v2): fix typos (#1930)
lex111 Nov 2, 2019
0baaad3
docs(v1): fix links in CHANGELOG (#1931)
glenwinters Nov 2, 2019
c41c19e
fix(v2): @theme/heading should not create anchor if id is not defined…
endiliey Nov 2, 2019
3f8cb78
docs(v2): theme, plugin, and preset config (#1929)
kabartolo Nov 3, 2019
82ece51
misc: use /usr/bin/env bash to increase portability (#1923)
marcjansen Nov 3, 2019
33718b6
misc(v1): use Node.js lts version (#1920)
gengjiawen Nov 3, 2019
2d13fe2
chore: downgrade imagemin (#1933)
endiliey Nov 3, 2019
34a84a3
fix(v2): add missing key prop in footer items with HTML (#1935)
lex111 Nov 3, 2019
146a301
fix(v2): fix browser window background (#1936)
lex111 Nov 4, 2019
9c34bb7
fix(v2): allows to create tabs with only one item (#1934)
Nov 4, 2019
0d445fc
fix(v2): remove redundant npm script in classic template (#1937)
lex111 Nov 4, 2019
cd9e2f2
v2.0.0-alpha.32
endiliey Nov 4, 2019
5909b49
chore(v2): changelog
endiliey Nov 4, 2019
32773e5
Merge branch 'feat/1752' of https://github.com/SantiagoGdaR/docusauru…
yangshun Nov 5, 2019
77e8890
misc(v2): update TOC highlight
yangshun Nov 5, 2019
542b7c9
misc(v2): update CHANGELOG
yangshun Nov 5, 2019
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
12 changes: 11 additions & 1 deletion packages/docusaurus-theme-classic/src/theme/DocItem/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,26 @@ import Head from '@docusaurus/Head';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useBaseUrl from '@docusaurus/useBaseUrl';
import DocPaginator from '@theme/DocPaginator';
import useTableOfContentHighlight from '@theme/hooks/useTableOfContentHighlight';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it makes sense TableOfContent shorten to simply toc? It will be easier to read and understand.

  • useTableOfContentHighlight -> useTocHighlight
  • tableOfContentLinkClassName -> tocLinkClassName
  • And so on


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

function Headings({headings, isChild}) {
const LINK_CLASS_NAME = 'contents__link';
const TOP_OFFSET = 100;

useTableOfContentHighlight(
LINK_CLASS_NAME,
'contents__link--active',
lex111 marked this conversation as resolved.
Show resolved Hide resolved
TOP_OFFSET,
);

if (!headings.length) return null;
return (
<ul className={isChild ? '' : 'contents contents__left-border'}>
{headings.map(heading => (
<li key={heading.id}>
<a href={`#${heading.id}`} className="contents__link">
<a href={`#${heading.id}`} className={LINK_CLASS_NAME}>
{heading.value}
</a>
<Headings isChild headings={heading.children} />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import {useEffect, useState} from 'react';

function useTableOfContentHighlight(
tableOfContentLinkClassName,
tableOfContentLinkActiveClassName,
topOffset,
) {
const [
lastActiveTableOfContentLink,
setLastActiveTableOfContentLink,
] = useState(undefined);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use null instead of undefined


useEffect(() => {
let headersAnchor = [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is not it more correct to call this var that?

headersAnchor -> headerAnchors

let tableOfContentLinks = [];

function getActiveHeaderAnchor() {
const TOP_OFFSET = topOffset;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you really need to create a constant for this when it is used once? I mean, the code is not so big, and there is no point in duplicating the same value in such a way.

In my opinion it is better to do without it:

- if (top >= 0 && top <= TOP_OFFSET) {}
+ if (top> = 0 && top <= topOffset) {}

let index = 0;
let activeHeaderAnchor;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You must probably explicitly set the default value.

 let activeHeaderAnchor = null;

headersAnchor = document.querySelectorAll('a.anchor');
while (index < headersAnchor.length && !activeHeaderAnchor) {
const headerAnchor = headersAnchor[index];
const {top} = headerAnchor.getBoundingClientRect();
if (top >= 0 && top <= TOP_OFFSET) {
activeHeaderAnchor = headerAnchor;
}
index += 1;
}
return activeHeaderAnchor;
}

function highlightTableOfContentLink(tableOfContentLink) {
if (lastActiveTableOfContentLink) {
lastActiveTableOfContentLink.classList.remove(
tableOfContentLinkActiveClassName,
);
}
tableOfContentLink.classList.add(tableOfContentLinkActiveClassName);
setLastActiveTableOfContentLink(tableOfContentLink);
}

function getAnchorValue(tableOfContentLink) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would consider this solution, it will be faster.

function getAnchorValue(tocLink) {
  return decodeURIComponent(
    tocLink.href.substring(tocLink.href.indexOf('#') + 1)
  );
}

const splittedUrl = tableOfContentLink.href
? decodeURIComponent(tableOfContentLink.href).split('#')
: [];
return splittedUrl.length > 1 ? splittedUrl[1] : '';
}

function setActiveTableOfContentLink() {
const activeHeaderAnchor = getActiveHeaderAnchor();
if (activeHeaderAnchor) {
SantiagoGdaR marked this conversation as resolved.
Show resolved Hide resolved
let index = 0;
let itemHighlighted = false;
tableOfContentLinks = document.querySelectorAll(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I would prefer to use the old-school document.getElementsByClassName (sort of like it's even faster), since the selection goes only by class and it is assumed that only the class will be used, otherwise you need to rename the parameter to tableOfContentLinkSelector and continue use querySelectorAll 🤔

`.${tableOfContentLinkClassName}`,
);
while (index < tableOfContentLinks.length && !itemHighlighted) {
const tableOfContentLink = tableOfContentLinks[index];
const anchorValue = getAnchorValue(tableOfContentLink);
if (activeHeaderAnchor.id === anchorValue) {
highlightTableOfContentLink(tableOfContentLink);
itemHighlighted = true;
}
index += 1;
}
}
}

document.addEventListener('scroll', setActiveTableOfContentLink);
document.addEventListener('resize', setActiveTableOfContentLink);

setActiveTableOfContentLink();

return () => {
document.removeEventListener('scroll', setActiveTableOfContentLink);
document.removeEventListener('resize', setActiveTableOfContentLink);
};
});
}

export default useTableOfContentHighlight;