diff --git a/astro.config.mjs b/astro.config.mjs index 621c415..c769fd1 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -19,6 +19,7 @@ import { expressiveCodeConfig } from "./src/config.ts"; import { pluginLanguageBadge } from "./src/plugins/expressive-code/language-badge.ts"; import { AdmonitionComponent } from "./src/plugins/rehype-component-admonition.mjs"; import { GithubCardComponent } from "./src/plugins/rehype-component-github-card.mjs"; +import { GitlabCardComponent } from "./src/plugins/rehype-component-gitlab-card.mjs"; import { parseDirectiveNode } from "./src/plugins/remark-directive-rehype.js"; import { remarkExcerpt } from "./src/plugins/remark-excerpt.js"; import { remarkReadingTime } from "./src/plugins/remark-reading-time.mjs"; @@ -120,6 +121,7 @@ export default defineConfig({ { components: { github: GithubCardComponent, + gitlab: GitlabCardComponent, 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/plugins/rehype-component-gitlab-card.mjs b/src/plugins/rehype-component-gitlab-card.mjs new file mode 100644 index 0000000..1fc68f4 --- /dev/null +++ b/src/plugins/rehype-component-gitlab-card.mjs @@ -0,0 +1,100 @@ +/// +import { h } from "hastscript"; + +/** + * Creates a GitLab Card component. + * + * @param {Object} properties - The properties of the component. + * @param {string} properties.repo - The Gitlab repository in the format "owner/repo". + * @param {import('mdast').RootContent[]} children - The children elements of the component. + * @returns {import('mdast').Parent} The created GitHub Card component. + */ +export function GitlabCardComponent(properties, children) { + if (Array.isArray(children) && children.length !== 0) + return h("div", { class: "" }, [ + 'Invalid directive. ("gitlab" directive must be leaf type "::gitlab{repo="owner/repo"}")', + ]); + + if (!properties.repo || !properties.repo.includes("/")) + return h( + "div", + { class: "" }, + 'Invalid repository. ("repo" attributte must be in the format "owner/repo")', + ); + + const repo = properties.repo; + const repoE = repo.replace("/", "%2F"); // encoding by replace / to %2F + const cardUuid = `GC${Math.random().toString(36).slice(-6)}`; // Collisions are not important + + 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: "github-logo" }), + ]); + + const nDescription = h( + `div#${cardUuid}-description`, + { class: "gc-description" }, + "Waiting for gitlab.com api...", + ); + + const nStars = h(`div#${cardUuid}-stars`, { class: "gc-stars" }, "00K"); + const nForks = h(`div#${cardUuid}-forks`, { class: "gc-forks" }, "0K"); + // const nLicense = h(`div#${cardUuid}-license`, { class: "gc-license" }, "0K"); + + console.log(`https://gitlab.com/api/v4/projects/${repoE}`); + + const nScript = h( + `script#${cardUuid}-script`, + { type: "text/javascript", defer: true }, + ` + fetch('https://gitlab.com/api/v4/projects/${repoE}', { referrerPolicy: "no-referrer" }).then(response => response.json()).then(data => { + console.log(data); + document.getElementById('${cardUuid}-description').innerText = data.description?.replace(/:[a-zA-Z0-9_]+:/g, '') || "Description not set"; + document.getElementById('${cardUuid}-language').innerText = data.language; + document.getElementById('${cardUuid}-forks').innerText = Intl.NumberFormat('en-us', { notation: "compact", maximumFractionDigits: 1 }).format(data.forks_count).replaceAll("\u202f", ''); + document.getElementById('${cardUuid}-stars').innerText = Intl.NumberFormat('en-us', { notation: "compact", maximumFractionDigits: 1 }).format(data.star_count).replaceAll("\u202f", ''); + const avatarEl = document.getElementById('${cardUuid}-avatar'); + avatarEl.style.backgroundImage = 'url(' + data.owner.avatar_url + ')'; + avatarEl.style.backgroundColor = 'transparent'; + // document.getElementById('${cardUuid}-license').innerText = data.license?.spdx_id || "no-license"; + document.getElementById('${cardUuid}-card').classList.remove("fetch-waiting"); + console.log("[GITLAB-CARD] Loaded card for ${repo} | ${cardUuid}.") + }).catch(err => { + const c = document.getElementById('${cardUuid}-card'); + c?.classList.add("fetch-error"); + console.error("[GITLAB-CARD] (Error) Loading card for ${repo} | ${cardUuid}."); + console.error(err); + }) + `, + ); + + return h( + `a#${cardUuid}-card`, + { + class: "card-github fetch-waiting no-styling", + href: `https://gitlab.com/${repo}`, + target: "_blank", + repo, + }, + [ + nTitle, + nDescription, + h("div", { class: "gc-infobar" }, [nStars, nForks]), + nScript, + ], + ); +}