index.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. <script setup lang="ts">
  2. import { isEmpty } from 'lodash-es'
  3. import { computed, defineAsyncComponent, watch } from 'vue'
  4. import texturePng from '@/assets/texture.png'
  5. import { CollapseTransition, EmptyPlaceholder } from '@/components'
  6. import { useInjection } from '@/composables'
  7. import { mediaQueryInjectionKey, layoutInjectionKey } from '@/injection'
  8. import { usePreferencesStore, useTabsStore } from '@/stores'
  9. import AsideLayout from './aside/index.vue'
  10. import Tabs from './component/Tabs.vue'
  11. import FooterLayout from './footer/index.vue'
  12. import HeaderLayout from './header/index.vue'
  13. import MainLayout from './main/index.vue'
  14. defineOptions({
  15. name: 'Layout',
  16. })
  17. const tabsStore = useTabsStore()
  18. const preferencesStore = usePreferencesStore()
  19. const { isSmallScreen } = useInjection(mediaQueryInjectionKey)
  20. const { layoutSlideDirection, setLayoutSlideDirection } = useInjection(layoutInjectionKey)
  21. const MobileHeader = defineAsyncComponent(() => import('./mobile/MobileHeader.vue'))
  22. const MobileLeftAside = defineAsyncComponent(() => import('./mobile/MobileLeftAside.vue'))
  23. const MobileRightAside = defineAsyncComponent(() => import('./mobile/MobileRightAside.vue'))
  24. const layoutTranslateOffset = computed(() => {
  25. return layoutSlideDirection.value === 'right'
  26. ? preferencesStore.preferences.menu.maxWidth || 0
  27. : layoutSlideDirection.value === 'left'
  28. ? -64
  29. : 0
  30. })
  31. watch(
  32. () => isSmallScreen.value,
  33. (isSmallScreen) => {
  34. if (isSmallScreen) {
  35. preferencesStore.modify({
  36. menu: {
  37. collapsed: false,
  38. },
  39. })
  40. setLayoutSlideDirection(null)
  41. }
  42. },
  43. )
  44. </script>
  45. <template>
  46. <div
  47. class="relative flex h-svh overflow-hidden"
  48. :style="{ backgroundImage: `url(${texturePng})` }"
  49. >
  50. <MobileLeftAside v-if="isSmallScreen" />
  51. <div
  52. class="relative flex h-full w-full flex-col max-sm:bg-naive-card/50"
  53. :class="{
  54. 'border-naive-border transition-[background-color,border-color,rounded,transform]':
  55. isSmallScreen,
  56. 'rounded-xl border pb-2': isSmallScreen && layoutTranslateOffset,
  57. }"
  58. :style="
  59. isSmallScreen &&
  60. layoutSlideDirection && {
  61. transform: `translate(${layoutTranslateOffset}px) scale(0.88)`,
  62. }
  63. "
  64. >
  65. <HeaderLayout v-if="!isSmallScreen" />
  66. <MobileHeader v-else />
  67. <div class="flex flex-1 overflow-hidden">
  68. <AsideLayout v-if="!isSmallScreen" />
  69. <div class="flex flex-1 flex-col overflow-hidden">
  70. <CollapseTransition
  71. v-if="!isSmallScreen"
  72. :display="!isEmpty(tabsStore.tabs) && preferencesStore.preferences.showTabs"
  73. direction="horizontal"
  74. :render-content="false"
  75. container-class="shrink-0 items-baseline"
  76. >
  77. <Tabs />
  78. </CollapseTransition>
  79. <div class="relative flex-1 overflow-hidden">
  80. <MainLayout />
  81. </div>
  82. <EmptyPlaceholder
  83. :show="isEmpty(tabsStore.tabs)"
  84. description="空标签页"
  85. size="huge"
  86. >
  87. <template #icon>
  88. <div class="flex items-center justify-center">
  89. <span class="iconify ph--rectangle" />
  90. </div>
  91. </template>
  92. </EmptyPlaceholder>
  93. <CollapseTransition
  94. v-if="!isSmallScreen"
  95. :display="preferencesStore.preferences.showFooter"
  96. direction="horizontal"
  97. :render-content="false"
  98. container-class="shrink-0 items-baseline"
  99. >
  100. <FooterLayout />
  101. </CollapseTransition>
  102. </div>
  103. </div>
  104. <div
  105. v-if="isSmallScreen && layoutSlideDirection"
  106. class="absolute inset-0"
  107. @click="setLayoutSlideDirection(null)"
  108. />
  109. </div>
  110. <MobileRightAside v-if="isSmallScreen" />
  111. </div>
  112. </template>