20260813222656
This commit is contained in:
1 parent
ab30604fe4
commit
68de86aee9
3668 files changed
+3921
-216192
No files matched your search
@@ -0,0 +1,115 @@
|
||||
<script setup lang="ts">
|
||||
import { useEventListener, usePreferredReducedMotion } from "@vueuse/core";
|
||||
import { computed, ref } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { useAppStore } from "@/stores/app";
|
||||
import AppSidebar from "@/layouts/components/AppSidebar.vue";
|
||||
import AppTabs from "@/layouts/components/AppTabs.vue";
|
||||
import AppTopbar from "@/layouts/components/AppTopbar.vue";
|
||||
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
|
||||
|
||||
const route = useRoute();
|
||||
const appStore = useAppStore();
|
||||
const preferredReducedMotion = usePreferredReducedMotion();
|
||||
const routeInstanceKey = computed(
|
||||
() => `${route.fullPath}:${appStore.getRouteRefreshKey(route.fullPath)}`,
|
||||
);
|
||||
|
||||
// -- drag rail --
|
||||
const MIN_WIDTH = 180;
|
||||
const MAX_WIDTH = 400;
|
||||
const dragging = ref(false);
|
||||
let startX = 0,
|
||||
startWidth = 0;
|
||||
|
||||
useEventListener("mousemove", (e: MouseEvent) => {
|
||||
if (!dragging.value) return;
|
||||
const newWidth = Math.max(
|
||||
MIN_WIDTH,
|
||||
Math.min(MAX_WIDTH, Math.round(startWidth + e.clientX - startX)),
|
||||
);
|
||||
const wrapper = document.querySelector("[data-slot='sidebar-wrapper']") as HTMLElement | null;
|
||||
wrapper?.style.setProperty("--sidebar-width", `${newWidth / 16}rem`);
|
||||
});
|
||||
|
||||
useEventListener("mouseup", () => {
|
||||
if (!dragging.value) return;
|
||||
dragging.value = false;
|
||||
const wrapper = document.querySelector("[data-slot='sidebar-wrapper']") as HTMLElement | null;
|
||||
if (wrapper) {
|
||||
wrapper.style.userSelect = "";
|
||||
const group = wrapper.querySelector(".group.peer") as HTMLElement | null;
|
||||
group?.querySelectorAll("*").forEach((el) => {
|
||||
(el as HTMLElement).style.removeProperty("transition");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function onRailMouseDown(e: MouseEvent) {
|
||||
const sidebar = document.querySelector("[data-slot='sidebar']") as HTMLElement | null;
|
||||
if (sidebar?.dataset.state !== "expanded") return;
|
||||
e.preventDefault();
|
||||
dragging.value = true;
|
||||
startX = e.clientX;
|
||||
const wrapper = document.querySelector("[data-slot='sidebar-wrapper']") as HTMLElement | null;
|
||||
if (wrapper) {
|
||||
const w = getComputedStyle(wrapper).getPropertyValue("--sidebar-width").trim();
|
||||
startWidth = parseFloat(w || "14") * 16;
|
||||
wrapper.style.userSelect = "none";
|
||||
const group = wrapper.querySelector(".group.peer") as HTMLElement | null;
|
||||
group?.querySelectorAll("*").forEach((el) => {
|
||||
(el as HTMLElement).style.setProperty("transition", "none", "important");
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SidebarProvider
|
||||
class="group/sidebar h-svh min-w-0 overflow-hidden bg-sidebar"
|
||||
:style="{ '--sidebar-width': '14rem' }"
|
||||
>
|
||||
<AppSidebar />
|
||||
|
||||
<!-- Drag rail: hidden when collapsed, follows sidebar width when expanded -->
|
||||
<div
|
||||
data-sidebar="rail"
|
||||
class="fixed top-0 z-50 hidden w-4 h-screen cursor-col-resize sm:block group-has-[[data-state=collapsed]]/sidebar:hidden after:absolute after:left-1/2 after:-translate-x-px after:inset-y-0 after:w-0.5 hover:after:bg-sidebar-border"
|
||||
:style="{ left: 'calc(var(--sidebar-width) - 0.5rem)' }"
|
||||
@mousedown="onRailMouseDown"
|
||||
/>
|
||||
|
||||
<SidebarInset class="m-2 ml-0 min-w-0 overflow-hidden rounded-xl shadow z-10">
|
||||
<AppTopbar />
|
||||
<AppTabs />
|
||||
|
||||
<div class="flex min-h-0 min-w-0 flex-1 flex-col gap-4 overflow-auto p-4 pt-2">
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition name="page" mode="out-in" :css="preferredReducedMotion !== 'reduce'">
|
||||
<keep-alive :max="8">
|
||||
<component :is="Component" :key="routeInstanceKey" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</router-view>
|
||||
</div>
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.page-enter-active {
|
||||
transition:
|
||||
opacity 160ms ease-out,
|
||||
transform 160ms ease-out;
|
||||
}
|
||||
.page-leave-active {
|
||||
transition: opacity 80ms ease-in;
|
||||
}
|
||||
.page-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateY(4px);
|
||||
}
|
||||
.page-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user