aboutsummaryrefslogtreecommitdiff
path: root/node_modules/vuepress/lib/default-theme
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/vuepress/lib/default-theme')
-rw-r--r--node_modules/vuepress/lib/default-theme/AlgoliaSearchBox.vue156
-rw-r--r--node_modules/vuepress/lib/default-theme/DropdownLink.vue181
-rw-r--r--node_modules/vuepress/lib/default-theme/DropdownTransition.vue33
-rw-r--r--node_modules/vuepress/lib/default-theme/Home.vue162
-rw-r--r--node_modules/vuepress/lib/default-theme/Layout.vue183
-rw-r--r--node_modules/vuepress/lib/default-theme/NavLink.vue49
-rw-r--r--node_modules/vuepress/lib/default-theme/NavLinks.vue151
-rw-r--r--node_modules/vuepress/lib/default-theme/Navbar.vue133
-rw-r--r--node_modules/vuepress/lib/default-theme/NotFound.vue26
-rw-r--r--node_modules/vuepress/lib/default-theme/Page.vue246
-rw-r--r--node_modules/vuepress/lib/default-theme/SWUpdatePopup.vue85
-rw-r--r--node_modules/vuepress/lib/default-theme/SearchBox.vue238
-rw-r--r--node_modules/vuepress/lib/default-theme/Sidebar.vue113
-rw-r--r--node_modules/vuepress/lib/default-theme/SidebarButton.vue28
-rw-r--r--node_modules/vuepress/lib/default-theme/SidebarGroup.vue77
-rw-r--r--node_modules/vuepress/lib/default-theme/SidebarLink.vue91
-rw-r--r--node_modules/vuepress/lib/default-theme/search.svg1
-rw-r--r--node_modules/vuepress/lib/default-theme/styles/arrow.styl22
-rw-r--r--node_modules/vuepress/lib/default-theme/styles/code.styl129
-rw-r--r--node_modules/vuepress/lib/default-theme/styles/config.styl22
-rw-r--r--node_modules/vuepress/lib/default-theme/styles/custom-blocks.styl28
-rw-r--r--node_modules/vuepress/lib/default-theme/styles/mobile.styl37
-rw-r--r--node_modules/vuepress/lib/default-theme/styles/nprogress.styl48
-rw-r--r--node_modules/vuepress/lib/default-theme/styles/theme.styl190
-rw-r--r--node_modules/vuepress/lib/default-theme/styles/toc.styl3
-rw-r--r--node_modules/vuepress/lib/default-theme/styles/wrapper.styl9
-rw-r--r--node_modules/vuepress/lib/default-theme/util.js216
27 files changed, 2657 insertions, 0 deletions
diff --git a/node_modules/vuepress/lib/default-theme/AlgoliaSearchBox.vue b/node_modules/vuepress/lib/default-theme/AlgoliaSearchBox.vue
new file mode 100644
index 00000000..0334ae0b
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/AlgoliaSearchBox.vue
@@ -0,0 +1,156 @@
+<template>
+ <form
+ id="search-form"
+ class="algolia-search-wrapper search-box"
+ >
+ <input
+ id="algolia-search-input"
+ class="search-query"
+ >
+ </form>
+</template>
+
+<script>
+export default {
+ props: ['options'],
+
+ mounted () {
+ this.initialize(this.options, this.$lang)
+ },
+
+ methods: {
+ initialize (userOptions, lang) {
+ Promise.all([
+ import(/* webpackChunkName: "docsearch" */ 'docsearch.js/dist/cdn/docsearch.min.js'),
+ import(/* webpackChunkName: "docsearch" */ 'docsearch.js/dist/cdn/docsearch.min.css')
+ ]).then(([docsearch]) => {
+ docsearch = docsearch.default
+ const { algoliaOptions = {}} = userOptions
+ docsearch(Object.assign(
+ {},
+ userOptions,
+ {
+ inputSelector: '#algolia-search-input',
+ // #697 Make docsearch work well at i18n mode.
+ algoliaOptions: Object.assign({
+ 'facetFilters': [`lang:${lang}`].concat(algoliaOptions.facetFilters || [])
+ }, algoliaOptions)
+ }
+ ))
+ })
+ },
+
+ update (options, lang) {
+ this.$el.innerHTML = '<input id="algolia-search-input" class="search-query">'
+ this.initialize(options, lang)
+ }
+ },
+
+ watch: {
+ $lang (newValue) {
+ this.update(this.options, newValue)
+ },
+
+ options (newValue) {
+ this.update(newValue, this.$lang)
+ }
+ }
+}
+</script>
+
+<style lang="stylus">
+@import './styles/config.styl'
+
+.algolia-search-wrapper
+ & > span
+ vertical-align middle
+ .algolia-autocomplete
+ line-height normal
+ .ds-dropdown-menu
+ background-color #fff
+ border 1px solid #999
+ border-radius 4px
+ font-size 16px
+ margin 6px 0 0
+ padding 4px
+ text-align left
+ &:before
+ border-color #999
+ [class*=ds-dataset-]
+ border none
+ padding 0
+ .ds-suggestions
+ margin-top 0
+ .ds-suggestion
+ border-bottom 1px solid $borderColor
+ .algolia-docsearch-suggestion--highlight
+ color #2c815b
+ .algolia-docsearch-suggestion
+ border-color $borderColor
+ padding 0
+ .algolia-docsearch-suggestion--category-header
+ padding 5px 10px
+ margin-top 0
+ background $accentColor
+ color #fff
+ font-weight 600
+ .algolia-docsearch-suggestion--highlight
+ background rgba(255, 255, 255, 0.6)
+ .algolia-docsearch-suggestion--wrapper
+ padding 0
+ .algolia-docsearch-suggestion--title
+ font-weight 600
+ margin-bottom 0
+ color $textColor
+ .algolia-docsearch-suggestion--subcategory-column
+ vertical-align top
+ padding 5px 7px 5px 5px
+ border-color $borderColor
+ background #f1f3f5
+ &:after
+ display none
+ .algolia-docsearch-suggestion--subcategory-column-text
+ color #555
+ .algolia-docsearch-footer
+ border-color $borderColor
+ .ds-cursor .algolia-docsearch-suggestion--content
+ background-color #e7edf3 !important
+ color $textColor
+
+@media (min-width: $MQMobile)
+ .algolia-search-wrapper
+ .algolia-autocomplete
+ .algolia-docsearch-suggestion
+ .algolia-docsearch-suggestion--subcategory-column
+ float none
+ width 150px
+ min-width 150px
+ display table-cell
+ .algolia-docsearch-suggestion--content
+ float none
+ display table-cell
+ width 100%
+ vertical-align top
+ .ds-dropdown-menu
+ min-width 515px !important
+
+@media (max-width: $MQMobile)
+ .algolia-search-wrapper
+ .ds-dropdown-menu
+ min-width calc(100vw - 4rem) !important
+ max-width calc(100vw - 4rem) !important
+ .algolia-docsearch-suggestion--wrapper
+ padding 5px 7px 5px 5px !important
+ .algolia-docsearch-suggestion--subcategory-column
+ padding 0 !important
+ background white !important
+ .algolia-docsearch-suggestion--subcategory-column-text:after
+ content " > "
+ font-size 10px
+ line-height 14.4px
+ display inline-block
+ width 5px
+ margin -3px 3px 0
+ vertical-align middle
+
+</style>
diff --git a/node_modules/vuepress/lib/default-theme/DropdownLink.vue b/node_modules/vuepress/lib/default-theme/DropdownLink.vue
new file mode 100644
index 00000000..e6000a60
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/DropdownLink.vue
@@ -0,0 +1,181 @@
+<template>
+ <div
+ class="dropdown-wrapper"
+ :class="{ open }"
+ >
+ <a
+ class="dropdown-title"
+ @click="toggle"
+ >
+ <span class="title">{{ item.text }}</span>
+ <span
+ class="arrow"
+ :class="open ? 'down' : 'right'"
+ ></span>
+ </a>
+
+ <DropdownTransition>
+ <ul
+ class="nav-dropdown"
+ v-show="open"
+ >
+ <li
+ class="dropdown-item"
+ :key="subItem.link || index"
+ v-for="(subItem, index) in item.items"
+ >
+ <h4 v-if="subItem.type === 'links'">{{ subItem.text }}</h4>
+
+ <ul
+ class="dropdown-subitem-wrapper"
+ v-if="subItem.type === 'links'"
+ >
+ <li
+ class="dropdown-subitem"
+ :key="childSubItem.link"
+ v-for="childSubItem in subItem.items"
+ >
+ <NavLink :item="childSubItem"/>
+ </li>
+ </ul>
+
+ <NavLink
+ v-else
+ :item="subItem"
+ />
+ </li>
+ </ul>
+ </DropdownTransition>
+ </div>
+</template>
+
+<script>
+import NavLink from './NavLink.vue'
+import DropdownTransition from './DropdownTransition.vue'
+
+export default {
+ components: { NavLink, DropdownTransition },
+
+ data () {
+ return {
+ open: false
+ }
+ },
+
+ props: {
+ item: {
+ required: true
+ }
+ },
+
+ methods: {
+ toggle () {
+ this.open = !this.open
+ }
+ }
+}
+</script>
+
+<style lang="stylus">
+@import './styles/config.styl'
+
+.dropdown-wrapper
+ cursor pointer
+ .dropdown-title
+ display block
+ &:hover
+ border-color transparent
+ .arrow
+ vertical-align middle
+ margin-top -1px
+ margin-left 0.4rem
+ .nav-dropdown
+ .dropdown-item
+ color inherit
+ line-height 1.7rem
+ h4
+ margin 0.45rem 0 0
+ border-top 1px solid #eee
+ padding 0.45rem 1.5rem 0 1.25rem
+ .dropdown-subitem-wrapper
+ padding 0
+ list-style none
+ .dropdown-subitem
+ font-size 0.9em
+ a
+ display block
+ line-height 1.7rem
+ position relative
+ border-bottom none
+ font-weight 400
+ margin-bottom 0
+ padding 0 1.5rem 0 1.25rem
+ &:hover
+ color $accentColor
+ &.router-link-active
+ color $accentColor
+ &::after
+ content ""
+ width 0
+ height 0
+ border-left 5px solid $accentColor
+ border-top 3px solid transparent
+ border-bottom 3px solid transparent
+ position absolute
+ top calc(50% - 2px)
+ left 9px
+ &:first-child h4
+ margin-top 0
+ padding-top 0
+ border-top 0
+
+@media (max-width: $MQMobile)
+ .dropdown-wrapper
+ &.open .dropdown-title
+ margin-bottom 0.5rem
+ .nav-dropdown
+ transition height .1s ease-out
+ overflow hidden
+ .dropdown-item
+ h4
+ border-top 0
+ margin-top 0
+ padding-top 0
+ h4, & > a
+ font-size 15px
+ line-height 2rem
+ .dropdown-subitem
+ font-size 14px
+ padding-left 1rem
+
+@media (min-width: $MQMobile)
+ .dropdown-wrapper
+ height 1.8rem
+ &:hover .nav-dropdown
+ // override the inline style.
+ display block !important
+ .dropdown-title .arrow
+ // make the arrow always down at desktop
+ border-left 4px solid transparent
+ border-right 4px solid transparent
+ border-top 6px solid $arrowBgColor
+ border-bottom 0
+ .nav-dropdown
+ display none
+ // Avoid height shaked by clicking
+ height auto !important
+ box-sizing border-box;
+ max-height calc(100vh - 2.7rem)
+ overflow-y auto
+ position absolute
+ top 100%
+ right 0
+ background-color #fff
+ padding 0.6rem 0
+ border 1px solid #ddd
+ border-bottom-color #ccc
+ text-align left
+ border-radius 0.25rem
+ white-space nowrap
+ margin 0
+</style>
diff --git a/node_modules/vuepress/lib/default-theme/DropdownTransition.vue b/node_modules/vuepress/lib/default-theme/DropdownTransition.vue
new file mode 100644
index 00000000..8c711a15
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/DropdownTransition.vue
@@ -0,0 +1,33 @@
+<template>
+ <transition
+ name="dropdown"
+ @enter="setHeight"
+ @after-enter="unsetHeight"
+ @before-leave="setHeight"
+ >
+ <slot/>
+ </transition>
+</template>
+
+<script>
+export default {
+ name: 'DropdownTransition',
+
+ methods: {
+ setHeight (items) {
+ // explicitly set height so that it can be transitioned
+ items.style.height = items.scrollHeight + 'px'
+ },
+
+ unsetHeight (items) {
+ items.style.height = ''
+ }
+ }
+}
+</script>
+
+<style lang="stylus">
+.dropdown-enter, .dropdown-leave-to
+ height 0 !important
+
+</style>
diff --git a/node_modules/vuepress/lib/default-theme/Home.vue b/node_modules/vuepress/lib/default-theme/Home.vue
new file mode 100644
index 00000000..a172eb9b
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/Home.vue
@@ -0,0 +1,162 @@
+<template>
+ <div class="home">
+ <div class="hero">
+ <img
+ v-if="data.heroImage"
+ :src="$withBase(data.heroImage)"
+ alt="hero"
+ >
+
+ <h1>{{ data.heroText || $title || 'Hello' }}</h1>
+
+ <p class="description">
+ {{ data.tagline || $description || 'Welcome to your VuePress site' }}
+ </p>
+
+ <p
+ class="action"
+ v-if="data.actionText && data.actionLink"
+ >
+ <NavLink
+ class="action-button"
+ :item="actionLink"
+ />
+ </p>
+ </div>
+
+ <div
+ class="features"
+ v-if="data.features && data.features.length"
+ >
+ <div
+ class="feature"
+ v-for="(feature, index) in data.features"
+ :key="index"
+ >
+ <h2>{{ feature.title }}</h2>
+ <p>{{ feature.details }}</p>
+ </div>
+ </div>
+
+ <Content custom/>
+
+ <div
+ class="footer"
+ v-if="data.footer"
+ >
+ {{ data.footer }}
+ </div>
+ </div>
+</template>
+
+<script>
+import NavLink from './NavLink.vue'
+
+export default {
+ components: { NavLink },
+
+ computed: {
+ data () {
+ return this.$page.frontmatter
+ },
+
+ actionLink () {
+ return {
+ link: this.data.actionLink,
+ text: this.data.actionText
+ }
+ }
+ }
+}
+</script>
+
+<style lang="stylus">
+@import './styles/config.styl'
+
+.home
+ padding $navbarHeight 2rem 0
+ max-width 960px
+ margin 0px auto
+ .hero
+ text-align center
+ img
+ max-height 280px
+ display block
+ margin 3rem auto 1.5rem
+ h1
+ font-size 3rem
+ h1, .description, .action
+ margin 1.8rem auto
+ .description
+ max-width 35rem
+ font-size 1.6rem
+ line-height 1.3
+ color lighten($textColor, 40%)
+ .action-button
+ display inline-block
+ font-size 1.2rem
+ color #fff
+ background-color $accentColor
+ padding 0.8rem 1.6rem
+ border-radius 4px
+ transition background-color .1s ease
+ box-sizing border-box
+ border-bottom 1px solid darken($accentColor, 10%)
+ &:hover
+ background-color lighten($accentColor, 10%)
+ .features
+ border-top 1px solid $borderColor
+ padding 1.2rem 0
+ margin-top 2.5rem
+ display flex
+ flex-wrap wrap
+ align-items flex-start
+ align-content stretch
+ justify-content space-between
+ .feature
+ flex-grow 1
+ flex-basis 30%
+ max-width 30%
+ h2
+ font-size 1.4rem
+ font-weight 500
+ border-bottom none
+ padding-bottom 0
+ color lighten($textColor, 10%)
+ p
+ color lighten($textColor, 25%)
+ .footer
+ padding 2.5rem
+ border-top 1px solid $borderColor
+ text-align center
+ color lighten($textColor, 25%)
+
+@media (max-width: $MQMobile)
+ .home
+ .features
+ flex-direction column
+ .feature
+ max-width 100%
+ padding 0 2.5rem
+
+@media (max-width: $MQMobileNarrow)
+ .home
+ padding-left 1.5rem
+ padding-right 1.5rem
+ .hero
+ img
+ max-height 210px
+ margin 2rem auto 1.2rem
+ h1
+ font-size 2rem
+ h1, .description, .action
+ margin 1.2rem auto
+ .description
+ font-size 1.2rem
+ .action-button
+ font-size 1rem
+ padding 0.6rem 1.2rem
+ .feature
+ h2
+ font-size 1.25rem
+</style>
diff --git a/node_modules/vuepress/lib/default-theme/Layout.vue b/node_modules/vuepress/lib/default-theme/Layout.vue
new file mode 100644
index 00000000..ee2e6abe
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/Layout.vue
@@ -0,0 +1,183 @@
+<template>
+ <div
+ class="theme-container"
+ :class="pageClasses"
+ @touchstart="onTouchStart"
+ @touchend="onTouchEnd"
+ >
+ <Navbar
+ v-if="shouldShowNavbar"
+ @toggle-sidebar="toggleSidebar"
+ />
+
+ <div
+ class="sidebar-mask"
+ @click="toggleSidebar(false)"
+ ></div>
+
+ <Sidebar
+ :items="sidebarItems"
+ @toggle-sidebar="toggleSidebar"
+ >
+ <slot
+ name="sidebar-top"
+ slot="top"
+ />
+ <slot
+ name="sidebar-bottom"
+ slot="bottom"
+ />
+ </Sidebar>
+
+ <div
+ class="custom-layout"
+ v-if="$page.frontmatter.layout"
+ >
+ <component :is="$page.frontmatter.layout"/>
+ </div>
+
+ <Home v-else-if="$page.frontmatter.home"/>
+
+ <Page
+ v-else
+ :sidebar-items="sidebarItems"
+ >
+ <slot
+ name="page-top"
+ slot="top"
+ />
+ <slot
+ name="page-bottom"
+ slot="bottom"
+ />
+ </Page>
+
+ <SWUpdatePopup :updateEvent="swUpdateEvent"/>
+ </div>
+</template>
+
+<script>
+import Vue from 'vue'
+import nprogress from 'nprogress'
+import Home from './Home.vue'
+import Navbar from './Navbar.vue'
+import Page from './Page.vue'
+import Sidebar from './Sidebar.vue'
+import SWUpdatePopup from './SWUpdatePopup.vue'
+import { resolveSidebarItems } from './util'
+
+export default {
+ components: { Home, Page, Sidebar, Navbar, SWUpdatePopup },
+
+ data () {
+ return {
+ isSidebarOpen: false,
+ swUpdateEvent: null
+ }
+ },
+
+ computed: {
+ shouldShowNavbar () {
+ const { themeConfig } = this.$site
+ const { frontmatter } = this.$page
+ if (
+ frontmatter.navbar === false ||
+ themeConfig.navbar === false) {
+ return false
+ }
+ return (
+ this.$title ||
+ themeConfig.logo ||
+ themeConfig.repo ||
+ themeConfig.nav ||
+ this.$themeLocaleConfig.nav
+ )
+ },
+
+ shouldShowSidebar () {
+ const { frontmatter } = this.$page
+ return (
+ !frontmatter.layout &&
+ !frontmatter.home &&
+ frontmatter.sidebar !== false &&
+ this.sidebarItems.length
+ )
+ },
+
+ sidebarItems () {
+ return resolveSidebarItems(
+ this.$page,
+ this.$route,
+ this.$site,
+ this.$localePath
+ )
+ },
+
+ pageClasses () {
+ const userPageClass = this.$page.frontmatter.pageClass
+ return [
+ {
+ 'no-navbar': !this.shouldShowNavbar,
+ 'sidebar-open': this.isSidebarOpen,
+ 'no-sidebar': !this.shouldShowSidebar
+ },
+ userPageClass
+ ]
+ }
+ },
+
+ mounted () {
+ window.addEventListener('scroll', this.onScroll)
+
+ // configure progress bar
+ nprogress.configure({ showSpinner: false })
+
+ this.$router.beforeEach((to, from, next) => {
+ if (to.path !== from.path && !Vue.component(to.name)) {
+ nprogress.start()
+ }
+ next()
+ })
+
+ this.$router.afterEach(() => {
+ nprogress.done()
+ this.isSidebarOpen = false
+ })
+
+ this.$on('sw-updated', this.onSWUpdated)
+ },
+
+ methods: {
+ toggleSidebar (to) {
+ this.isSidebarOpen = typeof to === 'boolean' ? to : !this.isSidebarOpen
+ },
+
+ // side swipe
+ onTouchStart (e) {
+ this.touchStart = {
+ x: e.changedTouches[0].clientX,
+ y: e.changedTouches[0].clientY
+ }
+ },
+
+ onTouchEnd (e) {
+ const dx = e.changedTouches[0].clientX - this.touchStart.x
+ const dy = e.changedTouches[0].clientY - this.touchStart.y
+ if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 40) {
+ if (dx > 0 && this.touchStart.x <= 80) {
+ this.toggleSidebar(true)
+ } else {
+ this.toggleSidebar(false)
+ }
+ }
+ },
+
+ onSWUpdated (e) {
+ this.swUpdateEvent = e
+ }
+ }
+}
+</script>
+
+<style src="prismjs/themes/prism-tomorrow.css"></style>
+<style src="./styles/theme.styl" lang="stylus"></style>
diff --git a/node_modules/vuepress/lib/default-theme/NavLink.vue b/node_modules/vuepress/lib/default-theme/NavLink.vue
new file mode 100644
index 00000000..d9fa4886
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/NavLink.vue
@@ -0,0 +1,49 @@
+<template>
+ <router-link
+ class="nav-link"
+ :to="link"
+ v-if="!isExternal(link)"
+ :exact="exact"
+ >{{ item.text }}</router-link>
+ <a
+ v-else
+ :href="link"
+ class="nav-link external"
+ :target="isMailto(link) || isTel(link) ? null : '_blank'"
+ :rel="isMailto(link) || isTel(link) ? null : 'noopener noreferrer'"
+ >
+ {{ item.text }}
+ <OutboundLink/>
+ </a>
+</template>
+
+<script>
+import { isExternal, isMailto, isTel, ensureExt } from './util'
+
+export default {
+ props: {
+ item: {
+ required: true
+ }
+ },
+
+ computed: {
+ link () {
+ return ensureExt(this.item.link)
+ },
+
+ exact () {
+ if (this.$site.locales) {
+ return Object.keys(this.$site.locales).some(rootLink => rootLink === this.link)
+ }
+ return this.link === '/'
+ }
+ },
+
+ methods: {
+ isExternal,
+ isMailto,
+ isTel
+ }
+}
+</script>
diff --git a/node_modules/vuepress/lib/default-theme/NavLinks.vue b/node_modules/vuepress/lib/default-theme/NavLinks.vue
new file mode 100644
index 00000000..4037f288
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/NavLinks.vue
@@ -0,0 +1,151 @@
+<template>
+ <nav
+ class="nav-links"
+ v-if="userLinks.length || repoLink"
+ >
+ <!-- user links -->
+ <div
+ class="nav-item"
+ v-for="item in userLinks"
+ :key="item.link"
+ >
+ <DropdownLink
+ v-if="item.type === 'links'"
+ :item="item"
+ />
+ <NavLink
+ v-else
+ :item="item"
+ />
+ </div>
+
+ <!-- repo link -->
+ <a
+ v-if="repoLink"
+ :href="repoLink"
+ class="repo-link"
+ target="_blank"
+ rel="noopener noreferrer"
+ >
+ {{ repoLabel }}
+ <OutboundLink/>
+ </a>
+ </nav>
+</template>
+
+<script>
+import DropdownLink from './DropdownLink.vue'
+import { resolveNavLinkItem } from './util'
+import NavLink from './NavLink.vue'
+
+export default {
+ components: { NavLink, DropdownLink },
+
+ computed: {
+ userNav () {
+ return this.$themeLocaleConfig.nav || this.$site.themeConfig.nav || []
+ },
+
+ nav () {
+ const { locales } = this.$site
+ if (locales && Object.keys(locales).length > 1) {
+ const currentLink = this.$page.path
+ const routes = this.$router.options.routes
+ const themeLocales = this.$site.themeConfig.locales || {}
+ const languageDropdown = {
+ text: this.$themeLocaleConfig.selectText || 'Languages',
+ items: Object.keys(locales).map(path => {
+ const locale = locales[path]
+ const text = themeLocales[path] && themeLocales[path].label || locale.lang
+ let link
+ // Stay on the current page
+ if (locale.lang === this.$lang) {
+ link = currentLink
+ } else {
+ // Try to stay on the same page
+ link = currentLink.replace(this.$localeConfig.path, path)
+ // fallback to homepage
+ if (!routes.some(route => route.path === link)) {
+ link = path
+ }
+ }
+ return { text, link }
+ })
+ }
+ return [...this.userNav, languageDropdown]
+ }
+ return this.userNav
+ },
+
+ userLinks () {
+ return (this.nav || []).map(link => {
+ return Object.assign(resolveNavLinkItem(link), {
+ items: (link.items || []).map(resolveNavLinkItem)
+ })
+ })
+ },
+
+ repoLink () {
+ const { repo } = this.$site.themeConfig
+ if (repo) {
+ return /^https?:/.test(repo)
+ ? repo
+ : `https://github.com/${repo}`
+ }
+ },
+
+ repoLabel () {
+ if (!this.repoLink) return
+ if (this.$site.themeConfig.repoLabel) {
+ return this.$site.themeConfig.repoLabel
+ }
+
+ const repoHost = this.repoLink.match(/^https?:\/\/[^/]+/)[0]
+ const platforms = ['GitHub', 'GitLab', 'Bitbucket']
+ for (let i = 0; i < platforms.length; i++) {
+ const platform = platforms[i]
+ if (new RegExp(platform, 'i').test(repoHost)) {
+ return platform
+ }
+ }
+
+ return 'Source'
+ }
+ }
+}
+</script>
+
+<style lang="stylus">
+@import './styles/config.styl'
+
+.nav-links
+ display inline-block
+ a
+ line-height 1.4rem
+ color inherit
+ &:hover, &.router-link-active
+ color $accentColor
+ .nav-item
+ position relative
+ display inline-block
+ margin-left 1.5rem
+ line-height 2rem
+ &:first-child
+ margin-left 0
+ .repo-link
+ margin-left 1.5rem
+
+@media (max-width: $MQMobile)
+ .nav-links
+ .nav-item, .repo-link
+ margin-left 0
+
+@media (min-width: $MQMobile)
+ .nav-links a
+ &:hover, &.router-link-active
+ color $textColor
+ .nav-item > a:not(.external)
+ &:hover, &.router-link-active
+ margin-bottom -2px
+ border-bottom 2px solid lighten($accentColor, 8%)
+</style>
diff --git a/node_modules/vuepress/lib/default-theme/Navbar.vue b/node_modules/vuepress/lib/default-theme/Navbar.vue
new file mode 100644
index 00000000..12795665
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/Navbar.vue
@@ -0,0 +1,133 @@
+<template>
+ <header class="navbar">
+ <SidebarButton @toggle-sidebar="$emit('toggle-sidebar')"/>
+
+ <router-link
+ :to="$localePath"
+ class="home-link"
+ >
+ <img
+ class="logo"
+ v-if="$site.themeConfig.logo"
+ :src="$withBase($site.themeConfig.logo)"
+ :alt="$siteTitle"
+ >
+ <span
+ ref="siteName"
+ class="site-name"
+ v-if="$siteTitle"
+ :class="{ 'can-hide': $site.themeConfig.logo }"
+ >{{ $siteTitle }}</span>
+ </router-link>
+
+ <div
+ class="links"
+ :style="{
+ 'max-width': linksWrapMaxWidth + 'px'
+ }"
+ >
+ <AlgoliaSearchBox
+ v-if="isAlgoliaSearch"
+ :options="algolia"
+ />
+ <SearchBox v-else-if="$site.themeConfig.search !== false"/>
+ <NavLinks class="can-hide"/>
+ </div>
+ </header>
+</template>
+
+<script>
+import SidebarButton from './SidebarButton.vue'
+import AlgoliaSearchBox from '@AlgoliaSearchBox'
+import SearchBox from './SearchBox.vue'
+import NavLinks from './NavLinks.vue'
+
+export default {
+ components: { SidebarButton, NavLinks, SearchBox, AlgoliaSearchBox },
+
+ data () {
+ return {
+ linksWrapMaxWidth: null
+ }
+ },
+
+ mounted () {
+ const MOBILE_DESKTOP_BREAKPOINT = 719 // refer to config.styl
+ const NAVBAR_VERTICAL_PADDING = parseInt(css(this.$el, 'paddingLeft')) + parseInt(css(this.$el, 'paddingRight'))
+ const handleLinksWrapWidth = () => {
+ if (document.documentElement.clientWidth < MOBILE_DESKTOP_BREAKPOINT) {
+ this.linksWrapMaxWidth = null
+ } else {
+ this.linksWrapMaxWidth = this.$el.offsetWidth - NAVBAR_VERTICAL_PADDING -
+ (this.$refs.siteName && this.$refs.siteName.offsetWidth || 0)
+ }
+ }
+ handleLinksWrapWidth()
+ window.addEventListener('resize', handleLinksWrapWidth, false)
+ },
+
+ computed: {
+ algolia () {
+ return this.$themeLocaleConfig.algolia || this.$site.themeConfig.algolia || {}
+ },
+
+ isAlgoliaSearch () {
+ return this.algolia && this.algolia.apiKey && this.algolia.indexName
+ }
+ }
+}
+
+function css (el, property) {
+ // NOTE: Known bug, will return 'auto' if style value is 'auto'
+ const win = el.ownerDocument.defaultView
+ // null means not to return pseudo styles
+ return win.getComputedStyle(el, null)[property]
+}
+</script>
+
+<style lang="stylus">
+@import './styles/config.styl'
+
+$navbar-vertical-padding = 0.7rem
+$navbar-horizontal-padding = 1.5rem
+
+.navbar
+ padding $navbar-vertical-padding $navbar-horizontal-padding
+ line-height $navbarHeight - 1.4rem
+ position relative
+ a, span, img
+ display inline-block
+ .logo
+ height $navbarHeight - 1.4rem
+ min-width $navbarHeight - 1.4rem
+ margin-right 0.8rem
+ vertical-align top
+ .site-name
+ font-size 1.3rem
+ font-weight 600
+ color $textColor
+ position relative
+ .links
+ padding-left 1.5rem
+ box-sizing border-box
+ background-color white
+ white-space nowrap
+ font-size 0.9rem
+ position absolute
+ right $navbar-horizontal-padding
+ top $navbar-vertical-padding
+ display flex
+ .search-box
+ flex: 0 0 auto
+ vertical-align top
+ .nav-links
+ flex 1
+
+@media (max-width: $MQMobile)
+ .navbar
+ padding-left 4rem
+ .can-hide
+ display none
+ .links
+ padding-left 1.5rem
+</style>
diff --git a/node_modules/vuepress/lib/default-theme/NotFound.vue b/node_modules/vuepress/lib/default-theme/NotFound.vue
new file mode 100644
index 00000000..6aefe797
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/NotFound.vue
@@ -0,0 +1,26 @@
+<template>
+ <div class="theme-container">
+ <div class="content">
+ <h1>404</h1>
+ <blockquote>{{ getMsg() }}</blockquote>
+ <router-link to="/">Take me home.</router-link>
+ </div>
+ </div>
+</template>
+
+<script>
+const msgs = [
+ `There's nothing here.`,
+ `How did we get here?`,
+ `That's a Four-Oh-Four.`,
+ `Looks like we've got some broken links.`
+]
+
+export default {
+ methods: {
+ getMsg () {
+ return msgs[Math.floor(Math.random() * msgs.length)]
+ }
+ }
+}
+</script>
diff --git a/node_modules/vuepress/lib/default-theme/Page.vue b/node_modules/vuepress/lib/default-theme/Page.vue
new file mode 100644
index 00000000..37d65b41
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/Page.vue
@@ -0,0 +1,246 @@
+<template>
+ <div class="page">
+ <slot name="top"/>
+
+ <Content :custom="false"/>
+
+ <div class="page-edit">
+ <div
+ class="edit-link"
+ v-if="editLink"
+ >
+ <a
+ :href="editLink"
+ target="_blank"
+ rel="noopener noreferrer"
+ >{{ editLinkText }}</a>
+ <OutboundLink/>
+ </div>
+
+ <div
+ class="last-updated"
+ v-if="lastUpdated"
+ >
+ <span class="prefix">{{ lastUpdatedText }}: </span>
+ <span class="time">{{ lastUpdated }}</span>
+ </div>
+ </div>
+
+ <div class="page-nav" v-if="prev || next">
+ <p class="inner">
+ <span
+ v-if="prev"
+ class="prev"
+ >
+ ←
+ <router-link
+ v-if="prev"
+ class="prev"
+ :to="prev.path"
+ >
+ {{ prev.title || prev.path }}
+ </router-link>
+ </span>
+
+ <span
+ v-if="next"
+ class="next"
+ >
+ <router-link
+ v-if="next"
+ :to="next.path"
+ >
+ {{ next.title || next.path }}
+ </router-link>
+ →
+ </span>
+ </p>
+ </div>
+
+ <slot name="bottom"/>
+ </div>
+</template>
+
+<script>
+import { resolvePage, normalize, outboundRE, endingSlashRE } from './util'
+
+export default {
+ props: ['sidebarItems'],
+
+ computed: {
+ lastUpdated () {
+ if (this.$page.lastUpdated) {
+ return new Date(this.$page.lastUpdated).toLocaleString(this.$lang)
+ }
+ },
+
+ lastUpdatedText () {
+ if (typeof this.$themeLocaleConfig.lastUpdated === 'string') {
+ return this.$themeLocaleConfig.lastUpdated
+ }
+ if (typeof this.$site.themeConfig.lastUpdated === 'string') {
+ return this.$site.themeConfig.lastUpdated
+ }
+ return 'Last Updated'
+ },
+
+ prev () {
+ const prev = this.$page.frontmatter.prev
+ if (prev === false) {
+ return
+ } else if (prev) {
+ return resolvePage(this.$site.pages, prev, this.$route.path)
+ } else {
+ return resolvePrev(this.$page, this.sidebarItems)
+ }
+ },
+
+ next () {
+ const next = this.$page.frontmatter.next
+ if (next === false) {
+ return
+ } else if (next) {
+ return resolvePage(this.$site.pages, next, this.$route.path)
+ } else {
+ return resolveNext(this.$page, this.sidebarItems)
+ }
+ },
+
+ editLink () {
+ if (this.$page.frontmatter.editLink === false) {
+ return
+ }
+ const {
+ repo,
+ editLinks,
+ docsDir = '',
+ docsBranch = 'master',
+ docsRepo = repo
+ } = this.$site.themeConfig
+
+ let path = normalize(this.$page.path)
+ if (endingSlashRE.test(path)) {
+ path += 'README.md'
+ } else {
+ path += '.md'
+ }
+ if (docsRepo && editLinks) {
+ return this.createEditLink(repo, docsRepo, docsDir, docsBranch, path)
+ }
+ },
+
+ editLinkText () {
+ return (
+ this.$themeLocaleConfig.editLinkText ||
+ this.$site.themeConfig.editLinkText ||
+ `Edit this page`
+ )
+ }
+ },
+
+ methods: {
+ createEditLink (repo, docsRepo, docsDir, docsBranch, path) {
+ const bitbucket = /bitbucket.org/
+ if (bitbucket.test(repo)) {
+ const base = outboundRE.test(docsRepo)
+ ? docsRepo
+ : repo
+ return (
+ base.replace(endingSlashRE, '') +
+ `/${docsBranch}` +
+ (docsDir ? '/' + docsDir.replace(endingSlashRE, '') : '') +
+ path +
+ `?mode=edit&spa=0&at=${docsBranch}&fileviewer=file-view-default`
+ )
+ }
+
+ const base = outboundRE.test(docsRepo)
+ ? docsRepo
+ : `https://github.com/${docsRepo}`
+
+ return (
+ base.replace(endingSlashRE, '') +
+ `/edit/${docsBranch}` +
+ (docsDir ? '/' + docsDir.replace(endingSlashRE, '') : '') +
+ path
+ )
+ }
+ }
+}
+
+function resolvePrev (page, items) {
+ return find(page, items, -1)
+}
+
+function resolveNext (page, items) {
+ return find(page, items, 1)
+}
+
+function find (page, items, offset) {
+ const res = []
+ items.forEach(item => {
+ if (item.type === 'group') {
+ res.push(...item.children || [])
+ } else {
+ res.push(item)
+ }
+ })
+ for (let i = 0; i < res.length; i++) {
+ const cur = res[i]
+ if (cur.type === 'page' && cur.path === page.path) {
+ return res[i + offset]
+ }
+ }
+}
+</script>
+
+<style lang="stylus">
+@import './styles/config.styl'
+@require './styles/wrapper.styl'
+
+.page
+ padding-bottom 2rem
+
+.page-edit
+ @extend $wrapper
+ padding-top 1rem
+ padding-bottom 1rem
+ overflow auto
+ .edit-link
+ display inline-block
+ a
+ color lighten($textColor, 25%)
+ margin-right 0.25rem
+ .last-updated
+ float right
+ font-size 0.9em
+ .prefix
+ font-weight 500
+ color lighten($textColor, 25%)
+ .time
+ font-weight 400
+ color #aaa
+
+.page-nav
+ @extend $wrapper
+ padding-top 1rem
+ padding-bottom 0
+ .inner
+ min-height 2rem
+ margin-top 0
+ border-top 1px solid $borderColor
+ padding-top 1rem
+ overflow auto // clear float
+ .next
+ float right
+
+@media (max-width: $MQMobile)
+ .page-edit
+ .edit-link
+ margin-bottom .5rem
+ .last-updated
+ font-size .8em
+ float none
+ text-align left
+
+</style>
diff --git a/node_modules/vuepress/lib/default-theme/SWUpdatePopup.vue b/node_modules/vuepress/lib/default-theme/SWUpdatePopup.vue
new file mode 100644
index 00000000..b224db31
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/SWUpdatePopup.vue
@@ -0,0 +1,85 @@
+<template>
+ <transition name="sw-update-popup">
+ <div
+ v-if="enabled"
+ class="sw-update-popup"
+ >
+ {{message}}<br>
+ <button @click="reload">{{buttonText}}</button>
+ </div>
+ </transition>
+</template>
+
+<script>
+export default {
+ props: {
+ updateEvent: {
+ type: Object,
+ default: null
+ }
+ },
+
+ computed: {
+ popupConfig () {
+ for (const config of [this.$themeLocaleConfig, this.$site.themeConfig]) {
+ const sw = config.serviceWorker
+ if (sw && sw.updatePopup) {
+ return typeof sw.updatePopup === 'object' ? sw.updatePopup : {}
+ }
+ }
+ return null
+ },
+
+ enabled () {
+ return Boolean(this.popupConfig && this.updateEvent)
+ },
+
+ message () {
+ const c = this.popupConfig
+ return (c && c.message) || 'New content is available.'
+ },
+
+ buttonText () {
+ const c = this.popupConfig
+ return (c && c.buttonText) || 'Refresh'
+ }
+ },
+
+ methods: {
+ reload () {
+ if (this.updateEvent) {
+ this.updateEvent.skipWaiting().then(() => {
+ location.reload(true)
+ })
+ this.updateEvent = null
+ }
+ }
+ }
+}
+</script>
+
+<style lang="stylus">
+@import './styles/config.styl'
+
+.sw-update-popup
+ position fixed
+ right 1em
+ bottom 1em
+ padding 1em
+ border 1px solid $accentColor
+ border-radius 3px
+ background #fff
+ box-shadow 0 4px 16px rgba(0, 0, 0, 0.5)
+ text-align center
+
+ button
+ margin-top 0.5em
+ padding 0.25em 2em
+
+.sw-update-popup-enter-active, .sw-update-popup-leave-active
+ transition opacity 0.3s, transform 0.3s
+
+.sw-update-popup-enter, .sw-update-popup-leave-to
+ opacity 0
+ transform translate(0, 50%) scale(0.5)
+</style>
diff --git a/node_modules/vuepress/lib/default-theme/SearchBox.vue b/node_modules/vuepress/lib/default-theme/SearchBox.vue
new file mode 100644
index 00000000..98608552
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/SearchBox.vue
@@ -0,0 +1,238 @@
+<template>
+ <div class="search-box">
+ <input
+ @input="query = $event.target.value"
+ aria-label="Search"
+ :value="query"
+ :class="{ 'focused': focused }"
+ autocomplete="off"
+ spellcheck="false"
+ @focus="focused = true"
+ @blur="focused = false"
+ @keyup.enter="go(focusIndex)"
+ @keyup.up="onUp"
+ @keyup.down="onDown"
+ >
+ <ul
+ class="suggestions"
+ v-if="showSuggestions"
+ :class="{ 'align-right': alignRight }"
+ @mouseleave="unfocus"
+ >
+ <li
+ class="suggestion"
+ v-for="(s, i) in suggestions"
+ :class="{ focused: i === focusIndex }"
+ @mousedown="go(i)"
+ @mouseenter="focus(i)"
+ >
+ <a :href="s.path" @click.prevent>
+ <span class="page-title">{{ s.title || s.path }}</span>
+ <span v-if="s.header" class="header">&gt; {{ s.header.title }}</span>
+ </a>
+ </li>
+ </ul>
+ </div>
+</template>
+
+<script>
+export default {
+ data () {
+ return {
+ query: '',
+ focused: false,
+ focusIndex: 0
+ }
+ },
+
+ computed: {
+ showSuggestions () {
+ return (
+ this.focused &&
+ this.suggestions &&
+ this.suggestions.length
+ )
+ },
+
+ suggestions () {
+ const query = this.query.trim().toLowerCase()
+ if (!query) {
+ return
+ }
+
+ const { pages, themeConfig } = this.$site
+ const max = themeConfig.searchMaxSuggestions || 5
+ const localePath = this.$localePath
+ const matches = item => (
+ item.title &&
+ item.title.toLowerCase().indexOf(query) > -1
+ )
+ const res = []
+ for (let i = 0; i < pages.length; i++) {
+ if (res.length >= max) break
+ const p = pages[i]
+ // filter out results that do not match current locale
+ if (this.getPageLocalePath(p) !== localePath) {
+ continue
+ }
+ if (matches(p)) {
+ res.push(p)
+ } else if (p.headers) {
+ for (let j = 0; j < p.headers.length; j++) {
+ if (res.length >= max) break
+ const h = p.headers[j]
+ if (matches(h)) {
+ res.push(Object.assign({}, p, {
+ path: p.path + '#' + h.slug,
+ header: h
+ }))
+ }
+ }
+ }
+ }
+ return res
+ },
+
+ // make suggestions align right when there are not enough items
+ alignRight () {
+ const navCount = (this.$site.themeConfig.nav || []).length
+ const repo = this.$site.repo ? 1 : 0
+ return navCount + repo <= 2
+ }
+ },
+
+ methods: {
+ getPageLocalePath (page) {
+ for (const localePath in this.$site.locales || {}) {
+ if (localePath !== '/' && page.path.indexOf(localePath) === 0) {
+ return localePath
+ }
+ }
+ return '/'
+ },
+
+ onUp () {
+ if (this.showSuggestions) {
+ if (this.focusIndex > 0) {
+ this.focusIndex--
+ } else {
+ this.focusIndex = this.suggestions.length - 1
+ }
+ }
+ },
+
+ onDown () {
+ if (this.showSuggestions) {
+ if (this.focusIndex < this.suggestions.length - 1) {
+ this.focusIndex++
+ } else {
+ this.focusIndex = 0
+ }
+ }
+ },
+
+ go (i) {
+ if (!this.showSuggestions) {
+ return
+ }
+ this.$router.push(this.suggestions[i].path)
+ this.query = ''
+ this.focusIndex = 0
+ },
+
+ focus (i) {
+ this.focusIndex = i
+ },
+
+ unfocus () {
+ this.focusIndex = -1
+ }
+ }
+}
+</script>
+
+<style lang="stylus">
+@import './styles/config.styl'
+
+.search-box
+ display inline-block
+ position relative
+ margin-right 1rem
+ input
+ cursor text
+ width 10rem
+ color lighten($textColor, 25%)
+ display inline-block
+ border 1px solid darken($borderColor, 10%)
+ border-radius 2rem
+ font-size 0.9rem
+ line-height 2rem
+ padding 0 0.5rem 0 2rem
+ outline none
+ transition all .2s ease
+ background #fff url(./search.svg) 0.6rem 0.5rem no-repeat
+ background-size 1rem
+ &:focus
+ cursor auto
+ border-color $accentColor
+ .suggestions
+ background #fff
+ width 20rem
+ position absolute
+ top 1.5rem
+ border 1px solid darken($borderColor, 10%)
+ border-radius 6px
+ padding 0.4rem
+ list-style-type none
+ &.align-right
+ right 0
+ .suggestion
+ line-height 1.4
+ padding 0.4rem 0.6rem
+ border-radius 4px
+ cursor pointer
+ a
+ white-space normal
+ color lighten($textColor, 35%)
+ .page-title
+ font-weight 600
+ .header
+ font-size 0.9em
+ margin-left 0.25em
+ &.focused
+ background-color #f3f4f5
+ a
+ color $accentColor
+
+@media (max-width: $MQNarrow)
+ .search-box
+ input
+ cursor pointer
+ width 0
+ border-color transparent
+ position relative
+ &:focus
+ cursor text
+ left 0
+ width 10rem
+
+@media (max-width: $MQNarrow) and (min-width: $MQMobile)
+ .search-box
+ .suggestions
+ left 0
+
+@media (max-width: $MQMobile)
+ .search-box
+ margin-right 0
+ input
+ left 1rem
+ .suggestions
+ right 0
+
+@media (max-width: $MQMobileNarrow)
+ .search-box
+ .suggestions
+ width calc(100vw - 4rem)
+ input:focus
+ width 8rem
+</style>
diff --git a/node_modules/vuepress/lib/default-theme/Sidebar.vue b/node_modules/vuepress/lib/default-theme/Sidebar.vue
new file mode 100644
index 00000000..7bcf0059
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/Sidebar.vue
@@ -0,0 +1,113 @@
+<template>
+ <div class="sidebar">
+ <NavLinks/>
+ <slot name="top"/>
+ <ul class="sidebar-links" v-if="items.length">
+ <li v-for="(item, i) in items" :key="i">
+ <SidebarGroup
+ v-if="item.type === 'group'"
+ :item="item"
+ :first="i === 0"
+ :open="i === openGroupIndex"
+ :collapsable="item.collapsable || item.collapsible"
+ @toggle="toggleGroup(i)"
+ />
+ <SidebarLink v-else :item="item"/>
+ </li>
+ </ul>
+ <slot name="bottom"/>
+ </div>
+</template>
+
+<script>
+import SidebarGroup from './SidebarGroup.vue'
+import SidebarLink from './SidebarLink.vue'
+import NavLinks from './NavLinks.vue'
+import { isActive } from './util'
+
+export default {
+ components: { SidebarGroup, SidebarLink, NavLinks },
+
+ props: ['items'],
+
+ data () {
+ return {
+ openGroupIndex: 0
+ }
+ },
+
+ created () {
+ this.refreshIndex()
+ },
+
+ watch: {
+ '$route' () {
+ this.refreshIndex()
+ }
+ },
+
+ methods: {
+ refreshIndex () {
+ const index = resolveOpenGroupIndex(
+ this.$route,
+ this.items
+ )
+ if (index > -1) {
+ this.openGroupIndex = index
+ }
+ },
+
+ toggleGroup (index) {
+ this.openGroupIndex = index === this.openGroupIndex ? -1 : index
+ },
+
+ isActive (page) {
+ return isActive(this.$route, page.path)
+ }
+ }
+}
+
+function resolveOpenGroupIndex (route, items) {
+ for (let i = 0; i < items.length; i++) {
+ const item = items[i]
+ if (item.type === 'group' && item.children.some(c => isActive(route, c.path))) {
+ return i
+ }
+ }
+ return -1
+}
+</script>
+
+<style lang="stylus">
+@import './styles/config.styl'
+
+.sidebar
+ ul
+ padding 0
+ margin 0
+ list-style-type none
+ a
+ display inline-block
+ .nav-links
+ display none
+ border-bottom 1px solid $borderColor
+ padding 0.5rem 0 0.75rem 0
+ a
+ font-weight 600
+ .nav-item, .repo-link
+ display block
+ line-height 1.25rem
+ font-size 1.1em
+ padding 0.5rem 0 0.5rem 1.5rem
+ .sidebar-links
+ padding 1.5rem 0
+
+@media (max-width: $MQMobile)
+ .sidebar
+ .nav-links
+ display block
+ .dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active::after
+ top calc(1rem - 2px)
+ .sidebar-links
+ padding 1rem 0
+</style>
diff --git a/node_modules/vuepress/lib/default-theme/SidebarButton.vue b/node_modules/vuepress/lib/default-theme/SidebarButton.vue
new file mode 100644
index 00000000..0a222434
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/SidebarButton.vue
@@ -0,0 +1,28 @@
+<template>
+ <div class="sidebar-button" @click="$emit('toggle-sidebar')">
+ <svg class="icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512">
+ <path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z" class=""></path>
+ </svg>
+ </div>
+</template>
+
+<style lang="stylus">
+@import './styles/config.styl'
+
+.sidebar-button
+ display none
+ width 1.25rem
+ height 1.25rem
+ position absolute
+ padding 0.6rem
+ top 0.6rem
+ left 1rem
+ .icon
+ display block
+ width 1.25rem
+ height 1.25rem
+
+@media (max-width: $MQMobile)
+ .sidebar-button
+ display block
+</style>
diff --git a/node_modules/vuepress/lib/default-theme/SidebarGroup.vue b/node_modules/vuepress/lib/default-theme/SidebarGroup.vue
new file mode 100644
index 00000000..119dfa14
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/SidebarGroup.vue
@@ -0,0 +1,77 @@
+<template>
+ <div
+ class="sidebar-group"
+ :class="{ first, collapsable }"
+ >
+ <p
+ class="sidebar-heading"
+ :class="{ open }"
+ @click="$emit('toggle')"
+ >
+ <span>{{ item.title }}</span>
+ <span
+ class="arrow"
+ v-if="collapsable"
+ :class="open ? 'down' : 'right'">
+ </span>
+ </p>
+
+ <DropdownTransition>
+ <ul
+ ref="items"
+ class="sidebar-group-items"
+ v-if="open || !collapsable"
+ >
+ <li v-for="child in item.children">
+ <SidebarLink :item="child"/>
+ </li>
+ </ul>
+ </DropdownTransition>
+ </div>
+</template>
+
+<script>
+import SidebarLink from './SidebarLink.vue'
+import DropdownTransition from './DropdownTransition.vue'
+
+export default {
+ name: 'SidebarGroup',
+ props: ['item', 'first', 'open', 'collapsable'],
+ components: { SidebarLink, DropdownTransition }
+}
+</script>
+
+<style lang="stylus">
+.sidebar-group
+ &:not(.first)
+ margin-top 1em
+ .sidebar-group
+ padding-left 0.5em
+ &:not(.collapsable)
+ .sidebar-heading
+ cursor auto
+ color inherit
+
+.sidebar-heading
+ color #999
+ transition color .15s ease
+ cursor pointer
+ font-size 1.1em
+ font-weight bold
+ // text-transform uppercase
+ padding 0 1.5rem
+ margin-top 0
+ margin-bottom 0.5rem
+ &.open, &:hover
+ color inherit
+ .arrow
+ position relative
+ top -0.12em
+ left 0.5em
+ &:.open .arrow
+ top -0.18em
+
+.sidebar-group-items
+ transition height .1s ease-out
+ overflow hidden
+</style>
diff --git a/node_modules/vuepress/lib/default-theme/SidebarLink.vue b/node_modules/vuepress/lib/default-theme/SidebarLink.vue
new file mode 100644
index 00000000..8288bf96
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/SidebarLink.vue
@@ -0,0 +1,91 @@
+<script>
+import { isActive, hashRE, groupHeaders } from './util'
+
+export default {
+ functional: true,
+
+ props: ['item'],
+
+ render (h, { parent: { $page, $site, $route }, props: { item }}) {
+ // use custom active class matching logic
+ // due to edge case of paths ending with / + hash
+ const selfActive = isActive($route, item.path)
+ // for sidebar: auto pages, a hash link should be active if one of its child
+ // matches
+ const active = item.type === 'auto'
+ ? selfActive || item.children.some(c => isActive($route, item.basePath + '#' + c.slug))
+ : selfActive
+ const link = renderLink(h, item.path, item.title || item.path, active)
+ const configDepth = $page.frontmatter.sidebarDepth != null
+ ? $page.frontmatter.sidebarDepth
+ : $site.themeConfig.sidebarDepth
+ const maxDepth = configDepth == null ? 1 : configDepth
+ const displayAllHeaders = !!$site.themeConfig.displayAllHeaders
+ if (item.type === 'auto') {
+ return [link, renderChildren(h, item.children, item.basePath, $route, maxDepth)]
+ } else if ((active || displayAllHeaders) && item.headers && !hashRE.test(item.path)) {
+ const children = groupHeaders(item.headers)
+ return [link, renderChildren(h, children, item.path, $route, maxDepth)]
+ } else {
+ return link
+ }
+ }
+}
+
+function renderLink (h, to, text, active) {
+ return h('router-link', {
+ props: {
+ to,
+ activeClass: '',
+ exactActiveClass: ''
+ },
+ class: {
+ active,
+ 'sidebar-link': true
+ }
+ }, text)
+}
+
+function renderChildren (h, children, path, route, maxDepth, depth = 1) {
+ if (!children || depth > maxDepth) return null
+ return h('ul', { class: 'sidebar-sub-headers' }, children.map(c => {
+ const active = isActive(route, path + '#' + c.slug)
+ return h('li', { class: 'sidebar-sub-header' }, [
+ renderLink(h, path + '#' + c.slug, c.title, active),
+ renderChildren(h, c.children, path, route, maxDepth, depth + 1)
+ ])
+ }))
+}
+</script>
+
+<style lang="stylus">
+@import './styles/config.styl'
+
+.sidebar .sidebar-sub-headers
+ padding-left 1rem
+ font-size 0.95em
+
+a.sidebar-link
+ font-weight 400
+ display inline-block
+ color $textColor
+ border-left 0.25rem solid transparent
+ padding 0.35rem 1rem 0.35rem 1.25rem
+ line-height 1.4
+ width: 100%
+ box-sizing: border-box
+ &:hover
+ color $accentColor
+ &.active
+ font-weight 600
+ color $accentColor
+ border-left-color $accentColor
+ .sidebar-group &
+ padding-left 2rem
+ .sidebar-sub-headers &
+ padding-top 0.25rem
+ padding-bottom 0.25rem
+ border-left none
+ &.active
+ font-weight 500
+</style>
diff --git a/node_modules/vuepress/lib/default-theme/search.svg b/node_modules/vuepress/lib/default-theme/search.svg
new file mode 100644
index 00000000..03d83913
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/search.svg
@@ -0,0 +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>
diff --git a/node_modules/vuepress/lib/default-theme/styles/arrow.styl b/node_modules/vuepress/lib/default-theme/styles/arrow.styl
new file mode 100644
index 00000000..20bffc0d
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/styles/arrow.styl
@@ -0,0 +1,22 @@
+@require './config'
+
+.arrow
+ display inline-block
+ width 0
+ height 0
+ &.up
+ border-left 4px solid transparent
+ border-right 4px solid transparent
+ border-bottom 6px solid $arrowBgColor
+ &.down
+ border-left 4px solid transparent
+ border-right 4px solid transparent
+ border-top 6px solid $arrowBgColor
+ &.right
+ border-top 4px solid transparent
+ border-bottom 4px solid transparent
+ border-left 6px solid $arrowBgColor
+ &.left
+ border-top 4px solid transparent
+ border-bottom 4px solid transparent
+ border-right 6px solid $arrowBgColor
diff --git a/node_modules/vuepress/lib/default-theme/styles/code.styl b/node_modules/vuepress/lib/default-theme/styles/code.styl
new file mode 100644
index 00000000..8383c6e3
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/styles/code.styl
@@ -0,0 +1,129 @@
+@require './config'
+
+.content
+ code
+ color lighten($textColor, 20%)
+ padding 0.25rem 0.5rem
+ margin 0
+ font-size 0.85em
+ background-color rgba(27,31,35,0.05)
+ border-radius 3px
+
+.content
+ pre, pre[class*="language-"]
+ line-height 1.4
+ padding 1.25rem 1.5rem
+ margin 0.85rem 0
+ background-color $codeBgColor
+ border-radius 6px
+ overflow auto
+ code
+ color #fff
+ padding 0
+ background-color transparent
+ border-radius 0
+
+div[class*="language-"]
+ position relative
+ background-color $codeBgColor
+ border-radius 6px
+ .highlight-lines
+ user-select none
+ padding-top 1.3rem
+ position absolute
+ top 0
+ left 0
+ width 100%
+ line-height 1.4
+ .highlighted
+ background-color rgba(0, 0, 0, 66%)
+ pre, pre[class*="language-"]
+ background transparent
+ position relative
+ z-index 1
+ &::before
+ position absolute
+ z-index 3
+ top 0.8em
+ right 1em
+ font-size 0.75rem
+ color rgba(255, 255, 255, 0.4)
+ &:not(.line-numbers-mode)
+ .line-numbers-wrapper
+ display none
+ &.line-numbers-mode
+ .highlight-lines .highlighted
+ position relative
+ &:before
+ content ' '
+ position absolute
+ z-index 3
+ left 0
+ top 0
+ display block
+ width $lineNumbersWrapperWidth
+ height 100%
+ background-color rgba(0, 0, 0, 66%)
+ pre
+ padding-left $lineNumbersWrapperWidth + 1 rem
+ vertical-align middle
+ .line-numbers-wrapper
+ position absolute
+ top 0
+ width $lineNumbersWrapperWidth
+ text-align center
+ color rgba(255, 255, 255, 0.3)
+ padding 1.25rem 0
+ line-height 1.4
+ br
+ user-select none
+ .line-number
+ position relative
+ z-index 4
+ user-select none
+ font-size 0.85em
+ &::after
+ content ''
+ position absolute
+ z-index 2
+ top 0
+ left 0
+ width $lineNumbersWrapperWidth
+ height 100%
+ border-radius 6px 0 0 6px
+ border-right 1px solid rgba(0, 0, 0, 66%)
+ background-color $codeBgColor
+
+
+for lang in $codeLang
+ div{'[class~="language-' + lang + '"]'}
+ &:before
+ content ('' + lang)
+
+div[class~="language-javascript"]
+ &:before
+ content "js"
+
+div[class~="language-typescript"]
+ &:before
+ content "ts"
+
+div[class~="language-markup"]
+ &:before
+ content "html"
+
+div[class~="language-markdown"]
+ &:before
+ content "md"
+
+div[class~="language-json"]:before
+ content "json"
+
+div[class~="language-ruby"]:before
+ content "rb"
+
+div[class~="language-python"]:before
+ content "py"
+
+div[class~="language-bash"]:before
+ content "sh"
diff --git a/node_modules/vuepress/lib/default-theme/styles/config.styl b/node_modules/vuepress/lib/default-theme/styles/config.styl
new file mode 100644
index 00000000..a57d4484
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/styles/config.styl
@@ -0,0 +1,22 @@
+// colors
+$accentColor = #3eaf7c
+$textColor = #2c3e50
+$borderColor = #eaecef
+$codeBgColor = #282c34
+$arrowBgColor = #ccc
+
+// layout
+$navbarHeight = 3.6rem
+$sidebarWidth = 20rem
+$contentWidth = 740px
+
+// responsive breakpoints
+$MQNarrow = 959px
+$MQMobile = 719px
+$MQMobileNarrow = 419px
+
+// code
+$lineNumbersWrapperWidth = 3.5rem
+$codeLang = js ts html md vue css sass scss less stylus go java c sh yaml py
+
+@import '~@temp/override.styl'
diff --git a/node_modules/vuepress/lib/default-theme/styles/custom-blocks.styl b/node_modules/vuepress/lib/default-theme/styles/custom-blocks.styl
new file mode 100644
index 00000000..3ccc2df2
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/styles/custom-blocks.styl
@@ -0,0 +1,28 @@
+.custom-block
+ .custom-block-title
+ font-weight 600
+ margin-bottom -0.4rem
+ &.tip, &.warning, &.danger
+ padding .1rem 1.5rem
+ border-left-width .5rem
+ border-left-style solid
+ margin 1rem 0
+ &.tip
+ background-color #f3f5f7
+ border-color #42b983
+ &.warning
+ background-color rgba(255,229,100,.3)
+ border-color darken(#ffe564, 35%)
+ color darken(#ffe564, 70%)
+ .custom-block-title
+ color darken(#ffe564, 50%)
+ a
+ color $textColor
+ &.danger
+ background-color #ffe6e6
+ border-color darken(red, 20%)
+ color darken(red, 70%)
+ .custom-block-title
+ color darken(red, 40%)
+ a
+ color $textColor
diff --git a/node_modules/vuepress/lib/default-theme/styles/mobile.styl b/node_modules/vuepress/lib/default-theme/styles/mobile.styl
new file mode 100644
index 00000000..b35e59c5
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/styles/mobile.styl
@@ -0,0 +1,37 @@
+@require './config'
+
+$mobileSidebarWidth = $sidebarWidth * 0.82
+
+// narrow desktop / iPad
+@media (max-width: $MQNarrow)
+ .sidebar
+ font-size 15px
+ width $mobileSidebarWidth
+ .page
+ padding-left $mobileSidebarWidth
+
+// wide mobile
+@media (max-width: $MQMobile)
+ .sidebar
+ top 0
+ padding-top $navbarHeight
+ transform translateX(-100%)
+ transition transform .2s ease
+ .page
+ padding-left 0
+ .theme-container
+ &.sidebar-open
+ .sidebar
+ transform translateX(0)
+ &.no-navbar
+ .sidebar
+ padding-top: 0
+
+// narrow mobile
+@media (max-width: $MQMobileNarrow)
+ h1
+ font-size 1.9rem
+ .content
+ div[class*="language-"]
+ margin 0.85rem -1.5rem
+ border-radius 0
diff --git a/node_modules/vuepress/lib/default-theme/styles/nprogress.styl b/node_modules/vuepress/lib/default-theme/styles/nprogress.styl
new file mode 100644
index 00000000..f186a67e
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/styles/nprogress.styl
@@ -0,0 +1,48 @@
+#nprogress
+ pointer-events none
+ .bar
+ background $accentColor
+ position fixed
+ z-index 1031
+ top 0
+ left 0
+ width 100%
+ height 2px
+ .peg
+ display block
+ position absolute
+ right 0px
+ width 100px
+ height 100%
+ box-shadow 0 0 10px $accentColor, 0 0 5px $accentColor
+ opacity 1.0
+ transform rotate(3deg) translate(0px, -4px)
+ .spinner
+ display block
+ position fixed
+ z-index 1031
+ top 15px
+ right 15px
+ .spinner-icon
+ width 18px
+ height 18px
+ box-sizing border-box
+ border solid 2px transparent
+ border-top-color $accentColor
+ border-left-color $accentColor
+ border-radius 50%
+ animation nprogress-spinner 400ms linear infinite
+
+.nprogress-custom-parent
+ overflow hidden
+ position relative
+
+.nprogress-custom-parent #nprogress .spinner,
+.nprogress-custom-parent #nprogress .bar
+ position absolute
+
+@keyframes nprogress-spinner
+ 0%
+ transform rotate(0deg)
+ 100%
+ transform rotate(360deg)
diff --git a/node_modules/vuepress/lib/default-theme/styles/theme.styl b/node_modules/vuepress/lib/default-theme/styles/theme.styl
new file mode 100644
index 00000000..a733861f
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/styles/theme.styl
@@ -0,0 +1,190 @@
+@require './config'
+@require './nprogress'
+@require './code'
+@require './custom-blocks'
+@require './arrow'
+@require './wrapper'
+@require './toc'
+
+html, body
+ padding 0
+ margin 0
+
+body
+ font-family -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif
+ -webkit-font-smoothing antialiased
+ -moz-osx-font-smoothing grayscale
+ font-size 16px
+ color $textColor
+
+.page
+ padding-left $sidebarWidth
+
+.navbar
+ position fixed
+ z-index 20
+ top 0
+ left 0
+ right 0
+ height $navbarHeight
+ background-color #fff
+ box-sizing border-box
+ border-bottom 1px solid $borderColor
+
+.sidebar-mask
+ position fixed
+ z-index 9
+ top 0
+ left 0
+ width 100vw
+ height 100vh
+ display none
+
+.sidebar
+ font-size 15px
+ background-color #fff
+ width $sidebarWidth
+ position fixed
+ z-index 10
+ margin 0
+ top $navbarHeight
+ left 0
+ bottom 0
+ box-sizing border-box
+ border-right 1px solid $borderColor
+ overflow-y auto
+
+.content:not(.custom)
+ @extend $wrapper
+ > *:first-child
+ margin-top $navbarHeight
+ a:hover
+ text-decoration underline
+ p.demo
+ padding 1rem 1.5rem
+ border 1px solid #ddd
+ border-radius 4px
+ img
+ max-width 100%
+
+.content.custom
+ padding 0
+ margin 0
+ img
+ max-width 100%
+
+a
+ font-weight 500
+ color $accentColor
+ text-decoration none
+
+p a code
+ font-weight 400
+ color $accentColor
+
+kbd
+ background #eee
+ border solid 0.15rem #ddd
+ border-bottom solid 0.25rem #ddd
+ border-radius 0.15rem
+ padding 0 0.15em
+
+blockquote
+ font-size 1.2rem
+ color #999
+ border-left .25rem solid #dfe2e5
+ margin-left 0
+ padding-left 1rem
+
+ul, ol
+ padding-left 1.2em
+
+strong
+ font-weight 600
+
+h1, h2, h3, h4, h5, h6
+ font-weight 600
+ line-height 1.25
+ .content:not(.custom) > &
+ margin-top (0.5rem - $navbarHeight)
+ padding-top ($navbarHeight + 1rem)
+ margin-bottom 0
+ &:first-child
+ margin-top -1.5rem
+ margin-bottom 1rem
+ + p, + pre, + .custom-block
+ margin-top 2rem
+ &:hover .header-anchor
+ opacity: 1
+
+h1
+ font-size 2.2rem
+
+h2
+ font-size 1.65rem
+ padding-bottom .3rem
+ border-bottom 1px solid $borderColor
+
+h3
+ font-size 1.35rem
+
+a.header-anchor
+ font-size 0.85em
+ float left
+ margin-left -0.87em
+ padding-right 0.23em
+ margin-top 0.125em
+ opacity 0
+ &:hover
+ text-decoration none
+
+code, kbd, .line-number
+ font-family source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace
+
+p, ul, ol
+ line-height 1.7
+
+hr
+ border 0
+ border-top 1px solid $borderColor
+
+table
+ border-collapse collapse
+ margin 1rem 0
+ display: block
+ overflow-x: auto
+
+tr
+ border-top 1px solid #dfe2e5
+ &:nth-child(2n)
+ background-color #f6f8fa
+
+th, td
+ border 1px solid #dfe2e5
+ padding .6em 1em
+
+.custom-layout
+ padding-top $navbarHeight
+
+.theme-container
+ &.sidebar-open
+ .sidebar-mask
+ display: block
+ &.no-navbar
+ .content:not(.custom) > h1, h2, h3, h4, h5, h6
+ margin-top 1.5rem
+ padding-top 0
+ .sidebar
+ top 0
+ .custom-layout
+ padding-top 0
+
+
+@media (min-width: ($MQMobile + 1px))
+ .theme-container.no-sidebar
+ .sidebar
+ display none
+ .page
+ padding-left 0
+
+@require './mobile.styl'
diff --git a/node_modules/vuepress/lib/default-theme/styles/toc.styl b/node_modules/vuepress/lib/default-theme/styles/toc.styl
new file mode 100644
index 00000000..d3e71069
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/styles/toc.styl
@@ -0,0 +1,3 @@
+.table-of-contents
+ .badge
+ vertical-align middle
diff --git a/node_modules/vuepress/lib/default-theme/styles/wrapper.styl b/node_modules/vuepress/lib/default-theme/styles/wrapper.styl
new file mode 100644
index 00000000..a99262c7
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/styles/wrapper.styl
@@ -0,0 +1,9 @@
+$wrapper
+ max-width $contentWidth
+ margin 0 auto
+ padding 2rem 2.5rem
+ @media (max-width: $MQNarrow)
+ padding 2rem
+ @media (max-width: $MQMobileNarrow)
+ padding 1.5rem
+
diff --git a/node_modules/vuepress/lib/default-theme/util.js b/node_modules/vuepress/lib/default-theme/util.js
new file mode 100644
index 00000000..ef95bea5
--- /dev/null
+++ b/node_modules/vuepress/lib/default-theme/util.js
@@ -0,0 +1,216 @@
+export const hashRE = /#.*$/
+export const extRE = /\.(md|html)$/
+export const endingSlashRE = /\/$/
+export const outboundRE = /^(https?:|mailto:|tel:)/
+
+export function normalize (path) {
+ return decodeURI(path)
+ .replace(hashRE, '')
+ .replace(extRE, '')
+}
+
+export function getHash (path) {
+ const match = path.match(hashRE)
+ if (match) {
+ return match[0]
+ }
+}
+
+export function isExternal (path) {
+ return outboundRE.test(path)
+}
+
+export function isMailto (path) {
+ return /^mailto:/.test(path)
+}
+
+export function isTel (path) {
+ return /^tel:/.test(path)
+}
+
+export function ensureExt (path) {
+ if (isExternal(path)) {
+ return path
+ }
+ const hashMatch = path.match(hashRE)
+ const hash = hashMatch ? hashMatch[0] : ''
+ const normalized = normalize(path)
+
+ if (endingSlashRE.test(normalized)) {
+ return path
+ }
+ return normalized + '.html' + hash
+}
+
+export function isActive (route, path) {
+ const routeHash = route.hash
+ const linkHash = getHash(path)
+ if (linkHash && routeHash !== linkHash) {
+ return false
+ }
+ const routePath = normalize(route.path)
+ const pagePath = normalize(path)
+ return routePath === pagePath
+}
+
+export function resolvePage (pages, rawPath, base) {
+ if (base) {
+ rawPath = resolvePath(rawPath, base)
+ }
+ const path = normalize(rawPath)
+ for (let i = 0; i < pages.length; i++) {
+ if (normalize(pages[i].path) === path) {
+ return Object.assign({}, pages[i], {
+ type: 'page',
+ path: ensureExt(rawPath)
+ })
+ }
+ }
+ console.error(`[vuepress] No matching page found for sidebar item "${rawPath}"`)
+ return {}
+}
+
+function resolvePath (relative, base, append) {
+ const firstChar = relative.charAt(0)
+ if (firstChar === '/') {
+ return relative
+ }
+
+ if (firstChar === '?' || firstChar === '#') {
+ return base + relative
+ }
+
+ const stack = base.split('/')
+
+ // remove trailing segment if:
+ // - not appending
+ // - appending to trailing slash (last segment is empty)
+ if (!append || !stack[stack.length - 1]) {
+ stack.pop()
+ }
+
+ // resolve relative path
+ const segments = relative.replace(/^\//, '').split('/')
+ for (let i = 0; i < segments.length; i++) {
+ const segment = segments[i]
+ if (segment === '..') {
+ stack.pop()
+ } else if (segment !== '.') {
+ stack.push(segment)
+ }
+ }
+
+ // ensure leading slash
+ if (stack[0] !== '') {
+ stack.unshift('')
+ }
+
+ return stack.join('/')
+}
+
+export function resolveSidebarItems (page, route, site, localePath) {
+ const { pages, themeConfig } = site
+
+ const localeConfig = localePath && themeConfig.locales
+ ? themeConfig.locales[localePath] || themeConfig
+ : themeConfig
+
+ const pageSidebarConfig = page.frontmatter.sidebar || localeConfig.sidebar || themeConfig.sidebar
+ if (pageSidebarConfig === 'auto') {
+ return resolveHeaders(page)
+ }
+
+ const sidebarConfig = localeConfig.sidebar || themeConfig.sidebar
+ if (!sidebarConfig) {
+ return []
+ } else {
+ const { base, config } = resolveMatchingConfig(route, sidebarConfig)
+ return config
+ ? config.map(item => resolveItem(item, pages, base))
+ : []
+ }
+}
+
+function resolveHeaders (page) {
+ const headers = groupHeaders(page.headers || [])
+ return [{
+ type: 'group',
+ collapsable: false,
+ title: page.title,
+ children: headers.map(h => ({
+ type: 'auto',
+ title: h.title,
+ basePath: page.path,
+ path: page.path + '#' + h.slug,
+ children: h.children || []
+ }))
+ }]
+}
+
+export function groupHeaders (headers) {
+ // group h3s under h2
+ headers = headers.map(h => Object.assign({}, h))
+ let lastH2
+ headers.forEach(h => {
+ if (h.level === 2) {
+ lastH2 = h
+ } else if (lastH2) {
+ (lastH2.children || (lastH2.children = [])).push(h)
+ }
+ })
+ return headers.filter(h => h.level === 2)
+}
+
+export function resolveNavLinkItem (linkItem) {
+ return Object.assign(linkItem, {
+ type: linkItem.items && linkItem.items.length ? 'links' : 'link'
+ })
+}
+
+export function resolveMatchingConfig (route, config) {
+ if (Array.isArray(config)) {
+ return {
+ base: '/',
+ config: config
+ }
+ }
+ for (const base in config) {
+ if (ensureEndingSlash(route.path).indexOf(base) === 0) {
+ return {
+ base,
+ config: config[base]
+ }
+ }
+ }
+ return {}
+}
+
+function ensureEndingSlash (path) {
+ return /(\.html|\/)$/.test(path)
+ ? path
+ : path + '/'
+}
+
+function resolveItem (item, pages, base, isNested) {
+ if (typeof item === 'string') {
+ return resolvePage(pages, item, base)
+ } else if (Array.isArray(item)) {
+ return Object.assign(resolvePage(pages, item[0], base), {
+ title: item[1]
+ })
+ } else {
+ if (isNested) {
+ console.error(
+ '[vuepress] Nested sidebar groups are not supported. ' +
+ 'Consider using navbar + categories instead.'
+ )
+ }
+ const children = item.children || []
+ return {
+ type: 'group',
+ title: item.title,
+ children: children.map(child => resolveItem(child, pages, base, true)),
+ collapsable: item.collapsable !== false
+ }
+ }
+}