Skip to content

Commit ef85e59

Browse files
authored
Merge pull request #16465 from github/add-dev-toc-redux
[spike] Minimal top-level toc
2 parents 0d9e1f9 + 4b411ec commit ef85e59

10 files changed

Lines changed: 154 additions & 0 deletions

File tree

javascripts/dev-toc.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
const expandText = 'Expand All'
2+
const closeText = 'Close All'
3+
4+
export default function devToc () {
5+
const expandButton = document.querySelector('.js-expand')
6+
if (!expandButton) return
7+
8+
const detailsElements = document.querySelectorAll('details')
9+
10+
expandButton.addEventListener('click', () => {
11+
// on click, toggle all the details elements open or closed
12+
const anyDetailsOpen = Array.from(detailsElements).find(details => details.open)
13+
14+
for (const detailsElement of detailsElements) {
15+
anyDetailsOpen
16+
? detailsElement.removeAttribute('open')
17+
: detailsElement.open = true
18+
}
19+
20+
// toggle the button text on click
21+
anyDetailsOpen
22+
? expandButton.textContent = expandText
23+
: expandButton.textContent = closeText
24+
})
25+
26+
// also toggle the button text on clicking any of the details elements
27+
for (const detailsElement of detailsElements) {
28+
detailsElement.addEventListener('click', () => {
29+
expandButton.textContent = closeText
30+
31+
// we can only get an accurate count of the open details elements if we wait a fraction after click
32+
setTimeout(() => {
33+
if (!Array.from(detailsElements).find(details => details.open)) {
34+
expandButton.textContent = expandText
35+
}
36+
}, 50)
37+
})
38+
}
39+
}

javascripts/events.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ export default function initializeEvents () {
192192
})
193193
})
194194

195+
if (!document.querySelector('.sidebar-products')) return
196+
195197
// Navigate event
196198
Array.from(
197199
document.querySelectorAll('.sidebar-products details')

javascripts/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { fillCsrf } from './get-csrf'
1616
import initializeEvents from './events'
1717
import filterCodeExamples from './filter-code-examples'
1818
import allArticles from './all-articles'
19+
import devToc from './dev-toc'
1920

2021
document.addEventListener('DOMContentLoaded', async () => {
2122
displayPlatformSpecificContent()
@@ -34,4 +35,5 @@ document.addEventListener('DOMContentLoaded', async () => {
3435
initializeEvents()
3536
filterCodeExamples()
3637
allArticles()
38+
devToc()
3739
})

javascripts/nav.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ export default function () {
33
const hamburgerButton = document.querySelector('.nav-mobile-burgerIcon')
44
const mobileDropdown = document.querySelector('.nav-mobile-dropdown')
55

6+
if (!(hamburgerButton && mobileDropdown)) return
7+
68
hamburgerButton.addEventListener('click', (event) => {
79
event.preventDefault()
810
hamburgerButton.classList.toggle('js-open')

javascripts/search.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ const resultTemplate = (item) => {
6363
}
6464

6565
export default function () {
66+
if (!document.querySelector('#search-results-container')) return
67+
6668
window.initialPageLoad = true
6769
const opts = {
6870

layouts/dev-toc.html

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<!doctype html>
2+
<html lang="{{currentLanguage}}">
3+
<head>
4+
<meta charset="utf-8" />
5+
<title>Docs TOC</title>
6+
<link rel="stylesheet" href="/dist/index.css">
7+
<link rel="alternate icon" type="image/png" href="/assets/images/site/favicon.png">
8+
<link rel="icon" type="image/svg+xml" href="/assets/images/site/favicon.svg">
9+
</head>
10+
11+
<body class="dev-toc p-3 m-3">
12+
<main class="width-full">
13+
14+
<h3>Versions</h3>
15+
<ul class="versions-list">
16+
{% for version in allVersions %}
17+
<li><a href="/{{ version[0] }}/dev-toc">{{ version[1].versionTitle }}</a>
18+
{% endfor %}
19+
</ul>
20+
21+
{% if allVersions[currentVersion] %}
22+
<h2 class="mt-3 mb-3"><abbr>TOC</abbr> for {{ allVersions[currentVersion].versionTitle }}</h2>
23+
24+
<button class="btn mb-3 js-expand" type="button">Expand All</button>
25+
<div/>
26+
27+
{% for product in siteTree[currentLanguage][currentVersion].products %}
28+
<details class="mb-1"><summary>{{product[1].title}}</summary>
29+
<ul class="products-list">
30+
<li title="{{product[1].title}}">
31+
<a href="/{{currentLanguage}}{{product[1].href}}">{{ product[1].title }}</a>
32+
{% for category in product[1].categories %}
33+
{% capture fullPathToCategory %}/{{currentLanguage}}{{category[1].href}}{% endcapture %}
34+
<ul>
35+
<li>
36+
<a href="{{fullPathToCategory}}">{{ category[1].title }}</a>
37+
<!-- some categories have maptopics with child articles -->
38+
{% if category[1].maptopics %}
39+
<ul">
40+
{% for maptopic in category[1].maptopics %}
41+
{% unless maptopic[1].hidden %}
42+
{% capture fullPathToMaptopic %}/{{currentLanguage}}{{maptopic[1].href}}{% endcapture %}
43+
44+
<li>
45+
<a href="{{fullPathToMaptopic}}">{{ maptopic[1].title }}</a>
46+
<ul>
47+
{% for article in maptopic[1].articles %}
48+
{% capture fullPathToArticle %}/{{currentLanguage}}{{article[1].href}}{% endcapture %}
49+
50+
<li>
51+
<a href="{{fullPathToArticle}}">{{ article[1].title }}</a>
52+
</li>
53+
{% endfor %}
54+
</ul>
55+
</li>
56+
{% endunless %}
57+
{% endfor %}
58+
</ul>
59+
<!-- some categories have no maptopics, only articles -->
60+
{% else %}
61+
<ul>
62+
{% for article in category[1].articles %}
63+
{% capture fullPathToArticle %}/{{currentLanguage}}{{article[1].href}}{% endcapture %}
64+
<li>
65+
<a href="{{fullPathToArticle}}">{{ article[1].title }}</a>
66+
</li>
67+
{% endfor %}
68+
</ul>
69+
{% endif %}
70+
</li>
71+
{% endfor %}
72+
</ul>
73+
</li>
74+
</ul>
75+
</details>
76+
{% endfor %}
77+
{% endif %}
78+
79+
{% include scripts %}
80+
</main>
81+
</body>
82+
</html>

middleware/dev-toc.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const { liquid } = require('../lib/render-content')
2+
const layouts = require('../lib/layouts')
3+
4+
module.exports = async (req, res, next) => {
5+
if (process.env.NODE_ENV !== 'development') return next()
6+
if (!req.path.endsWith('/dev-toc')) return next()
7+
8+
return res.send(await liquid.parseAndRender(layouts['dev-toc'], req.context))
9+
}

middleware/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ module.exports = function (app) {
5555
app.use(require('./disable-caching-on-safari'))
5656
app.get('/_500', asyncMiddleware(require('./trigger-error')))
5757
app.use(require('./breadcrumbs'))
58+
app.use(require('./dev-toc'))
5859
app.use(require('./featured-links'))
5960
app.get('/*', asyncMiddleware(require('./render-page')))
6061
app.use(require('./handle-errors'))

stylesheets/dev-toc.scss

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* Styles used for top-level TOC in development only
2+
------------------------------------------------------------------------------*/
3+
4+
ul.versions-list {
5+
list-style-type: none;
6+
}
7+
8+
ul.versions-list > li {
9+
margin: 3px 0 0 0;
10+
}
11+
12+
details ul.products-list li {
13+
margin: 3px 0 0 30px;
14+
}

stylesheets/index.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,4 @@ $marketing-font-path: "/dist/fonts/";
5555
@import "print.scss";
5656
@import "shadows.scss";
5757
@import "product-landing.scss";
58+
@import "dev-toc.scss";

0 commit comments

Comments
 (0)