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
No known key found for this signature in database
GPG Key ID: B73F0979CF18A0EA
14 changed files with 726 additions and 632 deletions

View File

@ -23,7 +23,7 @@ body
height 100% height 100%
body body
margin-left 240px margin-left 280px
button button
input input

View File

@ -74,14 +74,13 @@ export default {
} }
}, },
methods: { methods: {
getLocalePath (path, locale) { getLocalePath (path, locale = this.locale) {
let loc = locale || this.locale if (locale === DEFAULT_LOCALE) {
if (loc === DEFAULT_LOCALE) {
return path return path
} }
return `/${loc}${path}`.replace(/\/$/, '') return `/${locale}${path}`.replace(/\/$/, '')
}, },
isPathDisabled (path, locale) { isPathDisabled (path, locale = this.locale) {
let segments = compact(path.split('/')) let segments = compact(path.split('/'))
let navItem = segments.reduce((node, seg) => { let navItem = segments.reduce((node, seg) => {
if (!node) { if (!node) {

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

View File

@ -5,7 +5,6 @@
'no-links': !hasFooterLinks 'no-links': !hasFooterLinks
}" }"
> >
<one-header/>
<one-menu :nav="nav"/> <one-menu :nav="nav"/>
<nuxt/> <nuxt/>
<one-footer <one-footer
@ -19,7 +18,6 @@
<script> <script>
import 'focus-visible' import 'focus-visible'
import OneHeader from '../components/OneHeader'
import OneMenu from '../components/OneMenu' import OneMenu from '../components/OneMenu'
import OneFooter from '../components/OneFooter' import OneFooter from '../components/OneFooter'
import OneBackToTop from '../components/OneBackToTop' import OneBackToTop from '../components/OneBackToTop'
@ -30,7 +28,6 @@ import i18nMgr from 'veui/managers/i18n'
export default { export default {
name: 'main-doc', name: 'main-doc',
components: { components: {
OneHeader,
OneMenu, OneMenu,
OneFooter, OneFooter,
OneBackToTop OneBackToTop
@ -81,15 +78,13 @@ export default {
</script> </script>
<style lang="stylus" scoped> <style lang="stylus" scoped>
$sidebar-width = 240px $sidebar-width = 280px
main main
height 100% height 100%
.content .content
margin-top 60px .footer
.content, .footer
max-width 1180px - $sidebar-width max-width 1180px - $sidebar-width
min-width 560px min-width 560px
transition margin-left 0.5s cubic-bezier(0.785, 0.135, 0.15, 0.86) transition margin-left 0.5s cubic-bezier(0.785, 0.135, 0.15, 0.86)

View File

@ -27,19 +27,7 @@ module.exports = {
} }
], ],
link: [ link: [
{ rel: 'shortcut icon', href: 'https://www.baidu.com/favicon.ico' }, { rel: 'shortcut icon', href: 'https://www.baidu.com/favicon.ico' }
{
rel: 'stylesheet',
href:
'https://code.bdstatic.com/npm/docsearch.js@2.6.3/dist/cdn/docsearch.min.css'
}
],
script: [
{
src:
'https://code.bdstatic.com/npm/docsearch.js@2.6.3/dist/cdn/docsearch.min.js',
body: true
}
] ]
}, },
/** /**
@ -54,11 +42,9 @@ module.exports = {
css: ['veui-theme-dls/common.less', '@/assets/styles/global.styl'], css: ['veui-theme-dls/common.less', '@/assets/styles/global.styl'],
plugins: [ plugins: [
{ src: '~plugins/config.js' },
{ src: '~plugins/i18n.js' }, { src: '~plugins/i18n.js' },
{ src: '~plugins/l10n.js' }, { src: '~plugins/l10n.js' },
{ src: '~plugins/hm.js', ssr: false }, { src: '~plugins/hm.js', ssr: false }
{ src: '~plugins/algolia.js', ssr: false }
], ],
/** /**

View File

@ -8,19 +8,17 @@ export default function attacher () {
return (tree, { path }) => { return (tree, { path }) => {
let localPath = `/${relative(DOCS_DIR, path)}` let localPath = `/${relative(DOCS_DIR, path)}`
let [, locale] = localPath.match(RE_LOCALE) || [] let [, locale] = localPath.match(RE_LOCALE) || []
if (!locale) {
return
}
visit(tree, 'element', node => { visit(tree, 'element', node => {
let { tagName, properties, properties: { href } } = node let { tagName, properties: { href, ...props } } = node
if (tagName !== 'a' || href.match(/^\w+:\/\//)) { if (tagName !== 'a' || href.match(/^\w+:\/\//)) {
return return
} }
if (locale && href.indexOf('/') === 0) { let routePath = locale && href.indexOf('/') === 0 ? `/${locale}${href}` : href
properties.href = `/${locale}${href}`
} node.tagName = 'nuxt-link'
node.properties = { ...props, to: routePath }
}) })
} }
} }

View File

@ -1,7 +1,7 @@
# VEUI # VEUI
:::oss-badges :::oss-badges
[<img alt="VEUI on GitHub" src="https://badgen.net/badge/-/VEUI?label=GitHub" width="85.2" height="20">](https://github.com/ecomfe/veui) [<img alt="VEUI on CircleCI" src="https://badgen.net/circleci/github/ecomfe/veui?label=CircleCI" width="105.1" height="20">](https://circleci.com/gh/ecomfe/veui) [<img alt="VEUI on npm" src="https://badgen.net/npm/v/veui" width="133.5" height="20">](https://www.npmjs.com/package/veui) [<img alt="VEUI on CircleCI" src="https://badgen.net/circleci/github/ecomfe/veui?label=CircleCI&cache=300" height="20">](https://circleci.com/gh/ecomfe/veui) [<img alt="VEUI on npm" src="https://badgen.net/npm/v/veui?cache=300" height="20">](https://www.npmjs.com/package/veui)
::: :::
> VEUI is an enterprise UI component library, based on [Vue.js](https://vuejs.org). > VEUI is an enterprise UI component library, based on [Vue.js](https://vuejs.org).

View File

@ -1,7 +1,7 @@
# VEUI # VEUI
:::oss-badges :::oss-badges
[<img alt="VEUI on GitHub" src="https://badgen.net/badge/-/VEUI?label=GitHub" width="85.2" height="20">](https://github.com/ecomfe/veui) [<img alt="VEUI on CircleCI" src="https://badgen.net/circleci/github/ecomfe/veui?label=CircleCI" width="105.1" height="20">](https://circleci.com/gh/ecomfe/veui) [<img alt="VEUI on npm" src="https://badgen.net/npm/v/veui" width="133.5" height="20">](https://www.npmjs.com/package/veui) [<img alt="VEUI on CircleCI" src="https://badgen.net/circleci/github/ecomfe/veui?label=CircleCI&cache=300" height="20">](https://circleci.com/gh/ecomfe/veui) [<img alt="VEUI on npm" src="https://badgen.net/npm/v/veui?cache=300" height="20">](https://www.npmjs.com/package/veui)
::: :::
> VEUI 是一套基于 [Vue.js](https://vuejs.org) 的企业级应用组件库。 > VEUI 是一套基于 [Vue.js](https://vuejs.org) 的企业级应用组件库。

776
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -19,9 +19,11 @@
"update:veui": "npm i -D {veui-loader,veui,veui-theme-dls,babel-plugin-veui,veui-theme-dls-icons}@latest" "update:veui": "npm i -D {veui-loader,veui,veui-theme-dls,babel-plugin-veui,veui-theme-dls-icons}@latest"
}, },
"devDependencies": { "devDependencies": {
"@docsearch/css": "^1.0.0-alpha.27",
"@docsearch/js": "^1.0.0-alpha.27",
"babel-eslint": "^10.1.0", "babel-eslint": "^10.1.0",
"babel-plugin-lodash": "^3.3.4", "babel-plugin-lodash": "^3.3.4",
"babel-plugin-veui": "^2.0.0-beta.24", "babel-plugin-veui": "^2.0.0",
"dls-icons-vue": "^0.14.0", "dls-icons-vue": "^0.14.0",
"eslint": "^5.15.1", "eslint": "^5.15.1",
"eslint-config-prettier": "^4.1.0", "eslint-config-prettier": "^4.1.0",
@ -42,7 +44,7 @@
"less": "3.9.0", "less": "3.9.0",
"less-loader": "^4.1.0", "less-loader": "^4.1.0",
"less-plugin-est": "^3.0.0", "less-plugin-est": "^3.0.0",
"lodash": "^4.17.10", "lodash": "^4.17.21",
"lowlight": "^1.9.2", "lowlight": "^1.9.2",
"mkdirp": "^0.5.5", "mkdirp": "^0.5.5",
"moment": "^2.22.2", "moment": "^2.22.2",
@ -68,10 +70,10 @@
"stylus-loader": "^3.0.2", "stylus-loader": "^3.0.2",
"unist-util-remove": "^1.0.1", "unist-util-remove": "^1.0.1",
"unist-util-visit": "^1.4.0", "unist-util-visit": "^1.4.0",
"veui": "^2.0.0-beta.31", "veui": "^2.0.0",
"veui-loader": "^2.0.0-beta.31", "veui-loader": "^2.0.0",
"veui-theme-dls": "^2.0.0-beta.31", "veui-theme-dls": "^2.0.0",
"veui-theme-dls-icons": "^2.0.0-beta.31", "veui-theme-dls-icons": "^2.0.0",
"vue-awesome": "^4.1.0", "vue-awesome": "^4.1.0",
"vue-i18n": "^8.16.0", "vue-i18n": "^8.16.0",
"vue-windows": "^0.2.4" "vue-windows": "^0.2.4"

View File

@ -1,32 +0,0 @@
import { getLocale } from '../common/i18n'
function check (name, timeout, callback) {
if (name in window) {
setTimeout(() => callback(window[name]))
return
}
setTimeout(() => {
check(name, timeout, callback)
}, timeout)
}
export default ({ app, route }) => {
// if (process.env.NODE_ENV !== 'production') return
check('docsearch', 300, docsearch => {
window.docsearchInstance = docsearch({
apiKey: '21cdc123c620ec4bb81259c32e90c08f',
indexName: 'veui',
inputSelector: '.search',
algoliaOptions: {
facetFilters: [`lang:${getLocale(route.path)}`]
},
handleSelected (input, e, { url }) {
input.setVal('')
e.preventDefault()
let { pathname, search, hash } = new URL(url)
app.router.push(`${pathname}${search}${hash}`)
}
})
})
}

View File

@ -1,4 +0,0 @@
import 'veui/managers/config'
import config from 'veui/managers/config'
config.set('modal.scrollLockMode', 'advanced')