hexo-theme-linen 1.0.36 → 1.0.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/layout/post.ejs +9 -0
- package/package.json +1 -1
- package/scripts/footnote.js +1 -1
- package/scripts/lazyload/config.js +3 -3
- package/scripts/lazyload/inject.js +24 -8
- package/source/linen-theme/css/lazyload.css +2 -2
- package/source/linen-theme/css/linen.scss +26 -0
- package/source/linen-theme/js/photoswipe/photoswipe.esm.min.js +45 -4
package/layout/post.ejs
CHANGED
|
@@ -289,6 +289,15 @@ const seriesInfo = getSeriesInfo(page?.series);
|
|
|
289
289
|
return viewportSize.x < 700 ? smallScreenPadding : largeScreenPadding
|
|
290
290
|
},
|
|
291
291
|
});
|
|
292
|
+
const isSafari = !!(navigator.vendor && navigator.vendor.match(/apple/i));
|
|
293
|
+
lightbox.on('lazyLoadSlide', (event) => {
|
|
294
|
+
const imageSrc = event.itemData && event.itemData.src;
|
|
295
|
+
if (isSafari && imageSrc && imageSrc.includes('/hdr/')) {
|
|
296
|
+
// Let PhotoSwipe's main Content create and reuse its placeholder image.
|
|
297
|
+
// The bundled Lightbox preloader uses a separate, older Content class.
|
|
298
|
+
event.preventDefault();
|
|
299
|
+
}
|
|
300
|
+
});
|
|
292
301
|
|
|
293
302
|
const getExif = (element) => {
|
|
294
303
|
const exifString = (element && element.dataset && element.dataset.pspwExif) || '';
|
package/package.json
CHANGED
package/scripts/footnote.js
CHANGED
|
@@ -78,7 +78,7 @@ hexo.extend.filter.register("before_post_render", function (data) {
|
|
|
78
78
|
|
|
79
79
|
const backrefs = Array.from({ length: refCount[id] || 0 }, (_, i) => {
|
|
80
80
|
const n = i + 1;
|
|
81
|
-
return `<a href="#fnref-${id}-${n}" class="footnote-backref"></a>`;
|
|
81
|
+
return `<a href="#fnref-${id}-${n}" class="footnote-backref" aria-label="返回脚注引用" title="返回脚注引用"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M20 6v5a3 3 0 0 1-3 3H4m0 0 4-4m-4 4 4 4" /></svg></a>`;
|
|
82
82
|
}).join(" ");
|
|
83
83
|
|
|
84
84
|
return `<li id="fn-${id}">${html}${backrefs}</li>`;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
module.exports.defaultConfig = {
|
|
2
2
|
enable: false,
|
|
3
|
-
loadingImage: "
|
|
4
|
-
errorTipImage: "
|
|
3
|
+
loadingImage: "/linen-theme/img/lazyload/loading.svg",
|
|
4
|
+
errorTipImage: "/linen-theme/img/lazyload/error-tip.svg",
|
|
5
5
|
intersectionRatio: 0.25,
|
|
6
6
|
placeholderRatio: 3 / 2,
|
|
7
7
|
showTransition: true,
|
|
8
8
|
showAltText: true,
|
|
9
9
|
preloadCount: 5
|
|
10
|
-
}
|
|
10
|
+
}
|
|
@@ -19,11 +19,27 @@ module.exports = function (hexo) {
|
|
|
19
19
|
...(hexo?.config?.theme_config?.lazyload || {}),
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
+
const resolveSiteAsset = (assetPath) => {
|
|
23
|
+
if (!assetPath || /^(https?:)?\/\//i.test(assetPath) || /^data:/i.test(assetPath)) {
|
|
24
|
+
return assetPath;
|
|
25
|
+
}
|
|
26
|
+
if (!assetPath.startsWith("/")) return assetPath;
|
|
27
|
+
|
|
28
|
+
const rootSegments = String(hexo.config.root || "")
|
|
29
|
+
.split("/")
|
|
30
|
+
.filter(Boolean)
|
|
31
|
+
.join("/");
|
|
32
|
+
const root = rootSegments ? `/${rootSegments}/` : "/";
|
|
33
|
+
return `${root}${assetPath.replace(/^\/+/, "")}`;
|
|
34
|
+
};
|
|
35
|
+
const resolvedLoadingImage = resolveSiteAsset(loadingImage);
|
|
36
|
+
const resolvedErrorTipImage = resolveSiteAsset(errorTipImage);
|
|
37
|
+
|
|
22
38
|
const placeholderImage =
|
|
23
|
-
/^(https?:\/\/|\/|data:image|\.\.\/)/i.test(
|
|
24
|
-
/\.(svg|png|jpg|jpeg|webp|gif)$/i.test(
|
|
25
|
-
? `url(${
|
|
26
|
-
:
|
|
39
|
+
/^(https?:\/\/|\/|data:image|\.\.\/)/i.test(resolvedLoadingImage) ||
|
|
40
|
+
/\.(svg|png|jpg|jpeg|webp|gif)$/i.test(resolvedLoadingImage)
|
|
41
|
+
? `url(${resolvedLoadingImage})`
|
|
42
|
+
: resolvedLoadingImage;
|
|
27
43
|
|
|
28
44
|
const injectedStyles = `.lazyload-outer-wrap .caption{
|
|
29
45
|
width: 100%;
|
|
@@ -47,7 +63,7 @@ module.exports = function (hexo) {
|
|
|
47
63
|
padding-bottom: ${(100 / Number(placeholderRatio)).toFixed(5)}%;
|
|
48
64
|
background-size: 100% 100%;
|
|
49
65
|
background-repeat: no-repeat;
|
|
50
|
-
${
|
|
66
|
+
${resolvedLoadingImage ? `background-image: ${placeholderImage};` : ""}
|
|
51
67
|
background-color: #fff;
|
|
52
68
|
}
|
|
53
69
|
.lazyload-wrap .placeholder canvas{
|
|
@@ -104,7 +120,7 @@ module.exports = function (hexo) {
|
|
|
104
120
|
.lazyload-wrap .error-wrap .error-tip{
|
|
105
121
|
width: 60%;
|
|
106
122
|
background-size: cover;
|
|
107
|
-
background-image: url(${
|
|
123
|
+
background-image: url(${resolvedErrorTipImage});
|
|
108
124
|
}
|
|
109
125
|
.lazyload-wrap .error-wrap .error-tip::before{
|
|
110
126
|
content: '';
|
|
@@ -166,11 +182,11 @@ module.exports = function (hexo) {
|
|
|
166
182
|
if (/<\/body>/gi.test(htmlContent)) {
|
|
167
183
|
htmlContent = appendToHead(settingsContent, htmlContent);
|
|
168
184
|
htmlContent = appendToHead(
|
|
169
|
-
`<link rel="preload" as="image" href="${
|
|
185
|
+
`<link rel="preload" as="image" href="${resolvedLoadingImage}" />`,
|
|
170
186
|
htmlContent,
|
|
171
187
|
);
|
|
172
188
|
htmlContent = appendToHead(
|
|
173
|
-
`<link rel="preload" as="image" href="${
|
|
189
|
+
`<link rel="preload" as="image" href="${resolvedErrorTipImage}" />`,
|
|
174
190
|
htmlContent,
|
|
175
191
|
);
|
|
176
192
|
injectExtraScript(lazyLoadPath);
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
padding-bottom: 66.66667%;
|
|
21
21
|
background-size: 100% 100%;
|
|
22
22
|
background-repeat: no-repeat;
|
|
23
|
-
background-image: url(
|
|
23
|
+
background-image: url(/linen-theme/img/lazyload/loading.svg);
|
|
24
24
|
background-color: #fff;
|
|
25
25
|
}
|
|
26
26
|
.lazyload-wrap .placeholder canvas{
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
.lazyload-wrap .error-wrap .error-tip{
|
|
78
78
|
width: 60%;
|
|
79
79
|
background-size: cover;
|
|
80
|
-
background-image: url(
|
|
80
|
+
background-image: url(/linen-theme/img/lazyload/error-tip.svg);
|
|
81
81
|
}
|
|
82
82
|
.lazyload-wrap .error-wrap .error-tip::before{
|
|
83
83
|
content: '';
|
|
@@ -685,6 +685,32 @@ body {
|
|
|
685
685
|
}
|
|
686
686
|
}
|
|
687
687
|
|
|
688
|
+
.footnote-anchor-wrap {
|
|
689
|
+
scroll-margin-top: 1.5em;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
.footnotes .footnote-backref {
|
|
693
|
+
display: inline-block;
|
|
694
|
+
margin-left: 0.35em;
|
|
695
|
+
font-weight: normal;
|
|
696
|
+
|
|
697
|
+
svg {
|
|
698
|
+
display: inline-block;
|
|
699
|
+
width: 1em;
|
|
700
|
+
height: 1em;
|
|
701
|
+
overflow: visible;
|
|
702
|
+
vertical-align: -0.16em;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
path {
|
|
706
|
+
fill: none;
|
|
707
|
+
stroke: currentColor;
|
|
708
|
+
stroke-linecap: round;
|
|
709
|
+
stroke-linejoin: round;
|
|
710
|
+
stroke-width: 2;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
688
714
|
del {
|
|
689
715
|
a:not([class]):not(:has(.shared-link)) {
|
|
690
716
|
&::after {
|
|
@@ -170,6 +170,17 @@ function decodeImage(img) {
|
|
|
170
170
|
});
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
+
function areImageSourcesEqual(first, second) {
|
|
174
|
+
if (!first || !second) {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
return new URL(first, document.baseURI).href === new URL(second, document.baseURI).href;
|
|
179
|
+
} catch (error) {
|
|
180
|
+
return first === second;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
173
184
|
/** @typedef {LOAD_STATE[keyof LOAD_STATE]} LoadState */
|
|
174
185
|
/** @type {{ IDLE: 'idle'; LOADING: 'loading'; LOADED: 'loaded'; ERROR: 'error' }} */
|
|
175
186
|
const LOAD_STATE = {
|
|
@@ -4574,13 +4585,43 @@ class Content {
|
|
|
4574
4585
|
) {
|
|
4575
4586
|
return;
|
|
4576
4587
|
}
|
|
4577
|
-
|
|
4588
|
+
let imageElement = /** @type HTMLImageElement */ this.element;
|
|
4589
|
+
let reusingPlaceholder = false;
|
|
4590
|
+
const isHdrImage = this.data.src && this.data.src.includes("/hdr/");
|
|
4591
|
+
const placeholderElement = this.placeholder && this.placeholder.element;
|
|
4592
|
+
// Safari can flash when it swaps between two separate image layers,
|
|
4593
|
+
// even when the placeholder and the full-size HDR image use the same URL.
|
|
4594
|
+
// Reuse the placeholder so HDR is never decoded through HTMLImageElement.decode().
|
|
4595
|
+
if (
|
|
4596
|
+
isSafari() &&
|
|
4597
|
+
isHdrImage &&
|
|
4598
|
+
!this.data.srcset &&
|
|
4599
|
+
placeholderElement &&
|
|
4600
|
+
placeholderElement.tagName === "IMG" &&
|
|
4601
|
+
areImageSourcesEqual(placeholderElement.src, this.data.src)
|
|
4602
|
+
) {
|
|
4603
|
+
imageElement = /** @type HTMLImageElement */ placeholderElement;
|
|
4604
|
+
imageElement.classList.remove("pswp__img--placeholder");
|
|
4605
|
+
imageElement.removeAttribute("aria-hidden");
|
|
4606
|
+
imageElement.removeAttribute("role");
|
|
4607
|
+
imageElement.style.width = "";
|
|
4608
|
+
imageElement.style.height = "";
|
|
4609
|
+
imageElement.style.transform = "";
|
|
4610
|
+
imageElement.style.transformOrigin = "";
|
|
4611
|
+
setWidthHeight(imageElement, this.displayedImageWidth, this.displayedImageHeight);
|
|
4612
|
+
this.element = imageElement;
|
|
4613
|
+
this.placeholder.element = null;
|
|
4614
|
+
this.placeholder = undefined;
|
|
4615
|
+
reusingPlaceholder = true;
|
|
4616
|
+
}
|
|
4578
4617
|
this.updateSrcsetSizes();
|
|
4579
|
-
if (this.data.srcset) {
|
|
4618
|
+
if (this.data.srcset && !reusingPlaceholder) {
|
|
4580
4619
|
imageElement.srcset = this.data.srcset;
|
|
4581
4620
|
}
|
|
4582
|
-
|
|
4583
|
-
|
|
4621
|
+
if (!reusingPlaceholder) {
|
|
4622
|
+
imageElement.src =
|
|
4623
|
+
(_this$data$src = this.data.src) !== null && _this$data$src !== void 0 ? _this$data$src : "";
|
|
4624
|
+
}
|
|
4584
4625
|
imageElement.alt =
|
|
4585
4626
|
(_this$data$alt = this.data.alt) !== null && _this$data$alt !== void 0 ? _this$data$alt : "";
|
|
4586
4627
|
this.state = LOAD_STATE.LOADING;
|