Browse Source

refactor: reference Tailwind breakpoint query

nian 1 month ago
parent
commit
36afd35fcc

+ 10 - 9
src/App.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { useMediaQuery } from '@vueuse/core'
+import { breakpointsTailwind, useBreakpoints } from '@vueuse/core'
 import {
   NConfigProvider,
   NModalProvider,
@@ -25,13 +25,7 @@ import type { LayoutSlideDirection } from './injection'
 const { showWatermark, showNoise, watermarkOptions } = storeToRefs(usePreferencesStore())
 const configProviderProps = getConfigProviderProps()
 
-const mediaQuery = {
-  isSmallScreen: useMediaQuery('(max-width: 640px)'),
-  isMediumScreen: useMediaQuery('(max-width: 768px)'),
-  isLargeScreen: useMediaQuery('(max-width: 1024px)'),
-  isExtraLargeScreen: useMediaQuery('(max-width: 1280px)'),
-  isExtraExtraLargeScreen: useMediaQuery('(max-width: 1536px)'),
-}
+const breakpoints = useBreakpoints(breakpointsTailwind)
 
 const layoutSlideDirection = ref<LayoutSlideDirection>(null)
 
@@ -40,7 +34,14 @@ const shouldRefreshRoute = ref(false)
 function setLayoutSlideDirection(direction: LayoutSlideDirection) {
   layoutSlideDirection.value = direction === layoutSlideDirection.value ? null : direction
 }
-provide(mediaQueryInjectionKey, mediaQuery)
+
+provide(mediaQueryInjectionKey, {
+  isMaxSm: breakpoints.smaller('sm'),
+  isMaxMd: breakpoints.smaller('md'),
+  isMaxLg: breakpoints.smaller('lg'),
+  isMaxXl: breakpoints.smaller('xl'),
+  isMax2Xl: breakpoints.smaller('2xl'),
+})
 
 provide(layoutInjectionKey, {
   shouldRefreshRoute,

+ 5 - 5
src/injection/interface.ts

@@ -1,11 +1,11 @@
 import type { ComputedRef, Ref } from 'vue'
 
 export interface MediaQueryProvider {
-  isSmallScreen: ComputedRef<boolean>
-  isMediumScreen: ComputedRef<boolean>
-  isLargeScreen: ComputedRef<boolean>
-  isExtraLargeScreen: ComputedRef<boolean>
-  isExtraExtraLargeScreen: ComputedRef<boolean>
+  isMaxSm: ComputedRef<boolean>
+  isMaxMd: ComputedRef<boolean>
+  isMaxLg: ComputedRef<boolean>
+  isMaxXl: ComputedRef<boolean>
+  isMax2Xl: ComputedRef<boolean>
 }
 
 export type LayoutSlideDirection = 'left' | 'right' | null

+ 8 - 8
src/layout/header/action/PreferencesDrawer.vue

@@ -23,7 +23,7 @@ import LayoutThumbnail from './component/LayoutThumbnail.vue'
 import NoiseModal from './component/NoiseModal.vue'
 import WatermarkModal from './component/WatermarkModal.vue'
 
-const { isSmallScreen } = useInjection(mediaQueryInjectionKey)
+const { isMaxSm } = useInjection(mediaQueryInjectionKey)
 
 const preferencesStore = usePreferencesStore()
 
@@ -173,7 +173,7 @@ const showNoiseModal = () => {
                   :value="sidebarMenu.collapsed"
                   :checked-value="false"
                   :unchecked-value="true"
-                  :disabled="isSmallScreen || navigationMode !== 'sidebar'"
+                  :disabled="isMaxSm || navigationMode !== 'sidebar'"
                   @update-value="
                     (value) =>
                       modify({
@@ -212,7 +212,7 @@ const showNoiseModal = () => {
                 <span>显示导航按钮</span>
                 <NSwitch
                   :value="showNavigationButton"
-                  :disabled="isSmallScreen || navigationMode !== 'sidebar'"
+                  :disabled="isMaxSm || navigationMode !== 'sidebar'"
                   @update-value="
                     (value) =>
                       modify({
@@ -225,7 +225,7 @@ const showNoiseModal = () => {
                 <span>显示面包屑</span>
                 <NSwitch
                   :value="showBreadcrumb"
-                  :disabled="isSmallScreen || navigationMode !== 'sidebar'"
+                  :disabled="isMaxSm || navigationMode !== 'sidebar'"
                   @update-value="
                     (value) =>
                       modify({
@@ -238,7 +238,7 @@ const showNoiseModal = () => {
                 <span>显示标签页</span>
                 <NSwitch
                   :value="showTabs"
-                  :disabled="isSmallScreen"
+                  :disabled="isMaxSm"
                   @update-value="
                     (value) =>
                       modify({
@@ -251,7 +251,7 @@ const showNoiseModal = () => {
                 <span>常显标签关闭按钮</span>
                 <NSwitch
                   :value="showTabClose"
-                  :disabled="isSmallScreen"
+                  :disabled="isMaxSm"
                   @update-value="
                     (value) =>
                       modify({
@@ -264,7 +264,7 @@ const showNoiseModal = () => {
                 <span>显示底部</span>
                 <NSwitch
                   :value="showFooter"
-                  :disabled="isSmallScreen"
+                  :disabled="isMaxSm"
                   @update-value="
                     (value) =>
                       modify({
@@ -325,7 +325,7 @@ const showNoiseModal = () => {
                 <span>启用导航过渡效果</span>
                 <NSwitch
                   :value="enableNavigationTransition"
-                  :disabled="isSmallScreen"
+                  :disabled="isMaxSm"
                   @update-value="
                     (value) =>
                       modify({

+ 2 - 2
src/layout/header/action/index.vue

@@ -21,7 +21,7 @@ const AsyncAvatarDropdown = defineAsyncComponent({
   delay: 0,
 })
 
-const { isSmallScreen } = useInjection(mediaQueryInjectionKey)
+const { isMaxSm } = useInjection(mediaQueryInjectionKey)
 const { navigationMode } = storeToRefs(usePreferencesStore())
 </script>
 <template>
@@ -38,6 +38,6 @@ const { navigationMode } = storeToRefs(usePreferencesStore())
     <ThemePopselect />
     <PreferencesDrawer />
     <SignOut />
-    <AsyncAvatarDropdown v-if="!isSmallScreen && navigationMode === 'horizontal'" />
+    <AsyncAvatarDropdown v-if="!isMaxSm && navigationMode === 'horizontal'" />
   </div>
 </template>

+ 13 - 13
src/layout/index.vue

@@ -41,7 +41,7 @@ const AsyncAsideLayout = defineAsyncComponent({
 const tabsStore = useTabsStore()
 const { tabs } = storeToRefs(tabsStore)
 
-const { isSmallScreen } = useInjection(mediaQueryInjectionKey)
+const { isMaxSm } = useInjection(mediaQueryInjectionKey)
 
 const { layoutSlideDirection, setLayoutSlideDirection } = useInjection(layoutInjectionKey)
 
@@ -53,8 +53,8 @@ const layoutTranslateOffset = computed(() => {
       : 0
 })
 
-watch(isSmallScreen, (isSmallScreen) => {
-  if (isSmallScreen) {
+watch(isMaxSm, (isMaxSm) => {
+  if (isMaxSm) {
     modify({
       sidebarMenu: {
         collapsed: false,
@@ -69,27 +69,27 @@ watch(isSmallScreen, (isSmallScreen) => {
     class="relative h-svh overflow-hidden"
     :style="{ backgroundImage: `url(${texturePng})` }"
   >
-    <AsyncMobileLeftAside v-if="isSmallScreen" />
+    <AsyncMobileLeftAside v-if="isMaxSm" />
 
     <div
       class="relative flex h-full flex-col max-sm:bg-naive-card/50"
       :class="{
         'border-naive-border transition-[background-color,border-color,rounded,transform]':
-          isSmallScreen,
-        'rounded-xl border pb-2': isSmallScreen && layoutTranslateOffset,
+          isMaxSm,
+        'rounded-xl border pb-2': isMaxSm && layoutTranslateOffset,
       }"
       :style="
-        isSmallScreen &&
+        isMaxSm &&
         layoutSlideDirection && {
           transform: `translate(${layoutTranslateOffset}px) scale(0.88)`,
         }
       "
     >
-      <HeaderLayout v-if="!isSmallScreen" />
+      <HeaderLayout v-if="!isMaxSm" />
       <AsyncMobileHeader v-else />
       <div class="flex flex-1 overflow-hidden">
         <CollapseTransition
-          v-if="!isSmallScreen"
+          v-if="!isMaxSm"
           :display="navigationMode === 'sidebar'"
           content-class="min-h-0"
         >
@@ -99,7 +99,7 @@ watch(isSmallScreen, (isSmallScreen) => {
           class="relative flex flex-1 flex-col overflow-hidden border-t border-naive-border transition-[border-color]"
         >
           <CollapseTransition
-            v-if="!isSmallScreen"
+            v-if="!isMaxSm"
             :display="!isEmpty(tabs) && showTabs"
             direction="horizontal"
             :render-content="false"
@@ -121,7 +121,7 @@ watch(isSmallScreen, (isSmallScreen) => {
             </template>
           </EmptyPlaceholder>
           <CollapseTransition
-            v-if="!isSmallScreen"
+            v-if="!isMaxSm"
             :display="showFooter"
             direction="horizontal"
             :render-content="false"
@@ -131,12 +131,12 @@ watch(isSmallScreen, (isSmallScreen) => {
         </div>
       </div>
       <div
-        v-if="isSmallScreen && layoutSlideDirection"
+        v-if="isMaxSm && layoutSlideDirection"
         class="absolute inset-0"
         style="z-index: 9997"
         @click="setLayoutSlideDirection(null)"
       />
     </div>
-    <AsyncMobileRightAside v-if="isSmallScreen" />
+    <AsyncMobileRightAside v-if="isMaxSm" />
   </div>
 </template>

+ 2 - 2
src/layout/main/index.vue

@@ -16,7 +16,7 @@ defineOptions({
   name: 'MainLayout',
 })
 
-const { isSmallScreen } = useInjection(mediaQueryInjectionKey)
+const { isMaxSm } = useInjection(mediaQueryInjectionKey)
 
 const { shouldRefreshRoute, layoutSlideDirection, setLayoutSlideDirection } =
   useInjection(layoutInjectionKey)
@@ -81,7 +81,7 @@ watch(
       }
     }
 
-    if (isSmallScreen.value) {
+    if (isMaxSm.value) {
       navigationTransitionName.value = ''
       return
     }

+ 4 - 4
src/views/about/index.vue

@@ -13,7 +13,7 @@ defineOptions({
 
 let codeToHtml: any
 
-const { isMediumScreen } = useInjection(mediaQueryInjectionKey)
+const { isMaxMd } = useInjection(mediaQueryInjectionKey)
 
 const APP_NAME = import.meta.env.VITE_APP_NAME
 
@@ -219,7 +219,7 @@ onMounted(async () => {
   <ContentWrapper content-class="flex flex-col gap-y-2">
     <NCard
       :title="`关于 ${APP_NAME}`"
-      :size="isMediumScreen ? 'small' : undefined"
+      :size="isMaxMd ? 'small' : undefined"
     >
       <p class="text-base">
         {{ APP_NAME }} 是一个轻盈而优雅的后台管理模板,主要技术栈由
@@ -292,7 +292,7 @@ onMounted(async () => {
     <div class="flex gap-x-2 max-lg:flex-col">
       <NCard
         title="目录结构"
-        :size="isMediumScreen ? 'small' : undefined"
+        :size="isMaxMd ? 'small' : undefined"
       >
         <NScrollbar container-style="max-height: 1100px;">
           <div v-html="directoryStructureHighlight"></div>
@@ -300,7 +300,7 @@ onMounted(async () => {
       </NCard>
       <NCard
         title="依赖信息"
-        :size="isMediumScreen ? 'small' : undefined"
+        :size="isMaxMd ? 'small' : undefined"
       >
         <NSplit
           direction="vertical"

+ 5 - 5
src/views/data-show/data-form/index.vue

@@ -46,7 +46,7 @@ defineOptions({
 
 let codeToHtml: any
 
-const { isMediumScreen, isLargeScreen, isExtraLargeScreen } = useInjection(mediaQueryInjectionKey)
+const { isMaxMd, isMaxLg, isMaxXl } = useInjection(mediaQueryInjectionKey)
 
 const message = useMessage()
 
@@ -228,12 +228,12 @@ watch(
     >
       一个数据表单的例子,做了一些验证的限制,右边是规则和表单的数据,你可以拖动它们之间的分割线
     </NAlert>
-    <NCard :size="isMediumScreen ? 'small' : undefined">
+    <NCard :size="isMaxMd ? 'small' : undefined">
       <NSplit
-        :pane1-class="isLargeScreen ? 'pb-4' : 'pr-8'"
-        :pane2-class="isLargeScreen ? 'pt-4' : 'pl-8'"
+        :pane1-class="isMaxLg ? 'pb-4' : 'pr-8'"
+        :pane2-class="isMaxLg ? 'pt-4' : 'pl-8'"
         :default-size="0.6"
-        :direction="isExtraLargeScreen ? 'vertical' : 'horizontal'"
+        :direction="isMaxXl ? 'vertical' : 'horizontal'"
       >
         <template #1>
           <NScrollbar>

+ 13 - 13
src/views/data-show/data-table/index.vue

@@ -46,7 +46,7 @@ defineOptions({
   name: 'DataTable',
 })
 
-const { isMediumScreen, isLargeScreen } = useInjection(mediaQueryInjectionKey)
+const { isMaxMd, isMaxLg } = useInjection(mediaQueryInjectionKey)
 
 const formRef = useTemplateRef<InstanceType<typeof NForm>>('formRef')
 
@@ -398,7 +398,7 @@ function createOrEditData(data?: UserInfo) {
     draggable: true,
     style: {
       width: '500px',
-      ...(isMediumScreen.value ? { marginInline: '16px' } : {}),
+      ...(isMaxMd.value ? { marginInline: '16px' } : {}),
     },
     content: () => (
       <ActionModal
@@ -440,7 +440,7 @@ getDataList()
 <template>
   <ContentWrapper
     content-class="flex flex-col gap-y-2"
-    :scrollable="isLargeScreen"
+    :scrollable="isMaxLg"
   >
     <NAlert
       type="info"
@@ -449,7 +449,7 @@ getDataList()
       一个数据表格的例子,不算复杂,也许对你有帮助
     </NAlert>
     <NCard
-      :size="isMediumScreen ? 'small' : undefined"
+      :size="isMaxMd ? 'small' : undefined"
       class="flex-1"
       content-class="flex flex-col"
     >
@@ -458,10 +458,10 @@ getDataList()
           ref="formRef"
           :model="form"
           :rules="rules"
-          :inline="!isLargeScreen"
+          :inline="!isMaxLg"
           label-placement="left"
           class="max-lg:w-full max-lg:flex-col"
-          :label-width="isLargeScreen ? 70 : undefined"
+          :label-width="isMaxLg ? 70 : undefined"
         >
           <NFormItem
             label="姓名"
@@ -541,7 +541,7 @@ getDataList()
           ref="dataTableRef"
           v-model:checked-row-keys="checkedRowKeys"
           :remote="true"
-          :flex-height="!isLargeScreen"
+          :flex-height="!isMaxLg"
           :scroll-x="enableScrollX ? 1800 : 0"
           :columns="columns"
           :data="dataList"
@@ -581,7 +581,7 @@ getDataList()
               </NButton>
 
               <NButton
-                v-show="!isMediumScreen"
+                v-show="!isMaxMd"
                 @click="enableContextmenu = !enableContextmenu"
                 :type="enableContextmenu ? 'primary' : 'default'"
                 secondary
@@ -589,7 +589,7 @@ getDataList()
                 右键菜单
               </NButton>
               <NButton
-                v-show="!isMediumScreen"
+                v-show="!isMaxMd"
                 @click="handleDownloadCsvClick"
                 secondary
                 type="info"
@@ -601,10 +601,10 @@ getDataList()
           <NPagination
             v-bind="pagination"
             :prefix="paginationPrefix"
-            :page-slot="isMediumScreen ? 5 : undefined"
-            :show-quick-jump-dropdown="!isMediumScreen"
-            :show-quick-jumper="!isMediumScreen"
-            :show-size-picker="!isMediumScreen"
+            :page-slot="isMaxMd ? 5 : undefined"
+            :show-quick-jump-dropdown="!isMaxMd"
+            :show-quick-jumper="!isMaxMd"
+            :show-size-picker="!isMaxMd"
           />
         </div>
       </div>

+ 17 - 17
src/views/drag-drop/index.vue

@@ -15,7 +15,7 @@ defineOptions({
 
 let codeToHtml: any
 
-const { isMediumScreen } = useInjection(mediaQueryInjectionKey)
+const { isMaxMd } = useInjection(mediaQueryInjectionKey)
 
 const APP_NAME = import.meta.env.VITE_APP_NAME
 
@@ -125,14 +125,14 @@ watch(
     </NAlert>
     <NCard
       title="基础使用"
-      :size="isMediumScreen ? 'small' : undefined"
+      :size="isMaxMd ? 'small' : undefined"
     >
       <NSplit
-        :direction="isMediumScreen ? 'vertical' : 'horizontal'"
-        :pane1-class="isMediumScreen ? 'pb-4' : 'pr-8'"
-        :pane2-class="isMediumScreen ? 'pt-4' : 'pl-8'"
+        :direction="isMaxMd ? 'vertical' : 'horizontal'"
+        :pane1-class="isMaxMd ? 'pb-4' : 'pr-8'"
+        :pane2-class="isMaxMd ? 'pt-4' : 'pl-8'"
         :style="{
-          height: isMediumScreen ? '580px' : '280px',
+          height: isMaxMd ? '580px' : '280px',
         }"
       >
         <template #1>
@@ -170,7 +170,7 @@ watch(
     </NCard>
     <NCard
       title="网格布局"
-      :size="isMediumScreen ? 'small' : undefined"
+      :size="isMaxMd ? 'small' : undefined"
     >
       <div class="mb-4">
         你可以把<span class="text-primary">网格布局</span>的元素拖进<span class="text-primary"
@@ -178,11 +178,11 @@ watch(
         >中,它们可以相互拖放
       </div>
       <NSplit
-        :direction="isMediumScreen ? 'vertical' : 'horizontal'"
-        :pane1-class="isMediumScreen ? 'pb-4' : 'pr-8'"
-        :pane2-class="isMediumScreen ? 'pt-4' : 'pl-8'"
+        :direction="isMaxMd ? 'vertical' : 'horizontal'"
+        :pane1-class="isMaxMd ? 'pb-4' : 'pr-8'"
+        :pane2-class="isMaxMd ? 'pt-4' : 'pl-8'"
         :style="{
-          height: isMediumScreen ? '680px' : '280px',
+          height: isMaxMd ? '680px' : '280px',
         }"
         :default-size="0.7"
       >
@@ -220,14 +220,14 @@ watch(
     </NCard>
     <NCard
       title="克隆使用"
-      :size="isMediumScreen ? 'small' : undefined"
+      :size="isMaxMd ? 'small' : undefined"
     >
       <NSplit
-        :direction="isMediumScreen ? 'vertical' : 'horizontal'"
-        :pane1-class="isMediumScreen ? 'pb-4' : 'pr-8'"
-        :pane2-class="isMediumScreen ? 'pt-4' : 'pl-8'"
+        :direction="isMaxMd ? 'vertical' : 'horizontal'"
+        :pane1-class="isMaxMd ? 'pb-4' : 'pr-8'"
+        :pane2-class="isMaxMd ? 'pt-4' : 'pl-8'"
         :style="{
-          height: isMediumScreen ? '780px' : '280px',
+          height: isMaxMd ? '780px' : '280px',
         }"
         :default-size="0.7"
       >
@@ -256,7 +256,7 @@ watch(
             <NScrollbar>
               <EmptyPlaceholder
                 :show="cloneTaskList.length <= 0"
-                :description="`把${isMediumScreen ? '上' : '左'}边的任务拖拽到这里`"
+                :description="`把${isMaxMd ? '上' : '左'}边的任务拖拽到这里`"
               />
               <VueDraggable
                 ref="cloneTaskListDragRef"

+ 2 - 2
src/views/dynamic-route/index.vue

@@ -6,7 +6,7 @@ import { ContentWrapper } from '@/components'
 import { useInjection } from '@/composables'
 import { mediaQueryInjectionKey } from '@/injection'
 
-const { isMediumScreen } = useInjection(mediaQueryInjectionKey)
+const { isMaxMd } = useInjection(mediaQueryInjectionKey)
 
 defineOptions({
   name: 'DynamicRoute',
@@ -22,7 +22,7 @@ const router = useRouter()
     >
       在路由配置的 meta 中添加 enableMultiTab 属性,访问不同的动态路径时都会创建新的 tab
     </NAlert>
-    <NCard :size="isMediumScreen ? 'small' : undefined">
+    <NCard :size="isMaxMd ? 'small' : undefined">
       <div class="grid grid-cols-5 gap-4 max-lg:grid-cols-3 max-md:grid-cols-2 max-sm:grid-cols-1">
         <RouterLink
           v-for="value in 50"

+ 2 - 2
src/views/sign-in/index.vue

@@ -26,7 +26,7 @@ defineOptions({
 })
 
 const { isDark } = usePersonalization()
-const { isSmallScreen } = useInjection(mediaQueryInjectionKey)
+const { isMaxSm } = useInjection(mediaQueryInjectionKey)
 
 const userStore = useUserStore()
 const { setToken } = userStore
@@ -143,7 +143,7 @@ onUnmounted(() => {
     />
     <div class="relative z-50 flex h-[480px] w-[800px] justify-center rounded shadow-lg">
       <div
-        v-if="!isSmallScreen"
+        v-if="!isMaxSm"
         class="flex-1 bg-neutral-50 py-6 pl-6 text-primary transition-[background-color] dark:bg-neutral-850"
       >
         <NCarousel