feat(i18n): implement comprehensive blog post enhancements

- Add avatar to personal info in data.ts
- Remove redundant headings from blog posts
- Reorder imports in utils.ts for consistency
- Implement new blog layout components including:
  - PostMeta for displaying post metadata
  - TableOfContents for navigation
  - BlogNavigation for post pagination
  - ShareButtons for social sharing
  - AuthorCard for author information
- Enhance BlogPostLayout with:
  - Improved typography and spacing
  - Responsive sidebar layout
  - Dark mode support
  - Better code block styling
- Remove outdated i18n guide documentation
- Add comprehensive styling for all new components
This commit is contained in:
joyzhao
2025-06-17 19:37:36 +08:00
parent d22174e0dc
commit e5497e5e6d
18 changed files with 894 additions and 387 deletions

View File

@@ -0,0 +1,142 @@
---
import { type Lang } from '@/i18n/utils';
import { useTranslations } from '@/i18n/utils';
export interface Props {
lang: Lang;
publishDate?: string;
readingTime?: number;
tags?: string[];
category?: string | string[];
className?: string;
}
const {
lang,
publishDate,
readingTime,
tags,
category,
className = ''
} = Astro.props;
const t = useTranslations(lang);
/**
* Format date according to locale
*/
const formatDate = (dateString: string) => {
const date = new Date(dateString);
return date.toLocaleDateString(lang === 'zh' ? 'zh-CN' : 'en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
};
/**
* Get reading time text based on language
*/
const getReadingTimeText = (minutes: number) => {
if (lang === 'zh') {
return `${minutes} 分钟阅读`;
}
return `${minutes} min read`;
};
---
<div class={`space-y-6 ${className}`} data-component="PostMeta">
<!-- Primary Meta Info: Date and Reading Time -->
<div class="flex flex-wrap items-center gap-4 text-sm md:text-base text-muted-foreground">
<!-- Publish Date -->
{publishDate && (
<div class="flex items-center gap-2">
<svg class="w-4 h-4 md:w-5 md:h-5 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect>
<line x1="16" y1="2" x2="16" y2="6"></line>
<line x1="8" y1="2" x2="8" y2="6"></line>
<line x1="3" y1="10" x2="21" y2="10"></line>
</svg>
<time datetime={publishDate} class="font-medium">
{formatDate(publishDate)}
</time>
</div>
)}
<!-- Reading Time -->
{readingTime && (
<div class="flex items-center gap-2">
<svg class="w-4 h-4 md:w-5 md:h-5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="10"></circle>
<polyline points="12,6 12,12 16,14"></polyline>
</svg>
<span class="font-medium">{getReadingTimeText(readingTime)}</span>
</div>
)}
</div>
<!-- Secondary Meta Info: Category and Tags -->
{(category || (tags && tags.length > 0)) && (
<div class="space-y-3">
<!-- Category Section -->
{category && (
<div class="space-y-2">
<div class="text-xs font-medium text-muted-foreground uppercase tracking-wide">
分类
</div>
<div class="flex gap-2 flex-wrap">
{Array.isArray(category) ? (
category.map((cat) => (
<span class="inline-flex items-center px-3 py-1.5 rounded-full text-xs font-medium bg-gradient-to-r from-purple-500 to-purple-600 text-white shadow-sm hover:shadow-md transition-all duration-200 hover:scale-105">
{cat}
</span>
))
) : (
<span class="inline-flex items-center px-3 py-1.5 rounded-full text-xs font-medium bg-gradient-to-r from-purple-500 to-purple-600 text-white shadow-sm hover:shadow-md transition-all duration-200 hover:scale-105">
{category}
</span>
)}
</div>
</div>
)}
<!-- Tags Section -->
{tags && tags.length > 0 && (
<div class="space-y-2">
<div class="text-xs font-medium text-muted-foreground uppercase tracking-wide">
标签
</div>
<div class="flex gap-2 flex-wrap">
{tags.map((tag) => (
<span class="inline-flex items-center px-2.5 py-1 rounded-md text-xs font-medium bg-gray-100 text-gray-700 hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700 transition-colors border border-gray-200 dark:border-gray-600">
# {tag}
</span>
))}
</div>
</div>
)}
</div>
)}
</div>
<style>
/* Ensure smooth transitions for hover effects */
.transition-colors {
transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
}
/* Responsive adjustments */
@media (max-width: 640px) {
.flex-wrap {
gap: 0.75rem;
}
.text-sm {
font-size: 0.8rem;
}
}
</style>