添加目录树和大纲宽度调整功能
This commit is contained in:
@@ -67,17 +67,76 @@ const rootEntry = computed<DirEntry | null>(() => {
|
||||
// ---- sidebar view mode ----
|
||||
type ViewMode = "folder" | "search" | "setting";
|
||||
const activeView = ref<ViewMode>("folder");
|
||||
const expanded = ref(true);
|
||||
|
||||
// ---- sidebar resize ----
|
||||
const MIN_SIDEBAR_WIDTH = 180;
|
||||
const MAX_SIDEBAR_WIDTH = 500;
|
||||
const COLLAPSED_WIDTH = 48;
|
||||
const DEFAULT_EXPANDED_WIDTH = 288;
|
||||
|
||||
const sidebarWidth = ref(DEFAULT_EXPANDED_WIDTH);
|
||||
const lastExpandedWidth = ref(DEFAULT_EXPANDED_WIDTH);
|
||||
const isResizing = ref(false);
|
||||
const isCollapsed = computed(() => sidebarWidth.value <= COLLAPSED_WIDTH);
|
||||
|
||||
function expand() {
|
||||
sidebarWidth.value = lastExpandedWidth.value;
|
||||
}
|
||||
|
||||
function collapse() {
|
||||
sidebarWidth.value = COLLAPSED_WIDTH;
|
||||
}
|
||||
|
||||
function toggleCollapse() {
|
||||
if (isCollapsed.value) {
|
||||
expand();
|
||||
} else {
|
||||
collapse();
|
||||
}
|
||||
}
|
||||
|
||||
function switchView(view: ViewMode) {
|
||||
if (activeView.value === view) {
|
||||
expanded.value = !expanded.value;
|
||||
toggleCollapse();
|
||||
} else {
|
||||
activeView.value = view;
|
||||
expanded.value = true;
|
||||
if (isCollapsed.value) {
|
||||
expand();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---- resize handle drag ----
|
||||
let resizeStartX = 0;
|
||||
let resizeStartWidth = 0;
|
||||
|
||||
function startResize(e: MouseEvent) {
|
||||
resizeStartX = e.clientX;
|
||||
resizeStartWidth = sidebarWidth.value;
|
||||
isResizing.value = true;
|
||||
document.addEventListener("mousemove", onResize);
|
||||
document.addEventListener("mouseup", stopResize);
|
||||
document.body.style.cursor = "col-resize";
|
||||
document.body.style.userSelect = "none";
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function onResize(e: MouseEvent) {
|
||||
if (!isResizing.value) return;
|
||||
const delta = e.clientX - resizeStartX;
|
||||
const newWidth = Math.min(MAX_SIDEBAR_WIDTH, Math.max(MIN_SIDEBAR_WIDTH, resizeStartWidth + delta));
|
||||
sidebarWidth.value = newWidth;
|
||||
lastExpandedWidth.value = newWidth;
|
||||
}
|
||||
|
||||
function stopResize() {
|
||||
isResizing.value = false;
|
||||
document.removeEventListener("mousemove", onResize);
|
||||
document.removeEventListener("mouseup", stopResize);
|
||||
document.body.style.cursor = "";
|
||||
document.body.style.userSelect = "";
|
||||
}
|
||||
|
||||
// ---- workspace switcher ----
|
||||
const workspaceSwitcherRef = ref<HTMLElement | null>(null);
|
||||
const showWorkspaceMenu = ref(false);
|
||||
@@ -240,6 +299,10 @@ watch(() => props.folderPath, () => {
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener("click", onDocumentClick);
|
||||
document.removeEventListener("mousemove", onResize);
|
||||
document.removeEventListener("mouseup", stopResize);
|
||||
document.body.style.cursor = "";
|
||||
document.body.style.userSelect = "";
|
||||
});
|
||||
|
||||
// ---- settings modal ----
|
||||
@@ -259,7 +322,9 @@ function openSettings(page: SettingsPage) {
|
||||
|
||||
<template>
|
||||
<aside
|
||||
:class="['directory-sidebar flex flex-row transition-all duration-300 ease-in-out overflow-hidden shrink-0', expanded ? 'w-72' : 'w-12']"
|
||||
class="directory-sidebar flex flex-row overflow-hidden shrink-0"
|
||||
:class="{ 'transition-all duration-300 ease-in-out': !isResizing }"
|
||||
:style="{ width: sidebarWidth + 'px' }"
|
||||
>
|
||||
<!-- ============ Icon bar ============ -->
|
||||
<div class="w-12 shrink-0 flex flex-col items-center gap-1 py-3">
|
||||
@@ -293,7 +358,7 @@ function openSettings(page: SettingsPage) {
|
||||
</div>
|
||||
|
||||
<!-- ============ Expanded panel ============ -->
|
||||
<div v-show="expanded" class="directory-sidebar-panel flex-1 flex flex-col overflow-hidden">
|
||||
<div v-show="!isCollapsed" class="directory-sidebar-panel flex-1 flex flex-col overflow-hidden">
|
||||
<!-- ===== FOLDER VIEW ===== -->
|
||||
<div v-if="activeView === 'folder'" class="flex flex-col flex-1 overflow-hidden">
|
||||
<!-- File tree -->
|
||||
@@ -413,6 +478,16 @@ function openSettings(page: SettingsPage) {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ============ Resize handle ============ -->
|
||||
<div
|
||||
v-show="!isCollapsed"
|
||||
class="sidebar-resize-handle"
|
||||
:class="{ 'sidebar-resize-handle-active': isResizing }"
|
||||
@mousedown="startResize"
|
||||
>
|
||||
<div class="sidebar-resize-handle-bar"></div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<SettingsModal
|
||||
@@ -563,6 +638,7 @@ function openSettings(page: SettingsPage) {
|
||||
|
||||
<style scoped>
|
||||
.directory-sidebar {
|
||||
position: relative;
|
||||
border-right: 1px solid var(--app-border);
|
||||
background: color-mix(in srgb, var(--app-sidebar-bg) 82%, transparent);
|
||||
}
|
||||
@@ -571,6 +647,39 @@ function openSettings(page: SettingsPage) {
|
||||
border-left: 1px solid var(--app-border);
|
||||
}
|
||||
|
||||
/* ---- Resize handle ---- */
|
||||
.sidebar-resize-handle {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: -2px;
|
||||
bottom: 0;
|
||||
z-index: 25;
|
||||
display: flex;
|
||||
width: 7px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: col-resize;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.sidebar-resize-handle:hover,
|
||||
.sidebar-resize-handle-active {
|
||||
background: color-mix(in srgb, var(--app-accent) 18%, transparent);
|
||||
}
|
||||
|
||||
.sidebar-resize-handle-bar {
|
||||
width: 1px;
|
||||
height: 100%;
|
||||
border-radius: 1px;
|
||||
background: transparent;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.sidebar-resize-handle:hover .sidebar-resize-handle-bar,
|
||||
.sidebar-resize-handle-active .sidebar-resize-handle-bar {
|
||||
background: color-mix(in srgb, var(--app-accent) 36%, transparent);
|
||||
}
|
||||
|
||||
.sidebar-icon-btn {
|
||||
color: var(--app-subtle);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user