diff --git a/.vscode/settings.json b/.vscode/settings.json
index 3c8423d..d21d96a 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -108,10 +108,12 @@
     "owspace",
     "pandiyan",
     "penheulim",
+    "photoswipe",
     "pilgi",
     "plaiceholder",
     "playform",
     "psql",
+    "pswp",
     "pwsz",
     "qrcode",
     "quan",
diff --git a/package-lock.json b/package-lock.json
index 04c54c9..3815e6e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,7 +13,7 @@
         "@astrojs/node": "^9.0.0",
         "@astrojs/rss": "^4.0.9",
         "astro": "^5.0.1",
-        "drizzle-orm": "^0.36.4",
+        "drizzle-orm": "^0.37.0",
         "fuse.js": "^7.0.0",
         "lodash": "^4.17.21",
         "luxon": "^3.5.0",
@@ -37,6 +37,8 @@
         "aplayer": "^1.10.1",
         "astro-uploader": "^1.2.2",
         "bootstrap": "^5.3.3",
+        "photoswipe": "^5.4.4",
+        "photoswipe-dynamic-caption-plugin": "^1.2.7",
         "prettier": "^3.4.1",
         "prettier-plugin-astro": "^0.14.1",
         "prettier-plugin-astro-organize-imports": "^0.4.11",
@@ -3092,13 +3094,13 @@
       "license": "MIT"
     },
     "node_modules/drizzle-orm": {
-      "version": "0.36.4",
-      "resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.36.4.tgz",
-      "integrity": "sha512-1OZY3PXD7BR00Gl61UUOFihslDldfH4NFRH2MbP54Yxi0G/PKn4HfO65JYZ7c16DeP3SpM3Aw+VXVG9j6CRSXA==",
+      "version": "0.37.0",
+      "resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.37.0.tgz",
+      "integrity": "sha512-AsCNACQ/T2CyZUkrBRUqFT2ibHJ9ZHz3+lzYJFFn3hnj7ylIeItMz5kacRG89uSE74nXYShqehr6u+6ks4JR1A==",
       "license": "Apache-2.0",
       "peerDependencies": {
         "@aws-sdk/client-rds-data": ">=3",
-        "@cloudflare/workers-types": ">=3",
+        "@cloudflare/workers-types": ">=4",
         "@electric-sql/pglite": ">=0.2.0",
         "@libsql/client": ">=0.10.0",
         "@libsql/client-wasm": ">=0.10.0",
@@ -6030,6 +6032,23 @@
         "split2": "^4.1.0"
       }
     },
+    "node_modules/photoswipe": {
+      "version": "5.4.4",
+      "resolved": "https://registry.npmjs.org/photoswipe/-/photoswipe-5.4.4.tgz",
+      "integrity": "sha512-WNFHoKrkZNnvFFhbHL93WDkW3ifwVOXSW3w1UuZZelSmgXpIGiZSNlZJq37rR8YejqME2rHs9EhH9ZvlvFH2NA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.12.0"
+      }
+    },
+    "node_modules/photoswipe-dynamic-caption-plugin": {
+      "version": "1.2.7",
+      "resolved": "https://registry.npmjs.org/photoswipe-dynamic-caption-plugin/-/photoswipe-dynamic-caption-plugin-1.2.7.tgz",
+      "integrity": "sha512-5XXdXLf2381nwe7KqQvcyStiUBi9TitYXppUQTrzPwYAi4lZsmWNnNKMclM7I4QGlX6fXo42v3bgb6rlK9pY1Q==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/picocolors": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
diff --git a/package.json b/package.json
index 23e065d..6cf867f 100644
--- a/package.json
+++ b/package.json
@@ -46,7 +46,7 @@
     "@astrojs/node": "^9.0.0",
     "@astrojs/rss": "^4.0.9",
     "astro": "^5.0.1",
-    "drizzle-orm": "^0.36.4",
+    "drizzle-orm": "^0.37.0",
     "fuse.js": "^7.0.0",
     "lodash": "^4.17.21",
     "luxon": "^3.5.0",
@@ -70,6 +70,8 @@
     "aplayer": "^1.10.1",
     "astro-uploader": "^1.2.2",
     "bootstrap": "^5.3.3",
+    "photoswipe": "^5.4.4",
+    "photoswipe-dynamic-caption-plugin": "^1.2.7",
     "prettier": "^3.4.1",
     "prettier-plugin-astro": "^0.14.1",
     "prettier-plugin-astro-organize-imports": "^0.4.11",
diff --git a/plugins/images.ts b/plugins/images.ts
index eb13743..305426c 100644
--- a/plugins/images.ts
+++ b/plugins/images.ts
@@ -13,6 +13,11 @@ type ImageNode = Parent & {
   attributes: (Literal & { name: string })[];
 };
 
+type LinkNode = Node & {
+  url: string;
+  children?: ImageNode[];
+};
+
 export const astroImage = () => {
   return async (tree: Node) => {
     // Find all the image node.
@@ -23,6 +28,17 @@ export const astroImage = () => {
 
     // Process image with blur metadata.
     await Promise.all(imageNodes);
+
+    // Find all the image link nodes and replace the relative links.
+    for (const node of selectAll('link', tree)) {
+      const link = node as LinkNode;
+      if (link.children !== undefined && link.children.length !== 0) {
+        const images = link.children.filter((child) => child.type === 'mdxJsxFlowElement' && child.name === 'Image');
+        if (images.length > 0) {
+          link.url = link.url.startsWith('/') ? urlJoin(options.assetsPrefix(), link.url) : link.url;
+        }
+      }
+    }
     return tree;
   };
 };
diff --git a/src/assets/scripts/yufan.me.js b/src/assets/scripts/yufan.me.js
index 135830f..2c233ce 100644
--- a/src/assets/scripts/yufan.me.js
+++ b/src/assets/scripts/yufan.me.js
@@ -1,7 +1,42 @@
 import Aplayer from 'aplayer/dist/APlayer.min.js';
 import { actions, isInputError } from 'astro:actions';
+import PhotoSwipe from 'photoswipe';
+import PhotoSwipeDynamicCaption from 'photoswipe-dynamic-caption-plugin';
+import PhotoSwipeLightbox from 'photoswipe/lightbox';
 import stickySidebar from './sticky-sidebar.js';
 
+// Lightbox support for post images.
+const imageLinks = Array.from(document.querySelectorAll('.post-content a')).filter((link) => {
+  const img = link.querySelector('img');
+  return typeof img !== 'undefined' && img !== null;
+});
+
+if (imageLinks.length > 0) {
+  // Append the required data attributes.
+  for (const imageLink of imageLinks) {
+    const image = imageLink.querySelector('img');
+    if (image.getAttribute('width') !== null) {
+      imageLink.dataset.pswpWidth = image.getAttribute('width');
+    }
+    if (image.getAttribute('height') !== null) {
+      imageLink.dataset.pswpHeight = image.getAttribute('height');
+    }
+  }
+
+  const lightbox = new PhotoSwipeLightbox({
+    gallery: imageLinks,
+    showHideAnimationType: 'zoom',
+    showAnimationDuration: 300,
+    hideAnimationDuration: 300,
+    pswpModule: () => PhotoSwipe,
+  });
+  new PhotoSwipeDynamicCaption(lightbox, {
+    captionContent: (slide) => slide.data.alt,
+  });
+
+  lightbox.init();
+}
+
 // Error Popup.
 const handleActionError = (error) => {
   const errorMsg = isInputError(error)
diff --git a/src/assets/styles/globals.css b/src/assets/styles/globals.css
index 9376f9b..3a3bb3d 100644
--- a/src/assets/styles/globals.css
+++ b/src/assets/styles/globals.css
@@ -2466,6 +2466,10 @@ a:hover .overlay {
   margin: 0 0 1rem 1rem;
 }
 
+.post-content a img {
+  cursor: zoom-in;
+}
+
 @media (max-width: 767.98px) {
   .post-content h1,
   .post-content h2,
diff --git a/src/content/pages/about.mdx b/src/content/pages/about.mdx
index 03156d7..7060428 100644
--- a/src/content/pages/about.mdx
+++ b/src/content/pages/about.mdx
@@ -8,7 +8,7 @@ cover: /images/2024/11/2024112723215500.jpg
 published: true
 ---
 
-![ライブペイント by mocha@新刊委託中](/images/2024/11/2024112723242700.jpg)
+[![ライブペイント by mocha@新刊委託中](/images/2024/11/2024112723242700.jpg)](/images/2024/11/2024112723242700.jpg)
 
 <MusicPlayer netease={22705492} />
 
@@ -38,4 +38,4 @@ published: true
 
 雨帆就是我,一直很年轻的孩子。
 
-![天使のはしご by mocha@新刊委託中](/images/2024/11/2024112723270800.jpg)
+[![天使のはしご by mocha@新刊委託中](/images/2024/11/2024112723270800.jpg)](/images/2024/11/2024112723270800.jpg)
diff --git a/src/content/pages/guestbook.mdx b/src/content/pages/guestbook.mdx
index c54a5a0..9a719c6 100644
--- a/src/content/pages/guestbook.mdx
+++ b/src/content/pages/guestbook.mdx
@@ -8,7 +8,7 @@ cover: /images/2024/11/2024112723314900.jpg
 published: true
 ---
 
-![春の陽 by 防人](/images/2024/11/2024112723303500.jpg)
+[![春の陽 by 防人](/images/2024/11/2024112723303500.jpg)](/images/2024/11/2024112723303500.jpg)
 
 <MusicPlayer netease={2166180181} />
 
@@ -24,4 +24,4 @@ published: true
 
 人生似飞花匆匆,飞花也有过绚丽。只是,当多年后的你再次看到这些留言时,是否能像飞花一样泰然。
 
-![色なき風 by 防人](/images/2024/11/2024112723400500.jpg)
+[![色なき風 by 防人](/images/2024/11/2024112723400500.jpg)](/images/2024/11/2024112723400500.jpg)
diff --git a/src/content/pages/links.mdx b/src/content/pages/links.mdx
index cc33c1d..1a7c699 100644
--- a/src/content/pages/links.mdx
+++ b/src/content/pages/links.mdx
@@ -9,7 +9,7 @@ friend: true
 published: true
 ---
 
-![新作《天空的翅膀》 by 画师JW](/images/2024/11/2024112723183300.jpg)
+[![新作《天空的翅膀》 by 画师JW](/images/2024/11/2024112723183300.jpg)](/images/2024/11/2024112723183300.jpg)
 
 <MusicPlayer netease={28306936} />
 
diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro
index 751ed5e..5e7a16e 100644
--- a/src/layouts/BaseLayout.astro
+++ b/src/layouts/BaseLayout.astro
@@ -2,9 +2,11 @@
 // tslint:disable:ordered-imports
 import 'bootstrap/dist/css/bootstrap.min.css';
 import '@/assets/styles/iconfont/iconfont.css';
-import 'aplayer/dist/APlayer.min.css';
 import '@/assets/styles/reset.css';
 import '@/assets/styles/globals.css';
+import 'aplayer/dist/APlayer.min.css';
+import 'photoswipe/style.css';
+import 'photoswipe-dynamic-caption-plugin/photoswipe-dynamic-caption-plugin.css';
 import '@/assets/styles/opposans/opposans.css';
 
 import Footer from '@/components/footer/Footer.astro';