@asteroidcms/core-utils 0.1.1 → 0.1.3
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 +71 -0
- package/dist/client.cjs +1466 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +229 -0
- package/dist/client.d.ts +229 -0
- package/dist/client.js +1455 -0
- package/dist/client.js.map +1 -0
- package/dist/index.cjs +49 -670
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -157
- package/dist/index.d.ts +12 -157
- package/dist/index.js +48 -661
- package/dist/index.js.map +1 -1
- package/package.json +7 -2
package/dist/index.js
CHANGED
|
@@ -1,23 +1,8 @@
|
|
|
1
|
-
import { createContext, useContext, useMemo, useRef, useEffect, createElement } from 'react';
|
|
2
|
-
import { ApolloProvider, useQuery, useMutation } from '@apollo/client/react';
|
|
3
1
|
import { HttpLink, ApolloClient, InMemoryCache, ApolloLink, gql, CombinedGraphQLErrors, CombinedProtocolErrors } from '@apollo/client';
|
|
4
2
|
import { SetContextLink } from '@apollo/client/link/context';
|
|
5
3
|
import { ErrorLink } from '@apollo/client/link/error';
|
|
6
|
-
import { jsx } from 'react/jsx-runtime';
|
|
7
|
-
import hljs from 'highlight.js/lib/common';
|
|
8
|
-
import 'highlight.js/styles/tokyo-night-dark.css';
|
|
9
4
|
|
|
10
|
-
// src/
|
|
11
|
-
var AsteroidCMSContext = createContext(null);
|
|
12
|
-
function useAsteroidCMSConfig() {
|
|
13
|
-
const ctx = useContext(AsteroidCMSContext);
|
|
14
|
-
if (!ctx) {
|
|
15
|
-
throw new Error(
|
|
16
|
-
"useAsteroidCMSConfig must be used inside <AsteroidCMSProvider>. Wrap your app with <AsteroidCMSProvider cmsUrl=... apiKey=... />."
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
return ctx;
|
|
20
|
-
}
|
|
5
|
+
// src/apollo/createApolloClient.ts
|
|
21
6
|
function createErrorLink(onError) {
|
|
22
7
|
return new ErrorLink(({ error }) => {
|
|
23
8
|
if (!onError) return;
|
|
@@ -77,30 +62,32 @@ function createApolloClient(config) {
|
|
|
77
62
|
...config.apolloOptions
|
|
78
63
|
});
|
|
79
64
|
}
|
|
80
|
-
function
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
65
|
+
function buildSelection(items = []) {
|
|
66
|
+
const lines = [];
|
|
67
|
+
items.forEach((item) => {
|
|
68
|
+
if (typeof item === "string") {
|
|
69
|
+
lines.push(`${item}: dataField(slug: "${item}")`);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if ("field" in item && typeof item.field === "string") {
|
|
73
|
+
if (!("select" in item)) {
|
|
74
|
+
const alias2 = item.as || item.field;
|
|
75
|
+
lines.push(`${alias2}: dataField(slug: "${item.field}")`);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const alias = item.as || item.field;
|
|
79
|
+
const resolver = item.single ? "expandedReferenceObject" : "expandedReference";
|
|
80
|
+
const subSelection = item.select?.length ? buildSelection(item.select) : "data { ... }";
|
|
81
|
+
lines.push(`
|
|
82
|
+
${alias}: ${resolver}(slug: "${item.field}") {
|
|
83
|
+
${subSelection}
|
|
84
|
+
}
|
|
85
|
+
`);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
return lines.join("\n ").trim();
|
|
102
89
|
}
|
|
103
|
-
function
|
|
90
|
+
function buildCmsQuery({
|
|
104
91
|
schema_slug,
|
|
105
92
|
entrySlug,
|
|
106
93
|
select = [],
|
|
@@ -112,35 +99,16 @@ function useCmsContent({
|
|
|
112
99
|
search,
|
|
113
100
|
variables = {}
|
|
114
101
|
}) {
|
|
115
|
-
const isSingle =
|
|
116
|
-
const buildSelection = (items = []) => {
|
|
117
|
-
const lines = [];
|
|
118
|
-
items.forEach((item) => {
|
|
119
|
-
if (typeof item === "string") {
|
|
120
|
-
lines.push(`${item}: dataField(slug: "${item}")`);
|
|
121
|
-
} else if ("field" in item && typeof item.field === "string") {
|
|
122
|
-
if (!("select" in item)) {
|
|
123
|
-
const alias2 = item.as || item.field;
|
|
124
|
-
lines.push(`${alias2}: dataField(slug: "${item.field}")`);
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
const alias = item.as || item.field;
|
|
128
|
-
const resolver = item.single ? "expandedReferenceObject" : "expandedReference";
|
|
129
|
-
const subSelection = item.select?.length ? buildSelection(item.select) : "data { ... }";
|
|
130
|
-
lines.push(`
|
|
131
|
-
${alias}: ${resolver}(slug: "${item.field}") {
|
|
132
|
-
${subSelection}
|
|
133
|
-
}
|
|
134
|
-
`);
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
return lines.join("\n ").trim();
|
|
138
|
-
};
|
|
102
|
+
const isSingle = Boolean(entrySlug);
|
|
139
103
|
const selectionParts = [];
|
|
140
|
-
if (fullData)
|
|
104
|
+
if (fullData) {
|
|
105
|
+
selectionParts.push("data");
|
|
106
|
+
}
|
|
141
107
|
if (select.length > 0) {
|
|
142
108
|
const userSelection = buildSelection(select);
|
|
143
|
-
if (userSelection)
|
|
109
|
+
if (userSelection) {
|
|
110
|
+
selectionParts.push(userSelection);
|
|
111
|
+
}
|
|
144
112
|
}
|
|
145
113
|
const selection = selectionParts.join("\n ").trim() || "id";
|
|
146
114
|
const queryVariables = {
|
|
@@ -159,8 +127,11 @@ function useCmsContent({
|
|
|
159
127
|
queryVariables.offset = offset;
|
|
160
128
|
}
|
|
161
129
|
if (status) {
|
|
162
|
-
|
|
163
|
-
|
|
130
|
+
const statuses = status;
|
|
131
|
+
if (statuses.length > 0) {
|
|
132
|
+
fieldArgParts.push("status: $status");
|
|
133
|
+
queryVariables.status = statuses;
|
|
134
|
+
}
|
|
164
135
|
}
|
|
165
136
|
const hasSearch = Array.isArray(search) && search.length > 0;
|
|
166
137
|
const hasFilter = filter && typeof filter === "object" && Object.keys(filter).length > 0;
|
|
@@ -201,109 +172,18 @@ function useCmsContent({
|
|
|
201
172
|
}
|
|
202
173
|
}
|
|
203
174
|
`;
|
|
204
|
-
const GET_CONTENT = gql(queryStr);
|
|
205
|
-
const { loading, error, data, ...rest } = useQuery(GET_CONTENT, {
|
|
206
|
-
variables: queryVariables,
|
|
207
|
-
skip: !schema_slug || isSingle && !entrySlug
|
|
208
|
-
});
|
|
209
|
-
const typed = data;
|
|
210
|
-
const result = isSingle ? typed?.entry : typed?.entries;
|
|
211
175
|
return {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
...rest
|
|
176
|
+
query: gql(queryStr),
|
|
177
|
+
variables: queryVariables,
|
|
178
|
+
isSingle
|
|
216
179
|
};
|
|
217
180
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
variables: inputVariables = {}
|
|
225
|
-
}) {
|
|
226
|
-
const buildSelection = (items = []) => {
|
|
227
|
-
const lines = [];
|
|
228
|
-
for (const item of items) {
|
|
229
|
-
if (typeof item === "string") {
|
|
230
|
-
lines.push(`${item}: dataField(slug: "${item}")`);
|
|
231
|
-
continue;
|
|
232
|
-
}
|
|
233
|
-
const { field, as, single, select: subSelect } = item;
|
|
234
|
-
const alias = as || field;
|
|
235
|
-
if (!subSelect?.length) {
|
|
236
|
-
lines.push(`${alias}: dataField(slug: "${field}")`);
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
const resolver = single ? "expandedReferenceObject" : "expandedReference";
|
|
240
|
-
const sub = buildSelection(subSelect) || "id slug";
|
|
241
|
-
lines.push(`
|
|
242
|
-
${alias}: ${resolver}(slug: "${field}") {
|
|
243
|
-
id
|
|
244
|
-
slug
|
|
245
|
-
${sub}
|
|
246
|
-
}
|
|
247
|
-
`);
|
|
248
|
-
}
|
|
249
|
-
return lines.join("\n ").trim();
|
|
250
|
-
};
|
|
251
|
-
const userSelection = buildSelection(select);
|
|
252
|
-
let selection = fullData ? "data" : "";
|
|
253
|
-
if (userSelection) {
|
|
254
|
-
selection = selection ? `${selection}
|
|
255
|
-
${userSelection}` : userSelection;
|
|
256
|
-
}
|
|
257
|
-
if (!selection) {
|
|
258
|
-
selection = "id slug status version created_at updated_at";
|
|
259
|
-
}
|
|
260
|
-
const operation = mutationType;
|
|
261
|
-
const mutationName = `${operation}ContentEntry`;
|
|
262
|
-
const varDecls = ["$schema_slug: String!"];
|
|
263
|
-
const callArgs = ["schema_slug: $schema_slug"];
|
|
264
|
-
if (operation === "create" || operation === "update") {
|
|
265
|
-
varDecls.unshift("$data: JSONObject!");
|
|
266
|
-
callArgs.unshift("data: $data");
|
|
267
|
-
}
|
|
268
|
-
if (operation === "update" || operation === "delete") {
|
|
269
|
-
varDecls.push("$id: ID!");
|
|
270
|
-
callArgs.push("id: $id");
|
|
271
|
-
}
|
|
272
|
-
const returnFields = selection.includes("data") ? selection : `${selection}
|
|
273
|
-
data`;
|
|
274
|
-
const MUTATION = gql`
|
|
275
|
-
mutation ${mutationName}(${varDecls.join(", ")}) {
|
|
276
|
-
result: ${mutationName}(${callArgs.join(", ")}) {
|
|
277
|
-
id
|
|
278
|
-
status
|
|
279
|
-
version
|
|
280
|
-
created_at
|
|
281
|
-
updated_at
|
|
282
|
-
schema {
|
|
283
|
-
id
|
|
284
|
-
slug
|
|
285
|
-
}
|
|
286
|
-
${returnFields}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
`;
|
|
290
|
-
const mutationVariables = {
|
|
291
|
-
schema_slug,
|
|
292
|
-
...operation === "update" || operation === "delete" ? { id: entryId } : {},
|
|
293
|
-
...inputVariables
|
|
294
|
-
};
|
|
295
|
-
if ((operation === "update" || operation === "delete") && !entryId) {
|
|
296
|
-
console.warn(`useCmsMutate: entryId is required for ${operation}`);
|
|
297
|
-
}
|
|
298
|
-
const [mutateFn, mutationResult] = useMutation(MUTATION, {
|
|
299
|
-
variables: mutationVariables
|
|
300
|
-
});
|
|
301
|
-
const resultData = mutationResult.data?.result;
|
|
302
|
-
return {
|
|
303
|
-
mutate: mutateFn,
|
|
304
|
-
...mutationResult,
|
|
305
|
-
data: resultData
|
|
306
|
-
};
|
|
181
|
+
|
|
182
|
+
// src/fetchCmsContent.ts
|
|
183
|
+
async function fetchCmsContent(getClient, opts) {
|
|
184
|
+
const { query, variables, isSingle } = buildCmsQuery(opts);
|
|
185
|
+
const { data } = await getClient().query({ query, variables });
|
|
186
|
+
return isSingle ? data.entry : data.entries;
|
|
307
187
|
}
|
|
308
188
|
|
|
309
189
|
// src/utils/cmsImage.ts
|
|
@@ -313,10 +193,6 @@ function cmsImage(id, options) {
|
|
|
313
193
|
const path = (options.mediaPath ?? "/media/canonical").replace(/^\/?/, "/");
|
|
314
194
|
return `${base}${path}/${id}`;
|
|
315
195
|
}
|
|
316
|
-
function useCmsImage() {
|
|
317
|
-
const { cmsUrl, mediaPath } = useAsteroidCMSConfig();
|
|
318
|
-
return (id) => cmsImage(id, { cmsUrl, mediaPath });
|
|
319
|
-
}
|
|
320
196
|
|
|
321
197
|
// src/utils/getContentReadTime.ts
|
|
322
198
|
function getContentReadTime(content, options = {}) {
|
|
@@ -990,495 +866,6 @@ function sanitizeAndStyle(html, options) {
|
|
|
990
866
|
return out.join("");
|
|
991
867
|
}
|
|
992
868
|
|
|
993
|
-
|
|
994
|
-
var DEFAULT_CLASS_MAP = {
|
|
995
|
-
variants: {
|
|
996
|
-
"figure:pullquote": "relative my-8",
|
|
997
|
-
"blockquote:pullquote": "relative italic text-lg leading-snug tracking-[-0.01em] sm:text-xl",
|
|
998
|
-
"figcaption:pullquote": "mt-4 pt-3 border-t border-current/15 not-italic text-xs uppercase tracking-[0.14em] opacity-80",
|
|
999
|
-
"span:quote-open": "mr-1 font-serif text-[1.4em] leading-none align-[-0.15em] opacity-60 select-none",
|
|
1000
|
-
"span:quote-close": "ml-1 font-serif text-[1.4em] leading-none align-[-0.15em] opacity-60 select-none",
|
|
1001
|
-
"span:author": "ml-1 font-semibold not-italic tracking-[0.16em] text-current"
|
|
1002
|
-
}
|
|
1003
|
-
};
|
|
1004
|
-
function mergeClassMap(defaults, user) {
|
|
1005
|
-
if (!user) return defaults;
|
|
1006
|
-
return {
|
|
1007
|
-
...defaults,
|
|
1008
|
-
...user,
|
|
1009
|
-
variants: { ...defaults.variants, ...user.variants }
|
|
1010
|
-
};
|
|
1011
|
-
}
|
|
1012
|
-
var COPY_ICON_SVG = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`;
|
|
1013
|
-
var CHECK_ICON_SVG = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"></polyline></svg>`;
|
|
1014
|
-
var ATTRIBUTION_RE = /^(?:[—–-]+|--)\s+\S/;
|
|
1015
|
-
function isAttributionEl(el) {
|
|
1016
|
-
if (!el) return false;
|
|
1017
|
-
if (el.getAttribute("data-variant") === "attribution") return true;
|
|
1018
|
-
return ATTRIBUTION_RE.test((el.textContent ?? "").trim());
|
|
1019
|
-
}
|
|
1020
|
-
function findQuoteBody(bq) {
|
|
1021
|
-
const children = Array.from(bq.children);
|
|
1022
|
-
if (children.length === 0) return { first: null, last: null };
|
|
1023
|
-
let lastIdx = children.length - 1;
|
|
1024
|
-
while (lastIdx >= 0 && isAttributionEl(children[lastIdx])) lastIdx--;
|
|
1025
|
-
if (lastIdx < 0) return { first: null, last: null };
|
|
1026
|
-
return { first: children[0], last: children[lastIdx] };
|
|
1027
|
-
}
|
|
1028
|
-
function enhanceBlockquotes(root) {
|
|
1029
|
-
const quotes = root.querySelectorAll("blockquote");
|
|
1030
|
-
quotes.forEach((bq) => {
|
|
1031
|
-
if (bq.dataset.rtQuoted === "1") return;
|
|
1032
|
-
if (bq.closest('figure[data-variant="pullquote"]')) return;
|
|
1033
|
-
bq.dataset.rtQuoted = "1";
|
|
1034
|
-
const { first, last } = findQuoteBody(bq);
|
|
1035
|
-
if (!first || !last) return;
|
|
1036
|
-
const open = document.createElement("span");
|
|
1037
|
-
open.className = "rt-quote-open";
|
|
1038
|
-
open.setAttribute("aria-hidden", "true");
|
|
1039
|
-
open.textContent = "\u201C";
|
|
1040
|
-
const close = document.createElement("span");
|
|
1041
|
-
close.className = "rt-quote-close";
|
|
1042
|
-
close.setAttribute("aria-hidden", "true");
|
|
1043
|
-
close.textContent = "\u201D";
|
|
1044
|
-
first.prepend(open);
|
|
1045
|
-
last.append(close);
|
|
1046
|
-
});
|
|
1047
|
-
}
|
|
1048
|
-
function escapeHtml2(s) {
|
|
1049
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1050
|
-
}
|
|
1051
|
-
function preserveSpaces(html) {
|
|
1052
|
-
return html.replace(/ {2,}/g, (m) => " ".repeat(m.length));
|
|
1053
|
-
}
|
|
1054
|
-
function highlightSource(src, lang) {
|
|
1055
|
-
if (lang && hljs.getLanguage(lang)) {
|
|
1056
|
-
try {
|
|
1057
|
-
return hljs.highlight(src, { language: lang, ignoreIllegals: true }).value;
|
|
1058
|
-
} catch {
|
|
1059
|
-
}
|
|
1060
|
-
}
|
|
1061
|
-
return escapeHtml2(src);
|
|
1062
|
-
}
|
|
1063
|
-
function highlightLine(line, lang) {
|
|
1064
|
-
if (!line) return "";
|
|
1065
|
-
return preserveSpaces(highlightSource(line, lang));
|
|
1066
|
-
}
|
|
1067
|
-
function highlightCodeBlock(pre) {
|
|
1068
|
-
const lang = pre.dataset.language;
|
|
1069
|
-
if (!lang) return;
|
|
1070
|
-
const code = pre.querySelector("code");
|
|
1071
|
-
if (!code) return;
|
|
1072
|
-
if (code.dataset.rtHighlighted === "1") return;
|
|
1073
|
-
const source = code.textContent ?? "";
|
|
1074
|
-
code.innerHTML = highlightSource(source, lang);
|
|
1075
|
-
code.classList.add("hljs");
|
|
1076
|
-
code.dataset.rtHighlighted = "1";
|
|
1077
|
-
}
|
|
1078
|
-
var DIFF_SEPARATOR_RE = /\n?@@---@@\n?/;
|
|
1079
|
-
function diffLines(a, b) {
|
|
1080
|
-
const n = a.length;
|
|
1081
|
-
const m = b.length;
|
|
1082
|
-
const dp = Array.from(
|
|
1083
|
-
{ length: n + 1 },
|
|
1084
|
-
() => new Array(m + 1).fill(0)
|
|
1085
|
-
);
|
|
1086
|
-
for (let i2 = 1; i2 <= n; i2++) {
|
|
1087
|
-
for (let j2 = 1; j2 <= m; j2++) {
|
|
1088
|
-
dp[i2][j2] = a[i2 - 1] === b[j2 - 1] ? dp[i2 - 1][j2 - 1] + 1 : Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
const ops = [];
|
|
1092
|
-
let i = n;
|
|
1093
|
-
let j = m;
|
|
1094
|
-
while (i > 0 && j > 0) {
|
|
1095
|
-
if (a[i - 1] === b[j - 1]) {
|
|
1096
|
-
ops.unshift({ t: "eq", line: a[i - 1] });
|
|
1097
|
-
i--;
|
|
1098
|
-
j--;
|
|
1099
|
-
} else if (dp[i - 1][j] >= dp[i][j - 1]) {
|
|
1100
|
-
ops.unshift({ t: "rem", line: a[i - 1] });
|
|
1101
|
-
i--;
|
|
1102
|
-
} else {
|
|
1103
|
-
ops.unshift({ t: "add", line: b[j - 1] });
|
|
1104
|
-
j--;
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
while (i > 0) ops.unshift({ t: "rem", line: a[--i] });
|
|
1108
|
-
while (j > 0) ops.unshift({ t: "add", line: b[--j] });
|
|
1109
|
-
return ops;
|
|
1110
|
-
}
|
|
1111
|
-
function renderDiff(before, after, lang) {
|
|
1112
|
-
const ops = diffLines(before.split("\n"), after.split("\n"));
|
|
1113
|
-
const rows = [];
|
|
1114
|
-
let aNo = 0;
|
|
1115
|
-
let bNo = 0;
|
|
1116
|
-
let k = 0;
|
|
1117
|
-
while (k < ops.length) {
|
|
1118
|
-
const op = ops[k];
|
|
1119
|
-
if (op.t === "eq") {
|
|
1120
|
-
aNo++;
|
|
1121
|
-
bNo++;
|
|
1122
|
-
rows.push({
|
|
1123
|
-
left: { n: aNo, line: op.line, cls: "" },
|
|
1124
|
-
right: { n: bNo, line: op.line, cls: "" }
|
|
1125
|
-
});
|
|
1126
|
-
k++;
|
|
1127
|
-
continue;
|
|
1128
|
-
}
|
|
1129
|
-
const rems = [];
|
|
1130
|
-
while (k < ops.length && ops[k].t === "rem") {
|
|
1131
|
-
rems.push(ops[k].line);
|
|
1132
|
-
k++;
|
|
1133
|
-
}
|
|
1134
|
-
const adds = [];
|
|
1135
|
-
while (k < ops.length && ops[k].t === "add") {
|
|
1136
|
-
adds.push(ops[k].line);
|
|
1137
|
-
k++;
|
|
1138
|
-
}
|
|
1139
|
-
const len = Math.max(rems.length, adds.length);
|
|
1140
|
-
for (let x = 0; x < len; x++) {
|
|
1141
|
-
const remLine = x < rems.length ? rems[x] : null;
|
|
1142
|
-
const addLine = x < adds.length ? adds[x] : null;
|
|
1143
|
-
rows.push({
|
|
1144
|
-
left: {
|
|
1145
|
-
n: remLine !== null ? ++aNo : null,
|
|
1146
|
-
line: remLine,
|
|
1147
|
-
cls: remLine !== null ? "rt-diff-rem" : "rt-diff-empty"
|
|
1148
|
-
},
|
|
1149
|
-
right: {
|
|
1150
|
-
n: addLine !== null ? ++bNo : null,
|
|
1151
|
-
line: addLine,
|
|
1152
|
-
cls: addLine !== null ? "rt-diff-add" : "rt-diff-empty"
|
|
1153
|
-
}
|
|
1154
|
-
});
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
const cell = (c, side) => {
|
|
1158
|
-
const sign = side === "l" ? "-" : "+";
|
|
1159
|
-
const showSign = c.cls === "rt-diff-rem" || c.cls === "rt-diff-add";
|
|
1160
|
-
return `<td class="rt-diff-num">${c.n ?? ""}</td><td class="rt-diff-sign">${showSign ? sign : ""}</td><td class="rt-diff-line ${c.cls}">${c.line === null ? "" : highlightLine(c.line, lang) || " "}</td>`;
|
|
1161
|
-
};
|
|
1162
|
-
const body = rows.map((r) => `<tr>${cell(r.left, "l")}${cell(r.right, "r")}</tr>`).join("");
|
|
1163
|
-
return `<table class="rt-diff-table"><tbody>${body}</tbody></table>`;
|
|
1164
|
-
}
|
|
1165
|
-
function makeCopyButton(getText, opts = {}) {
|
|
1166
|
-
const btn = document.createElement("button");
|
|
1167
|
-
btn.type = "button";
|
|
1168
|
-
btn.className = opts.className ?? "rt-codeblock__copy";
|
|
1169
|
-
btn.setAttribute("aria-label", opts.label ?? "Copy code");
|
|
1170
|
-
btn.innerHTML = COPY_ICON_SVG;
|
|
1171
|
-
btn.addEventListener("click", async () => {
|
|
1172
|
-
try {
|
|
1173
|
-
await navigator.clipboard.writeText(getText());
|
|
1174
|
-
btn.innerHTML = CHECK_ICON_SVG;
|
|
1175
|
-
btn.classList.add("is-copied");
|
|
1176
|
-
window.setTimeout(() => {
|
|
1177
|
-
btn.innerHTML = COPY_ICON_SVG;
|
|
1178
|
-
btn.classList.remove("is-copied");
|
|
1179
|
-
}, 1500);
|
|
1180
|
-
} catch {
|
|
1181
|
-
}
|
|
1182
|
-
});
|
|
1183
|
-
return btn;
|
|
1184
|
-
}
|
|
1185
|
-
function buildCodeBlockLabel(pre) {
|
|
1186
|
-
const filename = pre.dataset.filename;
|
|
1187
|
-
if (!filename) return null;
|
|
1188
|
-
const tag = document.createElement("span");
|
|
1189
|
-
tag.className = "rt-codeblock__label";
|
|
1190
|
-
const file = document.createElement("span");
|
|
1191
|
-
file.className = "rt-codeblock__filename rt-codeblock__language";
|
|
1192
|
-
file.textContent = filename;
|
|
1193
|
-
tag.appendChild(file);
|
|
1194
|
-
return tag;
|
|
1195
|
-
}
|
|
1196
|
-
function enhanceCodeBlocks(root) {
|
|
1197
|
-
const blocks = root.querySelectorAll("pre");
|
|
1198
|
-
blocks.forEach((pre) => {
|
|
1199
|
-
if (pre.dataset.rtEnhanced === "1") return;
|
|
1200
|
-
pre.dataset.rtEnhanced = "1";
|
|
1201
|
-
pre.classList.add("rt-codeblock");
|
|
1202
|
-
const variant = pre.dataset.variant;
|
|
1203
|
-
if (variant === "diff") {
|
|
1204
|
-
const codeEl = pre.querySelector("code");
|
|
1205
|
-
const src = codeEl?.textContent ?? "";
|
|
1206
|
-
const [beforeSrc = "", afterSrc = ""] = src.split(DIFF_SEPARATOR_RE);
|
|
1207
|
-
pre.innerHTML = renderDiff(beforeSrc, afterSrc, pre.dataset.language);
|
|
1208
|
-
const bar = document.createElement("div");
|
|
1209
|
-
bar.className = "rt-diff-copy-bar";
|
|
1210
|
-
const leftHalf = document.createElement("div");
|
|
1211
|
-
leftHalf.className = "rt-diff-copy-half";
|
|
1212
|
-
leftHalf.appendChild(
|
|
1213
|
-
makeCopyButton(() => beforeSrc, {
|
|
1214
|
-
className: "rt-diff-copy",
|
|
1215
|
-
label: "Copy before"
|
|
1216
|
-
})
|
|
1217
|
-
);
|
|
1218
|
-
const rightHalf = document.createElement("div");
|
|
1219
|
-
rightHalf.className = "rt-diff-copy-half";
|
|
1220
|
-
rightHalf.appendChild(
|
|
1221
|
-
makeCopyButton(() => afterSrc, {
|
|
1222
|
-
className: "rt-diff-copy",
|
|
1223
|
-
label: "Copy after"
|
|
1224
|
-
})
|
|
1225
|
-
);
|
|
1226
|
-
bar.appendChild(leftHalf);
|
|
1227
|
-
bar.appendChild(rightHalf);
|
|
1228
|
-
pre.prepend(bar);
|
|
1229
|
-
const label2 = buildCodeBlockLabel(pre);
|
|
1230
|
-
if (label2) pre.prepend(label2);
|
|
1231
|
-
return;
|
|
1232
|
-
}
|
|
1233
|
-
if (variant === "terminal") {
|
|
1234
|
-
pre.classList.add("rt-terminal");
|
|
1235
|
-
const codeEl = pre.querySelector("code");
|
|
1236
|
-
const source = codeEl?.textContent ?? "";
|
|
1237
|
-
if (codeEl) {
|
|
1238
|
-
const lang = pre.dataset.language || "sh";
|
|
1239
|
-
const lines = source.split("\n");
|
|
1240
|
-
codeEl.innerHTML = lines.map(
|
|
1241
|
-
(line) => `<span class="rt-term-line"><span class="rt-term-prompt" aria-hidden="true">$</span> ${highlightLine(line, lang) || " "}</span>`
|
|
1242
|
-
).join("");
|
|
1243
|
-
}
|
|
1244
|
-
pre.appendChild(makeCopyButton(() => source, { label: "Copy commands" }));
|
|
1245
|
-
return;
|
|
1246
|
-
}
|
|
1247
|
-
const label = buildCodeBlockLabel(pre);
|
|
1248
|
-
if (label) pre.prepend(label);
|
|
1249
|
-
pre.appendChild(
|
|
1250
|
-
makeCopyButton(
|
|
1251
|
-
() => pre.querySelector("code")?.textContent ?? pre.innerText
|
|
1252
|
-
)
|
|
1253
|
-
);
|
|
1254
|
-
highlightCodeBlock(pre);
|
|
1255
|
-
});
|
|
1256
|
-
}
|
|
1257
|
-
var CODEBLOCK_STYLE = `
|
|
1258
|
-
.rt-codeblock { position: relative; }
|
|
1259
|
-
.rt-codeblock[data-filename]:not([data-filename=""]) { padding-top: 2rem; }
|
|
1260
|
-
.rt-codeblock__label {
|
|
1261
|
-
position: absolute; top: 0.45rem; left: 0.85rem;
|
|
1262
|
-
display: inline-flex; align-items: center; gap: 0.5rem;
|
|
1263
|
-
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
1264
|
-
pointer-events: none;
|
|
1265
|
-
}
|
|
1266
|
-
.rt-codeblock__filename {
|
|
1267
|
-
font-size: 0.72rem; letter-spacing: 0.02em;
|
|
1268
|
-
color: #d1d5db;
|
|
1269
|
-
}
|
|
1270
|
-
.rt-codeblock__sep {
|
|
1271
|
-
color: #6b7280;
|
|
1272
|
-
font-size: 0.72rem;
|
|
1273
|
-
}
|
|
1274
|
-
.rt-codeblock__language {
|
|
1275
|
-
font-size: 0.6rem; letter-spacing: 0.08em;
|
|
1276
|
-
text-transform: lowercase;
|
|
1277
|
-
color: #9ca3af;
|
|
1278
|
-
padding: 0.05rem 0.35rem;
|
|
1279
|
-
border: 1px solid rgba(255,255,255,0.12);
|
|
1280
|
-
border-radius: 0.25rem;
|
|
1281
|
-
}
|
|
1282
|
-
.rt-codeblock__copy {
|
|
1283
|
-
position: absolute; top: 0.4rem; right: 0.4rem;
|
|
1284
|
-
display: inline-flex; align-items: center; justify-content: center;
|
|
1285
|
-
width: 1.75rem; height: 1.75rem; padding: 0;
|
|
1286
|
-
border: 1px solid rgba(255,255,255,0.08);
|
|
1287
|
-
border-radius: 0.375rem;
|
|
1288
|
-
background: rgba(255,255,255,0.04);
|
|
1289
|
-
color: #d1d5db;
|
|
1290
|
-
cursor: pointer;
|
|
1291
|
-
opacity: 0; transition: opacity 120ms ease, background 120ms ease, color 120ms ease;
|
|
1292
|
-
}
|
|
1293
|
-
.rt-codeblock:hover .rt-codeblock__copy,
|
|
1294
|
-
.rt-codeblock:focus-within .rt-codeblock__copy { opacity: 1; }
|
|
1295
|
-
.rt-codeblock__copy:hover { background: rgba(255,255,255,0.1); color: #fff; }
|
|
1296
|
-
.rt-codeblock__copy.is-copied { color: #34d399; opacity: 1; }
|
|
1297
|
-
@media (hover: none) { .rt-codeblock__copy { opacity: 1; } }
|
|
1298
|
-
.rt-quote-open, .rt-quote-close {
|
|
1299
|
-
font-family: Georgia, "Times New Roman", serif;
|
|
1300
|
-
font-size: 1.4em;
|
|
1301
|
-
line-height: 0;
|
|
1302
|
-
vertical-align: -0.15em;
|
|
1303
|
-
opacity: 0.6;
|
|
1304
|
-
user-select: none;
|
|
1305
|
-
}
|
|
1306
|
-
.rt-quote-open { margin-right: 0.15em; }
|
|
1307
|
-
.rt-quote-close { margin-left: 0.15em; }
|
|
1308
|
-
/* highlight.js theme handles .hljs-* color classes; we only override the
|
|
1309
|
-
default .hljs background so the per-block chrome (dark bg, terminal,
|
|
1310
|
-
diff red/green rows) wins. */
|
|
1311
|
-
.rt-codeblock .hljs,
|
|
1312
|
-
.rt-codeblock code.hljs { background: transparent; padding: 0; }
|
|
1313
|
-
|
|
1314
|
-
/* Terminal variant ------------------------------------------------------- */
|
|
1315
|
-
.rt-codeblock.rt-terminal,
|
|
1316
|
-
.rt-codeblock[data-variant="terminal"] {
|
|
1317
|
-
position: relative;
|
|
1318
|
-
padding-top: 2.25rem;
|
|
1319
|
-
background: #0b0b0d;
|
|
1320
|
-
border: 1px solid rgba(255,255,255,0.08);
|
|
1321
|
-
border-radius: 0.65rem;
|
|
1322
|
-
box-shadow: 0 1px 0 rgba(255,255,255,0.04) inset,
|
|
1323
|
-
0 10px 30px -10px rgba(0,0,0,0.6);
|
|
1324
|
-
}
|
|
1325
|
-
.rt-codeblock.rt-terminal::before,
|
|
1326
|
-
.rt-codeblock[data-variant="terminal"]::before {
|
|
1327
|
-
content: "";
|
|
1328
|
-
position: absolute; top: 0; left: 0; right: 0; height: 1.75rem;
|
|
1329
|
-
background: linear-gradient(#1a1a1d, #141417);
|
|
1330
|
-
border-bottom: 1px solid rgba(255,255,255,0.06);
|
|
1331
|
-
border-radius: 0.65rem 0.65rem 0 0;
|
|
1332
|
-
}
|
|
1333
|
-
.rt-codeblock.rt-terminal::after,
|
|
1334
|
-
.rt-codeblock[data-variant="terminal"]::after {
|
|
1335
|
-
content: "";
|
|
1336
|
-
position: absolute; top: 0.55rem; left: 0.75rem;
|
|
1337
|
-
width: 0.65rem; height: 0.65rem; border-radius: 50%;
|
|
1338
|
-
background: #ff5f57;
|
|
1339
|
-
box-shadow:
|
|
1340
|
-
1.1rem 0 0 0 #febc2e,
|
|
1341
|
-
2.2rem 0 0 0 #28c840;
|
|
1342
|
-
}
|
|
1343
|
-
.rt-codeblock.rt-terminal code,
|
|
1344
|
-
.rt-codeblock[data-variant="terminal"] code {
|
|
1345
|
-
color: #d4d4d8;
|
|
1346
|
-
display: block;
|
|
1347
|
-
}
|
|
1348
|
-
.rt-term-line { display: block; white-space: pre-wrap; }
|
|
1349
|
-
.rt-term-prompt {
|
|
1350
|
-
color: #28c840;
|
|
1351
|
-
font-weight: 600;
|
|
1352
|
-
margin-right: 0.35em;
|
|
1353
|
-
user-select: none;
|
|
1354
|
-
}
|
|
1355
|
-
|
|
1356
|
-
/* Diff variant ----------------------------------------------------------- */
|
|
1357
|
-
.rt-codeblock[data-variant="diff"] {
|
|
1358
|
-
padding: 0;
|
|
1359
|
-
overflow: hidden;
|
|
1360
|
-
background: #0b0b0d;
|
|
1361
|
-
border: 1px solid rgba(255,255,255,0.08);
|
|
1362
|
-
}
|
|
1363
|
-
.rt-codeblock[data-variant="diff"][data-filename]:not([data-filename=""]) {
|
|
1364
|
-
padding-top: 2rem;
|
|
1365
|
-
}
|
|
1366
|
-
.rt-diff-table {
|
|
1367
|
-
width: 100%;
|
|
1368
|
-
border-collapse: collapse;
|
|
1369
|
-
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
1370
|
-
font-size: 0.78rem;
|
|
1371
|
-
line-height: 1.55;
|
|
1372
|
-
color: #e5e7eb;
|
|
1373
|
-
table-layout: fixed;
|
|
1374
|
-
}
|
|
1375
|
-
.rt-diff-table colgroup { display: none; }
|
|
1376
|
-
.rt-diff-table td {
|
|
1377
|
-
padding: 0 0.5rem;
|
|
1378
|
-
vertical-align: top;
|
|
1379
|
-
white-space: pre-wrap;
|
|
1380
|
-
word-break: break-word;
|
|
1381
|
-
}
|
|
1382
|
-
.rt-diff-table td.rt-diff-num {
|
|
1383
|
-
width: 2.25rem;
|
|
1384
|
-
text-align: right;
|
|
1385
|
-
color: rgba(156,163,175,0.55);
|
|
1386
|
-
user-select: none;
|
|
1387
|
-
background: rgba(255,255,255,0.02);
|
|
1388
|
-
}
|
|
1389
|
-
.rt-diff-table td.rt-diff-sign {
|
|
1390
|
-
width: 0.85rem;
|
|
1391
|
-
text-align: center;
|
|
1392
|
-
user-select: none;
|
|
1393
|
-
color: rgba(255,255,255,0.45);
|
|
1394
|
-
}
|
|
1395
|
-
.rt-diff-table td.rt-diff-line.rt-diff-rem {
|
|
1396
|
-
background: rgba(248,113,113,0.12);
|
|
1397
|
-
color: #fecaca;
|
|
1398
|
-
}
|
|
1399
|
-
.rt-diff-table tr:has(td.rt-diff-rem) td.rt-diff-sign:first-of-type {
|
|
1400
|
-
color: #f87171;
|
|
1401
|
-
}
|
|
1402
|
-
.rt-diff-table td.rt-diff-line.rt-diff-add {
|
|
1403
|
-
background: rgba(74,222,128,0.12);
|
|
1404
|
-
color: #bbf7d0;
|
|
1405
|
-
}
|
|
1406
|
-
.rt-diff-table tr:has(td.rt-diff-add) td.rt-diff-sign + td + td + td.rt-diff-sign {
|
|
1407
|
-
color: #4ade80;
|
|
1408
|
-
}
|
|
1409
|
-
.rt-diff-table td.rt-diff-line.rt-diff-empty {
|
|
1410
|
-
background: rgba(255,255,255,0.025);
|
|
1411
|
-
}
|
|
1412
|
-
.rt-diff-table tr td:nth-child(4) { border-left: 1px solid rgba(255,255,255,0.06); }
|
|
1413
|
-
.rt-diff-copy-bar {
|
|
1414
|
-
position: absolute; top: 0.4rem; left: 0; right: 0; z-index: 2;
|
|
1415
|
-
display: grid; grid-template-columns: 1fr 1fr;
|
|
1416
|
-
pointer-events: none;
|
|
1417
|
-
}
|
|
1418
|
-
.rt-diff-copy-half {
|
|
1419
|
-
display: flex;
|
|
1420
|
-
justify-content: flex-end;
|
|
1421
|
-
padding-right: 0.4rem;
|
|
1422
|
-
}
|
|
1423
|
-
.rt-diff-copy {
|
|
1424
|
-
pointer-events: auto;
|
|
1425
|
-
display: inline-flex; align-items: center; justify-content: center;
|
|
1426
|
-
width: 1.6rem; height: 1.6rem; padding: 0;
|
|
1427
|
-
border: 1px solid rgba(255,255,255,0.1);
|
|
1428
|
-
border-radius: 0.375rem;
|
|
1429
|
-
background: rgba(20,20,23,0.85);
|
|
1430
|
-
color: #d1d5db;
|
|
1431
|
-
cursor: pointer;
|
|
1432
|
-
opacity: 0; transition: opacity 120ms ease, background 120ms ease, color 120ms ease;
|
|
1433
|
-
}
|
|
1434
|
-
.rt-codeblock[data-variant="diff"]:hover .rt-diff-copy,
|
|
1435
|
-
.rt-codeblock[data-variant="diff"]:focus-within .rt-diff-copy { opacity: 1; }
|
|
1436
|
-
.rt-diff-copy:hover { background: rgba(0,0,0,0.92); color: #fff; }
|
|
1437
|
-
.rt-diff-copy.is-copied { color: #34d399; opacity: 1; }
|
|
1438
|
-
@media (hover: none) { .rt-diff-copy { opacity: 1; } }
|
|
1439
|
-
`;
|
|
1440
|
-
var styleInjected = false;
|
|
1441
|
-
function ensureCodeBlockStyles() {
|
|
1442
|
-
if (styleInjected || typeof document === "undefined") return;
|
|
1443
|
-
if (document.getElementById("rt-codeblock-style")) {
|
|
1444
|
-
styleInjected = true;
|
|
1445
|
-
return;
|
|
1446
|
-
}
|
|
1447
|
-
const tag = document.createElement("style");
|
|
1448
|
-
tag.id = "rt-codeblock-style";
|
|
1449
|
-
tag.textContent = CODEBLOCK_STYLE;
|
|
1450
|
-
document.head.appendChild(tag);
|
|
1451
|
-
styleInjected = true;
|
|
1452
|
-
}
|
|
1453
|
-
function RichTextContent({
|
|
1454
|
-
html,
|
|
1455
|
-
classMap,
|
|
1456
|
-
as = "div",
|
|
1457
|
-
className
|
|
1458
|
-
}) {
|
|
1459
|
-
const merged = useMemo(
|
|
1460
|
-
() => mergeClassMap(DEFAULT_CLASS_MAP, classMap),
|
|
1461
|
-
[classMap]
|
|
1462
|
-
);
|
|
1463
|
-
const safe = useMemo(
|
|
1464
|
-
() => parseRichText(html, { classMap: merged }),
|
|
1465
|
-
[html, merged]
|
|
1466
|
-
);
|
|
1467
|
-
const ref = useRef(null);
|
|
1468
|
-
useEffect(() => {
|
|
1469
|
-
ensureCodeBlockStyles();
|
|
1470
|
-
if (ref.current) {
|
|
1471
|
-
enhanceCodeBlocks(ref.current);
|
|
1472
|
-
enhanceBlockquotes(ref.current);
|
|
1473
|
-
}
|
|
1474
|
-
}, [safe]);
|
|
1475
|
-
return createElement(as, {
|
|
1476
|
-
ref,
|
|
1477
|
-
className,
|
|
1478
|
-
dangerouslySetInnerHTML: { __html: safe }
|
|
1479
|
-
});
|
|
1480
|
-
}
|
|
1481
|
-
|
|
1482
|
-
export { AsteroidCMSProvider, RichTextContent, cmsImage, createApolloClient, getContentReadTime, parseRichText, removeEmptyParagraphs, useAsteroidCMSConfig, useCmsContent, useCmsImage, useCmsMutate };
|
|
869
|
+
export { buildCmsQuery, cmsImage, createApolloClient, fetchCmsContent, getContentReadTime, parseRichText, removeEmptyParagraphs };
|
|
1483
870
|
//# sourceMappingURL=index.js.map
|
|
1484
871
|
//# sourceMappingURL=index.js.map
|