Compare commits
2 Commits
ca9e083399
...
b8a8cc474b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8a8cc474b | ||
|
|
78c468a7d2 |
@@ -2,6 +2,7 @@ import { useEffect, useRef } from 'react';
|
||||
import type { WalineInstance, WalineInitOptions } from '@waline/client';
|
||||
import { init } from '@waline/client';
|
||||
import '@waline/client/style';
|
||||
import '@/styles/waline-custom.css';
|
||||
|
||||
import type { Lang } from '@/types/i18n';
|
||||
|
||||
@@ -28,6 +29,8 @@ export default function Comments({ lang = 'en', ...props }: CommentsProps) {
|
||||
serverURL: import.meta.env.PUBLIC_WALINE_SERVER_URL,
|
||||
lang: walineLang,
|
||||
dark: getTheme(),
|
||||
pageview: true,
|
||||
comment: true,
|
||||
path,
|
||||
});
|
||||
|
||||
|
||||
342
src/styles/waline-custom.css
Normal file
342
src/styles/waline-custom.css
Normal file
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* Waline Custom Styles
|
||||
* 适配网站主题风格 - 紫色渐变主题
|
||||
*/
|
||||
|
||||
/* ========== 基础变量覆盖 ========== */
|
||||
:root {
|
||||
/* 主题色 - 使用网站的紫色渐变accent */
|
||||
--waline-theme-color: #8B5CF6;
|
||||
--waline-active-color: #EC4899;
|
||||
|
||||
/* 背景色 */
|
||||
--waline-bg-color: oklch(1 0 0);
|
||||
--waline-bg-color-light: oklch(0.97 0 0);
|
||||
--waline-bg-color-hover: oklch(0.93 0 0);
|
||||
|
||||
/* 文字颜色 */
|
||||
--waline-color: oklch(0.4 0 0);
|
||||
--waline-light-grey: oklch(0.65 0 0);
|
||||
--waline-dark-grey: oklch(0.3 0 0);
|
||||
|
||||
/* 边框颜色 */
|
||||
--waline-border-color: oklch(0.87 0 0);
|
||||
|
||||
/* 其他颜色 */
|
||||
--waline-badge-color: #8B5CF6;
|
||||
--waline-info-bg-color: oklch(0.97 0 0);
|
||||
--waline-info-color: oklch(0.55 0 0);
|
||||
--waline-bq-color: oklch(0.93 0 0);
|
||||
|
||||
/* 代码块背景 */
|
||||
--waline-code-bg-color: oklch(0.25 0 0);
|
||||
|
||||
/* 圆角 - 与网站一致 */
|
||||
--waline-border-radius: var(--radius, 0.75rem);
|
||||
|
||||
/* 阴影 */
|
||||
--waline-box-shadow: var(--shadow-md, 0 4px 12px rgba(0, 0, 0, 0.08));
|
||||
|
||||
/* 头像圆角 - 使用网站风格 */
|
||||
--waline-avatar-radius: var(--radius-md, 0.5rem);
|
||||
|
||||
/* 按钮样式 */
|
||||
--waline-btn-radius: var(--radius, 0.75rem);
|
||||
}
|
||||
|
||||
/* ========== 暗黑模式 ========== */
|
||||
.dark {
|
||||
--waline-bg-color: oklch(0.205 0 0);
|
||||
--waline-bg-color-light: oklch(0.269 0 0);
|
||||
--waline-bg-color-hover: oklch(0.32 0 0);
|
||||
|
||||
--waline-color: oklch(0.9 0 0);
|
||||
--waline-light-grey: oklch(0.6 0 0);
|
||||
--waline-dark-grey: oklch(0.75 0 0);
|
||||
|
||||
--waline-border-color: oklch(1 0 0 / 15%);
|
||||
|
||||
--waline-info-bg-color: oklch(0.269 0 0);
|
||||
--waline-info-color: oklch(0.6 0 0);
|
||||
--waline-bq-color: oklch(0.269 0 0);
|
||||
|
||||
--waline-code-bg-color: oklch(0.12 0 0);
|
||||
|
||||
--waline-box-shadow: var(--shadow-md, 0 4px 12px rgba(0, 0, 0, 0.25));
|
||||
}
|
||||
|
||||
/* ========== 评论面板样式 ========== */
|
||||
.wl-panel {
|
||||
border-radius: var(--waline-border-radius) !important;
|
||||
border: 1px solid var(--waline-border-color) !important;
|
||||
box-shadow: var(--waline-box-shadow) !important;
|
||||
background: var(--waline-bg-color) !important;
|
||||
}
|
||||
|
||||
/* ========== 输入框样式 ========== */
|
||||
.wl-header {
|
||||
border-bottom-color: var(--waline-border-color) !important;
|
||||
}
|
||||
|
||||
.wl-header label {
|
||||
color: var(--waline-color) !important;
|
||||
}
|
||||
|
||||
.wl-header input {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.wl-editor {
|
||||
background: var(--waline-bg-color-light) !important;
|
||||
border-radius: var(--waline-btn-radius) !important;
|
||||
}
|
||||
|
||||
.wl-editor:focus {
|
||||
background: var(--waline-bg-color-hover) !important;
|
||||
}
|
||||
|
||||
/* ========== 按钮样式 ========== */
|
||||
.wl-btn {
|
||||
border-radius: var(--waline-btn-radius) !important;
|
||||
font-size: 0.875em !important;
|
||||
transition: all 0.2s ease !important;
|
||||
}
|
||||
|
||||
.wl-btn:hover {
|
||||
border-color: var(--waline-theme-color) !important;
|
||||
color: var(--waline-theme-color) !important;
|
||||
background: var(--waline-bg-color-light) !important;
|
||||
}
|
||||
|
||||
.wl-btn.primary {
|
||||
background: linear-gradient(135deg, #8B5CF6, #EC4899) !important;
|
||||
border: none !important;
|
||||
color: white !important;
|
||||
font-weight: 500 !important;
|
||||
}
|
||||
|
||||
.wl-btn.primary:hover {
|
||||
background: linear-gradient(135deg, #7C3AED, #DB2777) !important;
|
||||
border: none !important;
|
||||
color: white !important;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(139, 92, 246, 0.3);
|
||||
}
|
||||
|
||||
/* ========== 头部标签页 ========== */
|
||||
.wl-header label {
|
||||
transition: all 0.2s ease !important;
|
||||
}
|
||||
|
||||
.wl-header label:hover {
|
||||
background: var(--waline-bg-color-light) !important;
|
||||
}
|
||||
|
||||
/* ========== 评论卡片样式 ========== */
|
||||
.wl-card {
|
||||
border-bottom-color: var(--waline-border-color) !important;
|
||||
}
|
||||
|
||||
.wl-card:first-child {
|
||||
margin-inline-start: 0 !important;
|
||||
}
|
||||
|
||||
.wl-nick {
|
||||
color: var(--waline-color) !important;
|
||||
}
|
||||
|
||||
.wl-time {
|
||||
color: var(--waline-info-color) !important;
|
||||
}
|
||||
|
||||
.wl-content {
|
||||
color: var(--waline-color) !important;
|
||||
line-height: 1.8 !important;
|
||||
}
|
||||
|
||||
/* ========== 徽章样式 ========== */
|
||||
.wl-badge {
|
||||
background: linear-gradient(135deg, #8B5CF6, #EC4899) !important;
|
||||
border: none !important;
|
||||
color: white !important;
|
||||
font-size: 0.7em !important;
|
||||
padding: 2px 8px !important;
|
||||
border-radius: 9999px !important;
|
||||
}
|
||||
|
||||
/* ========== 操作按钮 ========== */
|
||||
.wl-action {
|
||||
color: var(--waline-light-grey) !important;
|
||||
transition: all 0.2s ease !important;
|
||||
}
|
||||
|
||||
.wl-action:hover {
|
||||
color: var(--waline-theme-color) !important;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.wl-action.active {
|
||||
color: var(--waline-active-color) !important;
|
||||
}
|
||||
|
||||
/* ========== 评论操作 ========== */
|
||||
.wl-delete:hover,
|
||||
.wl-like:hover,
|
||||
.wl-reply:hover,
|
||||
.wl-edit:hover {
|
||||
color: var(--waline-theme-color) !important;
|
||||
}
|
||||
|
||||
.wl-delete.active,
|
||||
.wl-like.active,
|
||||
.wl-reply.active,
|
||||
.wl-edit.active {
|
||||
color: var(--waline-active-color) !important;
|
||||
}
|
||||
|
||||
/* ========== 排序按钮 ========== */
|
||||
.wl-sort li {
|
||||
color: var(--waline-info-color) !important;
|
||||
transition: all 0.2s ease !important;
|
||||
}
|
||||
|
||||
.wl-sort li:hover {
|
||||
color: var(--waline-theme-color) !important;
|
||||
}
|
||||
|
||||
.wl-sort li.active {
|
||||
color: var(--waline-theme-color) !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* ========== 表情弹窗 ========== */
|
||||
.wl-emoji-popup {
|
||||
border-radius: var(--waline-border-radius) !important;
|
||||
box-shadow: var(--waline-box-shadow) !important;
|
||||
background: var(--waline-bg-color) !important;
|
||||
border: 1px solid var(--waline-border-color) !important;
|
||||
}
|
||||
|
||||
.wl-emoji-popup .wl-tab.active {
|
||||
background: var(--waline-bg-color-light) !important;
|
||||
}
|
||||
|
||||
.wl-emoji-popup button:hover {
|
||||
background: var(--waline-bg-color-hover) !important;
|
||||
}
|
||||
|
||||
/* ========== GIF 弹窗 ========== */
|
||||
.wl-gif-popup {
|
||||
border-radius: var(--waline-border-radius) !important;
|
||||
box-shadow: var(--waline-box-shadow) !important;
|
||||
background: var(--waline-bg-color) !important;
|
||||
border: 1px solid var(--waline-border-color) !important;
|
||||
}
|
||||
|
||||
/* ========== 评论统计 ========== */
|
||||
.wl-count {
|
||||
color: var(--waline-theme-color) !important;
|
||||
font-size: 1.5em !important;
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
|
||||
/* ========== 空状态 ========== */
|
||||
.wl-empty {
|
||||
color: var(--waline-info-color) !important;
|
||||
}
|
||||
|
||||
/* ========== 头像样式 ========== */
|
||||
.wl-avatar {
|
||||
border-radius: var(--waline-avatar-radius) !important;
|
||||
border: 2px solid var(--waline-border-color) !important;
|
||||
box-shadow: var(--waline-box-shadow) !important;
|
||||
}
|
||||
|
||||
/* ========== 回复引用框 ========== */
|
||||
.wl-quote {
|
||||
border-left-color: var(--waline-border-color) !important;
|
||||
}
|
||||
|
||||
/* ========== 预览区域 ========== */
|
||||
.wl-preview .wl-content {
|
||||
background: var(--waline-bg-color-light) !important;
|
||||
border-radius: var(--waline-btn-radius) !important;
|
||||
}
|
||||
|
||||
/* ========== 反应区域 ========== */
|
||||
.wl-reaction-title {
|
||||
color: var(--waline-color) !important;
|
||||
}
|
||||
|
||||
.wl-reaction-item.active .wl-reaction-text {
|
||||
color: var(--waline-theme-color) !important;
|
||||
}
|
||||
|
||||
.wl-reaction-votes {
|
||||
border-color: var(--waline-theme-color) !important;
|
||||
color: var(--waline-theme-color) !important;
|
||||
}
|
||||
|
||||
.wl-reaction-item.active .wl-reaction-votes {
|
||||
background: var(--waline-theme-color) !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
/* ========== 加载动画 ========== */
|
||||
.wl-loading svg {
|
||||
color: var(--waline-theme-color) !important;
|
||||
}
|
||||
|
||||
/* ========== 滚动条样式 ========== */
|
||||
[data-waline] ::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
[data-waline] ::-webkit-scrollbar-track-piece {
|
||||
background: var(--waline-bg-color-light);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
[data-waline] ::-webkit-scrollbar-thumb {
|
||||
background: var(--waline-theme-color);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
[data-waline] ::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--waline-active-color);
|
||||
}
|
||||
|
||||
/* ========== 链接样式 ========== */
|
||||
[data-waline] a {
|
||||
color: var(--waline-theme-color) !important;
|
||||
text-decoration: none !important;
|
||||
transition: all 0.2s ease !important;
|
||||
}
|
||||
|
||||
[data-waline] a:hover {
|
||||
color: var(--waline-active-color) !important;
|
||||
}
|
||||
|
||||
/* ========== 代码块样式 ========== */
|
||||
.wl-content pre,
|
||||
.wl-content pre[class*="language-"] {
|
||||
background: var(--waline-code-bg-color) !important;
|
||||
border-radius: var(--waline-btn-radius) !important;
|
||||
}
|
||||
|
||||
/* ========== 移动端适配 ========== */
|
||||
@media (max-width: 640px) {
|
||||
.wl-panel {
|
||||
border-radius: var(--radius-md, 0.5rem) !important;
|
||||
}
|
||||
|
||||
.wl-btn {
|
||||
font-size: 0.8em !important;
|
||||
padding: 0.4em 0.8em !important;
|
||||
}
|
||||
|
||||
.wl-editor {
|
||||
min-height: 6em !important;
|
||||
}
|
||||
}
|
||||
@@ -1,309 +0,0 @@
|
||||
/**
|
||||
* Blog utility functions
|
||||
* This file contains common functions used across blog components
|
||||
*/
|
||||
|
||||
import { type BlogPost, type Lang } from '@/types';
|
||||
import { defaultLang } from '@/i18n/ui';
|
||||
|
||||
/**
|
||||
* Get blog posts based on language
|
||||
* @param lang - Current language
|
||||
* @param postsGlob - Object containing imported posts from glob
|
||||
* @returns Processed blog posts array
|
||||
*/
|
||||
export async function getBlogPosts(lang: Lang, postsGlob: Record<string, any>): Promise<BlogPost[]> {
|
||||
// Get posts based on language
|
||||
let allPosts = [];
|
||||
|
||||
if (lang === 'zh') {
|
||||
allPosts = postsGlob.zh;
|
||||
} else {
|
||||
allPosts = postsGlob.en;
|
||||
}
|
||||
|
||||
// Process blog post data
|
||||
const posts: BlogPost[] = allPosts.map((post: any) => {
|
||||
const slug = post.url?.split('/').filter(Boolean).pop() || '';
|
||||
|
||||
// Default image if not specified in frontmatter
|
||||
const defaultImage = "https://images.unsplash.com/photo-1516321318423-f06f85e504b3?w=400&h=250&fit=crop&crop=center";
|
||||
|
||||
return {
|
||||
title: post.frontmatter.title,
|
||||
description: post.frontmatter.description || '',
|
||||
image: post.frontmatter.image || defaultImage,
|
||||
slug: slug,
|
||||
tags: post.frontmatter.tags || [],
|
||||
tagId: post.frontmatter.tagId || [],
|
||||
category: Array.isArray(post.frontmatter.category) ? post.frontmatter.category : post.frontmatter.category ? [post.frontmatter.category] : [],
|
||||
categoryId: Array.isArray(post.frontmatter.categoryId) ? post.frontmatter.categoryId : post.frontmatter.categoryId ? [post.frontmatter.categoryId] : [],
|
||||
date: post.frontmatter.date || post.frontmatter.pubDate || '',
|
||||
readTime: post.frontmatter.readTime || post.frontmatter.readingTime || '5 min read',
|
||||
url: post.url || '',
|
||||
};
|
||||
});
|
||||
|
||||
return posts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort blog posts by date (newest first)
|
||||
* @param posts - Array of blog posts
|
||||
* @returns Sorted array of blog posts
|
||||
*/
|
||||
export function sortPostsByDate(posts: BlogPost[]): BlogPost[] {
|
||||
return posts
|
||||
.filter(post => post.date) // Filter out posts without dates
|
||||
.sort((a, b) => {
|
||||
const dateA = new Date(a.date).getTime();
|
||||
const dateB = new Date(b.date).getTime();
|
||||
return dateB - dateA; // Descending order, newest first
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter posts by category
|
||||
* @param posts - Array of blog posts
|
||||
* @param category - Category to filter by
|
||||
* @returns Filtered array of blog posts
|
||||
*/
|
||||
export function filterPostsByCategory(posts: BlogPost[], category: string): BlogPost[] {
|
||||
if (!category) return posts;
|
||||
|
||||
return posts.filter(post => {
|
||||
// First check if post contains the current category ID
|
||||
if (post.categoryId && Array.isArray(post.categoryId)) {
|
||||
return post.categoryId.some(catId =>
|
||||
catId.toLowerCase() === category.toLowerCase()
|
||||
);
|
||||
}
|
||||
// If no categoryId, check category
|
||||
else if (post.category && Array.isArray(post.category)) {
|
||||
return post.category.some(cat =>
|
||||
cat.toLowerCase() === category.toLowerCase()
|
||||
);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter posts by tag
|
||||
* @param posts - Array of blog posts
|
||||
* @param tag - Tag to filter by
|
||||
* @returns Filtered array of blog posts
|
||||
*/
|
||||
export function filterPostsByTag(posts: BlogPost[], tag: string): BlogPost[] {
|
||||
if (!tag) return posts;
|
||||
|
||||
return posts.filter(post => {
|
||||
// First check if post contains the current tag ID
|
||||
if (post.tagId && Array.isArray(post.tagId)) {
|
||||
return post.tagId.some(tagId =>
|
||||
tagId.toLowerCase() === tag.toLowerCase()
|
||||
);
|
||||
}
|
||||
// If no tagId, check tags
|
||||
else if (post.tags && Array.isArray(post.tags)) {
|
||||
return post.tags.some(postTag =>
|
||||
postTag.toLowerCase() === tag.toLowerCase()
|
||||
);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract categories from posts
|
||||
* @param posts - Array of blog posts
|
||||
* @returns Map of category names to category IDs
|
||||
*/
|
||||
export function extractCategories(posts: any[]): Map<string, string> {
|
||||
const allCategories = new Set<string>();
|
||||
const categoryMap = new Map<string, string>(); // Map of category name to ID
|
||||
|
||||
posts.forEach(post => {
|
||||
// Process categories
|
||||
if (post.frontmatter?.category) {
|
||||
const categories = Array.isArray(post.frontmatter.category)
|
||||
? post.frontmatter.category
|
||||
: [post.frontmatter.category];
|
||||
|
||||
const categoryIds = Array.isArray(post.frontmatter.categoryId)
|
||||
? post.frontmatter.categoryId
|
||||
: post.frontmatter.categoryId ? [post.frontmatter.categoryId] : [];
|
||||
|
||||
// If categoryId exists, use mapping between categoryId and category
|
||||
if (categoryIds.length > 0 && categoryIds.length === categories.length) {
|
||||
categories.forEach((cat: string, index: number) => {
|
||||
if (cat && categoryIds[index]) {
|
||||
allCategories.add(cat);
|
||||
categoryMap.set(cat, categoryIds[index]);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// If no categoryId or lengths don't match, use category name as ID
|
||||
categories.forEach((cat: string) => {
|
||||
if (cat) {
|
||||
allCategories.add(cat);
|
||||
categoryMap.set(cat, cat.toLowerCase());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return categoryMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract tags from posts
|
||||
* @param posts - Array of blog posts
|
||||
* @returns Map of tag names to tag IDs
|
||||
*/
|
||||
export function extractTags(posts: any[]): Map<string, string> {
|
||||
const allTags = new Set<string>();
|
||||
const tagMap = new Map<string, string>(); // Map of tag name to ID
|
||||
|
||||
posts.forEach(post => {
|
||||
// Process tags
|
||||
if (post.frontmatter?.tags && Array.isArray(post.frontmatter.tags)) {
|
||||
const tags = post.frontmatter.tags;
|
||||
const tagIds = Array.isArray(post.frontmatter.tagId)
|
||||
? post.frontmatter.tagId
|
||||
: post.frontmatter.tagId ? [post.frontmatter.tagId] : [];
|
||||
|
||||
// If tagId exists, use mapping between tagId and tag
|
||||
if (tagIds.length > 0 && tagIds.length === tags.length) {
|
||||
tags.forEach((tag: string, index: number) => {
|
||||
if (tag && tagIds[index]) {
|
||||
allTags.add(tag);
|
||||
tagMap.set(tag, tagIds[index]);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// If no tagId or lengths don't match, use tag name as ID
|
||||
tags.forEach((tag: string) => {
|
||||
if (tag) {
|
||||
allTags.add(tag);
|
||||
tagMap.set(tag, tag.toLowerCase());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return tagMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get base URL for blog based on language
|
||||
* @param lang - Current language
|
||||
* @returns Base URL string
|
||||
*/
|
||||
export function getBlogBaseUrl(lang: Lang): string {
|
||||
return lang === defaultLang ? '/blog' : `/${lang}/blog`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process raw blog post data from import.meta.glob
|
||||
* @param allPosts - Raw posts data from import.meta.glob
|
||||
* @param lang - Current language
|
||||
* @returns Processed blog posts array
|
||||
*/
|
||||
export function processRawBlogPosts(allPosts: Record<string, any>[] | any[], lang: Lang): BlogPost[] {
|
||||
// Process blog post data
|
||||
const posts: BlogPost[] = allPosts.map((post: any) => {
|
||||
const slug = post.url?.split('/').filter(Boolean).pop() || '';
|
||||
|
||||
// Default image if not specified in frontmatter
|
||||
const defaultImage = "https://images.unsplash.com/photo-1516321318423-f06f85e504b3?w=400&h=250&fit=crop&crop=center";
|
||||
|
||||
// Default read time text based on language
|
||||
const defaultReadTime = lang === 'zh' ? '5 分钟阅读' : '5 min read';
|
||||
|
||||
return {
|
||||
title: post.frontmatter.title,
|
||||
description: post.frontmatter.description || '',
|
||||
image: post.frontmatter.image || defaultImage,
|
||||
slug: slug,
|
||||
tags: post.frontmatter.tags || [],
|
||||
tagId: post.frontmatter.tagId || [],
|
||||
category: Array.isArray(post.frontmatter.category) ? post.frontmatter.category : post.frontmatter.category ? [post.frontmatter.category] : [],
|
||||
categoryId: Array.isArray(post.frontmatter.categoryId) ? post.frontmatter.categoryId : post.frontmatter.categoryId ? [post.frontmatter.categoryId] : [],
|
||||
date: post.frontmatter.date || post.frontmatter.pubDate || '',
|
||||
readTime: post.frontmatter.readTime || post.frontmatter.readingTime || defaultReadTime,
|
||||
url: post.url || '',
|
||||
};
|
||||
});
|
||||
|
||||
return posts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract post metadata for categories and tags
|
||||
* @param posts - Array of blog posts
|
||||
* @returns Array of post metadata
|
||||
*/
|
||||
export function extractPostMetadata(posts: any[]) {
|
||||
return posts.map((post: any) => ({
|
||||
category: post.frontmatter?.category || [],
|
||||
categoryId: post.frontmatter?.categoryId || [],
|
||||
tags: post.frontmatter?.tags || [],
|
||||
tagId: post.frontmatter?.tagId || []
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all blog posts with processing for a taxonomy page (category or tag)
|
||||
* @param lang - Current language
|
||||
* @param options - Additional options for processing
|
||||
* @returns Object containing processed posts and metadata
|
||||
*/
|
||||
export async function getTaxonomyPageData(lang: Lang, options?: {
|
||||
category?: string;
|
||||
tag?: string;
|
||||
}) {
|
||||
// Read all blog posts
|
||||
// Note: import.meta.glob only accepts literal strings, not variables
|
||||
let allPosts;
|
||||
|
||||
// Use specific glob patterns based on language
|
||||
if (lang === 'zh') {
|
||||
allPosts = await import.meta.glob('/src/pages/zh/blog/posts/*.{md,mdx}', { eager: true });
|
||||
} else {
|
||||
allPosts = await import.meta.glob('/src/pages/blog/posts/*.{md,mdx}', { eager: true });
|
||||
}
|
||||
|
||||
// Process blog post data
|
||||
const blogPosts = processRawBlogPosts(Object.values(allPosts), lang);
|
||||
|
||||
// Apply filters if specified
|
||||
let filteredPosts = blogPosts;
|
||||
|
||||
if (options?.category) {
|
||||
filteredPosts = filterPostsByCategory(filteredPosts, options.category);
|
||||
}
|
||||
|
||||
if (options?.tag) {
|
||||
filteredPosts = filterPostsByTag(filteredPosts, options.tag);
|
||||
}
|
||||
|
||||
// Sort posts by date
|
||||
const sortedBlogPosts = sortPostsByDate(filteredPosts);
|
||||
|
||||
// Extract categories and tags from all posts for sidebar
|
||||
const allPostsMetadata = extractPostMetadata(Object.values(allPosts));
|
||||
|
||||
// Get categories and tags for sidebar
|
||||
const categories = extractCategories(allPostsMetadata);
|
||||
const tags = extractTags(allPostsMetadata);
|
||||
|
||||
return {
|
||||
posts: sortedBlogPosts,
|
||||
categories,
|
||||
tags,
|
||||
allPosts
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user