diff --git a/components/static/Detail.vue b/components/static/Detail.vue index 9d77a006..04414926 100644 --- a/components/static/Detail.vue +++ b/components/static/Detail.vue @@ -32,6 +32,8 @@ import { useServerAssets } from "~/plugins/renderer/useServerAssets" import { useAuthModeFetch } from "~/composables/useAuthModeFetch" import { useProviderMode } from "~/composables/useProviderMode" import Sidebar from "~/components/static/Sidebar.vue" +import Outline from "~/components/static/Outline.vue" +import { type TreeNode, TreeUtils } from "~/utils/TreeUtils" // https://github.com/nuxt/nuxt/issues/15346 // 由于布局是个宏,静态构建情况下,不能动态设置,只能在前面的页面写死 @@ -61,36 +63,13 @@ const formData = reactive({ isExpires: false, // 文档树 - items: [ - { id: "1", name: "首页", children: [] }, - { - id: "2", - name: "产品", - children: [ - { id: "3", name: "产品A", content: "这是产品A的内容" }, - { - id: "4", - name: "产品B", - children: [ - { id: "5", name: "产品B1", content: "这是产品B1的内容" }, - { id: "6", name: "产品B2", content: "这是产品B2的内容" }, - ], - }, - ], - }, - { - id: "7", - name: "关于我们", - children: [ - { id: "8", name: "公司简介", content: "这是公司的简介" }, - { id: "9", name: "联系方式", content: "这是联系方式" }, - ], - }, - ], - defaultOpen: "8", + items: [], + defaultOpen: id, maxDepth: 3, openItems: [], selectedItem: {}, + + outlineItems: [], }) const onItemSelected = (item: any) => { @@ -128,15 +107,44 @@ if (!props.overrideSeo) { } useSeoMeta(seoMeta) } +const editorDom = formData.post.editorDom?.replaceAll('contenteditable="true"', 'contenteditable="false"') ?? "" + +const parseOutline = (content: string, depth = 1): any[] => { + const headings = [] + + const items: any[] = [] + headings.forEach((heading) => { + const id = heading.id || heading.textContent?.trim().toLowerCase().replace(/\s+/g, "-") || "" + items.push({ id, title: heading.textContent || "", depth }) + }) + + return items +} + +const contentRef = ref(null) + +const scrollToSection = (id: string) => { + if (contentRef.value) { + const section = contentRef.value.querySelector(`#${id}`) + if (section) { + section.scrollIntoView({ behavior: "smooth" }) + } + } +} onMounted(async () => { + formData.items = TreeUtils.buildTree(formData.post.docTree ?? []) formData.openItems.push(formData.defaultOpen) + // formData.outlineItems = parseOutline(editorDom) + + console.log("formData.items", formData.items) + console.log("formData.openItems", formData.openItems) }) const VNode = () => h("div", { class: "", - innerHTML: formData.post.editorDom?.replaceAll('contenteditable="true"', 'contenteditable="false"') ?? "", + innerHTML: editorDom, }) @@ -145,7 +153,7 @@ const VNode = () => -
+
@item-selected="onItemSelected" /> -
-
-
-
- {{ formData.post.title }} +
+
+ +
+
+
+
+
+
+ {{ formData.post.title }} +
+
+
+ +
-
- -
- + diff --git a/components/static/Outline.vue b/components/static/Outline.vue new file mode 100644 index 00000000..ec8f874f --- /dev/null +++ b/components/static/Outline.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/components/static/Sidebar.vue b/components/static/Sidebar.vue index 8955fb41..8c98aef2 100644 --- a/components/static/Sidebar.vue +++ b/components/static/Sidebar.vue @@ -1,7 +1,14 @@