Files
blog-code/src/components/PostMeta.astro
2025-12-08 01:03:07 +08:00

171 lines
6.7 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
import { Icon } from "astro-icon/components";
import { umamiConfig } from "../config";
import I18nKey from "../i18n/i18nKey";
import { i18n } from "../i18n/translation";
import { formatDateToYYYYMMDD } from "../utils/date-utils";
import { getCategoryUrl, getTagUrl } from "../utils/url-utils";
// 解析 umami
const umamiEnabled = umamiConfig.enabled || false;
const umamiWebsiteId =
umamiConfig.scripts.match(/data-website-id="([^"]+)"/)?.[1] || "";
const umamiApiKey = umamiConfig.apiKey || "";
const umamiBaseUrl = umamiConfig.baseUrl || "";
export interface Props {
published: Date;
updated?: Date;
category?: string;
tags?: string[];
hideUpdateDate?: boolean;
hideTagsForMobile?: boolean;
isHome?: boolean;
className?: string;
id?: string;
showOnlyBasicMeta?: boolean; // 新增属性,控制是否只显示基本元数据
words?: number; // 字数统计
minutes?: number; // 阅读时间(分钟)
showWordCount?: boolean; // 是否显示字数统计
}
const {
published,
updated,
category,
tags,
hideUpdateDate,
hideTagsForMobile,
isHome,
className = "",
id,
showOnlyBasicMeta = false, // 默认为false保持原有行为
words,
// minutes,
showWordCount = false, // 默认不显示字数统计
} = Astro.props;
---
<div class:list={["flex flex-wrap text-neutral-500 dark:text-neutral-400 items-center gap-4 gap-x-4 gap-y-2", className]}>
<!-- publish date -->
<div class="flex items-center">
<div class="meta-icon">
<Icon name="material-symbols:calendar-today-outline-rounded" class="text-xl"></Icon>
</div>
<span class="text-50 text-sm font-medium">{formatDateToYYYYMMDD(published)}</span>
</div>
<!-- update date -->
{!hideUpdateDate && updated && updated.getTime() !== published.getTime() && (
<div class="flex items-center">
<div class="meta-icon">
<Icon name="material-symbols:edit-calendar-outline-rounded" class="text-xl"></Icon>
</div>
<span class="text-50 text-sm font-medium">{formatDateToYYYYMMDD(updated)}</span>
</div>
)}
<!-- categories -->
<div class="flex items-center">
<div class="meta-icon">
<Icon name="material-symbols:book-2-outline-rounded" class="text-xl"></Icon>
</div>
<div class="flex flex-row flex-nowrap items-center">
<a href={getCategoryUrl(category || '')} aria-label={`View all posts in the ${category} category`}
class="link-lg transition text-50 text-sm font-medium
hover:text-[var(--primary)] dark:hover:text-[var(--primary)] whitespace-nowrap">
{category || i18n(I18nKey.uncategorized)}
</a>
</div>
</div>
<!-- word count -->
{showWordCount && words && (
<div class="flex items-center">
<div class="meta-icon">
<Icon name="material-symbols:article-outline-rounded" class="text-xl"></Icon>
</div>
<span class="text-50 text-sm font-medium">
{words} {words > 1 ? i18n(I18nKey.wordsCount) : i18n(I18nKey.wordCount)}
</span>
</div>
)}
<!-- tags (只有在不显示基本元数据时才显示) -->
{!showOnlyBasicMeta && (
<div class:list={["items-center", {"flex": !hideTagsForMobile, "hidden md:flex": hideTagsForMobile}]}>
<div class="meta-icon">
<Icon name="material-symbols:tag-rounded" class="text-xl"></Icon>
</div>
<div class="flex flex-row flex-nowrap items-center">
{(tags && tags.length > 0) && tags.map((tag, i) => (
<>
<div class:list={[{"hidden": i == 0}, "mx-1.5 text-[var(--meta-divider)] text-sm"]}>/</div>
<a href={getTagUrl(tag)} aria-label={`View all posts with the ${tag.trim()} tag`}
class="link-lg transition text-50 text-sm font-medium
hover:text-[var(--primary)] dark:hover:text-[var(--primary)] whitespace-nowrap">
{tag.trim()}
</a>
</>
))}
{!(tags && tags.length > 0) && <div class="transition text-50 text-sm font-medium">{i18n(I18nKey.noTags)}</div>}
</div>
</div>
)}
<!-- 访问量首页不显示且umami.enabled为true时显示 -->
{!isHome && umamiEnabled && id && (
<div class="flex items-center">
<div class="meta-icon">
<Icon name="material-symbols:visibility-outline-rounded" class="text-xl"></Icon>
</div>
<span class="text-50 text-sm font-medium" id="page-views-display">统计加载中...</span>
</div>
)}
</div>
<!-- 只有在非首页且启用umami且有slug时才加载脚本 -->
{!isHome && umamiEnabled && id && (
<script is:inline define:vars={{ id, umamiBaseUrl, umamiApiKey, umamiWebsiteId, umamiConfig }}>
// 客户端统计文案生成函数
function generateStatsText(pageViews, visitors) {
return `浏览量 ${pageViews} · 访客 ${visitors}`;
}
// 获取访问量统计
async function fetchPageViews(isRetry = false) {
// @ts-ignore
if (!umamiConfig.enabled || !umamiWebsiteId || !id || !isRetry) return;
try {
// 构造文章页面的URL路径
const pageUrl = `/posts/${id}/`;
// 调用全局工具获取特定页面的 Umami 统计数据
const stats = await getUmamiPageStats(umamiBaseUrl, umamiApiKey, umamiWebsiteId, pageUrl);
// 从返回的数据中提取页面浏览量和访客数
const pageViews = stats.pageviews || 0;
const visitors = stats.visitors || 0;
const displayElement = document.getElementById('page-views-display');
if (displayElement) {
displayElement.textContent = generateStatsText(pageViews, visitors);
}
} catch (error) {
console.error('Error fetching page views:', error);
const displayElement = document.getElementById('page-views-display');
if (displayElement) {
displayElement.textContent = '统计不可用';
}
}
}
// 页面加载完成后获取统计数据
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', fetchPageViews);
} else {
fetchPageViews();
}
</script>
)}