feat: enhance file name transformer with additional options (#555)

- Add v2 badge-style option as alternative to v1 tab-style
- v2 features: border, rounded corners, positioned with CSS custom property
- v1 features: tab-style with rounded top corners, muted background
- Add hideDot option to control green dot indicator visibility
- Include comprehensive JSDoc documentation with usage examples
- Support both styling variants with configuration parameters
This commit is contained in:
Sat Naing
2025-07-09 23:35:41 +07:00
committed by GitHub
parent 5d47275687
commit c863c8219d
4 changed files with 50 additions and 12 deletions
+2 -2
View File
@@ -27,7 +27,7 @@ export default defineConfig({
defaultColor: false, defaultColor: false,
wrap: false, wrap: false,
transformers: [ transformers: [
transformerFileName(), transformerFileName({ style: "v2", hideDot: false }),
transformerNotationHighlight(), transformerNotationHighlight(),
transformerNotationWordHighlight(), transformerNotationWordHighlight(),
transformerNotationDiff({ matchAlgorithm: "v3" }), transformerNotationDiff({ matchAlgorithm: "v3" }),
@@ -35,7 +35,7 @@ export default defineConfig({
}, },
}, },
vite: { vite: {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line
// @ts-ignore // @ts-ignore
// This will be fixed in Astro 6 with Vite 7 support // This will be fixed in Astro 6 with Vite 7 support
// See: https://github.com/withastro/astro/issues/14030 // See: https://github.com/withastro/astro/issues/14030
+11 -2
View File
@@ -234,9 +234,18 @@ const nextPost =
const wrapper = document.createElement("div"); const wrapper = document.createElement("div");
wrapper.style.position = "relative"; wrapper.style.position = "relative";
// Check if --file-name-offset custom property exists
const computedStyle = getComputedStyle(codeBlock);
const hasFileNameOffset =
computedStyle.getPropertyValue("--file-name-offset").trim() !== "";
// Determine the top positioning class
const topClass = hasFileNameOffset
? "top-(--file-name-offset)"
: "-top-3";
const copyButton = document.createElement("button"); const copyButton = document.createElement("button");
copyButton.className = copyButton.className = `copy-code absolute end-3 ${topClass} rounded bg-muted border border-muted px-2 py-1 text-xs leading-4 text-foreground font-medium`;
"copy-code absolute end-3 top-3 rounded bg-muted/80 px-2 py-1 text-xs leading-4 text-foreground font-medium";
copyButton.innerHTML = copyButtonLabel; copyButton.innerHTML = copyButtonLabel;
codeBlock.setAttribute("tabindex", "0"); codeBlock.setAttribute("tabindex", "0");
codeBlock.appendChild(copyButton); codeBlock.appendChild(copyButton);
+1 -1
View File
@@ -16,7 +16,7 @@ html[data-theme="dark"] {
--background: #212737; --background: #212737;
--foreground: #eaedf3; --foreground: #eaedf3;
--accent: #ff6b01; --accent: #ff6b01;
--muted: #343f60bf; --muted: #343f60;
--border: #ab4b08; --border: #ab4b08;
} }
+36 -7
View File
@@ -1,5 +1,26 @@
export const transformerFileName = () => ({ /**
* CustomShiki transformer that adds file name labels to code blocks.
*
* This transformer looks for the `file="filename"` meta attribute in code blocks
* and creates a styled label showing the filename. It supports two different
* styling options and can optionally hide the green dot indicator.
*
* @param {Object} options - Configuration options for the transformer
* @param {string} [options.style="v2"] - The styling variant to use
* - `"v1"`: Tab-style with rounded top corners, positioned at top-left
* - `"v2"`: Badge-style with border, positioned at top-left with offset
* @param {boolean} [options.hideDot=false] - Whether to hide the green dot indicator
*/
export const transformerFileName = ({
style = "v2",
hideDot = false,
} = {}) => ({
pre(node) { pre(node) {
// Add CSS custom property to the node
const fileNameOffset = style === "v1" ? "0.75rem" : "-0.75rem";
node.properties.style =
(node.properties.style || "") + `--file-name-offset: ${fileNameOffset};`;
const raw = this.options.meta?.__raw?.split(" "); const raw = this.options.meta?.__raw?.split(" ");
if (!raw) return; if (!raw) return;
@@ -15,15 +36,25 @@ export const transformerFileName = () => ({
if (!file) return; if (!file) return;
// Add additional margin to code block
this.addClassToHast(
node,
`mt-8 ${style === "v1" ? "rounded-tl-none" : ""}`
);
// Add file name to code block
node.children.push({ node.children.push({
type: "element", type: "element",
tagName: "span", tagName: "span",
properties: { properties: {
class: [ class: [
"px-2 py-1", "absolute py-1 text-foreground text-xs font-medium leading-4",
"absolute left-0 -top-6", hideDot
"rounded-t-md border border-b-0", ? "px-2"
"bg-muted/50 text-foreground text-xs font-medium leading-4", : "pl-4 pr-2 before:inline-block before:size-1 before:bg-green-500 before:rounded-full before:absolute before:top-[45%] before:left-2",
style === "v1"
? "left-0 -top-6 rounded-t-md border border-b-0 bg-muted/50"
: "left-2 top-(--file-name-offset) border rounded-md bg-background",
], ],
}, },
children: [ children: [
@@ -33,7 +64,5 @@ export const transformerFileName = () => ({
}, },
], ],
}); });
this.addClassToHast(node, "mt-12 rounded-tl-none");
}, },
}); });