feat(theme): add support blog as home page

This commit is contained in:
pengzhanbo 2024-09-03 11:19:02 +08:00
parent ccbfc16db5
commit f60e4ea63e
12 changed files with 113 additions and 25 deletions

View File

@ -104,11 +104,11 @@
"local-pkg": "^0.5.0",
"nanoid": "^5.0.7",
"vue": "^3.4.38",
"vue-router": "^4.4.3",
"vuepress-plugin-md-enhance": "2.0.0-rc.52",
"vuepress-plugin-md-power": "workspace:*"
},
"devDependencies": {
"@iconify/json": "^2.2.243"
"@iconify/json": "^2.2.243",
"vue-router": "^4.4.3"
}
}

View File

@ -9,11 +9,17 @@ import VPBlogNav from '@theme/Blog/VPBlogNav.vue'
import VPTransitionFadeSlideY from '@theme/VPTransitionFadeSlideY.vue'
import { useData } from '../../composables/index.js'
defineProps<{
homeBlog?: boolean
type?: string
onlyOnce?: boolean
}>()
const { theme, page } = useData()
</script>
<template>
<div class="vp-blog">
<div class="vp-blog" :class="{ 'home-blog': homeBlog }">
<slot name="blog-top" />
<div class="blog-container" :class="{ 'no-profile': !theme.profile }">
@ -53,7 +59,7 @@ const { theme, page } = useData()
<slot name="blog-categories-content-before" />
</template>
</VPBlogCategories>
<VPPostList v-else>
<VPPostList v-else :home-blog="homeBlog">
<template #blog-post-list-before>
<slot name="blog-post-list-before" />
</template>
@ -96,6 +102,12 @@ const { theme, page } = useData()
transition: background-color var(--t-color);
}
@media(min-width: 419px) {
.vp-blog.home-blog {
background-color: var(--vp-c-bg-alt);
}
}
.blog-container {
display: flex;
align-items: flex-start;

View File

@ -1,9 +1,14 @@
<script lang="ts" setup>
import { computed } from 'vue'
import VPTransitionDrop from '@theme/VPTransitionDrop.vue'
import VPPostItem from '@theme/Blog/VPPostItem.vue'
import VPPagination from '@theme/Blog/VPPagination.vue'
import { usePostListControl } from '../../composables/index.js'
const props = defineProps<{
homeBlog?: boolean
}>()
const {
postList,
page,
@ -13,7 +18,7 @@ const {
isFirstPage,
isPaginationEnabled,
changePage,
} = usePostListControl()
} = usePostListControl(computed(() => !!props.homeBlog))
</script>
<template>

View File

@ -1,13 +1,33 @@
<script lang="ts" setup>
import { type Component, computed, nextTick, onUnmounted, resolveComponent, watch } from 'vue'
import type { Component } from 'vue'
import { computed, h, nextTick, onUnmounted, resolveComponent, watch } from 'vue'
import VPHomeBanner from '@theme/Home/VPHomeBanner.vue'
import VPHomeHero from '@theme/Home/VPHomeHero.vue'
import VPHomeFeatures from '@theme/Home/VPHomeFeatures.vue'
import VPHomeTextImage from '@theme/Home/VPHomeTextImage.vue'
import VPHomeProfile from '@theme/Home/VPHomeProfile.vue'
import VPHomeCustom from '@theme/Home/VPHomeCustom.vue'
import VPBlog from '@theme/Blog/VPBlog.vue'
import { useData } from '../../composables/index.js'
const slots = defineSlots<{
'blog-top': () => any
'blog-bottom': () => any
'blog-post-list-before': () => any
'blog-post-list-after': () => any
'blog-post-list-pagination-after': () => any
}>()
function VPHomeBlog() {
return h(VPBlog, { homeBlog: true }, {
'blog-top': () => slots['blog-top']?.(),
'blog-bottom': () => slots['blog-bottom']?.(),
'blog-post-list-before': () => slots['blog-post-list-before']?.(),
'blog-post-list-after': () => slots['blog-post-list-after']?.(),
'blog-post-list-pagination-after': () => slots['blog-post-list-pagination-after']?.(),
})
}
const components: Record<string, Component<any, any, any>> = {
'banner': VPHomeBanner,
'hero': VPHomeHero,
@ -15,6 +35,7 @@ const components: Record<string, Component<any, any, any>> = {
'text-image': VPHomeTextImage,
'image-text': VPHomeTextImage,
'profile': VPHomeProfile,
'blog': VPHomeBlog,
'custom': VPHomeCustom,
}

View File

@ -99,7 +99,23 @@ watch([isBlogLayout, () => frontmatter.value.pageLayout], () => nextTick(() =>
<VPFriends v-else-if="frontmatter.pageLayout === 'friends'" />
<VPHome v-else-if="frontmatter.pageLayout === 'home'" />
<VPHome v-else-if="frontmatter.pageLayout === 'home'">
<template #blog-top>
<slot name="blog-top" />
</template>
<template #blog-bottom>
<slot name="blog-bottom" />
</template>
<template #blog-post-list-before>
<slot name="blog-post-list-before" />
</template>
<template #blog-post-list-after>
<slot name="blog-post-list-after" />
</template>
<template #blog-post-list-pagination-after>
<slot name="blog-post-list-pagination-after" />
</template>
</VPHome>
<component :is="frontmatter.pageLayout" v-else-if="frontmatter.pageLayout && frontmatter.pageLayout !== 'doc'" />

View File

@ -1,4 +1,4 @@
import { computed } from 'vue'
import { type Ref, computed } from 'vue'
import { useMediaQuery } from '@vueuse/core'
import type { PlumeThemeBlogPostItem } from '../../shared/index.js'
import { useLocalePostList } from './blog-data.js'
@ -7,7 +7,7 @@ import { useRouteQuery } from './route-query.js'
const DEFAULT_PER_PAGE = 10
export function usePostListControl() {
export function usePostListControl(homePage: Ref<boolean>) {
const { theme } = useData()
const list = useLocalePostList()
@ -111,7 +111,15 @@ export function usePostListControl() {
if (page.value === current)
return
page.value = current
window.scrollTo({ top: 0, left: 0, behavior: 'instant' })
setTimeout(() => {
let top = 0
if (homePage.value) {
top = document.querySelector('.vp-blog')?.getBoundingClientRect().top || 0
top += window.scrollY - 64
}
window.scrollTo({ top, behavior: 'instant' })
}, 0)
}
return {

View File

@ -67,3 +67,15 @@ export function scrollTo(
window.scrollTo({ top, behavior: 'smooth' })
}
}
export function getOffsetTop<T extends HTMLElement = HTMLElement>(target: T | null): number {
if (!target)
return 0
let parent: HTMLElement | null = target
let top = 0
while (parent) {
top += parent.offsetTop
parent = parent.offsetParent as HTMLElement
}
return top
}

View File

@ -1,6 +1,6 @@
export * from './shared.js'
export * from './dom.js'
// export * from './dom.js'
export * from './resolveEditLink.js'
export * from './resolveRepoType.js'
export * from './resolveNavLink.js'
export * from './animate.js'
// export * from './animate.js'

View File

@ -8,11 +8,12 @@ const FALLBACK_OPTIONS: PlumeThemeLocaleData = {
appearance: true,
blog: {
link: '/blog/',
pagination: { perPage: 15 },
postList: true,
tags: true,
archives: true,
categories: true,
link: '/blog/',
tagsLink: '/blog/tags/',
archivesLink: '/blog/archives/',
categoriesLink: '/blog/categories/',

View File

@ -39,10 +39,12 @@ export async function setupPage(
const locale = localePath === '/' ? rootPath : localePath
// 添加 博客页面
pageList.push(createPage(app, {
path: withBase(link, localePath),
frontmatter: { lang, _pageLayout: 'blog', title: getTitle(locale, 'blog') },
}))
if (blog.postList !== false) {
pageList.push(createPage(app, {
path: withBase(link, localePath),
frontmatter: { lang, _pageLayout: 'blog', title: getTitle(locale, 'blog') },
}))
}
// 添加 标签页
if (blog.tags !== false) {
@ -108,6 +110,11 @@ export function extendsPageData(
delete page.frontmatter._pageLayout
}
if (page.frontmatter.pageLayout === 'blog') {
page.frontmatter.draft = true
page.data.type = 'blog'
}
if ('externalLink' in page.frontmatter) {
page.frontmatter.externalLinkIcon = page.frontmatter.externalLink
delete page.frontmatter.externalLink

View File

@ -16,13 +16,6 @@ export type PlumeThemeBlogPostData = PlumeThemeBlogPostItem[]
export interface PlumeThemeBlog {
/**
*
*
* @default '/blog/'
*/
link?: string
/**
* glob string
*
@ -55,6 +48,19 @@ export interface PlumeThemeBlog {
perPage?: number
}
/**
*
*
* @default '/blog/'
*/
link?: string
/**
*
* @default true
*/
postList?: boolean
/**
*
* @default true

View File

@ -19,7 +19,7 @@ export interface PlumeNormalFrontmatter extends PageFrontmatter {
/**
* page layout
*/
pageLayout?: false | 'home' | 'doc' | 'custom' | 'page' | 'friends'
pageLayout?: false | 'home' | 'blog' | 'doc' | 'custom' | 'page' | 'friends'
/**
* class