Skip to content

Commit 0ae77d0

Browse files
committed
feat(blog): add clickable images that link to full-size versions
Adds a rehype plugin that wraps markdown images in anchor tags pointing to the original image. Images open in a new tab and have a subtle zoom-in cursor and hover effect to indicate clickability.
1 parent 128cc12 commit 0ae77d0

3 files changed

Lines changed: 60 additions & 1 deletion

File tree

astro.config.mjs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import { defineConfig } from 'astro/config';
33
import tailwindcss from '@tailwindcss/vite';
44
import sitemap from '@astrojs/sitemap';
5+
import rehypeImageLinks from './src/plugins/rehype-image-links.js';
6+
57
// https://astro.build/config
68
export default defineConfig({
79
site: 'https://www.codingwithcalvin.net',
@@ -14,6 +16,7 @@ export default defineConfig({
1416
shikiConfig: {
1517
theme: 'github-dark',
1618
wrap: true
17-
}
19+
},
20+
rehypePlugins: [rehypeImageLinks]
1821
}
1922
});

src/plugins/rehype-image-links.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { visit } from "unist-util-visit";
2+
3+
/**
4+
* Rehype plugin to wrap images in links to their full-size versions.
5+
* Skips images that are already wrapped in links.
6+
*/
7+
export default function rehypeImageLinks() {
8+
return (tree) => {
9+
visit(tree, "element", (node, index, parent) => {
10+
// Only process img elements
11+
if (node.tagName !== "img") return;
12+
13+
// Skip if already wrapped in a link
14+
if (parent?.tagName === "a") return;
15+
16+
// Skip if no src
17+
const src = node.properties?.src;
18+
if (!src) return;
19+
20+
// Create the wrapper anchor element
21+
const wrapper = {
22+
type: "element",
23+
tagName: "a",
24+
properties: {
25+
href: src,
26+
target: "_blank",
27+
rel: "noopener noreferrer",
28+
class: "image-link",
29+
},
30+
children: [node],
31+
};
32+
33+
// Replace the img with the wrapped version
34+
parent.children[index] = wrapper;
35+
});
36+
};
37+
}

src/styles/global.css

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,25 @@ code {
9595
margin-bottom: 1.5em;
9696
}
9797

98+
/* Clickable images */
99+
.prose a.image-link {
100+
display: block;
101+
text-decoration: none;
102+
transition: transform 0.2s ease, box-shadow 0.2s ease;
103+
}
104+
105+
.prose a.image-link:hover {
106+
text-decoration: none;
107+
transform: scale(1.01);
108+
box-shadow: 0 4px 20px rgba(51, 145, 203, 0.3);
109+
}
110+
111+
.prose a.image-link img {
112+
margin-top: 0;
113+
margin-bottom: 0;
114+
cursor: zoom-in;
115+
}
116+
98117
.prose h2 {
99118
margin-top: 2em;
100119
margin-bottom: 1em;

0 commit comments

Comments
 (0)