功能完善

This commit is contained in:
2026-07-08 11:08:33 +08:00
parent fc2d5ba6a2
commit 78352dd193
4 changed files with 54 additions and 125 deletions

View File

@@ -13,17 +13,14 @@ const props = withDefaults(
defineProps<{
folderPath: string;
entries: DirEntry[];
content?: string;
currentFilePath?: string | null;
}>(),
{
content: "",
currentFilePath: null,
},
);
const emit = defineEmits<{
headingClick: [heading: { text: string; level: number }];
openFolder: [];
toggleFolder: [path: string];
openFile: [path: string];
@@ -44,7 +41,7 @@ const rootEntry = computed<DirEntry | null>(() => {
});
// ---- sidebar view mode ----
type ViewMode = "folder" | "search" | "outline" | "setting";
type ViewMode = "folder" | "search" | "setting";
const activeView = ref<ViewMode>("folder");
const expanded = ref(true);
@@ -57,33 +54,6 @@ function switchView(view: ViewMode) {
}
}
// ---- outline state ----
interface OutlineItem {
text: string;
level: number;
id: string;
}
const headings = computed<OutlineItem[]>(() => {
if (!props.content) return [];
const result: OutlineItem[] = [];
const regex = /^(#{1,3})\s+(.+)$/gm;
let match: RegExpExecArray | null;
while ((match = regex.exec(props.content)) !== null) {
const level = match[1].length;
// Strip any remaining markdown formatting from the heading text
const text = match[2].replace(/\*{1,3}|_{1,3}|`+|~~|\[([^\]]*)\]\([^)]*\)/g, (_, linkText) => linkText || "").trim();
if (text) {
result.push({text, level, id: `heading-${result.length}`});
}
}
return result;
});
function onHeadingClick(item: OutlineItem) {
emit("headingClick", {text: item.text, level: item.level});
}
// ---- settings modal ----
const showSettings = ref(false);
</script>
@@ -112,15 +82,6 @@ const showSettings = ref(false);
>
<i class="ri-search-line text-base"></i>
</button>
<!-- Outline -->
<button
class="p-2 rounded-md transition-colors"
:class="activeView === 'outline' ? 'text-[#bf6a3b] bg-[#ede8de]' : 'text-[#b8b3a8] hover:text-[#5c574e] hover:bg-[#ede8de]'"
title="大纲"
@click="switchView('outline')"
>
<i class="ri-menu-line text-base"></i>
</button>
<!-- ===== Settings ===== -->
<button
class="p-2 rounded-md transition-colors mt-auto"
@@ -183,48 +144,6 @@ const showSettings = ref(false);
</p>
</div>
</div>
<!-- ===== OUTLINE VIEW ===== -->
<div v-if="activeView === 'outline'" class="flex-1 overflow-y-auto px-2 py-2">
<template v-if="!currentFilePath">
<p class="text-xs text-[#b8b3a8] px-2 py-4 text-center leading-relaxed">
暂无打开的文件
</p>
</template>
<template v-else-if="headings.length === 0">
<p class="text-xs text-[#b8b3a8] px-2 py-4 text-center leading-relaxed">
暂无标题<br/>使用 H1-H3 标题<br/>自动生成大纲
</p>
</template>
<template v-else>
<div
v-for="item in headings"
:key="item.id"
:class="[
'px-2 py-1 rounded-md text-sm cursor-pointer hover:bg-[#ede8de] transition-colors truncate',
item.level === 1
? 'text-[#38342e] font-medium ml-0'
: item.level === 2
? 'text-[#8c877d] ml-3'
: 'text-[#b8b3a8] ml-6 text-xs',
]"
:title="item.text"
@click="onHeadingClick(item)"
>
<span
:class="[
'inline-block w-1.5 h-1.5 rounded-full mr-1.5 align-middle',
item.level === 1
? 'bg-[#bf6a3b]'
: item.level === 2
? 'bg-[#7ba587]/60'
: 'bg-gray-500',
]"
/>
{{ item.text }}
</div>
</template>
</div>
</div>
</aside>