Compare commits

...

3 Commits

Author SHA1 Message Date
joyzhao
0e6f611455 feat: 添加“返回顶部”组件,提升用户导航体验
Some checks failed
Deploy docs for Site / deploy (20.x) (push) Has been cancelled
2026-01-09 09:55:52 +08:00
joyzhao
99c41d537f feat(blog): 添加“返回博客列表”链接,支持多语言切换 2026-01-09 09:45:58 +08:00
joyzhao
551877780f fix: 修正博客导航中上一篇和下一篇文章的索引逻辑 2026-01-09 09:39:20 +08:00
5 changed files with 73 additions and 2 deletions

View File

@@ -64,8 +64,8 @@ const sortedPosts = posts
const currentIndex = sortedPosts.findIndex((post) => post.slug === currentSlug);
const nextPost = currentIndex > 0 ? sortedPosts[currentIndex - 1] : null;
const prevPost = currentIndex < sortedPosts.length - 1 ? sortedPosts[currentIndex + 1] : null;
const nextPost = currentIndex < sortedPosts.length - 1 ? sortedPosts[currentIndex + 1] : null;
const prevPost = currentIndex > 0 ? sortedPosts[currentIndex - 1] : null;
const prevText = lang === 'zh' ? '上一篇' : 'Previous Post';
const nextText = lang === 'zh' ? '下一篇' : 'Next Post';

View File

@@ -0,0 +1,46 @@
import { ArrowUp } from "lucide-react";
import { Button } from "./button";
import { useEffect, useState } from "react";
export default function BackToTop() {
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
const toggleVisibility = () => {
if (window.scrollY > 300) {
setIsVisible(true);
} else {
setIsVisible(false);
}
};
window.addEventListener("scroll", toggleVisibility);
return () => window.removeEventListener("scroll", toggleVisibility);
}, []);
const scrollToTop = () => {
window.scrollTo({
top: 0,
behavior: "smooth",
});
};
return (
<div
className={`fixed bottom-8 right-8 z-50 transition-all duration-300 ${
isVisible
? "translate-y-0 opacity-100"
: "translate-y-4 opacity-0 pointer-events-none"
}`}
>
<Button
size="icon"
onClick={scrollToTop}
className="rounded-full shadow-lg bg-primary/90 backdrop-blur-sm border border-border/50 hover:bg-primary hover:shadow-xl hover:-translate-y-1 transition-all h-10 w-10"
>
<ArrowUp className="h-5 w-5 text-primary-foreground" />
<span className="sr-only">Back to top</span>
</Button>
</div>
);
}

View File

@@ -49,6 +49,7 @@ export const translations = {
},
blog: {
slogan: 'This is where innovative thinking meets complex problems.',
backToList: 'Back to Blog',
},
services: {
title: 'What I Do',
@@ -105,6 +106,7 @@ export const translations = {
},
blog: {
slogan: '这里是创新思维与复杂问题相遇的地方。',
backToList: '返回博客列表',
},
services: {
title: '我能做什么',

View File

@@ -4,6 +4,7 @@ import type { MarkdownLayoutProps } from 'astro';
import { type Lang } from '@/types/i18n';
import { type FrontmatterProps } from '@/types';
import { defaultLang } from '@/i18n/ui';
import { useTranslations } from '@/i18n/utils';
import GlassHeader from '@/components/GlassHeader';
import Footer from '@/components/Footer';
import AuthorCard from '@/components/AuthorCard';
@@ -31,6 +32,9 @@ const {
} = frontmatter;
const lang = Astro.currentLocale as Lang || defaultLang;
const t = useTranslations(lang);
const blogListUrl = lang === 'zh' ? '/zh/blog' : '/blog';
// Handle different field names for backward compatibility
const finalPublishDate = publishDate || date;
@@ -51,6 +55,23 @@ const finalReadingTime = readTime ? parseInt(readTime.replace(/\D/g, '')) : unde
<!-- Blog post header -->
<header class="mb-10">
<a
href={blogListUrl}
class="inline-flex items-center gap-2 text-sm text-muted-foreground hover:text-primary transition-colors duration-200 mb-6 group"
>
<svg
width="16"
height="16"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
class="group-hover:-translate-x-1 transition-transform duration-200"
>
<path d="M6.85355 3.85355C7.04882 3.65829 7.04882 3.34171 6.85355 3.14645C6.65829 2.95118 6.34171 2.95118 6.14645 3.14645L2.14645 7.14645C1.95118 7.34171 1.95118 7.65829 2.14645 7.85355L6.14645 11.8536C6.34171 12.0488 6.65829 12.0488 6.85355 11.8536C7.04882 11.6583 7.04882 11.3417 6.85355 11.1464L3.20711 7.5L6.85355 3.85355Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path>
</svg>
{t('blog.backToList')}
</a>
<PostMeta
lang={lang}
publishDate={finalPublishDate}

View File

@@ -1,4 +1,5 @@
---
import BackToTop from "@/components/ui/back-to-top";
import { useTranslations } from "@/i18n/utils";
import type { Lang } from "@/types/i18n";
import { defaultLang } from "@/i18n/ui";
@@ -44,6 +45,7 @@ const t = useTranslations(lang);
>
</div>
<slot />
<BackToTop client:load />
</body>
</html>