feat(theme): support encryption for all page layouts (#770)

This commit is contained in:
pengzhanbo 2025-12-03 13:25:16 +08:00 committed by GitHub
parent 4957c8b1de
commit 20ebeb5e62
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 145 additions and 135 deletions

View File

@ -8,6 +8,7 @@ import VPHomeHero from '@theme/Home/VPHomeHero.vue'
import VPHomeProfile from '@theme/Home/VPHomeProfile.vue' import VPHomeProfile from '@theme/Home/VPHomeProfile.vue'
import VPHomeTextImage from '@theme/Home/VPHomeTextImage.vue' import VPHomeTextImage from '@theme/Home/VPHomeTextImage.vue'
import VPPosts from '@theme/Posts/VPPosts.vue' import VPPosts from '@theme/Posts/VPPosts.vue'
import VPEncrypt from '@theme/VPEncrypt.vue'
import { computed, h, nextTick, onUnmounted, resolveComponent, watch } from 'vue' import { computed, h, nextTick, onUnmounted, resolveComponent, watch } from 'vue'
import { useData } from '../../composables/index.js' import { useData } from '../../composables/index.js'
@ -96,19 +97,21 @@ onUnmounted(() => {
<template> <template>
<div class="vp-home"> <div class="vp-home">
<template <VPEncrypt>
v-for="(item, index) in config" <template
:key="item.type + index" v-for="(item, index) in config"
> :key="item.type + index"
<div :class="{ layout: index > 0 && item.type !== 'features' && item.type !== 'custom' }"> >
<component <div :class="{ layout: index > 0 && item.type !== 'features' && item.type !== 'custom' }">
:is="resolveComponentName(item.type)" <component
v-bind="item" :is="resolveComponentName(item.type)"
:index="index" v-bind="item"
:only-once="onlyOnce" :index="index"
/> :only-once="onlyOnce"
</div> />
</template> </div>
</template>
</VPEncrypt>
</div> </div>
</template> </template>

View File

@ -6,6 +6,7 @@ import VPPostsCategories from '@theme/Posts/VPPostsCategories.vue'
import VPPostsExtract from '@theme/Posts/VPPostsExtract.vue' import VPPostsExtract from '@theme/Posts/VPPostsExtract.vue'
import VPPostsNav from '@theme/Posts/VPPostsNav.vue' import VPPostsNav from '@theme/Posts/VPPostsNav.vue'
import VPPostsTags from '@theme/Posts/VPPostsTags.vue' import VPPostsTags from '@theme/Posts/VPPostsTags.vue'
import VPEncrypt from '@theme/VPEncrypt.vue'
import VPTransitionFadeSlideY from '@theme/VPTransitionFadeSlideY.vue' import VPTransitionFadeSlideY from '@theme/VPTransitionFadeSlideY.vue'
import { onBeforeUnmount, watch } from 'vue' import { onBeforeUnmount, watch } from 'vue'
import { forceUpdateCollection, useData } from '../../composables/index.js' import { forceUpdateCollection, useData } from '../../composables/index.js'
@ -30,80 +31,82 @@ onBeforeUnmount(() => forceUpdateCollection(undefined))
<template> <template>
<div class="vp-posts" :class="{ 'home-posts': homePosts }" vp-posts> <div class="vp-posts" :class="{ 'home-posts': homePosts }" vp-posts>
<slot name="posts-top" /> <VPEncrypt>
<slot name="posts-top" />
<div <div
class="posts-container" class="posts-container"
:class="{ 'no-profile': !theme.profile, 'left': theme.profile?.layout === 'left' }" :class="{ 'no-profile': !theme.profile, 'left': theme.profile?.layout === 'left' }"
> >
<VPPostsNav v-if="!theme.profile" is-local /> <VPPostsNav v-if="!theme.profile" is-local />
<VPTransitionFadeSlideY> <VPTransitionFadeSlideY>
<VPPostsArchives v-if="page.type === 'posts-archives'"> <VPPostsArchives v-if="page.type === 'posts-archives'">
<template #posts-archives-before> <template #posts-archives-before>
<slot name="posts-archives-before" /> <slot name="posts-archives-before" />
</template> </template>
<template #posts-archives-after> <template #posts-archives-after>
<slot name="posts-archives-after" /> <slot name="posts-archives-after" />
</template> </template>
</VPPostsArchives> </VPPostsArchives>
<VPPostsTags v-else-if="page.type === 'posts-tags'"> <VPPostsTags v-else-if="page.type === 'posts-tags'">
<template #posts-tags-before> <template #posts-tags-before>
<slot name="posts-tags-before" /> <slot name="posts-tags-before" />
</template> </template>
<template #posts-tags-after> <template #posts-tags-after>
<slot name="posts-tags-after" /> <slot name="posts-tags-after" />
</template> </template>
<template #posts-tags-title-after> <template #posts-tags-title-after>
<slot name="posts-tags-title-after" /> <slot name="posts-tags-title-after" />
</template> </template>
<template #posts-tags-content-before> <template #posts-tags-content-before>
<slot name="posts-tags-content-before" /> <slot name="posts-tags-content-before" />
</template> </template>
</VPPostsTags> </VPPostsTags>
<VPPostsCategories v-else-if="page.type === 'posts-categories'"> <VPPostsCategories v-else-if="page.type === 'posts-categories'">
<template #posts-categories-before> <template #posts-categories-before>
<slot name="posts-categories-before" /> <slot name="posts-categories-before" />
</template> </template>
<template #posts-categories-after> <template #posts-categories-after>
<slot name="posts-categories-after" /> <slot name="posts-categories-after" />
</template> </template>
<template #posts-categories-content-before> <template #posts-categories-content-before>
<slot name="posts-categories-content-before" /> <slot name="posts-categories-content-before" />
</template> </template>
</VPPostsCategories> </VPPostsCategories>
<VPPostList v-else :home-posts="homePosts"> <VPPostList v-else :home-posts="homePosts">
<template #posts-post-list-before> <template #posts-post-list-before>
<slot name="posts-post-list-before" /> <slot name="posts-post-list-before" />
</template> </template>
<template #posts-post-list-after> <template #posts-post-list-after>
<slot name="posts-post-list-after" /> <slot name="posts-post-list-after" />
</template> </template>
<template #posts-post-list-pagination-after> <template #posts-post-list-pagination-after>
<slot name="posts-post-list-pagination-after" /> <slot name="posts-post-list-pagination-after" />
</template> </template>
</VPPostList> </VPPostList>
</VPTransitionFadeSlideY> </VPTransitionFadeSlideY>
<VPPostsAside> <VPPostsAside>
<template #posts-aside-top> <template #posts-aside-top>
<slot name="posts-aside-top" /> <slot name="posts-aside-top" />
</template> </template>
<template #posts-aside-bottom> <template #posts-aside-bottom>
<slot name="posts-aside-bottom" /> <slot name="posts-aside-bottom" />
</template> </template>
</VPPostsAside> </VPPostsAside>
<VPPostsExtract> <VPPostsExtract>
<template #posts-extract-before> <template #posts-extract-before>
<slot name="posts-extract-before" /> <slot name="posts-extract-before" />
</template> </template>
<template #posts-extract-after> <template #posts-extract-after>
<slot name="posts-extract-after" /> <slot name="posts-extract-after" />
</template> </template>
</VPPostsExtract> </VPPostsExtract>
</div> </div>
<slot name="posts-bottom" /> <slot name="posts-bottom" />
</VPEncrypt>
</div> </div>
</template> </template>

View File

@ -5,7 +5,7 @@ import VPDocBreadcrumbs from '@theme/VPDocBreadcrumbs.vue'
import VPDocCopyright from '@theme/VPDocCopyright.vue' import VPDocCopyright from '@theme/VPDocCopyright.vue'
import VPDocFooter from '@theme/VPDocFooter.vue' import VPDocFooter from '@theme/VPDocFooter.vue'
import VPDocMeta from '@theme/VPDocMeta.vue' import VPDocMeta from '@theme/VPDocMeta.vue'
import VPEncryptPage from '@theme/VPEncryptPage.vue' import VPEncrypt from '@theme/VPEncrypt.vue'
import VPTransitionFadeSlideY from '@theme/VPTransitionFadeSlideY.vue' import VPTransitionFadeSlideY from '@theme/VPTransitionFadeSlideY.vue'
import { computed, nextTick, ref, watch } from 'vue' import { computed, nextTick, ref, watch } from 'vue'
import { useRoute } from 'vuepress/client' import { useRoute } from 'vuepress/client'
@ -137,25 +137,27 @@ watch(
</VPDocMeta> </VPDocMeta>
<slot name="doc-meta-bottom" /> <slot name="doc-meta-bottom" />
<VPEncryptPage v-if="!isPageDecrypted" /> <VPEncrypt>
<div <div
v-else class="vp-doc plume-content" class="vp-doc plume-content"
:class="[pageName, enabledExternalLinkIcon && 'external-link-icon-enabled']" vp-content :class="[pageName, enabledExternalLinkIcon && 'external-link-icon-enabled']" vp-content
> >
<slot name="doc-content-before" /> <slot name="doc-content-before" />
<Content /> <Content />
<DocGitContributors v-if="contributorsMode === 'block'" /> <DocGitContributors v-if="contributorsMode === 'block'" />
<DocGitChangelog /> <DocGitChangelog />
<VPDocCopyright /> <VPDocCopyright />
</div>
<VPDocFooter>
<template #doc-footer-before>
<slot name="doc-footer-before" />
</template>
</VPDocFooter>
</div>
</VPEncrypt>
</main> </main>
<VPDocFooter v-if="isPageDecrypted">
<template #doc-footer-before>
<slot name="doc-footer-before" />
</template>
</VPDocFooter>
<VPComment /> <VPComment />

View File

@ -1,12 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import VPEncryptForm from '@theme/VPEncryptForm.vue' import VPEncryptForm from '@theme/VPEncryptForm.vue'
import { useTemplateRef } from 'vue' import { useTemplateRef } from 'vue'
import { useData } from '../composables/index.js' import { useData, useEncrypt } from '../composables/index.js'
defineOptions({ defineOptions({
inheritAttrs: false, inheritAttrs: false,
}) })
const { isPageDecrypted } = useEncrypt()
const { theme, frontmatter } = useData<'post'>() const { theme, frontmatter } = useData<'post'>()
const el = useTemplateRef<HTMLElement>('el') const el = useTemplateRef<HTMLElement>('el')
@ -21,7 +23,7 @@ function onValidate(isValidate: boolean) {
</script> </script>
<template> <template>
<ClientOnly> <ClientOnly v-if="!isPageDecrypted">
<div ref="el" class="vp-page-encrypt" v-bind="$attrs"> <div ref="el" class="vp-page-encrypt" v-bind="$attrs">
<div class="logo"> <div class="logo">
<span class="vpi-lock icon-lock-head" /> <span class="vpi-lock icon-lock-head" />
@ -29,6 +31,7 @@ function onValidate(isValidate: boolean) {
<VPEncryptForm :info="frontmatter.passwordHint || theme.encryptPageText" @validate="onValidate" /> <VPEncryptForm :info="frontmatter.passwordHint || theme.encryptPageText" @validate="onValidate" />
</div> </div>
</ClientOnly> </ClientOnly>
<slot v-else />
</template> </template>
<style scoped> <style scoped>

View File

@ -1,5 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import VPComment from '@theme/VPComment.vue' import VPComment from '@theme/VPComment.vue'
import VPEncrypt from '@theme/VPEncrypt.vue'
import VPFriendsGroup from '@theme/VPFriendsGroup.vue' import VPFriendsGroup from '@theme/VPFriendsGroup.vue'
import VPFriendsItem from '@theme/VPFriendsItem.vue' import VPFriendsItem from '@theme/VPFriendsItem.vue'
import VPLink from '@theme/VPLink.vue' import VPLink from '@theme/VPLink.vue'
@ -15,36 +16,38 @@ const groups = computed(() => matter.value.groups || [])
<template> <template>
<div class="vp-friends"> <div class="vp-friends">
<Content v-if="matter.contentPosition === 'before'" class="vp-doc plume-content before" vp-content /> <VPEncrypt>
<Content v-if="matter.contentPosition === 'before'" class="vp-doc plume-content before" vp-content />
<h2 class="title"> <h2 class="title">
{{ matter.title || 'My Friends' }} {{ matter.title || 'My Friends' }}
</h2> </h2>
<p v-if="matter.description && !page.autoDesc" class="description"> <p v-if="matter.description && !page.autoDesc" class="description">
{{ matter.description }} {{ matter.description }}
</p> </p>
<section v-if="list.length" class="friends-list"> <section v-if="list.length" class="friends-list">
<VPFriendsItem <VPFriendsItem
v-for="(friend, index) in list" v-for="(friend, index) in list"
:key="friend.name + index" :key="friend.name + index"
:friend="friend" :friend="friend"
/> />
</section> </section>
<VPFriendsGroup v-for="(group, index) in groups" :key="index" :group="group" /> <VPFriendsGroup v-for="(group, index) in groups" :key="index" :group="group" />
<Content v-if="matter.contentPosition !== 'before'" class="vp-doc plume-content after" vp-content /> <Content v-if="matter.contentPosition !== 'before'" class="vp-doc plume-content after" vp-content />
<div v-if="editLink" class="edit-link"> <div v-if="editLink" class="edit-link">
<VPLink <VPLink
class="edit-link-button" class="edit-link-button"
:href="editLink.link" :href="editLink.link"
no-icon no-icon
> >
<span class="vpi-square-pen edit-link-icon" aria-label="edit icon" /> <span class="vpi-square-pen edit-link-icon" aria-label="edit icon" />
{{ editLink.text }} {{ editLink.text }}
</VPLink> </VPLink>
</div> </div>
</VPEncrypt>
<VPComment /> <VPComment />
</div> </div>

View File

@ -1,17 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
import VPEncryptPage from '@theme/VPEncryptPage.vue' import VPEncrypt from '@theme/VPEncrypt.vue'
import { useEncrypt } from '../composables/index.js'
const { isPageDecrypted } = useEncrypt()
</script> </script>
<template> <template>
<div class="vp-page"> <div class="vp-page">
<VPEncryptPage v-if="!isPageDecrypted" /> <VPEncrypt>
<template v-else>
<slot name="page-top" /> <slot name="page-top" />
<Content class="vp-doc plume-content" vp-content /> <Content class="vp-doc plume-content" vp-content />
<slot name="page-bottom" /> <slot name="page-bottom" />
</template> </VPEncrypt>
</div> </div>
</template> </template>