themekit-js 1.1.1 → 1.1.2

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 (198) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1 -2
  3. package/dist/client/app/components/ClientOnly.js +10 -0
  4. package/dist/client/app/components/Content.js +23 -0
  5. package/dist/client/app/composables/codeGroups.js +40 -0
  6. package/dist/client/app/composables/copyCode.js +73 -0
  7. package/dist/client/app/composables/head.js +81 -0
  8. package/dist/client/app/composables/preFetch.js +99 -0
  9. package/dist/client/app/data.js +59 -0
  10. package/dist/client/app/devtools.js +29 -0
  11. package/dist/client/app/index.js +140 -0
  12. package/dist/client/app/router.js +233 -0
  13. package/dist/client/app/ssr.js +10 -0
  14. package/dist/client/app/theme.js +1 -0
  15. package/dist/client/app/utils.js +119 -0
  16. package/dist/client/index.d.ts +1446 -0
  17. package/dist/client/index.js +8 -0
  18. package/dist/client/shared.js +139 -0
  19. package/dist/client/theme-default/Layout.vue +94 -0
  20. package/dist/client/theme-default/NotFound.vue +109 -0
  21. package/dist/client/theme-default/components/VPAlgoliaSearchBox.vue +99 -0
  22. package/dist/client/theme-default/components/VPBackdrop.vue +41 -0
  23. package/dist/client/theme-default/components/VPBadge.vue +86 -0
  24. package/dist/client/theme-default/components/VPButton.vue +123 -0
  25. package/dist/client/theme-default/components/VPCarbonAds.vue +109 -0
  26. package/dist/client/theme-default/components/VPContent.vue +98 -0
  27. package/dist/client/theme-default/components/VPDoc.vue +193 -0
  28. package/dist/client/theme-default/components/VPDocAside.vue +46 -0
  29. package/dist/client/theme-default/components/VPDocAsideCarbonAds.vue +18 -0
  30. package/dist/client/theme-default/components/VPDocAsideOutline.vue +87 -0
  31. package/dist/client/theme-default/components/VPDocAsideSponsors.vue +17 -0
  32. package/dist/client/theme-default/components/VPDocFooter.vue +145 -0
  33. package/dist/client/theme-default/components/VPDocFooterLastUpdated.vue +50 -0
  34. package/dist/client/theme-default/components/VPDocOutlineItem.vue +59 -0
  35. package/dist/client/theme-default/components/VPFeature.vue +123 -0
  36. package/dist/client/theme-default/components/VPFeatures.vue +121 -0
  37. package/dist/client/theme-default/components/VPFlyout.vue +136 -0
  38. package/dist/client/theme-default/components/VPFooter.vue +60 -0
  39. package/dist/client/theme-default/components/VPHero.vue +336 -0
  40. package/dist/client/theme-default/components/VPHome.vue +43 -0
  41. package/dist/client/theme-default/components/VPHomeContent.vue +52 -0
  42. package/dist/client/theme-default/components/VPHomeFeatures.vue +14 -0
  43. package/dist/client/theme-default/components/VPHomeHero.vue +24 -0
  44. package/dist/client/theme-default/components/VPHomeSponsors.vue +116 -0
  45. package/dist/client/theme-default/components/VPImage.vue +46 -0
  46. package/dist/client/theme-default/components/VPLink.vue +33 -0
  47. package/dist/client/theme-default/components/VPLocalNav.vue +171 -0
  48. package/dist/client/theme-default/components/VPLocalNavOutlineDropdown.vue +190 -0
  49. package/dist/client/theme-default/components/VPLocalSearchBox.vue +856 -0
  50. package/dist/client/theme-default/components/VPMenu.vue +72 -0
  51. package/dist/client/theme-default/components/VPMenuGroup.vue +47 -0
  52. package/dist/client/theme-default/components/VPMenuLink.vue +54 -0
  53. package/dist/client/theme-default/components/VPNav.vue +57 -0
  54. package/dist/client/theme-default/components/VPNavBar.vue +267 -0
  55. package/dist/client/theme-default/components/VPNavBarAppearance.vue +25 -0
  56. package/dist/client/theme-default/components/VPNavBarExtra.vue +94 -0
  57. package/dist/client/theme-default/components/VPNavBarHamburger.vue +79 -0
  58. package/dist/client/theme-default/components/VPNavBarMenu.vue +29 -0
  59. package/dist/client/theme-default/components/VPNavBarMenuGroup.vue +42 -0
  60. package/dist/client/theme-default/components/VPNavBarMenuLink.vue +53 -0
  61. package/dist/client/theme-default/components/VPNavBarSearch.vue +194 -0
  62. package/dist/client/theme-default/components/VPNavBarSearchButton.vue +208 -0
  63. package/dist/client/theme-default/components/VPNavBarSocialLinks.vue +27 -0
  64. package/dist/client/theme-default/components/VPNavBarTitle.vue +76 -0
  65. package/dist/client/theme-default/components/VPNavBarTranslations.vue +47 -0
  66. package/dist/client/theme-default/components/VPNavScreen.vue +99 -0
  67. package/dist/client/theme-default/components/VPNavScreenAppearance.vue +33 -0
  68. package/dist/client/theme-default/components/VPNavScreenMenu.vue +23 -0
  69. package/dist/client/theme-default/components/VPNavScreenMenuGroup.vue +111 -0
  70. package/dist/client/theme-default/components/VPNavScreenMenuGroupLink.vue +39 -0
  71. package/dist/client/theme-default/components/VPNavScreenMenuGroupSection.vue +34 -0
  72. package/dist/client/theme-default/components/VPNavScreenMenuLink.vue +39 -0
  73. package/dist/client/theme-default/components/VPNavScreenSocialLinks.vue +14 -0
  74. package/dist/client/theme-default/components/VPNavScreenTranslations.vue +73 -0
  75. package/dist/client/theme-default/components/VPPage.vue +7 -0
  76. package/dist/client/theme-default/components/VPSidebar.vue +137 -0
  77. package/dist/client/theme-default/components/VPSidebarItem.vue +250 -0
  78. package/dist/client/theme-default/components/VPSkipLink.vue +68 -0
  79. package/dist/client/theme-default/components/VPSocialLink.vue +50 -0
  80. package/dist/client/theme-default/components/VPSocialLinks.vue +27 -0
  81. package/dist/client/theme-default/components/VPSponsors.vue +48 -0
  82. package/dist/client/theme-default/components/VPSponsorsGrid.vue +48 -0
  83. package/dist/client/theme-default/components/VPSwitch.vue +63 -0
  84. package/dist/client/theme-default/components/VPSwitchAppearance.vue +52 -0
  85. package/dist/client/theme-default/components/VPTeamMembers.vue +66 -0
  86. package/dist/client/theme-default/components/VPTeamMembersItem.vue +225 -0
  87. package/dist/client/theme-default/components/VPTeamPage.vue +58 -0
  88. package/dist/client/theme-default/components/VPTeamPageSection.vue +77 -0
  89. package/dist/client/theme-default/components/VPTeamPageTitle.vue +63 -0
  90. package/dist/client/theme-default/components/icons/VPIconAlignJustify.vue +8 -0
  91. package/dist/client/theme-default/components/icons/VPIconAlignLeft.vue +8 -0
  92. package/dist/client/theme-default/components/icons/VPIconAlignRight.vue +8 -0
  93. package/dist/client/theme-default/components/icons/VPIconArrowLeft.vue +7 -0
  94. package/dist/client/theme-default/components/icons/VPIconArrowRight.vue +7 -0
  95. package/dist/client/theme-default/components/icons/VPIconChevronDown.vue +5 -0
  96. package/dist/client/theme-default/components/icons/VPIconChevronLeft.vue +5 -0
  97. package/dist/client/theme-default/components/icons/VPIconChevronRight.vue +5 -0
  98. package/dist/client/theme-default/components/icons/VPIconChevronUp.vue +5 -0
  99. package/dist/client/theme-default/components/icons/VPIconEdit.vue +6 -0
  100. package/dist/client/theme-default/components/icons/VPIconHeart.vue +5 -0
  101. package/dist/client/theme-default/components/icons/VPIconLanguages.vue +9 -0
  102. package/dist/client/theme-default/components/icons/VPIconMinus.vue +5 -0
  103. package/dist/client/theme-default/components/icons/VPIconMinusSquare.vue +6 -0
  104. package/dist/client/theme-default/components/icons/VPIconMoon.vue +5 -0
  105. package/dist/client/theme-default/components/icons/VPIconMoreHorizontal.vue +7 -0
  106. package/dist/client/theme-default/components/icons/VPIconPlus.vue +5 -0
  107. package/dist/client/theme-default/components/icons/VPIconPlusSquare.vue +6 -0
  108. package/dist/client/theme-default/components/icons/VPIconSun.vue +13 -0
  109. package/dist/client/theme-default/composables/aside.js +17 -0
  110. package/dist/client/theme-default/composables/data.js +2 -0
  111. package/dist/client/theme-default/composables/edit-link.js +16 -0
  112. package/dist/client/theme-default/composables/flyout.js +41 -0
  113. package/dist/client/theme-default/composables/langs.js +26 -0
  114. package/dist/client/theme-default/composables/local-nav.js +18 -0
  115. package/dist/client/theme-default/composables/nav.js +30 -0
  116. package/dist/client/theme-default/composables/outline.js +178 -0
  117. package/dist/client/theme-default/composables/prev-next.js +57 -0
  118. package/dist/client/theme-default/composables/sidebar.js +136 -0
  119. package/dist/client/theme-default/composables/sponsor-grid.js +94 -0
  120. package/dist/client/theme-default/fonts/inter-italic-cyrillic-ext.woff2 +0 -0
  121. package/dist/client/theme-default/fonts/inter-italic-cyrillic.woff2 +0 -0
  122. package/dist/client/theme-default/fonts/inter-italic-greek-ext.woff2 +0 -0
  123. package/dist/client/theme-default/fonts/inter-italic-greek.woff2 +0 -0
  124. package/dist/client/theme-default/fonts/inter-italic-latin-ext.woff2 +0 -0
  125. package/dist/client/theme-default/fonts/inter-italic-latin.woff2 +0 -0
  126. package/dist/client/theme-default/fonts/inter-italic-vietnamese.woff2 +0 -0
  127. package/dist/client/theme-default/fonts/inter-roman-cyrillic-ext.woff2 +0 -0
  128. package/dist/client/theme-default/fonts/inter-roman-cyrillic.woff2 +0 -0
  129. package/dist/client/theme-default/fonts/inter-roman-greek-ext.woff2 +0 -0
  130. package/dist/client/theme-default/fonts/inter-roman-greek.woff2 +0 -0
  131. package/dist/client/theme-default/fonts/inter-roman-latin-ext.woff2 +0 -0
  132. package/dist/client/theme-default/fonts/inter-roman-latin.woff2 +0 -0
  133. package/dist/client/theme-default/fonts/inter-roman-vietnamese.woff2 +0 -0
  134. package/dist/client/theme-default/index.js +3 -0
  135. package/dist/client/theme-default/styles/base.css +252 -0
  136. package/dist/client/theme-default/styles/components/custom-block.css +208 -0
  137. package/dist/client/theme-default/styles/components/vp-code-group.css +85 -0
  138. package/dist/client/theme-default/styles/components/vp-code.css +7 -0
  139. package/dist/client/theme-default/styles/components/vp-doc.css +570 -0
  140. package/dist/client/theme-default/styles/components/vp-sponsor.css +155 -0
  141. package/dist/client/theme-default/styles/fonts.css +157 -0
  142. package/dist/client/theme-default/styles/icons.css +123 -0
  143. package/dist/client/theme-default/styles/utils.css +9 -0
  144. package/dist/client/theme-default/styles/vars.css +563 -0
  145. package/dist/client/theme-default/support/lru.js +33 -0
  146. package/dist/client/theme-default/support/sidebar.js +89 -0
  147. package/dist/client/theme-default/support/translation.js +49 -0
  148. package/dist/client/theme-default/support/utils.js +33 -0
  149. package/dist/client/theme-default/without-fonts.js +32 -0
  150. package/dist/node/cli.js +444 -0
  151. package/dist/node/index.d.ts +4589 -0
  152. package/dist/node/index.js +198 -0
  153. package/dist/node/serve-C7_9EEpC.js +50353 -0
  154. package/package.json +6 -9
  155. package/template/.themekit/bootstrap3/dist/css/bootstrap-theme.css +587 -0
  156. package/template/.themekit/bootstrap3/dist/css/bootstrap-theme.css.map +1 -0
  157. package/template/.themekit/bootstrap3/dist/css/bootstrap-theme.min.css +6 -0
  158. package/template/.themekit/bootstrap3/dist/css/bootstrap-theme.min.css.map +1 -0
  159. package/template/.themekit/bootstrap3/dist/css/bootstrap.css +6834 -0
  160. package/template/.themekit/bootstrap3/dist/css/bootstrap.css.map +1 -0
  161. package/template/.themekit/bootstrap3/dist/css/bootstrap.min.css +6 -0
  162. package/template/.themekit/bootstrap3/dist/css/bootstrap.min.css.map +1 -0
  163. package/template/.themekit/bootstrap3/dist/fonts/glyphicons-halflings-regular.eot +0 -0
  164. package/template/.themekit/bootstrap3/dist/fonts/glyphicons-halflings-regular.svg +288 -0
  165. package/template/.themekit/bootstrap3/dist/fonts/glyphicons-halflings-regular.ttf +0 -0
  166. package/template/.themekit/bootstrap3/dist/fonts/glyphicons-halflings-regular.woff +0 -0
  167. package/template/.themekit/bootstrap3/dist/fonts/glyphicons-halflings-regular.woff2 +0 -0
  168. package/template/.themekit/bootstrap3/dist/js/bootstrap.js +2580 -0
  169. package/template/.themekit/bootstrap3/dist/js/bootstrap.min.js +6 -0
  170. package/template/.themekit/bootstrap3/dist/js/html5shiv.min.js +4 -0
  171. package/template/.themekit/bootstrap3/dist/js/jquery.min.js +5 -0
  172. package/template/.themekit/bootstrap3/dist/js/npm.js +13 -0
  173. package/template/.themekit/bootstrap3/dist/js/respond.min.js +6 -0
  174. package/template/.themekit/changzhou/dist/css/animate.css +1 -0
  175. package/template/.themekit/changzhou/dist/css/bootstrap-select.min.css +6 -0
  176. package/template/.themekit/changzhou/dist/css/carousel.css +25 -0
  177. package/template/.themekit/changzhou/dist/css/font-awesome.min.css +4 -0
  178. package/template/.themekit/changzhou/dist/css/prettyPhoto.css +170 -0
  179. package/template/.themekit/changzhou/dist/css/style.css +2315 -0
  180. package/template/.themekit/changzhou/dist/js/bootstrap-select.min.js +14 -0
  181. package/template/.themekit/changzhou/dist/js/carousel.js +3300 -0
  182. package/template/.themekit/changzhou/dist/js/custom.js +42 -0
  183. package/template/.themekit/changzhou/dist/js/jquery.prettyPhoto.js +11 -0
  184. package/template/.themekit/changzhou/dist/js/map.js +112 -0
  185. package/template/.themekit/changzhou/dist/js/parallax.js +17 -0
  186. package/template/.themekit/changzhou/dist/js/vendor/html5shiv.js +2125 -0
  187. package/template/.themekit/changzhou/dist/js/vendor/respond.min.js +2156 -0
  188. package/template/.themekit/changzhou/dist/js/videobg.js +70 -0
  189. package/template/.themekit/changzhou/theme/Layout.vue +21 -0
  190. package/template/.themekit/changzhou/theme/index.js +29 -0
  191. package/template/.themekit/changzhou/theme/style.css +139 -0
  192. package/template/{.vitepress → .themekit}/config.js +1 -1
  193. package/template/{.vitepress → .themekit}/theme/Layout.vue +1 -1
  194. package/template/{.vitepress → .themekit}/theme/index.js +5 -5
  195. package/template/api-examples.md +2 -2
  196. package/template/index.md +1 -2
  197. package/theme.d.ts +1 -1
  198. /package/template/{.vitepress → .themekit}/theme/style.css +0 -0
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2024 Seedunk
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2019-present, Yuxi (Evan) You
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,2 +1 @@
1
- # ThemeKit
2
- ## seedunk
1
+ # ThemeKit
@@ -0,0 +1,10 @@
1
+ import { defineComponent, ref, onMounted } from 'vue';
2
+ export const ClientOnly = defineComponent({
3
+ setup(_, { slots }) {
4
+ const show = ref(false);
5
+ onMounted(() => {
6
+ show.value = true;
7
+ });
8
+ return () => (show.value && slots.default ? slots.default() : null);
9
+ }
10
+ });
@@ -0,0 +1,23 @@
1
+ import { defineComponent, h } from 'vue';
2
+ import { useData, useRoute } from 'themekit-js';
3
+ import { contentUpdatedCallbacks } from '../utils';
4
+ const runCbs = () => contentUpdatedCallbacks.forEach((fn) => fn());
5
+ export const Content = defineComponent({
6
+ name: 'VitePressContent',
7
+ props: {
8
+ as: { type: [Object, String], default: 'div' }
9
+ },
10
+ setup(props) {
11
+ const route = useRoute();
12
+ const { site } = useData();
13
+ return () => h(props.as, site.value.contentProps ?? { style: { position: 'relative' } }, [
14
+ route.component
15
+ ? h(route.component, {
16
+ onVnodeMounted: runCbs,
17
+ onVnodeUpdated: runCbs,
18
+ onVnodeUnmounted: runCbs
19
+ })
20
+ : '404 Page Not Found'
21
+ ]);
22
+ }
23
+ });
@@ -0,0 +1,40 @@
1
+ import { inBrowser, onContentUpdated } from 'themekit-js';
2
+ export function useCodeGroups() {
3
+ if (import.meta.env.DEV) {
4
+ onContentUpdated(() => {
5
+ document.querySelectorAll('.vp-code-group > .blocks').forEach((el) => {
6
+ Array.from(el.children).forEach((child) => {
7
+ child.classList.remove('active');
8
+ });
9
+ el.children[0].classList.add('active');
10
+ });
11
+ });
12
+ }
13
+ if (inBrowser) {
14
+ window.addEventListener('click', (e) => {
15
+ const el = e.target;
16
+ if (el.matches('.vp-code-group input')) {
17
+ // input <- .tabs <- .vp-code-group
18
+ const group = el.parentElement?.parentElement;
19
+ if (!group)
20
+ return;
21
+ const i = Array.from(group.querySelectorAll('input')).indexOf(el);
22
+ if (i < 0)
23
+ return;
24
+ const blocks = group.querySelector('.blocks');
25
+ if (!blocks)
26
+ return;
27
+ const current = Array.from(blocks.children).find((child) => child.classList.contains('active'));
28
+ if (!current)
29
+ return;
30
+ const next = blocks.children[i];
31
+ if (!next || current === next)
32
+ return;
33
+ current.classList.remove('active');
34
+ next.classList.add('active');
35
+ const label = group?.querySelector(`label[for="${el.id}"]`);
36
+ label?.scrollIntoView({ block: 'nearest' });
37
+ }
38
+ });
39
+ }
40
+ }
@@ -0,0 +1,73 @@
1
+ import { inBrowser } from 'themekit-js';
2
+ export function useCopyCode() {
3
+ if (inBrowser) {
4
+ const timeoutIdMap = new WeakMap();
5
+ window.addEventListener('click', (e) => {
6
+ const el = e.target;
7
+ if (el.matches('div[class*="language-"] > button.copy')) {
8
+ const parent = el.parentElement;
9
+ const sibling = el.nextElementSibling?.nextElementSibling;
10
+ if (!parent || !sibling) {
11
+ return;
12
+ }
13
+ const isShell = /language-(shellscript|shell|bash|sh|zsh)/.test(parent.className);
14
+ const ignoredNodes = ['.vp-copy-ignore', '.diff.remove'];
15
+ // Clone the node and remove the ignored nodes
16
+ const clone = sibling.cloneNode(true);
17
+ clone
18
+ .querySelectorAll(ignoredNodes.join(','))
19
+ .forEach((node) => node.remove());
20
+ let text = clone.textContent || '';
21
+ if (isShell) {
22
+ text = text.replace(/^ *(\$|>) /gm, '').trim();
23
+ }
24
+ copyToClipboard(text).then(() => {
25
+ el.classList.add('copied');
26
+ clearTimeout(timeoutIdMap.get(el));
27
+ const timeoutId = setTimeout(() => {
28
+ el.classList.remove('copied');
29
+ el.blur();
30
+ timeoutIdMap.delete(el);
31
+ }, 2000);
32
+ timeoutIdMap.set(el, timeoutId);
33
+ });
34
+ }
35
+ });
36
+ }
37
+ }
38
+ async function copyToClipboard(text) {
39
+ try {
40
+ return navigator.clipboard.writeText(text);
41
+ }
42
+ catch {
43
+ const element = document.createElement('textarea');
44
+ const previouslyFocusedElement = document.activeElement;
45
+ element.value = text;
46
+ // Prevent keyboard from showing on mobile
47
+ element.setAttribute('readonly', '');
48
+ element.style.contain = 'strict';
49
+ element.style.position = 'absolute';
50
+ element.style.left = '-9999px';
51
+ element.style.fontSize = '12pt'; // Prevent zooming on iOS
52
+ const selection = document.getSelection();
53
+ const originalRange = selection
54
+ ? selection.rangeCount > 0 && selection.getRangeAt(0)
55
+ : null;
56
+ document.body.appendChild(element);
57
+ element.select();
58
+ // Explicit selection workaround for iOS
59
+ element.selectionStart = 0;
60
+ element.selectionEnd = text.length;
61
+ document.execCommand('copy');
62
+ document.body.removeChild(element);
63
+ if (originalRange) {
64
+ selection.removeAllRanges(); // originalRange can't be truthy when selection is falsy
65
+ selection.addRange(originalRange);
66
+ }
67
+ // Get the focus back on the previously focused element, if any
68
+ if (previouslyFocusedElement) {
69
+ ;
70
+ previouslyFocusedElement.focus();
71
+ }
72
+ }
73
+ }
@@ -0,0 +1,81 @@
1
+ import { watchEffect } from 'vue';
2
+ import { createTitle, mergeHead } from '../../shared';
3
+ export function useUpdateHead(route, siteDataByRouteRef) {
4
+ let isFirstUpdate = true;
5
+ let managedHeadElements = [];
6
+ const updateHeadTags = (newTags) => {
7
+ if (import.meta.env.PROD && isFirstUpdate) {
8
+ // in production, the initial meta tags are already pre-rendered so we
9
+ // skip the first update.
10
+ isFirstUpdate = false;
11
+ newTags.forEach((tag) => {
12
+ const headEl = createHeadElement(tag);
13
+ for (const el of document.head.children) {
14
+ if (el.isEqualNode(headEl)) {
15
+ managedHeadElements.push(el);
16
+ return;
17
+ }
18
+ }
19
+ });
20
+ return;
21
+ }
22
+ const newElements = newTags.map(createHeadElement);
23
+ managedHeadElements.forEach((oldEl, oldIndex) => {
24
+ const matchedIndex = newElements.findIndex((newEl) => newEl?.isEqualNode(oldEl ?? null));
25
+ if (matchedIndex !== -1) {
26
+ delete newElements[matchedIndex];
27
+ }
28
+ else {
29
+ oldEl?.remove();
30
+ delete managedHeadElements[oldIndex];
31
+ }
32
+ });
33
+ newElements.forEach((el) => el && document.head.appendChild(el));
34
+ managedHeadElements = [...managedHeadElements, ...newElements].filter(Boolean);
35
+ };
36
+ watchEffect(() => {
37
+ const pageData = route.data;
38
+ const siteData = siteDataByRouteRef.value;
39
+ const pageDescription = pageData && pageData.description;
40
+ const frontmatterHead = (pageData && pageData.frontmatter.head) || [];
41
+ // update title and description
42
+ const title = createTitle(siteData, pageData);
43
+ if (title !== document.title) {
44
+ document.title = title;
45
+ }
46
+ const description = pageDescription || siteData.description;
47
+ let metaDescriptionElement = document.querySelector(`meta[name=description]`);
48
+ if (metaDescriptionElement) {
49
+ if (metaDescriptionElement.getAttribute('content') !== description) {
50
+ metaDescriptionElement.setAttribute('content', description);
51
+ }
52
+ }
53
+ else {
54
+ createHeadElement(['meta', { name: 'description', content: description }]);
55
+ }
56
+ updateHeadTags(mergeHead(siteData.head, filterOutHeadDescription(frontmatterHead)));
57
+ });
58
+ }
59
+ function createHeadElement([tag, attrs, innerHTML]) {
60
+ const el = document.createElement(tag);
61
+ for (const key in attrs) {
62
+ el.setAttribute(key, attrs[key]);
63
+ }
64
+ if (innerHTML) {
65
+ el.innerHTML = innerHTML;
66
+ }
67
+ if (tag === 'script' && !attrs.async) {
68
+ // async is true by default for dynamically created scripts
69
+ ;
70
+ el.async = false;
71
+ }
72
+ return el;
73
+ }
74
+ function isMetaDescription(headConfig) {
75
+ return (headConfig[0] === 'meta' &&
76
+ headConfig[1] &&
77
+ headConfig[1].name === 'description');
78
+ }
79
+ function filterOutHeadDescription(head) {
80
+ return head.filter((h) => !isMetaDescription(h));
81
+ }
@@ -0,0 +1,99 @@
1
+ // Customized pre-fetch for page chunks based on
2
+ // https://github.com/GoogleChromeLabs/quicklink
3
+ import { useRoute } from '../router';
4
+ import { onMounted, onUnmounted, watch } from 'vue';
5
+ import { inBrowser, pathToFile } from '../utils';
6
+ const hasFetched = new Set();
7
+ const createLink = () => document.createElement('link');
8
+ const viaDOM = (url) => {
9
+ const link = createLink();
10
+ link.rel = `prefetch`;
11
+ link.href = url;
12
+ document.head.appendChild(link);
13
+ };
14
+ const viaXHR = (url) => {
15
+ const req = new XMLHttpRequest();
16
+ req.open('GET', url, (req.withCredentials = true));
17
+ req.send();
18
+ };
19
+ let link;
20
+ const doFetch = inBrowser &&
21
+ (link = createLink()) &&
22
+ link.relList &&
23
+ link.relList.supports &&
24
+ link.relList.supports('prefetch')
25
+ ? viaDOM
26
+ : viaXHR;
27
+ export function usePrefetch() {
28
+ if (!inBrowser) {
29
+ return;
30
+ }
31
+ if (!window.IntersectionObserver) {
32
+ return;
33
+ }
34
+ let conn;
35
+ if ((conn = navigator.connection) &&
36
+ (conn.saveData || /2g/.test(conn.effectiveType))) {
37
+ // Don't prefetch if using 2G or if Save-Data is enabled.
38
+ return;
39
+ }
40
+ const rIC = window.requestIdleCallback || setTimeout;
41
+ let observer = null;
42
+ const observeLinks = () => {
43
+ if (observer) {
44
+ observer.disconnect();
45
+ }
46
+ observer = new IntersectionObserver((entries) => {
47
+ entries.forEach((entry) => {
48
+ if (entry.isIntersecting) {
49
+ const link = entry.target;
50
+ observer.unobserve(link);
51
+ const { pathname } = link;
52
+ if (!hasFetched.has(pathname)) {
53
+ hasFetched.add(pathname);
54
+ const pageChunkPath = pathToFile(pathname);
55
+ if (pageChunkPath)
56
+ doFetch(pageChunkPath);
57
+ }
58
+ }
59
+ });
60
+ });
61
+ rIC(() => {
62
+ document
63
+ .querySelectorAll('#app a')
64
+ .forEach((link) => {
65
+ const { hostname, pathname } = new URL(link.href instanceof SVGAnimatedString
66
+ ? link.href.animVal
67
+ : link.href, link.baseURI);
68
+ const extMatch = pathname.match(/\.\w+$/);
69
+ if (extMatch && extMatch[0] !== '.html') {
70
+ return;
71
+ }
72
+ if (
73
+ // only prefetch same tab navigation, since a new tab will load
74
+ // the lean js chunk instead.
75
+ link.target !== '_blank' &&
76
+ // only prefetch inbound links
77
+ hostname === location.hostname) {
78
+ if (pathname !== location.pathname) {
79
+ observer.observe(link);
80
+ }
81
+ else {
82
+ // No need to prefetch chunk for the current page, but also mark
83
+ // it as already fetched. This is because the initial page uses its
84
+ // lean chunk, and if we don't mark it, navigation to another page
85
+ // with a link back to the first page will fetch its full chunk
86
+ // which isn't needed.
87
+ hasFetched.add(pathname);
88
+ }
89
+ }
90
+ });
91
+ });
92
+ };
93
+ onMounted(observeLinks);
94
+ const route = useRoute();
95
+ watch(() => route.path, observeLinks);
96
+ onUnmounted(() => {
97
+ observer && observer.disconnect();
98
+ });
99
+ }
@@ -0,0 +1,59 @@
1
+ import siteData from '@siteData';
2
+ import { useDark } from '@vueuse/core';
3
+ import { computed, inject, readonly, ref, shallowRef, watch } from 'vue';
4
+ import { APPEARANCE_KEY, createTitle, inBrowser, resolveSiteDataByRoute } from '../shared';
5
+ export const dataSymbol = Symbol();
6
+ // site data is a singleton
7
+ export const siteDataRef = shallowRef((import.meta.env.PROD ? siteData : readonly(siteData)));
8
+ // hmr
9
+ if (import.meta.hot) {
10
+ import.meta.hot.accept('/@siteData', (m) => {
11
+ if (m) {
12
+ siteDataRef.value = m.default;
13
+ }
14
+ });
15
+ }
16
+ // per-app data
17
+ export function initData(route) {
18
+ const site = computed(() => resolveSiteDataByRoute(siteDataRef.value, route.data.relativePath));
19
+ const appearance = site.value.appearance; // fine with reactivity being lost here, config change triggers a restart
20
+ const isDark = appearance === 'force-dark'
21
+ ? ref(true)
22
+ : appearance
23
+ ? useDark({
24
+ storageKey: APPEARANCE_KEY,
25
+ initialValue: () => typeof appearance === 'string' ? appearance : 'auto',
26
+ ...(typeof appearance === 'object' ? appearance : {})
27
+ })
28
+ : ref(false);
29
+ const hashRef = ref(inBrowser ? location.hash : '');
30
+ if (inBrowser) {
31
+ window.addEventListener('hashchange', () => {
32
+ hashRef.value = location.hash;
33
+ });
34
+ }
35
+ watch(() => route.data, () => {
36
+ hashRef.value = inBrowser ? location.hash : '';
37
+ });
38
+ return {
39
+ site,
40
+ theme: computed(() => site.value.themeConfig),
41
+ page: computed(() => route.data),
42
+ frontmatter: computed(() => route.data.frontmatter),
43
+ params: computed(() => route.data.params),
44
+ lang: computed(() => site.value.lang),
45
+ dir: computed(() => route.data.frontmatter.dir || site.value.dir),
46
+ localeIndex: computed(() => site.value.localeIndex || 'root'),
47
+ title: computed(() => createTitle(site.value, route.data)),
48
+ description: computed(() => route.data.description || site.value.description),
49
+ isDark,
50
+ hash: computed(() => hashRef.value)
51
+ };
52
+ }
53
+ export function useData() {
54
+ const data = inject(dataSymbol);
55
+ if (!data) {
56
+ throw new Error('vitepress data not properly injected in app');
57
+ }
58
+ return data;
59
+ }
@@ -0,0 +1,29 @@
1
+ import { setupDevToolsPlugin } from '@vue/devtools-api';
2
+ const COMPONENT_STATE_TYPE = 'VitePress';
3
+ export const setupDevtools = (app, router, data) => {
4
+ setupDevToolsPlugin({
5
+ // fix recursive reference
6
+ app: app,
7
+ id: 'com.seedunk.themekit-js',
8
+ label: 'ThemeKit JS',
9
+ packageName: 'themekit-js',
10
+ homepage: 'https://seedunk.com/@themekit-js',
11
+ componentStateTypes: [COMPONENT_STATE_TYPE]
12
+ }, (api) => {
13
+ // TODO: remove any
14
+ api.on.inspectComponent((payload) => {
15
+ payload.instanceData.state.push({
16
+ type: COMPONENT_STATE_TYPE,
17
+ key: 'route',
18
+ value: router.route,
19
+ editable: false
20
+ });
21
+ payload.instanceData.state.push({
22
+ type: COMPONENT_STATE_TYPE,
23
+ key: 'data',
24
+ value: data,
25
+ editable: false
26
+ });
27
+ });
28
+ });
29
+ };
@@ -0,0 +1,140 @@
1
+ import RawTheme from '@theme/index';
2
+ import { createApp as createClientApp, createSSRApp, defineComponent, h, onMounted, watchEffect } from 'vue';
3
+ import { ClientOnly } from './components/ClientOnly';
4
+ import { Content } from './components/Content';
5
+ import { useCodeGroups } from './composables/codeGroups';
6
+ import { useCopyCode } from './composables/copyCode';
7
+ import { useUpdateHead } from './composables/head';
8
+ import { usePrefetch } from './composables/preFetch';
9
+ import { dataSymbol, initData, siteDataRef, useData } from './data';
10
+ import { RouterSymbol, createRouter, scrollTo } from './router';
11
+ import { inBrowser, pathToFile } from './utils';
12
+ function resolveThemeExtends(theme) {
13
+ if (theme.extends) {
14
+ const base = resolveThemeExtends(theme.extends);
15
+ return {
16
+ ...base,
17
+ ...theme,
18
+ async enhanceApp(ctx) {
19
+ if (base.enhanceApp)
20
+ await base.enhanceApp(ctx);
21
+ if (theme.enhanceApp)
22
+ await theme.enhanceApp(ctx);
23
+ }
24
+ };
25
+ }
26
+ return theme;
27
+ }
28
+ const Theme = resolveThemeExtends(RawTheme);
29
+ const VitePressApp = defineComponent({
30
+ name: 'VitePressApp',
31
+ setup() {
32
+ const { site, lang, dir } = useData();
33
+ // change the language on the HTML element based on the current lang
34
+ onMounted(() => {
35
+ watchEffect(() => {
36
+ document.documentElement.lang = lang.value;
37
+ document.documentElement.dir = dir.value;
38
+ });
39
+ });
40
+ if (import.meta.env.PROD && site.value.router.prefetchLinks) {
41
+ // in prod mode, enable intersectionObserver based pre-fetch
42
+ usePrefetch();
43
+ }
44
+ // setup global copy code handler
45
+ useCopyCode();
46
+ // setup global code groups handler
47
+ useCodeGroups();
48
+ if (Theme.setup)
49
+ Theme.setup();
50
+ return () => h(Theme.Layout);
51
+ }
52
+ });
53
+ export async function createApp() {
54
+ ;
55
+ globalThis.__VITEPRESS__ = true;
56
+ const router = newRouter();
57
+ const app = newApp();
58
+ app.provide(RouterSymbol, router);
59
+ const data = initData(router.route);
60
+ app.provide(dataSymbol, data);
61
+ // install global components
62
+ app.component('Content', Content);
63
+ app.component('ClientOnly', ClientOnly);
64
+ // expose $frontmatter & $params
65
+ Object.defineProperties(app.config.globalProperties, {
66
+ $frontmatter: {
67
+ get() {
68
+ return data.frontmatter.value;
69
+ }
70
+ },
71
+ $params: {
72
+ get() {
73
+ return data.page.value.params;
74
+ }
75
+ }
76
+ });
77
+ if (Theme.enhanceApp) {
78
+ await Theme.enhanceApp({
79
+ app,
80
+ router,
81
+ siteData: siteDataRef
82
+ });
83
+ }
84
+ // setup devtools in dev mode
85
+ if (import.meta.env.DEV || __VUE_PROD_DEVTOOLS__) {
86
+ import('./devtools.js').then(({ setupDevtools }) => setupDevtools(app, router, data));
87
+ }
88
+ return { app, router, data };
89
+ }
90
+ function newApp() {
91
+ return import.meta.env.PROD
92
+ ? createSSRApp(VitePressApp)
93
+ : createClientApp(VitePressApp);
94
+ }
95
+ function newRouter() {
96
+ let isInitialPageLoad = inBrowser;
97
+ let initialPath;
98
+ return createRouter((path) => {
99
+ let pageFilePath = pathToFile(path);
100
+ let pageModule = null;
101
+ if (pageFilePath) {
102
+ if (isInitialPageLoad) {
103
+ initialPath = pageFilePath;
104
+ }
105
+ // use lean build if this is the initial page load or navigating back
106
+ // to the initial loaded path (the static vnodes already adopted the
107
+ // static content on that load so no need to re-fetch the page)
108
+ if (isInitialPageLoad || initialPath === pageFilePath) {
109
+ pageFilePath = pageFilePath.replace(/\.js$/, '.lean.js');
110
+ }
111
+ if (import.meta.env.SSR) {
112
+ pageModule = import(/*@vite-ignore*/ pageFilePath + '?t=' + Date.now());
113
+ }
114
+ else {
115
+ pageModule = import(/*@vite-ignore*/ pageFilePath);
116
+ }
117
+ }
118
+ if (inBrowser) {
119
+ isInitialPageLoad = false;
120
+ }
121
+ return pageModule;
122
+ }, Theme.NotFound);
123
+ }
124
+ if (inBrowser) {
125
+ createApp().then(({ app, router, data }) => {
126
+ // wait until page component is fetched before mounting
127
+ router.go().then(() => {
128
+ // dynamically update head tags
129
+ useUpdateHead(router.route, data.site);
130
+ app.mount('#app');
131
+ // scroll to hash on new tab during dev
132
+ if (import.meta.env.DEV && location.hash) {
133
+ const target = document.getElementById(decodeURIComponent(location.hash).slice(1));
134
+ if (target) {
135
+ scrollTo(target, location.hash);
136
+ }
137
+ }
138
+ });
139
+ });
140
+ }