feat: update blog page localization and styling

- Change "publisher" to "author" in English and Chinese translation files
- Add Lucide icons for date and reading time in blog post page
- Implement link underline animation in global CSS
- Enhance blog post page layout with icon-based metadata display
- Improve visual consistency and internationalization for blog components
This commit is contained in:
javayhu 2025-03-08 18:39:57 +08:00
parent 13810236d4
commit 99490cfd0b
4 changed files with 29 additions and 15 deletions

View File

@ -66,7 +66,7 @@
"BlogPage": { "BlogPage": {
"title": "Blog", "title": "Blog",
"subtitle": "Latest news and updates from our team", "subtitle": "Latest news and updates from our team",
"publisher": "Publisher", "author": "Author",
"categories": "Categories", "categories": "Categories",
"tableOfContents": "Table of Contents", "tableOfContents": "Table of Contents",
"all": "All", "all": "All",

View File

@ -66,7 +66,7 @@
"BlogPage": { "BlogPage": {
"title": "博客", "title": "博客",
"subtitle": "来自我们的团队最新新闻和更新", "subtitle": "来自我们的团队最新新闻和更新",
"publisher": "发布者", "author": "作者",
"categories": "分类", "categories": "分类",
"tableOfContents": "目录", "tableOfContents": "目录",
"all": "全部", "all": "全部",

View File

@ -7,10 +7,11 @@ import { getBaseUrl } from '@/lib/urls/get-base-url';
import { estimateReadingTime, getLocaleDate } from '@/lib/utils'; import { estimateReadingTime, getLocaleDate } from '@/lib/utils';
import type { NextPageProps } from '@/types/next-page-props'; import type { NextPageProps } from '@/types/next-page-props';
import { allPosts } from 'content-collections'; import { allPosts } from 'content-collections';
import { CalendarIcon, ClockIcon } from 'lucide-react';
import type { Metadata } from 'next'; import type { Metadata } from 'next';
import { getTranslations } from 'next-intl/server';
import Image from 'next/image'; import Image from 'next/image';
import { notFound } from 'next/navigation'; import { notFound } from 'next/navigation';
import { getTranslations } from 'next-intl/server';
import '@/styles/mdx.css'; import '@/styles/mdx.css';
@ -35,28 +36,28 @@ async function getBlogPostFromParams(props: NextPageProps) {
if (!params) { if (!params) {
return null; return null;
} }
const locale = params.locale as string; const locale = params.locale as string;
const slug = const slug =
(Array.isArray(params.slug) ? params.slug?.join('/') : params.slug) || ''; (Array.isArray(params.slug) ? params.slug?.join('/') : params.slug) || '';
// Find post with matching slug and locale // Find post with matching slug and locale
const post = allPosts.find( const post = allPosts.find(
(post) => (post) =>
(post.slugAsParams === slug || (!slug && post.slugAsParams === 'index')) && (post.slugAsParams === slug || (!slug && post.slugAsParams === 'index')) &&
post.locale === locale post.locale === locale
); );
if (!post) { if (!post) {
// If no post found with the current locale, try to find one with the default locale // If no post found with the current locale, try to find one with the default locale
const defaultPost = allPosts.find( const defaultPost = allPosts.find(
(post) => (post) =>
(post.slugAsParams === slug || (!slug && post.slugAsParams === 'index')) (post.slugAsParams === slug || (!slug && post.slugAsParams === 'index'))
); );
return defaultPost; return defaultPost;
} }
return post; return post;
} }
@ -115,8 +116,14 @@ export default async function BlogPostPage(props: NextPageProps) {
{/* blog post date */} {/* blog post date */}
<div className="flex items-center justify-between gap-2"> <div className="flex items-center justify-between gap-2">
<p className="text-sm text-muted-foreground">{date}</p> <div className="flex items-center gap-2">
<p className="text-sm text-muted-foreground">{estimateReadingTime(post.body.raw)}</p> <CalendarIcon className="size-4 text-muted-foreground" />
<p className="text-sm text-muted-foreground">{date}</p>
</div>
<div className="flex items-center gap-2">
<ClockIcon className="size-4 text-muted-foreground" />
<p className="text-sm text-muted-foreground">{estimateReadingTime(post.body.raw)}</p>
</div>
</div> </div>
{/* blog post title */} {/* blog post title */}
@ -141,7 +148,7 @@ export default async function BlogPostPage(props: NextPageProps) {
<div className="space-y-4 lg:sticky lg:top-24"> <div className="space-y-4 lg:sticky lg:top-24">
{/* author info */} {/* author info */}
<div className="bg-muted/50 rounded-lg p-6"> <div className="bg-muted/50 rounded-lg p-6">
<h2 className="text-lg font-semibold mb-4">{t("publisher")}</h2> <h2 className="text-lg font-semibold mb-4">{t("author")}</h2>
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<div className="relative h-8 w-8 flex-shrink-0"> <div className="relative h-8 w-8 flex-shrink-0">
{post.author?.avatar && ( {post.author?.avatar && (
@ -166,7 +173,7 @@ export default async function BlogPostPage(props: NextPageProps) {
<li key={category.slug}> <li key={category.slug}>
<LocaleLink <LocaleLink
href={`/blog/category/${category.slug}`} href={`/blog/category/${category.slug}`}
className="text-sm link-underline" className="text-sm link-underline-animation"
> >
{category.name} {category.name}
</LocaleLink> </LocaleLink>

View File

@ -62,3 +62,10 @@
@apply bg-background text-foreground; @apply bg-background text-foreground;
} }
} }
@layer utilities {
.link-underline-animation {
@apply relative underline underline-offset-4 decoration-transparent decoration-2
hover:decoration-primary hover:text-primary transition-all duration-300 ease-in-out;
}
}