VersionPicker.vue (3482B)
1 <!-- Adapted from https://github.com/MakieOrg/Makie.jl/blob/master/docs/src/.vitepress/theme/VersionPicker.vue --> 2 3 <script setup lang="ts"> 4 import { ref, onMounted, computed} from 'vue' 5 import { useData } from 'vitepress' 6 import VPNavBarMenuGroup from 'vitepress/dist/client/theme-default/components/VPNavBarMenuGroup.vue' 7 import VPNavScreenMenuGroup from 'vitepress/dist/client/theme-default/components/VPNavScreenMenuGroup.vue' 8 9 declare global { 10 interface Window { 11 DOC_VERSIONS?: string[]; 12 DOCUMENTER_CURRENT_VERSION?: string; 13 } 14 } 15 16 const absoluteRoot = __DEPLOY_ABSPATH__; 17 const absoluteOrigin = (typeof window === 'undefined' ? '' : window.location.origin) + absoluteRoot; 18 19 const props = defineProps<{ screenMenu?: boolean }>(); 20 const versions = ref<Array<{ text: string, link: string, class?: string }>>([]); 21 const currentVersion = ref('Versions'); 22 const isClient = ref(false); 23 const { site } = useData(); 24 25 const isLocalBuild = () => { 26 return typeof window !== 'undefined' && (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'); 27 }; 28 29 const waitForScriptsToLoad = () => { 30 return new Promise<boolean>((resolve) => { 31 if (isLocalBuild() || typeof window === 'undefined') { 32 resolve(false); 33 return; 34 } 35 const checkInterval = setInterval(() => { 36 if (window.DOC_VERSIONS && window.DOCUMENTER_CURRENT_VERSION) { 37 clearInterval(checkInterval); 38 resolve(true); 39 } 40 }, 100); 41 setTimeout(() => { 42 clearInterval(checkInterval); 43 resolve(false); 44 }, 5000); 45 }); 46 }; 47 48 const loadVersions = async () => { 49 if (typeof window === 'undefined') return; 50 51 try { 52 if (isLocalBuild()) { 53 versions.value = [{ text: 'dev', link: '/' }]; 54 currentVersion.value = 'dev'; 55 } else { 56 const scriptsLoaded = await waitForScriptsToLoad(); 57 58 if (scriptsLoaded && window.DOC_VERSIONS && window.DOCUMENTER_CURRENT_VERSION) { 59 const allVersions = new Set([...window.DOC_VERSIONS, window.DOCUMENTER_CURRENT_VERSION]); 60 versions.value = Array.from(allVersions).map(v => ({ 61 text: v, 62 link: `${absoluteOrigin}/${v}/` 63 })); 64 currentVersion.value = window.DOCUMENTER_CURRENT_VERSION; 65 } else { 66 versions.value = [{ text: 'dev', link: `${absoluteOrigin}/dev/` }]; 67 currentVersion.value = 'dev'; 68 } 69 } 70 } catch (error) { 71 console.warn('Error loading versions:', error); 72 versions.value = [{ text: 'dev', link: `${absoluteOrigin}/dev/` }]; 73 currentVersion.value = 'dev'; 74 } 75 isClient.value = true; 76 }; 77 78 const versionItems = computed(() => { 79 return versions.value.map((v) => ({ 80 text: v.text, 81 link: v.link 82 })); 83 }); 84 85 onMounted(() => { 86 if (typeof window !== 'undefined') { 87 currentVersion.value = window.DOCUMENTER_CURRENT_VERSION ?? 'Versions'; 88 loadVersions(); 89 } 90 }); 91 </script> 92 93 <template> 94 <template v-if="isClient"> 95 <VPNavBarMenuGroup 96 v-if="!screenMenu && versions.length > 0" 97 :item="{ text: currentVersion, items: versionItems }" 98 class="VPVersionPicker" 99 /> 100 <VPNavScreenMenuGroup 101 v-else-if="screenMenu && versions.length > 0" 102 :text="currentVersion" 103 :items="versionItems" 104 class="VPVersionPicker" 105 /> 106 </template> 107 </template> 108 109 <style scoped> 110 .VPVersionPicker :deep(button .text) { 111 color: var(--vp-c-text-1) !important; 112 } 113 .VPVersionPicker:hover :deep(button .text) { 114 color: var(--vp-c-text-2) !important; 115 } 116 </style>