vitepress 2.0.0-alpha.2 → 2.0.0-alpha.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (286) hide show
  1. package/README.md +34 -2
  2. package/THIRD-PARTY-NOTICES.md +1736 -0
  3. package/bin/vitepress.js +14 -0
  4. package/client.d.ts +9 -0
  5. package/dist/client/app/components/ClientOnly.d.ts +5 -0
  6. package/dist/client/app/components/ClientOnly.js +11 -10
  7. package/dist/client/app/components/Content.d.ts +17 -0
  8. package/dist/client/app/components/Content.js +25 -22
  9. package/dist/client/app/composables/codeGroups.d.ts +3 -0
  10. package/dist/client/app/composables/codeGroups.js +36 -39
  11. package/dist/client/app/composables/copyCode.d.ts +3 -0
  12. package/dist/client/app/composables/copyCode.js +59 -70
  13. package/dist/client/app/composables/head.d.ts +5 -0
  14. package/dist/client/app/composables/head.js +56 -74
  15. package/dist/client/app/composables/icon.d.ts +12 -0
  16. package/dist/client/app/composables/icon.js +56 -0
  17. package/dist/client/app/composables/preFetch.d.ts +3 -0
  18. package/dist/client/app/composables/preFetch.js +64 -96
  19. package/dist/client/app/data.d.ts +9 -0
  20. package/dist/client/app/data.js +34 -59
  21. package/dist/client/app/devtools.d.ts +7 -0
  22. package/dist/client/app/devtools.js +29 -28
  23. package/dist/client/app/index.d.ts +11 -0
  24. package/dist/client/app/index.js +106 -131
  25. package/dist/client/app/router.d.ts +49 -0
  26. package/dist/client/app/router.js +198 -239
  27. package/dist/client/app/ssr.d.ts +4 -0
  28. package/dist/client/app/ssr.js +14 -9
  29. package/dist/client/app/theme.d.ts +24 -0
  30. package/dist/client/app/theme.js +0 -1
  31. package/dist/client/app/utils.d.ts +35 -0
  32. package/dist/client/app/utils.js +77 -110
  33. package/dist/client/index.d.ts +21 -137
  34. package/dist/client/index.js +8 -9
  35. package/dist/client/shared.d.ts +88 -0
  36. package/dist/client/shared.js +265 -141
  37. package/dist/client/theme-default/Layout.d.vue.ts +79 -0
  38. package/dist/client/theme-default/Layout.vue +33 -36
  39. package/dist/client/theme-default/NotFound.d.vue.ts +3 -0
  40. package/dist/client/theme-default/NotFound.vue +33 -35
  41. package/dist/client/theme-default/components/VPAlgoliaSearchBox.d.vue.ts +11 -0
  42. package/dist/client/theme-default/components/VPAlgoliaSearchBox.vue +202 -70
  43. package/dist/client/theme-default/components/VPBackdrop.d.vue.ts +6 -0
  44. package/dist/client/theme-default/components/VPBackdrop.vue +8 -12
  45. package/dist/client/theme-default/components/VPBadge.d.vue.ts +19 -0
  46. package/dist/client/theme-default/components/VPBadge.vue +49 -26
  47. package/dist/client/theme-default/components/VPButton.d.vue.ts +25 -0
  48. package/dist/client/theme-default/components/VPButton.vue +53 -36
  49. package/dist/client/theme-default/components/VPCarbonAds.d.vue.ts +7 -0
  50. package/dist/client/theme-default/components/VPCarbonAds.vue +51 -52
  51. package/dist/client/theme-default/components/VPContent.d.vue.ts +59 -0
  52. package/dist/client/theme-default/components/VPContent.vue +27 -26
  53. package/dist/client/theme-default/components/VPDoc.d.vue.ts +33 -0
  54. package/dist/client/theme-default/components/VPDoc.vue +52 -48
  55. package/dist/client/theme-default/components/VPDocAside.d.vue.ts +23 -0
  56. package/dist/client/theme-default/components/VPDocAside.vue +7 -8
  57. package/dist/client/theme-default/components/VPDocAsideCarbonAds.d.vue.ts +7 -0
  58. package/dist/client/theme-default/components/VPDocAsideCarbonAds.vue +7 -11
  59. package/dist/client/theme-default/components/VPDocAsideOutline.d.vue.ts +3 -0
  60. package/dist/client/theme-default/components/VPDocAsideOutline.vue +22 -38
  61. package/dist/client/theme-default/components/VPDocAsideSponsors.d.vue.ts +10 -0
  62. package/dist/client/theme-default/components/VPDocAsideSponsors.vue +17 -11
  63. package/dist/client/theme-default/components/VPDocFooter.d.vue.ts +13 -0
  64. package/dist/client/theme-default/components/VPDocFooter.vue +38 -45
  65. package/dist/client/theme-default/components/VPDocFooterLastUpdated.d.vue.ts +3 -0
  66. package/dist/client/theme-default/components/VPDocFooterLastUpdated.vue +30 -29
  67. package/dist/client/theme-default/components/VPDocOutlineItem.d.vue.ts +8 -0
  68. package/dist/client/theme-default/components/VPDocOutlineItem.vue +20 -19
  69. package/dist/client/theme-default/components/VPFeature.d.vue.ts +13 -0
  70. package/dist/client/theme-default/components/VPFeature.vue +62 -36
  71. package/dist/client/theme-default/components/VPFeatures.d.vue.ts +16 -0
  72. package/dist/client/theme-default/components/VPFeatures.vue +35 -48
  73. package/dist/client/theme-default/components/VPFlyout.d.vue.ts +26 -0
  74. package/dist/client/theme-default/components/VPFlyout.vue +111 -47
  75. package/dist/client/theme-default/components/VPFooter.d.vue.ts +3 -0
  76. package/dist/client/theme-default/components/VPFooter.vue +22 -15
  77. package/dist/client/theme-default/components/VPHero.d.vue.ts +38 -0
  78. package/dist/client/theme-default/components/VPHero.vue +109 -99
  79. package/dist/client/theme-default/components/VPHome.d.vue.ts +31 -0
  80. package/dist/client/theme-default/components/VPHome.vue +15 -15
  81. package/dist/client/theme-default/components/VPHomeContent.d.vue.ts +13 -0
  82. package/dist/client/theme-default/components/VPHomeContent.vue +9 -27
  83. package/dist/client/theme-default/components/VPHomeFeatures.d.vue.ts +3 -0
  84. package/dist/client/theme-default/components/VPHomeFeatures.vue +4 -5
  85. package/dist/client/theme-default/components/VPHomeHero.d.vue.ts +23 -0
  86. package/dist/client/theme-default/components/VPHomeHero.vue +5 -5
  87. package/dist/client/theme-default/components/VPHomeSponsors.d.vue.ts +21 -0
  88. package/dist/client/theme-default/components/VPHomeSponsors.vue +42 -43
  89. package/dist/client/theme-default/components/VPIcon.d.vue.ts +8 -0
  90. package/dist/client/theme-default/components/VPIcon.vue +29 -0
  91. package/dist/client/theme-default/components/VPImage.d.vue.ts +8 -0
  92. package/dist/client/theme-default/components/VPImage.vue +20 -14
  93. package/dist/client/theme-default/components/VPLink.d.vue.ts +23 -0
  94. package/dist/client/theme-default/components/VPLink.vue +42 -23
  95. package/dist/client/theme-default/components/VPLocalNav.d.vue.ts +10 -0
  96. package/dist/client/theme-default/components/VPLocalNav.vue +69 -86
  97. package/dist/client/theme-default/components/VPLocalNavOutlineDropdown.d.vue.ts +8 -0
  98. package/dist/client/theme-default/components/VPLocalNavOutlineDropdown.vue +98 -96
  99. package/dist/client/theme-default/components/VPLocalSearchBox.d.vue.ts +7 -0
  100. package/dist/client/theme-default/components/VPLocalSearchBox.vue +391 -454
  101. package/dist/client/theme-default/components/VPMenu.d.vue.ts +23 -0
  102. package/dist/client/theme-default/components/VPMenu.vue +19 -31
  103. package/dist/client/theme-default/components/VPMenuGroup.d.vue.ts +22 -0
  104. package/dist/client/theme-default/components/VPMenuGroup.vue +72 -18
  105. package/dist/client/theme-default/components/VPMenuLink.d.vue.ts +22 -0
  106. package/dist/client/theme-default/components/VPMenuLink.vue +65 -31
  107. package/dist/client/theme-default/components/VPNav.d.vue.ts +23 -0
  108. package/dist/client/theme-default/components/VPNav.vue +18 -24
  109. package/dist/client/theme-default/components/VPNavAppearance.d.vue.ts +9 -0
  110. package/dist/client/theme-default/components/VPNavAppearance.vue +88 -0
  111. package/dist/client/theme-default/components/VPNavBar.d.vue.ts +26 -0
  112. package/dist/client/theme-default/components/VPNavBar.vue +170 -142
  113. package/dist/client/theme-default/components/VPNavBarAskAiButton.d.vue.ts +3 -0
  114. package/dist/client/theme-default/components/VPNavBarAskAiButton.vue +31 -0
  115. package/dist/client/theme-default/components/VPNavBarExtra.d.vue.ts +3 -0
  116. package/dist/client/theme-default/components/VPNavBarExtra.vue +51 -73
  117. package/dist/client/theme-default/components/VPNavBarHamburger.d.vue.ts +10 -0
  118. package/dist/client/theme-default/components/VPNavBarHamburger.vue +38 -28
  119. package/dist/client/theme-default/components/VPNavBarSearch.d.vue.ts +3 -0
  120. package/dist/client/theme-default/components/VPNavBarSearch.vue +129 -160
  121. package/dist/client/theme-default/components/VPNavBarSearchButton.d.vue.ts +6 -0
  122. package/dist/client/theme-default/components/VPNavBarSearchButton.vue +48 -182
  123. package/dist/client/theme-default/components/VPNavBarTitle.d.vue.ts +15 -0
  124. package/dist/client/theme-default/components/VPNavBarTitle.vue +39 -38
  125. package/dist/client/theme-default/components/VPNavMenu.d.vue.ts +6 -0
  126. package/dist/client/theme-default/components/VPNavMenu.vue +76 -0
  127. package/dist/client/theme-default/components/VPNavMenuGroup.d.vue.ts +11 -0
  128. package/dist/client/theme-default/components/VPNavMenuGroup.vue +140 -0
  129. package/dist/client/theme-default/components/VPNavMenuLink.d.vue.ts +8 -0
  130. package/dist/client/theme-default/components/VPNavMenuLink.vue +69 -0
  131. package/dist/client/theme-default/components/VPNavScreen.d.vue.ts +18 -0
  132. package/dist/client/theme-default/components/VPNavScreen.vue +36 -34
  133. package/dist/client/theme-default/components/VPNavSocialLinks.d.vue.ts +6 -0
  134. package/dist/client/theme-default/components/VPNavSocialLinks.vue +36 -0
  135. package/dist/client/theme-default/components/VPNavTranslations.d.vue.ts +9 -0
  136. package/dist/client/theme-default/components/VPNavTranslations.vue +170 -0
  137. package/dist/client/theme-default/components/VPPage.d.vue.ts +15 -0
  138. package/dist/client/theme-default/components/VPSidebar.d.vue.ts +18 -0
  139. package/dist/client/theme-default/components/VPSidebar.vue +40 -53
  140. package/dist/client/theme-default/components/VPSidebarGroup.d.vue.ts +7 -0
  141. package/dist/client/theme-default/components/VPSidebarGroup.vue +24 -29
  142. package/dist/client/theme-default/components/VPSidebarItem.d.vue.ts +8 -0
  143. package/dist/client/theme-default/components/VPSidebarItem.vue +60 -93
  144. package/dist/client/theme-default/components/VPSkipLink.d.vue.ts +6 -0
  145. package/dist/client/theme-default/components/VPSkipLink.vue +23 -42
  146. package/dist/client/theme-default/components/VPSocialLink.d.vue.ts +11 -0
  147. package/dist/client/theme-default/components/VPSocialLink.vue +42 -49
  148. package/dist/client/theme-default/components/VPSocialLinks.d.vue.ts +10 -0
  149. package/dist/client/theme-default/components/VPSocialLinks.vue +26 -16
  150. package/dist/client/theme-default/components/VPSponsors.d.vue.ts +18 -0
  151. package/dist/client/theme-default/components/VPSponsors.vue +34 -33
  152. package/dist/client/theme-default/components/VPSponsorsGrid.d.vue.ts +15 -0
  153. package/dist/client/theme-default/components/VPSponsorsGrid.vue +23 -26
  154. package/dist/client/theme-default/components/VPSwitch.d.vue.ts +13 -0
  155. package/dist/client/theme-default/components/VPSwitch.vue +12 -13
  156. package/dist/client/theme-default/components/VPSwitchAppearance.d.vue.ts +3 -0
  157. package/dist/client/theme-default/components/VPSwitchAppearance.vue +16 -21
  158. package/dist/client/theme-default/components/VPTeamMembers.d.vue.ts +10 -0
  159. package/dist/client/theme-default/components/VPTeamMembers.vue +59 -32
  160. package/dist/client/theme-default/components/VPTeamMembersItem.d.vue.ts +10 -0
  161. package/dist/client/theme-default/components/VPTeamMembersItem.vue +62 -58
  162. package/dist/client/theme-default/components/VPTeamPage.d.vue.ts +13 -0
  163. package/dist/client/theme-default/components/VPTeamPage.vue +14 -14
  164. package/dist/client/theme-default/components/VPTeamPageSection.d.vue.ts +17 -0
  165. package/dist/client/theme-default/components/VPTeamPageSection.vue +20 -19
  166. package/dist/client/theme-default/components/VPTeamPageTitle.d.vue.ts +15 -0
  167. package/dist/client/theme-default/components/VPTeamPageTitle.vue +22 -22
  168. package/dist/client/theme-default/composables/data.d.ts +5 -0
  169. package/dist/client/theme-default/composables/data.js +5 -2
  170. package/dist/client/theme-default/composables/edit-link.d.ts +6 -0
  171. package/dist/client/theme-default/composables/edit-link.js +17 -15
  172. package/dist/client/theme-default/composables/flyout.d.ts +10 -0
  173. package/dist/client/theme-default/composables/flyout.js +33 -32
  174. package/dist/client/theme-default/composables/langs.d.ts +44 -0
  175. package/dist/client/theme-default/composables/langs.js +48 -24
  176. package/dist/client/theme-default/composables/layout.d.ts +13 -0
  177. package/dist/client/theme-default/composables/layout.js +68 -0
  178. package/dist/client/theme-default/composables/nav-overflow.d.ts +54 -0
  179. package/dist/client/theme-default/composables/nav-overflow.js +179 -0
  180. package/dist/client/theme-default/composables/nav.d.ts +25 -0
  181. package/dist/client/theme-default/composables/nav.js +58 -29
  182. package/dist/client/theme-default/composables/outline.d.ts +8 -0
  183. package/dist/client/theme-default/composables/outline.js +144 -166
  184. package/dist/client/theme-default/composables/prev-next.d.ts +16 -0
  185. package/dist/client/theme-default/composables/prev-next.js +34 -56
  186. package/dist/client/theme-default/composables/scroll-lock.d.ts +4 -0
  187. package/dist/client/theme-default/composables/scroll-lock.js +95 -0
  188. package/dist/client/theme-default/composables/sidebar.d.ts +25 -0
  189. package/dist/client/theme-default/composables/sidebar.js +96 -133
  190. package/dist/client/theme-default/composables/sponsor-grid.d.ts +10 -0
  191. package/dist/client/theme-default/composables/sponsor-grid.js +69 -76
  192. package/dist/client/theme-default/fonts/inter-italic-cyrillic-ext.woff2 +0 -0
  193. package/dist/client/theme-default/fonts/inter-italic-cyrillic.woff2 +0 -0
  194. package/dist/client/theme-default/fonts/inter-italic-greek-ext.woff2 +0 -0
  195. package/dist/client/theme-default/fonts/inter-italic-greek.woff2 +0 -0
  196. package/dist/client/theme-default/fonts/inter-italic-latin-ext.woff2 +0 -0
  197. package/dist/client/theme-default/fonts/inter-italic-latin.woff2 +0 -0
  198. package/dist/client/theme-default/fonts/inter-italic-symbols.woff2 +0 -0
  199. package/dist/client/theme-default/fonts/inter-italic-vietnamese.woff2 +0 -0
  200. package/dist/client/theme-default/fonts/inter-roman-cyrillic-ext.woff2 +0 -0
  201. package/dist/client/theme-default/fonts/inter-roman-cyrillic.woff2 +0 -0
  202. package/dist/client/theme-default/fonts/inter-roman-greek-ext.woff2 +0 -0
  203. package/dist/client/theme-default/fonts/inter-roman-greek.woff2 +0 -0
  204. package/dist/client/theme-default/fonts/inter-roman-latin-ext.woff2 +0 -0
  205. package/dist/client/theme-default/fonts/inter-roman-latin.woff2 +0 -0
  206. package/dist/client/theme-default/fonts/inter-roman-symbols.woff2 +0 -0
  207. package/dist/client/theme-default/fonts/inter-roman-vietnamese.woff2 +0 -0
  208. package/dist/client/theme-default/index.d.ts +3 -0
  209. package/dist/client/theme-default/index.js +4 -3
  210. package/dist/client/theme-default/styles/base.css +279 -211
  211. package/dist/client/theme-default/styles/components/custom-block.css +12 -7
  212. package/dist/client/theme-default/styles/components/vp-code-group.css +13 -16
  213. package/dist/client/theme-default/styles/components/vp-code.css +10 -2
  214. package/dist/client/theme-default/styles/components/vp-doc.css +188 -142
  215. package/dist/client/theme-default/styles/components/vp-sponsor.css +48 -37
  216. package/dist/client/theme-default/styles/docsearch.css +138 -0
  217. package/dist/client/theme-default/styles/fonts.css +216 -55
  218. package/dist/client/theme-default/styles/icons.css +42 -22
  219. package/dist/client/theme-default/styles/vars.css +111 -46
  220. package/dist/client/theme-default/support/docsearch.d.ts +57 -0
  221. package/dist/client/theme-default/support/docsearch.js +145 -0
  222. package/dist/client/theme-default/support/local-search.d.ts +9 -0
  223. package/dist/client/theme-default/support/local-search.js +31 -0
  224. package/dist/client/theme-default/support/lru.d.ts +11 -0
  225. package/dist/client/theme-default/support/lru.js +30 -33
  226. package/dist/client/theme-default/support/reactivity.d.ts +4 -0
  227. package/dist/client/theme-default/support/reactivity.js +10 -0
  228. package/dist/client/theme-default/support/sidebar.d.ts +27 -0
  229. package/dist/client/theme-default/support/sidebar.js +69 -80
  230. package/dist/client/theme-default/support/translation.d.ts +6 -0
  231. package/dist/client/theme-default/support/translation.js +33 -47
  232. package/dist/client/theme-default/support/utils.d.ts +7 -0
  233. package/dist/client/theme-default/support/utils.js +39 -30
  234. package/dist/client/theme-default/without-fonts.d.ts +25 -0
  235. package/dist/client/theme-default/without-fonts.js +37 -36
  236. package/dist/node/chunk-BjrVv9r8.js +28627 -0
  237. package/dist/node/cli.d.ts +1 -0
  238. package/dist/node/cli.js +160 -423
  239. package/dist/node/index.d.ts +1761 -2476
  240. package/dist/node/index.js +1 -121
  241. package/dist/web-types.json +75 -0
  242. package/package.json +89 -98
  243. package/template/.vitepress/config.js +3 -1
  244. package/template/.vitepress/theme/style.css +3 -11
  245. package/theme.d.ts +30 -23
  246. package/types/default-theme.d.ts +109 -113
  247. package/types/docsearch.d.ts +61 -142
  248. package/types/shared.d.ts +469 -50
  249. package/dist/client/theme-default/components/VPNavBarAppearance.vue +0 -32
  250. package/dist/client/theme-default/components/VPNavBarMenu.vue +0 -40
  251. package/dist/client/theme-default/components/VPNavBarMenuGroup.vue +0 -42
  252. package/dist/client/theme-default/components/VPNavBarMenuLink.vue +0 -53
  253. package/dist/client/theme-default/components/VPNavBarSocialLinks.vue +0 -27
  254. package/dist/client/theme-default/components/VPNavBarTranslations.vue +0 -47
  255. package/dist/client/theme-default/components/VPNavScreenAppearance.vue +0 -40
  256. package/dist/client/theme-default/components/VPNavScreenMenu.vue +0 -26
  257. package/dist/client/theme-default/components/VPNavScreenMenuGroup.vue +0 -112
  258. package/dist/client/theme-default/components/VPNavScreenMenuGroupLink.vue +0 -40
  259. package/dist/client/theme-default/components/VPNavScreenMenuGroupSection.vue +0 -34
  260. package/dist/client/theme-default/components/VPNavScreenMenuLink.vue +0 -43
  261. package/dist/client/theme-default/components/VPNavScreenSocialLinks.vue +0 -14
  262. package/dist/client/theme-default/components/VPNavScreenTranslations.vue +0 -73
  263. package/dist/client/theme-default/components/icons/VPIconAlignJustify.vue +0 -8
  264. package/dist/client/theme-default/components/icons/VPIconAlignLeft.vue +0 -8
  265. package/dist/client/theme-default/components/icons/VPIconAlignRight.vue +0 -8
  266. package/dist/client/theme-default/components/icons/VPIconArrowLeft.vue +0 -7
  267. package/dist/client/theme-default/components/icons/VPIconArrowRight.vue +0 -7
  268. package/dist/client/theme-default/components/icons/VPIconChevronDown.vue +0 -5
  269. package/dist/client/theme-default/components/icons/VPIconChevronLeft.vue +0 -5
  270. package/dist/client/theme-default/components/icons/VPIconChevronRight.vue +0 -5
  271. package/dist/client/theme-default/components/icons/VPIconChevronUp.vue +0 -5
  272. package/dist/client/theme-default/components/icons/VPIconEdit.vue +0 -6
  273. package/dist/client/theme-default/components/icons/VPIconHeart.vue +0 -5
  274. package/dist/client/theme-default/components/icons/VPIconLanguages.vue +0 -9
  275. package/dist/client/theme-default/components/icons/VPIconMinus.vue +0 -5
  276. package/dist/client/theme-default/components/icons/VPIconMinusSquare.vue +0 -6
  277. package/dist/client/theme-default/components/icons/VPIconMoon.vue +0 -5
  278. package/dist/client/theme-default/components/icons/VPIconMoreHorizontal.vue +0 -7
  279. package/dist/client/theme-default/components/icons/VPIconPlus.vue +0 -5
  280. package/dist/client/theme-default/components/icons/VPIconPlusSquare.vue +0 -6
  281. package/dist/client/theme-default/components/icons/VPIconSun.vue +0 -13
  282. package/dist/client/theme-default/composables/aside.js +0 -17
  283. package/dist/client/theme-default/composables/local-nav.js +0 -18
  284. package/dist/node/chunk-C-d2RJOW.js +0 -470
  285. package/dist/node/chunk-CxQfvv8o.js +0 -49065
  286. package/dist/node/worker_shikiResolveLang.js +0 -13
@@ -1,414 +1,317 @@
1
- <script lang="ts" setup>
2
- import localSearchIndex from '@localSearchIndex'
3
- import {
4
- computedAsync,
5
- debouncedWatch,
6
- onKeyStroke,
7
- useEventListener,
8
- useLocalStorage,
9
- useScrollLock,
10
- useSessionStorage
11
- } from '@vueuse/core'
12
- import { useFocusTrap } from '@vueuse/integrations/useFocusTrap'
13
- import Mark from 'mark.js/src/vanilla.js'
14
- import MiniSearch, { type SearchResult } from 'minisearch'
15
- import { dataSymbol, inBrowser, useRouter } from 'vitepress'
16
- import {
17
- computed,
18
- createApp,
19
- markRaw,
20
- nextTick,
21
- onBeforeUnmount,
22
- onMounted,
23
- ref,
24
- shallowRef,
25
- watch,
26
- watchEffect,
27
- type Ref
28
- } from 'vue'
29
- import type { ModalTranslations } from '../../../../types/local-search'
30
- import { pathToFile } from '../../app/utils'
31
- import { escapeRegExp } from '../../shared'
32
- import { useData } from '../composables/data'
33
- import { LRUCache } from '../support/lru'
34
- import { createSearchTranslate } from '../support/translation'
35
-
36
- const emit = defineEmits<{
37
- (e: 'close'): void
38
- }>()
39
-
40
- const el = shallowRef<HTMLElement>()
41
- const resultsEl = shallowRef<HTMLElement>()
42
-
1
+ <script setup>
2
+ import localSearchIndex from "@localSearchIndex";
3
+ import { computedAsync, watchDebounced, onKeyStroke, useEventListener, useLocalStorage, useSessionStorage } from "@vueuse/core";
4
+ import { useFocusTrap } from "@vueuse/integrations/useFocusTrap";
5
+ import Mark from "mark.js/src/vanilla.js";
6
+ import "minisearch";
7
+ import { dataSymbol, useRouter, withBase } from "vitepress";
8
+ import { computed, createApp, markRaw, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, useTemplateRef, watch, watchEffect } from "vue";
9
+ import { pathToFile } from "../../app/utils";
10
+ import { escapeRegExp } from "../../shared";
11
+ import { useData } from "../composables/data";
12
+ import { useBodyScrollLock } from "../composables/scroll-lock";
13
+ import { loadLocalSearchIndex } from "../support/local-search";
14
+ import { LRUCache } from "../support/lru";
15
+ import { createSearchTranslate } from "../support/translation";
16
+ const emit = defineEmits(["close"]);
17
+ const el = useTemplateRef("el");
18
+ const resultsEl = useTemplateRef("resultsEl");
43
19
  /* Search */
44
-
45
- const searchIndexData = shallowRef(localSearchIndex)
46
-
20
+ const searchIndexData = shallowRef(localSearchIndex);
47
21
  // hmr
48
22
  if (import.meta.hot) {
49
- import.meta.hot.accept('/@localSearchIndex', (m) => {
50
- if (m) {
51
- searchIndexData.value = m.default
52
- }
53
- })
54
- }
55
-
56
- interface Result {
57
- title: string
58
- titles: string[]
59
- text?: string
23
+ import.meta.hot.accept("@localSearchIndex", (m) => {
24
+ if (m) {
25
+ searchIndexData.value = m.default;
26
+ }
27
+ });
60
28
  }
61
-
62
- const vitePressData = useData()
29
+ const vitePressData = useData();
63
30
  const { activate } = useFocusTrap(el, {
64
- immediate: true,
65
- allowOutsideClick: true,
66
- clickOutsideDeactivates: true,
67
- escapeDeactivates: true
68
- })
69
- const { localeIndex, theme } = vitePressData
70
- const searchIndex = computedAsync(async () =>
71
- markRaw(
72
- MiniSearch.loadJSON<Result>(
73
- (await searchIndexData.value[localeIndex.value]?.())?.default,
74
- {
75
- fields: ['title', 'titles', 'text'],
76
- storeFields: ['title', 'titles'],
77
- searchOptions: {
78
- fuzzy: 0.2,
79
- prefix: true,
80
- boost: { title: 4, text: 2, titles: 1 },
81
- ...(theme.value.search?.provider === 'local' &&
82
- theme.value.search.options?.miniSearch?.searchOptions)
83
- },
84
- ...(theme.value.search?.provider === 'local' &&
85
- theme.value.search.options?.miniSearch?.options)
86
- }
87
- )
88
- )
89
- )
90
-
31
+ immediate: true,
32
+ allowOutsideClick: true,
33
+ clickOutsideDeactivates: true,
34
+ escapeDeactivates: true
35
+ });
36
+ const { localeIndex, theme } = vitePressData;
37
+ const isSearchIndexLoading = ref(false);
38
+ const isSearching = ref(false);
39
+ const showSearchSpinner = computed(() => {
40
+ return isSearchIndexLoading.value || isSearching.value;
41
+ });
42
+ const searchIndex = computedAsync(async () => {
43
+ const json = (await searchIndexData.value[localeIndex.value]?.())?.default;
44
+ if (!json) return null;
45
+ return markRaw(loadLocalSearchIndex(json, theme.value.search?.provider === "local" ? theme.value.search.options?.miniSearch : undefined));
46
+ }, undefined, isSearchIndexLoading);
91
47
  const disableQueryPersistence = computed(() => {
92
- return (
93
- theme.value.search?.provider === 'local' &&
94
- theme.value.search.options?.disableQueryPersistence === true
95
- )
96
- })
97
-
98
- const filterText = disableQueryPersistence.value
99
- ? ref('')
100
- : useSessionStorage('vitepress:local-search-filter', '')
101
-
102
- const showDetailedList = useLocalStorage(
103
- 'vitepress:local-search-detailed-list',
104
- theme.value.search?.provider === 'local' &&
105
- theme.value.search.options?.detailedView === true
106
- )
107
-
48
+ return theme.value.search?.provider === "local" && theme.value.search.options?.disableQueryPersistence === true;
49
+ });
50
+ const filterText = disableQueryPersistence.value ? ref("") : useSessionStorage("vitepress:local-search-filter", "");
51
+ const showDetailedList = useLocalStorage("vitepress:local-search-detailed-list", theme.value.search?.provider === "local" && theme.value.search.options?.detailedView === true);
108
52
  const disableDetailedView = computed(() => {
109
- return (
110
- theme.value.search?.provider === 'local' &&
111
- (theme.value.search.options?.disableDetailedView === true ||
112
- theme.value.search.options?.detailedView === false)
113
- )
114
- })
115
-
116
- const buttonText = computed(() => {
117
- const options = theme.value.search?.options ?? theme.value.algolia
118
-
119
- return (
120
- options?.locales?.[localeIndex.value]?.translations?.button?.buttonText ||
121
- options?.translations?.button?.buttonText ||
122
- 'Search'
123
- )
124
- })
125
-
53
+ return theme.value.search?.provider === "local" && theme.value.search.options?.detailedView === false;
54
+ });
126
55
  watchEffect(() => {
127
- if (disableDetailedView.value) {
128
- showDetailedList.value = false
129
- }
130
- })
131
-
132
- const results: Ref<(SearchResult & Result)[]> = shallowRef([])
133
-
134
- const enableNoResults = ref(false)
135
-
56
+ if (disableDetailedView.value) {
57
+ showDetailedList.value = false;
58
+ }
59
+ });
60
+ const results = shallowRef([]);
61
+ const enableNoResults = ref(false);
136
62
  watch(filterText, () => {
137
- enableNoResults.value = false
138
- })
139
-
63
+ enableNoResults.value = false;
64
+ });
140
65
  const mark = computedAsync(async () => {
141
- if (!resultsEl.value) return
142
- return markRaw(new Mark(resultsEl.value))
143
- }, null)
144
-
145
- const cache = new LRUCache<string, Map<string, string>>(16) // 16 files
146
-
147
- debouncedWatch(
148
- () => [searchIndex.value, filterText.value, showDetailedList.value] as const,
149
- async ([index, filterTextValue, showDetailedListValue], old, onCleanup) => {
150
- if (old?.[0] !== index) {
151
- // in case of hmr
152
- cache.clear()
153
- }
154
-
155
- let canceled = false
156
- onCleanup(() => {
157
- canceled = true
158
- })
159
-
160
- if (!index) return
161
-
162
- // Search
163
- results.value = index
164
- .search(filterTextValue)
165
- .slice(0, 16) as (SearchResult & Result)[]
166
- enableNoResults.value = true
167
-
168
- // Highlighting
169
- const mods = showDetailedListValue
170
- ? await Promise.all(results.value.map((r) => fetchExcerpt(r.id)))
171
- : []
172
- if (canceled) return
173
- for (const { id, mod } of mods) {
174
- const mapId = id.slice(0, id.indexOf('#'))
175
- let map = cache.get(mapId)
176
- if (map) continue
177
- map = new Map()
178
- cache.set(mapId, map)
179
- const comp = mod.default ?? mod
180
- if (comp?.render || comp?.setup) {
181
- const app = createApp(comp)
182
- // Silence warnings about missing components
183
- app.config.warnHandler = () => {}
184
- app.provide(dataSymbol, vitePressData)
185
- Object.defineProperties(app.config.globalProperties, {
186
- $frontmatter: {
187
- get() {
188
- return vitePressData.frontmatter.value
189
- }
190
- },
191
- $params: {
192
- get() {
193
- return vitePressData.page.value.params
194
- }
195
- }
196
- })
197
- const div = document.createElement('div')
198
- app.mount(div)
199
- const headings = div.querySelectorAll('h1, h2, h3, h4, h5, h6')
200
- headings.forEach((el) => {
201
- const href = el.querySelector('a')?.getAttribute('href')
202
- const anchor = href?.startsWith('#') && href.slice(1)
203
- if (!anchor) return
204
- let html = ''
205
- while ((el = el.nextElementSibling!) && !/^h[1-6]$/i.test(el.tagName))
206
- html += el.outerHTML
207
- map!.set(anchor, html)
208
- })
209
- app.unmount()
210
- }
211
- if (canceled) return
212
- }
213
-
214
- const terms = new Set<string>()
215
-
216
- results.value = results.value.map((r) => {
217
- const [id, anchor] = r.id.split('#')
218
- const map = cache.get(id)
219
- const text = map?.get(anchor) ?? ''
220
- for (const term in r.match) {
221
- terms.add(term)
222
- }
223
- return { ...r, text }
224
- })
225
-
226
- await nextTick()
227
- if (canceled) return
228
-
229
- await new Promise((r) => {
230
- mark.value?.unmark({
231
- done: () => {
232
- mark.value?.markRegExp(formMarkRegex(terms), { done: r })
233
- }
234
- })
235
- })
236
-
237
- const excerpts = el.value?.querySelectorAll('.result .excerpt') ?? []
238
- for (const excerpt of excerpts) {
239
- excerpt
240
- .querySelector('mark[data-markjs="true"]')
241
- ?.scrollIntoView({ block: 'center' })
242
- }
243
- // FIXME: without this whole page scrolls to the bottom
244
- resultsEl.value?.firstElementChild?.scrollIntoView({ block: 'start' })
245
- },
246
- { debounce: 200, immediate: true }
66
+ if (!resultsEl.value) return;
67
+ return markRaw(new Mark(resultsEl.value));
68
+ }, null);
69
+ const cache = new LRUCache(16);
70
+ watchDebounced(() => [
71
+ searchIndex.value,
72
+ filterText.value,
73
+ showDetailedList.value
74
+ ], async ([index, filterTextValue, showDetailedListValue], old, onCleanup) => {
75
+ if (old?.[0] !== index) {
76
+ // in case of hmr
77
+ cache.clear();
78
+ }
79
+ let canceled = false;
80
+ onCleanup(() => {
81
+ canceled = true;
82
+ isSearching.value = false;
83
+ });
84
+ if (!index) {
85
+ results.value = [];
86
+ return;
87
+ }
88
+ isSearching.value = true;
89
+ // Search
90
+ results.value = index.search(filterTextValue).slice(0, 16);
91
+ enableNoResults.value = true;
92
+ // Highlighting
93
+ const mods = showDetailedListValue ? await Promise.all(results.value.map((r) => fetchExcerpt(r.id))) : [];
94
+ if (canceled) return;
95
+ for (const { id, mod } of mods) {
96
+ const mapId = id.replace(/#.*$/, "");
97
+ let map = cache.get(mapId);
98
+ if (map) continue;
99
+ map = new Map();
100
+ cache.set(mapId, map);
101
+ const comp = mod.default ?? mod;
102
+ if (comp?.render || comp?.setup) {
103
+ const app = createApp(comp);
104
+ // Silence warnings about missing components
105
+ app.config.warnHandler = () => {};
106
+ app.provide(dataSymbol, vitePressData);
107
+ Object.defineProperties(app.config.globalProperties, {
108
+ $frontmatter: { get() {
109
+ return vitePressData.frontmatter.value;
110
+ } },
111
+ $params: { get() {
112
+ return vitePressData.page.value.params;
113
+ } }
114
+ });
115
+ const div = document.createElement("div");
116
+ app.mount(div);
117
+ const headings = div.querySelectorAll("h1, h2, h3, h4, h5, h6");
118
+ headings.forEach((el) => {
119
+ const href = el.querySelector("a")?.getAttribute("href");
120
+ const anchor = href?.startsWith("#") && href.slice(1);
121
+ if (!anchor) return;
122
+ let html = "";
123
+ while ((el = el.nextElementSibling) && !/^h[1-6]$/i.test(el.tagName)) html += el.outerHTML;
124
+ map.set(anchor, html);
125
+ });
126
+ app.unmount();
127
+ }
128
+ if (canceled) return;
129
+ }
130
+ const terms = new Set();
131
+ results.value = results.value.map((r) => {
132
+ const [id, anchor] = r.id.split("#");
133
+ const map = cache.get(id);
134
+ const text = map?.get(anchor) ?? "";
135
+ for (const term in r.match) {
136
+ terms.add(term);
137
+ }
138
+ return {
139
+ ...r,
140
+ text
141
+ };
142
+ });
143
+ await nextTick();
144
+ if (canceled) return;
145
+ await new Promise((r) => {
146
+ mark.value?.unmark({ done: () => {
147
+ mark.value?.markRegExp(formMarkRegex(terms), { done: r });
148
+ } });
149
+ });
150
+ const excerpts = el.value?.querySelectorAll(".result .excerpt") ?? [];
151
+ for (const excerpt of excerpts) {
152
+ excerpt.querySelector("mark[data-markjs=\"true\"]")?.scrollIntoView({ block: "center" });
153
+ }
154
+ // FIXME: without this whole page scrolls to the bottom
155
+ resultsEl.value?.firstElementChild?.scrollIntoView({ block: "start" });
156
+ isSearching.value = false;
157
+ }, {
158
+ debounce: 200,
159
+ immediate: true
160
+ });
161
+ async function fetchExcerpt(id) {
162
+ const file = pathToFile(withBase(id.replace(/#.*$/, "")));
163
+ try {
164
+ if (!file) throw new Error(`Cannot find file for id: ${id}`);
165
+ return {
166
+ id,
167
+ mod: await import(
168
+ /*@vite-ignore*/
169
+ file
247
170
  )
248
-
249
- async function fetchExcerpt(id: string) {
250
- const file = pathToFile(id.slice(0, id.indexOf('#')))
251
- try {
252
- if (!file) throw new Error(`Cannot find file for id: ${id}`)
253
- return { id, mod: await import(/*@vite-ignore*/ file) }
254
- } catch (e) {
255
- console.error(e)
256
- return { id, mod: {} }
257
- }
171
+ };
172
+ } catch (e) {
173
+ console.error(e);
174
+ return {
175
+ id,
176
+ mod: {}
177
+ };
178
+ }
258
179
  }
259
-
260
180
  /* Search input focus */
261
-
262
- const searchInput = ref<HTMLInputElement>()
181
+ const searchInput = useTemplateRef("searchInput");
263
182
  const disableReset = computed(() => {
264
- return filterText.value?.length <= 0
265
- })
183
+ return filterText.value?.length <= 0;
184
+ });
266
185
  function focusSearchInput(select = true) {
267
- searchInput.value?.focus()
268
- select && searchInput.value?.select()
186
+ searchInput.value?.focus();
187
+ select && searchInput.value?.select();
269
188
  }
270
-
271
189
  onMounted(() => {
272
- focusSearchInput()
273
- })
274
-
275
- function onSearchBarClick(event: PointerEvent) {
276
- if (event.pointerType === 'mouse') {
277
- focusSearchInput()
278
- }
190
+ focusSearchInput();
191
+ });
192
+ function onSearchBarClick(event) {
193
+ if (event.pointerType === "mouse") {
194
+ focusSearchInput();
195
+ }
279
196
  }
280
-
281
197
  /* Search keyboard selection */
282
-
283
- const selectedIndex = ref(-1)
284
- const disableMouseOver = ref(true)
285
-
198
+ const selectedIndex = ref(-1);
199
+ const disableMouseOver = ref(true);
286
200
  watch(results, (r) => {
287
- selectedIndex.value = r.length ? 0 : -1
288
- scrollToSelectedResult()
289
- })
290
-
201
+ selectedIndex.value = r.length ? 0 : -1;
202
+ scrollToSelectedResult();
203
+ });
291
204
  function scrollToSelectedResult() {
292
- nextTick(() => {
293
- const selectedEl = document.querySelector('.result.selected')
294
- selectedEl?.scrollIntoView({ block: 'nearest' })
295
- })
296
- }
297
-
298
- onKeyStroke('ArrowUp', (event) => {
299
- event.preventDefault()
300
- selectedIndex.value--
301
- if (selectedIndex.value < 0) {
302
- selectedIndex.value = results.value.length - 1
303
- }
304
- disableMouseOver.value = true
305
- scrollToSelectedResult()
306
- })
307
-
308
- onKeyStroke('ArrowDown', (event) => {
309
- event.preventDefault()
310
- selectedIndex.value++
311
- if (selectedIndex.value >= results.value.length) {
312
- selectedIndex.value = 0
313
- }
314
- disableMouseOver.value = true
315
- scrollToSelectedResult()
316
- })
317
-
318
- const router = useRouter()
319
-
320
- onKeyStroke('Enter', (e) => {
321
- if (e.isComposing) return
322
-
323
- if (e.target instanceof HTMLButtonElement && e.target.type !== 'submit')
324
- return
325
-
326
- const selectedPackage = results.value[selectedIndex.value]
327
- if (e.target instanceof HTMLInputElement && !selectedPackage) {
328
- e.preventDefault()
329
- return
330
- }
331
-
332
- if (selectedPackage) {
333
- router.go(selectedPackage.id)
334
- emit('close')
335
- }
336
- })
337
-
338
- onKeyStroke('Escape', () => {
339
- emit('close')
340
- })
341
-
342
- // Translations
343
- const defaultTranslations: { modal: ModalTranslations } = {
344
- modal: {
345
- displayDetails: 'Display detailed list',
346
- resetButtonTitle: 'Reset search',
347
- backButtonTitle: 'Close search',
348
- noResultsText: 'No results for',
349
- footer: {
350
- selectText: 'to select',
351
- selectKeyAriaLabel: 'enter',
352
- navigateText: 'to navigate',
353
- navigateUpKeyAriaLabel: 'up arrow',
354
- navigateDownKeyAriaLabel: 'down arrow',
355
- closeText: 'to close',
356
- closeKeyAriaLabel: 'escape'
357
- }
358
- }
359
- }
360
-
361
- const translate = createSearchTranslate(defaultTranslations)
362
-
363
- // Back
364
-
205
+ nextTick(() => {
206
+ const selectedEl = document.querySelector(".result.selected");
207
+ selectedEl?.scrollIntoView({ block: "nearest" });
208
+ });
209
+ }
210
+ function selectPreviousResult(event) {
211
+ event.preventDefault();
212
+ selectedIndex.value--;
213
+ if (selectedIndex.value < 0) {
214
+ selectedIndex.value = results.value.length - 1;
215
+ }
216
+ disableMouseOver.value = true;
217
+ scrollToSelectedResult();
218
+ }
219
+ function selectNextResult(event) {
220
+ event.preventDefault();
221
+ selectedIndex.value++;
222
+ if (selectedIndex.value >= results.value.length) {
223
+ selectedIndex.value = 0;
224
+ }
225
+ disableMouseOver.value = true;
226
+ scrollToSelectedResult();
227
+ }
228
+ function isMacCtrlShortcut(event) {
229
+ return event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey && document.documentElement.classList.contains("mac");
230
+ }
231
+ onKeyStroke("ArrowUp", selectPreviousResult);
232
+ onKeyStroke("ArrowDown", selectNextResult);
233
+ onKeyStroke(["p", "P"], (event) => {
234
+ if (isMacCtrlShortcut(event)) {
235
+ selectPreviousResult(event);
236
+ }
237
+ });
238
+ onKeyStroke(["n", "N"], (event) => {
239
+ if (isMacCtrlShortcut(event)) {
240
+ selectNextResult(event);
241
+ }
242
+ });
243
+ const router = useRouter();
244
+ onKeyStroke("Enter", (e) => {
245
+ if (e.isComposing) return;
246
+ if (e.target instanceof HTMLButtonElement && e.target.type !== "submit") return;
247
+ const selectedPackage = results.value[selectedIndex.value];
248
+ if (e.target instanceof HTMLInputElement && !selectedPackage) {
249
+ e.preventDefault();
250
+ return;
251
+ }
252
+ if (selectedPackage) {
253
+ router.go(withBase(selectedPackage.id));
254
+ emit("close");
255
+ }
256
+ });
257
+ onKeyStroke("Escape", () => {
258
+ emit("close");
259
+ });
260
+ /* Translations */
261
+ const defaultTranslations = {
262
+ button: { buttonText: "Search" },
263
+ modal: {
264
+ displayDetails: "Display detailed list",
265
+ resetButtonTitle: "Reset search",
266
+ backButtonTitle: "Close search",
267
+ noResultsText: "No results for",
268
+ footer: {
269
+ selectText: "to select",
270
+ selectKeyAriaLabel: "enter",
271
+ navigateText: "to navigate",
272
+ navigateUpKeyAriaLabel: "up arrow",
273
+ navigateDownKeyAriaLabel: "down arrow",
274
+ closeText: "to close",
275
+ closeKeyAriaLabel: "escape"
276
+ }
277
+ }
278
+ };
279
+ const translate = createSearchTranslate(defaultTranslations);
280
+ /* Back */
365
281
  onMounted(() => {
366
- // Prevents going to previous site
367
- window.history.pushState(null, '', null)
368
- })
369
-
370
- useEventListener('popstate', (event) => {
371
- event.preventDefault()
372
- emit('close')
373
- })
374
-
282
+ // Prevents going to previous site
283
+ window.history.pushState(null, "", null);
284
+ });
285
+ useEventListener("popstate", (event) => {
286
+ event.preventDefault();
287
+ emit("close");
288
+ });
375
289
  /** Lock body */
376
- const isLocked = useScrollLock(inBrowser ? document.body : null)
377
-
290
+ const isLocked = useBodyScrollLock();
378
291
  onMounted(() => {
379
- nextTick(() => {
380
- isLocked.value = true
381
- nextTick().then(() => activate())
382
- })
383
- })
384
-
292
+ nextTick(() => {
293
+ isLocked.value = true;
294
+ nextTick().then(() => activate());
295
+ });
296
+ });
385
297
  onBeforeUnmount(() => {
386
- isLocked.value = false
387
- })
388
-
298
+ isLocked.value = false;
299
+ });
389
300
  function resetSearch() {
390
- filterText.value = ''
391
- nextTick().then(() => focusSearchInput(false))
392
- }
393
-
394
- function formMarkRegex(terms: Set<string>) {
395
- return new RegExp(
396
- [...terms]
397
- .sort((a, b) => b.length - a.length)
398
- .map((term) => `(${escapeRegExp(term)})`)
399
- .join('|'),
400
- 'gi'
401
- )
402
- }
403
-
404
- function onMouseMove(e: MouseEvent) {
405
- if (!disableMouseOver.value) return
406
- const el = (e.target as HTMLElement)?.closest<HTMLAnchorElement>('.result')
407
- const index = Number.parseInt(el?.dataset.index!)
408
- if (index >= 0 && index !== selectedIndex.value) {
409
- selectedIndex.value = index
410
- }
411
- disableMouseOver.value = false
301
+ filterText.value = "";
302
+ nextTick().then(() => focusSearchInput(false));
303
+ }
304
+ function formMarkRegex(terms) {
305
+ return new RegExp([...terms].sort((a, b) => b.length - a.length).map((term) => `(${escapeRegExp(term)})`).join("|"), "gi");
306
+ }
307
+ function onMouseMove(e) {
308
+ if (!disableMouseOver.value) return;
309
+ const el = e.target?.closest(".result");
310
+ const index = Number.parseInt(el?.dataset.index);
311
+ if (index >= 0 && index !== selectedIndex.value) {
312
+ selectedIndex.value = index;
313
+ }
314
+ disableMouseOver.value = false;
412
315
  }
413
316
  </script>
414
317
 
@@ -432,7 +335,7 @@ function onMouseMove(e: MouseEvent) {
432
335
  @submit.prevent=""
433
336
  >
434
337
  <label
435
- :title="buttonText"
338
+ :title="translate('button.buttonText')"
436
339
  id="localsearch-label"
437
340
  for="localsearch-input"
438
341
  >
@@ -450,7 +353,7 @@ function onMouseMove(e: MouseEvent) {
450
353
  <input
451
354
  ref="searchInput"
452
355
  v-model="filterText"
453
- :aria-activedescendant="selectedIndex > -1 ? ('localsearch-item-' + selectedIndex) : undefined"
356
+ :aria-activedescendant="selectedIndex > -1 ? 'localsearch-item-' + selectedIndex : undefined"
454
357
  aria-autocomplete="both"
455
358
  :aria-controls="results?.length ? 'localsearch-list' : undefined"
456
359
  aria-labelledby="localsearch-label"
@@ -461,20 +364,26 @@ function onMouseMove(e: MouseEvent) {
461
364
  id="localsearch-input"
462
365
  enterkeyhint="go"
463
366
  maxlength="64"
464
- :placeholder="buttonText"
367
+ :placeholder="translate('button.buttonText')"
465
368
  spellcheck="false"
466
369
  type="search"
467
370
  />
468
371
  <div class="search-actions">
372
+ <span
373
+ class="search-loading"
374
+ :class="{ active: showSearchSpinner }"
375
+ :role="showSearchSpinner ? 'status' : undefined"
376
+ aria-live="polite"
377
+ :aria-label="showSearchSpinner ? 'Loading search results' : undefined"
378
+ />
379
+
469
380
  <button
470
381
  v-if="!disableDetailedView"
471
382
  class="toggle-layout-button"
472
383
  type="button"
473
384
  :class="{ 'detailed-list': showDetailedList }"
474
385
  :title="translate('modal.displayDetails')"
475
- @click="
476
- selectedIndex > -1 && (showDetailedList = !showDetailedList)
477
- "
386
+ @click="selectedIndex > -1 && (showDetailedList = !showDetailedList)"
478
387
  >
479
388
  <span class="vpi-layout-list local-search-icon" />
480
389
  </button>
@@ -495,6 +404,7 @@ function onMouseMove(e: MouseEvent) {
495
404
  ref="resultsEl"
496
405
  :id="results?.length ? 'localsearch-list' : undefined"
497
406
  :role="results?.length ? 'listbox' : undefined"
407
+ :aria-busy="showSearchSpinner ? 'true' : 'false'"
498
408
  :aria-labelledby="results?.length ? 'localsearch-label' : undefined"
499
409
  class="results"
500
410
  @mousemove="onMouseMove"
@@ -507,11 +417,9 @@ function onMouseMove(e: MouseEvent) {
507
417
  role="option"
508
418
  >
509
419
  <a
510
- :href="p.id"
420
+ :href="withBase(p.id)"
511
421
  class="result"
512
- :class="{
513
- selected: selectedIndex === index
514
- }"
422
+ :class="{ selected: selectedIndex === index }"
515
423
  :aria-label="[...p.titles, p.title].join(' > ')"
516
424
  @mouseenter="!disableMouseOver && (selectedIndex = index)"
517
425
  @focusin="selectedIndex = index"
@@ -526,11 +434,11 @@ function onMouseMove(e: MouseEvent) {
526
434
  :key="index"
527
435
  class="title"
528
436
  >
529
- <span class="text" v-html="t" />
437
+ <span class="text" dir="auto" v-html="t" />
530
438
  <span class="vpi-chevron-right local-search-icon" />
531
439
  </span>
532
440
  <span class="title main">
533
- <span class="text" v-html="p.title" />
441
+ <span class="text" dir="auto" v-html="p.title" />
534
442
  </span>
535
443
  </div>
536
444
 
@@ -548,8 +456,7 @@ function onMouseMove(e: MouseEvent) {
548
456
  v-if="filterText && !results.length && enableNoResults"
549
457
  class="no-results"
550
458
  >
551
- {{ translate('modal.noResultsText') }} "<strong>{{ filterText }}</strong
552
- >"
459
+ {{ translate("modal.noResultsText") }} "<strong>{{ filterText }}</strong>"
553
460
  </li>
554
461
  </ul>
555
462
 
@@ -561,17 +468,17 @@ function onMouseMove(e: MouseEvent) {
561
468
  <kbd :aria-label="translate('modal.footer.navigateDownKeyAriaLabel')">
562
469
  <span class="vpi-arrow-down navigate-icon" />
563
470
  </kbd>
564
- {{ translate('modal.footer.navigateText') }}
471
+ {{ translate("modal.footer.navigateText") }}
565
472
  </span>
566
473
  <span>
567
474
  <kbd :aria-label="translate('modal.footer.selectKeyAriaLabel')">
568
475
  <span class="vpi-corner-down-left navigate-icon" />
569
476
  </kbd>
570
- {{ translate('modal.footer.selectText') }}
477
+ {{ translate("modal.footer.selectText") }}
571
478
  </span>
572
479
  <span>
573
480
  <kbd :aria-label="translate('modal.footer.closeKeyAriaLabel')">esc</kbd>
574
- {{ translate('modal.footer.closeText') }}
481
+ {{ translate("modal.footer.closeText") }}
575
482
  </span>
576
483
  </div>
577
484
  </div>
@@ -596,19 +503,19 @@ function onMouseMove(e: MouseEvent) {
596
503
 
597
504
  .shell {
598
505
  position: relative;
599
- padding: 12px;
600
- margin: 64px auto;
506
+ padding: 0.75rem;
507
+ margin: 4rem auto;
601
508
  display: flex;
602
509
  flex-direction: column;
603
- gap: 16px;
510
+ gap: 1rem;
604
511
  background: var(--vp-local-search-bg);
605
- width: min(100vw - 60px, 900px);
512
+ width: min(100vw - 3.75rem, 56.25rem);
606
513
  height: min-content;
607
- max-height: min(100vh - 128px, 900px);
608
- border-radius: 6px;
514
+ max-height: min(100vh - 8rem, 56.25rem);
515
+ border-radius: 0.375rem;
609
516
  }
610
517
 
611
- @media (max-width: 767px) {
518
+ @media not all and (min-width: 48rem) {
612
519
  .shell {
613
520
  margin: 0;
614
521
  width: 100vw;
@@ -620,16 +527,16 @@ function onMouseMove(e: MouseEvent) {
620
527
 
621
528
  .search-bar {
622
529
  border: 1px solid var(--vp-c-divider);
623
- border-radius: 4px;
530
+ border-radius: 0.25rem;
624
531
  display: flex;
625
532
  align-items: center;
626
- padding: 0 12px;
533
+ padding: 0 0.75rem;
627
534
  cursor: text;
628
535
  }
629
536
 
630
- @media (max-width: 767px) {
537
+ @media not all and (min-width: 48rem) {
631
538
  .search-bar {
632
- padding: 0 8px;
539
+ padding: 0 0.5rem;
633
540
  }
634
541
  }
635
542
 
@@ -639,55 +546,59 @@ function onMouseMove(e: MouseEvent) {
639
546
 
640
547
  .local-search-icon {
641
548
  display: block;
642
- font-size: 18px;
549
+ font-size: 1.125rem;
643
550
  }
644
551
 
645
552
  .navigate-icon {
646
553
  display: block;
647
- font-size: 14px;
554
+ font-size: 0.875rem;
648
555
  }
649
556
 
650
557
  .search-icon {
651
- margin: 8px;
558
+ margin: 0.5rem;
652
559
  }
653
560
 
654
- @media (max-width: 767px) {
561
+ @media not all and (min-width: 48rem) {
655
562
  .search-icon {
656
563
  display: none;
657
564
  }
658
565
  }
659
566
 
660
567
  .search-input {
661
- padding: 6px 12px;
568
+ padding: 0.375rem 0.75rem;
662
569
  font-size: inherit;
663
570
  width: 100%;
664
571
  }
665
572
 
666
- @media (max-width: 767px) {
573
+ .search-input::-webkit-search-cancel-button {
574
+ display: none;
575
+ }
576
+
577
+ @media not all and (min-width: 48rem) {
667
578
  .search-input {
668
- padding: 6px 4px;
579
+ padding: 0.375rem 0.25rem;
669
580
  }
670
581
  }
671
582
 
672
583
  .search-actions {
673
584
  display: flex;
674
- gap: 4px;
585
+ gap: 0.25rem;
675
586
  }
676
587
 
677
588
  @media (any-pointer: coarse) {
678
589
  .search-actions {
679
- gap: 8px;
590
+ gap: 0.5rem;
680
591
  }
681
592
  }
682
593
 
683
- @media (min-width: 769px) {
594
+ @media (min-width: 48rem) {
684
595
  .search-actions.before {
685
596
  display: none;
686
597
  }
687
598
  }
688
599
 
689
600
  .search-actions button {
690
- padding: 8px;
601
+ padding: 0.5rem;
691
602
  }
692
603
 
693
604
  .search-actions button:not([disabled]):hover,
@@ -699,22 +610,50 @@ function onMouseMove(e: MouseEvent) {
699
610
  opacity: 0.37;
700
611
  }
701
612
 
613
+ .search-loading {
614
+ visibility: hidden;
615
+ margin: 0.5rem;
616
+ width: 1.125rem;
617
+ height: 1.125rem;
618
+ flex: none;
619
+ border: 2px solid var(--vp-c-divider);
620
+ border-top-color: var(--vp-c-brand-1);
621
+ border-radius: 50%;
622
+ }
623
+
624
+ .search-loading.active {
625
+ visibility: visible;
626
+ animation: local-search-loading 0.8s linear infinite;
627
+ }
628
+
629
+ @media (prefers-reduced-motion: reduce) {
630
+ .search-loading.active {
631
+ animation: none;
632
+ }
633
+ }
634
+
635
+ @keyframes local-search-loading {
636
+ to {
637
+ transform: rotate(360deg);
638
+ }
639
+ }
640
+
702
641
  .search-keyboard-shortcuts {
703
642
  font-size: 0.8rem;
704
643
  opacity: 75%;
705
644
  display: flex;
706
645
  flex-wrap: wrap;
707
- gap: 16px;
708
- line-height: 14px;
646
+ gap: 1rem;
647
+ line-height: 1.09375;
709
648
  }
710
649
 
711
650
  .search-keyboard-shortcuts span {
712
651
  display: flex;
713
652
  align-items: center;
714
- gap: 4px;
653
+ gap: 0.25rem;
715
654
  }
716
655
 
717
- @media (max-width: 767px) {
656
+ @media not all and (min-width: 48rem) {
718
657
  .search-keyboard-shortcuts {
719
658
  display: none;
720
659
  }
@@ -722,9 +661,9 @@ function onMouseMove(e: MouseEvent) {
722
661
 
723
662
  .search-keyboard-shortcuts kbd {
724
663
  background: rgba(128, 128, 128, 0.1);
725
- border-radius: 4px;
726
- padding: 3px 6px;
727
- min-width: 24px;
664
+ border-radius: 0.25rem;
665
+ padding: 0.1875rem 0.375rem;
666
+ min-width: 1.5rem;
728
667
  display: inline-block;
729
668
  text-align: center;
730
669
  vertical-align: middle;
@@ -735,7 +674,7 @@ function onMouseMove(e: MouseEvent) {
735
674
  .results {
736
675
  display: flex;
737
676
  flex-direction: column;
738
- gap: 6px;
677
+ gap: 0.375rem;
739
678
  overflow-x: hidden;
740
679
  overflow-y: auto;
741
680
  overscroll-behavior: contain;
@@ -744,39 +683,39 @@ function onMouseMove(e: MouseEvent) {
744
683
  .result {
745
684
  display: flex;
746
685
  align-items: center;
747
- gap: 8px;
748
- border-radius: 4px;
686
+ gap: 0.5rem;
687
+ border-radius: 0.25rem;
749
688
  transition: none;
750
- line-height: 1rem;
689
+ line-height: 1;
751
690
  border: solid 2px var(--vp-local-search-result-border);
752
691
  outline: none;
753
692
  }
754
693
 
755
694
  .result > div {
756
- margin: 12px;
695
+ margin: 0.75rem;
757
696
  width: 100%;
758
697
  overflow: hidden;
759
698
  }
760
699
 
761
- @media (max-width: 767px) {
700
+ @media not all and (min-width: 48rem) {
762
701
  .result > div {
763
- margin: 8px;
702
+ margin: 0.5rem;
764
703
  }
765
704
  }
766
705
 
767
706
  .titles {
768
707
  display: flex;
769
708
  flex-wrap: wrap;
770
- gap: 4px;
709
+ gap: 0.25rem;
771
710
  position: relative;
772
711
  z-index: 1001;
773
- padding: 2px 0;
712
+ padding: 0.125rem 0;
774
713
  }
775
714
 
776
715
  .title {
777
716
  display: flex;
778
717
  align-items: center;
779
- gap: 4px;
718
+ gap: 0.25rem;
780
719
  }
781
720
 
782
721
  .title.main {
@@ -805,10 +744,10 @@ function onMouseMove(e: MouseEvent) {
805
744
  .excerpt {
806
745
  opacity: 50%;
807
746
  pointer-events: none;
808
- max-height: 140px;
747
+ max-height: 8.75rem;
809
748
  overflow: hidden;
810
749
  position: relative;
811
- margin-top: 4px;
750
+ margin-top: 0.25rem;
812
751
  }
813
752
 
814
753
  .result.selected .excerpt {
@@ -817,15 +756,15 @@ function onMouseMove(e: MouseEvent) {
817
756
 
818
757
  .excerpt :deep(*) {
819
758
  font-size: 0.8rem !important;
820
- line-height: 130% !important;
759
+ line-height: 1.3 !important;
821
760
  }
822
761
 
823
762
  .titles :deep(mark),
824
763
  .excerpt :deep(mark) {
825
764
  background-color: var(--vp-local-search-highlight-bg);
826
765
  color: var(--vp-local-search-highlight-text);
827
- border-radius: 2px;
828
- padding: 0 2px;
766
+ border-radius: 0.125rem;
767
+ padding: 0 0.125rem;
829
768
  }
830
769
 
831
770
  .excerpt :deep(.vp-code-group) .tabs {
@@ -833,15 +772,14 @@ function onMouseMove(e: MouseEvent) {
833
772
  }
834
773
 
835
774
  .excerpt :deep(.vp-code-group) div[class*='language-'] {
836
- border-radius: 8px !important;
775
+ border-radius: 0.5rem !important;
837
776
  }
838
777
 
839
778
  .excerpt-gradient-bottom {
840
779
  position: absolute;
841
780
  bottom: -1px;
842
- left: 0;
843
- width: 100%;
844
- height: 8px;
781
+ inset-inline: 0;
782
+ height: 0.5rem;
845
783
  background: linear-gradient(transparent, var(--vp-local-search-result-bg));
846
784
  z-index: 1000;
847
785
  }
@@ -849,9 +787,8 @@ function onMouseMove(e: MouseEvent) {
849
787
  .excerpt-gradient-top {
850
788
  position: absolute;
851
789
  top: -1px;
852
- left: 0;
853
- width: 100%;
854
- height: 8px;
790
+ inset-inline: 0;
791
+ height: 0.5rem;
855
792
  background: linear-gradient(var(--vp-local-search-result-bg), transparent);
856
793
  z-index: 1000;
857
794
  }
@@ -864,7 +801,7 @@ function onMouseMove(e: MouseEvent) {
864
801
  .no-results {
865
802
  font-size: 0.9rem;
866
803
  text-align: center;
867
- padding: 12px;
804
+ padding: 0.75rem;
868
805
  }
869
806
 
870
807
  svg {