feat: upgrade sidebar, remove header, upgrade search

This commit is contained in:
Justineo
2021-07-19 16:27:38 +08:00
parent a9d349aed1
commit fe6f5376a9
14 changed files with 726 additions and 632 deletions

View File

@@ -1,89 +0,0 @@
<template>
<header class="one-header">
<h1>Baidu DLS</h1>
<a
href="http://dls.baidu.com/"
target="_blank"
>返回 DLS</a>
<veui-dropdown
label="Vue"
:options="options"
@click="redirect"
/>
</header>
</template>
<script>
import { Dropdown } from 'veui'
export default {
name: 'one-header',
components: {
'veui-dropdown': Dropdown
},
data () {
return {
options: [
{
label: 'Vue',
value: '/'
},
{
label: 'React',
value: 'http://one-ui.baidu-int.com/'
},
{
label: 'Angular',
value: 'http://cp01-wangfengjiao01.epc.baidu.com:8404/'
}
]
}
},
methods: {
redirect (url) {
location.href = url
}
}
}
</script>
<style lang="stylus" scoped>
.one-header
position fixed
top 0
left 0
right 0
z-index 20
display flex
align-items center
height 60px
background-color #070628
color #ffffff
padding 0 51px 0 17px
h1
display inline-block
font-size 18px
a
margin-left auto
color #ffffff
font-size 16px
&:hover
color #ffffff
.veui-dropdown
margin-left 40px
& >>> .veui-dropdown-button
color #ffffff
background-color transparent
border-radius 6px
height 28px
display inline-flex
align-items center
.veui-dropdown-label
line-height 1
</style>

View File

@@ -1,90 +1,53 @@
<template>
<aside class="one-nav">
<nav class="secondary">
<h2><span>VEUI<small>beta</small></span></h2>
<section class="desc">
<a href="https://github.com/ecomfe/veui">
<img
alt="VEUI on GitHub"
src="https://badgen.net/badge/-/GitHub?icon=github&label"
width="69.2"
height="20"
>
</a>
<nuxt-link
:class="{
'locale-swith': true,
disabled: altLocale.disabled
}"
:to="altLocale.disabled ? '' : altLocale.to"
>
{{ altLocale.label }}
</nuxt-link>
</section>
<section class="filter">
<input
type="text"
placeholder="Search…"
class="search"
>
</section>
<menu class="menu">
<template v-for="(item, i) in nav">
<li
:key="`menu-${i}`"
class="menu-item"
>
<nuxt-link
v-if="item.link !== false"
class="menu-link"
:exact="item.exact"
:to="getLocalePath(`/${item.slug}`)"
<veui-menu
class="one-menu"
:items="menuItems"
:expanded.sync="expanded"
>
<template #before>
<h2>VEUI</h2>
<section class="desc">
<a href="https://github.com/ecomfe/veui">
<img
alt="VEUI on GitHub"
src="https://badgen.net/badge/-/GitHub?icon=github&label"
width="69.2"
height="20"
>
{{ item.title }}
</nuxt-link>
<span
v-else
class="menu-link"
>{{ item.title }}</span>
<menu
v-if="item.children && item.children.length"
class="menu"
>
<template
v-for="(subItem, j) in item.children"
>
<li
v-if="!subItem.hidden"
:key="`sub-${j}`"
class="menu-item"
>
<nuxt-link
:class="{
'menu-link': true,
'menu-link-disabled': subItem.disabled,
'menu-link-sub': subItem.sub,
'menu-link-active': isActive(`/${item.slug}/${subItem.slug}`)
}"
:exact="subItem.exact"
:to="subItem.disabled ? '/' : getLocalePath(`/${item.slug}/${subItem.slug}`)"
v-html="getTitleHTML(subItem.title)"
/>
</li>
</template>
</menu>
</li>
</template>
</menu>
</nav>
</a>
<nuxt-link
:class="{
'locale-swith': true,
disabled: altLocale.disabled,
}"
:to="altLocale.disabled ? '' : altLocale.to"
>
{{ altLocale.label }}
</nuxt-link>
</section>
<section class="filter">
<one-search/>
</section>
</template>
<template #item-label="{ label, sub }">
{{ label }}<small>{{ sub }}</small>
</template>
</veui-menu>
</aside>
</template>
<script>
import { escape } from 'lodash'
import i18n from '../common/i18n'
import OneSearch from './OneSearch'
import { Menu } from 'veui'
export default {
name: 'one-menu',
components: {
'one-search': OneSearch,
'veui-menu': Menu
},
mixins: [i18n],
props: {
nav: {
@@ -94,6 +57,11 @@ export default {
}
}
},
data () {
return {
expanded: []
}
},
computed: {
altLocale () {
let { canonicalPath, locale, getLocalePath, isPathDisabled } = this
@@ -105,52 +73,37 @@ export default {
disabled,
label
}
},
menuItems () {
return this.nav.map(item => this.normalizeItem(item))
}
},
watch: {
$route: 'scrollActiveIntoView'
},
mounted () {
this.scrollActiveIntoView()
},
beforeDestroy () {
clearTimeout(this.timer)
created () {
this.expanded = this.menuItems.map(({ name }) => name)
},
methods: {
getTitleHTML (title) {
getTitleDetail (title) {
let [main, sub] = title.split(' - ')
return escape(main) + (sub ? `<small>${escape(sub)}</small>` : '')
return [main, sub]
},
isActive (path) {
let { route = {} } = this.$router.resolve(path) || {}
return route.name === this.$route.name
},
scrollActiveIntoView () {
this.timer = setTimeout(() => {
if (!this.$el) {
return
}
let active =
this.$el.querySelector('.nuxt-link-exact-active') ||
this.$el.querySelector('.menu-link-active')
if (!active) {
return
}
normalizeItem ({ title, children, slug, link, disabled }, base = '') {
const fullSlug = `${base}/${slug}`
const localePath = this.getLocalePath(fullSlug)
const to = (link !== false && fullSlug) ? localePath : null
const [main, sub] = this.getTitleDetail(title)
let menu = active.offsetParent
if (!menu) {
return
}
if (
active.offsetTop < menu.scrollTop ||
active.offsetTop + active.offsetHeight > menu.scrollTop
) {
active.scrollIntoView({
behavior: 'smooth',
block: 'nearest'
})
}
})
return {
label: main,
sub,
to,
name: fullSlug,
disabled,
children: children ? children.map(child => this.normalizeItem(child, fullSlug)) : []
}
}
}
}
@@ -159,43 +112,33 @@ export default {
<style lang="stylus" scoped>
.one-nav
position fixed
top 60px
top 0
bottom 0
left 0
width 280px
z-index 1
padding-top 30px
border-right 1px solid #e5e5e5
.primary
margin-left -250px
.secondary
.one-menu
width 100%
height 100%
position relative
display flex
justify-content stretch
flex-direction column
float left
width 240px
::v-deep .veui-menu-tree-wrapper
display flex
flex-direction column
flex-grow 1
height 100%
overflow visible
.veui-menu-tree
overflow auto
h2
display flex
align-items center
margin 0 0 0 20px
margin 30px 0 0 20px
font-size 20px
font-weight 500
span
position relative
small
position absolute
font-size 16px
font-weight 400
transform scale(0.75) translateY(-3px)
margin-left 3px
opacity 0.7
a
display block
@@ -208,6 +151,10 @@ export default {
img
display block
small
margin-left 8px
opacity 0.7
.locale-swith
display block
margin-left 12px
@@ -224,8 +171,7 @@ export default {
border-color #999
.filter
margin-top 20px
margin-left 20px
margin 20px 0 20px 20px
.search
display block
@@ -242,66 +188,6 @@ export default {
border-color #999
box-shadow 0 0 0 2px rgba(0, 0, 0, 0.15)
& > .menu
position relative
width 100%
flex 1 1 auto
margin-top 25px
padding-left 20px
overflow auto
.menu
.menu-item
.menu-link
float left
clear left
.menu .menu
margin 3.5px 0
.menu-item
margin 3.5px 0
font-size 16px
.menu-item
font-size 13px
.menu-link
color #333
font-weight 400
& >>> small
color #999
font-size 13px
margin-left 10px
white-space nowrap
&::after
display block
.menu-link
float left
clear left
color #333
font-weight 500
padding 9px 0
text-decoration none
&-disabled
opacity 0.3
pointer-events none
// &-sub
// margin-left 10px
&::after
background-color #999
.nuxt-link-exact-active::after
.menu-link-active::after
width 100%
left 0
background-color #333
.toggle
margin-right 15px
font-size 13px

107
components/OneSearch.vue Normal file
View File

@@ -0,0 +1,107 @@
<template>
<div id="docsearch"/>
</template>
<script>
import i18n from '../common/i18n'
function isSpecialClick (event) {
return (
event.button === 1 ||
event.altKey ||
event.ctrlKey ||
event.metaKey ||
event.shiftKey
)
}
export default {
name: 'one-search',
mixins: [i18n],
watch: {
locale (val) {
this.update(val)
}
},
mounted () {
this.initialize(this.locale)
},
methods: {
getRelativePath (absoluteUrl) {
const { pathname, hash } = new URL(absoluteUrl)
return `${pathname}/${hash}`
},
initialize (locale) {
Promise.all([
import(/* webpackChunkName: "docsearch" */ '@docsearch/js'),
import(/* webpackChunkName: "docsearch" */ '@docsearch/css')
]).then(([docsearch]) => {
docsearch = docsearch.default
docsearch({
apiKey: '21cdc123c620ec4bb81259c32e90c08f',
indexName: 'veui',
container: '#docsearch',
searchParameters: {
facetFilters: [`lang:${locale}`]
},
navigator: {
navigate ({ suggestionUrl }) {
const { pathname: hitPathname } = new URL(
window.location.origin + suggestionUrl
)
if (this.$router.history.current.path === hitPathname) {
window.location.assign(window.location.origin + suggestionUrl)
} else {
this.$router.push(suggestionUrl)
}
}
},
transformItems: items => {
return items.map(item => {
return {
...item,
url: this.getRelativePath(item.url)
}
})
},
hitComponent: ({ hit, children }) => {
return {
type: 'a',
ref: undefined,
constructor: undefined,
key: undefined,
props: {
href: hit.url,
onClick: event => {
if (isSpecialClick(event)) {
return
}
// We rely on the native link scrolling when user is
// already on the right anchor because Vue Router doesn't
// support duplicated history entries.
if (this.$router.history.current.fullPath === hit.url) {
return
}
const { pathname: hitPathname } = new URL(
window.location.origin + hit.url
)
// If the hits goes to another page, we prevent the native link behavior
// to leverage the Vue Router loading feature.
if (this.$router.history.current.path !== hitPathname) {
event.preventDefault()
}
this.$router.push(hit.url)
},
children
}
}
}
})
})
},
update (locale) {
this.$el.innerHTML = '<div id="docsearch"></div>'
this.initialize(locale)
}
}
}
</script>