Files
estel_docs/app/pages/blog/[...slug].vue
2025-08-09 13:27:47 +08:00

251 lines
6.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import type { ContentNavigationItem } from '@nuxt/content'
import { findPageHeadline } from '#ui-pro/utils/content'
definePageMeta({
layout: 'blog'
})
const route = useRoute()
const appConfig = useAppConfig()
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
// 获取主题系统的字号设置
const { selectedFontSize } = useTheme()
// 计算页面内容的字号类
const pageFontSizeClass = computed(() => {
return `text-${selectedFontSize.value}`
})
// 根据路由参数构建内容路径
const path = computed(() => route.path)
// URL 解码并验证路径
const queryPath = computed(() => {
try {
return decodeURIComponent(path.value)
} catch (error) {
console.error('URL decode error:', error)
return path.value // 如果解码失败,返回原始路径
}
})
const { data: page } = await useAsyncData(
`page-${route.path}`, // 使用更具体的 key
() => queryCollection('blog').path(decodeURIComponent(path.value)).first(),
{
default: () => null // 提供默认值
}
)
if (!page.value) {
throw createError({
statusCode: 404,
statusMessage: '文档不存在',
message: `当前页面不存在,请您检查路径是否正确: ${queryPath.value}`,
fatal: true
})
}
const { data: surround } = await useAsyncData(`${route.path}-surround`, () => {
return queryCollectionItemSurroundings('docs', route.path, {
fields: ['description']
})
})
const title = page.value.seo?.title || page.value.title
const description = page.value.seo?.description || page.value.description
useSeoMeta({
title,
ogTitle: title,
description,
ogDescription: description
})
const headline = computed(() => findPageHeadline(navigation?.value, page.value))
defineOgImageComponent('Docs', {
headline: headline.value
})
const editLink = computed(() => {
if (!appConfig.github) {
return
}
return [
appConfig.github.url,
'edit',
appConfig.github.branch,
appConfig.github.rootDir,
'content',
`${page.value?.stem}.${page.value?.extension}`
].filter(Boolean).join('/')
})
const links = computed(() => {
const links = []
if (appConfig.toc?.bottom?.edit) {
links.push({
icon: 'lucide-external-link',
label: '编辑页面',
to: `${appConfig.toc.bottom.edit}/${page?.value?.stem}.${page?.value?.extension}`,
target: '_blank'
})
}
return [...links, ...(appConfig.toc?.bottom?.links || [])].filter(Boolean)
})
// ===== 微信分享(测试按钮用)=====
const wxShareActive = ref(false)
// const contentRoot = ref<HTMLElement | null>(null)
const shareLink = 'https://lijue.me' + decodeURIComponent(path.value)
const shareTitle = computed(() => title)
const shareDesc = computed(() => description || title)
const shareImg = page?.value?.img
// const shareImg = ref<string>('/images/default-blog.jpg')
// onMounted(() => {
// // 从正文中抓取第一张图片作为分享图
// const el = contentRoot.value
// const firstImg = el?.querySelector('img') as HTMLImageElement | null
// if (firstImg?.src) {
// shareImg.value = firstImg.src
// }
// })
// Toast点击测试分享后给出指引
const toast = useToast()
function handleShareClick() {
wxShareActive.value = true
toast.add({
title: '已获取分享接口',
description: '点击右上角分享吧',
duration: 3000,
icon: 'i-lucide-share-2'
})
}
</script>
<template>
<UPage
v-if="page"
:class="['lg:mr-30 lg:ml-5 sm:mt-6', pageFontSizeClass]"
>
<UPageHeader
:title="page.title"
:description="page.description"
:headline="headline"
:ui="{
wrapper: 'flex-row items-center flex-wrap justify-between '
}"
>
<template #links>
<UButton
v-for="(link, index) in page.links"
:key="index"
size="sm"
v-bind="link"
/>
<DocsPageHeaderLinks />
</template>
</UPageHeader>
<UPageBody>
<ContentRenderer
v-if="page"
:value="page"
/>
<USeparator>
<div
v-if="editLink"
class="flex items-center gap-2 text-sm text-muted"
>
<UButton
variant="link"
color="neutral"
:to="editLink"
target="_blank"
icon="lucide-pen"
:ui="{ leadingIcon: 'size-4' }"
>
编辑页面
</UButton>
or
<!-- <UButton
variant="link"
color="neutral"
:to="`${appConfig.github.url}/issues/new/choose`"
target="_blank"
icon="lucide-alert-circle"
:ui="{ leadingIcon: 'size-4' }"
>
提交问题
</UButton> -->
<UButton
variant="link"
color="neutral"
icon="lucide-share-2"
:ui="{ leadingIcon: 'size-4' }"
@click="handleShareClick()"
>
微信分享
</UButton>
</div>
</USeparator>
<UContentSurround :surround="surround" />
<!-- 激活后挂载分享组件无可视内容 -->
<SharedWxShare
v-if="wxShareActive"
:url="shareLink"
:title="shareTitle"
:desc="shareDesc"
:img-url="shareImg"
/>
</UPageBody>
<template
v-if="page?.body?.toc?.links?.length"
#right
>
<div class="">
<UContentToc
:title="appConfig.toc?.title"
:links="page.body?.toc?.links"
:ui="{
root: 'fixed w-full xl:right-12 xl:w-64 z-50 bg-white dark:bg-gray-900 lg:border border-gray-200 dark:border-gray-700 rounded-lg lg:shadow-lg lg:mt-5'
}"
>
<template
v-if="appConfig.toc?.bottom"
#bottom
>
<div
class=""
:class="{ '!mt-5': page.body?.toc?.links?.length }"
>
<USeparator
v-if="page.body?.toc?.links?.length"
type="dashed"
/>
<UPageLinks
:title="appConfig.toc.bottom.title"
:links="links"
/>
</div>
</template>
</UContentToc>
</div>
</template>
</UPage>
</template>