aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/docs/app/integrations
diff options
context:
space:
mode:
author简律纯 <hsiangnianian@outlook.com>2023-04-19 17:30:39 +0800
committer简律纯 <hsiangnianian@outlook.com>2023-04-19 17:30:39 +0800
commit3adc965dd09490b7efa1cce9f09b0a3b30970277 (patch)
treef813abb07d7b003984aa74e3154752b6ffc3ccd5 /docs/app/integrations
parentc7c9ca6f0c8eddf6d34cd40779f3b2d9463f3a46 (diff)
downloadHydroRoll-3adc965dd09490b7efa1cce9f09b0a3b30970277.tar.gz
HydroRoll-3adc965dd09490b7efa1cce9f09b0a3b30970277.zip
✨优化文档
Diffstat (limited to 'docs/app/integrations')
-rw-r--r--docs/app/integrations/docsearch.ts176
1 files changed, 176 insertions, 0 deletions
diff --git a/docs/app/integrations/docsearch.ts b/docs/app/integrations/docsearch.ts
new file mode 100644
index 0000000..93ca0e7
--- /dev/null
+++ b/docs/app/integrations/docsearch.ts
@@ -0,0 +1,176 @@
+import { withoutTrailingSlash } from 'ufo'
+import type { DocSearchOptions } from '@nuxtjs/algolia/dist/module.d'
+
+export default defineNuxtPlugin(() => {
+ const config = useRuntimeConfig()
+
+ const docSearchElement = ref()
+
+ const hasDocSearch = computed(() => config?.public?.algolia?.docSearch)
+
+ // Setup Algolia DocSearch integration
+ if (hasDocSearch.value) {
+ const route = useRoute()
+
+ const router = useRouter()
+
+ /**
+ * Try to grab options from runtimeConfig.
+ *
+ * If not found, fallback on props.
+ */
+ const options = computed<DocSearchOptions>(() => {
+ const { algolia } = useRuntimeConfig()
+
+ if (algolia && algolia.docSearch) {
+ return algolia
+ }
+
+ return {}
+ })
+
+ /**
+ * Check if event is special click to avoid closing the DocSearch too soon.
+ */
+ const isSpecialClick = (event: MouseEvent) => event.button === 1 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey
+
+ /**
+ * Gets the relative path from an absolute URL provided by the DocSearch instance.
+ */
+ const getRelativePath = (absoluteUrl: string) => {
+ const { pathname, hash } = new URL(absoluteUrl)
+ const url = window.location.origin
+ const relativeUrl = pathname.replace(url, '/')
+ return withoutTrailingSlash(relativeUrl) + hash
+ }
+
+ /**
+ * Initialize the DocSearch instance.
+ * @param userOptions
+ */
+ const initialize = async (userOptions: any & DocSearchOptions) => {
+ const el = document.createElement('div')
+ el.id = '#docsearch-container'
+ el.style.width = '0'
+ el.style.height = '0'
+ el.style.display = 'none'
+ document.body.appendChild(el)
+ docSearchElement.value = el
+
+ // @ts-expect-errors - Import @docsearch at runtime
+ const docsearch = await Promise.all([import(/* webpackChunkName: "docsearch" */ '@docsearch/js'), import(/* webpackChunkName: "docsearch" */ '@docsearch/css')]).then(
+ ([docsearch]) => docsearch.default
+ )
+
+ // TODO: Maybe bind this with @nuxt/i18n ?
+ // Resolve lang
+ const lang = userOptions?.lang || 'en'
+
+ // Generate lang prefix
+ const langPrefix = `${userOptions.langAttribute || 'language'}:${lang}`
+
+ // Get facet filters
+ const userFacetFilters = userOptions.docSearch.facetFilters || []
+
+ // Create DocSearch instance
+ docsearch({
+ /**
+ * Local implementation of this DocSearch box uses a local element with an `docsearch` id.
+ */
+ container: el,
+ appId: userOptions.applicationId,
+ apiKey: userOptions.apiKey,
+ indexName: userOptions.docSearch.indexName,
+ searchParameters: {
+ ...(!lang
+ ? {
+ facetFilters: userFacetFilters
+ }
+ : {
+ facetFilters: [langPrefix].concat(userFacetFilters)
+ }),
+ ...userOptions.searchParameters
+ },
+ /**
+ * Transform items into relative URL format (compatibility with Vue Router).
+ */
+ transformItems: userOptions.transformItems
+ ? userOptions.transformItems
+ : (items) => {
+ return items.map((item) => {
+ return {
+ ...item,
+ url: getRelativePath(item.url)
+ }
+ })
+ },
+ navigator: userOptions.navigator
+ ? userOptions.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 (route.path === hitPathname) {
+ window.location.assign(window.location.origin + itemUrl)
+ } else {
+ router.push(itemUrl)
+ }
+ }
+ },
+ hitComponent: userOptions.hitComponent
+ ? userOptions.hitComponent
+ : ({ hit, children }) => {
+ return {
+ type: 'a',
+ constructor: undefined,
+ __v: 1,
+ props: {
+ href: hit.url,
+ children,
+ onClick: (event: MouseEvent) => {
+ 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 (route.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 (route.path !== hitPathname) {
+ event.preventDefault()
+ }
+ router.push(hit.url)
+ }
+ }
+ }
+ },
+ // Spread user options, except the ones that are already used in the instance.
+ ...Object.entries(userOptions)
+ // Skip already used keys
+ .filter(([key]) => !['applicationId', 'apiKey', 'indexName', 'transformItems', 'navigator', 'hitComponent', 'facetFilters', 'langAttribute', 'lang'].includes(key))
+ // Recompose options
+ .reduce((acc: any, [key, value]) => {
+ acc[key] = value
+ return acc
+ }, {})
+ })
+ }
+
+ // Watch options and restart the instance if needed.
+ if (process.client) { initialize(options.value) }
+ }
+
+ return {
+ provide: {
+ docSearch: {
+ element: docSearchElement,
+ hasDocSearch
+ }
+ }
+ }
+})