docs_vue2/components/OneSearch.vue

167 lines
4.2 KiB
Vue
Raw Normal View History

<template>
2021-08-23 19:37:43 +08:00
<div class="one-search">
<veui-search-box
v-model="query"
class="input"
:placeholder="searchPlaceholder"
@input="handleInput"
/>
<div
ref="docsearch"
class="docsearch"
/>
</div>
</template>
<script>
2021-08-23 19:37:43 +08:00
import { SearchBox } from 'veui'
import { createElement } from 'preact'
import i18n from '../common/i18n'
function isSpecialClick (event) {
return (
event.button === 1 ||
event.altKey ||
event.ctrlKey ||
event.metaKey ||
event.shiftKey
)
}
2021-10-22 17:04:26 +08:00
function normalizeURL (url) {
if (url.endsWith('/')) {
return url.slice(0, -1)
}
return url.replace(/\/([#?])/, '$1')
}
export default {
name: 'one-search',
2021-08-23 19:37:43 +08:00
components: {
'veui-search-box': SearchBox
},
mixins: [i18n],
2021-08-23 19:37:43 +08:00
data () {
return {
query: ''
}
},
computed: {
searchPlaceholder () {
return this.locale === 'zh-Hans' ? '⌘ K | 搜索…' : '⌘ K | Search...'
}
},
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',
2021-08-23 19:37:43 +08:00
container: this.$refs.docsearch,
searchParameters: {
facetFilters: [`lang:${locale}`]
},
navigator: {
2021-08-24 14:50:43 +08:00
navigate: ({ itemUrl }) => {
const { pathname: hitPathname } = new URL(
2021-08-24 14:50:43 +08:00
window.location.origin + itemUrl
)
if (this.$router.history.current.path === hitPathname) {
2021-08-24 14:50:43 +08:00
window.location.assign(window.location.origin + itemUrl)
} else {
2021-08-24 14:50:43 +08:00
this.$router.push(itemUrl)
}
}
},
transformItems: items => {
return items.map(item => {
return {
...item,
url: this.getRelativePath(item.url)
}
})
},
hitComponent: ({ hit, children }) => {
2021-10-22 17:04:26 +08:00
const url = normalizeURL(hit.url)
2021-08-23 19:37:43 +08:00
return createElement(
'a',
{
2021-10-22 17:04:26 +08:00
href: 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()
}
2021-10-22 17:04:26 +08:00
this.$router.push(url)
},
children
}
2021-08-23 19:37:43 +08:00
)
}
})
})
},
update (locale) {
2021-08-23 19:37:43 +08:00
this.$refs.docsearch.innerHTML = ''
this.initialize(locale)
2021-08-23 19:37:43 +08:00
},
handleInput (value) {
if (!value) {
return
}
this.teleportQuery(value)
},
teleportQuery (value) {
this.query = ''
const docsearchButton = this.$refs.docsearch.querySelector('.DocSearch')
docsearchButton.click()
setTimeout(() => {
const docsearchInput = document.getElementById('docsearch-input')
docsearchInput.value = value
docsearchInput.dispatchEvent(new Event('input'))
})
}
}
}
</script>
2021-08-23 19:37:43 +08:00
<style lang="stylus" scoped>
.input
width auto
.docsearch
display none
</style>