mirror of
https://github.com/pengzhanbo/vuepress-theme-plume.git
synced 2026-04-23 10:58:13 +08:00
fix(theme): 修复最后更新时间不一致导致的SSR水合过程错误
This commit is contained in:
parent
805374de71
commit
e3f79a8db6
@ -34,42 +34,38 @@ onContentUpdated(() => zoom?.refresh())
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="plume-page" :class="{
|
||||
'has-sidebar': hasSidebar,
|
||||
'has-aside': hasAside,
|
||||
'is-blog': page.isBlogPost,
|
||||
'with-encrypt': !isPageDecrypted,
|
||||
}"
|
||||
>
|
||||
<div class="container">
|
||||
<TransitionFadeSlideY>
|
||||
<div v-if="enableAside" :key="page.path" class="aside">
|
||||
<TransitionFadeSlideY>
|
||||
<div
|
||||
:key="page.path" class="plume-page" :class="{
|
||||
'has-sidebar': hasSidebar,
|
||||
'has-aside': hasAside,
|
||||
'is-blog': page.isBlogPost,
|
||||
'with-encrypt': !isPageDecrypted,
|
||||
}"
|
||||
>
|
||||
<div class="container">
|
||||
<div v-if="enableAside" class="aside">
|
||||
<div class="aside-container">
|
||||
<div class="aside-content">
|
||||
<PageAside />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</TransitionFadeSlideY>
|
||||
<div class="content">
|
||||
<div class="content-container">
|
||||
<TransitionFadeSlideY>
|
||||
<main :key="page.path" class="main">
|
||||
<PageMeta />
|
||||
<EncryptPage v-if="!isPageDecrypted" />
|
||||
<template v-else>
|
||||
<Content class="plume-content" />
|
||||
<div class="content">
|
||||
<div class="content-container">
|
||||
<PageMeta />
|
||||
<EncryptPage v-if="!isPageDecrypted" />
|
||||
<template v-else>
|
||||
<Content class="plume-content" />
|
||||
|
||||
<PageFooter />
|
||||
<PageComment v-if="hasComments" :darkmode="isDark" />
|
||||
</template>
|
||||
</main>
|
||||
</TransitionFadeSlideY>
|
||||
<PageFooter />
|
||||
<PageComment v-if="hasComments" :darkmode="isDark" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</TransitionFadeSlideY>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@ -12,7 +12,7 @@ import IconEdit from './icons/IconEdit.vue'
|
||||
|
||||
const themeLocale = useThemeLocaleData()
|
||||
const editNavLink = useEditNavLink()
|
||||
const lastUpdated = useLastUpdated()
|
||||
const { datetime: lastUpdated, isoDatetime, lastUpdatedText } = useLastUpdated()
|
||||
const contributors = useContributors()
|
||||
const { prev, next } = usePageNav()
|
||||
|
||||
@ -25,11 +25,7 @@ const showFooter = computed(() => {
|
||||
<footer v-if="showFooter" class="page-footer">
|
||||
<div v-if="editNavLink || lastUpdated" class="edit-info">
|
||||
<div v-if="editNavLink" class="edit-link">
|
||||
<AutoLink
|
||||
class="edit-link-button"
|
||||
:href="editNavLink.link"
|
||||
:no-icon="true"
|
||||
>
|
||||
<AutoLink class="edit-link-button" :href="editNavLink.link" :no-icon="true">
|
||||
<IconEdit class="edit-link-icon" aria-label="edit icon" />
|
||||
{{ editNavLink.text }}
|
||||
</AutoLink>
|
||||
@ -37,8 +33,8 @@ const showFooter = computed(() => {
|
||||
|
||||
<div v-if="lastUpdated" class="last-updated">
|
||||
<p class="last-updated-text">
|
||||
{{ themeLocale.lastUpdatedText || 'Last updated' }}:
|
||||
<time :datetime="lastUpdated" class="last-updated-time">
|
||||
{{ lastUpdatedText }}:
|
||||
<time :datetime="isoDatetime" class="last-updated-time">
|
||||
{{ lastUpdated }}
|
||||
</time>
|
||||
</p>
|
||||
@ -61,21 +57,13 @@ const showFooter = computed(() => {
|
||||
|
||||
<nav v-if="prev?.link || next?.link" class="prev-next">
|
||||
<div class="pager">
|
||||
<AutoLink
|
||||
v-if="prev?.link"
|
||||
class="pager-link prev"
|
||||
:href="prev.link"
|
||||
>
|
||||
<AutoLink v-if="prev?.link" class="pager-link prev" :href="prev.link">
|
||||
<span class="desc" v-html="themeLocale.prevPageLabel || 'Previous page'" />
|
||||
<span class="title" v-html="prev.text" />
|
||||
</AutoLink>
|
||||
</div>
|
||||
<div class="pager">
|
||||
<AutoLink
|
||||
v-if="next?.link"
|
||||
class="pager-link next"
|
||||
:href="next.link"
|
||||
>
|
||||
<AutoLink v-if="next?.link" class="pager-link next" :href="next.link">
|
||||
<span class="desc" v-html="themeLocale.nextPageLabel || 'Next page'" />
|
||||
<span class="title" v-html="next.text" />
|
||||
</AutoLink>
|
||||
|
||||
@ -2,7 +2,7 @@ import { usePageData, usePageFrontmatter, usePageLang, useRoute } from 'vuepress
|
||||
import { isPlainObject, isString } from 'vuepress/shared'
|
||||
import { useBlogPostData } from '@vuepress-plume/plugin-blog-data/client'
|
||||
import type { NotesSidebarItem } from '@vuepress-plume/plugin-notes-data'
|
||||
import { computed } from 'vue'
|
||||
import { computed, onMounted, ref, watchEffect } from 'vue'
|
||||
import type { ComputedRef, Ref } from 'vue'
|
||||
import type {
|
||||
NavItemWithLink,
|
||||
@ -54,25 +54,43 @@ export function useEditNavLink(): ComputedRef<null | NavItemWithLink> {
|
||||
})
|
||||
}
|
||||
|
||||
export function useLastUpdated(): ComputedRef<null | string> {
|
||||
const themeLocale = useThemeLocaleData()
|
||||
export function useLastUpdated() {
|
||||
const theme = useThemeLocaleData()
|
||||
const page = usePageData<PlumeThemePageData>()
|
||||
const frontmatter = usePageFrontmatter<PlumeThemePageFrontmatter>()
|
||||
const lang = usePageLang()
|
||||
|
||||
return computed(() => {
|
||||
const showLastUpdated
|
||||
= frontmatter.value.lastUpdated ?? themeLocale.value.lastUpdated ?? true
|
||||
const date = computed(() => new Date(page.value.git?.updatedTime ?? ''))
|
||||
const isoDatetime = computed(() => date.value.toISOString())
|
||||
|
||||
if (!showLastUpdated)
|
||||
return null
|
||||
const datetime = ref('')
|
||||
|
||||
if (!page.value.git?.updatedTime)
|
||||
return null
|
||||
|
||||
const updatedDate = new Date(page.value.git?.updatedTime)
|
||||
|
||||
return updatedDate.toLocaleString()
|
||||
const lastUpdatedText = computed(() => {
|
||||
if (theme.value.lastUpdated === false)
|
||||
return
|
||||
return theme.value.lastUpdated?.text || theme.value.lastUpdatedText || 'Last updated'
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
watchEffect(() => {
|
||||
if (frontmatter.value.lastUpdated === false || theme.value.lastUpdated === false)
|
||||
return
|
||||
|
||||
datetime.value = new Intl.DateTimeFormat(
|
||||
theme.value.lastUpdated?.formatOptions?.forceLocale ? lang.value : undefined,
|
||||
theme.value.lastUpdated?.formatOptions ?? {
|
||||
dateStyle: 'short',
|
||||
timeStyle: 'short',
|
||||
},
|
||||
).format(date.value)
|
||||
})
|
||||
})
|
||||
|
||||
return {
|
||||
datetime,
|
||||
isoDatetime,
|
||||
lastUpdatedText,
|
||||
}
|
||||
}
|
||||
|
||||
export function useContributors(): ComputedRef<
|
||||
|
||||
@ -9,10 +9,13 @@ const defaultLocales: NonNullable<PlumeThemeLocaleOptions['locales']> = {
|
||||
selectLanguageName: 'English',
|
||||
selectLanguageText: 'Languages',
|
||||
editLinkText: 'Edit this page',
|
||||
lastUpdatedText: 'Last Updated',
|
||||
contributorsText: 'Contributors',
|
||||
appearanceText: 'Appearance',
|
||||
|
||||
lastUpdated: {
|
||||
text: 'Last Updated',
|
||||
},
|
||||
|
||||
encryptButtonText: 'Confirm',
|
||||
encryptPlaceholder: 'Enter password',
|
||||
encryptGlobalText: 'Only password can access this site',
|
||||
@ -28,11 +31,14 @@ const defaultLocales: NonNullable<PlumeThemeLocaleOptions['locales']> = {
|
||||
returnToTopLabel: '返回顶部',
|
||||
editLinkText: '编辑此页',
|
||||
contributorsText: '贡献者',
|
||||
lastUpdatedText: '上次更新',
|
||||
appearanceText: '外观',
|
||||
prevPageLabel: '上一页',
|
||||
nextPageLabel: '下一页',
|
||||
|
||||
lastUpdated: {
|
||||
text: '最后更新于',
|
||||
},
|
||||
|
||||
notFound: {
|
||||
code: '404',
|
||||
title: '页面未找到',
|
||||
@ -54,7 +60,6 @@ export const fallbackLocaleOption: Partial<PlumeThemeLocaleOptions> = {
|
||||
navbarSocialInclude: ['github', 'twitter', 'discord', 'facebook'],
|
||||
// page meta
|
||||
editLink: true,
|
||||
lastUpdated: true,
|
||||
contributors: true,
|
||||
footer: {
|
||||
message:
|
||||
|
||||
@ -151,6 +151,24 @@ export interface PlumeThemeEncrypt {
|
||||
}
|
||||
}
|
||||
|
||||
export interface LastUpdatedOptions {
|
||||
/**
|
||||
* Set custom last updated text.
|
||||
*
|
||||
* @default 'Last updated'
|
||||
*/
|
||||
text?: string
|
||||
|
||||
/**
|
||||
* Set options for last updated time formatting.
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat#using_options
|
||||
*
|
||||
* @default
|
||||
* { dateStyle: 'short', timeStyle: 'short' }
|
||||
*/
|
||||
formatOptions?: Intl.DateTimeFormatOptions & { forceLocale?: boolean }
|
||||
}
|
||||
|
||||
export interface PlumeThemeLocaleData extends LocaleData {
|
||||
/**
|
||||
* 网站站点首页
|
||||
@ -294,12 +312,14 @@ export interface PlumeThemeLocaleData extends LocaleData {
|
||||
*
|
||||
* Whether to show "Last Updated" or not
|
||||
*/
|
||||
lastUpdated?: boolean
|
||||
lastUpdated?: false | LastUpdatedOptions
|
||||
|
||||
/**
|
||||
* Page meta - last updated config
|
||||
* @deprecated Use `lastUpdated.text` instead.
|
||||
*
|
||||
* The text to replace the default "Last Updated"
|
||||
* Set custom last updated text.
|
||||
*
|
||||
* @default 'Last updated'
|
||||
*/
|
||||
lastUpdatedText?: string
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user