feat: 文章图片预览

This commit is contained in:
2026-07-17 18:24:01 +08:00
parent c7766edb01
commit 9909d8d7a5
3 changed files with 75 additions and 1 deletions

View File

@@ -19,6 +19,7 @@
"jsdom": "^29.1.1", "jsdom": "^29.1.1",
"ky": "^2.0.2", "ky": "^2.0.2",
"modern-normalize": "^3.0.1", "modern-normalize": "^3.0.1",
"photoswipe": "^5.4.4",
"shiki": "^4.3.1", "shiki": "^4.3.1",
"solid-js": "^1.9.14" "solid-js": "^1.9.14"
}, },

9
pnpm-lock.yaml generated
View File

@@ -35,6 +35,9 @@ importers:
modern-normalize: modern-normalize:
specifier: ^3.0.1 specifier: ^3.0.1
version: 3.0.1 version: 3.0.1
photoswipe:
specifier: ^5.4.4
version: 5.4.4
shiki: shiki:
specifier: ^4.3.1 specifier: ^4.3.1
version: 4.3.1 version: 4.3.1
@@ -1801,6 +1804,10 @@ packages:
parse5@8.0.1: parse5@8.0.1:
resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==}
photoswipe@5.4.4:
resolution: {integrity: sha512-WNFHoKrkZNnvFFhbHL93WDkW3ifwVOXSW3w1UuZZelSmgXpIGiZSNlZJq37rR8YejqME2rHs9EhH9ZvlvFH2NA==}
engines: {node: '>= 0.12.0'}
piccolore@0.1.3: piccolore@0.1.3:
resolution: {integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==} resolution: {integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==}
@@ -3841,6 +3848,8 @@ snapshots:
dependencies: dependencies:
entities: 8.0.0 entities: 8.0.0
photoswipe@5.4.4: {}
piccolore@0.1.3: {} piccolore@0.1.3: {}
picocolors@1.1.1: {} picocolors@1.1.1: {}

View File

@@ -1,6 +1,7 @@
--- ---
import "@/styles/github-markdown.css" import "@/styles/github-markdown.css"
import "@/styles/github-markdown-reset.css" import "@/styles/github-markdown-reset.css"
import "photoswipe/dist/photoswipe.css";
import Layout from "@/layouts/Layout.astro"; import Layout from "@/layouts/Layout.astro";
import {createHttp} from "@/lib/request.ts"; import {createHttp} from "@/lib/request.ts";
@@ -98,6 +99,11 @@ const published_at = formatDatetime(data.published_at, 'YYYY 年 M 月 D 日')
box-shadow: rgba(149, 157, 165, 0.2) 0 2px 14px -4px; box-shadow: rgba(149, 157, 165, 0.2) 0 2px 14px -4px;
} }
:global(.post.markdown-body img) {
object-fit: contain;
height: auto !important;
}
.post-view { .post-view {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -129,3 +135,61 @@ const published_at = formatDatetime(data.published_at, 'YYYY 年 M 月 D 日')
box-shadow: rgba(255, 255, 255, 0.5) 0 0px 10px -4px; box-shadow: rgba(255, 255, 255, 0.5) 0 0px 10px -4px;
} }
</style> </style>
<script>
import PhotoSwipeLightbox from "photoswipe/lightbox"
const init = async () => {
const post = document.querySelector('.post')!
const images = Array.from(post.querySelectorAll('img'))
const waitImageLoaded = (img: HTMLImageElement) => {
if (img.complete && img.naturalWidth > 0 && img.naturalHeight > 0) {
return Promise.resolve()
}
return new Promise<void>((resolve) => {
img.addEventListener("load", () => resolve(), {once: true})
img.addEventListener("error", () => resolve(), {once: true})
})
}
await Promise.all(
images.map(async (img) => {
if (img.closest("a")) return
await waitImageLoaded(img)
const link = document.createElement("a")
link.href = img.currentSrc || img.src
link.target = "_blank"
link.rel = "noreferrer"
link.dataset.pswpWidth = String(img.naturalWidth || img.width || 1200)
link.dataset.pswpHeight = String(img.naturalHeight || img.height || 800)
img.parentNode?.insertBefore(link, img)
link.appendChild(img)
})
)
const lightbox = new PhotoSwipeLightbox({
gallery: ".post",
children: "a",
pswpModule: () => import("photoswipe"),
padding: {
top: 48,
right: 24,
bottom: 48,
left: 24,
},
bgOpacity: 0.5,
})
lightbox.init()
}
init()
</script>