vp-app.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. <script setup lang="ts">
  2. import { onMounted } from 'vue'
  3. import { ElMessageBox } from 'element-plus'
  4. import nprogress from 'nprogress'
  5. import dayjs from 'dayjs'
  6. import { isClient, useStorage, useToggle } from '@vueuse/core'
  7. import { useSidebar } from '../composables/sidebar'
  8. import { useToggleWidgets } from '../composables/toggle-widgets'
  9. import { useLang } from '../composables/lang'
  10. import { breakpoints } from '../constant'
  11. import VPOverlay from './vp-overlay.vue'
  12. import VPNav from './vp-nav.vue'
  13. import VPSubNav from './vp-subnav.vue'
  14. import VPSidebar from './vp-sidebar.vue'
  15. import VPContent from './vp-content.vue'
  16. import VPSponsors from './vp-sponsors.vue'
  17. const USER_PREFER_GITHUB_PAGE = 'USER_PREFER_GITHUB_PAGE'
  18. const [isSidebarOpen, toggleSidebar] = useToggle(false)
  19. const { hasSidebar } = useSidebar()
  20. const lang = useLang()
  21. const mirrorUrl = 'element-plus.gitee.io'
  22. const isMirrorUrl = () => {
  23. if (!isClient) return
  24. return window.location.hostname === mirrorUrl
  25. }
  26. useToggleWidgets(isSidebarOpen, () => {
  27. if (!isClient) return
  28. if (window.outerWidth >= breakpoints.lg) {
  29. toggleSidebar(false)
  30. }
  31. })
  32. const userPrefer = useStorage<boolean | string>(USER_PREFER_GITHUB_PAGE, null)
  33. onMounted(async () => {
  34. if (!isClient) return
  35. window.addEventListener(
  36. 'click',
  37. (e) => {
  38. const link = (e.target as HTMLElement).closest('a')
  39. if (!link) return
  40. const { protocol, hostname, pathname, target } = link
  41. const currentUrl = window.location
  42. const extMatch = pathname.match(/\.\w+$/)
  43. // only intercept inbound links
  44. if (
  45. !e.ctrlKey &&
  46. !e.shiftKey &&
  47. !e.altKey &&
  48. !e.metaKey &&
  49. target !== `_blank` &&
  50. protocol === currentUrl.protocol &&
  51. hostname === currentUrl.hostname &&
  52. !(extMatch && extMatch[0] !== '.html')
  53. ) {
  54. e.preventDefault()
  55. if (pathname !== currentUrl.pathname) {
  56. nprogress.start()
  57. }
  58. }
  59. },
  60. { capture: true }
  61. )
  62. if (lang.value === 'zh-CN') {
  63. if (isMirrorUrl()) return
  64. if (userPrefer.value) {
  65. // no alert in the next 90 days
  66. if (
  67. dayjs
  68. .unix(Number(userPrefer.value))
  69. .add(90, 'day')
  70. .diff(dayjs(), 'day', true) > 0
  71. )
  72. return
  73. }
  74. try {
  75. await ElMessageBox.confirm(
  76. '建议大陆用户访问部署在国内的站点,是否跳转?',
  77. '提示',
  78. {
  79. confirmButtonText: '跳转',
  80. cancelButtonText: '取消',
  81. }
  82. )
  83. const toLang = '/zh-CN/'
  84. location.href = `https://element-plus.gitee.io${toLang}${location.pathname.slice(
  85. toLang.length
  86. )}`
  87. } catch {
  88. userPrefer.value = String(dayjs().unix())
  89. }
  90. }
  91. // unregister sw
  92. navigator?.serviceWorker?.getRegistrations().then((registrations) => {
  93. for (const registration of registrations) {
  94. registration.unregister()
  95. }
  96. })
  97. })
  98. </script>
  99. <template>
  100. <div class="App">
  101. <VPOverlay
  102. class="overlay"
  103. :show="isSidebarOpen"
  104. @click="toggleSidebar(false)"
  105. />
  106. <VPNav />
  107. <VPSubNav v-if="hasSidebar" @open-menu="toggleSidebar(true)" />
  108. <VPSidebar :open="isSidebarOpen" @close="toggleSidebar(false)">
  109. <template #top>
  110. <VPSponsors />
  111. </template>
  112. <template #bottom>
  113. <slot name="sidebar-bottom" />
  114. </template>
  115. </VPSidebar>
  116. <VPContent :is-sidebar-open="isSidebarOpen">
  117. <template #content-top>
  118. <slot name="content-top" />
  119. </template>
  120. <template #content-bottom>
  121. <slot name="content-bottom" />
  122. </template>
  123. <template #aside-top>
  124. <slot name="aside-top" />
  125. </template>
  126. <template #aside-mid>
  127. <slot name="aside-mid" />
  128. </template>
  129. <template #aside-bottom>
  130. <slot name="aside-bottom" />
  131. </template>
  132. </VPContent>
  133. <Debug />
  134. </div>
  135. </template>