From 17f144c2c940590a92348e06c2c3a974b298704e Mon Sep 17 00:00:00 2001 From: Clas Wen Date: Tue, 28 Jan 2025 13:39:00 +0800 Subject: [PATCH] move plugins --- astro.config.mts | 210 +------------------------------------------ src/plugins/cover.ts | 30 +++++++ src/plugins/theme.ts | 179 ++++++++++++++++++++++++++++++++++++ src/utils/image.ts | 3 +- 4 files changed, 213 insertions(+), 209 deletions(-) create mode 100644 src/plugins/cover.ts create mode 100644 src/plugins/theme.ts diff --git a/astro.config.mts b/astro.config.mts index 3d0a3be..29d2d89 100644 --- a/astro.config.mts +++ b/astro.config.mts @@ -1,220 +1,16 @@ -// @ts-check - import { defineConfig } from "astro/config" import { SITE_URL } from "./src/consts" import vue from "@astrojs/vue" -import { visit } from "unist-util-visit" import tailwind from "@astrojs/tailwind" import react from "@astrojs/react" -import md5 from "md5" -import { type RehypePlugin } from "@astrojs/markdown-remark" -import path from "path" -import { convertImageToBase64URL } from "./src/utils/image" - -function pipeline() { - return [ - () => tree => { - visit(tree, "element", (node, index) => { - if (node.tagName === "p" && node.children[0].tagName === "img") { - node.tagName = "figure" - let img = node.children[0] - let sign = md5(img.properties.src) - let data = img.properties.alt.split("|") - let alt = data[0] - let size = "big" - if (data.length > 1) { - size = data[1] - } - let classes = ["image component image-full-bleed body-copy-wide nr-scroll-animation nr-scroll-animation--on"] - classes.push(`image-${size}`) - node.properties.className = classes - node.children = [ - { - type: "element", - tagName: "div", - properties: { - className: ["component-content"], - }, - children: [ - { - type: "element", - tagName: "div", - properties: { - className: ["image-share-sheet"], - }, - children: [ - { - type: "element", - tagName: "div", - properties: { - className: [`image image-loaded image-asset image-${sign}`], - id: `lht${sign}`, - }, - children: [ - { - type: "element", - tagName: "picture", - properties: { - className: ["picture"], - }, - children: [ - { - type: "element", - tagName: "img", - properties: { - src: img.properties.src, - alt: alt, - className: ["picture-image"], - }, - }, - ], - }, - ], - }, - ], - }, - { - type: "element", - tagName: "div", - properties: { - className: ["image-description"], - }, - children: [ - { - type: "element", - tagName: "div", - properties: { - className: ["image-caption"], - }, - children: [ - { - type: "text", - value: alt, - }, - ], - }, - ], - }, - ], - }, - ] - } - }) - }, - () => tree => { - tree.children.forEach(node => { - if (node.type === "raw") { - node.value = `
${node.value}
` - // node.value = node.value.replace(/astro-code/g, 'astro-code') - } - }) - }, - () => tree => { - for (let i = 0; i < tree.children.length; i++) { - const node = tree.children[i] - if (node.type === "element" && ["p", "h1", "h2", "h3", "h4", "h5", "h6", "table"].includes(node.tagName)) { - let next = tree.children[i + 1] - const nodes = [node] - while (next && !["figure"].includes(next.tagName) && next.type != "raw") { - nodes.push(next) - next = tree.children[tree.children.indexOf(next) + 1] - } - if (nodes.length > 1) { - // rename label - nodes.forEach(node => { - if (node.tagName === "p") { - node.properties.className = ["page-body-copy"] - node.tagName = "div" - } - if (["h1", "h2", "h3", "h4", "h5", "h6"].includes(node.tagName)) { - node.properties.className = ["page-body-header"] - } - }) - tree.children.splice(i, nodes.length, { - type: "element", - tagName: "div", - properties: { - className: ["page-body text component"], - }, - children: [ - { - type: "element", - tagName: "div", - properties: { - className: ["component-content"], - }, - children: nodes, - }, - ], - }) - } - } - } - }, - () => tree => { - const len = tree.children.length - for (let index = 0; index < len; index++) { - const node = tree.children[index] - if (node.type === "element" && node.tagName === "figure") { - tree.children.splice(index, 0, { - type: "element", - tagName: "div", - properties: { - className: ["tertiary-nav component"], - }, - children: [ - { - type: "element", - tagName: "div", - properties: { - className: ["component-content"], - }, - }, - ], - }) - index++ - } - } - }, - ] -} - -const handleLocalCoverPlugin: RehypePlugin = () => { - return async (tree, file) => { - const filePath = file.history[0] - type AstroData = { - frontmatter: { - cover: - | { - url: string - } - | string - | undefined - } - } - const astroData = file.data.astro as AstroData - if (!astroData.frontmatter.cover) { - return - } - const coverUrl = typeof astroData.frontmatter.cover === "string" ? astroData.frontmatter.cover : astroData.frontmatter.cover.url - if (coverUrl.includes("http")) { - return - } - const url = path.resolve(path.dirname(filePath), coverUrl) - const dataURL = await convertImageToBase64URL(url) - if (typeof astroData.frontmatter.cover === "string") { - astroData.frontmatter.cover = dataURL - } else { - astroData.frontmatter.cover.url = dataURL - } - } -} +import { handleLocalCoverPlugin } from "./src/plugins/cover" +import { themePipeline } from "./src/plugins/theme" // https://astro.build/config export default defineConfig({ site: SITE_URL, markdown: { - rehypePlugins: [handleLocalCoverPlugin, ...pipeline()], + rehypePlugins: [handleLocalCoverPlugin, ...themePipeline], syntaxHighlight: "prism", }, integrations: [ diff --git a/src/plugins/cover.ts b/src/plugins/cover.ts new file mode 100644 index 0000000..4f17648 --- /dev/null +++ b/src/plugins/cover.ts @@ -0,0 +1,30 @@ +import path from "path" +import { type RehypePlugin } from "@astrojs/markdown-remark" +import { convertImageToBase64URL } from "../utils/image" + +export const handleLocalCoverPlugin: RehypePlugin = () => { + return async (tree, file) => { + const filePath = file.history[0] + type AstroData = { + frontmatter: { + cover: { url: string } | string | undefined + } + } + const astroData = file.data.astro as AstroData + if (!astroData.frontmatter.cover) { + return + } + const coverUrl = typeof astroData.frontmatter.cover === "string" ? astroData.frontmatter.cover : astroData.frontmatter.cover.url + if (coverUrl.includes("http")) { + return + } + const url = path.resolve(path.dirname(filePath), coverUrl) + const dataURL = await convertImageToBase64URL(url) + if (typeof astroData.frontmatter.cover === "string") { + astroData.frontmatter.cover = dataURL + } + else { + astroData.frontmatter.cover.url = dataURL + } + } +} diff --git a/src/plugins/theme.ts b/src/plugins/theme.ts new file mode 100644 index 0000000..1eb2b13 --- /dev/null +++ b/src/plugins/theme.ts @@ -0,0 +1,179 @@ +import { type RehypePlugin } from "@astrojs/markdown-remark" +import type { RehypePlugins } from "astro" +import { visit } from "unist-util-visit" +import md5 from "md5" + +export const addSeparator: RehypePlugin = () => + (tree) => { + const len = tree.children.length + for (let index = 0; index < len; index++) { + const node = tree.children[index] + if (node.type === "element" && node.tagName === "figure") { + tree.children.splice(index, 0, { + type: "element", + tagName: "div", + properties: { + className: ["tertiary-nav component"], + }, + children: [ + { + type: "element", + tagName: "div", + properties: { + className: ["component-content"], + }, + children: [], + }, + ], + }) + index++ + } + } + } +const image: RehypePlugin = () => (tree) => { + visit(tree, "element", (node) => { + if (node.tagName === "p" && node.children[0].tagName === "img") { + node.tagName = "figure" + const img = node.children[0] + const sign = md5(img.properties.src) + const data = img.properties.alt.split("|") + const alt = data[0] + let size = "big" + if (data.length > 1) { + size = data[1] + } + const classes = ["image component image-full-bleed body-copy-wide nr-scroll-animation nr-scroll-animation--on"] + classes.push(`image-${size}`) + node.properties.className = classes + node.children = [ + { + type: "element", + tagName: "div", + properties: { + className: ["component-content"], + }, + children: [ + { + type: "element", + tagName: "div", + properties: { + className: ["image-share-sheet"], + }, + children: [ + { + type: "element", + tagName: "div", + properties: { + className: [`image image-loaded image-asset image-${sign}`], + id: `lht${sign}`, + }, + children: [ + { + type: "element", + tagName: "picture", + properties: { + className: ["picture"], + }, + children: [ + { + type: "element", + tagName: "img", + properties: { + src: img.properties.src, + alt: alt, + className: ["picture-image"], + }, + }, + ], + }, + ], + }, + ], + }, + { + type: "element", + tagName: "div", + properties: { + className: ["image-description"], + }, + children: [ + { + type: "element", + tagName: "div", + properties: { + className: ["image-caption"], + }, + children: [ + { + type: "text", + value: alt, + }, + ], + }, + ], + }, + ], + }, + ] + } + }) +} + +const code: RehypePlugin = () => (tree) => { + tree.children.forEach((node) => { + if (node.type === "raw") { + node.value = `
${node.value}
` + // node.value = node.value.replace(/astro-code/g, 'astro-code') + } + }) +} + +const body: RehypePlugin = () => (tree) => { + for (let i = 0; i < tree.children.length; i++) { + const node = tree.children[i] + if (node.type === "element" && ["p", "h1", "h2", "h3", "h4", "h5", "h6", "table"].includes(node.tagName)) { + let next = tree.children[i + 1] + const nodes = [node] + while (next && !["figure"].includes(next.tagName) && next.type != "raw") { + nodes.push(next) + next = tree.children[tree.children.indexOf(next) + 1] + } + if (nodes.length > 1) { + // rename label + nodes.forEach((node) => { + if (node.tagName === "p") { + node.properties.className = ["page-body-copy"] + node.tagName = "div" + } + if (["h1", "h2", "h3", "h4", "h5", "h6"].includes(node.tagName)) { + node.properties.className = ["page-body-header"] + } + }) + tree.children.splice(i, nodes.length, { + type: "element", + tagName: "div", + properties: { + className: ["page-body text component"], + }, + children: [ + { + type: "element", + tagName: "div", + properties: { + className: ["component-content"], + }, + children: nodes, + }, + ], + }) + } + } + } +} + +export const themePipeline: RehypePlugins = [ + addSeparator, + image, + code, + body, +] diff --git a/src/utils/image.ts b/src/utils/image.ts index 86c7ba1..11b8e4d 100644 --- a/src/utils/image.ts +++ b/src/utils/image.ts @@ -7,10 +7,9 @@ export const convertImageToBase64URL = async (filename: Filename, imageType: Ima try { const buffer = await readFile(filename) const base64String = Buffer.from(buffer).toString("base64") - // console.log(`base64String`, base64String.slice(0, 100)); return `data:image/${imageType};base64,${base64String}` } catch (error) { - throw new Error(`file ${filename} no exist ❌`) + throw new Error(`file ${filename} no exist ❌`, error) } }