mirror of
https://github.com/Ad-closeNN/blog-fuwari.git
synced 2026-05-31 01:20:06 -04:00
feat(component): 加入总字数统计模块
This commit is contained in:
@@ -3,6 +3,7 @@ import { Icon } from "astro-icon/components";
|
||||
import { profileConfig } from "../../config";
|
||||
import { url } from "../../utils/url-utils";
|
||||
import ImageWrapper from "../misc/ImageWrapper.astro";
|
||||
import TotalWords from "./TotalWords.astro";
|
||||
|
||||
const config = profileConfig;
|
||||
---
|
||||
@@ -45,6 +46,8 @@ const config = profileConfig;
|
||||
</a>}
|
||||
</div>
|
||||
|
||||
<TotalWords />
|
||||
|
||||
<!-- 全站访问量统计 https://github.com/afoim/fuwari/blob/81f22decb17ff7ee1dd480c10773f7ba8f4df296/src/components/widget/Profile.astro -->
|
||||
<div class="text-center text-sm text-neutral-500 dark:text-neutral-400 mt-3 pt-3 border-t border-neutral-200 dark:border-neutral-700">
|
||||
<div class="flex items-center justify-center gap-1">
|
||||
@@ -74,18 +77,37 @@ const config = profileConfig;
|
||||
fetch("https://v1.hitokoto.cn")
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
// API 返回的字段是 data.text
|
||||
document.getElementById("hitokoto").innerText = data.hitokoto;
|
||||
const hitokotoElement = document.getElementById("hitokoto");
|
||||
if (hitokotoElement) {
|
||||
hitokotoElement.innerText = data.hitokoto;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("获取一言失败:", error);
|
||||
//document.getElementById("hitokoto").innerText = "获取失败,请稍后再试。";
|
||||
//失败后用内置的,成功了用别人的。
|
||||
document.getElementById("hitokoto").innerText = "再热情的心也经不起冷漠,再爱你的人也经不起冷落。";
|
||||
const hitokotoElement = document.getElementById("hitokoto");
|
||||
if (hitokotoElement) {
|
||||
hitokotoElement.innerText = "再热情的心也经不起冷漠,再爱你的人也经不起冷落。";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
type SiteStatsData = {
|
||||
pageviews?: {
|
||||
value?: number;
|
||||
};
|
||||
};
|
||||
|
||||
type BlogUmamiStore = {
|
||||
getStats: (key: string, createUrl: (websiteId: string) => string) => Promise<SiteStatsData | undefined>;
|
||||
};
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__blogUmami?: BlogUmamiStore;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取全站访问量统计
|
||||
async function loadSiteStats() {
|
||||
const statsElement = document.getElementById('site-stats');
|
||||
@@ -96,8 +118,8 @@ fetch("https://v1.hitokoto.cn")
|
||||
statsElement.dataset.umamiState = 'loading';
|
||||
|
||||
try {
|
||||
const umamiStore = window['__blogUmami'];
|
||||
const statsData = await umamiStore?.getStats('site:all', (websiteId) => {
|
||||
const umamiStore = window.__blogUmami;
|
||||
const statsData = await umamiStore?.getStats('site:all', (websiteId: string) => {
|
||||
const currentTimestamp = Date.now();
|
||||
return `https://umami.adclosenn.top/api/websites/${websiteId}/stats?startAt=0&endAt=${currentTimestamp}&unit=hour&timezone=${encodeURIComponent('Asia/Shanghai')}&compare=false`;
|
||||
});
|
||||
@@ -125,46 +147,46 @@ fetch("https://v1.hitokoto.cn")
|
||||
</script>
|
||||
<!-- 获取 Commit 信息 via API -->
|
||||
<script>
|
||||
type GithubCommit = {
|
||||
sha: string;
|
||||
html_url: string;
|
||||
commit: {
|
||||
message: string;
|
||||
committer: {
|
||||
date: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
async function loadCommitStats() {
|
||||
try {
|
||||
const statsElement = document.getElementById('github-commit'); // 查找 id
|
||||
const link = document.getElementById('github-commit-link'); // 查找 id
|
||||
|
||||
// 第一步:调用 API
|
||||
const statsElement = document.getElementById('github-commit');
|
||||
const link = document.getElementById('github-commit-link');
|
||||
|
||||
const githubResponse = await fetch(`https://api.github.com/repos/Ad-closeNN/blog-fuwari/commits?per_page=1`);
|
||||
|
||||
if (!githubResponse.ok) {
|
||||
throw new Error('获取信息失败');
|
||||
}
|
||||
|
||||
let Data = await githubResponse.json();
|
||||
Data = Data[0];
|
||||
// 第二步:获取 Commit 数据
|
||||
const latestCommit = Data;
|
||||
|
||||
const commitData = {
|
||||
hash: latestCommit.sha.slice(0, 7),
|
||||
fullHash: latestCommit.sha,
|
||||
message: latestCommit.commit.message.split('\n')[0],
|
||||
author: latestCommit.commit.author.name,
|
||||
date: latestCommit.commit.author.date,
|
||||
url: latestCommit.html_url
|
||||
};
|
||||
|
||||
|
||||
if (statsElement) {
|
||||
statsElement.textContent = `当前提交:${Data.sha.slice(0,7)}`;
|
||||
}
|
||||
|
||||
const data = (await githubResponse.json()) as GithubCommit[];
|
||||
const latestCommit = data[0];
|
||||
|
||||
if (link){
|
||||
// const gurl = "https://github.com/Ad-closeNN/blog-fuwari/commit/"+Data.sha;
|
||||
const gurl = "/info/";
|
||||
link.href = gurl;
|
||||
link.title = "("+Data.commit.committer.date + ")" + " " + Data.commit.message;
|
||||
if (!latestCommit) {
|
||||
throw new Error('未获取到提交信息');
|
||||
}
|
||||
|
||||
if (statsElement) {
|
||||
statsElement.textContent = `当前提交:${latestCommit.sha.slice(0, 7)}`;
|
||||
}
|
||||
|
||||
if (link instanceof HTMLAnchorElement) {
|
||||
const infoUrl = "/info/";
|
||||
link.href = infoUrl;
|
||||
link.title = `(${latestCommit.commit.committer.date}) ${latestCommit.commit.message}`;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取 Commit 信息失败:', error);
|
||||
console.error('获取 Commit 信息失败:', error);
|
||||
const statsElement = document.getElementById('github-commit');
|
||||
if (statsElement) {
|
||||
statsElement.textContent = '提交信息不可用';
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
import I18nKey from "@i18n/i18nKey";
|
||||
import { i18n } from "@i18n/translation";
|
||||
import { getTotalWords } from "@utils/content-utils";
|
||||
|
||||
const totalWords = await getTotalWords();
|
||||
const formattedTotalWords = totalWords.toLocaleString("zh-CN");
|
||||
---
|
||||
<div class="text-center text-sm text-neutral-500 dark:text-neutral-400 mt-3 pt-3 border-t border-neutral-200 dark:border-neutral-700">
|
||||
<div class="flex items-center justify-center gap-1">
|
||||
<Icon name="material-symbols:article-outline" class="text-base"></Icon>
|
||||
<span>总计 {formattedTotalWords} {i18n(I18nKey.wordsCount)}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -8,7 +8,7 @@
|
||||
::github{repo="afoim/fuwari"}
|
||||
|
||||
# 站点分流
|
||||
经过几个月的测试,**本站**之后将弃用 Netlify 托管,转而使用免费且更强大的 Cloudflare。之前使用过的分流测试版站点已移除。谢谢 Netlify,你好 Cloudflare!
|
||||
经过几个月的测试,**本站**之后将弃用 Netlify 托管,转而使用免费且更强大的 Cloudflare。之前使用过的分流测试版站点已移除,且博客域名已改为 `blog.adclosenn.top`。谢谢你 Netlify,你好 Cloudflare!
|
||||
|
||||
# 关于我
|
||||
一位住在 [中华人民共和国广西壮族自治区](https://baike.baidu.com/item/%E5%B9%BF%E8%A5%BF%E5%A3%AE%E6%97%8F%E8%87%AA%E6%B2%BB%E5%8C%BA/163178) 的学生。 [me.adclosenn.top](https://me.adclosenn.top)
|
||||
@@ -16,7 +16,7 @@
|
||||
## 联系方式
|
||||
电子邮箱:[admin@adclosenn.top](mailto:admin@adclosenn.top)
|
||||
Discord:https://discord.com/users/1068060784300658688
|
||||
BlueSky:https://bsky.app/profile/adclosenn.top
|
||||
X:https://x.com/Ad_closeNN
|
||||
|
||||
# 关于本站
|
||||
## 字体
|
||||
|
||||
@@ -92,7 +92,8 @@ const customcover = entry.data.customcover;
|
||||
data-pagefind-body data-pagefind-weight="10" data-pagefind-meta="title"
|
||||
class="transition w-full block font-bold mb-3
|
||||
text-3xl md:text-[2.25rem]/[2.75rem]
|
||||
text-black/90 dark:text-white/90
|
||||
text-[var(--primary)]
|
||||
underline decoration-[3px] decoration-[var(--primary)] underline-offset-[0.45rem]
|
||||
md:before:w-1 before:h-5 before:rounded-md before:bg-[var(--primary)]
|
||||
before:absolute before:top-[0.75rem] before:left-[-1.125rem]
|
||||
">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type CollectionEntry, getCollection } from "astro:content";
|
||||
import { render, type CollectionEntry, getCollection } from "astro:content";
|
||||
import I18nKey from "@i18n/i18nKey";
|
||||
import { i18n } from "@i18n/translation";
|
||||
import { getCategoryUrl } from "@utils/url-utils.ts";
|
||||
@@ -46,6 +46,24 @@ export async function getSortedPostsList(): Promise<PostForList[]> {
|
||||
|
||||
return sortedPostsList;
|
||||
}
|
||||
|
||||
let totalWordsCache: number | undefined;
|
||||
|
||||
export async function getTotalWords(): Promise<number> {
|
||||
if (totalWordsCache !== undefined) {
|
||||
return totalWordsCache;
|
||||
}
|
||||
|
||||
const posts = await getRawSortedPosts();
|
||||
const renderedPosts = await Promise.all(posts.map((post) => render(post)));
|
||||
const totalWords = renderedPosts.reduce((sum, { remarkPluginFrontmatter }) => {
|
||||
const words = Number(remarkPluginFrontmatter?.words ?? 0);
|
||||
return sum + (Number.isFinite(words) ? words : 0);
|
||||
}, 0);
|
||||
|
||||
totalWordsCache = totalWords;
|
||||
return totalWords;
|
||||
}
|
||||
export type Tag = {
|
||||
name: string;
|
||||
count: number;
|
||||
|
||||
Reference in New Issue
Block a user