优化功能

This commit is contained in:
2026-07-10 16:58:05 +08:00
parent 78913c46b6
commit fed4110565
3 changed files with 116 additions and 97 deletions

View File

@@ -30,10 +30,10 @@
"updatedAt": 1783653328367
},
"topic_20260710-032907_600adc6b00791607": {
"stage": 1,
"userTurns": 1,
"basisHash": "60a646e63a54c3bf",
"updatedAt": 1783669646165
"stage": 3,
"userTurns": 3,
"basisHash": "179afc4a827fe6eb",
"updatedAt": 1783671091019
},
"topic_20260710-034033_6432ee6566f7b432": {
"stage": 1,

View File

@@ -3,6 +3,7 @@ import {ref, computed, onBeforeUnmount, watch, nextTick} from "vue";
import { invoke } from "@tauri-apps/api/core";
import SettingsModal from "./SettingsModal.vue";
import TreeEntry from "./TreeEntry.vue";
import PromptDialog from "./PromptDialog.vue";
type SettingsPage = "about" | "editor";
type DocumentMode = "preview" | "edit" | "mixed";
@@ -524,6 +525,59 @@ function openSettings(page: SettingsPage) {
showSettings.value = true;
}
// ---- root create prompt ----
const promptShow = ref(false);
const promptTitle = ref("");
const promptMessage = ref("");
const promptPlaceholder = ref("");
const promptDefaultValue = ref("");
let promptCallback: ((value: string) => void) | null = null;
function openPrompt(
title: string,
message: string,
placeholder: string,
defaultValue: string,
cb: (value: string) => void,
) {
promptTitle.value = title;
promptMessage.value = message;
promptPlaceholder.value = placeholder;
promptDefaultValue.value = defaultValue;
promptCallback = cb;
promptShow.value = true;
}
function onPromptConfirm(value: string) {
promptShow.value = false;
promptCallback?.(value);
promptCallback = null;
}
function onPromptCancel() {
promptShow.value = false;
promptCallback = null;
}
function joinWorkspacePath(name: string) {
const base = props.folderPath.replace(/[\\/]+$/, "");
return `${base}/${name}`;
}
function handleCreateRootFolder() {
if (!props.folderPath) return;
openPrompt("新建文件夹", "", "输入文件夹名称", "", (name) => {
emit("createFolder", joinWorkspacePath(name));
});
}
function handleCreateRootFile() {
if (!props.folderPath) return;
openPrompt("新建 MD 文件", "", "输入文件名称(无需 .md 后缀)", "", (name) => {
emit("createFile", joinWorkspacePath(`${name}.md`));
});
}
</script>
@@ -568,10 +622,32 @@ function openSettings(page: SettingsPage) {
<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">
<!-- Tree toolbar -->
<div
v-if="folderPath"
class="tree-toolbar flex items-center gap-1 px-3 py-1.5"
>
<button
class="tree-toolbar-btn"
type="button"
title="新建文件夹"
@click="handleCreateRootFolder"
>
<i class="ri-folder-add-line"></i>
</button>
<button
class="tree-toolbar-btn"
type="button"
title="新建 MD 文件"
@click="handleCreateRootFile"
>
<i class="ri-file-add-line"></i>
</button>
</div>
<!-- File tree -->
<div
class="flex-1 overflow-y-auto px-2 py-2 flex flex-col gap-0.5"
@contextmenu.prevent
>
<TreeEntry
v-for="entry in entries"
@@ -872,6 +948,16 @@ function openSettings(page: SettingsPage) {
@update-app-theme="(theme: AppTheme) => emit('updateAppTheme', theme)"
/>
<PromptDialog
:show="promptShow"
:title="promptTitle"
:message="promptMessage"
:placeholder="promptPlaceholder"
:model-value="promptDefaultValue"
@confirm="onPromptConfirm"
@cancel="onPromptCancel"
/>
<Teleport to="body">
<div
v-if="showWorkspaceManager"
@@ -1079,6 +1165,31 @@ function openSettings(page: SettingsPage) {
color: var(--app-accent);
}
.tree-toolbar {
border-bottom: 1px solid var(--app-border);
background: color-mix(in srgb, var(--app-sidebar-bg) 88%, transparent);
}
.tree-toolbar-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border: none;
border-radius: 6px;
background: transparent;
color: var(--app-muted);
font-size: 16px;
cursor: pointer;
transition: background-color 0.15s ease, color 0.15s ease;
}
.tree-toolbar-btn:hover {
background: var(--app-hover);
color: var(--app-text);
}
.sidebar-search-input {
border: 1px solid var(--app-border-strong);
background: var(--app-hover);

View File

@@ -7,14 +7,6 @@ export default { name: "TreeEntry" };
import { computed, onBeforeUnmount, ref, watch } from "vue";
import ConfirmDialog from "./ConfirmDialog.vue";
import PromptDialog from "./PromptDialog.vue";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
interface DirEntry {
name: string;
@@ -305,40 +297,6 @@ function onContextMenu(event: MouseEvent) {
></i>
<i class="tree-entry-icon ri-folder-2-line text-base shrink-0"></i>
<span class="truncate flex-1 min-w-0">{{ entry.name }}</span>
<!-- More button + DropdownMenu -->
<DropdownMenu>
<DropdownMenuTrigger
class="tree-more-btn shrink-0 ml-auto opacity-0 group-hover:opacity-100 transition-opacity focus-visible:opacity-100"
title="更多操作"
@click.stop
>
<i class="ri-more-line"></i>
</DropdownMenuTrigger>
<DropdownMenuContent @click.stop>
<DropdownMenuGroup>
<DropdownMenuItem @click="handleCreateFolder">
<i class="ri-folder-add-line"></i>
<span>新建文件夹</span>
</DropdownMenuItem>
<DropdownMenuItem @click="handleCreateFile">
<i class="ri-file-add-line"></i>
<span>新建 MD 文件</span>
</DropdownMenuItem>
<DropdownMenuItem @click="handleRename">
<i class="ri-edit-line"></i>
<span>重命名</span>
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem variant="destructive" @click="handleDelete">
<i class="ri-delete-bin-line"></i>
<span>删除文件夹</span>
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</div>
<!-- Children (recursive) -->
@@ -375,32 +333,6 @@ function onContextMenu(event: MouseEvent) {
>
<i :class="['tree-entry-icon', fileIcon, 'text-sm shrink-0']"></i>
<span class="truncate flex-1 min-w-0">{{ entry.name }}</span>
<!-- More button + DropdownMenu -->
<DropdownMenu>
<DropdownMenuTrigger
class="tree-more-btn shrink-0 ml-auto opacity-0 group-hover:opacity-100 transition-opacity focus-visible:opacity-100"
title="更多操作"
@click.stop
>
<i class="ri-more-line"></i>
</DropdownMenuTrigger>
<DropdownMenuContent @click.stop>
<DropdownMenuGroup>
<DropdownMenuItem @click="handleRename">
<i class="ri-edit-line"></i>
<span>重命名</span>
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem variant="destructive" @click="handleDelete">
<i class="ri-delete-bin-line"></i>
<span>删除</span>
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</div>
</template>
@@ -435,30 +367,6 @@ function onContextMenu(event: MouseEvent) {
color: var(--app-accent);
}
/* ── More button ────────────────────────────── */
.tree-more-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
border: none;
border-radius: 4px;
background: transparent;
color: var(--app-muted);
font-size: 14px;
cursor: pointer;
transition:
background-color 0.12s ease,
color 0.12s ease;
flex-shrink: 0;
}
.tree-more-btn:hover {
background: var(--app-border);
color: var(--app-text);
}
.tree-context-menu {
position: fixed;
z-index: 100;