Browse Source

wip: drag the sidebar

nian 1 month ago
parent
commit
093a9a248a
4 changed files with 71 additions and 20 deletions
  1. 3 0
      src/App.vue
  2. 1 0
      src/injection/interface.ts
  3. 59 19
      src/layout/aside/index.vue
  4. 8 1
      src/layout/header/logo/index.vue

+ 3 - 0
src/App.vue

@@ -31,6 +31,8 @@ const layoutSlideDirection = ref<LayoutSlideDirection>(null)
 
 const shouldRefreshRoute = ref(false)
 
+const isSidebarColResizing = ref(false)
+
 function setLayoutSlideDirection(direction: LayoutSlideDirection) {
   layoutSlideDirection.value = direction === layoutSlideDirection.value ? null : direction
 }
@@ -47,6 +49,7 @@ provide(layoutInjectionKey, {
   shouldRefreshRoute,
   layoutSlideDirection,
   setLayoutSlideDirection,
+  isSidebarColResizing,
 })
 </script>
 

+ 1 - 0
src/injection/interface.ts

@@ -14,4 +14,5 @@ export interface LayoutProvider {
   shouldRefreshRoute: Ref<boolean>
   layoutSlideDirection: Ref<LayoutSlideDirection>
   setLayoutSlideDirection: (direction: LayoutSlideDirection) => void
+  isSidebarColResizing: Ref<boolean>
 }

+ 59 - 19
src/layout/aside/index.vue

@@ -1,6 +1,9 @@
 <script setup lang="ts">
-import { computed } from 'vue'
+import { useDraggable } from '@vueuse/core'
+import { computed, useTemplateRef, watch } from 'vue'
 
+import { useInjection } from '@/composables'
+import { layoutInjectionKey } from '@/injection'
 import { toRefsPreferencesStore, DEFAULT_PREFERENCES_OPTIONS } from '@/stores'
 
 import SidebarMenu from './SidebarMenu.vue'
@@ -12,6 +15,12 @@ defineOptions({
 
 const { preferences, sidebarMenu } = toRefsPreferencesStore()
 
+const { isSidebarColResizing } = useInjection(layoutInjectionKey)
+
+const sidelineRef = useTemplateRef<HTMLDivElement>('sidebarLine')
+
+const { x } = useDraggable(sidelineRef, {})
+
 const menuCollapseWidth = computed(() => {
   return sidebarMenu.value.collapsed
     ? sidebarMenu.value.width || DEFAULT_PREFERENCES_OPTIONS.sidebarMenu.width
@@ -21,26 +30,57 @@ const menuCollapseWidth = computed(() => {
 function handleCollapseClick() {
   preferences.value.sidebarMenu.collapsed = !sidebarMenu.value.collapsed
 }
+
+const onSidelineMouseDown = () => {
+  isSidebarColResizing.value = true
+  document.documentElement.style.userSelect = 'none'
+  document.addEventListener(
+    'mouseup',
+    () => {
+      isSidebarColResizing.value = false
+      document.documentElement.style.userSelect = 'auto'
+    },
+    {
+      once: true,
+    },
+  )
+}
+
+watch(x, (newX) => {
+  console.log(newX)
+})
 </script>
 <template>
-  <aside
-    class="relative flex h-full flex-col justify-between gap-y-4 border-r border-naive-border bg-naive-card pb-4 transition-[background-color,border-color,width]"
-    :style="{
-      width: `${menuCollapseWidth + 1}px`,
-    }"
-  >
-    <SidebarMenu />
-    <SidebarUserPanel />
-    <div
-      class="absolute top-1/2 right-0 z-50 grid size-6 translate-x-1/2 -translate-y-1/2 cursor-pointer place-items-center rounded-full border border-naive-border bg-white transition-[background-color,border-color] hover:bg-neutral-50 dark:bg-neutral-750 dark:hover:bg-neutral-700"
-      @click="handleCollapseClick"
+  <div class="flex h-full">
+    <aside
+      class="relative flex h-full flex-col justify-between gap-y-4 bg-naive-card pb-4"
+      :class="{
+        'transition-[background-color,width]': !isSidebarColResizing,
+      }"
+      :style="{
+        width: `${menuCollapseWidth}px`,
+      }"
     >
-      <span
-        class="iconify size-4.5 transition-[color,rotate] ph--caret-left dark:text-neutral-400"
-        :class="{
-          'rotate-180': sidebarMenu.collapsed,
-        }"
-      />
+      <SidebarMenu />
+      <SidebarUserPanel />
+      <div
+        class="absolute top-1/2 right-0 z-50 grid size-6 translate-x-1/2 -translate-y-1/2 cursor-pointer place-items-center rounded-full border border-naive-border bg-white transition-[background-color,border-color] hover:bg-neutral-50 dark:bg-neutral-750 dark:hover:bg-neutral-700"
+        @click="handleCollapseClick"
+      >
+        <span
+          class="iconify size-4.5 transition-[color,rotate] ph--caret-left dark:text-neutral-400"
+          :class="{
+            'rotate-180': sidebarMenu.collapsed,
+          }"
+        />
+      </div>
+    </aside>
+    <div class="relative flex h-full justify-center border-r border-naive-border">
+      <div
+        ref="sidebarLine"
+        class="absolute z-10 h-full w-[5px] cursor-col-resize"
+        @mousedown="onSidelineMouseDown"
+      ></div>
     </div>
-  </aside>
+  </div>
 </template>

+ 8 - 1
src/layout/header/logo/index.vue

@@ -2,6 +2,8 @@
 import { nextTick, ref, useTemplateRef, watch } from 'vue'
 
 import Logo from '@/components/AppLogo.vue'
+import { useInjection } from '@/composables'
+import { layoutInjectionKey } from '@/injection'
 import { toRefsPreferencesStore, DEFAULT_PREFERENCES_OPTIONS } from '@/stores'
 
 defineOptions({
@@ -10,6 +12,8 @@ defineOptions({
 
 const APP_NAME = import.meta.env.VITE_APP_NAME
 
+const { isSidebarColResizing } = useInjection(layoutInjectionKey)
+
 const { navigationMode, sidebarMenu, showLogo } = toRefsPreferencesStore()
 
 const logoWrapperRef = useTemplateRef<HTMLElement>('logoWrapper')
@@ -37,7 +41,10 @@ watch(
 </script>
 <template>
   <div
-    class="shrink-0 transition-[width]"
+    class="shrink-0"
+    :class="{
+      'transition-[width]': !isSidebarColResizing,
+    }"
     :style="
       collapseWidth > 0 && {
         width: `${collapseWidth}px`,