App.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. <template lang="pug">
  2. router-view
  3. </template>
  4. <script setup>
  5. import { reactive, watch } from 'vue'
  6. import { useRouter, useRoute } from 'vue-router'
  7. import { setCssVar, useQuasar } from 'quasar'
  8. import { useI18n } from 'vue-i18n'
  9. import '@mdi/font/css/materialdesignicons.css'
  10. import { useCommonStore } from './stores/common'
  11. import { useFlagsStore } from 'src/stores/flags'
  12. import { useSiteStore } from 'src/stores/site'
  13. import { useUserStore } from 'src/stores/user'
  14. /* global siteConfig */
  15. // QUASAR
  16. const $q = useQuasar()
  17. // STORES
  18. const commonStore = useCommonStore()
  19. const flagsStore = useFlagsStore()
  20. const siteStore = useSiteStore()
  21. const userStore = useUserStore()
  22. // I18N
  23. const i18n = useI18n({ useScope: 'global' })
  24. // ROUTER
  25. const router = useRouter()
  26. // STATE
  27. const state = reactive({
  28. isInitialized: false
  29. })
  30. // WATCHERS
  31. watch(() => userStore.appearance, (newValue) => {
  32. if (newValue === 'site') {
  33. $q.dark.set(siteStore.theme.dark)
  34. } else {
  35. $q.dark.set(newValue === 'dark')
  36. }
  37. })
  38. watch(() => userStore.cvd, () => {
  39. applyTheme()
  40. })
  41. watch(() => commonStore.locale, applyLocale)
  42. // LOCALE
  43. async function applyLocale (locale) {
  44. if (!i18n.availableLocales.includes(locale)) {
  45. try {
  46. i18n.setLocaleMessage(locale, await commonStore.fetchLocaleStrings(locale))
  47. } catch (err) {
  48. $q.notify({
  49. type: 'negative',
  50. message: `Failed to load ${locale} locale strings.`,
  51. caption: err.message
  52. })
  53. }
  54. }
  55. i18n.locale.value = locale
  56. }
  57. // THEME
  58. async function applyTheme () {
  59. // -> Dark Mode
  60. if (userStore.appearance === 'site') {
  61. $q.dark.set(siteStore.theme.dark)
  62. } else {
  63. $q.dark.set(userStore.appearance === 'dark')
  64. }
  65. // -> CSS Vars
  66. setCssVar('primary', userStore.getAccessibleColor('primary', siteStore.theme.colorPrimary))
  67. setCssVar('secondary', userStore.getAccessibleColor('secondary', siteStore.theme.colorSecondary))
  68. setCssVar('accent', userStore.getAccessibleColor('accent', siteStore.theme.colorAccent))
  69. setCssVar('header', userStore.getAccessibleColor('header', siteStore.theme.colorHeader))
  70. setCssVar('sidebar', userStore.getAccessibleColor('sidebar', siteStore.theme.colorSidebar))
  71. setCssVar('positive', userStore.getAccessibleColor('positive', '#02C39A'))
  72. setCssVar('negative', userStore.getAccessibleColor('negative', '#f03a47'))
  73. // -> Highlight.js Theme
  74. if (siteStore.theme.codeBlocksTheme) {
  75. const desiredHljsTheme = userStore.cvd !== 'none' ? 'github' : siteStore.theme.codeBlocksTheme
  76. const hljsStyleEl = document.querySelector('#hljs-theme')
  77. if (hljsStyleEl) {
  78. hljsStyleEl.remove()
  79. }
  80. const newHljsStyleEl = document.createElement('style')
  81. newHljsStyleEl.id = 'hljs-theme'
  82. newHljsStyleEl.innerHTML = (await import(`../node_modules/highlight.js/styles/${desiredHljsTheme}.css`)).default
  83. document.head.appendChild(newHljsStyleEl)
  84. }
  85. }
  86. // INIT SITE STORE
  87. if (typeof siteConfig !== 'undefined') {
  88. siteStore.$patch({
  89. id: siteConfig.id,
  90. title: siteConfig.title
  91. })
  92. applyTheme()
  93. }
  94. // ROUTE GUARDS
  95. router.beforeEach(async (to, from) => {
  96. commonStore.routerLoading = true
  97. // -> Init Auth Token
  98. if (userStore.token && !userStore.authenticated) {
  99. userStore.loadToken()
  100. }
  101. // -> System Flags
  102. if (!flagsStore.loaded) {
  103. flagsStore.load()
  104. }
  105. // -> Site Info
  106. if (!siteStore.id) {
  107. console.info('No pre-cached site config. Loading site info...')
  108. await siteStore.loadSite(window.location.hostname)
  109. console.info(`Using Site ID ${siteStore.id}`)
  110. }
  111. // -> Locale
  112. if (!commonStore.desiredLocale || !siteStore.locales.active.some(l => l.code === commonStore.desiredLocale)) {
  113. commonStore.setLocale(siteStore.locales.primary)
  114. } else {
  115. applyLocale(commonStore.desiredLocale)
  116. }
  117. // -> User Profile
  118. if (userStore.authenticated && !userStore.profileLoaded) {
  119. console.info(`Refreshing user ${userStore.id} profile...`)
  120. await userStore.refreshProfile()
  121. }
  122. // -> Page Permissions
  123. await userStore.fetchPagePermissions(to.path)
  124. })
  125. // GLOBAL EVENTS HANDLERS
  126. EVENT_BUS.on('logout', () => {
  127. router.push('/')
  128. $q.notify({
  129. type: 'positive',
  130. icon: 'las la-sign-out-alt',
  131. message: i18n.t('auth.logoutSuccess')
  132. })
  133. })
  134. EVENT_BUS.on('applyTheme', () => {
  135. applyTheme()
  136. })
  137. // LOADER
  138. router.afterEach(() => {
  139. if (!state.isInitialized) {
  140. state.isInitialized = true
  141. applyTheme()
  142. document.querySelector('.init-loading').remove()
  143. }
  144. commonStore.routerLoading = false
  145. })
  146. </script>