Skip to content

Commit 22268aa

Browse files
authored
docs: add quick links to docs pages for small screens and add section table of contents indexes (#4145)
1 parent d6d00ca commit 22268aa

File tree

19 files changed

+366
-82
lines changed

19 files changed

+366
-82
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<template>
2+
<nav aria-label="Breadcrumbs">
3+
<b-breadcrumb :items="items" class="d-inline-flex bg-transparent px-2 py-1 my-0">
4+
</b-breadcrumb>
5+
</nav>
6+
</template>
7+
8+
<style scoped>
9+
.breadcrumb /deep/ .breadcrumb-item {
10+
font-size: 0.875rem;
11+
line-height: 1.5;
12+
margin-bottom: 0;
13+
}
14+
</style>
15+
16+
<script>
17+
import { nav } from '~/content'
18+
19+
const navLookup = nav.reduce((obj, section) => {
20+
obj[section.base.replace('/', '')] = section
21+
return obj
22+
}, {})
23+
24+
export default {
25+
name: 'BDVBreadcrumbs',
26+
computed: {
27+
items() {
28+
const items = [{ text: 'Home', to: '/' }, { text: 'Docs', to: '/docs' }]
29+
const section = this.$route.name.split('-')[1] || ''
30+
const slug = this.$route.params.slug || ''
31+
if (section) {
32+
const sectionMeta = navLookup[section] || {}
33+
items.push({
34+
text: sectionMeta.title || section,
35+
to: ['/docs', section].join('/')
36+
})
37+
if (slug) {
38+
const pagesMeta = sectionMeta.pages || {}
39+
items.push({
40+
text: (pagesMeta[slug] || {}).title || slug,
41+
to: ['/docs', section, slug].join('/')
42+
})
43+
}
44+
}
45+
return items
46+
}
47+
}
48+
}
49+
</script>

docs/components/feedback.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ export default {
66
}
77
},
88
computed: {
9+
show() {
10+
const name = this.$route.name
11+
const slug = this.$route.params.slug
12+
return slug || name === 'docs'
13+
},
914
reportIssueUrl() {
1015
// Add appreciate query params for proper issue title
1116
return `${this.baseUrl}/issues/new?title=Docs`
@@ -35,6 +40,9 @@ export default {
3540
}
3641
},
3742
render(h) {
43+
if (!this.show) {
44+
return h()
45+
}
3846
const $reportIssueButton = h(
3947
'b-button',
4048
{

docs/components/quick-links.vue

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<template>
2+
<nav
3+
:class="['bd-quick-links', 'mb-3', { 'd-none': !quickLinksVisible || !hasContent }]"
4+
:aria-hidden="hasContent ? null : 'true'"
5+
>
6+
<header v-if="hasContent">
7+
<b-button
8+
v-b-toggle.bd-quick-links-collapse
9+
class="font-weight-bold"
10+
variant="outline-secondary"
11+
size="sm"
12+
block
13+
>
14+
<span v-if="quickLinksExpanded">Hide</span>
15+
<span v-else>Show</span>
16+
page table of contents
17+
</b-button>
18+
</header>
19+
<b-collapse v-if="hasContent" id="bd-quick-links-collapse" v-model="quickLinksExpanded" tag="ul">
20+
<li v-for="h2 in toc.toc" :key="h2.href">
21+
<b-link :href="h2.href" @click="scrollIntoView($event, h2.href)">
22+
<span v-html="h2.label"></span>
23+
</b-link>
24+
<ul v-if="h2.toc && h2.toc.length > 0" :key="`sub-${h2.href}`">
25+
<li v-for="h3 in h2.toc" :key="h3.href">
26+
<b-link :href="h3.href" @click="scrollIntoView($event, h3.href)">
27+
<span v-html="h3.label"></span>
28+
</b-link>
29+
</li>
30+
</ul>
31+
</li>
32+
</b-collapse>
33+
</nav>
34+
</template>
35+
36+
<style scoped lang="scss">
37+
#bd-quick-links-collapse {
38+
list-style-type: square;
39+
border-left: 5px solid #ccc;
40+
padding-left: 2.5rem;
41+
margin-top: 1rem;
42+
43+
ul {
44+
list-style-type: circle;
45+
padding-left: 1.25rem;
46+
margin-bottom: 0.25rem;
47+
}
48+
}
49+
</style>
50+
51+
<script>
52+
import { offsetTop, scrollTo } from '~/utils'
53+
54+
export default {
55+
name: 'BDVQuickToc',
56+
data() {
57+
return {
58+
toc: {},
59+
offset: 0,
60+
quickLinksExpanded: false,
61+
quickLinksVisible: false
62+
}
63+
},
64+
computed: {
65+
hasContent() {
66+
return !!this.toc.toc
67+
}
68+
},
69+
created() {
70+
this.$root.$on('docs-set-toc', toc => {
71+
// Reset visible/expanded states
72+
this.quickLinksVisible = false
73+
this.quickLinksExpanded = false
74+
// Update the TOC content
75+
this.toc = toc
76+
// Re-position the quick links
77+
this.positionQuickLinks()
78+
})
79+
},
80+
mounted() {
81+
// Set the correct offset based on the header height
82+
const $header = document.body.querySelector('header.navbar')
83+
if ($header) {
84+
this.offset = $header.offsetHeight + 6
85+
}
86+
// Re-position the quick links
87+
this.positionQuickLinks()
88+
},
89+
methods: {
90+
scrollIntoView(evt, href) {
91+
evt.preventDefault()
92+
evt.stopPropagation()
93+
// We use an attribute `querySelector()` rather than `getElementByID()`,
94+
// as some auto-generated ID's are invalid or not unique
95+
const id = (href || '').replace(/#/g, '')
96+
const $el = document.body.querySelector(`[id="${id}"]`)
97+
if ($el) {
98+
// Get the document scrolling element
99+
const scroller = document.scrollingElement || document.documentElement || document.body
100+
// Scroll heading into view (minus offset to account for nav top height
101+
scrollTo(scroller, offsetTop($el) - 70, 100, () => {
102+
// Set a tab index so we can focus header for a11y support
103+
$el.tabIndex = -1
104+
// Focus the heading
105+
$el.focus()
106+
})
107+
}
108+
},
109+
positionQuickLinks() {
110+
if (typeof document === 'undefined') {
111+
return
112+
}
113+
// Move the quick links to the correct position, if possible
114+
const $body = document.body
115+
const $referenceNode = $body.querySelector('.bd-lead') || $body.querySelector('h1')
116+
if ($referenceNode) {
117+
// IE 11 doesn't support the `node.after()` method, and appears
118+
// that the polyfill doesn't polyfill this method
119+
$referenceNode.insertAdjacentElement('afterend', this.$el)
120+
}
121+
// Make the quick links visible
122+
// We hide them initially to make the position change not that distracting
123+
this.quickLinksVisible = true
124+
}
125+
}
126+
}
127+
</script>

docs/components/search.vue

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,30 +11,6 @@
1111
placeholder="Search..."
1212
aria-label="Search docs"
1313
></b-form-input>
14-
<button
15-
v-b-toggle.bd-docs-nav
16-
type="button"
17-
class="btn btn-link bd-search-docs-toggle d-md-none p-0 ml-3"
18-
aria-label="Toggle docs navigation"
19-
>
20-
<svg
21-
class=""
22-
xmlns="http://www.w3.org/2000/svg"
23-
viewBox="0 0 30 30"
24-
width="30"
25-
height="30"
26-
focusable="false"
27-
>
28-
<title>Menu</title>
29-
<path
30-
stroke="currentColor"
31-
stroke-width="2"
32-
stroke-linecap="round"
33-
stroke-miterlimit="10"
34-
d="M4 7h22M4 15h22M4 23h22"
35-
/>
36-
</svg>
37-
</button>
3814
</form>
3915
</template>
4016

docs/components/section-toc.vue

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<template>
2+
<Main>
3+
<Section>
4+
<h1 :id="id" tabindex="-1">
5+
<span class="bd-content-title">
6+
{{ groupTitle }} <span class="small text-muted">- table of contents</span>
7+
</span>
8+
</h1>
9+
<p v-if="groupDescription" class="bd-lead">{{ groupDescription }}</p>
10+
<b-list-group tag="nav" :aria-label="`${groupTitle} section navigation`" class="mb-5">
11+
<b-list-group-item
12+
v-for="page in pages"
13+
:key="page.slug"
14+
:to="`/docs/${slug}/${page.slug}`"
15+
active-class=""
16+
>
17+
<strong class="text-primary">{{ page.title }}</strong> &mdash;
18+
<span class="text-muted">{{ page.description }}</span>
19+
</b-list-group-item>
20+
</b-list-group>
21+
</Section>
22+
</Main>
23+
</template>
24+
25+
<style scoped>
26+
.list-group .list-group-item:hover strong {
27+
text-decoration: underline;
28+
}
29+
</style>
30+
31+
<script>
32+
import Main from '~/components/main'
33+
import Section from '~/components/section'
34+
import { nav } from '~/content'
35+
36+
// Normalize nav into a lookup object
37+
const groups = nav.reduce((obj, g) => {
38+
const groupSlug = g.base.replace(/\/$/, '')
39+
obj[groupSlug] = g
40+
return obj
41+
}, {})
42+
43+
export default {
44+
layout: 'docs',
45+
components: {
46+
Main,
47+
Section
48+
},
49+
computed: {
50+
slug() {
51+
return this.$route.path.replace(/^\//, '').split('/')[1] || ''
52+
},
53+
id() {
54+
return `bd-section-toc-${this.slug}`
55+
},
56+
group() {
57+
return groups[this.slug] || {}
58+
},
59+
groupDescription() {
60+
return this.group.description
61+
},
62+
groupTitle() {
63+
const title = this.group.title || ''
64+
return title === 'Components'
65+
? 'Component groups'
66+
: title === 'Misc'
67+
? 'Miscellaneous'
68+
: title || ''
69+
},
70+
pages() {
71+
return this.group.pages || []
72+
}
73+
}
74+
}
75+
</script>

docs/components/section.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const scrollIntoView = (evt, href) => {
99
evt.preventDefault()
1010
evt.stopPropagation()
1111
// We use an attribute `querySelector()` rather than `getElementByID()`,
12-
// as some auto-generated ID's are invalid or may not be unique
12+
// as some auto-generated ID's are invalid or not unique
1313
const id = (href || '').replace(/#/g, '')
1414
const $el = document.body.querySelector(`[id="${id}"]`)
1515
if ($el) {

docs/components/sidebar.vue

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
<template>
2-
<b-collapse
3-
id="bd-docs-nav"
4-
class="bd-links"
5-
tag="nav"
6-
is-nav
7-
aria-label="Main navigation"
8-
>
2+
<nav id="bd-docs-nav" class="bd-links d-none d-md-block" aria-label="Main navigation">
93
<b-link to="/" exact router-tag="div" active-class="active">
104
<b-link to="/" exact class="bd-toc-link" active-class="">Home</b-link>
115
</b-link>
@@ -59,7 +53,7 @@
5953
<b-link to="/play" exact router-tag="div" active-class="active">
6054
<b-link to="/play" exact class="bd-toc-link" active-class="">Playground</b-link>
6155
</b-link>
62-
</b-collapse>
56+
</nav>
6357
</template>
6458

6559
<script>

docs/components/toc.vue

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,31 +46,26 @@
4646
</template>
4747

4848
<script>
49-
import { makeTOC, offsetTop, scrollTo } from '~/utils'
49+
import { offsetTop, scrollTo } from '~/utils'
5050
5151
export default {
5252
name: 'BDVToc',
5353
data() {
5454
return {
55-
readme: '',
56-
meta: null,
55+
toc: {},
5756
offset: 0
5857
}
5958
},
60-
computed: {
61-
toc() {
62-
return makeTOC(this.readme, this.meta)
63-
}
59+
created() {
60+
this.$root.$on('docs-set-toc', toc => {
61+
this.toc = toc
62+
})
6463
},
6564
mounted() {
6665
const $header = document.body.querySelector('header.navbar')
6766
if ($header) {
6867
this.offset = $header.offsetHeight + 6
6968
}
70-
this.$root.$on('setTOC', (readme, meta) => {
71-
this.readme = readme
72-
this.meta = meta || null
73-
})
7469
},
7570
methods: {
7671
isArray(value) {

0 commit comments

Comments
 (0)