vuepress-theme-uniapp-official 1.4.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/components/AlgoliaSearchBox.vue +130 -0
- package/components/DcloudSearchPage/components/Result.vue +160 -0
- package/components/DcloudSearchPage/components/Results.vue +66 -0
- package/components/DcloudSearchPage/components/pagination.vue +155 -0
- package/components/DcloudSearchPage/index.styl +183 -0
- package/components/DcloudSearchPage/index.vue +500 -0
- package/components/DcloudSearchPage/styles/ask.styl +272 -0
- package/components/DcloudSearchPage/styles/ext.styl +68 -0
- package/components/DcloudSearchPage/utils/Base64.js +134 -0
- package/components/DcloudSearchPage/utils/mock.js +434 -0
- package/components/DcloudSearchPage/utils/postDcloudServer.js +141 -0
- package/components/DcloudSearchPage/utils/searchClient.js +101 -0
- package/components/DcloudSearchPage/utils/searchUtils.js +52 -0
- package/components/Footer.vue +142 -0
- package/components/MainNavbarLink.vue +57 -0
- package/components/NavLink.vue +95 -0
- package/components/NavLinks.vue +173 -0
- package/components/Navbar.vue +322 -0
- package/components/NavbarLogo.vue +24 -0
- package/components/OutboundLink.vue +45 -0
- package/components/SearchBox/dist/match-query.dev.js +61 -0
- package/components/SearchBox/index.vue +337 -0
- package/components/SearchBox/match-query.js +51 -0
- package/components/SearchBox/search.svg +1 -0
- package/components/SidebarGroup.vue +141 -0
- package/components/SidebarLink.vue +152 -0
- package/components/SidebarLinks.vue +106 -0
- package/components/SiderBarBottom.vue +134 -0
- package/components/Sticker.vue +64 -0
- package/components/Toc-top.vue +95 -0
- package/components/Toc.vue +165 -0
- package/config/copy.js +7 -0
- package/config/footer.js +195 -0
- package/config/i18n/index.js +2 -0
- package/config/navbar.js +163 -0
- package/config/redirectRouter.js +120 -0
- package/config/searchPage.js +48 -0
- package/config/siderbar/index.js +8 -0
- package/config/siderbar/uni-app.js +210 -0
- package/config/siderbar/uniCloud.js +55 -0
- package/config/toc.js +5 -0
- package/enhanceApp.js +142 -0
- package/global-components/CodeSimulator.vue +211 -0
- package/global-components/icons.js +647 -0
- package/global-components/iconsLayouts.vue +117 -0
- package/global-components/uniIcon.vue +85 -0
- package/global-components/uniicons.css +656 -0
- package/global-components/uniicons.ttf +0 -0
- package/index.js +152 -0
- package/layouts/404.vue +22 -0
- package/layouts/Layout.vue +238 -0
- package/layouts/SimpleLayout.vue +18 -0
- package/mixin/navInject.js +21 -0
- package/mixin/navProvider.js +65 -0
- package/mixin/toc.js +36 -0
- package/package.json +50 -0
- package/styles/custom-block.styl +336 -0
- package/styles/footer.styl +248 -0
- package/styles/index.styl +197 -0
- package/styles/navbar.styl +293 -0
- package/styles/palette.styl +9 -0
- package/util/index.js +317 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="search-box">
|
|
3
|
+
<input
|
|
4
|
+
ref="input"
|
|
5
|
+
aria-label="Search"
|
|
6
|
+
:value="query"
|
|
7
|
+
:class="{ focused: focused }"
|
|
8
|
+
:placeholder="placeholder"
|
|
9
|
+
class="custom-search"
|
|
10
|
+
autocomplete="off"
|
|
11
|
+
spellcheck="false"
|
|
12
|
+
@input="query = $event.target.value"
|
|
13
|
+
@focus="focused = true"
|
|
14
|
+
@blur="focused = false"
|
|
15
|
+
@keyup.enter="go(focusIndex)"
|
|
16
|
+
@keyup.up="onUp"
|
|
17
|
+
@keyup.down="onDown"
|
|
18
|
+
/>
|
|
19
|
+
<ul
|
|
20
|
+
v-if="showSuggestions"
|
|
21
|
+
class="suggestions"
|
|
22
|
+
:class="{ 'align-right': alignRight }"
|
|
23
|
+
style="z-index: 1"
|
|
24
|
+
@mouseleave="unfocus"
|
|
25
|
+
>
|
|
26
|
+
<template v-if="this.suggestions && this.suggestions.length">
|
|
27
|
+
<li
|
|
28
|
+
v-for="(s, i) in suggestions"
|
|
29
|
+
:key="i"
|
|
30
|
+
class="suggestion"
|
|
31
|
+
:class="{ focused: i === focusIndex }"
|
|
32
|
+
@mousedown="go(i)"
|
|
33
|
+
@mouseenter="focus(i)"
|
|
34
|
+
>
|
|
35
|
+
<a :href="s.path" @click.prevent>
|
|
36
|
+
<div class="suggestion-item">
|
|
37
|
+
<span class="page-title">{{ s.title || 'Document' }}</span>
|
|
38
|
+
<span v-if="s.header" class="header">{{ s.header.title }}</span>
|
|
39
|
+
</div>
|
|
40
|
+
</a>
|
|
41
|
+
</li>
|
|
42
|
+
</template>
|
|
43
|
+
<li v-else class="suggestion">
|
|
44
|
+
<div class="suggestion-item">
|
|
45
|
+
<span class="page-title">暂无结果</span>
|
|
46
|
+
</div>
|
|
47
|
+
</li>
|
|
48
|
+
</ul>
|
|
49
|
+
</div>
|
|
50
|
+
</template>
|
|
51
|
+
|
|
52
|
+
<script>
|
|
53
|
+
import matchQuery from './match-query';
|
|
54
|
+
/* global SEARCH_MAX_SUGGESTIONS, SEARCH_PATHS, SEARCH_HOTKEYS */
|
|
55
|
+
export default {
|
|
56
|
+
name: 'SearchBox',
|
|
57
|
+
|
|
58
|
+
data() {
|
|
59
|
+
return {
|
|
60
|
+
query: '',
|
|
61
|
+
focused: false,
|
|
62
|
+
focusIndex: 0,
|
|
63
|
+
placeholder: undefined,
|
|
64
|
+
SEARCH_PATHS: null,
|
|
65
|
+
SEARCH_HOTKEYS: ['s', '/'],
|
|
66
|
+
SEARCH_MAX_SUGGESTIONS: 5,
|
|
67
|
+
};
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
computed: {
|
|
71
|
+
showSuggestions() {
|
|
72
|
+
return this.focused && this.query && this.query.length; // && this.suggestions && this.suggestions.length;
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
suggestions() {
|
|
76
|
+
const query = this.query.trim().toLowerCase();
|
|
77
|
+
if (!query) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const { pages } = this.$site;
|
|
82
|
+
const max = this.$site.themeConfig.searchMaxSuggestions || this.SEARCH_MAX_SUGGESTIONS;
|
|
83
|
+
const localePath = this.$localePath;
|
|
84
|
+
const res = [];
|
|
85
|
+
for (let i = 0; i < pages.length; i++) {
|
|
86
|
+
if (res.length >= max) break;
|
|
87
|
+
const p = pages[i];
|
|
88
|
+
// filter out results that do not match current locale
|
|
89
|
+
if (this.getPageLocalePath(p) !== localePath) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// filter out results that do not match searchable paths
|
|
94
|
+
if (!this.isSearchable(p)) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (matchQuery(query, p)) {
|
|
99
|
+
res.push(p);
|
|
100
|
+
} else if (p.headers) {
|
|
101
|
+
for (let j = 0; j < p.headers.length; j++) {
|
|
102
|
+
if (res.length >= max) break;
|
|
103
|
+
const h = p.headers[j];
|
|
104
|
+
if (h.title && matchQuery(query, p, h.title)) {
|
|
105
|
+
res.push(
|
|
106
|
+
Object.assign({}, p, {
|
|
107
|
+
path: p.path + '#' + h.slug,
|
|
108
|
+
header: h,
|
|
109
|
+
})
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return res;
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
// make suggestions align right when there are not enough items
|
|
119
|
+
alignRight() {
|
|
120
|
+
const navCount = (this.$site.themeConfig.nav || []).length;
|
|
121
|
+
const repo = this.$site.repo ? 1 : 0;
|
|
122
|
+
return navCount + repo <= 2;
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
mounted() {
|
|
127
|
+
this.placeholder = this.$site.themeConfig.searchPlaceholder || '';
|
|
128
|
+
document.addEventListener('keydown', this.onHotkey);
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
beforeDestroy() {
|
|
132
|
+
document.removeEventListener('keydown', this.onHotkey);
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
methods: {
|
|
136
|
+
getPageLocalePath(page) {
|
|
137
|
+
for (const localePath in this.$site.locales || {}) {
|
|
138
|
+
if (localePath !== '/' && page.path.indexOf(localePath) === 0) {
|
|
139
|
+
return localePath;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return '/';
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
isSearchable(page) {
|
|
146
|
+
let searchPaths = this.SEARCH_PATHS;
|
|
147
|
+
|
|
148
|
+
// all paths searchables
|
|
149
|
+
if (searchPaths === null) {
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
searchPaths = Array.isArray(searchPaths) ? searchPaths : new Array(searchPaths);
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
searchPaths.filter(path => {
|
|
157
|
+
return page.path.match(path);
|
|
158
|
+
}).length > 0
|
|
159
|
+
);
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
onHotkey(event) {
|
|
163
|
+
if (event.srcElement === document.body && this.SEARCH_HOTKEYS.includes(event.key)) {
|
|
164
|
+
this.$refs.input.focus();
|
|
165
|
+
event.preventDefault();
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
onUp() {
|
|
170
|
+
if (this.showSuggestions) {
|
|
171
|
+
if (this.focusIndex > 0) {
|
|
172
|
+
this.focusIndex--;
|
|
173
|
+
} else {
|
|
174
|
+
this.focusIndex = this.suggestions.length - 1;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
onDown() {
|
|
180
|
+
if (this.showSuggestions) {
|
|
181
|
+
if (this.focusIndex < this.suggestions.length - 1) {
|
|
182
|
+
this.focusIndex++;
|
|
183
|
+
} else {
|
|
184
|
+
this.focusIndex = 0;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
go(i) {
|
|
190
|
+
if (!this.showSuggestions) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
this.$router.push(this.suggestions[i].path);
|
|
194
|
+
this.query = '';
|
|
195
|
+
this.focusIndex = 0;
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
focus(i) {
|
|
199
|
+
this.focusIndex = i;
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
unfocus() {
|
|
203
|
+
this.focusIndex = -1;
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
</script>
|
|
208
|
+
|
|
209
|
+
<style lang="stylus">
|
|
210
|
+
.search-box
|
|
211
|
+
display inline-block
|
|
212
|
+
position relative
|
|
213
|
+
margin-right 1rem
|
|
214
|
+
input
|
|
215
|
+
cursor text
|
|
216
|
+
width 10rem
|
|
217
|
+
height: 2rem
|
|
218
|
+
color lighten($textColor, 25%)
|
|
219
|
+
display inline-block
|
|
220
|
+
border 1px solid darken($borderColor, 10%)
|
|
221
|
+
border-radius 2rem
|
|
222
|
+
font-size 0.9rem
|
|
223
|
+
line-height 2rem
|
|
224
|
+
padding 0 0.5rem 0 2rem
|
|
225
|
+
outline none
|
|
226
|
+
transition all .2s ease
|
|
227
|
+
background #fff url(search.svg) 0.6rem 0.5rem no-repeat
|
|
228
|
+
background-size 1rem
|
|
229
|
+
&:focus
|
|
230
|
+
cursor auto
|
|
231
|
+
border-color $accentColor
|
|
232
|
+
.suggestions
|
|
233
|
+
background #fff
|
|
234
|
+
width 20rem
|
|
235
|
+
position absolute
|
|
236
|
+
top 2 rem
|
|
237
|
+
border 1px solid darken($borderColor, 10%)
|
|
238
|
+
border-radius 6px
|
|
239
|
+
padding 0.4rem
|
|
240
|
+
list-style-type none
|
|
241
|
+
&.align-right
|
|
242
|
+
right 0
|
|
243
|
+
.suggestion
|
|
244
|
+
line-height 1.4
|
|
245
|
+
padding 0.4rem 0.6rem
|
|
246
|
+
border-radius 4px
|
|
247
|
+
cursor pointer
|
|
248
|
+
a
|
|
249
|
+
white-space normal
|
|
250
|
+
color lighten($textColor, 35%)
|
|
251
|
+
.page-title
|
|
252
|
+
font-weight 600
|
|
253
|
+
.header
|
|
254
|
+
font-size 0.9em
|
|
255
|
+
margin-left 0.25em
|
|
256
|
+
&.focused
|
|
257
|
+
background-color #f3f4f5
|
|
258
|
+
a
|
|
259
|
+
color $accentColor
|
|
260
|
+
|
|
261
|
+
@media (max-width: $MQNarrow)
|
|
262
|
+
.search-box
|
|
263
|
+
input
|
|
264
|
+
cursor pointer
|
|
265
|
+
width 0
|
|
266
|
+
border-color transparent
|
|
267
|
+
position relative
|
|
268
|
+
&:focus
|
|
269
|
+
cursor text
|
|
270
|
+
left 0
|
|
271
|
+
width 10rem
|
|
272
|
+
|
|
273
|
+
// Match IE11
|
|
274
|
+
@media all and (-ms-high-contrast: none)
|
|
275
|
+
.search-box input
|
|
276
|
+
height 2rem
|
|
277
|
+
|
|
278
|
+
@media (max-width: $MQNarrow) and (min-width: $MQMobile)
|
|
279
|
+
.search-box
|
|
280
|
+
.suggestions
|
|
281
|
+
left 0
|
|
282
|
+
|
|
283
|
+
@media (max-width: $MQMobile)
|
|
284
|
+
.search-box
|
|
285
|
+
margin-right 0
|
|
286
|
+
input
|
|
287
|
+
left 1rem
|
|
288
|
+
.suggestions
|
|
289
|
+
right 0
|
|
290
|
+
|
|
291
|
+
@media (max-width: $MQMobileNarrow)
|
|
292
|
+
.search-box
|
|
293
|
+
.suggestions
|
|
294
|
+
width calc(100vw - 4rem)
|
|
295
|
+
input:focus
|
|
296
|
+
width 8rem
|
|
297
|
+
// by Lxh
|
|
298
|
+
.search-box
|
|
299
|
+
.suggestions
|
|
300
|
+
width 30rem
|
|
301
|
+
.suggestion
|
|
302
|
+
$li-border-color = #f0f0f0
|
|
303
|
+
border 1px solid $li-border-color
|
|
304
|
+
border-radius 0
|
|
305
|
+
padding 0
|
|
306
|
+
&:not(:last-child)
|
|
307
|
+
border-bottom none
|
|
308
|
+
&:first-child
|
|
309
|
+
border-top-left-radius 6px
|
|
310
|
+
border-top-right-radius 6px
|
|
311
|
+
&:last-child
|
|
312
|
+
border-bottom 1px solid $li-border-color
|
|
313
|
+
border-bottom-left-radius 6px
|
|
314
|
+
border-bottom-right-radius 6px
|
|
315
|
+
a
|
|
316
|
+
width 100%
|
|
317
|
+
.suggestion-item
|
|
318
|
+
width 100%
|
|
319
|
+
display flex
|
|
320
|
+
.page-title
|
|
321
|
+
flex 1
|
|
322
|
+
width 9rem
|
|
323
|
+
background-color #f7f7f7
|
|
324
|
+
padding 10px
|
|
325
|
+
display flex
|
|
326
|
+
flex-direction column
|
|
327
|
+
justify-content center
|
|
328
|
+
text-align center
|
|
329
|
+
word-break break-all
|
|
330
|
+
.header
|
|
331
|
+
flex 2
|
|
332
|
+
padding-left 20px
|
|
333
|
+
display flex
|
|
334
|
+
flex-direction column
|
|
335
|
+
justify-content center
|
|
336
|
+
text-align left
|
|
337
|
+
</style>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
|
|
2
|
+
import get from 'lodash/get'
|
|
3
|
+
|
|
4
|
+
export default (query, page, additionalStr = null) => {
|
|
5
|
+
let domain = get(page, 'title', '')
|
|
6
|
+
|
|
7
|
+
if (get(page, 'frontmatter.tags')) {
|
|
8
|
+
domain += ` ${page.frontmatter.tags.join(' ')}`
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (additionalStr) {
|
|
12
|
+
domain += ` ${additionalStr}`
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return matchTest(query, domain)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const matchTest = (query, domain) => {
|
|
19
|
+
const escapeRegExp = str => str.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
20
|
+
|
|
21
|
+
// eslint-disable-next-line no-control-regex
|
|
22
|
+
const nonASCIIRegExp = new RegExp('[^\x00-\x7F]')
|
|
23
|
+
|
|
24
|
+
const words = query
|
|
25
|
+
.split(/\s+/g)
|
|
26
|
+
.map(str => str.trim())
|
|
27
|
+
.filter(str => !!str)
|
|
28
|
+
|
|
29
|
+
if (!nonASCIIRegExp.test(query)) {
|
|
30
|
+
// if the query only has ASCII chars, treat as English
|
|
31
|
+
const hasTrailingSpace = query.endsWith(' ')
|
|
32
|
+
const searchRegex = new RegExp(
|
|
33
|
+
words
|
|
34
|
+
.map((word, index) => {
|
|
35
|
+
if (words.length === index + 1 && !hasTrailingSpace) {
|
|
36
|
+
// The last word - ok with the word being "startswith"-like
|
|
37
|
+
return `(?=.*\\b${escapeRegExp(word)})`
|
|
38
|
+
} else {
|
|
39
|
+
// Not the last word - expect the whole word exactly
|
|
40
|
+
return `(?=.*\\b${escapeRegExp(word)}\\b)`
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
.join('') + '.+',
|
|
44
|
+
'gi'
|
|
45
|
+
)
|
|
46
|
+
return searchRegex.test(domain)
|
|
47
|
+
} else {
|
|
48
|
+
// if the query has non-ASCII chars, treat as other languages
|
|
49
|
+
return words.some(word => domain.toLowerCase().indexOf(word) > -1)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="12" height="13"><g stroke-width="2" stroke="#aaa" fill="none"><path d="M11.29 11.71l-4-4"/><circle cx="5" cy="5" r="4"/></g></svg>
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<section
|
|
3
|
+
class="sidebar-group"
|
|
4
|
+
:class="[
|
|
5
|
+
{
|
|
6
|
+
collapsable,
|
|
7
|
+
'is-sub-group': depth !== 0
|
|
8
|
+
},
|
|
9
|
+
`depth-${depth}`
|
|
10
|
+
]"
|
|
11
|
+
>
|
|
12
|
+
<RouterLink
|
|
13
|
+
v-if="item.path"
|
|
14
|
+
class="sidebar-heading clickable"
|
|
15
|
+
:class="{
|
|
16
|
+
open,
|
|
17
|
+
'active': isActive($route, item.path)
|
|
18
|
+
}"
|
|
19
|
+
:to="item.path"
|
|
20
|
+
@click.native="$emit('toggle')"
|
|
21
|
+
>
|
|
22
|
+
<span>{{ item.title }}</span>
|
|
23
|
+
<span
|
|
24
|
+
v-if="collapsable"
|
|
25
|
+
class="arrow"
|
|
26
|
+
:class="open ? 'down' : 'right'"
|
|
27
|
+
/>
|
|
28
|
+
</RouterLink>
|
|
29
|
+
|
|
30
|
+
<p
|
|
31
|
+
v-else
|
|
32
|
+
class="sidebar-heading"
|
|
33
|
+
:class="{ open }"
|
|
34
|
+
@click="$emit('toggle')"
|
|
35
|
+
>
|
|
36
|
+
<span>{{ item.title }}</span>
|
|
37
|
+
<span
|
|
38
|
+
v-if="collapsable"
|
|
39
|
+
class="arrow"
|
|
40
|
+
:class="open ? 'down' : 'right'"
|
|
41
|
+
/>
|
|
42
|
+
</p>
|
|
43
|
+
|
|
44
|
+
<DropdownTransition>
|
|
45
|
+
<SidebarLinks
|
|
46
|
+
v-if="open || !collapsable"
|
|
47
|
+
class="sidebar-group-items"
|
|
48
|
+
:items="item.children"
|
|
49
|
+
:sidebar-depth="item.sidebarDepth"
|
|
50
|
+
:initial-open-group-index="item.initialOpenGroupIndex"
|
|
51
|
+
:depth="depth + 1"
|
|
52
|
+
/>
|
|
53
|
+
</DropdownTransition>
|
|
54
|
+
</section>
|
|
55
|
+
</template>
|
|
56
|
+
|
|
57
|
+
<script>
|
|
58
|
+
import { isActive } from '../util'
|
|
59
|
+
import DropdownTransition from '@theme/components/DropdownTransition.vue'
|
|
60
|
+
|
|
61
|
+
export default {
|
|
62
|
+
name: 'SidebarGroup',
|
|
63
|
+
|
|
64
|
+
components: {
|
|
65
|
+
DropdownTransition
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
props: [
|
|
69
|
+
'item',
|
|
70
|
+
'open',
|
|
71
|
+
'collapsable',
|
|
72
|
+
'depth'
|
|
73
|
+
],
|
|
74
|
+
|
|
75
|
+
// ref: https://vuejs.org/v2/guide/components-edge-cases.html#Circular-References-Between-Components
|
|
76
|
+
beforeCreate () {
|
|
77
|
+
this.$options.components.SidebarLinks = require('@theme/components/SidebarLinks.vue').default
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
methods: { isActive }
|
|
81
|
+
}
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
<style lang="stylus">
|
|
85
|
+
.sidebar-group
|
|
86
|
+
.sidebar-group
|
|
87
|
+
padding-left 0.5em
|
|
88
|
+
&:not(.collapsable)
|
|
89
|
+
& > .sidebar-heading:not(.clickable)
|
|
90
|
+
cursor auto
|
|
91
|
+
color inherit
|
|
92
|
+
// refine styles of nested sidebar groups
|
|
93
|
+
&.is-sub-group
|
|
94
|
+
padding-left 0
|
|
95
|
+
& > .sidebar-heading
|
|
96
|
+
font-size 0.95em
|
|
97
|
+
line-height 1.4
|
|
98
|
+
font-weight normal
|
|
99
|
+
padding-left 2rem
|
|
100
|
+
&:not(.clickable)
|
|
101
|
+
opacity 0.5
|
|
102
|
+
& > .sidebar-group-items
|
|
103
|
+
padding-left 1rem
|
|
104
|
+
& > li > .sidebar-link
|
|
105
|
+
font-size: 0.95em;
|
|
106
|
+
border-left none
|
|
107
|
+
&.depth-2
|
|
108
|
+
& > .sidebar-heading
|
|
109
|
+
border-left none
|
|
110
|
+
|
|
111
|
+
.sidebar-heading
|
|
112
|
+
color $textColor
|
|
113
|
+
transition color .15s ease
|
|
114
|
+
cursor pointer
|
|
115
|
+
font-size 1.1em
|
|
116
|
+
font-weight bold
|
|
117
|
+
// text-transform uppercase
|
|
118
|
+
padding 0.35rem 1.5rem 0.35rem 1.25rem
|
|
119
|
+
width 100%
|
|
120
|
+
box-sizing border-box
|
|
121
|
+
margin 0
|
|
122
|
+
border-left 0.25rem solid transparent
|
|
123
|
+
&.open, &:hover
|
|
124
|
+
color inherit
|
|
125
|
+
.arrow
|
|
126
|
+
position relative
|
|
127
|
+
top -0.12em
|
|
128
|
+
left 0.5em
|
|
129
|
+
&.clickable
|
|
130
|
+
&.active
|
|
131
|
+
font-weight 600
|
|
132
|
+
color $accentColor
|
|
133
|
+
border-left-color $accentColor
|
|
134
|
+
&:hover
|
|
135
|
+
color $accentColor
|
|
136
|
+
|
|
137
|
+
.sidebar-group-items
|
|
138
|
+
transition height .1s ease-out
|
|
139
|
+
font-size 0.95em
|
|
140
|
+
overflow hidden
|
|
141
|
+
</style>
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { isActive, hashRE, groupHeaders } from '../util'
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
functional: true,
|
|
6
|
+
|
|
7
|
+
props: ['item', 'sidebarDepth'],
|
|
8
|
+
|
|
9
|
+
render (h,
|
|
10
|
+
{
|
|
11
|
+
parent: {
|
|
12
|
+
$page,
|
|
13
|
+
$site,
|
|
14
|
+
$route,
|
|
15
|
+
$themeConfig,
|
|
16
|
+
$themeLocaleConfig
|
|
17
|
+
},
|
|
18
|
+
props: {
|
|
19
|
+
item,
|
|
20
|
+
sidebarDepth
|
|
21
|
+
}
|
|
22
|
+
}) {
|
|
23
|
+
// use custom active class matching logic
|
|
24
|
+
// due to edge case of paths ending with / + hash
|
|
25
|
+
const selfActive = isActive($route, item.path)
|
|
26
|
+
|
|
27
|
+
const maxDepth = [
|
|
28
|
+
$page.frontmatter.sidebarDepth,
|
|
29
|
+
sidebarDepth,
|
|
30
|
+
$themeLocaleConfig.sidebarDepth,
|
|
31
|
+
$themeConfig.sidebarDepth,
|
|
32
|
+
1
|
|
33
|
+
].find(depth => depth !== undefined)
|
|
34
|
+
|
|
35
|
+
// for sidebar: auto pages, a hash link should be active if one of its child
|
|
36
|
+
// matches
|
|
37
|
+
const active = item.type === 'auto'
|
|
38
|
+
? selfActive || item.children.some(c => isActive($route, item.basePath + '#' + c.slug))
|
|
39
|
+
: selfActive
|
|
40
|
+
const link = item.type === 'external'
|
|
41
|
+
? renderExternal(h, item.path, item.title || item.path)
|
|
42
|
+
: renderLink(h, item.path, item.title || item.path, active, undefined, item.headers)
|
|
43
|
+
|
|
44
|
+
const displayAllHeaders = $themeLocaleConfig.displayAllHeaders
|
|
45
|
+
|| $themeConfig.displayAllHeaders
|
|
46
|
+
|
|
47
|
+
if (item.type === 'auto') {
|
|
48
|
+
return [link, renderChildren(h, item.children, item.basePath, $route, maxDepth)]
|
|
49
|
+
} else if ((active || displayAllHeaders) && item.headers && !hashRE.test(item.path)) {
|
|
50
|
+
const children = groupHeaders(item.headers)
|
|
51
|
+
return [link, renderChildren(h, children, item.path, $route, maxDepth)]
|
|
52
|
+
} else {
|
|
53
|
+
return link
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let beforeActiveLinkText = ''
|
|
59
|
+
function renderLink (h, to, text, active, level, headers) {
|
|
60
|
+
let VNode
|
|
61
|
+
let firstRender
|
|
62
|
+
if(headers && active){
|
|
63
|
+
firstRender = beforeActiveLinkText !== text
|
|
64
|
+
beforeActiveLinkText = text
|
|
65
|
+
}
|
|
66
|
+
const component = {
|
|
67
|
+
props: {
|
|
68
|
+
to,
|
|
69
|
+
activeClass: '',
|
|
70
|
+
exactActiveClass: ''
|
|
71
|
+
},
|
|
72
|
+
class: {
|
|
73
|
+
active,
|
|
74
|
+
'sidebar-link': true,
|
|
75
|
+
'data-no-emphasize': headers && headers.some(item => item.level < 3)
|
|
76
|
+
},
|
|
77
|
+
nativeOn: {
|
|
78
|
+
click: (e) => {
|
|
79
|
+
if (firstRender) { firstRender = false; return; }
|
|
80
|
+
if (e.target.className.indexOf('data-no-emphasize') === -1) return;
|
|
81
|
+
const child = VNode.componentOptions.children[0].elm.parentElement.nextElementSibling
|
|
82
|
+
if(!child) return
|
|
83
|
+
const originDisplay = child.style.display
|
|
84
|
+
child.style.display = originDisplay === 'none' ? 'block' : 'none'
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (level > 2) {
|
|
90
|
+
component.style = {
|
|
91
|
+
'padding-left': level + 'rem'
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
VNode = h('RouterLink', component, text)
|
|
95
|
+
return VNode
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function renderChildren (h, children, path, route, maxDepth, depth = 1) {
|
|
99
|
+
if (!children || depth > maxDepth) return null
|
|
100
|
+
return h('ul', { class: 'sidebar-sub-headers' }, children.map(c => {
|
|
101
|
+
const active = isActive(route, path + '#' + c.slug)
|
|
102
|
+
return h('li', { class: 'sidebar-sub-header' }, [
|
|
103
|
+
renderLink(h, path + '#' + c.slug, c.title, active, c.level - 1),
|
|
104
|
+
renderChildren(h, c.children, path, route, maxDepth, depth + 1)
|
|
105
|
+
])
|
|
106
|
+
}))
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function renderExternal (h, to, text) {
|
|
110
|
+
return h('a', {
|
|
111
|
+
attrs: {
|
|
112
|
+
href: to,
|
|
113
|
+
target: '_blank',
|
|
114
|
+
rel: 'noopener noreferrer'
|
|
115
|
+
},
|
|
116
|
+
class: {
|
|
117
|
+
'sidebar-link': true
|
|
118
|
+
}
|
|
119
|
+
}, [text, h('OutboundLink')])
|
|
120
|
+
}
|
|
121
|
+
</script>
|
|
122
|
+
|
|
123
|
+
<style lang="stylus">
|
|
124
|
+
.sidebar .sidebar-sub-headers
|
|
125
|
+
padding-left 1rem
|
|
126
|
+
font-size 0.95em
|
|
127
|
+
|
|
128
|
+
a.sidebar-link
|
|
129
|
+
font-size 1em
|
|
130
|
+
font-weight 400
|
|
131
|
+
display inline-block
|
|
132
|
+
color $textColor
|
|
133
|
+
border-left 0.25rem solid transparent
|
|
134
|
+
padding 0.35rem 1rem 0.35rem 1.25rem
|
|
135
|
+
line-height 1.4
|
|
136
|
+
width: 100%
|
|
137
|
+
box-sizing: border-box
|
|
138
|
+
&:hover
|
|
139
|
+
color $accentColor
|
|
140
|
+
&.active
|
|
141
|
+
font-weight 600
|
|
142
|
+
color $accentColor
|
|
143
|
+
border-left-color $accentColor
|
|
144
|
+
.sidebar-group &
|
|
145
|
+
padding-left 2rem
|
|
146
|
+
.sidebar-sub-headers &
|
|
147
|
+
padding-top 0.25rem
|
|
148
|
+
padding-bottom 0.25rem
|
|
149
|
+
border-left none
|
|
150
|
+
&.active
|
|
151
|
+
font-weight 500
|
|
152
|
+
</style>
|