|
4 | 4 |
|
5 | 5 | <script setup lang="ts"> |
6 | 6 | import '@docsearch/css' |
7 | | -import { useRoute, useRouter } from 'vitepress' |
8 | | -import { defineProps, getCurrentInstance, onMounted, watch } from 'vue' |
9 | 7 | import docsearch from '@docsearch/js' |
10 | | -import type { DocSearchHit } from '@docsearch/react/dist/esm/types' |
11 | | -import type { DefaultTheme } from '../config' |
| 8 | +import { onMounted } from 'vue' |
| 9 | +import { useRouter, useRoute, useData } from 'vitepress' |
12 | 10 |
|
13 | | -const props = defineProps<{ |
14 | | - options: DefaultTheme.AlgoliaSearchOptions |
15 | | -}>() |
16 | | -
|
17 | | -const vm = getCurrentInstance() |
18 | | -const route = useRoute() |
19 | 11 | const router = useRouter() |
20 | | -
|
21 | | -watch( |
22 | | - () => props.options, |
23 | | - (value) => { |
24 | | - update(value) |
25 | | - }, |
26 | | -) |
| 12 | +const route = useRoute() |
| 13 | +const { theme, site } = useData() |
27 | 14 |
|
28 | 15 | onMounted(() => { |
29 | | - initialize(props.options) |
| 16 | + initialize(theme.value.algolia) |
30 | 17 | }) |
31 | 18 |
|
32 | | -function isSpecialClick(event: MouseEvent) { |
33 | | - return ( |
34 | | - event.button === 1 |
35 | | - || event.altKey |
36 | | - || event.ctrlKey |
37 | | - || event.metaKey |
38 | | - || event.shiftKey |
39 | | - ) |
40 | | -} |
| 19 | +// @ts-expect-error |
| 20 | +const docsearch$ = docsearch.default ?? docsearch |
| 21 | +type DocSearchProps = Parameters<typeof docsearch$>[0] |
41 | 22 |
|
42 | | -function getRelativePath(absoluteUrl: string) { |
43 | | - const { pathname, hash } = new URL(absoluteUrl) |
44 | | -
|
45 | | - return pathname + hash |
46 | | -} |
| 23 | +function initialize(userOptions: any) { |
| 24 | + // note: multi-lang search support is removed since the theme |
| 25 | + // doesn't support multiple locales as of now. |
| 26 | + const options = Object.assign<{}, {}, DocSearchProps>({}, userOptions, { |
| 27 | + container: '#docsearch', |
| 28 | +
|
| 29 | + navigator: { |
| 30 | + navigate({ itemUrl }: any) { |
| 31 | + const { pathname: hitPathname } = new URL( |
| 32 | + window.location.origin + itemUrl |
| 33 | + ) |
| 34 | +
|
| 35 | + // router doesn't handle same-page navigation so we use the native |
| 36 | + // browser location API for anchor navigation |
| 37 | + if (route.path === hitPathname) { |
| 38 | + window.location.assign(window.location.origin + itemUrl) |
| 39 | + } else { |
| 40 | + router.go(itemUrl) |
| 41 | + } |
| 42 | + } |
| 43 | + }, |
47 | 44 |
|
48 | | -function update(options: any) { |
49 | | - if (vm && vm.vnode.el) { |
50 | | - vm.vnode.el.innerHTML |
51 | | - = '<div class="algolia-search-box" id="docsearch"></div>' |
52 | | - initialize(options) |
53 | | - } |
| 45 | + transformItems(items: any) { |
| 46 | + return items.map((item: any) => { |
| 47 | + return Object.assign({}, item, { |
| 48 | + url: getRelativePath(item.url) |
| 49 | + }) |
| 50 | + }) |
| 51 | + }, |
| 52 | +
|
| 53 | + // @ts-expect-error vue-tsc thinks this should return Vue JSX but it returns the required React one |
| 54 | + hitComponent({ hit, children }) { |
| 55 | + return { |
| 56 | + __v: null, |
| 57 | + type: 'a', |
| 58 | + ref: undefined, |
| 59 | + constructor: undefined, |
| 60 | + key: undefined, |
| 61 | + props: { href: hit.url, children } |
| 62 | + } |
| 63 | + } |
| 64 | + }) |
| 65 | +
|
| 66 | + docsearch$(options) |
54 | 67 | } |
55 | 68 |
|
56 | | -function initialize(userOptions: any) { |
57 | | - docsearch( |
58 | | - Object.assign({}, userOptions, { |
59 | | - container: '#docsearch', |
60 | | -
|
61 | | - searchParameters: Object.assign({}, userOptions.searchParameters), |
62 | | -
|
63 | | - navigator: { |
64 | | - navigate: ({ suggestionUrl }: { suggestionUrl: string }) => { |
65 | | - const { pathname: hitPathname } = new URL( |
66 | | - window.location.origin + suggestionUrl, |
67 | | - ) |
68 | | -
|
69 | | - // Router doesn't handle same-page navigation so we use the native |
70 | | - // browser location API for anchor navigation |
71 | | - if (route.path === hitPathname) |
72 | | - window.location.assign(window.location.origin + suggestionUrl) |
73 | | -
|
74 | | - else |
75 | | - router.go(suggestionUrl) |
76 | | - }, |
77 | | - }, |
78 | | -
|
79 | | - transformItems: (items: DocSearchHit[]) => { |
80 | | - return items.map((item) => { |
81 | | - return Object.assign({}, item, { |
82 | | - url: getRelativePath(item.url), |
83 | | - }) |
84 | | - }) |
85 | | - }, |
86 | | -
|
87 | | - hitComponent: ({ |
88 | | - hit, |
89 | | - children, |
90 | | - }: { |
91 | | - hit: DocSearchHit |
92 | | - children: any |
93 | | - }) => { |
94 | | - const relativeHit = hit.url.startsWith('http') |
95 | | - ? getRelativePath(hit.url as string) |
96 | | - : hit.url |
97 | | -
|
98 | | - return { |
99 | | - type: 'a', |
100 | | - ref: undefined, |
101 | | - constructor: undefined, |
102 | | - key: undefined, |
103 | | - props: { |
104 | | - href: hit.url, |
105 | | - onClick: (event: MouseEvent) => { |
106 | | - if (isSpecialClick(event)) |
107 | | - return |
108 | | -
|
109 | | - // we rely on the native link scrolling when user is already on |
110 | | - // the right anchor because Router doesn't support duplicated |
111 | | - // history entries |
112 | | - if (route.path === relativeHit) |
113 | | - return |
114 | | -
|
115 | | - // if the hits goes to another page, we prevent the native link |
116 | | - // behavior to leverage the Router loading feature |
117 | | - if (route.path !== relativeHit) |
118 | | - event.preventDefault() |
119 | | -
|
120 | | - router.go(relativeHit) |
121 | | - }, |
122 | | - children, |
123 | | - }, |
124 | | - } |
125 | | - }, |
126 | | - }), |
| 69 | +function getRelativePath(absoluteUrl: string) { |
| 70 | + const { pathname, hash } = new URL(absoluteUrl) |
| 71 | + return ( |
| 72 | + pathname.replace( |
| 73 | + /\.html$/, |
| 74 | + // @ts-expect-error |
| 75 | + site.value.cleanUrls === 'disabled' ? '.html' : '' |
| 76 | + ) + hash |
127 | 77 | ) |
128 | 78 | } |
129 | 79 | </script> |
|
0 commit comments