优化功能
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user