From 8c8dfa42cdb48ef911a8d536211c6288a979e511 Mon Sep 17 00:00:00 2001 From: Paolo Insogna Date: Thu, 24 Feb 2022 12:00:42 +0100 Subject: [PATCH] doc,tools: improve navigability of API docs PR-URL: https://github.com/nodejs/node/pull/41404 Reviewed-By: Rich Trott Reviewed-By: Antoine du Hamel --- doc/api_assets/style.css | 130 +++++++++++++++++++++++++++++---- doc/template.html | 32 +++++--- test/doctool/test-make-doc.mjs | 3 +- tools/doc/html.mjs | 80 ++++++++++++++++---- 4 files changed, 205 insertions(+), 40 deletions(-) diff --git a/doc/api_assets/style.css b/doc/api_assets/style.css index 9ae45a09c84ca8..fa12c02ce7dfbb 100644 --- a/doc/api_assets/style.css +++ b/doc/api_assets/style.css @@ -162,7 +162,7 @@ em code { margin-bottom: 1rem; } -#gtoc ul { +#gtoc > ul { list-style: none; margin-left: 0; line-height: 1.5rem; @@ -172,42 +172,73 @@ em code { color: var(--color-critical); } -li.version-picker { +li.picker-header { position: relative; } -li.version-picker:hover > a { +li.picker-header .collapsed-arrow, li.picker-header .expanded-arrow { + width: 1.5ch; + height: 1.5em; +} + +li.picker-header .collapsed-arrow { + display: inline-block; +} + +li.picker-header .expanded-arrow { + display: none; +} + +li.picker-header:hover .collapsed-arrow { + display: none; +} + +li.picker-header:hover .expanded-arrow { + display: inline-block; +} + +li.picker-header:hover > a { border-radius: 2px 2px 0 0; } -li.version-picker:hover > ol { +li.picker-header:hover > .picker { display: block; z-index: 1; } -li.version-picker a span { +li.picker-header a span { font-size: .7rem; } -ol.version-picker { +.picker { background-color: var(--color-fill-app); border: 1px solid var(--color-brand-secondary); border-radius: 0 0 2px 2px; display: none; list-style: none; position: absolute; - right: 0; + left: 0; top: 100%; - width: 100%; + width: max-content; + min-width: min(300px, 75vw); + max-width: 75vw; + max-height: min(600px, 60vh); + overflow-y: auto; } -#gtoc ol.version-picker li { +.picker > ul, .picker > ol { + list-style: none; + margin-left: 0; + line-height: 1.5rem; +} + +.picker li { display: block; border-right: 0; margin-right: 0; } -ol.version-picker li a { +.picker li a { border-radius: 0; display: block; margin: 0; @@ -215,17 +246,32 @@ ol.version-picker li a { padding-left: 1rem; } -ol.version-picker li:last-child a { +.picker li a.active, +.picker li a.active:hover, +.picker li a.active:focus { + font-weight: 700; +} + +.picker li:last-child a { border-bottom-right-radius: 1px; border-bottom-left-radius: 1px; } +.gtoc-picker-header { + display: none; +} + .line { width: calc(100% - 1rem); display: block; padding-bottom: 1px; } +.picker .line { + margin: 0; + width: 100%; +} + .api_stability { color: var(--white) !important; margin: 0 0 1rem; @@ -506,6 +552,41 @@ hr { margin-top: .666rem; } +.toc ul { + margin: 0 +} + +.toc li a::before { + content: "■"; + color: var(--color-text-primary); + padding-right: 1em; + font-size: 0.9em; +} + +.toc li a:hover::before { + color: var(--white); +} + +.toc ul ul a { + padding-left: 1rem; +} + +.toc ul ul ul a { + padding-left: 2rem; +} + +.toc ul ul ul ul a { + padding-left: 3rem; +} + +.toc ul ul ul ul ul a { + padding-left: 4rem; +} + +.toc ul ul ul ul ul ul a { + padding-left: 5rem; +} + #toc .stability_0::after { background-color: var(--red2); color: var(--white); @@ -718,10 +799,25 @@ kbd { } } +.header { + position: sticky; + top: -1px; + z-index: 1; + padding-top: 1rem; + background-color: var(--color-fill-app); +} + +@media not screen, (max-height: 1000px) { + .header { + position: relative; + top: 0; + } +} + .header-container { display: flex; align-items: center; - margin: 1.5rem 0 1rem; + margin-bottom: 1rem; justify-content: space-between; } @@ -735,7 +831,7 @@ kbd { outline: var(--brand3) dotted 2px; } -@media only screen and (min-width: 577px) { +@media only screen and (min-width: 601px) { #gtoc > ul > li { display: inline; border-right: 1px currentColor solid; @@ -748,6 +844,10 @@ kbd { margin-right: 0; padding-right: 0; } + + #gtoc > ul > li.gtoc-picker-header { + display: none; + } } @media only screen and (max-width: 1024px) { @@ -764,6 +864,10 @@ kbd { #column2 { display: none; } + + #gtoc > ul > li.gtoc-picker-header { + display: inline; + } } .icon { diff --git a/doc/template.html b/doc/template.html index c8c78dce59b64a..89dd2fbeac9e01 100644 --- a/doc/template.html +++ b/doc/template.html @@ -22,7 +22,7 @@
-
+

Node.js __VERSION__ documentation


diff --git a/test/doctool/test-make-doc.mjs b/test/doctool/test-make-doc.mjs index 06ec6e028bf4e8..54483c7d68932d 100644 --- a/test/doctool/test-make-doc.mjs +++ b/test/doctool/test-make-doc.mjs @@ -40,7 +40,8 @@ const links = toc.match(globalRe); assert.notStrictEqual(links, null); // Filter out duplicate links, leave just filenames, add expected JSON files. -const linkedHtmls = [...new Set(links)].map((link) => link.match(re)[1]); +const linkedHtmls = [...new Set(links)].map((link) => link.match(re)[1]) + .concat(['index.html']); const expectedJsons = linkedHtmls .map((name) => name.replace('.html', '.json')); const expectedDocs = linkedHtmls.concat(expectedJsons); diff --git a/tools/doc/html.mjs b/tools/doc/html.mjs index 8d356836eb5667..1c5ad61182bc79 100644 --- a/tools/doc/html.mjs +++ b/tools/doc/html.mjs @@ -98,8 +98,10 @@ export function toHTML({ input, content, filename, nodeVersion, versions }) { .replace(/__FILENAME__/g, filename) .replace('__SECTION__', content.section) .replace(/__VERSION__/g, nodeVersion) - .replace('__TOC__', content.toc) - .replace('__GTOC__', gtocHTML.replace( + .replace(/__TOC__/g, content.toc) + .replace(/__TOC_PICKER__/g, tocPicker(id, content)) + .replace(/__GTOC_PICKER__/g, gtocPicker(id)) + .replace(/__GTOC__/g, gtocHTML.replace( `class="nav-${id}"`, `class="nav-${id} active"`)) .replace('__EDIT_ON_GITHUB__', editOnGitHub(filename)) .replace('__CONTENT__', processContent(content)); @@ -442,17 +444,18 @@ export function buildToc({ filename, apilinks }) { }); if (toc !== '') { - file.toc = '
Table of contents' + - unified() - .use(markdown) - .use(gfm) - .use(remark2rehype, { allowDangerousHtml: true }) - .use(raw) - .use(htmlStringify) - .processSync(toc).toString() + - '
'; + const inner = unified() + .use(markdown) + .use(gfm) + .use(remark2rehype, { allowDangerousHtml: true }) + .use(raw) + .use(htmlStringify) + .processSync(toc).toString(); + + file.toc = `
Table of contents${inner}
`; + file.tocPicker = `
${inner}
`; } else { - file.toc = ''; + file.toc = file.tocPicker = ''; } }; } @@ -508,9 +511,12 @@ function altDocs(filename, docCreated, versions) { const list = versions.filter(isDocInVersion).map(wrapInListItem).join('\n'); return list ? ` -
  • - View another version -
      ${list}
    +
  • + + + Other versions + +
      ${list}
  • ` : ''; } @@ -518,3 +524,47 @@ function altDocs(filename, docCreated, versions) { function editOnGitHub(filename) { return `
  • Edit on GitHub
  • `; } + +function gtocPicker(id) { + if (id === 'index') { + return ''; + } + + // Highlight the current module and add a link to the index + const gtoc = gtocHTML.replace( + `class="nav-${id}"`, `class="nav-${id} active"` + ).replace('', ` +
  • + Index +
  • + + `); + + return ` +
  • + + + Index + + +
    ${gtoc}
    +
  • + `; +} + +function tocPicker(id, content) { + if (id === 'index') { + return ''; + } + + return ` +
  • + + + Table of contents + + +
    ${content.tocPicker}
    +
  • + `; +}