Nuxt/docs/components/app/AlgoliaSearchBox.vue

193 lines
6.0 KiB
Vue

<template>
<div id="docsearch">
<button type="button" class="DocSearch DocSearch-Button" aria-label="Search">
<svg width="20" height="20" class="d-icon m-auto" viewBox="0 0 20 20">
<path
d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z"
stroke="currentColor"
fill="none"
fill-rule="evenodd"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
</div>
</template>
<script>
function isSpecialClick(event) {
return event.button === 1 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey
}
export default {
props: {
options: {
type: Object,
required: true
},
settings: {
type: Object,
required: true
}
},
watch: {
'$i18n.locale'(newValue) {
this.update(this.options, newValue)
},
options(newValue) {
this.update(newValue, this.$i18n.locale)
}
},
mounted() {
this.initialize(this.options, this.$i18n.locale)
},
methods: {
stripTrailingSlash(url) {
return url.replace(/\/$|\/(?=\?)|\/(?=#)/g, '')
},
getRelativePath(absoluteUrl) {
const { pathname, hash } = new URL(absoluteUrl)
const url = pathname.replace(this.settings.url, '/') + hash
return this.stripTrailingSlash(url)
},
async initialize(userOptions, code) {
const lang = this.$i18n.locales.find(locale => locale.code === code)
const docsearch = await Promise.all([
import(/* webpackChunkName: "docsearch" */ '@docsearch/js'),
import(/* webpackChunkName: "docsearch" */ '@docsearch/css')
]).then(([docsearch]) => docsearch.default)
docsearch({
...userOptions,
container: '#docsearch',
searchParameters: {
...((!lang) ? {} : {
facetFilters: [`${userOptions.langAttribute || 'language'}:${lang.iso}`].concat(
userOptions.facetFilters || []
)
}),
},
navigator: {
navigate: ({ itemUrl }) => {
const { pathname: hitPathname } = new URL(window.location.origin + itemUrl)
// Vue Router doesn't handle same-page navigation so we use
// the native browser location API for anchor navigation.
if (this.$router.history.current.path === hitPathname) {
window.location.assign(window.location.origin + itemUrl)
} else {
this.$router.push(itemUrl)
}
}
},
transformItems: (items) => {
return items.map((item) => {
return {
...item,
url: this.getRelativePath(item.url)
}
})
},
hitComponent: ({ hit, children }) => {
return {
type: 'a',
constructor: undefined,
__v: 1,
props: {
href: hit.url,
children: children,
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)
},
}
}
}
})
},
update(options, lang) {
return this.initialize(options, lang)
}
}
}
</script>
<style lang="postcss">
.DocSearch {
--docsearch-primary-color: #00dc82;
--docsearch-highlight-color: var(--docsearch-primary-color);
--docsearch-text-color: rgb(113, 113, 122);
--docsearch-modal-background: theme("colors.gray.100");
--docsearch-searchbox-shadow: 0 0 0 2px var(--docsearch-primary-color);
--docsearch-searchbox-background: var(--color-transparent);
--docsearch-searchbox-focus-background: var(--color-transparent);
--docsearch-hit-color: var(--color-gray-700);
--docsearch-hit-shadow: none;
--docsearch-logo-color: var(--docsearch-text-color);
--docsearch-muted-color: var(--color-gray-500);
--docsearch-container-background: rgb(244 244 245 / 55%);
}
.dark {
& .DocSearch {
--docsearch-text-color: rgb(146, 173, 173);
--docsearch-modal-background: theme("colors.secondary-darker");
--docsearch-modal-shadow: inset 1px 1px 0 0 #052f14, 0 3px 8px 0 #0b160d;
--docsearch-hit-color: var(--color-gray-300);
--docsearch-hit-background: theme("colors.secondary-darkest");
--docsearch-footer-background: theme("colors.secondary-darkest");
--docsearch-footer-shadow: inset 0 1px 0 0 rgba(73, 76, 106, 0.5),
0 -4px 8px 0 rgba(0, 0, 0, 0.2);
--docsearch-container-background: rgb(0 30 38 / 64%);
}
}
.DocSearch-Container {
@apply blur-8;
}
.DocSearch-Modal {
@apply lg:rounded-xl !important;
}
.DocSearch-SearchBar {
@apply pb-1 !important;
}
.DocSearch-Button {
@apply rounded-sm w-12 h-12 m-auto bg-transparent hover:shadow-none focus:outline-none !important;
}
.DocSearch-Button > svg {
@apply mx-auto !important;
}
.DocSearch-Button-Key {
@apply hidden !important;
}
.DocSearch-Button-Placeholder {
@apply hidden !important;
}
.DocSearch-NoResults > .DocSearch-Screen-Icon > svg {
@apply mx-auto !important;
}
.DocSearch-Commands-Key {
@apply inline-flex items-center justify-center w-auto h-auto p-1 bg-none rounded shadow-none border light:border-gray-500 !important;
}
</style>