--- import { getCollection } from "astro:content"; import { Icon } from "astro-icon/components"; import * as fs from "node:fs"; import * as path from "node:path"; import { createHighlighter } from "shiki"; import { unified } from "unified"; import remarkParse from "remark-parse"; import remarkRehype from "remark-rehype"; import rehypeSlug from "rehype-slug"; import rehypeAutolinkHeadings from "rehype-autolink-headings"; import rehypeStringify from "rehype-stringify"; import { icons as heroicons } from "@iconify-json/heroicons"; import { getIconData, iconToSVG } from "@iconify/utils"; import BaseLayout from "../../../layouts/BaseLayout.astro"; import ThemeToggle from "../../../components/ThemeToggle.astro"; import { config } from "../../../config"; // Get the link icon SVG from heroicons for use in anchor links const linkIconData = getIconData(heroicons, "link-20-solid"); const linkIconSvg = linkIconData ? iconToSVG(linkIconData) : null; // Parse the icon body into hast nodes for rehype function parseIconBody(body: string): import("hast").ElementContent[] { // Simple regex-based parser for SVG path/g elements const elements: import("hast").ElementContent[] = []; const tagRegex = /<(\w+)([^>]*)(?:\/>|>([\s\S]*?)<\/\1>)/g; let match; while ((match = tagRegex.exec(body)) !== null) { const [, tagName, attrs, children] = match; const properties: Record = {}; // Parse attributes const attrRegex = /(\w+(?:-\w+)*)="([^"]*)"/g; let attrMatch; while ((attrMatch = attrRegex.exec(attrs)) !== null) { properties[attrMatch[1]] = attrMatch[2]; } elements.push({ type: "element", tagName, properties, children: children ? parseIconBody(children) : [], }); } return elements; } export async function getStaticPaths() { const specs = await getCollection("spec"); return specs.map((spec) => ({ params: { version: spec.data.version }, props: { spec }, })); } const { spec } = Astro.props; const version = spec.data.version; // Read the markdown file const filePath = path.join(process.cwd(), "src/content/spec", `${version}.md`); const content = fs.readFileSync(filePath, "utf-8"); // Remove frontmatter const markdown = content.replace(/^---[\s\S]*?---\n/, ""); // Create syntax highlighter for code view const highlighter = await createHighlighter({ themes: ["github-light", "github-dark"], langs: ["markdown"], }); const highlightedHtml = highlighter.codeToHtml(markdown, { lang: "markdown", themes: { light: "github-light", dark: "github-dark", }, }); // Build the anchor link icon content from the heroicons data const anchorIconContent = linkIconSvg ? { type: "element" as const, tagName: "svg", properties: { className: ["anchor-icon"], viewBox: `0 0 ${linkIconSvg.attributes.width} ${linkIconSvg.attributes.height}`, fill: "currentColor", "aria-hidden": "true", }, children: parseIconBody(linkIconSvg.body), } : { type: "text" as const, value: "#" }; // Render markdown to HTML for preview view const previewHtml = await unified() .use(remarkParse) .use(remarkRehype) .use(rehypeSlug) .use(rehypeAutolinkHeadings, { behavior: "append", properties: { className: ["anchor-link"], ariaLabel: "Link to this section", }, content: anchorIconContent, }) .use(rehypeStringify) .process(markdown) .then((file) => String(file)); ---
Markdown v{version}

git-common-flow-v{version}.md

Copied!