feat(theme): 新增页面跳转过渡动效

This commit is contained in:
pengzhanbo 2024-03-19 00:34:56 +08:00
parent c09cd98075
commit 0fcfe3f0d6
8 changed files with 160 additions and 52 deletions

View File

@ -2,6 +2,7 @@
import { usePageData } from 'vuepress/client'
import type { PlumeThemePageData } from '../../../shared/index.js'
import { useThemeLocaleData } from '../../composables/index.js'
import TransitionFadeSlideY from '../TransitionFadeSlideY.vue'
import PostList from './PostList.vue'
import Archives from './Archives.vue'
import BlogAside from './BlogAside.vue'
@ -16,10 +17,12 @@ const page = usePageData<PlumeThemePageData>()
<template>
<div class="blog-wrapper">
<div class="blog-container" :class="{ 'no-avatar': !theme.avatar }">
<BlogNav v-if="!theme.avatar" is-local />
<PostList v-if="page.type === 'blog'" />
<Tags v-if="page.type === 'blog-tags'" />
<Archives v-if="page.type === 'blog-archives'" />
<TransitionFadeSlideY>
<BlogNav v-if="!theme.avatar" is-local />
<PostList v-if="page.type === 'blog'" />
<Tags v-if="page.type === 'blog-tags'" />
<Archives v-if="page.type === 'blog-archives'" />
</TransitionFadeSlideY>
<BlogAside />
<BlogExtract />
</div>

View File

@ -1,6 +1,9 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useThemeLocaleData } from '../../composables/index.js'
import SocialLinks from '../SocialLinks.vue'
import IconLocation from '../icons/IconLocation.vue'
import IconOrganization from '../icons/IconOrganization.vue'
const theme = useThemeLocaleData()
const avatar = computed(() => theme.value.avatar)
@ -13,7 +16,18 @@ const avatar = computed(() => theme.value.avatar)
</p>
<div>
<h3>{{ avatar.name }}</h3>
<p>{{ avatar.description }}</p>
<p v-if="avatar.description" v-html="avatar.description" />
<div v-if="avatar.location" class="avatar-location">
<IconLocation />
<p v-html="avatar.location" />
</div>
<div v-if="avatar.organization" class="avatar-organization">
<IconOrganization />
<p v-html="avatar.organization" />
</div>
</div>
<div v-if="theme.social" class="avatar-social">
<SocialLinks :links="theme.social" />
</div>
</div>
</template>
@ -44,7 +58,7 @@ const avatar = computed(() => theme.value.avatar)
.avatar-profile h3 {
margin-top: 1.5rem;
font-size: 16px;
font-size: 18px;
font-weight: 600;
}
@ -58,4 +72,40 @@ const avatar = computed(() => theme.value.avatar)
overflow: hidden;
border-radius: 50%;
}
.avatar-location,
.avatar-organization {
display: flex;
align-items: center;
justify-content: center;
margin-top: 16px;
font-size: 14px;
color: var(--vp-c-text-3);
transition: color var(--t-color);
}
.avatar-location p,
.avatar-organization p {
margin: 0 4px;
}
.avatar-location + .avatar-organization {
margin-top: 0;
}
.avatar-social {
padding-top: 12px;
margin-top: 12px;
border-top: 1px solid var(--vp-c-divider);
transition: border var(--t-color);
}
.avatar-social :deep(.social-link) {
width: 32px;
height: 32px;
}
.avatar-social :deep(.social-link:hover) {
color: var(--vp-c-brand-1);
}
</style>

View File

@ -23,7 +23,9 @@ const { hasSidebar } = useSidebar()
flex-grow: 1;
flex-shrink: 0;
width: 100%;
padding-left: 0;
margin: var(--vp-layout-top-height, 0) auto 0;
transition: padding-left 0.2s ease;
}
.layout-content.is-home {

View File

@ -10,6 +10,7 @@ import PageAside from './PageAside.vue'
import PageFooter from './PageFooter.vue'
import PageMeta from './PageMeta.vue'
import EncryptPage from './EncryptPage.vue'
import TransitionFadeSlideY from './TransitionFadeSlideY.vue'
const { hasSidebar, hasAside } = useSidebar()
const isDark = useDarkMode()
@ -42,24 +43,29 @@ onContentUpdated(() => zoom?.refresh())
}"
>
<div class="container">
<div v-if="enableAside" class="aside">
<div class="aside-container">
<div class="aside-content">
<PageAside />
<TransitionFadeSlideY>
<div v-if="enableAside" :key="page.path" class="aside">
<div class="aside-container">
<div class="aside-content">
<PageAside />
</div>
</div>
</div>
</div>
</TransitionFadeSlideY>
<div class="content">
<div class="content-container">
<main class="main">
<PageMeta />
<EncryptPage v-if="!isPageDecrypted" />
<template v-else>
<Content class="plume-content" />
<PageFooter />
<PageComment v-if="hasComments" :darkmode="isDark" />
</template>
</main>
<TransitionFadeSlideY>
<main :key="page.path" class="main">
<PageMeta />
<EncryptPage v-if="!isPageDecrypted" />
<template v-else>
<Content class="plume-content" />
<PageFooter />
<PageComment v-if="hasComments" :darkmode="isDark" />
</template>
</main>
</TransitionFadeSlideY>
</div>
</div>
</div>

View File

@ -29,30 +29,32 @@ watch(
</script>
<template>
<aside
v-if="hasSidebar"
ref="navEl"
class="sidebar-wrapper"
:class="{ open }"
@click.stop
>
<div class="curtain" />
<nav
id="SidebarNav"
class="nav"
aria-labelledby="sidebar-aria-label"
tabindex="-1"
<Transition name="fade-slide-x" mode="out-in">
<aside
v-if="hasSidebar"
ref="navEl"
class="sidebar-wrapper"
:class="{ open }"
@click.stop
>
<span id="sidebar-aria-label" class="visually-hidden">
Sidebar Navigation
</span>
<div class="curtain" />
<div v-for="item in sidebarGroups" :key="item.text" class="group">
<SidebarItem :item="item" :depth="0" />
</div>
</nav>
</aside>
<nav
id="SidebarNav"
class="nav"
aria-labelledby="sidebar-aria-label"
tabindex="-1"
>
<span id="sidebar-aria-label" class="visually-hidden">
Sidebar Navigation
</span>
<div v-for="item in sidebarGroups" :key="item.text" class="group">
<SidebarItem :item="item" :depth="0" />
</div>
</nav>
</aside>
</Transition>
</template>
<style scoped>

View File

@ -225,8 +225,21 @@ function onCaretClick() {
color: var(--vp-c-text-1);
}
.sidebar-item:not(.collapsible) > .item:hover :deep(.vp-iconify),
.sidebar-item:not(.collapsible).has-active > .item > :deep(.vp-iconify) {
.sidebar-item.level-0.is-active > .item > :deep(.vp-iconify),
.sidebar-item.level-1.is-active > .item > :deep(.vp-iconify),
.sidebar-item.level-2.is-active > .item > :deep(.vp-iconify),
.sidebar-item.level-3.is-active > .item > :deep(.vp-iconify),
.sidebar-item.level-4.is-active > .item > :deep(.vp-iconify),
.sidebar-item.level-5.is-active > .item > :deep(.vp-iconify) {
color: var(--vp-c-brand-1);
}
.sidebar-item.level-0.is-link > .item:hover :deep(.vp-iconify),
.sidebar-item.level-1.is-link > .item:hover :deep(.vp-iconify),
.sidebar-item.level-2.is-link > .item:hover :deep(.vp-iconify),
.sidebar-item.level-3.is-link > .item:hover :deep(.vp-iconify),
.sidebar-item.level-4.is-link > .item:hover :deep(.vp-iconify),
.sidebar-item.level-5.is-link > .item:hover :deep(.vp-iconify) {
color: var(--vp-c-brand-1);
}

View File

@ -15,6 +15,7 @@ import SkipLink from '../components/SkipLink.vue'
import VFooter from '../components/VFooter.vue'
import BackToTop from '../components/BackToTop.vue'
import EncryptGlobal from '../components/EncryptGlobal.vue'
import TransitionFadeSlideY from '../components/TransitionFadeSlideY.vue'
import {
useCloseSidebarOnEscape,
useSidebar,
@ -56,17 +57,17 @@ provide('is-sidebar-open', isSidebarOpen)
<SkipLink />
<Backdrop :show="isSidebarOpen" @click="closeSidebar" />
<Nav />
<LocalNav
:open="isSidebarOpen"
:show-outline="isPageDecrypted"
@open-menu="openSidebar"
/>
<LocalNav :open="isSidebarOpen" :show-outline="isPageDecrypted" @open-menu="openSidebar" />
<Sidebar :open="isSidebarOpen" />
<LayoutContent>
<Home v-if="page.frontmatter.home" />
<Friends v-else-if="page.frontmatter.friends" />
<Blog v-else-if="isBlogLayout" />
<Page v-else />
<template v-else>
<TransitionFadeSlideY>
<Friends v-if="page.frontmatter.friends" />
<Blog v-else-if="isBlogLayout" />
<Page v-else />
</TransitionFadeSlideY>
</template>
<BackToTop />
<VFooter />
</LayoutContent>

View File

@ -16,3 +16,34 @@
.vp-iconify {
margin: 0.3em;
}
/* ----------------- Transition ------------------------ */
.fade-slide-y-enter-active {
transition: all 0.25s ease !important;
}
.fade-slide-y-leave-active {
transition: all 0.25s cubic-bezier(0, 1, 0.3, 1) !important;
}
.fade-slide-y-enter-from,
.fade-slide-y-leave-to {
opacity: 0;
transform: translateY(10px);
}
.fade-slide-x-enter-active {
transition: all 0.25s ease !important;
}
.fade-slide-x-leave-active {
transition: all 0.25s cubic-bezier(0, 1, 0.3, 1) !important;
}
.fade-slide-x-enter-from,
.fade-slide-x-leave-to {
opacity: 0 !important;
transform: translateX(-10px) !important;
}