1<template>
2 <div class="relative" :style="{ width: `${sidebarWidth}px` }">
3 <slot v-bind="{ sidebarResizing, sidebarWidth }" />
4 <div
5 class="absolute z-10 h-full w-1 cursor-col-resize bg-surface-gray-4 opacity-0 transition-opacity hover:opacity-100"
6 :class="{
7 'opacity-100': sidebarResizing,
8 'left-0': side == 'right',
9 'right-0': side == 'left',
10 }"
11 @mousedown="startResize"
12 />
13 </div>
14</template>
15<script setup>
16import { ref } from "vue";
17
18const props = defineProps({
19 defaultWidth: {
20 type: Number,
21 default: 352,
22 },
23 minWidth: {
24 type: Number,
25 default: 16 * 16,
26 },
27 maxWidth: {
28 type: Number,
29 default: 30 * 16,
30 },
31 side: {
32 type: String,
33 default: "left",
34 },
35 parent: {
36 type: Object,
37 default: null,
38 },
39});
40
41const sidebarResizing = ref(false);
42const sidebarWidth = ref(props.defaultWidth);
43
44function startResize() {
45 document.addEventListener("mousemove", resize);
46 document.addEventListener("mouseup", () => {
47 document.body.classList.remove("select-none");
48 document.body.classList.remove("cursor-col-resize");
49 document.querySelectorAll(".select-text1").forEach((el) => {
50 el.classList.remove("select-text1");
51 el.classList.add("select-text");
52 });
53 localStorage.setItem("sidebarWidth", sidebarWidth.value);
54 sidebarResizing.value = false;
55 document.removeEventListener("mousemove", resize);
56 });
57}
58function resize(e) {
59 sidebarResizing.value = true;
60 document.body.classList.add("select-none");
61 document.body.classList.add("cursor-col-resize");
62 document.querySelectorAll(".select-text").forEach((el) => {
63 el.classList.remove("select-text");
64 el.classList.add("select-text1");
65 });
66 sidebarWidth.value =
67 props.side == "left" ? e.clientX : window.innerWidth - e.clientX;
68
69 let gap = props.parent ? distance() : 0;
70 sidebarWidth.value = sidebarWidth.value - gap;
71
72 // snap to props.defaultWidth
73 let range = [props.defaultWidth - 10, props.defaultWidth + 10];
74 if (sidebarWidth.value > range[0] && sidebarWidth.value < range[1]) {
75 sidebarWidth.value = props.defaultWidth;
76 }
77
78 if (sidebarWidth.value < props.minWidth) {
79 sidebarWidth.value = props.minWidth;
80 }
81 if (sidebarWidth.value > props.maxWidth) {
82 sidebarWidth.value = props.maxWidth;
83 }
84}
85function distance() {
86 if (!props.parent) return 0;
87 const rect = props.parent.getBoundingClientRect();
88 return rect[props.side];
89}
90</script>
91