From e1e91fcdda6155e65a05573b096fa7508d1cf927 Mon Sep 17 00:00:00 2001 From: Atdunbg Date: Thu, 2 Apr 2026 02:00:30 +0800 Subject: [PATCH] add gitea card render support, update about page --- astro.config.mjs | 2 + src/content/spec/about.md | 13 +++ src/plugins/rehype-component-gitea-card.mjs | 101 ++++++++++++++++++++ src/styles/markdown-extend.styl | 8 +- 4 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 src/plugins/rehype-component-gitea-card.mjs diff --git a/astro.config.mjs b/astro.config.mjs index b9ebfcc..c297a61 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -19,6 +19,7 @@ import { expressiveCodeConfig } from "./src/config.ts"; import { pluginCustomCopyButton } from "./src/plugins/expressive-code/custom-copy-button.js"; import { pluginLanguageBadge } from "./src/plugins/expressive-code/language-badge.ts"; import { AdmonitionComponent } from "./src/plugins/rehype-component-admonition.mjs"; +import { GiteaCardComponent } from "./src/plugins/rehype-component-gitea-card.mjs"; import { GithubCardComponent } from "./src/plugins/rehype-component-github-card.mjs"; import { parseDirectiveNode } from "./src/plugins/remark-directive-rehype.js"; import { remarkExcerpt } from "./src/plugins/remark-excerpt.js"; @@ -121,6 +122,7 @@ export default defineConfig({ { components: { github: GithubCardComponent, + gitea: GiteaCardComponent, note: (x, y) => AdmonitionComponent(x, y, "note"), tip: (x, y) => AdmonitionComponent(x, y, "tip"), important: (x, y) => AdmonitionComponent(x, y, "important"), diff --git a/src/content/spec/about.md b/src/content/spec/about.md index c25c067..5b6188f 100644 --- a/src/content/spec/about.md +++ b/src/content/spec/about.md @@ -1,11 +1,15 @@ # About Me ::github{repo="atdunbg/atdunbg"} +::gitea{repo="atdunbg/Prism"} 欢迎来到[Atdunbg](https://atdunbg.xyz)的小站, 这里是一个又菜又爱学的技术小白。 本人就读与一所郑州的不知名本科学院, 学的软件工程,目前已经大四了。 + + + ## 本站记录 > 2022 年 1月1日,本站问世,框架使用`hexo` + `butterfly` @@ -13,3 +17,12 @@ > 2025年 12月12日主题迁移至 `Redefine` > > 2026年 3月6日框架迁移至`Astro` , 主题使用`Fuwari` + + +## 为什么写博客 + +写博客对我来说,是记录,也是分享。 + +学习新东西的时候,把它写下来能帮自己理清思路。技术这东西,光看懂了不算,能讲清楚、写明白,才算真正消化。所以博客里大多是学习笔记和踩坑记录,不一定多深,但都是自己一步步琢磨出来的。 + +另外也是想有个地方和同样在折腾技术的人交流。代码可以开源,思路可以公开,踩过的坑别人能少走一次,那就挺好。 diff --git a/src/plugins/rehype-component-gitea-card.mjs b/src/plugins/rehype-component-gitea-card.mjs new file mode 100644 index 0000000..bda9f91 --- /dev/null +++ b/src/plugins/rehype-component-gitea-card.mjs @@ -0,0 +1,101 @@ +/// +import { h } from "hastscript"; + +/** + * Creates a Gitea Card component. + * + * @param {Object} properties - The properties of the component. + * @param {string} properties.repo - The Gitea repository in the format "owner/repo". + * @param {import('mdast').RootContent[]} children - The children elements of the component. + * @returns {import('mdast').Parent} The created Gitea Card component. + */ +export function GiteaCardComponent(properties, children) { + if (Array.isArray(children) && children.length !== 0) + return h("div", { class: "hidden" }, [ + 'Invalid directive. ("gitea" directive must be leaf type "::gitea{repo="owner/repo"}")', + ]); + + if (!properties.repo || !properties.repo.includes("/")) + return h( + "div", + { class: "hidden" }, + 'Invalid repository. ("repo" attribute must be in the format "owner/repo")', + ); + + const repo = properties.repo; + const cardUuid = `GC${Math.random().toString(36).slice(-6)}`; // 唯一标识 + + // 创建头像占位元素(Gitea API 也提供头像 URL) + const nAvatar = h(`div#${cardUuid}-avatar`, { class: "gc-avatar" }); + const nLanguage = h( + `span#${cardUuid}-language`, + { class: "gc-language" }, + "Waiting...", + ); + + const nTitle = h("div", { class: "gc-titlebar" }, [ + h("div", { class: "gc-titlebar-left" }, [ + h("div", { class: "gc-owner" }, [ + nAvatar, + h("div", { class: "gc-user" }, repo.split("/")[0]), + ]), + h("div", { class: "gc-divider" }, "/"), + h("div", { class: "gc-repo" }, repo.split("/")[1]), + ]), + h("div", { class: "gitea-logo" }), // 可以换成 Gitea 图标 + ]); + + const nDescription = h( + `div#${cardUuid}-description`, + { class: "gc-description" }, + "Waiting for Gitea API...", + ); + + const nStars = h(`div#${cardUuid}-stars`, { class: "gc-stars" }, "00K"); + const nForks = h(`div#${cardUuid}-forks`, { class: "gc-forks" }, "0K"); + // Gitea 可能没有 license 字段,可以去掉或显示其他信息 + const nLicense = h(`div#${cardUuid}-license`, { class: "gc-license" }, ""); + + const nScript = h( + `script#${cardUuid}-script`, + { type: "text/javascript", defer: true }, + ` + fetch('https://gitea.atdunbg.xyz/api/v1/repos/${repo}', { referrerPolicy: "no-referrer" }) + .then(response => response.json()) + .then(data => { + document.getElementById('${cardUuid}-description').innerText = data.description || "No description"; + document.getElementById('${cardUuid}-language').innerText = data.language || "Not specified"; + document.getElementById('${cardUuid}-forks').innerText = Intl.NumberFormat('en-us', { notation: "compact", maximumFractionDigits: 1 }).format(data.forks_count || 0).replaceAll("\\u202f", ""); + document.getElementById('${cardUuid}-stars').innerText = Intl.NumberFormat('en-us', { notation: "compact", maximumFractionDigits: 1 }).format(data.stars_count || 0).replaceAll("\\u202f", ""); + const avatarEl = document.getElementById('${cardUuid}-avatar'); + avatarEl.style.backgroundImage = 'url(' + data.owner.avatar_url + ')'; + avatarEl.style.backgroundColor = 'transparent'; + // 如果 Gitea API 返回 license 信息,可以显示 + // document.getElementById('${cardUuid}-license').innerText = data.license?.spdx_id || "no-license"; + document.getElementById('${cardUuid}-card').classList.remove("fetch-waiting"); + console.log("[GITEA-CARD] Loaded card for ${repo} | ${cardUuid}."); + }) + .catch(err => { + const c = document.getElementById('${cardUuid}-card'); + c?.classList.add("fetch-error"); + console.warn("[GITEA-CARD] (Error) Loading card for ${repo} | ${cardUuid}.", err); + }); + `, + ); + + return h( + `a#${cardUuid}-card`, + { + class: "card-gitea fetch-waiting no-styling", + href: `https://gitea.atdunbg.xyz/${repo}`, + target: "_blank", + repo, + }, + [ + nTitle, + nDescription, + h("div", { class: "gc-infobar" }, [nStars, nForks, nLicense, nLanguage]), + nScript, + ], + ); +} diff --git a/src/styles/markdown-extend.styl b/src/styles/markdown-extend.styl index 687be28..c7366f1 100644 --- a/src/styles/markdown-extend.styl +++ b/src/styles/markdown-extend.styl @@ -84,7 +84,7 @@ margin-right: auto max-width: 100% -a.card-github +a.card-github, a.card-gitea display: block background: var(--license-block-bg) position: relative @@ -206,7 +206,7 @@ a.card-github margin-right: 0 mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='31' height='32' viewBox='0 0 496 512'%3E%3Cpath fill='%23a1f7cb' d='M165.9 397.4c0 2-2.3 3.6-5.2 3.6c-3.3.3-5.6-1.3-5.6-3.6c0-2 2.3-3.6 5.2-3.6c3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9c2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9c.3 2 2.9 3.3 5.9 2.6c2.9-.7 4.9-2.6 4.6-4.6c-.3-1.9-3-3.2-5.9-2.9M244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2c12.8 2.3 17.3-5.6 17.3-12.1c0-6.2-.3-40.4-.3-61.4c0 0-70 15-84.7-29.8c0 0-11.4-29.1-27.8-36.6c0 0-22.9-15.7 1.6-15.4c0 0 24.9 2 38.6 25.8c21.9 38.6 58.6 27.5 72.9 20.9c2.3-16 8.8-27.1 16-33.7c-55.9-6.2-112.3-14.3-112.3-110.5c0-27.5 7.6-41.3 23.6-58.9c-2.6-6.5-11.1-33.3 2.6-67.9c20.9-6.5 69 27 69 27c20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27c13.7 34.7 5.2 61.4 2.6 67.9c16 17.7 25.8 31.5 25.8 58.9c0 96.5-58.9 104.2-114.8 110.5c9.2 7.9 17 22.9 17 46.4c0 33.7-.3 75.4-.3 83.6c0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252C496 113.3 383.5 8 244.8 8M97.2 352.9c-1.3 1-1 3.3.7 5.2c1.6 1.6 3.9 2.3 5.2 1c1.3-1 1-3.3-.7-5.2c-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9c1.6 1 3.6.7 4.3-.7c.7-1.3-.3-2.9-2.3-3.9c-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2c2.3 2.3 5.2 2.6 6.5 1c1.3-1.3.7-4.3-1.3-6.2c-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9c1.6 2.3 4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2c-1.4-2.3-4-3.3-5.6-2'/%3E%3C/svg%3E") -a.card-github.fetch-waiting +a.card-github.fetch-waiting, a.card-gitea.fetch-waiting pointer-events: none opacity: 0.7 transition: opacity 0.15s ease-in-out @@ -227,7 +227,7 @@ a.card-github.fetch-waiting .gc-description, .gc-infobar border-radius: 0.5rem -a.card-github.fetch-error +a.card-github.fetch-error, a.card-gitea.fetch-error pointer-events: all opacity: 1 @@ -239,7 +239,7 @@ a.card-github.fetch-error 100% opacity: 0.15 -.card-github, .gc-description, .gc-titlebar, .gc-stars, .gc-forks, .gc-license, .gc-avatar, .github-logo +.card-github, .card-gitea, .gc-description, .gc-titlebar, .gc-stars, .gc-forks, .gc-license, .gc-avatar, .github-logo transition-property: all transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1) transition-duration: 0.15s