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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hexo-theme-linen",
3
- "version": "1.0.36",
3
+ "version": "1.0.38",
4
4
  "description": "A clean Hexo theme",
5
5
  "main": "index.js",
6
6
  "homepage": "https://github.com/lynanbreeze/hexo-theme-linen",
@@ -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: "../linen-theme/img/lazyload/loading.svg",
4
- errorTipImage: "../linen-theme/img/lazyload/error-tip.svg",
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(loadingImage) ||
24
- /\.(svg|png|jpg|jpeg|webp|gif)$/i.test(loadingImage)
25
- ? `url(${loadingImage})`
26
- : loadingImage;
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
- ${loadingImage ? `background-image: ${placeholderImage};` : ""}
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(${errorTipImage});
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="${loadingImage}" />`,
185
+ `<link rel="preload" as="image" href="${resolvedLoadingImage}" />`,
170
186
  htmlContent,
171
187
  );
172
188
  htmlContent = appendToHead(
173
- `<link rel="preload" as="image" href="${errorTipImage}" />`,
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(../linen-theme/img/lazyload/loading.svg);
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(../linen-theme/img/lazyload/error-tip.svg);
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
- const imageElement = /** @type HTMLImageElement */ this.element;
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
- imageElement.src =
4583
- (_this$data$src = this.data.src) !== null && _this$data$src !== void 0 ? _this$data$src : "";
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;