@xingwangzhe/stalux 1.49.0 → 1.51.0
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/README.md +65 -330
- package/package.json +3 -2
- package/src/internal/sharp-loader.ts +45 -0
- package/src/internal/social-card-cover.ts +143 -0
- package/src/internal/social-card-data.ts +0 -1
- package/src/internal/social-card-layout.ts +153 -0
- package/src/internal/social-card-renderer.ts +138 -275
- package/src/layouts/Stalux.astro +1 -0
- package/src/pages/og/[image].[format].ts +20 -21
- package/src/scripts/route-prefetch.ts +120 -0
- package/src/utils/social-image.ts +17 -8
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { loadSharp } from "../internal/sharp-loader";
|
|
2
3
|
|
|
3
4
|
export interface SocialCardData {
|
|
4
5
|
title: string;
|
|
@@ -7,12 +8,13 @@ export interface SocialCardData {
|
|
|
7
8
|
author: string;
|
|
8
9
|
host: string;
|
|
9
10
|
lang: string;
|
|
10
|
-
accent: string;
|
|
11
11
|
date: string;
|
|
12
12
|
category: string;
|
|
13
13
|
cover?: string;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
export type SocialCardFormat = "jpg" | "png";
|
|
17
|
+
|
|
16
18
|
export interface SocialImage {
|
|
17
19
|
url: string;
|
|
18
20
|
width?: number;
|
|
@@ -35,13 +37,23 @@ export function isSocialImageUrl(value: string): boolean {
|
|
|
35
37
|
}
|
|
36
38
|
}
|
|
37
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Cards with artwork are photographic, so JPEG saves most of the bytes and is
|
|
42
|
+
* accepted by every crawler. Plain cards stay PNG: flat type compresses far
|
|
43
|
+
* better there. Without `sharp` neither palette PNG nor JPEG is available, so
|
|
44
|
+
* the card falls back to a plain PNG.
|
|
45
|
+
*/
|
|
46
|
+
export function socialCardFormat(data: Pick<SocialCardData, "cover">): SocialCardFormat {
|
|
47
|
+
return data.cover && loadSharp() ? "jpg" : "png";
|
|
48
|
+
}
|
|
49
|
+
|
|
38
50
|
export function socialCardPath(data: SocialCardData, base = "/"): string {
|
|
39
51
|
// Bump the template revision when layout changes. Metadata changes get a fresh URL.
|
|
40
52
|
const hash = createHash("sha256")
|
|
41
|
-
.update(JSON.stringify(["stalux-
|
|
53
|
+
.update(JSON.stringify(["stalux-mono-v1", data]))
|
|
42
54
|
.digest("hex")
|
|
43
55
|
.slice(0, 20);
|
|
44
|
-
return `${base.replace(/\/$/u, "")}/og/${hash}
|
|
56
|
+
return `${base.replace(/\/$/u, "")}/og/${hash}.${socialCardFormat(data)}`;
|
|
45
57
|
}
|
|
46
58
|
|
|
47
59
|
export function resolvePostSocialImage(
|
|
@@ -50,14 +62,11 @@ export function resolvePostSocialImage(
|
|
|
50
62
|
base = "/",
|
|
51
63
|
): SocialImage {
|
|
52
64
|
if (explicit?.trim() && isSocialImageUrl(explicit.trim())) return { url: explicit.trim() };
|
|
53
|
-
|
|
54
|
-
// crawler) refuse WebP or AVIF in og:image, so this is the one place the
|
|
55
|
-
// modern format costs reach instead of saving bytes. In-page images are
|
|
56
|
-
// served as WebP instead, where the browser decides.
|
|
65
|
+
const format = socialCardFormat(data);
|
|
57
66
|
return {
|
|
58
67
|
url: socialCardPath(data, base),
|
|
59
68
|
width: 1200,
|
|
60
69
|
height: 630,
|
|
61
|
-
type: "image/png",
|
|
70
|
+
type: format === "jpg" ? "image/jpeg" : "image/png",
|
|
62
71
|
};
|
|
63
72
|
}
|