@haklex/rich-renderer-linkcard 0.0.82 → 0.0.83
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/dist/LinkCardRenderer-CJB5CmHP.js +1314 -0
- package/dist/index.mjs +292 -262
- package/dist/rich-renderer-linkcard.css +1 -2
- package/dist/static.mjs +29 -2
- package/package.json +4 -4
- package/dist/LinkCardRenderer-C-luOWVc.js +0 -1331
|
@@ -0,0 +1,1314 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Star, Globe } from "lucide-react";
|
|
3
|
+
import { useMemo, createContext, use, useState, useCallback, useRef, useEffect } from "react";
|
|
4
|
+
import { useInView } from "react-intersection-observer";
|
|
5
|
+
import { vars } from "@haklex/rich-style-token";
|
|
6
|
+
const arxivPlugin = {
|
|
7
|
+
name: "arxiv",
|
|
8
|
+
displayName: "arXiv Paper",
|
|
9
|
+
priority: 80,
|
|
10
|
+
typeClass: "academic",
|
|
11
|
+
matchUrl(url) {
|
|
12
|
+
if (url.hostname !== "arxiv.org") return null;
|
|
13
|
+
const match = url.pathname.match(/\/(abs|pdf)\/(\d{4}\.\d+(?:v\d+)?)/i);
|
|
14
|
+
if (!match) return null;
|
|
15
|
+
return { id: match[2].toLowerCase(), fullUrl: url.toString() };
|
|
16
|
+
},
|
|
17
|
+
isValidId(id) {
|
|
18
|
+
return /^\d{4}\.\d+(?:v\d+)?$/.test(id);
|
|
19
|
+
},
|
|
20
|
+
async fetch(id) {
|
|
21
|
+
const response = await fetch(
|
|
22
|
+
`https://export.arxiv.org/api/query?id_list=${id}`
|
|
23
|
+
);
|
|
24
|
+
const text = await response.text();
|
|
25
|
+
const parser = new DOMParser();
|
|
26
|
+
const xmlDoc = parser.parseFromString(text, "application/xml");
|
|
27
|
+
const entry = xmlDoc.getElementsByTagName("entry")[0];
|
|
28
|
+
const title2 = entry.getElementsByTagName("title")[0].textContent;
|
|
29
|
+
const authors = entry.getElementsByTagName("author");
|
|
30
|
+
const authorNames = Array.from(authors).map(
|
|
31
|
+
(author) => author.getElementsByTagName("name")[0].textContent
|
|
32
|
+
);
|
|
33
|
+
return {
|
|
34
|
+
title: /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
35
|
+
/* @__PURE__ */ jsx("span", { style: { flex: 1 }, children: title2 }),
|
|
36
|
+
/* @__PURE__ */ jsx("span", { style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx(
|
|
37
|
+
"span",
|
|
38
|
+
{
|
|
39
|
+
style: {
|
|
40
|
+
display: "inline-flex",
|
|
41
|
+
alignItems: "center",
|
|
42
|
+
gap: "4px",
|
|
43
|
+
fontSize: vars.typography.fontSizeMd,
|
|
44
|
+
color: "#fb923c"
|
|
45
|
+
},
|
|
46
|
+
children: /* @__PURE__ */ jsx("span", { style: { fontFamily: "sans-serif", fontWeight: 500 }, children: id })
|
|
47
|
+
}
|
|
48
|
+
) })
|
|
49
|
+
] }),
|
|
50
|
+
desc: authorNames.length > 1 ? `${authorNames[0]} et al.` : authorNames[0]
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
function toCamelCase(str) {
|
|
55
|
+
return str.replaceAll(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
56
|
+
}
|
|
57
|
+
function camelcaseKeys(obj) {
|
|
58
|
+
if (Array.isArray(obj)) return obj.map(camelcaseKeys);
|
|
59
|
+
if (obj !== null && typeof obj === "object") {
|
|
60
|
+
return Object.fromEntries(
|
|
61
|
+
Object.entries(obj).map(([k, v]) => [toCamelCase(k), camelcaseKeys(v)])
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
return obj;
|
|
65
|
+
}
|
|
66
|
+
async function fetchJsonWithContext(url, context, provider, init) {
|
|
67
|
+
const providerAdapter = provider && context?.adapters ? context.adapters[provider] : void 0;
|
|
68
|
+
if (providerAdapter) {
|
|
69
|
+
return providerAdapter.request(url, init);
|
|
70
|
+
}
|
|
71
|
+
if (context?.fetchJson) {
|
|
72
|
+
return context.fetchJson(url, init);
|
|
73
|
+
}
|
|
74
|
+
const response = await fetch(url, init);
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
throw new Error(`Request failed: ${response.status}`);
|
|
77
|
+
}
|
|
78
|
+
return response.json();
|
|
79
|
+
}
|
|
80
|
+
async function fetchGitHubApi(url, context) {
|
|
81
|
+
const path = url.replace("https://api.github.com", "");
|
|
82
|
+
return fetchJsonWithContext(`https://api.github.com${path}`, context, "github");
|
|
83
|
+
}
|
|
84
|
+
const LanguageToColorMap = {
|
|
85
|
+
"typescript": "#2b7489",
|
|
86
|
+
"javascript": "#f1e05a",
|
|
87
|
+
"html": "#e34c26",
|
|
88
|
+
"java": "#b07219",
|
|
89
|
+
"go": "#00add8",
|
|
90
|
+
"vue": "#2c3e50",
|
|
91
|
+
"css": "#563d7c",
|
|
92
|
+
"yaml": "#cb171e",
|
|
93
|
+
"json": "#292929",
|
|
94
|
+
"markdown": "#083fa1",
|
|
95
|
+
"csharp": "#178600",
|
|
96
|
+
"c#": "#178600",
|
|
97
|
+
"c": "#555555",
|
|
98
|
+
"cpp": "#f34b7d",
|
|
99
|
+
"c++": "#f34b7d",
|
|
100
|
+
"python": "#3572a5",
|
|
101
|
+
"lua": "#000080",
|
|
102
|
+
"vimscript": "#199f4b",
|
|
103
|
+
"shell": "#89e051",
|
|
104
|
+
"dockerfile": "#384d54",
|
|
105
|
+
"ruby": "#701516",
|
|
106
|
+
"php": "#4f5d95",
|
|
107
|
+
"lisp": "#3fb68b",
|
|
108
|
+
"kotlin": "#F18E33",
|
|
109
|
+
"rust": "#dea584",
|
|
110
|
+
"dart": "#00B4AB",
|
|
111
|
+
"swift": "#ffac45",
|
|
112
|
+
"objective-c": "#438eff",
|
|
113
|
+
"objective-c++": "#6866fb",
|
|
114
|
+
"r": "#198ce7",
|
|
115
|
+
"matlab": "#e16737",
|
|
116
|
+
"scala": "#c22d40",
|
|
117
|
+
"sql": "#e38c00",
|
|
118
|
+
"perl": "#0298c3"
|
|
119
|
+
};
|
|
120
|
+
const bangumiTypeMap = {
|
|
121
|
+
subject: "subjects",
|
|
122
|
+
character: "characters",
|
|
123
|
+
person: "persons"
|
|
124
|
+
};
|
|
125
|
+
const allowedBangumiTypes = Object.keys(bangumiTypeMap);
|
|
126
|
+
function hslToHex(h, s, l) {
|
|
127
|
+
s /= 100;
|
|
128
|
+
l /= 100;
|
|
129
|
+
const a = s * Math.min(l, 1 - l);
|
|
130
|
+
const f = (n) => {
|
|
131
|
+
const k = (n + h / 30) % 12;
|
|
132
|
+
const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
|
|
133
|
+
return Math.round(255 * color).toString(16).padStart(2, "0");
|
|
134
|
+
};
|
|
135
|
+
return `#${f(0)}${f(8)}${f(4)}`;
|
|
136
|
+
}
|
|
137
|
+
function generateColor(str, saturation = [30, 35], lightness = [60, 70]) {
|
|
138
|
+
let hash = 0;
|
|
139
|
+
for (let i = 0; i < str.length; i++) {
|
|
140
|
+
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
|
141
|
+
}
|
|
142
|
+
const sRange = saturation[1] - saturation[0] + 1;
|
|
143
|
+
const lRange = lightness[1] - lightness[0] + 1;
|
|
144
|
+
const h = Math.abs(hash) % 360;
|
|
145
|
+
const s = saturation[0] + Math.abs(hash >> 8) % sRange;
|
|
146
|
+
const l = lightness[0] + Math.abs(hash >> 16) % lRange;
|
|
147
|
+
return hslToHex(h, s, l);
|
|
148
|
+
}
|
|
149
|
+
function stripMarkdown(text) {
|
|
150
|
+
return text.replaceAll(/!\[[^\]]*\]\([^)]*\)/g, "").replaceAll(/\[([^\]]*)\]\([^)]*\)/g, "$1").replaceAll(/[#*>_`~]/g, "").replaceAll(/\n+/g, " ").trim();
|
|
151
|
+
}
|
|
152
|
+
function getDifficultyColor(difficulty) {
|
|
153
|
+
switch (difficulty) {
|
|
154
|
+
case "Easy": {
|
|
155
|
+
return "#00BFA5";
|
|
156
|
+
}
|
|
157
|
+
case "Medium": {
|
|
158
|
+
return "#FFA726";
|
|
159
|
+
}
|
|
160
|
+
case "Hard": {
|
|
161
|
+
return "#F44336";
|
|
162
|
+
}
|
|
163
|
+
default: {
|
|
164
|
+
return "#757575";
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const leetcodePlugin = {
|
|
169
|
+
name: "leetcode",
|
|
170
|
+
displayName: "LeetCode",
|
|
171
|
+
priority: 65,
|
|
172
|
+
typeClass: "wide",
|
|
173
|
+
provider: "leetcode",
|
|
174
|
+
matchUrl(url) {
|
|
175
|
+
if (url.hostname !== "leetcode.cn" && url.hostname !== "leetcode.com") return null;
|
|
176
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
177
|
+
if (parts[0] !== "problems" || !parts[1]) return null;
|
|
178
|
+
return { id: parts[1], fullUrl: url.toString() };
|
|
179
|
+
},
|
|
180
|
+
isValidId(id) {
|
|
181
|
+
return typeof id === "string" && id.length > 0;
|
|
182
|
+
},
|
|
183
|
+
async fetch(id, _meta, context) {
|
|
184
|
+
const body = {
|
|
185
|
+
query: `query questionData($titleSlug: String!) {
|
|
186
|
+
question(titleSlug: $titleSlug) {translatedTitle
|
|
187
|
+
difficulty
|
|
188
|
+
likes
|
|
189
|
+
topicTags { translatedName
|
|
190
|
+
}
|
|
191
|
+
stats
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
`,
|
|
195
|
+
variables: { titleSlug: id }
|
|
196
|
+
};
|
|
197
|
+
const questionData = await fetchJsonWithContext(
|
|
198
|
+
"https://leetcode.cn/graphql/",
|
|
199
|
+
context,
|
|
200
|
+
"leetcode",
|
|
201
|
+
{
|
|
202
|
+
method: "POST",
|
|
203
|
+
headers: { "Content-Type": "application/json" },
|
|
204
|
+
body: JSON.stringify(body)
|
|
205
|
+
}
|
|
206
|
+
);
|
|
207
|
+
const questionTitleData = camelcaseKeys(questionData.data.question);
|
|
208
|
+
const stats = JSON.parse(questionTitleData.stats);
|
|
209
|
+
return {
|
|
210
|
+
title: /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
211
|
+
/* @__PURE__ */ jsx("span", { style: { flex: 1 }, children: questionTitleData.translatedTitle }),
|
|
212
|
+
/* @__PURE__ */ jsx("span", { style: { flexShrink: 0 }, children: questionTitleData.likes > 0 && /* @__PURE__ */ jsxs(
|
|
213
|
+
"span",
|
|
214
|
+
{
|
|
215
|
+
style: {
|
|
216
|
+
display: "inline-flex",
|
|
217
|
+
alignItems: "center",
|
|
218
|
+
gap: "4px",
|
|
219
|
+
fontSize: vars.typography.fontSizeMd,
|
|
220
|
+
color: "#fb923c"
|
|
221
|
+
},
|
|
222
|
+
children: [
|
|
223
|
+
"👍",
|
|
224
|
+
/* @__PURE__ */ jsx("span", { style: { fontFamily: "sans-serif", fontWeight: 500 }, children: questionTitleData.likes })
|
|
225
|
+
]
|
|
226
|
+
}
|
|
227
|
+
) })
|
|
228
|
+
] }),
|
|
229
|
+
desc: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
230
|
+
/* @__PURE__ */ jsx(
|
|
231
|
+
"span",
|
|
232
|
+
{
|
|
233
|
+
style: {
|
|
234
|
+
marginRight: "16px",
|
|
235
|
+
fontWeight: "bold",
|
|
236
|
+
color: getDifficultyColor(questionTitleData.difficulty)
|
|
237
|
+
},
|
|
238
|
+
children: questionTitleData.difficulty
|
|
239
|
+
}
|
|
240
|
+
),
|
|
241
|
+
/* @__PURE__ */ jsx("span", { style: { overflow: "hidden" }, children: questionTitleData.topicTags.map((tag) => tag.translatedName).join(" / ") }),
|
|
242
|
+
/* @__PURE__ */ jsxs("span", { style: { float: "right", overflow: "hidden" }, children: [
|
|
243
|
+
"AR: ",
|
|
244
|
+
stats.acRate
|
|
245
|
+
] })
|
|
246
|
+
] }),
|
|
247
|
+
image: "https://upload.wikimedia.org/wikipedia/commons/1/19/LeetCode_logo_black.png",
|
|
248
|
+
color: getDifficultyColor(questionTitleData.difficulty)
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
const githubCommitPlugin = {
|
|
253
|
+
name: "gh-commit",
|
|
254
|
+
displayName: "GitHub Commit",
|
|
255
|
+
priority: 95,
|
|
256
|
+
typeClass: "github",
|
|
257
|
+
provider: "github",
|
|
258
|
+
matchUrl(url) {
|
|
259
|
+
if (url.hostname !== "github.com") return null;
|
|
260
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
261
|
+
if (parts.length < 4 || parts[2] !== "commit") return null;
|
|
262
|
+
const [owner, repo, , commitId] = parts;
|
|
263
|
+
return {
|
|
264
|
+
id: `${owner}/${repo}/commit/${commitId}`,
|
|
265
|
+
fullUrl: url.toString()
|
|
266
|
+
};
|
|
267
|
+
},
|
|
268
|
+
isValidId(id) {
|
|
269
|
+
const parts = id.split("/");
|
|
270
|
+
return parts.length === 4 && parts.every((p) => p.length > 0) && parts[2] === "commit";
|
|
271
|
+
},
|
|
272
|
+
async fetch(id, _meta, context) {
|
|
273
|
+
const [owner, repo, , commitId] = id.split("/");
|
|
274
|
+
const response = await fetchGitHubApi(
|
|
275
|
+
`https://api.github.com/repos/${owner}/${repo}/commits/${commitId}`,
|
|
276
|
+
context
|
|
277
|
+
);
|
|
278
|
+
const data = camelcaseKeys(response);
|
|
279
|
+
return {
|
|
280
|
+
title: /* @__PURE__ */ jsx("span", { style: { fontWeight: "normal" }, children: data.commit.message.replace(/Signed-off-by:.+/s, "").trim() }),
|
|
281
|
+
desc: /* @__PURE__ */ jsxs(
|
|
282
|
+
"span",
|
|
283
|
+
{
|
|
284
|
+
style: {
|
|
285
|
+
display: "flex",
|
|
286
|
+
flexWrap: "wrap",
|
|
287
|
+
alignItems: "center",
|
|
288
|
+
gap: "4px 12px",
|
|
289
|
+
fontFamily: vars.typography.fontMono
|
|
290
|
+
},
|
|
291
|
+
children: [
|
|
292
|
+
/* @__PURE__ */ jsxs(
|
|
293
|
+
"span",
|
|
294
|
+
{
|
|
295
|
+
style: {
|
|
296
|
+
display: "inline-flex",
|
|
297
|
+
alignItems: "center",
|
|
298
|
+
gap: "8px"
|
|
299
|
+
},
|
|
300
|
+
children: [
|
|
301
|
+
/* @__PURE__ */ jsxs("span", { style: { color: "#238636" }, children: [
|
|
302
|
+
"+",
|
|
303
|
+
data.stats.additions
|
|
304
|
+
] }),
|
|
305
|
+
/* @__PURE__ */ jsxs("span", { style: { color: "#f85149" }, children: [
|
|
306
|
+
"-",
|
|
307
|
+
data.stats.deletions
|
|
308
|
+
] })
|
|
309
|
+
]
|
|
310
|
+
}
|
|
311
|
+
),
|
|
312
|
+
/* @__PURE__ */ jsx("span", { style: { fontSize: vars.typography.fontSizeMd }, children: data.sha.slice(0, 7) }),
|
|
313
|
+
/* @__PURE__ */ jsxs("span", { style: { fontSize: vars.typography.fontSizeMd, opacity: 0.8 }, children: [
|
|
314
|
+
owner,
|
|
315
|
+
"/",
|
|
316
|
+
repo
|
|
317
|
+
] })
|
|
318
|
+
]
|
|
319
|
+
}
|
|
320
|
+
),
|
|
321
|
+
image: data.author?.avatarUrl
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
const githubDiscussionPlugin = {
|
|
326
|
+
name: "gh-discussion",
|
|
327
|
+
displayName: "GitHub Discussion",
|
|
328
|
+
priority: 95,
|
|
329
|
+
typeClass: "github",
|
|
330
|
+
provider: "github",
|
|
331
|
+
matchUrl(url) {
|
|
332
|
+
if (url.hostname !== "github.com") return null;
|
|
333
|
+
if (!url.pathname.includes("/discussions/")) return null;
|
|
334
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
335
|
+
if (parts.length < 4 || parts[2] !== "discussions") return null;
|
|
336
|
+
const discussionNumber = parts[3];
|
|
337
|
+
if (!/^\d+$/.test(discussionNumber)) return null;
|
|
338
|
+
const [owner, repo] = parts;
|
|
339
|
+
return {
|
|
340
|
+
id: `${owner}/${repo}/${discussionNumber}`,
|
|
341
|
+
fullUrl: url.toString()
|
|
342
|
+
};
|
|
343
|
+
},
|
|
344
|
+
isValidId(id) {
|
|
345
|
+
const parts = id.split("/");
|
|
346
|
+
return parts.length === 3 && parts.every((p) => p.length > 0) && /^\d+$/.test(parts[2]);
|
|
347
|
+
},
|
|
348
|
+
async fetch(id, _meta, context) {
|
|
349
|
+
const [owner, repo, discussionNumber] = id.split("/");
|
|
350
|
+
const response = await fetchGitHubApi(
|
|
351
|
+
`https://api.github.com/repos/${owner}/${repo}/discussions/${discussionNumber}`,
|
|
352
|
+
context
|
|
353
|
+
);
|
|
354
|
+
const data = camelcaseKeys(response);
|
|
355
|
+
const categoryName = data.category?.name || "Discussion";
|
|
356
|
+
return {
|
|
357
|
+
title: `Discussion: ${data.title}`,
|
|
358
|
+
desc: /* @__PURE__ */ jsxs(
|
|
359
|
+
"span",
|
|
360
|
+
{
|
|
361
|
+
style: {
|
|
362
|
+
display: "flex",
|
|
363
|
+
flexWrap: "wrap",
|
|
364
|
+
alignItems: "center",
|
|
365
|
+
gap: "4px 12px",
|
|
366
|
+
fontFamily: vars.typography.fontMono
|
|
367
|
+
},
|
|
368
|
+
children: [
|
|
369
|
+
/* @__PURE__ */ jsx(
|
|
370
|
+
"span",
|
|
371
|
+
{
|
|
372
|
+
style: {
|
|
373
|
+
borderRadius: "4px",
|
|
374
|
+
backgroundColor: "rgba(128,128,128,0.15)",
|
|
375
|
+
padding: "2px 6px",
|
|
376
|
+
fontSize: vars.typography.fontSizeXs
|
|
377
|
+
},
|
|
378
|
+
children: categoryName
|
|
379
|
+
}
|
|
380
|
+
),
|
|
381
|
+
/* @__PURE__ */ jsxs("span", { style: { fontSize: vars.typography.fontSizeMd, opacity: 0.8 }, children: [
|
|
382
|
+
"#",
|
|
383
|
+
discussionNumber,
|
|
384
|
+
" · ",
|
|
385
|
+
owner,
|
|
386
|
+
"/",
|
|
387
|
+
repo
|
|
388
|
+
] })
|
|
389
|
+
]
|
|
390
|
+
}
|
|
391
|
+
),
|
|
392
|
+
image: data.user?.avatarUrl
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
const stateColors = {
|
|
397
|
+
open: "#238636",
|
|
398
|
+
closed: "#f85149"
|
|
399
|
+
};
|
|
400
|
+
const stateTextMap$1 = {
|
|
401
|
+
open: "Open",
|
|
402
|
+
closed: "Closed"
|
|
403
|
+
};
|
|
404
|
+
const githubIssuePlugin = {
|
|
405
|
+
name: "gh-issue",
|
|
406
|
+
displayName: "GitHub Issue",
|
|
407
|
+
priority: 95,
|
|
408
|
+
typeClass: "github",
|
|
409
|
+
provider: "github",
|
|
410
|
+
matchUrl(url) {
|
|
411
|
+
if (url.hostname !== "github.com") return null;
|
|
412
|
+
if (!url.pathname.includes("/issues/")) return null;
|
|
413
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
414
|
+
if (parts.length < 4 || parts[2] !== "issues") return null;
|
|
415
|
+
const issueNumber = parts[3];
|
|
416
|
+
if (!/^\d+$/.test(issueNumber)) return null;
|
|
417
|
+
const [owner, repo] = parts;
|
|
418
|
+
return { id: `${owner}/${repo}/${issueNumber}`, fullUrl: url.toString() };
|
|
419
|
+
},
|
|
420
|
+
isValidId(id) {
|
|
421
|
+
const parts = id.split("/");
|
|
422
|
+
return parts.length === 3 && parts.every((p) => p.length > 0) && /^\d+$/.test(parts[2]);
|
|
423
|
+
},
|
|
424
|
+
async fetch(id, _meta, context) {
|
|
425
|
+
const [owner, repo, issueNumber] = id.split("/");
|
|
426
|
+
const response = await fetchGitHubApi(
|
|
427
|
+
`https://api.github.com/repos/${owner}/${repo}/issues/${issueNumber}`,
|
|
428
|
+
context
|
|
429
|
+
);
|
|
430
|
+
const data = camelcaseKeys(response);
|
|
431
|
+
const color = stateColors[data.state] || "#6b7280";
|
|
432
|
+
const stateText = stateTextMap$1[data.state] || data.state;
|
|
433
|
+
return {
|
|
434
|
+
title: `Issue: ${data.title}`,
|
|
435
|
+
color,
|
|
436
|
+
desc: /* @__PURE__ */ jsxs(
|
|
437
|
+
"span",
|
|
438
|
+
{
|
|
439
|
+
style: {
|
|
440
|
+
display: "flex",
|
|
441
|
+
flexWrap: "wrap",
|
|
442
|
+
alignItems: "center",
|
|
443
|
+
gap: "4px 12px",
|
|
444
|
+
fontFamily: vars.typography.fontMono
|
|
445
|
+
},
|
|
446
|
+
children: [
|
|
447
|
+
/* @__PURE__ */ jsx("span", { style: { color }, children: stateText }),
|
|
448
|
+
/* @__PURE__ */ jsxs("span", { style: { fontSize: vars.typography.fontSizeMd, opacity: 0.8 }, children: [
|
|
449
|
+
"#",
|
|
450
|
+
issueNumber,
|
|
451
|
+
" · ",
|
|
452
|
+
owner,
|
|
453
|
+
"/",
|
|
454
|
+
repo
|
|
455
|
+
] })
|
|
456
|
+
]
|
|
457
|
+
}
|
|
458
|
+
),
|
|
459
|
+
image: data.user?.avatarUrl
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
const getPrState = (data) => {
|
|
464
|
+
if (data.merged) return "merged";
|
|
465
|
+
return data.state;
|
|
466
|
+
};
|
|
467
|
+
const stateColorMap = {
|
|
468
|
+
open: "#238636",
|
|
469
|
+
merged: "#8957e5",
|
|
470
|
+
closed: "#f85149"
|
|
471
|
+
};
|
|
472
|
+
const stateTextMap = {
|
|
473
|
+
open: "Open",
|
|
474
|
+
merged: "Merged",
|
|
475
|
+
closed: "Closed"
|
|
476
|
+
};
|
|
477
|
+
const githubPrPlugin = {
|
|
478
|
+
name: "gh-pr",
|
|
479
|
+
displayName: "GitHub Pull Request",
|
|
480
|
+
priority: 95,
|
|
481
|
+
typeClass: "github",
|
|
482
|
+
provider: "github",
|
|
483
|
+
matchUrl(url) {
|
|
484
|
+
if (url.hostname !== "github.com") return null;
|
|
485
|
+
if (!url.pathname.includes("/pull/")) return null;
|
|
486
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
487
|
+
if (parts.length < 4 || parts[2] !== "pull") return null;
|
|
488
|
+
const [owner, repo, , prNumber] = parts;
|
|
489
|
+
return { id: `${owner}/${repo}/${prNumber}`, fullUrl: url.toString() };
|
|
490
|
+
},
|
|
491
|
+
isValidId(id) {
|
|
492
|
+
const parts = id.split("/");
|
|
493
|
+
return parts.length === 3 && parts.every((p) => p.length > 0);
|
|
494
|
+
},
|
|
495
|
+
async fetch(id, _meta, context) {
|
|
496
|
+
const [owner, repo, prNumber] = id.split("/");
|
|
497
|
+
const response = await fetchGitHubApi(
|
|
498
|
+
`https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}`,
|
|
499
|
+
context
|
|
500
|
+
);
|
|
501
|
+
const data = camelcaseKeys(response);
|
|
502
|
+
const state = getPrState(data);
|
|
503
|
+
const color = stateColorMap[state];
|
|
504
|
+
const stateText = stateTextMap[state];
|
|
505
|
+
return {
|
|
506
|
+
title: `PR: ${data.title}`,
|
|
507
|
+
color,
|
|
508
|
+
desc: /* @__PURE__ */ jsxs(
|
|
509
|
+
"span",
|
|
510
|
+
{
|
|
511
|
+
style: {
|
|
512
|
+
display: "flex",
|
|
513
|
+
flexWrap: "wrap",
|
|
514
|
+
alignItems: "center",
|
|
515
|
+
gap: "4px 12px",
|
|
516
|
+
fontFamily: vars.typography.fontMono
|
|
517
|
+
},
|
|
518
|
+
children: [
|
|
519
|
+
/* @__PURE__ */ jsx("span", { style: { color }, children: stateText }),
|
|
520
|
+
/* @__PURE__ */ jsxs(
|
|
521
|
+
"span",
|
|
522
|
+
{
|
|
523
|
+
style: {
|
|
524
|
+
display: "inline-flex",
|
|
525
|
+
alignItems: "center",
|
|
526
|
+
gap: "8px",
|
|
527
|
+
whiteSpace: "nowrap"
|
|
528
|
+
},
|
|
529
|
+
children: [
|
|
530
|
+
/* @__PURE__ */ jsxs("span", { style: { color: "#238636" }, children: [
|
|
531
|
+
"+",
|
|
532
|
+
data.additions
|
|
533
|
+
] }),
|
|
534
|
+
/* @__PURE__ */ jsxs("span", { style: { color: "#f85149" }, children: [
|
|
535
|
+
"-",
|
|
536
|
+
data.deletions
|
|
537
|
+
] })
|
|
538
|
+
]
|
|
539
|
+
}
|
|
540
|
+
),
|
|
541
|
+
/* @__PURE__ */ jsxs("span", { style: { fontSize: vars.typography.fontSizeMd, opacity: 0.8 }, children: [
|
|
542
|
+
owner,
|
|
543
|
+
"/",
|
|
544
|
+
repo
|
|
545
|
+
] })
|
|
546
|
+
]
|
|
547
|
+
}
|
|
548
|
+
),
|
|
549
|
+
image: data.user.avatarUrl
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
function formatStargazers(n) {
|
|
554
|
+
return n.toLocaleString("en-US");
|
|
555
|
+
}
|
|
556
|
+
const githubRepoPlugin = {
|
|
557
|
+
name: "gh-repo",
|
|
558
|
+
displayName: "GitHub Repository",
|
|
559
|
+
priority: 100,
|
|
560
|
+
typeClass: "github",
|
|
561
|
+
provider: "github",
|
|
562
|
+
matchUrl(url) {
|
|
563
|
+
if (url.hostname !== "github.com") return null;
|
|
564
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
565
|
+
if (parts.length !== 2) return null;
|
|
566
|
+
const [owner, repo] = parts;
|
|
567
|
+
if (!owner || !repo) return null;
|
|
568
|
+
return { id: `${owner}/${repo}`, fullUrl: url.toString() };
|
|
569
|
+
},
|
|
570
|
+
isValidId(id) {
|
|
571
|
+
const parts = id.split("/");
|
|
572
|
+
return parts.length === 2 && parts[0].length > 0 && parts[1].length > 0;
|
|
573
|
+
},
|
|
574
|
+
async fetch(id, _meta, context) {
|
|
575
|
+
const [owner, repo] = id.split("/");
|
|
576
|
+
const response = await fetchGitHubApi(`https://api.github.com/repos/${owner}/${repo}`, context);
|
|
577
|
+
const data = camelcaseKeys(response);
|
|
578
|
+
return {
|
|
579
|
+
title: /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
580
|
+
/* @__PURE__ */ jsx("span", { style: { flex: 1 }, children: data.name }),
|
|
581
|
+
/* @__PURE__ */ jsx("span", { style: { flexShrink: 0 }, children: data.stargazersCount > 0 && /* @__PURE__ */ jsxs(
|
|
582
|
+
"span",
|
|
583
|
+
{
|
|
584
|
+
style: {
|
|
585
|
+
display: "inline-flex",
|
|
586
|
+
alignItems: "center",
|
|
587
|
+
gap: "4px",
|
|
588
|
+
fontSize: vars.typography.fontSizeMd,
|
|
589
|
+
color: "#fb923c"
|
|
590
|
+
},
|
|
591
|
+
children: [
|
|
592
|
+
/* @__PURE__ */ jsx(Star, { "aria-hidden": true, size: 14, strokeWidth: 2 }),
|
|
593
|
+
/* @__PURE__ */ jsx("span", { style: { fontFamily: "sans-serif", fontWeight: 500 }, children: formatStargazers(data.stargazersCount) })
|
|
594
|
+
]
|
|
595
|
+
}
|
|
596
|
+
) })
|
|
597
|
+
] }),
|
|
598
|
+
desc: data.description,
|
|
599
|
+
image: data.owner.avatarUrl,
|
|
600
|
+
color: LanguageToColorMap[data.language?.toLowerCase()]
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
const bangumiPlugin = {
|
|
605
|
+
name: "bangumi",
|
|
606
|
+
displayName: "Bangumi",
|
|
607
|
+
priority: 70,
|
|
608
|
+
typeClass: "media",
|
|
609
|
+
provider: "bangumi",
|
|
610
|
+
matchUrl(url) {
|
|
611
|
+
if (url.hostname !== "bgm.tv" && url.hostname !== "bangumi.tv") return null;
|
|
612
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
613
|
+
if (parts.length < 2) return null;
|
|
614
|
+
const [type, realId] = parts;
|
|
615
|
+
if (!allowedBangumiTypes.includes(type)) return null;
|
|
616
|
+
return { id: `${type}/${realId}`, fullUrl: url.toString(), meta: { type } };
|
|
617
|
+
},
|
|
618
|
+
isValidId(id) {
|
|
619
|
+
const [type, realId] = id.split("/");
|
|
620
|
+
return allowedBangumiTypes.includes(type) && realId?.length > 0;
|
|
621
|
+
},
|
|
622
|
+
async fetch(id, _meta, context) {
|
|
623
|
+
const [type, realId] = id.split("/");
|
|
624
|
+
const json = await fetchJsonWithContext(
|
|
625
|
+
`https://api.bgm.tv/v0/${bangumiTypeMap[type]}/${realId}`,
|
|
626
|
+
context,
|
|
627
|
+
"bangumi"
|
|
628
|
+
);
|
|
629
|
+
let title2 = "";
|
|
630
|
+
let originalTitle = "";
|
|
631
|
+
if (type === "subject") {
|
|
632
|
+
if (json.name_cn && json.name_cn !== json.name && json.name_cn !== "") {
|
|
633
|
+
title2 = json.name_cn;
|
|
634
|
+
originalTitle = json.name;
|
|
635
|
+
} else {
|
|
636
|
+
title2 = json.name;
|
|
637
|
+
originalTitle = json.name;
|
|
638
|
+
}
|
|
639
|
+
} else if (type === "character" || type === "person") {
|
|
640
|
+
const { infobox } = json;
|
|
641
|
+
infobox.forEach(
|
|
642
|
+
(item) => {
|
|
643
|
+
if (item.key === "简体中文名") {
|
|
644
|
+
title2 = typeof item.value === "string" ? item.value : item.value[0].v;
|
|
645
|
+
} else if (item.key === "别名") {
|
|
646
|
+
const aliases = item.value;
|
|
647
|
+
aliases.forEach((alias) => {
|
|
648
|
+
originalTitle += `${alias.v} / `;
|
|
649
|
+
});
|
|
650
|
+
originalTitle = originalTitle.slice(0, -3);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
const starStyle = {
|
|
656
|
+
display: "inline-flex",
|
|
657
|
+
flexShrink: 0,
|
|
658
|
+
alignItems: "center",
|
|
659
|
+
gap: "4px",
|
|
660
|
+
alignSelf: "center",
|
|
661
|
+
fontSize: vars.typography.fontSizeXs,
|
|
662
|
+
color: "#fb923c"
|
|
663
|
+
};
|
|
664
|
+
return {
|
|
665
|
+
title: /* @__PURE__ */ jsxs(
|
|
666
|
+
"span",
|
|
667
|
+
{
|
|
668
|
+
style: {
|
|
669
|
+
display: "flex",
|
|
670
|
+
flexWrap: "wrap",
|
|
671
|
+
alignItems: "flex-end",
|
|
672
|
+
gap: "8px"
|
|
673
|
+
},
|
|
674
|
+
children: [
|
|
675
|
+
/* @__PURE__ */ jsx("span", { children: title2 }),
|
|
676
|
+
title2 !== originalTitle && /* @__PURE__ */ jsxs(
|
|
677
|
+
"span",
|
|
678
|
+
{
|
|
679
|
+
style: { fontSize: vars.typography.fontSizeMd, opacity: 0.7 },
|
|
680
|
+
children: [
|
|
681
|
+
"(",
|
|
682
|
+
originalTitle,
|
|
683
|
+
")"
|
|
684
|
+
]
|
|
685
|
+
}
|
|
686
|
+
),
|
|
687
|
+
type === "subject" && /* @__PURE__ */ jsxs(
|
|
688
|
+
"span",
|
|
689
|
+
{
|
|
690
|
+
style: {
|
|
691
|
+
display: "inline-flex",
|
|
692
|
+
flexShrink: 0,
|
|
693
|
+
alignItems: "center",
|
|
694
|
+
gap: "12px",
|
|
695
|
+
alignSelf: "center"
|
|
696
|
+
},
|
|
697
|
+
children: [
|
|
698
|
+
/* @__PURE__ */ jsxs("span", { style: starStyle, children: [
|
|
699
|
+
"★",
|
|
700
|
+
/* @__PURE__ */ jsx("span", { style: { fontFamily: "sans-serif", fontWeight: 500 }, children: json.rating.score > 0 && json.rating.score.toFixed(1) })
|
|
701
|
+
] }),
|
|
702
|
+
/* @__PURE__ */ jsxs("span", { style: starStyle, children: [
|
|
703
|
+
"☆",
|
|
704
|
+
/* @__PURE__ */ jsx("span", { style: { fontFamily: "sans-serif", fontWeight: 500 }, children: json.collection && json.collection.on_hold + json.collection.dropped + json.collection.wish + json.collection.collect + json.collection.doing })
|
|
705
|
+
] })
|
|
706
|
+
]
|
|
707
|
+
}
|
|
708
|
+
),
|
|
709
|
+
(type === "character" || type === "person") && /* @__PURE__ */ jsxs("span", { style: starStyle, children: [
|
|
710
|
+
"☆",
|
|
711
|
+
/* @__PURE__ */ jsx("span", { style: { fontFamily: "sans-serif", fontWeight: 500 }, children: json.stat.collects > 0 && json.stat.collects })
|
|
712
|
+
] })
|
|
713
|
+
]
|
|
714
|
+
}
|
|
715
|
+
),
|
|
716
|
+
desc: /* @__PURE__ */ jsx("span", { style: { overflow: "visible", whiteSpace: "pre-wrap" }, children: json.summary }),
|
|
717
|
+
image: json.images.grid,
|
|
718
|
+
color: generateColor(title2),
|
|
719
|
+
classNames: {
|
|
720
|
+
image: "link-card__image--poster",
|
|
721
|
+
cardRoot: "link-card--poster"
|
|
722
|
+
}
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
const neteaseMusicPlugin = {
|
|
727
|
+
name: "netease-music-song",
|
|
728
|
+
displayName: "Netease Music Song",
|
|
729
|
+
priority: 60,
|
|
730
|
+
typeClass: "wide",
|
|
731
|
+
provider: "netease-music",
|
|
732
|
+
matchUrl(url) {
|
|
733
|
+
if (url.hostname !== "music.163.com") return null;
|
|
734
|
+
if (!url.pathname.includes("/song") && !url.hash.includes("/song"))
|
|
735
|
+
return null;
|
|
736
|
+
const urlString = url.toString().replaceAll("/#/", "/");
|
|
737
|
+
const _url = new URL(urlString);
|
|
738
|
+
const id = _url.searchParams.get("id");
|
|
739
|
+
if (!id) return null;
|
|
740
|
+
return { id, fullUrl: url.toString() };
|
|
741
|
+
},
|
|
742
|
+
isValidId(id) {
|
|
743
|
+
return id.length > 0;
|
|
744
|
+
},
|
|
745
|
+
async fetch(id, _meta, context) {
|
|
746
|
+
const songData = await fetchJsonWithContext(
|
|
747
|
+
`https://music.163.com/song/${id}`,
|
|
748
|
+
context,
|
|
749
|
+
"netease-music"
|
|
750
|
+
);
|
|
751
|
+
const songInfo = songData.songs[0];
|
|
752
|
+
const albumInfo = songInfo.al;
|
|
753
|
+
const singerInfo = songInfo.ar;
|
|
754
|
+
return {
|
|
755
|
+
title: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
756
|
+
/* @__PURE__ */ jsx("span", { children: songInfo.name }),
|
|
757
|
+
songInfo.tns && /* @__PURE__ */ jsx(
|
|
758
|
+
"span",
|
|
759
|
+
{
|
|
760
|
+
style: {
|
|
761
|
+
marginLeft: "8px",
|
|
762
|
+
fontSize: vars.typography.fontSizeMd,
|
|
763
|
+
color: "#a1a1aa"
|
|
764
|
+
},
|
|
765
|
+
children: songInfo.tns[0]
|
|
766
|
+
}
|
|
767
|
+
)
|
|
768
|
+
] }),
|
|
769
|
+
desc: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
770
|
+
/* @__PURE__ */ jsxs("span", { style: { display: "block" }, children: [
|
|
771
|
+
/* @__PURE__ */ jsx("span", { style: { fontWeight: "bold" }, children: "歌手:" }),
|
|
772
|
+
/* @__PURE__ */ jsx("span", { children: singerInfo.map((p) => p.name).join(" / ") })
|
|
773
|
+
] }),
|
|
774
|
+
/* @__PURE__ */ jsxs("span", { style: { display: "block" }, children: [
|
|
775
|
+
/* @__PURE__ */ jsx("span", { style: { fontWeight: "bold" }, children: "专辑:" }),
|
|
776
|
+
/* @__PURE__ */ jsx("span", { children: albumInfo.name })
|
|
777
|
+
] })
|
|
778
|
+
] }),
|
|
779
|
+
image: albumInfo.picUrl,
|
|
780
|
+
color: "#e72d2c"
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
};
|
|
784
|
+
const qqMusicPlugin = {
|
|
785
|
+
name: "qq-music-song",
|
|
786
|
+
displayName: "QQ Music Song",
|
|
787
|
+
priority: 60,
|
|
788
|
+
typeClass: "wide",
|
|
789
|
+
provider: "qq-music",
|
|
790
|
+
matchUrl(url) {
|
|
791
|
+
if (url.hostname !== "y.qq.com") return null;
|
|
792
|
+
if (!url.pathname.includes("/songDetail/")) return null;
|
|
793
|
+
const parts = url.pathname.split("/");
|
|
794
|
+
const songDetailIndex = parts.indexOf("songDetail");
|
|
795
|
+
if (songDetailIndex === -1 || !parts[songDetailIndex + 1]) return null;
|
|
796
|
+
return { id: parts[songDetailIndex + 1], fullUrl: url.toString() };
|
|
797
|
+
},
|
|
798
|
+
isValidId(id) {
|
|
799
|
+
return typeof id === "string" && id.length > 0;
|
|
800
|
+
},
|
|
801
|
+
async fetch(id, _meta, context) {
|
|
802
|
+
const songData = await fetchJsonWithContext(
|
|
803
|
+
`https://y.qq.com/song/${id}`,
|
|
804
|
+
context,
|
|
805
|
+
"qq-music"
|
|
806
|
+
);
|
|
807
|
+
const songInfo = songData.data[0];
|
|
808
|
+
const albumId = songInfo.album.mid;
|
|
809
|
+
return {
|
|
810
|
+
title: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
811
|
+
/* @__PURE__ */ jsx("span", { children: songInfo.title }),
|
|
812
|
+
songInfo.subtitle && /* @__PURE__ */ jsx(
|
|
813
|
+
"span",
|
|
814
|
+
{
|
|
815
|
+
style: {
|
|
816
|
+
marginLeft: "8px",
|
|
817
|
+
fontSize: vars.typography.fontSizeMd,
|
|
818
|
+
color: "#a1a1aa"
|
|
819
|
+
},
|
|
820
|
+
children: songInfo.subtitle
|
|
821
|
+
}
|
|
822
|
+
)
|
|
823
|
+
] }),
|
|
824
|
+
desc: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
825
|
+
/* @__PURE__ */ jsxs("span", { style: { display: "block" }, children: [
|
|
826
|
+
/* @__PURE__ */ jsx("span", { style: { fontWeight: "bold" }, children: "歌手:" }),
|
|
827
|
+
/* @__PURE__ */ jsx("span", { children: songInfo.singer.map((p) => p.name).join(" / ") })
|
|
828
|
+
] }),
|
|
829
|
+
/* @__PURE__ */ jsxs("span", { style: { display: "block" }, children: [
|
|
830
|
+
/* @__PURE__ */ jsx("span", { style: { fontWeight: "bold" }, children: "专辑:" }),
|
|
831
|
+
/* @__PURE__ */ jsx("span", { children: songInfo.album.name })
|
|
832
|
+
] })
|
|
833
|
+
] }),
|
|
834
|
+
image: `https://y.gtimg.cn/music/photo_new/T002R300x300M000${albumId}.jpg?max_age=2592000`,
|
|
835
|
+
color: "#31c27c"
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
};
|
|
839
|
+
const TMDB_LANGUAGE_BY_LOCALE = {
|
|
840
|
+
zh: "zh-CN",
|
|
841
|
+
en: "en-US",
|
|
842
|
+
ja: "ja-JP"
|
|
843
|
+
};
|
|
844
|
+
const getCurrentLocale = () => {
|
|
845
|
+
if (typeof document !== "undefined") {
|
|
846
|
+
const lang = document.documentElement?.lang?.trim();
|
|
847
|
+
if (lang) return lang;
|
|
848
|
+
}
|
|
849
|
+
if (typeof window !== "undefined") {
|
|
850
|
+
const firstSegment = window.location.pathname.split("/").find((s) => s.length > 0);
|
|
851
|
+
if (firstSegment) return firstSegment;
|
|
852
|
+
}
|
|
853
|
+
return "en";
|
|
854
|
+
};
|
|
855
|
+
const tmdbPlugin = {
|
|
856
|
+
name: "tmdb",
|
|
857
|
+
displayName: "The Movie Database",
|
|
858
|
+
priority: 70,
|
|
859
|
+
typeClass: "media",
|
|
860
|
+
provider: "tmdb",
|
|
861
|
+
matchUrl(url) {
|
|
862
|
+
if (!url.hostname.includes("themoviedb.org")) return null;
|
|
863
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
864
|
+
if (parts.length < 2) return null;
|
|
865
|
+
const [type, realId] = parts;
|
|
866
|
+
const canParsedTypes = ["tv", "movie"];
|
|
867
|
+
if (!canParsedTypes.includes(type) || !realId) return null;
|
|
868
|
+
return { id: `${type}/${realId}`, fullUrl: url.toString(), meta: { type } };
|
|
869
|
+
},
|
|
870
|
+
isValidId(id) {
|
|
871
|
+
const [type, realId] = id.split("/");
|
|
872
|
+
const canParsedTypes = ["tv", "movie"];
|
|
873
|
+
return canParsedTypes.includes(type) && realId?.length > 0;
|
|
874
|
+
},
|
|
875
|
+
async fetch(id, _meta, context) {
|
|
876
|
+
const [type, realId] = id.split("/");
|
|
877
|
+
const locale = getCurrentLocale();
|
|
878
|
+
const userLanguage = TMDB_LANGUAGE_BY_LOCALE[locale] || (typeof navigator !== "undefined" ? navigator.language : "en-US") || "en-US";
|
|
879
|
+
const json = await fetchJsonWithContext(
|
|
880
|
+
`https://api.themoviedb.org/3/${type}/${realId}?language=${userLanguage}`,
|
|
881
|
+
context,
|
|
882
|
+
"tmdb"
|
|
883
|
+
);
|
|
884
|
+
const title2 = type === "tv" ? json.name : json.title;
|
|
885
|
+
const originalTitle = type === "tv" ? json.original_name : json.original_title;
|
|
886
|
+
return {
|
|
887
|
+
title: /* @__PURE__ */ jsxs(
|
|
888
|
+
"span",
|
|
889
|
+
{
|
|
890
|
+
style: {
|
|
891
|
+
display: "flex",
|
|
892
|
+
flexWrap: "wrap",
|
|
893
|
+
alignItems: "flex-end",
|
|
894
|
+
gap: "8px"
|
|
895
|
+
},
|
|
896
|
+
children: [
|
|
897
|
+
/* @__PURE__ */ jsx("span", { children: title2 }),
|
|
898
|
+
title2 !== originalTitle && /* @__PURE__ */ jsxs(
|
|
899
|
+
"span",
|
|
900
|
+
{
|
|
901
|
+
style: { fontSize: vars.typography.fontSizeMd, opacity: 0.7 },
|
|
902
|
+
children: [
|
|
903
|
+
"(",
|
|
904
|
+
originalTitle,
|
|
905
|
+
")"
|
|
906
|
+
]
|
|
907
|
+
}
|
|
908
|
+
),
|
|
909
|
+
/* @__PURE__ */ jsxs(
|
|
910
|
+
"span",
|
|
911
|
+
{
|
|
912
|
+
style: {
|
|
913
|
+
display: "inline-flex",
|
|
914
|
+
flexShrink: 0,
|
|
915
|
+
alignItems: "center",
|
|
916
|
+
gap: "4px",
|
|
917
|
+
alignSelf: "center",
|
|
918
|
+
fontSize: vars.typography.fontSizeXs,
|
|
919
|
+
color: "#fb923c"
|
|
920
|
+
},
|
|
921
|
+
children: [
|
|
922
|
+
"★",
|
|
923
|
+
/* @__PURE__ */ jsx("span", { style: { fontFamily: "sans-serif", fontWeight: 500 }, children: json.vote_average > 0 && json.vote_average.toFixed(1) })
|
|
924
|
+
]
|
|
925
|
+
}
|
|
926
|
+
)
|
|
927
|
+
]
|
|
928
|
+
}
|
|
929
|
+
),
|
|
930
|
+
desc: /* @__PURE__ */ jsx("span", { style: { overflow: "visible", whiteSpace: "pre-wrap" }, children: json.overview }),
|
|
931
|
+
image: `https://image.tmdb.org/t/p/w500${json.poster_path}`,
|
|
932
|
+
color: generateColor(title2 || originalTitle || id),
|
|
933
|
+
classNames: {
|
|
934
|
+
image: "link-card__image--poster",
|
|
935
|
+
cardRoot: "link-card--poster"
|
|
936
|
+
}
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
};
|
|
940
|
+
function createMxSpacePlugin(config) {
|
|
941
|
+
const webHost = new URL(config.webUrl).hostname;
|
|
942
|
+
return {
|
|
943
|
+
name: "self",
|
|
944
|
+
displayName: "MxSpace Article",
|
|
945
|
+
priority: 10,
|
|
946
|
+
provider: "mx-space",
|
|
947
|
+
matchUrl(url) {
|
|
948
|
+
if (webHost !== url.hostname) return null;
|
|
949
|
+
if (!url.pathname.startsWith("/posts/") && !url.pathname.startsWith("/notes/")) {
|
|
950
|
+
return null;
|
|
951
|
+
}
|
|
952
|
+
return { id: url.pathname.slice(1), fullUrl: url.toString() };
|
|
953
|
+
},
|
|
954
|
+
isValidId(id) {
|
|
955
|
+
const [type, ...rest] = id.split("/");
|
|
956
|
+
if (type !== "posts" && type !== "notes") return false;
|
|
957
|
+
if (type === "posts") return rest.length === 2;
|
|
958
|
+
return rest.length === 1;
|
|
959
|
+
},
|
|
960
|
+
async fetch(id, _meta, context) {
|
|
961
|
+
const [type, ...rest] = id.split("/");
|
|
962
|
+
let data = { title: "", text: "" };
|
|
963
|
+
if (type === "posts") {
|
|
964
|
+
const [cate, slug] = rest;
|
|
965
|
+
data = await fetchJsonWithContext(
|
|
966
|
+
`posts/${cate}/${slug}`,
|
|
967
|
+
context,
|
|
968
|
+
"mx-space"
|
|
969
|
+
);
|
|
970
|
+
} else if (type === "notes") {
|
|
971
|
+
const [nid] = rest;
|
|
972
|
+
const response = await fetchJsonWithContext(
|
|
973
|
+
`notes/${nid}`,
|
|
974
|
+
context,
|
|
975
|
+
"mx-space"
|
|
976
|
+
);
|
|
977
|
+
data = response.data || response;
|
|
978
|
+
}
|
|
979
|
+
const coverImage = data.cover || data.meta?.cover;
|
|
980
|
+
const spotlightColor = generateColor(data.title);
|
|
981
|
+
return {
|
|
982
|
+
title: data.title,
|
|
983
|
+
desc: data.summary || `${stripMarkdown(data.text).slice(0, 50)}...`,
|
|
984
|
+
image: coverImage || data.images?.[0]?.src,
|
|
985
|
+
color: spotlightColor
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
const plugins = [
|
|
991
|
+
githubRepoPlugin,
|
|
992
|
+
githubCommitPlugin,
|
|
993
|
+
githubPrPlugin,
|
|
994
|
+
githubIssuePlugin,
|
|
995
|
+
githubDiscussionPlugin,
|
|
996
|
+
arxivPlugin,
|
|
997
|
+
tmdbPlugin,
|
|
998
|
+
bangumiPlugin,
|
|
999
|
+
qqMusicPlugin,
|
|
1000
|
+
neteaseMusicPlugin,
|
|
1001
|
+
leetcodePlugin
|
|
1002
|
+
].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
1003
|
+
function getPluginByName(name) {
|
|
1004
|
+
return plugins.find((p) => p.name === name);
|
|
1005
|
+
}
|
|
1006
|
+
const pluginMap = new Map(
|
|
1007
|
+
plugins.map((p) => [p.name, p])
|
|
1008
|
+
);
|
|
1009
|
+
function matchUrl(url, pluginRegistry = plugins) {
|
|
1010
|
+
try {
|
|
1011
|
+
const parsed = new URL(url);
|
|
1012
|
+
for (const plugin of pluginRegistry) {
|
|
1013
|
+
const match = plugin.matchUrl(parsed);
|
|
1014
|
+
if (match) return { plugin, match };
|
|
1015
|
+
}
|
|
1016
|
+
} catch {
|
|
1017
|
+
}
|
|
1018
|
+
return null;
|
|
1019
|
+
}
|
|
1020
|
+
function useUrlMatcher(url, pluginRegistry = plugins) {
|
|
1021
|
+
return useMemo(() => {
|
|
1022
|
+
if (!url) return null;
|
|
1023
|
+
return matchUrl(url, pluginRegistry);
|
|
1024
|
+
}, [url, pluginRegistry]);
|
|
1025
|
+
}
|
|
1026
|
+
var semanticClassNames = { card: "link-card", cardShortDesc: "link-card--short-desc", cardSkeleton: "link-card--skeleton", cardError: "link-card--error", bg: "link-card__bg", image: "link-card__image", icon: "link-card__icon", content: "link-card__content", title: "link-card__title", titleText: "link-card__title-text", desc: "link-card__desc", desc2: "link-card__desc-2", editWrapper: "rich-link-card-edit-wrapper", editPanel: "rich-link-card-edit-panel", editUrlRow: "rich-link-card-edit-url-row", editLinkIcon: "rich-link-card-edit-link-icon", editInput: "rich-link-card-edit-input" };
|
|
1027
|
+
var card = "_13weebv0";
|
|
1028
|
+
var cardShortDesc = "_13weebv1";
|
|
1029
|
+
var bg = "_13weebv2";
|
|
1030
|
+
var image = "_13weebv3";
|
|
1031
|
+
var icon = "_13weebv5";
|
|
1032
|
+
var content = "_13weebv6";
|
|
1033
|
+
var title = "_13weebv7";
|
|
1034
|
+
var titleText = "_13weebv8";
|
|
1035
|
+
var desc = "_13weebv9";
|
|
1036
|
+
var desc2 = "_13weebva";
|
|
1037
|
+
var cardSkeleton = "_13weebvg";
|
|
1038
|
+
var cardError = "_13weebvi";
|
|
1039
|
+
var editWrapper = "_13weebvj";
|
|
1040
|
+
var editPanel = "_13weebvk";
|
|
1041
|
+
var editUrlRow = "_13weebvl";
|
|
1042
|
+
var editLinkIcon = "_13weebvm";
|
|
1043
|
+
var editInput = "_13weebvn";
|
|
1044
|
+
var typeCardModifier = { media: "_13weebvd", github: "_13weebve", academic: "_13weebvf", wide: "_13weebvc" };
|
|
1045
|
+
var semanticTypeClassNames = { media: "link-card--media", github: "link-card--github", academic: "link-card--academic", wide: "link-card--wide" };
|
|
1046
|
+
var semanticClassToStyle = { "link-card--short-desc": "_13weebv1", "link-card--skeleton": "_13weebvg", "link-card--error": "_13weebvi", "link-card--poster": "_13weebvb", "link-card--wide": "_13weebvc", "link-card--media": "_13weebvd", "link-card--github": "_13weebve", "link-card--academic": "_13weebvf", "link-card__image--poster": "_13weebv4" };
|
|
1047
|
+
const ctx = createContext(void 0);
|
|
1048
|
+
const LinkCardFetchProvider = ctx.Provider;
|
|
1049
|
+
function useLinkCardFetchContext() {
|
|
1050
|
+
return use(ctx);
|
|
1051
|
+
}
|
|
1052
|
+
function useCardFetcher(options) {
|
|
1053
|
+
const { source, plugin, id, fallbackUrl, enabled = true, context } = options;
|
|
1054
|
+
const [loading, setLoading] = useState(true);
|
|
1055
|
+
const [isError, setIsError] = useState(false);
|
|
1056
|
+
const [fullUrl] = useState(fallbackUrl || "javascript:;");
|
|
1057
|
+
const [cardInfo, setCardInfo] = useState();
|
|
1058
|
+
const isValid = useMemo(() => {
|
|
1059
|
+
if (!enabled || !plugin) return false;
|
|
1060
|
+
return plugin.isValidId(id);
|
|
1061
|
+
}, [plugin, enabled, id]);
|
|
1062
|
+
const fetchInfo = useCallback(async () => {
|
|
1063
|
+
if (!plugin || !isValid) return;
|
|
1064
|
+
setLoading(true);
|
|
1065
|
+
setIsError(false);
|
|
1066
|
+
try {
|
|
1067
|
+
const data = await plugin.fetch(id, void 0, context);
|
|
1068
|
+
setCardInfo(data);
|
|
1069
|
+
} catch (err) {
|
|
1070
|
+
console.error(`[LinkCard] Error fetching ${source || plugin.name} data:`, err);
|
|
1071
|
+
setIsError(true);
|
|
1072
|
+
} finally {
|
|
1073
|
+
setLoading(false);
|
|
1074
|
+
}
|
|
1075
|
+
}, [context, plugin, isValid, id, source]);
|
|
1076
|
+
const { ref } = useInView({
|
|
1077
|
+
triggerOnce: true,
|
|
1078
|
+
onChange(inView) {
|
|
1079
|
+
if (!inView || !enabled) return;
|
|
1080
|
+
fetchInfo();
|
|
1081
|
+
}
|
|
1082
|
+
});
|
|
1083
|
+
return {
|
|
1084
|
+
loading,
|
|
1085
|
+
isError,
|
|
1086
|
+
cardInfo,
|
|
1087
|
+
fullUrl,
|
|
1088
|
+
isValid,
|
|
1089
|
+
ref
|
|
1090
|
+
};
|
|
1091
|
+
}
|
|
1092
|
+
function LinkCardSkeleton({
|
|
1093
|
+
source,
|
|
1094
|
+
className
|
|
1095
|
+
}) {
|
|
1096
|
+
const plugin = source ? pluginMap.get(source) : void 0;
|
|
1097
|
+
const typeClass = plugin?.typeClass;
|
|
1098
|
+
const typeStyleClass = typeClass ? typeCardModifier[typeClass] : "";
|
|
1099
|
+
const typeSemanticClass = typeClass ? semanticTypeClassNames[typeClass] : "";
|
|
1100
|
+
return /* @__PURE__ */ jsxs(
|
|
1101
|
+
"span",
|
|
1102
|
+
{
|
|
1103
|
+
"data-hide-print": true,
|
|
1104
|
+
"data-source": source || void 0,
|
|
1105
|
+
className: [
|
|
1106
|
+
card,
|
|
1107
|
+
semanticClassNames.card,
|
|
1108
|
+
cardSkeleton,
|
|
1109
|
+
semanticClassNames.cardSkeleton,
|
|
1110
|
+
typeStyleClass,
|
|
1111
|
+
typeSemanticClass,
|
|
1112
|
+
className
|
|
1113
|
+
].filter(Boolean).join(" "),
|
|
1114
|
+
children: [
|
|
1115
|
+
/* @__PURE__ */ jsx("span", { className: `${image} ${semanticClassNames.image}` }),
|
|
1116
|
+
/* @__PURE__ */ jsxs(
|
|
1117
|
+
"span",
|
|
1118
|
+
{
|
|
1119
|
+
className: `${content} ${semanticClassNames.content}`,
|
|
1120
|
+
children: [
|
|
1121
|
+
/* @__PURE__ */ jsx("span", { className: `${title} ${semanticClassNames.title}`, children: /* @__PURE__ */ jsx(
|
|
1122
|
+
"span",
|
|
1123
|
+
{
|
|
1124
|
+
className: `${titleText} ${semanticClassNames.titleText}`
|
|
1125
|
+
}
|
|
1126
|
+
) }),
|
|
1127
|
+
/* @__PURE__ */ jsx("span", { className: `${desc} ${semanticClassNames.desc}` }),
|
|
1128
|
+
/* @__PURE__ */ jsx(
|
|
1129
|
+
"span",
|
|
1130
|
+
{
|
|
1131
|
+
className: `${desc} ${semanticClassNames.desc} ${desc2} ${semanticClassNames.desc2}`
|
|
1132
|
+
}
|
|
1133
|
+
)
|
|
1134
|
+
]
|
|
1135
|
+
}
|
|
1136
|
+
)
|
|
1137
|
+
]
|
|
1138
|
+
}
|
|
1139
|
+
);
|
|
1140
|
+
}
|
|
1141
|
+
function FallbackIcon({ favicon }) {
|
|
1142
|
+
const [faviconFailed, setFaviconFailed] = useState(false);
|
|
1143
|
+
return /* @__PURE__ */ jsx("span", { className: `${icon} ${semanticClassNames.icon}`, children: favicon && !faviconFailed ? /* @__PURE__ */ jsx("img", { alt: "", src: favicon, onError: () => setFaviconFailed(true) }) : /* @__PURE__ */ jsx(Globe, { "aria-hidden": "true" }) });
|
|
1144
|
+
}
|
|
1145
|
+
function mapSemanticClasses(classNames) {
|
|
1146
|
+
if (!classNames) return "";
|
|
1147
|
+
return classNames.split(/\s+/).filter(Boolean).map(
|
|
1148
|
+
(cls) => semanticClassToStyle[cls] ? `${semanticClassToStyle[cls]} ${cls}` : cls
|
|
1149
|
+
).join(" ");
|
|
1150
|
+
}
|
|
1151
|
+
const LinkCardRenderer = (props) => {
|
|
1152
|
+
const {
|
|
1153
|
+
url,
|
|
1154
|
+
title: title$1,
|
|
1155
|
+
description,
|
|
1156
|
+
favicon,
|
|
1157
|
+
image: image$1,
|
|
1158
|
+
source: explicitSource,
|
|
1159
|
+
id: explicitId,
|
|
1160
|
+
className,
|
|
1161
|
+
plugins: extraPlugins,
|
|
1162
|
+
fetchContext: fetchContextProp
|
|
1163
|
+
} = props;
|
|
1164
|
+
const contextValue = useLinkCardFetchContext();
|
|
1165
|
+
const fetchContext = fetchContextProp ?? contextValue;
|
|
1166
|
+
const mergedPlugins = useMemo(() => {
|
|
1167
|
+
if (!extraPlugins || extraPlugins.length === 0) return plugins;
|
|
1168
|
+
const map = new Map(plugins.map((p) => [p.name, p]));
|
|
1169
|
+
for (const plugin of extraPlugins) {
|
|
1170
|
+
map.set(plugin.name, plugin);
|
|
1171
|
+
}
|
|
1172
|
+
return [...map.values()].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
1173
|
+
}, [extraPlugins]);
|
|
1174
|
+
const pluginMap2 = useMemo(
|
|
1175
|
+
() => new Map(mergedPlugins.map((plugin) => [plugin.name, plugin])),
|
|
1176
|
+
[mergedPlugins]
|
|
1177
|
+
);
|
|
1178
|
+
const urlMatch = useUrlMatcher(!explicitSource || !explicitId ? url : void 0, mergedPlugins);
|
|
1179
|
+
const source = explicitSource || urlMatch?.plugin.name;
|
|
1180
|
+
const id = explicitId || urlMatch?.match.id;
|
|
1181
|
+
const matchedFullUrl = urlMatch?.match.fullUrl;
|
|
1182
|
+
const useDynamicFetch = !!source && !!id;
|
|
1183
|
+
const selectedPlugin = source ? pluginMap2.get(source) : void 0;
|
|
1184
|
+
const { loading, isError, cardInfo, fullUrl, isValid, ref } = useCardFetcher({
|
|
1185
|
+
source,
|
|
1186
|
+
plugin: selectedPlugin,
|
|
1187
|
+
id: id || "",
|
|
1188
|
+
fallbackUrl: matchedFullUrl || url,
|
|
1189
|
+
enabled: useDynamicFetch,
|
|
1190
|
+
context: fetchContext
|
|
1191
|
+
});
|
|
1192
|
+
const typeClass = selectedPlugin?.typeClass;
|
|
1193
|
+
const typeStyleClass = typeClass ? typeCardModifier[typeClass] : "";
|
|
1194
|
+
const typeSemanticClass = typeClass ? semanticTypeClassNames[typeClass] : "";
|
|
1195
|
+
const isErrorState = useDynamicFetch && isError;
|
|
1196
|
+
const finalTitle = cardInfo?.title || title$1 || (isErrorState ? "" : url);
|
|
1197
|
+
const finalDesc = cardInfo?.desc || description;
|
|
1198
|
+
const finalImage = cardInfo?.image || image$1;
|
|
1199
|
+
const finalColor = cardInfo?.color;
|
|
1200
|
+
const classNames = cardInfo?.classNames || {};
|
|
1201
|
+
const mappedCardRootClass = mapSemanticClasses(classNames.cardRoot);
|
|
1202
|
+
const mappedImageClass = mapSemanticClasses(classNames.image);
|
|
1203
|
+
const [shortDesc, setShortDesc] = useState(false);
|
|
1204
|
+
const descRef = useRef(null);
|
|
1205
|
+
useEffect(() => {
|
|
1206
|
+
const el = descRef.current;
|
|
1207
|
+
if (!el || !finalDesc) {
|
|
1208
|
+
setShortDesc(false);
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1211
|
+
const style = getComputedStyle(el);
|
|
1212
|
+
const lineHeight = Number.parseFloat(style.lineHeight) || 1.5 * 14;
|
|
1213
|
+
const maxTwoLines = lineHeight * 2;
|
|
1214
|
+
setShortDesc(el.scrollHeight <= maxTwoLines + 1);
|
|
1215
|
+
}, [finalDesc, finalTitle]);
|
|
1216
|
+
if (useDynamicFetch && !isValid) {
|
|
1217
|
+
return null;
|
|
1218
|
+
}
|
|
1219
|
+
if (useDynamicFetch && loading) {
|
|
1220
|
+
return /* @__PURE__ */ jsx("a", { "data-hide-print": true, href: fullUrl, ref, rel: "noopener noreferrer", target: "_blank", children: /* @__PURE__ */ jsx(LinkCardSkeleton, { source }) });
|
|
1221
|
+
}
|
|
1222
|
+
const hasImage = !!finalImage;
|
|
1223
|
+
const showImagePlaceholder = isErrorState && !hasImage;
|
|
1224
|
+
const shouldCenterContent = !finalDesc || shortDesc;
|
|
1225
|
+
return /* @__PURE__ */ jsxs(
|
|
1226
|
+
"a",
|
|
1227
|
+
{
|
|
1228
|
+
"data-hide-print": true,
|
|
1229
|
+
"data-source": source || void 0,
|
|
1230
|
+
href: useDynamicFetch ? fullUrl : url,
|
|
1231
|
+
ref: useDynamicFetch ? ref : void 0,
|
|
1232
|
+
rel: "noopener noreferrer",
|
|
1233
|
+
target: "_blank",
|
|
1234
|
+
className: [
|
|
1235
|
+
card,
|
|
1236
|
+
semanticClassNames.card,
|
|
1237
|
+
typeStyleClass,
|
|
1238
|
+
typeSemanticClass,
|
|
1239
|
+
shouldCenterContent && cardShortDesc,
|
|
1240
|
+
shouldCenterContent && semanticClassNames.cardShortDesc,
|
|
1241
|
+
useDynamicFetch && (loading || isError) && cardSkeleton,
|
|
1242
|
+
useDynamicFetch && (loading || isError) && semanticClassNames.cardSkeleton,
|
|
1243
|
+
useDynamicFetch && isError && cardError,
|
|
1244
|
+
useDynamicFetch && isError && semanticClassNames.cardError,
|
|
1245
|
+
"not-prose",
|
|
1246
|
+
className,
|
|
1247
|
+
mappedCardRootClass
|
|
1248
|
+
].filter(Boolean).join(" "),
|
|
1249
|
+
style: {
|
|
1250
|
+
borderColor: finalColor ? `${finalColor}30` : void 0
|
|
1251
|
+
},
|
|
1252
|
+
children: [
|
|
1253
|
+
finalColor && /* @__PURE__ */ jsx(
|
|
1254
|
+
"div",
|
|
1255
|
+
{
|
|
1256
|
+
className: `${bg} ${semanticClassNames.bg}`,
|
|
1257
|
+
style: {
|
|
1258
|
+
backgroundColor: finalColor,
|
|
1259
|
+
opacity: 0.04
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
),
|
|
1263
|
+
hasImage || showImagePlaceholder ? /* @__PURE__ */ jsx(
|
|
1264
|
+
"span",
|
|
1265
|
+
{
|
|
1266
|
+
"data-image": finalImage || "",
|
|
1267
|
+
className: [image, semanticClassNames.image, mappedImageClass].filter(Boolean).join(" "),
|
|
1268
|
+
style: {
|
|
1269
|
+
backgroundImage: finalImage ? `url(${finalImage})` : void 0
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
) : /* @__PURE__ */ jsx(FallbackIcon, { favicon }),
|
|
1273
|
+
/* @__PURE__ */ jsxs("span", { className: `${content} ${semanticClassNames.content}`, children: [
|
|
1274
|
+
/* @__PURE__ */ jsx("span", { className: `${title} ${semanticClassNames.title}`, children: /* @__PURE__ */ jsx("span", { className: `${titleText} ${semanticClassNames.titleText}`, children: finalTitle }) }),
|
|
1275
|
+
finalDesc && /* @__PURE__ */ jsx("span", { className: `${desc} ${semanticClassNames.desc}`, ref: descRef, children: finalDesc })
|
|
1276
|
+
] })
|
|
1277
|
+
]
|
|
1278
|
+
}
|
|
1279
|
+
);
|
|
1280
|
+
};
|
|
1281
|
+
export {
|
|
1282
|
+
semanticClassNames as A,
|
|
1283
|
+
editPanel as B,
|
|
1284
|
+
editUrlRow as C,
|
|
1285
|
+
editLinkIcon as D,
|
|
1286
|
+
editInput as E,
|
|
1287
|
+
LanguageToColorMap as L,
|
|
1288
|
+
LinkCardFetchProvider as a,
|
|
1289
|
+
LinkCardRenderer as b,
|
|
1290
|
+
LinkCardSkeleton as c,
|
|
1291
|
+
arxivPlugin as d,
|
|
1292
|
+
bangumiPlugin as e,
|
|
1293
|
+
camelcaseKeys as f,
|
|
1294
|
+
createMxSpacePlugin as g,
|
|
1295
|
+
fetchGitHubApi as h,
|
|
1296
|
+
fetchJsonWithContext as i,
|
|
1297
|
+
generateColor as j,
|
|
1298
|
+
getPluginByName as k,
|
|
1299
|
+
githubCommitPlugin as l,
|
|
1300
|
+
githubDiscussionPlugin as m,
|
|
1301
|
+
githubIssuePlugin as n,
|
|
1302
|
+
githubPrPlugin as o,
|
|
1303
|
+
githubRepoPlugin as p,
|
|
1304
|
+
leetcodePlugin as q,
|
|
1305
|
+
matchUrl as r,
|
|
1306
|
+
neteaseMusicPlugin as s,
|
|
1307
|
+
pluginMap as t,
|
|
1308
|
+
plugins as u,
|
|
1309
|
+
qqMusicPlugin as v,
|
|
1310
|
+
tmdbPlugin as w,
|
|
1311
|
+
useLinkCardFetchContext as x,
|
|
1312
|
+
useUrlMatcher as y,
|
|
1313
|
+
editWrapper as z
|
|
1314
|
+
};
|