功能完善
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user