@noirmd/previewer 1.0.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/dist/NReditor.d.mts +29 -0
- package/dist/NReditor.d.ts +29 -0
- package/dist/NReditor.js +2375 -0
- package/dist/NReditor.js.map +1 -0
- package/dist/NReditor.mjs +2344 -0
- package/dist/NReditor.mjs.map +1 -0
- package/dist/index.d.mts +219 -0
- package/dist/index.d.ts +219 -0
- package/dist/index.js +12041 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +12015 -0
- package/dist/index.mjs.map +1 -0
- package/dist/markdown.css +344 -0
- package/markdown.css +344 -0
- package/package.json +106 -0
|
@@ -0,0 +1,2344 @@
|
|
|
1
|
+
// NReditor.tsx
|
|
2
|
+
import React9, { useRef as useRef6, useState as useState5 } from "react";
|
|
3
|
+
import CodeMirror from "@uiw/react-codemirror";
|
|
4
|
+
import { EditorView, Decoration, ViewPlugin, lineNumbers, scrollPastEnd, keymap } from "@codemirror/view";
|
|
5
|
+
|
|
6
|
+
// custom-syntax.ts
|
|
7
|
+
import { StreamLanguage } from "@codemirror/language";
|
|
8
|
+
import { tags as t } from "@lezer/highlight";
|
|
9
|
+
var customStreamParserV2 = StreamLanguage.define({
|
|
10
|
+
startState: () => ({
|
|
11
|
+
inCodeBlock: false,
|
|
12
|
+
inDirectiveHeader: false,
|
|
13
|
+
inPropsBlock: false,
|
|
14
|
+
braceDepth: 0,
|
|
15
|
+
blockStack: [],
|
|
16
|
+
imageState: "none",
|
|
17
|
+
linkState: "none",
|
|
18
|
+
lastPropKey: "",
|
|
19
|
+
inHtmlBlock: false,
|
|
20
|
+
htmlTagName: "",
|
|
21
|
+
isClosingHtmlTag: false,
|
|
22
|
+
embeddedLang: "none"
|
|
23
|
+
}),
|
|
24
|
+
token(stream, state) {
|
|
25
|
+
if (stream.sol()) {
|
|
26
|
+
state.inDirectiveHeader = false;
|
|
27
|
+
state.imageState = "none";
|
|
28
|
+
state.linkState = "none";
|
|
29
|
+
if (state.inCodeBlock && stream.match(/^\s*```/)) {
|
|
30
|
+
state.inCodeBlock = false;
|
|
31
|
+
return "comment";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (state.inHtmlBlock) {
|
|
35
|
+
stream.eatSpace();
|
|
36
|
+
if (stream.match(/^\/>/)) {
|
|
37
|
+
state.inHtmlBlock = false;
|
|
38
|
+
state.htmlTagName = "";
|
|
39
|
+
state.isClosingHtmlTag = false;
|
|
40
|
+
return "typeName";
|
|
41
|
+
}
|
|
42
|
+
if (stream.match(/^>/)) {
|
|
43
|
+
state.inHtmlBlock = false;
|
|
44
|
+
if (!state.isClosingHtmlTag && (state.htmlTagName === "script" || state.htmlTagName === "style")) {
|
|
45
|
+
state.embeddedLang = state.htmlTagName;
|
|
46
|
+
}
|
|
47
|
+
state.htmlTagName = "";
|
|
48
|
+
state.isClosingHtmlTag = false;
|
|
49
|
+
return "typeName";
|
|
50
|
+
}
|
|
51
|
+
if (stream.match(/^[a-zA-Z_:][\w-.:]*/)) return "attributeName";
|
|
52
|
+
if (stream.match(/^=/)) return "keyword";
|
|
53
|
+
if (stream.match(/^"[^"]*"/)) return "string";
|
|
54
|
+
if (stream.match(/^"[^"]*$/)) return "string";
|
|
55
|
+
if (stream.match(/^'[^']*'/)) return "string";
|
|
56
|
+
if (stream.match(/^'[^']*$/)) return "string";
|
|
57
|
+
if (stream.match(/^[^\s>]+/)) return "string";
|
|
58
|
+
if (stream.eatSpace()) return null;
|
|
59
|
+
stream.next();
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
if (state.embeddedLang !== "none") {
|
|
63
|
+
if (stream.match(/^<\/(script|style)\b/i)) {
|
|
64
|
+
const closeTag = stream.current().replace(/^<\//, "").toLowerCase();
|
|
65
|
+
state.embeddedLang = "none";
|
|
66
|
+
state.inHtmlBlock = true;
|
|
67
|
+
state.htmlTagName = closeTag;
|
|
68
|
+
state.isClosingHtmlTag = true;
|
|
69
|
+
return "typeName";
|
|
70
|
+
}
|
|
71
|
+
if (state.embeddedLang === "script") {
|
|
72
|
+
if (stream.match(/^\/\//)) {
|
|
73
|
+
stream.skipToEnd();
|
|
74
|
+
return "comment";
|
|
75
|
+
}
|
|
76
|
+
if (stream.match(/^\/\*/)) {
|
|
77
|
+
while (!stream.eol()) {
|
|
78
|
+
if (stream.match(/\*\//)) return "comment";
|
|
79
|
+
stream.next();
|
|
80
|
+
}
|
|
81
|
+
return "comment";
|
|
82
|
+
}
|
|
83
|
+
if (stream.match(/^["']/)) {
|
|
84
|
+
const q = stream.current();
|
|
85
|
+
while (!stream.eol()) {
|
|
86
|
+
const ch = stream.next();
|
|
87
|
+
if (ch === q && stream.string[stream.pos - 2] !== "\\") break;
|
|
88
|
+
}
|
|
89
|
+
return "string";
|
|
90
|
+
}
|
|
91
|
+
if (stream.match(/^`/)) {
|
|
92
|
+
while (!stream.eol()) {
|
|
93
|
+
if (stream.next() === "`") break;
|
|
94
|
+
}
|
|
95
|
+
return "string";
|
|
96
|
+
}
|
|
97
|
+
if (stream.match(/\b(const|let|var|function|return|if|else|for|while|do|switch|case|break|continue|new|this|class|extends|import|export|default|from|try|catch|finally|throw|async|await|typeof|instanceof|in|of|void|null|undefined|true|false)\b/)) return "keyword";
|
|
98
|
+
if (stream.match(/^\d+(\.\d+)?/)) return "number";
|
|
99
|
+
if (stream.match(/^[a-zA-Z_$][\w$]*(?=\s*\()/)) return "function";
|
|
100
|
+
if (stream.match(/^[a-zA-Z_$][\w$]*/)) return "variableName";
|
|
101
|
+
if (stream.match(/^[+\-*\/%=!<>&|^~?:]+/)) return "keyword";
|
|
102
|
+
stream.next();
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
if (state.embeddedLang === "style") {
|
|
106
|
+
if (stream.match(/^\/\*/)) {
|
|
107
|
+
while (!stream.eol()) {
|
|
108
|
+
if (stream.match(/\*\//)) return "comment";
|
|
109
|
+
stream.next();
|
|
110
|
+
}
|
|
111
|
+
return "comment";
|
|
112
|
+
}
|
|
113
|
+
if (stream.match(/^["']/)) {
|
|
114
|
+
const q = stream.current();
|
|
115
|
+
while (!stream.eol()) {
|
|
116
|
+
const ch = stream.next();
|
|
117
|
+
if (ch === q && stream.string[stream.pos - 2] !== "\\") break;
|
|
118
|
+
}
|
|
119
|
+
return "string";
|
|
120
|
+
}
|
|
121
|
+
if (stream.match(/^@[a-zA-Z-]+/)) return "keyword";
|
|
122
|
+
if (stream.match(/^#[0-9a-fA-F]{3,8}\b/)) return "string";
|
|
123
|
+
if (stream.match(/^\d+(\.\d+)?(px|em|rem|%|vh|vw|vmin|vmax|s|ms|deg|fr)?\b/)) return "number";
|
|
124
|
+
if (stream.match(/^[a-zA-Z-]+(?=\s*:)/)) return "propertyName";
|
|
125
|
+
if (stream.match(/^[.#][a-zA-Z][\w-]*/)) return "className";
|
|
126
|
+
if (stream.match(/\b(none|auto|inherit|initial|unset|normal|bold|italic|center|left|right|flex|grid|block|inline|relative|absolute|fixed|sticky|hidden|visible|scroll|cover|contain)\b/)) return "keyword";
|
|
127
|
+
if (stream.match(/^[a-zA-Z][\w-]*/)) return "typeName";
|
|
128
|
+
if (stream.match(/^[{}();:,]/)) return "keyword";
|
|
129
|
+
stream.next();
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (state.inCodeBlock) {
|
|
134
|
+
stream.skipToEnd();
|
|
135
|
+
return "comment";
|
|
136
|
+
}
|
|
137
|
+
if (state.inPropsBlock) {
|
|
138
|
+
stream.eatSpace();
|
|
139
|
+
if (stream.peek() === "}") {
|
|
140
|
+
stream.next();
|
|
141
|
+
state.inPropsBlock = false;
|
|
142
|
+
state.inDirectiveHeader = false;
|
|
143
|
+
state.lastPropKey = "";
|
|
144
|
+
return "keyword";
|
|
145
|
+
}
|
|
146
|
+
if (stream.match(/^\.[a-zA-Z0-9_-]+/)) return "className";
|
|
147
|
+
if (stream.match(/^#[a-zA-Z0-9_-]+/)) return "propertyName";
|
|
148
|
+
const urlKeys = /^(url|href|image|src|icon)$/i;
|
|
149
|
+
if (stream.match(/^[a-zA-Z][\w-]*(?==)/)) {
|
|
150
|
+
state.lastPropKey = stream.current();
|
|
151
|
+
return "propertyName";
|
|
152
|
+
}
|
|
153
|
+
if (stream.match(/^=/)) return "keyword";
|
|
154
|
+
if (stream.match(/^"[^"]*"|^'[^']*'/)) {
|
|
155
|
+
return urlKeys.test(state.lastPropKey) ? "url" : "string";
|
|
156
|
+
}
|
|
157
|
+
stream.next();
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
if (stream.sol()) {
|
|
161
|
+
let match;
|
|
162
|
+
if (match = stream.match(/^\s*(:::)\s*/)) {
|
|
163
|
+
const rest = stream.string.slice(stream.pos).trim();
|
|
164
|
+
if (rest === "") {
|
|
165
|
+
state.blockStack.pop();
|
|
166
|
+
} else {
|
|
167
|
+
const typeMatch = rest.match(/^([\w-]+)/);
|
|
168
|
+
state.blockStack.push(typeMatch ? typeMatch[1].toLowerCase() : "generic");
|
|
169
|
+
}
|
|
170
|
+
state.inDirectiveHeader = true;
|
|
171
|
+
return "keyword";
|
|
172
|
+
}
|
|
173
|
+
if (stream.match(/^\s*#[a-zA-Z][\w-]*\s*$/) && !stream.match(/^\s*#{1,6}\s/)) {
|
|
174
|
+
return "propertyName";
|
|
175
|
+
}
|
|
176
|
+
if (stream.match(/^\s*(#{1,6})\s+/)) return "heading";
|
|
177
|
+
if (stream.match(/^\s*```/)) {
|
|
178
|
+
state.inCodeBlock = true;
|
|
179
|
+
stream.skipToEnd();
|
|
180
|
+
return "comment";
|
|
181
|
+
}
|
|
182
|
+
if (stream.match(/^\s*([-*+]|\d+\.)\s+/)) return "variableName";
|
|
183
|
+
if (stream.match(/^\s*(---|___|(\*\s*){3,})\s*$/)) return "meta";
|
|
184
|
+
if (stream.match(/^\s*\[TOC\d?\]/)) return "keyword";
|
|
185
|
+
}
|
|
186
|
+
if (state.inDirectiveHeader) {
|
|
187
|
+
stream.eatSpace();
|
|
188
|
+
if (stream.match(/^[\w-]+/)) return "typeName";
|
|
189
|
+
if (stream.peek() === "{") {
|
|
190
|
+
stream.next();
|
|
191
|
+
state.inPropsBlock = true;
|
|
192
|
+
state.inDirectiveHeader = true;
|
|
193
|
+
return "keyword";
|
|
194
|
+
}
|
|
195
|
+
state.inDirectiveHeader = false;
|
|
196
|
+
}
|
|
197
|
+
const currentBlockType = state.blockStack[state.blockStack.length - 1];
|
|
198
|
+
if (currentBlockType === "raw" && !state.inDirectiveHeader) {
|
|
199
|
+
if (stream.eatSpace()) return null;
|
|
200
|
+
if (stream.match(/^<\/?[a-zA-Z0-9-]+/)) return "typeName";
|
|
201
|
+
if (stream.match(/^>/)) return "typeName";
|
|
202
|
+
if (stream.match(/^[{}]/)) return "keyword";
|
|
203
|
+
if (stream.match(/^--[a-zA-Z0-9_-]+/)) return "variableName";
|
|
204
|
+
if (stream.match(/^[a-zA-Z-]+(?=\s*:)/)) return "propertyName";
|
|
205
|
+
if (stream.match(/^var\([^)]+\)/)) return "variableName";
|
|
206
|
+
if (stream.match(/^['"`][^'"`]*['"`]/)) return "string";
|
|
207
|
+
if (stream.match(/^[#.][a-zA-Z0-9_-]+/)) return "className";
|
|
208
|
+
if (stream.match(/^:[a-zA-Z0-9_-]+/)) return "keyword";
|
|
209
|
+
if (stream.match(/\b(const|let|var|function|return|if|else|for|while)\b/)) return "keyword";
|
|
210
|
+
stream.next();
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
if (state.imageState === "expectUrl") {
|
|
214
|
+
state.imageState = "expectOptions";
|
|
215
|
+
if (stream.eat("(")) {
|
|
216
|
+
let parenLevel = 1;
|
|
217
|
+
while (!stream.eol() && parenLevel > 0) {
|
|
218
|
+
const next = stream.next();
|
|
219
|
+
if (next === "(") parenLevel++;
|
|
220
|
+
else if (next === ")" && stream.string[stream.pos - 2] !== "\\") parenLevel--;
|
|
221
|
+
}
|
|
222
|
+
return "url";
|
|
223
|
+
} else {
|
|
224
|
+
state.imageState = "none";
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (state.imageState === "expectOptions") {
|
|
228
|
+
state.imageState = "none";
|
|
229
|
+
if (stream.eat("{")) {
|
|
230
|
+
stream.eatWhile(/[^}]/);
|
|
231
|
+
stream.eat("}");
|
|
232
|
+
return "attributeName";
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (state.linkState === "expectUrl") {
|
|
236
|
+
state.linkState = "none";
|
|
237
|
+
if (stream.eat("(")) {
|
|
238
|
+
let parenLevel = 1;
|
|
239
|
+
while (!stream.eol() && parenLevel > 0) {
|
|
240
|
+
const next = stream.next();
|
|
241
|
+
if (next === "(") parenLevel++;
|
|
242
|
+
else if (next === ")" && stream.string[stream.pos - 2] !== "\\") parenLevel--;
|
|
243
|
+
}
|
|
244
|
+
return "url";
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (stream.match(/^<\/?[a-zA-Z][\w-]*(?=[>\s/]|$)/)) {
|
|
248
|
+
const raw = stream.current();
|
|
249
|
+
state.htmlTagName = raw.replace(/^<\/?/, "").toLowerCase();
|
|
250
|
+
state.isClosingHtmlTag = raw.startsWith("</");
|
|
251
|
+
state.inHtmlBlock = true;
|
|
252
|
+
return "typeName";
|
|
253
|
+
}
|
|
254
|
+
if (stream.match(/\*\*\*.+?\*\*\*/)) return "strongEmphasis";
|
|
255
|
+
if (stream.match(/\*\*.+?\*\*/)) return "strong";
|
|
256
|
+
if (stream.match(/!\[[^\]]*?\]/)) {
|
|
257
|
+
if (stream.peek() === "(") state.imageState = "expectUrl";
|
|
258
|
+
return "string";
|
|
259
|
+
}
|
|
260
|
+
if (stream.match(/\[[^\]]+?\]/)) {
|
|
261
|
+
if (stream.peek() === "(") state.linkState = "expectUrl";
|
|
262
|
+
return "string";
|
|
263
|
+
}
|
|
264
|
+
if (stream.match(/\|\[[^\]]+?\]\|/)) return "keyword";
|
|
265
|
+
if (stream.match(/`[^`]+`/)) return "comment";
|
|
266
|
+
if (stream.match(/_(.+?)_/)) return "emphasis";
|
|
267
|
+
if (stream.match(/~~(.+?)~~/)) return "strikethrough";
|
|
268
|
+
if (stream.match(/!~(.+?)~!/)) return "underline";
|
|
269
|
+
if (stream.match(/==(.+?)==/)) return "highlight";
|
|
270
|
+
if (stream.match(/!>.+?<!/)) return "comment";
|
|
271
|
+
if (stream.match(/%[^%\s]+?%[^%]+?%%/)) return "string";
|
|
272
|
+
if (stream.match(/->|<-|\|/)) return "meta";
|
|
273
|
+
stream.next();
|
|
274
|
+
return null;
|
|
275
|
+
},
|
|
276
|
+
tokenTable: {
|
|
277
|
+
heading: t.heading,
|
|
278
|
+
keyword: t.keyword,
|
|
279
|
+
typeName: t.typeName,
|
|
280
|
+
string: t.string,
|
|
281
|
+
attributeName: t.attributeName,
|
|
282
|
+
propertyName: t.propertyName,
|
|
283
|
+
className: t.className,
|
|
284
|
+
comment: t.comment,
|
|
285
|
+
variableName: t.variableName,
|
|
286
|
+
meta: t.meta,
|
|
287
|
+
strong: t.strong,
|
|
288
|
+
emphasis: t.emphasis,
|
|
289
|
+
strongEmphasis: [t.strong, t.emphasis],
|
|
290
|
+
strikethrough: t.strikethrough,
|
|
291
|
+
underline: t.special(t.emphasis),
|
|
292
|
+
highlight: t.special(t.comment),
|
|
293
|
+
url: t.url,
|
|
294
|
+
link: t.string,
|
|
295
|
+
number: t.number,
|
|
296
|
+
function: t.function(t.variableName)
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// NReditor.tsx
|
|
301
|
+
import { RangeSetBuilder } from "@codemirror/state";
|
|
302
|
+
import { syntaxHighlighting, HighlightStyle, foldService, foldGutter, foldAll, unfoldAll } from "@codemirror/language";
|
|
303
|
+
import { tags as t2 } from "@lezer/highlight";
|
|
304
|
+
|
|
305
|
+
// useDebounce.ts
|
|
306
|
+
import { useState, useEffect } from "react";
|
|
307
|
+
function useDebounce(value, delay) {
|
|
308
|
+
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
309
|
+
useEffect(() => {
|
|
310
|
+
const timer = setTimeout(() => setDebouncedValue(value), delay);
|
|
311
|
+
return () => clearTimeout(timer);
|
|
312
|
+
}, [value, delay]);
|
|
313
|
+
return debouncedValue;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// CustomMarkdownRenderer.tsx
|
|
317
|
+
import React8, { useState as useState4, useEffect as useEffect5, useCallback as useCallback2, useMemo, useId as useId3, useRef as useRef5 } from "react";
|
|
318
|
+
|
|
319
|
+
// utils.ts
|
|
320
|
+
function parseCssString(cssText) {
|
|
321
|
+
if (!cssText) return {};
|
|
322
|
+
return cssText.split(";").filter(Boolean).reduce((styleObj, styleString) => {
|
|
323
|
+
const parts = styleString.split(":");
|
|
324
|
+
if (parts.length < 2) return styleObj;
|
|
325
|
+
const key = parts[0].trim().replace(/-([a-z])/g, (_, g) => g.toUpperCase());
|
|
326
|
+
const value = parts.slice(1).join(":").trim();
|
|
327
|
+
styleObj[key] = value;
|
|
328
|
+
return styleObj;
|
|
329
|
+
}, {});
|
|
330
|
+
}
|
|
331
|
+
function generateId(text) {
|
|
332
|
+
return text.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-");
|
|
333
|
+
}
|
|
334
|
+
function scrollToId(id) {
|
|
335
|
+
const element = document.getElementById(id);
|
|
336
|
+
if (element) {
|
|
337
|
+
element.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function extractAttributes(text) {
|
|
341
|
+
const match = text.match(/^(.*?)\s*##\{([^}]*)\}\s*$/);
|
|
342
|
+
if (!match) return { text, classes: "", id: "" };
|
|
343
|
+
const rawAttrs = match[2];
|
|
344
|
+
const cleanedText = match[1];
|
|
345
|
+
const classList = [];
|
|
346
|
+
let id = "";
|
|
347
|
+
for (const [, key, value] of rawAttrs.matchAll(/([\w-]+)="([^"]*)"/g)) {
|
|
348
|
+
if (key === "class") {
|
|
349
|
+
classList.push(...value.split(/\s+/).filter(Boolean));
|
|
350
|
+
} else if (key === "id") {
|
|
351
|
+
id = value;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
const stripped = rawAttrs.replace(/[\w-]+="[^"]*"/g, "");
|
|
355
|
+
for (const token of stripped.split(/\s+/).filter(Boolean)) {
|
|
356
|
+
if (token.startsWith(".")) classList.push(token.slice(1));
|
|
357
|
+
else if (token.startsWith("#") && !id) id = token.slice(1);
|
|
358
|
+
}
|
|
359
|
+
return { text: cleanedText, classes: classList.join(" "), id };
|
|
360
|
+
}
|
|
361
|
+
var _scopeCounter = 0;
|
|
362
|
+
function resetScopeCounter() {
|
|
363
|
+
_scopeCounter = 0;
|
|
364
|
+
}
|
|
365
|
+
function generateScopeId() {
|
|
366
|
+
return `scope-${++_scopeCounter}`;
|
|
367
|
+
}
|
|
368
|
+
function parseProps(propsString) {
|
|
369
|
+
const props = {};
|
|
370
|
+
if (!propsString?.trim()) return props;
|
|
371
|
+
const pairRegex = /(\w[\w-]*)=(?:"([^"]*)"|'([^']*)')/g;
|
|
372
|
+
let match;
|
|
373
|
+
while ((match = pairRegex.exec(propsString)) !== null) {
|
|
374
|
+
const key = match[1];
|
|
375
|
+
const value = match[2] ?? match[3] ?? "";
|
|
376
|
+
props[key] = value;
|
|
377
|
+
}
|
|
378
|
+
const classMatches = propsString.match(/\.([a-zA-Z0-9_!/.\-]+)/g);
|
|
379
|
+
if (classMatches) {
|
|
380
|
+
const existing = props["class"] || "";
|
|
381
|
+
const newClasses = classMatches.map((c) => c.substring(1)).join(" ");
|
|
382
|
+
props["class"] = existing ? `${existing} ${newClasses}` : newClasses;
|
|
383
|
+
}
|
|
384
|
+
const idMatch = propsString.match(/#([a-zA-Z0-9_-]+)(?=\s|}|$)/);
|
|
385
|
+
if (idMatch && !props["id"]) {
|
|
386
|
+
props["id"] = idMatch[1];
|
|
387
|
+
}
|
|
388
|
+
return props;
|
|
389
|
+
}
|
|
390
|
+
function parseHtmlAttrs(attrsString) {
|
|
391
|
+
const props = {};
|
|
392
|
+
if (!attrsString?.trim()) return props;
|
|
393
|
+
const pairRegex = /([a-zA-Z0-9_-]+)(?:=(?:"([^"]*)"|'([^']*)'|([^\s>]+)))?/g;
|
|
394
|
+
let match;
|
|
395
|
+
while ((match = pairRegex.exec(attrsString)) !== null) {
|
|
396
|
+
let key = match[1];
|
|
397
|
+
const value = match[2] ?? match[3] ?? match[4] ?? true;
|
|
398
|
+
if (key === "class") key = "className";
|
|
399
|
+
else if (key === "for") key = "htmlFor";
|
|
400
|
+
else if (key === "tabindex") key = "tabIndex";
|
|
401
|
+
if (key === "style" && typeof value === "string") {
|
|
402
|
+
props[key] = parseCssString(value);
|
|
403
|
+
} else {
|
|
404
|
+
props[key] = value;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return props;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// parser.ts
|
|
411
|
+
function parseMarkdown(markdown2) {
|
|
412
|
+
if (!markdown2) return [];
|
|
413
|
+
const lines = markdown2.split("\n");
|
|
414
|
+
const result = [];
|
|
415
|
+
let i = 0;
|
|
416
|
+
while (i < lines.length) {
|
|
417
|
+
const line = lines[i];
|
|
418
|
+
const trimmed = line.trim();
|
|
419
|
+
let match;
|
|
420
|
+
if (match = trimmed.match(/^(#{1,6})\s+(.+)$/)) {
|
|
421
|
+
const level = match[1].length;
|
|
422
|
+
const rawText = match[2];
|
|
423
|
+
const { text: text2, classes: classes2, id: customId } = extractAttributes(rawText);
|
|
424
|
+
const id2 = customId || generateId(text2.replace(/->|<-/g, ""));
|
|
425
|
+
result.push({ type: "header", level, text: text2, id: id2, classes: classes2 || void 0 });
|
|
426
|
+
i++;
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
if (match = trimmed.match(/^->\s*(.+?)\s*(<-|->)\s*$/)) {
|
|
430
|
+
const content = match[1];
|
|
431
|
+
const align = match[2] === "<-" ? "center" : "right";
|
|
432
|
+
result.push({ type: "paragraph", content, align });
|
|
433
|
+
i++;
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
if (trimmed.startsWith("```")) {
|
|
437
|
+
const fenceHeader = trimmed.slice(3).trim();
|
|
438
|
+
const titleMatch = fenceHeader.match(/title=["']([^"']*)["']/);
|
|
439
|
+
const lang = fenceHeader.replace(/title=["'][^"']*["']/, "").trim();
|
|
440
|
+
const title = titleMatch ? titleMatch[1] : void 0;
|
|
441
|
+
const content = [];
|
|
442
|
+
i++;
|
|
443
|
+
while (i < lines.length && !lines[i].trim().startsWith("```")) {
|
|
444
|
+
content.push(lines[i]);
|
|
445
|
+
i++;
|
|
446
|
+
}
|
|
447
|
+
result.push({ type: "codeblock", language: lang, title, content: content.join("\n") });
|
|
448
|
+
i++;
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
if (trimmed.startsWith(":::")) {
|
|
452
|
+
const rest = trimmed.slice(3).trim();
|
|
453
|
+
if (rest === "") {
|
|
454
|
+
result.push({ type: "paragraph", content: line });
|
|
455
|
+
i++;
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
const typeMatch = rest.match(/^([\w-]+)/);
|
|
459
|
+
const directiveType = typeMatch ? typeMatch[1] : "custom";
|
|
460
|
+
let j = i + 1;
|
|
461
|
+
let nestedLevel = 0;
|
|
462
|
+
let foundClose = false;
|
|
463
|
+
while (j < lines.length) {
|
|
464
|
+
const currentTrimmed = lines[j].trim();
|
|
465
|
+
if (currentTrimmed === ":::") {
|
|
466
|
+
if (nestedLevel === 0) {
|
|
467
|
+
foundClose = true;
|
|
468
|
+
break;
|
|
469
|
+
} else {
|
|
470
|
+
nestedLevel--;
|
|
471
|
+
}
|
|
472
|
+
} else if (currentTrimmed.startsWith(":::")) {
|
|
473
|
+
nestedLevel++;
|
|
474
|
+
}
|
|
475
|
+
j++;
|
|
476
|
+
}
|
|
477
|
+
if (foundClose) {
|
|
478
|
+
const contentLines = [];
|
|
479
|
+
for (let k = i + 1; k < j; k++) {
|
|
480
|
+
contentLines.push(lines[k]);
|
|
481
|
+
}
|
|
482
|
+
const rawContent = contentLines.join("\n");
|
|
483
|
+
const headerRest = typeMatch ? rest.slice(directiveType.length).trim() : rest;
|
|
484
|
+
let propsString = "";
|
|
485
|
+
let shortForm = "";
|
|
486
|
+
const propsBlockMatch = headerRest.match(/^\{([^]*)\}\s*$/);
|
|
487
|
+
if (propsBlockMatch) {
|
|
488
|
+
propsString = propsBlockMatch[1];
|
|
489
|
+
} else if (headerRest) {
|
|
490
|
+
shortForm = headerRest;
|
|
491
|
+
}
|
|
492
|
+
const props = parseProps(propsString);
|
|
493
|
+
if (shortForm && !props["title"]) {
|
|
494
|
+
props["title"] = shortForm;
|
|
495
|
+
}
|
|
496
|
+
const slots = splitSlots(rawContent);
|
|
497
|
+
result.push({
|
|
498
|
+
type: "directive",
|
|
499
|
+
directiveType,
|
|
500
|
+
props,
|
|
501
|
+
slots,
|
|
502
|
+
scopeId: generateScopeId()
|
|
503
|
+
});
|
|
504
|
+
i = j + 1;
|
|
505
|
+
continue;
|
|
506
|
+
} else {
|
|
507
|
+
result.push({ type: "paragraph", content: line });
|
|
508
|
+
i++;
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if (match = trimmed.match(/^(.*?)!\[([^\]]*)\]\(([^)]+?)\)(?:\{([^}]+?)\})?(.*)$/)) {
|
|
513
|
+
const [, preText, alt, srcAndFloat, size, postText] = match;
|
|
514
|
+
if (preText.trim()) {
|
|
515
|
+
result.push({ type: "paragraph", content: preText.trim() });
|
|
516
|
+
}
|
|
517
|
+
let src = srcAndFloat;
|
|
518
|
+
const style = {};
|
|
519
|
+
if (src.includes("#left")) {
|
|
520
|
+
src = src.replace("#left", "");
|
|
521
|
+
style.float = "left";
|
|
522
|
+
style.margin = "0 1em 1em 0";
|
|
523
|
+
} else if (src.includes("#right")) {
|
|
524
|
+
src = src.replace("#right", "");
|
|
525
|
+
style.float = "right";
|
|
526
|
+
style.margin = "0 0 1em 1em";
|
|
527
|
+
} else if (src.includes("#center")) {
|
|
528
|
+
src = src.replace("#center", "");
|
|
529
|
+
style.display = "block";
|
|
530
|
+
style.margin = "0 auto 1em auto";
|
|
531
|
+
}
|
|
532
|
+
if (size) {
|
|
533
|
+
const [width, height] = size.split(":");
|
|
534
|
+
if (width) style.width = width.trim();
|
|
535
|
+
if (height) style.height = height.trim();
|
|
536
|
+
}
|
|
537
|
+
result.push({ type: "image", alt, src, style });
|
|
538
|
+
if (postText.trim()) {
|
|
539
|
+
result.push({ type: "paragraph", content: postText.trim() });
|
|
540
|
+
}
|
|
541
|
+
i++;
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
if (trimmed.includes("|") && i + 1 < lines.length && lines[i + 1].includes("---")) {
|
|
545
|
+
const tableLines = [line];
|
|
546
|
+
i++;
|
|
547
|
+
tableLines.push(lines[i]);
|
|
548
|
+
i++;
|
|
549
|
+
while (i < lines.length && lines[i].trim().includes("|")) {
|
|
550
|
+
tableLines.push(lines[i]);
|
|
551
|
+
i++;
|
|
552
|
+
}
|
|
553
|
+
result.push({ type: "table", content: tableLines.join("\n") });
|
|
554
|
+
continue;
|
|
555
|
+
}
|
|
556
|
+
if (match = trimmed.match(/^(\s*)([-*+]|\d+\.)\s+(.+)$/)) {
|
|
557
|
+
const listItems = [line];
|
|
558
|
+
i++;
|
|
559
|
+
while (i < lines.length) {
|
|
560
|
+
const nextLine = lines[i];
|
|
561
|
+
const nextTrimmed = nextLine.trim();
|
|
562
|
+
if (nextTrimmed.match(/^(\s*)([-*+]|\d+\.)\s+(.+)$/) || nextTrimmed === "" || nextLine.startsWith(" ")) {
|
|
563
|
+
listItems.push(nextLine);
|
|
564
|
+
i++;
|
|
565
|
+
} else {
|
|
566
|
+
break;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
result.push({ type: "list", content: listItems.join("\n") });
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
572
|
+
if (trimmed.startsWith(">")) {
|
|
573
|
+
const quoteLines = [line];
|
|
574
|
+
i++;
|
|
575
|
+
while (i < lines.length && (lines[i].trim().startsWith(">") || lines[i].trim() === "")) {
|
|
576
|
+
quoteLines.push(lines[i]);
|
|
577
|
+
i++;
|
|
578
|
+
}
|
|
579
|
+
const rawQuote = quoteLines.join("\n").replace(/^>\s?/gm, "");
|
|
580
|
+
const { text: text2, classes: classes2, id: id2 } = extractAttributes(rawQuote);
|
|
581
|
+
result.push({ type: "blockquote", content: text2, classes: classes2 || void 0, id: id2 });
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
if (/^(---|___|(\*\s*){3,})\s*$/.test(trimmed)) {
|
|
585
|
+
result.push({ type: "hr" });
|
|
586
|
+
i++;
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
589
|
+
if (/^\[TOC\d?\]\s*$/.test(trimmed)) {
|
|
590
|
+
result.push({ type: "toc" });
|
|
591
|
+
i++;
|
|
592
|
+
continue;
|
|
593
|
+
}
|
|
594
|
+
if (trimmed === "") {
|
|
595
|
+
i++;
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
let tagStartMatch = trimmed.match(/^<([a-zA-Z][\w-]*)/);
|
|
599
|
+
if (tagStartMatch) {
|
|
600
|
+
const tagName = tagStartMatch[1].toLowerCase();
|
|
601
|
+
const voidElements = /* @__PURE__ */ new Set([
|
|
602
|
+
"area",
|
|
603
|
+
"base",
|
|
604
|
+
"br",
|
|
605
|
+
"col",
|
|
606
|
+
"embed",
|
|
607
|
+
"hr",
|
|
608
|
+
"img",
|
|
609
|
+
"input",
|
|
610
|
+
"link",
|
|
611
|
+
"meta",
|
|
612
|
+
"param",
|
|
613
|
+
"source",
|
|
614
|
+
"track",
|
|
615
|
+
"wbr"
|
|
616
|
+
]);
|
|
617
|
+
const remainingText = lines.slice(i).join("\n");
|
|
618
|
+
const openTagRegex = new RegExp(`^\\s*<${tagName}\\b([^>]*?)>`, "i");
|
|
619
|
+
const openTagMatch = remainingText.match(openTagRegex);
|
|
620
|
+
if (openTagMatch) {
|
|
621
|
+
const fullOpenTag = openTagMatch[0];
|
|
622
|
+
const attrs = openTagMatch[1].replace(/\s+/g, " ").trim();
|
|
623
|
+
const isSelfClosing = fullOpenTag.endsWith("/>") || voidElements.has(tagName);
|
|
624
|
+
if (isSelfClosing) {
|
|
625
|
+
const blockText = remainingText.substring(0, openTagMatch.index + fullOpenTag.length);
|
|
626
|
+
const consumedLines = blockText.split("\n").length;
|
|
627
|
+
result.push({
|
|
628
|
+
type: "html-block",
|
|
629
|
+
tag: tagName,
|
|
630
|
+
attrs,
|
|
631
|
+
children: []
|
|
632
|
+
// No children
|
|
633
|
+
});
|
|
634
|
+
i += consumedLines;
|
|
635
|
+
continue;
|
|
636
|
+
} else {
|
|
637
|
+
let nestedLevel = 0;
|
|
638
|
+
let closeIndex = -1;
|
|
639
|
+
let closeTagLength = 0;
|
|
640
|
+
const tagRegex = new RegExp(`</?${tagName}\\b[^>]*>`, "gi");
|
|
641
|
+
tagRegex.lastIndex = openTagMatch.index + fullOpenTag.length;
|
|
642
|
+
let execMatch;
|
|
643
|
+
while ((execMatch = tagRegex.exec(remainingText)) !== null) {
|
|
644
|
+
if (execMatch[0].startsWith("</")) {
|
|
645
|
+
nestedLevel--;
|
|
646
|
+
if (nestedLevel < 0) {
|
|
647
|
+
closeIndex = execMatch.index;
|
|
648
|
+
closeTagLength = execMatch[0].length;
|
|
649
|
+
break;
|
|
650
|
+
}
|
|
651
|
+
} else {
|
|
652
|
+
if (!execMatch[0].endsWith("/>")) {
|
|
653
|
+
nestedLevel++;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
if (closeIndex !== -1) {
|
|
658
|
+
const fullBlock = remainingText.substring(0, closeIndex + closeTagLength);
|
|
659
|
+
const consumedLines = fullBlock.split("\n").length;
|
|
660
|
+
if (tagName === "style" || tagName === "script") {
|
|
661
|
+
result.push({
|
|
662
|
+
type: "html",
|
|
663
|
+
content: fullBlock,
|
|
664
|
+
scopeId: generateScopeId()
|
|
665
|
+
});
|
|
666
|
+
} else {
|
|
667
|
+
const innerContent = remainingText.substring(openTagMatch.index + fullOpenTag.length, closeIndex);
|
|
668
|
+
result.push({
|
|
669
|
+
type: "html-block",
|
|
670
|
+
tag: tagName,
|
|
671
|
+
attrs,
|
|
672
|
+
children: parseMarkdown(innerContent)
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
i += consumedLines;
|
|
676
|
+
continue;
|
|
677
|
+
} else {
|
|
678
|
+
const blockText = remainingText.substring(0, openTagMatch.index + fullOpenTag.length);
|
|
679
|
+
const consumedLines = blockText.split("\n").length;
|
|
680
|
+
result.push({
|
|
681
|
+
type: "html-block",
|
|
682
|
+
tag: tagName,
|
|
683
|
+
attrs,
|
|
684
|
+
children: []
|
|
685
|
+
});
|
|
686
|
+
i += consumedLines;
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
const paragraphLines = [line];
|
|
693
|
+
i++;
|
|
694
|
+
while (i < lines.length) {
|
|
695
|
+
const nextLine = lines[i];
|
|
696
|
+
const nextTrimmed = nextLine.trim();
|
|
697
|
+
if (nextTrimmed === "" || nextTrimmed.startsWith("#") || nextTrimmed.startsWith(":::") || nextTrimmed.includes("|") || nextTrimmed.match(/^(\s*)([-*+]|\d+\.)\s+/) || nextTrimmed.startsWith(">") || nextTrimmed.startsWith("```") || nextTrimmed.startsWith("->") || nextTrimmed.match(/^<([a-zA-Z][\w-]*)\b/)) {
|
|
698
|
+
break;
|
|
699
|
+
}
|
|
700
|
+
paragraphLines.push(nextLine);
|
|
701
|
+
i++;
|
|
702
|
+
}
|
|
703
|
+
const rawParagraph = paragraphLines.join("\n").trim();
|
|
704
|
+
const { text, classes, id } = extractAttributes(rawParagraph);
|
|
705
|
+
result.push({ type: "paragraph", content: text, classes: classes || void 0, id });
|
|
706
|
+
}
|
|
707
|
+
return result;
|
|
708
|
+
}
|
|
709
|
+
function splitSlots(rawContent) {
|
|
710
|
+
const slots = {};
|
|
711
|
+
const lines = rawContent.split("\n");
|
|
712
|
+
let currentSlot = "default";
|
|
713
|
+
let buffer = [];
|
|
714
|
+
let nestingDepth = 0;
|
|
715
|
+
for (const line of lines) {
|
|
716
|
+
const trimmed = line.trim();
|
|
717
|
+
if (trimmed.startsWith(":::")) {
|
|
718
|
+
const rest = trimmed.slice(3).trim();
|
|
719
|
+
if (rest === "") {
|
|
720
|
+
nestingDepth = Math.max(0, nestingDepth - 1);
|
|
721
|
+
} else {
|
|
722
|
+
nestingDepth++;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
const slotMatch = trimmed.match(/^#([\w-]+)$/);
|
|
726
|
+
if (slotMatch && nestingDepth === 0) {
|
|
727
|
+
slots[currentSlot] = buffer.join("\n").trim();
|
|
728
|
+
buffer = [];
|
|
729
|
+
currentSlot = slotMatch[1];
|
|
730
|
+
} else {
|
|
731
|
+
buffer.push(line);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
slots[currentSlot] = buffer.join("\n").trim();
|
|
735
|
+
for (const key of Object.keys(slots)) {
|
|
736
|
+
if (!slots[key]) delete slots[key];
|
|
737
|
+
}
|
|
738
|
+
return slots;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// ui-components.tsx
|
|
742
|
+
import { useState as useState2, useRef } from "react";
|
|
743
|
+
|
|
744
|
+
// highlightSetup.ts
|
|
745
|
+
import hljs from "highlight.js/lib/core";
|
|
746
|
+
import javascript from "highlight.js/lib/languages/javascript";
|
|
747
|
+
import typescript from "highlight.js/lib/languages/typescript";
|
|
748
|
+
import python from "highlight.js/lib/languages/python";
|
|
749
|
+
import css from "highlight.js/lib/languages/css";
|
|
750
|
+
import xml from "highlight.js/lib/languages/xml";
|
|
751
|
+
import json from "highlight.js/lib/languages/json";
|
|
752
|
+
import bash from "highlight.js/lib/languages/bash";
|
|
753
|
+
import sql from "highlight.js/lib/languages/sql";
|
|
754
|
+
import markdown from "highlight.js/lib/languages/markdown";
|
|
755
|
+
import java from "highlight.js/lib/languages/java";
|
|
756
|
+
import csharp from "highlight.js/lib/languages/csharp";
|
|
757
|
+
import cpp from "highlight.js/lib/languages/cpp";
|
|
758
|
+
import go from "highlight.js/lib/languages/go";
|
|
759
|
+
import rust from "highlight.js/lib/languages/rust";
|
|
760
|
+
import php from "highlight.js/lib/languages/php";
|
|
761
|
+
import ruby from "highlight.js/lib/languages/ruby";
|
|
762
|
+
import swift from "highlight.js/lib/languages/swift";
|
|
763
|
+
import kotlin from "highlight.js/lib/languages/kotlin";
|
|
764
|
+
import dart from "highlight.js/lib/languages/dart";
|
|
765
|
+
import yaml from "highlight.js/lib/languages/yaml";
|
|
766
|
+
import toml from "highlight.js/lib/languages/ini";
|
|
767
|
+
import dockerfile from "highlight.js/lib/languages/dockerfile";
|
|
768
|
+
import diff from "highlight.js/lib/languages/diff";
|
|
769
|
+
import shell from "highlight.js/lib/languages/shell";
|
|
770
|
+
hljs.registerLanguage("javascript", javascript);
|
|
771
|
+
hljs.registerLanguage("js", javascript);
|
|
772
|
+
hljs.registerLanguage("jsx", javascript);
|
|
773
|
+
hljs.registerLanguage("typescript", typescript);
|
|
774
|
+
hljs.registerLanguage("ts", typescript);
|
|
775
|
+
hljs.registerLanguage("tsx", typescript);
|
|
776
|
+
hljs.registerLanguage("python", python);
|
|
777
|
+
hljs.registerLanguage("py", python);
|
|
778
|
+
hljs.registerLanguage("css", css);
|
|
779
|
+
hljs.registerLanguage("html", xml);
|
|
780
|
+
hljs.registerLanguage("xml", xml);
|
|
781
|
+
hljs.registerLanguage("svg", xml);
|
|
782
|
+
hljs.registerLanguage("json", json);
|
|
783
|
+
hljs.registerLanguage("bash", bash);
|
|
784
|
+
hljs.registerLanguage("sh", bash);
|
|
785
|
+
hljs.registerLanguage("zsh", bash);
|
|
786
|
+
hljs.registerLanguage("sql", sql);
|
|
787
|
+
hljs.registerLanguage("markdown", markdown);
|
|
788
|
+
hljs.registerLanguage("md", markdown);
|
|
789
|
+
hljs.registerLanguage("java", java);
|
|
790
|
+
hljs.registerLanguage("csharp", csharp);
|
|
791
|
+
hljs.registerLanguage("cs", csharp);
|
|
792
|
+
hljs.registerLanguage("cpp", cpp);
|
|
793
|
+
hljs.registerLanguage("c", cpp);
|
|
794
|
+
hljs.registerLanguage("go", go);
|
|
795
|
+
hljs.registerLanguage("rust", rust);
|
|
796
|
+
hljs.registerLanguage("rs", rust);
|
|
797
|
+
hljs.registerLanguage("php", php);
|
|
798
|
+
hljs.registerLanguage("ruby", ruby);
|
|
799
|
+
hljs.registerLanguage("rb", ruby);
|
|
800
|
+
hljs.registerLanguage("swift", swift);
|
|
801
|
+
hljs.registerLanguage("kotlin", kotlin);
|
|
802
|
+
hljs.registerLanguage("kt", kotlin);
|
|
803
|
+
hljs.registerLanguage("dart", dart);
|
|
804
|
+
hljs.registerLanguage("yaml", yaml);
|
|
805
|
+
hljs.registerLanguage("yml", yaml);
|
|
806
|
+
hljs.registerLanguage("toml", toml);
|
|
807
|
+
hljs.registerLanguage("ini", toml);
|
|
808
|
+
hljs.registerLanguage("dockerfile", dockerfile);
|
|
809
|
+
hljs.registerLanguage("docker", dockerfile);
|
|
810
|
+
hljs.registerLanguage("diff", diff);
|
|
811
|
+
hljs.registerLanguage("shell", shell);
|
|
812
|
+
var highlightSetup_default = hljs;
|
|
813
|
+
|
|
814
|
+
// ui-components.tsx
|
|
815
|
+
import { Dialog } from "@base-ui/react/dialog";
|
|
816
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
817
|
+
var IconRenderer = ({ iconName, extraClasses = "" }) => {
|
|
818
|
+
if (!iconName) return null;
|
|
819
|
+
const baseClass = `material-symbols-rounded !text-[1em] leading-none align-top ${extraClasses}`;
|
|
820
|
+
const isCodepoint = /^[eE][0-9a-fA-F]{3,4}$/.test(iconName);
|
|
821
|
+
if (isCodepoint) {
|
|
822
|
+
return /* @__PURE__ */ jsx(
|
|
823
|
+
"span",
|
|
824
|
+
{
|
|
825
|
+
className: baseClass,
|
|
826
|
+
dangerouslySetInnerHTML: { __html: `&#x${iconName};` },
|
|
827
|
+
"aria-hidden": "true"
|
|
828
|
+
}
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
return /* @__PURE__ */ jsx("span", { className: baseClass, "aria-hidden": "true", children: iconName });
|
|
832
|
+
};
|
|
833
|
+
var CodeBlock = ({ code, language, title }) => {
|
|
834
|
+
const [copied, setCopied] = useState2(false);
|
|
835
|
+
const timerRef = useRef(null);
|
|
836
|
+
const lang = language?.split(/[\s{]/)[0]?.trim() || "";
|
|
837
|
+
let html;
|
|
838
|
+
try {
|
|
839
|
+
if (lang && highlightSetup_default.getLanguage(lang)) {
|
|
840
|
+
html = highlightSetup_default.highlight(code, { language: lang }).value;
|
|
841
|
+
} else {
|
|
842
|
+
html = highlightSetup_default.highlightAuto(code).value;
|
|
843
|
+
}
|
|
844
|
+
} catch {
|
|
845
|
+
html = "";
|
|
846
|
+
}
|
|
847
|
+
const handleCopy = () => {
|
|
848
|
+
navigator.clipboard.writeText(code);
|
|
849
|
+
setCopied(true);
|
|
850
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
851
|
+
timerRef.current = setTimeout(() => setCopied(false), 1800);
|
|
852
|
+
};
|
|
853
|
+
return /* @__PURE__ */ jsxs("div", { className: "not-prose my-4 rounded-2xl border border-border overflow-hidden bg-background-secondary-solid/5", children: [
|
|
854
|
+
title && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-4 py-2 border-b border-border bg-background-secondary-solid/10 text-xs sm:text-sm font-mono text-text-secondary", children: [
|
|
855
|
+
/* @__PURE__ */ jsx("span", { className: "material-symbols-rounded text-base", children: "description" }),
|
|
856
|
+
title
|
|
857
|
+
] }),
|
|
858
|
+
/* @__PURE__ */ jsx("div", { className: "overflow-auto [&_pre]:m-0 [&_pre]:p-4 [&_pre]:text-xs sm:[&_pre]:text-sm", children: /* @__PURE__ */ jsx("pre", { className: "m-0", children: /* @__PURE__ */ jsx("code", { className: `language-${lang || "plaintext"}`, dangerouslySetInnerHTML: { __html: html } }) }) }),
|
|
859
|
+
/* @__PURE__ */ jsx("button", { className: "absolute top-2 right-2 p-1.5 rounded-lg bg-background-secondary-solid/20 hover:bg-background-secondary-solid/40 transition-colors cursor-pointer border-none text-text-secondary hover:text-text-primary", onClick: handleCopy, title: "Copy code", children: /* @__PURE__ */ jsx("span", { className: "material-symbols-rounded", style: { fontSize: "1rem" }, children: copied ? "check" : "content_copy" }) })
|
|
860
|
+
] });
|
|
861
|
+
};
|
|
862
|
+
var defaultIcons = {
|
|
863
|
+
note: "info",
|
|
864
|
+
info: "lightbulb",
|
|
865
|
+
warning: "warning",
|
|
866
|
+
danger: "report",
|
|
867
|
+
greentext: "subdirectory_play_arrow"
|
|
868
|
+
};
|
|
869
|
+
var typeClasses = {
|
|
870
|
+
note: "border-info/20 bg-info/5 text-info",
|
|
871
|
+
info: "border-info/30 bg-info/10 text-info",
|
|
872
|
+
warning: "border-amber-500/30 bg-amber-500/10 text-amber-500",
|
|
873
|
+
danger: "border-danger/30 bg-danger/10 text-danger",
|
|
874
|
+
greentext: "border-success/30 bg-success/10 text-success"
|
|
875
|
+
};
|
|
876
|
+
var Admonition = ({ type, title, icon, className = "", style, children }) => {
|
|
877
|
+
const iconToRender = icon || defaultIcons[type] || "info";
|
|
878
|
+
return /* @__PURE__ */ jsxs(
|
|
879
|
+
"div",
|
|
880
|
+
{
|
|
881
|
+
className: `not-prose rounded-2xl mb-6 border shadow-xs p-4 ${typeClasses[type] || typeClasses.note} ${className}`,
|
|
882
|
+
style,
|
|
883
|
+
children: [
|
|
884
|
+
title && /* @__PURE__ */ jsxs("h5", { className: "font-bold text-base mb-2 m-0 flex items-center gap-2", children: [
|
|
885
|
+
/* @__PURE__ */ jsx(IconRenderer, { iconName: iconToRender, extraClasses: "shrink-0" }),
|
|
886
|
+
/* @__PURE__ */ jsx("span", { children: title })
|
|
887
|
+
] }),
|
|
888
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm leading-relaxed opacity-90", children })
|
|
889
|
+
]
|
|
890
|
+
}
|
|
891
|
+
);
|
|
892
|
+
};
|
|
893
|
+
var Details = ({
|
|
894
|
+
title,
|
|
895
|
+
icon,
|
|
896
|
+
defaultOpen = false,
|
|
897
|
+
className = "",
|
|
898
|
+
style,
|
|
899
|
+
children
|
|
900
|
+
}) => {
|
|
901
|
+
const [isOpen, setIsOpen] = useState2(defaultOpen);
|
|
902
|
+
const iconToRender = icon || "play_arrow";
|
|
903
|
+
return /* @__PURE__ */ jsxs(
|
|
904
|
+
"details",
|
|
905
|
+
{
|
|
906
|
+
className: `not-prose rounded-2xl border border-border mb-4 bg-background-primary/5 ${className}`,
|
|
907
|
+
open: isOpen,
|
|
908
|
+
style,
|
|
909
|
+
children: [
|
|
910
|
+
/* @__PURE__ */ jsxs(
|
|
911
|
+
"summary",
|
|
912
|
+
{
|
|
913
|
+
className: "cursor-pointer p-4 font-bold flex items-center gap-2 list-none [&::-webkit-details-marker]:hidden hover:text-accent-primary transition-colors",
|
|
914
|
+
onClick: (e) => {
|
|
915
|
+
e.preventDefault();
|
|
916
|
+
setIsOpen((prev) => !prev);
|
|
917
|
+
},
|
|
918
|
+
children: [
|
|
919
|
+
/* @__PURE__ */ jsx(
|
|
920
|
+
IconRenderer,
|
|
921
|
+
{
|
|
922
|
+
iconName: iconToRender,
|
|
923
|
+
extraClasses: `transition-transform ${isOpen ? "rotate-90" : ""}`
|
|
924
|
+
}
|
|
925
|
+
),
|
|
926
|
+
/* @__PURE__ */ jsx("span", { children: title })
|
|
927
|
+
]
|
|
928
|
+
}
|
|
929
|
+
),
|
|
930
|
+
isOpen && /* @__PURE__ */ jsx("div", { className: "px-4 pb-4 border-t border-border pt-3 text-sm leading-relaxed opacity-90 overflow-hidden min-w-0", children })
|
|
931
|
+
]
|
|
932
|
+
}
|
|
933
|
+
);
|
|
934
|
+
};
|
|
935
|
+
var Modal = ({ title, isOpen, onClose, children }) => {
|
|
936
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: (open) => {
|
|
937
|
+
if (!open) onClose();
|
|
938
|
+
}, children: /* @__PURE__ */ jsxs(Dialog.Portal, { children: [
|
|
939
|
+
/* @__PURE__ */ jsx(Dialog.Backdrop, { className: "fixed inset-0 z-[9999] bg-black/60" }),
|
|
940
|
+
/* @__PURE__ */ jsx(Dialog.Viewport, { className: "fixed inset-0 z-[9999] flex items-center justify-center p-4", children: /* @__PURE__ */ jsxs(Dialog.Popup, { className: "bg-background-primary border border-border shadow-2xl rounded-3xl w-full max-w-3xl max-h-[85vh] flex flex-col overflow-hidden", children: [
|
|
941
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center p-4 border-b border-border bg-background-secondary-solid/20", children: [
|
|
942
|
+
/* @__PURE__ */ jsx(Dialog.Title, { className: "text-lg font-bold !m-0", children: title }),
|
|
943
|
+
/* @__PURE__ */ jsx(Dialog.Close, { className: "w-8 h-8 rounded-full hover:bg-white/10 flex items-center justify-center transition-colors cursor-pointer border-none bg-transparent", children: /* @__PURE__ */ jsx("span", { className: "material-symbols-rounded text-base", children: "close" }) })
|
|
944
|
+
] }),
|
|
945
|
+
/* @__PURE__ */ jsx("div", { className: "p-6 overflow-auto min-h-0 text-text-primary [&_h1:first-child]:mt-0 [&_h2:first-child]:mt-0 [&_h3:first-child]:mt-0 [&_h4:first-child]:mt-0 [&_h5:first-child]:mt-0 [&_h6:first-child]:mt-0", children })
|
|
946
|
+
] }) })
|
|
947
|
+
] }) });
|
|
948
|
+
};
|
|
949
|
+
|
|
950
|
+
// renderers.tsx
|
|
951
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
952
|
+
function renderInline(text) {
|
|
953
|
+
if (!text) return text;
|
|
954
|
+
const parsePart = (part, key) => {
|
|
955
|
+
let match2;
|
|
956
|
+
if (match2 = part.match(/^\|\[([^\]]+)\]\|$/)) {
|
|
957
|
+
return /* @__PURE__ */ jsx2(IconRenderer, { iconName: match2[1] }, key);
|
|
958
|
+
}
|
|
959
|
+
if (match2 = part.match(/^!~(.+?)~!$/)) {
|
|
960
|
+
const content = match2[1];
|
|
961
|
+
const parts = content.split(";");
|
|
962
|
+
let color = "currentColor";
|
|
963
|
+
let decorationStyle = "solid";
|
|
964
|
+
let type = "underline";
|
|
965
|
+
let textIndex = 0;
|
|
966
|
+
if (parts[textIndex]?.match(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/) || ["red", "blue", "green", "purple", "orange", "yellow", "pink"].includes(parts[textIndex])) {
|
|
967
|
+
color = parts[textIndex++];
|
|
968
|
+
}
|
|
969
|
+
if (["solid", "double", "dotted", "dashed", "wavy"].includes(parts[textIndex])) {
|
|
970
|
+
decorationStyle = parts[textIndex++];
|
|
971
|
+
}
|
|
972
|
+
if (["underline", "line-through", "overline", "both"].includes(parts[textIndex])) {
|
|
973
|
+
type = parts[textIndex] === "both" ? "underline line-through" : parts[textIndex++];
|
|
974
|
+
}
|
|
975
|
+
const innerText = parts.slice(textIndex).join(";");
|
|
976
|
+
return /* @__PURE__ */ jsx2(
|
|
977
|
+
"span",
|
|
978
|
+
{
|
|
979
|
+
style: {
|
|
980
|
+
textDecoration: `${type} ${decorationStyle} ${color}`,
|
|
981
|
+
textDecorationThickness: "auto"
|
|
982
|
+
},
|
|
983
|
+
children: renderInline(innerText)
|
|
984
|
+
},
|
|
985
|
+
key
|
|
986
|
+
);
|
|
987
|
+
}
|
|
988
|
+
if (match2 = part.match(/%([^%\s]+?)%([\s\S]+?)%%/)) {
|
|
989
|
+
return /* @__PURE__ */ jsx2("span", { style: { color: match2[1] }, children: renderInline(match2[2]) }, key);
|
|
990
|
+
}
|
|
991
|
+
if (match2 = part.match(/^!>([^<]+?)<!$/)) {
|
|
992
|
+
return /* @__PURE__ */ jsx2("span", { className: "bg-text-primary text-bg-primary px-1 rounded hover:bg-transparent transition-colors cursor-pointer", children: renderInline(match2[1]) }, key);
|
|
993
|
+
}
|
|
994
|
+
if (match2 = part.match(/^==(.+?)==$/)) {
|
|
995
|
+
return /* @__PURE__ */ jsx2("mark", { className: "bg-yellow-500/20 text-inherit px-0.5 rounded", children: renderInline(match2[1]) }, key);
|
|
996
|
+
}
|
|
997
|
+
if (match2 = part.match(/^\*\*\*(.+?)\*\*\*$/)) {
|
|
998
|
+
return /* @__PURE__ */ jsx2("strong", { children: /* @__PURE__ */ jsx2("em", { children: renderInline(match2[1]) }) }, key);
|
|
999
|
+
}
|
|
1000
|
+
if (match2 = part.match(/^\*\*(.+?)\*\*$/)) {
|
|
1001
|
+
return /* @__PURE__ */ jsx2("strong", { children: renderInline(match2[1]) }, key);
|
|
1002
|
+
}
|
|
1003
|
+
if (match2 = part.match(/^_(.+?)_$/)) {
|
|
1004
|
+
return /* @__PURE__ */ jsx2("em", { children: renderInline(match2[1]) }, key);
|
|
1005
|
+
}
|
|
1006
|
+
if (match2 = part.match(/^~~(.+?)~~$/)) {
|
|
1007
|
+
return /* @__PURE__ */ jsx2("del", { children: renderInline(match2[1]) }, key);
|
|
1008
|
+
}
|
|
1009
|
+
if (match2 = part.match(/^`([^`]+)`$/)) {
|
|
1010
|
+
return /* @__PURE__ */ jsx2("code", { className: "text-[0.875em] font-mono bg-background-secondary/50 px-1.5 py-0.5 rounded text-text-primary", children: match2[1] }, key);
|
|
1011
|
+
}
|
|
1012
|
+
if (match2 = part.match(/^\[([^\]]+?)\]\(([^)]+?)\)$/)) {
|
|
1013
|
+
return /* @__PURE__ */ jsx2(
|
|
1014
|
+
"a",
|
|
1015
|
+
{
|
|
1016
|
+
href: match2[2],
|
|
1017
|
+
className: "text-accent-primary underline decoration-accent-primary/40 hover:decoration-accent-primary transition-colors",
|
|
1018
|
+
target: "_blank",
|
|
1019
|
+
rel: "noopener noreferrer",
|
|
1020
|
+
children: renderInline(match2[1])
|
|
1021
|
+
},
|
|
1022
|
+
key
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
if (part.startsWith("<") && part.endsWith(">")) {
|
|
1026
|
+
return /* @__PURE__ */ jsx2("span", { dangerouslySetInnerHTML: { __html: part } }, key);
|
|
1027
|
+
}
|
|
1028
|
+
return part;
|
|
1029
|
+
};
|
|
1030
|
+
const regex = /(\|\[[^\]]+\]\||\*\*\*.+?\*\*\*|\*\*.+?\*\*|_.+?_|~~.+?~~|`[^`]+?`|!~.+?~!|%[^%\s]+?%[\s\S]+?%%|!>.+?<!|==.+?==|\[[^\]]+?\]\([^)]+?\)|<[^>]+>)/g;
|
|
1031
|
+
const elements = [];
|
|
1032
|
+
let lastIndex = 0;
|
|
1033
|
+
let match;
|
|
1034
|
+
let keyCounter = 0;
|
|
1035
|
+
while ((match = regex.exec(text)) !== null) {
|
|
1036
|
+
if (match.index > lastIndex) {
|
|
1037
|
+
elements.push(text.slice(lastIndex, match.index));
|
|
1038
|
+
}
|
|
1039
|
+
elements.push(parsePart(match[0], `inline-${keyCounter++}`));
|
|
1040
|
+
lastIndex = regex.lastIndex;
|
|
1041
|
+
}
|
|
1042
|
+
if (lastIndex < text.length) {
|
|
1043
|
+
elements.push(text.slice(lastIndex));
|
|
1044
|
+
}
|
|
1045
|
+
return elements;
|
|
1046
|
+
}
|
|
1047
|
+
function renderTable(content) {
|
|
1048
|
+
const rows = content.split("\n").filter((r) => r.trim());
|
|
1049
|
+
if (rows.length < 2) return /* @__PURE__ */ jsx2("p", { children: content });
|
|
1050
|
+
const parseRow = (row) => row.split("|").map((c) => c.trim()).filter(Boolean);
|
|
1051
|
+
const headerCells = parseRow(rows[0]);
|
|
1052
|
+
const bodyRows = rows.slice(2).map(parseRow);
|
|
1053
|
+
return /* @__PURE__ */ jsx2("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs2("table", { className: "w-full text-sm sm:text-base border-collapse my-4", children: [
|
|
1054
|
+
/* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsx2("tr", { children: headerCells.map((cell, ci) => /* @__PURE__ */ jsx2("th", { className: "border border-border px-3 py-2 bg-background-secondary-solid/10 text-left font-bold", children: renderInline(cell) }, ci)) }) }),
|
|
1055
|
+
/* @__PURE__ */ jsx2("tbody", { children: bodyRows.map((cells, ri) => /* @__PURE__ */ jsx2("tr", { children: cells.map((cell, ci) => /* @__PURE__ */ jsx2("td", { className: "border border-border px-3 py-2", children: renderInline(cell) }, ci)) }, ri)) })
|
|
1056
|
+
] }) });
|
|
1057
|
+
}
|
|
1058
|
+
function renderList(content) {
|
|
1059
|
+
const lines = content.split("\n");
|
|
1060
|
+
const items = [];
|
|
1061
|
+
for (const line of lines) {
|
|
1062
|
+
if (!line.trim()) continue;
|
|
1063
|
+
const match = line.match(/^(\s*)([-*+]|\d+\.)\s+(.+)$/);
|
|
1064
|
+
if (match) {
|
|
1065
|
+
items.push({
|
|
1066
|
+
indent: match[1].length,
|
|
1067
|
+
marker: match[2],
|
|
1068
|
+
text: match[3]
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
if (items.length === 0) return /* @__PURE__ */ jsx2("p", { children: content });
|
|
1073
|
+
const isOrdered = /^\d+\.$/.test(items[0].marker);
|
|
1074
|
+
const Tag = isOrdered ? "ol" : "ul";
|
|
1075
|
+
return /* @__PURE__ */ jsx2(Tag, { className: `${isOrdered ? "list-decimal" : "list-disc"} pl-6 my-3 space-y-1 text-sm sm:text-base`, children: items.map((item, index) => /* @__PURE__ */ jsx2("li", { className: "leading-relaxed", children: renderInline(item.text) }, index)) });
|
|
1076
|
+
}
|
|
1077
|
+
function extractHeaders(elements) {
|
|
1078
|
+
return elements.filter((el) => el.type === "header");
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
// directives/AdmonitionDirective.tsx
|
|
1082
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
1083
|
+
var AdmonitionDirective = ({
|
|
1084
|
+
directiveType,
|
|
1085
|
+
props,
|
|
1086
|
+
renderSlot
|
|
1087
|
+
}) => {
|
|
1088
|
+
return /* @__PURE__ */ jsx3(
|
|
1089
|
+
Admonition,
|
|
1090
|
+
{
|
|
1091
|
+
type: directiveType,
|
|
1092
|
+
title: props.title,
|
|
1093
|
+
icon: props.icon,
|
|
1094
|
+
className: props.class,
|
|
1095
|
+
style: props.style ? parseCssString(props.style) : void 0,
|
|
1096
|
+
children: renderSlot("default")
|
|
1097
|
+
}
|
|
1098
|
+
);
|
|
1099
|
+
};
|
|
1100
|
+
var AdmonitionDirective_default = AdmonitionDirective;
|
|
1101
|
+
|
|
1102
|
+
// directives/CardDirective.tsx
|
|
1103
|
+
import React2, { useId } from "react";
|
|
1104
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1105
|
+
var CardDirective = ({
|
|
1106
|
+
directiveType,
|
|
1107
|
+
props,
|
|
1108
|
+
slots,
|
|
1109
|
+
renderSlot,
|
|
1110
|
+
context,
|
|
1111
|
+
options = {}
|
|
1112
|
+
}) => {
|
|
1113
|
+
const stableId = useId();
|
|
1114
|
+
const { title, image, icon, class: customClass, url, target } = props;
|
|
1115
|
+
const hasDescription = !!slots.description;
|
|
1116
|
+
const { isSingleCard } = options;
|
|
1117
|
+
const isModal = directiveType === "card-m";
|
|
1118
|
+
const isLink = directiveType === "card-b";
|
|
1119
|
+
const modalId = `modal-card-${props.id || stableId}`;
|
|
1120
|
+
const wrapperClass = customClass || "";
|
|
1121
|
+
const inlineStyles = props.style ? parseCssString(props.style) : {};
|
|
1122
|
+
const description = hasDescription ? renderSlot("description") : null;
|
|
1123
|
+
const content = renderSlot("content") || renderSlot("default");
|
|
1124
|
+
return /* @__PURE__ */ jsxs3(React2.Fragment, { children: [
|
|
1125
|
+
/* @__PURE__ */ jsxs3(
|
|
1126
|
+
"div",
|
|
1127
|
+
{
|
|
1128
|
+
className: `flex flex-col h-full rounded-3xl transition-all relative overflow-hidden group border min-w-[18rem] w-[18rem] max-w-[20rem] ${isModal || isLink ? "cursor-pointer !border-accent-primary/10 hover:border-accent-primary/50" : "border-border"} ${wrapperClass}`,
|
|
1129
|
+
style: inlineStyles,
|
|
1130
|
+
onClick: isModal ? (e) => {
|
|
1131
|
+
e.preventDefault();
|
|
1132
|
+
e.stopPropagation();
|
|
1133
|
+
context.setModals((prev) => ({ ...prev, [modalId]: true }));
|
|
1134
|
+
} : isLink && url ? () => window.open(url, "_blank") : void 0,
|
|
1135
|
+
role: isModal ? "button" : void 0,
|
|
1136
|
+
tabIndex: isModal ? 0 : void 0,
|
|
1137
|
+
onKeyDown: isModal ? (e) => {
|
|
1138
|
+
if (e.key === "Enter" || e.key === " ") context.setModals((prev) => ({ ...prev, [modalId]: true }));
|
|
1139
|
+
} : void 0,
|
|
1140
|
+
children: [
|
|
1141
|
+
image && /* @__PURE__ */ jsxs3("div", { className: `w-full ${isSingleCard ? "h-[240px]" : "h-[160px]"} overflow-hidden relative transition-all duration-500`, children: [
|
|
1142
|
+
/* @__PURE__ */ jsx4("img", { src: image, alt: title || "", className: "w-full h-full object-cover !m-0" }),
|
|
1143
|
+
/* @__PURE__ */ jsx4("div", { className: "absolute inset-0 bg-gradient-to-t from-background-primary/40 to-transparent" })
|
|
1144
|
+
] }),
|
|
1145
|
+
/* @__PURE__ */ jsxs3("div", { className: `flex flex-col flex-1 bg-background-primary/80 rounded-t-xl p-6 relative ${image ? "-mt-10" : ""} border-t border-white/5 shadow-2xl`, children: [
|
|
1146
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-3 mb-3", children: [
|
|
1147
|
+
icon && /* @__PURE__ */ jsx4("div", { className: "w-10 h-10 text-[1.6em] rounded-xl bg-accent-primary/20 flex items-center justify-center shrink-0 text-accent-primary", children: /* @__PURE__ */ jsx4(IconRenderer, { iconName: icon }) }),
|
|
1148
|
+
/* @__PURE__ */ jsx4("h3", { className: "text-base font-black tracking-tight leading-tight !m-0", children: title })
|
|
1149
|
+
] }),
|
|
1150
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex-1 flex flex-col gap-2", children: [
|
|
1151
|
+
description && /* @__PURE__ */ jsx4("div", { className: "text-sm opacity-80 leading-relaxed font-medium", children: description }),
|
|
1152
|
+
directiveType === "card" && content && /* @__PURE__ */ jsx4("div", { className: "mt-2", children: content })
|
|
1153
|
+
] }),
|
|
1154
|
+
(isModal || isLink) && /* @__PURE__ */ jsx4("div", { className: "mt-6 flex justify-end", children: isLink && url ? /* @__PURE__ */ jsxs3(
|
|
1155
|
+
"a",
|
|
1156
|
+
{
|
|
1157
|
+
href: url,
|
|
1158
|
+
target: "_blank",
|
|
1159
|
+
rel: "noopener noreferrer",
|
|
1160
|
+
className: "bg-accent-primary/20 hover:bg-accent-primary/30 px-4 py-2 rounded-xl flex items-center gap-1.5 text-[10px] font-black uppercase tracking-widest opacity-50 group-hover:opacity-100 group-hover:text-accent-primary transition-all no-underline",
|
|
1161
|
+
onClick: (e) => e.stopPropagation(),
|
|
1162
|
+
children: [
|
|
1163
|
+
/* @__PURE__ */ jsx4(IconRenderer, { iconName: "open_in_new" }),
|
|
1164
|
+
" Link"
|
|
1165
|
+
]
|
|
1166
|
+
}
|
|
1167
|
+
) : isModal ? /* @__PURE__ */ jsxs3("div", { className: "bg-accent-primary/20 hover:bg-accent-primary/30 px-4 py-2 cursor-pointer rounded-xl flex items-center gap-1.5 text-[10px] font-black uppercase tracking-widest opacity-50 group-hover:opacity-100 group-hover:text-accent-primary transition-all", children: [
|
|
1168
|
+
/* @__PURE__ */ jsx4(IconRenderer, { iconName: "arrow_forward" }),
|
|
1169
|
+
" Abrir"
|
|
1170
|
+
] }) : null })
|
|
1171
|
+
] })
|
|
1172
|
+
]
|
|
1173
|
+
}
|
|
1174
|
+
),
|
|
1175
|
+
isModal && /* @__PURE__ */ jsx4(
|
|
1176
|
+
Modal,
|
|
1177
|
+
{
|
|
1178
|
+
title: title || "Detalles",
|
|
1179
|
+
isOpen: !!context.modals[modalId],
|
|
1180
|
+
onClose: () => context.setModals((prev) => ({ ...prev, [modalId]: false })),
|
|
1181
|
+
children: /* @__PURE__ */ jsx4("div", { className: "prose prose-sm max-w-none", children: content })
|
|
1182
|
+
}
|
|
1183
|
+
)
|
|
1184
|
+
] });
|
|
1185
|
+
};
|
|
1186
|
+
var CardDirective_default = CardDirective;
|
|
1187
|
+
|
|
1188
|
+
// directives/DetailsDirective.tsx
|
|
1189
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
1190
|
+
var DetailsDirective = ({
|
|
1191
|
+
props,
|
|
1192
|
+
renderSlot
|
|
1193
|
+
}) => {
|
|
1194
|
+
return /* @__PURE__ */ jsx5(
|
|
1195
|
+
Details,
|
|
1196
|
+
{
|
|
1197
|
+
title: props.title || "Details",
|
|
1198
|
+
icon: props.icon,
|
|
1199
|
+
defaultOpen: props.defaultOpen === "true",
|
|
1200
|
+
className: props.class,
|
|
1201
|
+
style: props.style ? parseCssString(props.style) : void 0,
|
|
1202
|
+
children: renderSlot("default")
|
|
1203
|
+
}
|
|
1204
|
+
);
|
|
1205
|
+
};
|
|
1206
|
+
var DetailsDirective_default = DetailsDirective;
|
|
1207
|
+
|
|
1208
|
+
// directives/ModalDirective.tsx
|
|
1209
|
+
import { useId as useId2 } from "react";
|
|
1210
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1211
|
+
var ModalDirective = ({
|
|
1212
|
+
props,
|
|
1213
|
+
renderSlot,
|
|
1214
|
+
context
|
|
1215
|
+
}) => {
|
|
1216
|
+
const stableId = useId2();
|
|
1217
|
+
const modalId = `modal-${props.id || stableId}`;
|
|
1218
|
+
const label = props.label || props.title || "Open";
|
|
1219
|
+
const modalTitle = props.title || "Modal";
|
|
1220
|
+
const customClass = props.class || "";
|
|
1221
|
+
const hasSizeClass = /\btext-(xs|sm|base|lg|xl|[2-9]xl)\b/.test(customClass);
|
|
1222
|
+
const sizeClass = hasSizeClass ? "" : "text-sm";
|
|
1223
|
+
const hasDisplayClass = /\b(flex|inline-flex|block|inline-block|grid|inline-grid|hidden)\b/.test(customClass);
|
|
1224
|
+
const displayClass = hasDisplayClass ? "" : "inline-flex";
|
|
1225
|
+
const isInlineFlex = /\binline-flex\b/.test(customClass);
|
|
1226
|
+
const marginClass = isInlineFlex ? "my-1 mx-1" : "my-4";
|
|
1227
|
+
const btnBase = `${displayClass} items-center w-fit ${marginClass} ${sizeClass} px-4 py-2 rounded-xl font-bold no-underline gap-2 transition-all hover:scale-105 active:scale-95 border border-border bg-background-primary/5 hover:bg-background-primary/10 text-text-primary hover:text-text-primary`.replace(/\s+/g, " ");
|
|
1228
|
+
const btnClass = `${btnBase} ${customClass}`.trim();
|
|
1229
|
+
const positionMap = {
|
|
1230
|
+
"#left": "text-left",
|
|
1231
|
+
"#center": "text-center",
|
|
1232
|
+
"#right": "text-right"
|
|
1233
|
+
};
|
|
1234
|
+
const wrapperClass = customClass.split(/\s+/).map((c) => positionMap[c] || c).join(" ");
|
|
1235
|
+
const handleOpen = () => {
|
|
1236
|
+
context.setModals((prev) => ({ ...prev, [modalId]: true }));
|
|
1237
|
+
};
|
|
1238
|
+
const handleClose = () => {
|
|
1239
|
+
context.setModals((prev) => ({ ...prev, [modalId]: false }));
|
|
1240
|
+
};
|
|
1241
|
+
return /* @__PURE__ */ jsxs4("div", { className: `not-prose ${wrapperClass}`.trim(), children: [
|
|
1242
|
+
/* @__PURE__ */ jsxs4("button", { className: btnClass, onClick: handleOpen, children: [
|
|
1243
|
+
props.icon && /* @__PURE__ */ jsx6(IconRenderer, { iconName: props.icon }),
|
|
1244
|
+
label
|
|
1245
|
+
] }),
|
|
1246
|
+
/* @__PURE__ */ jsx6(
|
|
1247
|
+
Modal,
|
|
1248
|
+
{
|
|
1249
|
+
title: modalTitle,
|
|
1250
|
+
isOpen: !!context.modals[modalId],
|
|
1251
|
+
onClose: handleClose,
|
|
1252
|
+
children: renderSlot("default")
|
|
1253
|
+
}
|
|
1254
|
+
)
|
|
1255
|
+
] });
|
|
1256
|
+
};
|
|
1257
|
+
var ModalDirective_default = ModalDirective;
|
|
1258
|
+
|
|
1259
|
+
// directives/ButtonDirective.tsx
|
|
1260
|
+
import React4 from "react";
|
|
1261
|
+
import { Fragment, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1262
|
+
var ButtonDirective = ({
|
|
1263
|
+
props,
|
|
1264
|
+
renderSlot
|
|
1265
|
+
}) => {
|
|
1266
|
+
const url = props.url || props.href || "#";
|
|
1267
|
+
const label = props.label;
|
|
1268
|
+
const icon = props.icon || "near_me";
|
|
1269
|
+
const target = props.target || "_blank";
|
|
1270
|
+
const customClass = props.class || "";
|
|
1271
|
+
const hasSizeClass = /\btext-(xs|sm|base|lg|xl|[2-9]xl)\b/.test(customClass);
|
|
1272
|
+
const sizeClass = hasSizeClass ? "" : "text-sm";
|
|
1273
|
+
const hasDisplayClass = /\b(flex|inline-flex|block|inline-block|grid|inline-grid|hidden)\b/.test(customClass);
|
|
1274
|
+
const displayClass = hasDisplayClass ? "" : "inline-flex";
|
|
1275
|
+
const isInline = !customClass || !/\b(flex|block|grid)\b/.test(customClass) || /\binline-flex\b/.test(customClass);
|
|
1276
|
+
const marginClass = isInline ? "my-1 mx-1" : "my-4";
|
|
1277
|
+
const btnBase = `${displayClass} items-center w-fit ${marginClass} ${sizeClass} px-4 py-2 rounded-xl font-bold no-underline gap-2 transition-all hover:scale-105 active:scale-95 border border-border bg-background-primary/5 hover:bg-background-primary/10 text-text-primary hover:text-text-primary`.replace(/\s+/g, " ");
|
|
1278
|
+
const btnClass = `${btnBase} ${customClass}`.trim();
|
|
1279
|
+
const positionMap = {
|
|
1280
|
+
"#left": "flex justify-start",
|
|
1281
|
+
"#center": "flex justify-center",
|
|
1282
|
+
"#right": "flex justify-end"
|
|
1283
|
+
};
|
|
1284
|
+
const wrapperClass = customClass.split(/\s+/).map((c) => positionMap[c] || c).join(" ");
|
|
1285
|
+
if (label) {
|
|
1286
|
+
return /* @__PURE__ */ jsx7("div", { className: `not-prose ${wrapperClass}`.trim(), children: /* @__PURE__ */ jsxs5(
|
|
1287
|
+
"a",
|
|
1288
|
+
{
|
|
1289
|
+
href: url,
|
|
1290
|
+
target,
|
|
1291
|
+
rel: "noopener noreferrer",
|
|
1292
|
+
className: btnClass,
|
|
1293
|
+
children: [
|
|
1294
|
+
/* @__PURE__ */ jsx7(IconRenderer, { iconName: icon }),
|
|
1295
|
+
label
|
|
1296
|
+
]
|
|
1297
|
+
}
|
|
1298
|
+
) });
|
|
1299
|
+
}
|
|
1300
|
+
const slotContent = renderSlot("default");
|
|
1301
|
+
const findLinks = (element) => {
|
|
1302
|
+
if (!element) return [];
|
|
1303
|
+
if (React4.isValidElement(element) && element.type === "a") {
|
|
1304
|
+
return [element];
|
|
1305
|
+
}
|
|
1306
|
+
if (Array.isArray(element)) {
|
|
1307
|
+
return element.flatMap(findLinks);
|
|
1308
|
+
}
|
|
1309
|
+
if (React4.isValidElement(element) && element.props.children) {
|
|
1310
|
+
return findLinks(element.props.children);
|
|
1311
|
+
}
|
|
1312
|
+
return [];
|
|
1313
|
+
};
|
|
1314
|
+
const links = findLinks(slotContent);
|
|
1315
|
+
if (links.length > 0) {
|
|
1316
|
+
return /* @__PURE__ */ jsx7("div", { className: `not-prose ${wrapperClass}`.trim(), children: links.map(
|
|
1317
|
+
(link, index) => React4.cloneElement(
|
|
1318
|
+
link,
|
|
1319
|
+
{
|
|
1320
|
+
key: index,
|
|
1321
|
+
className: `${link.props.className || ""} ${btnClass}`.trim(),
|
|
1322
|
+
target,
|
|
1323
|
+
rel: "noopener noreferrer"
|
|
1324
|
+
},
|
|
1325
|
+
/* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
1326
|
+
/* @__PURE__ */ jsx7(IconRenderer, { iconName: icon }),
|
|
1327
|
+
link.props.children
|
|
1328
|
+
] })
|
|
1329
|
+
)
|
|
1330
|
+
) });
|
|
1331
|
+
}
|
|
1332
|
+
return /* @__PURE__ */ jsx7("div", { className: `not-prose ${wrapperClass}`.trim(), children: /* @__PURE__ */ jsxs5("a", { href: url, target, rel: "noopener noreferrer", className: btnClass, children: [
|
|
1333
|
+
/* @__PURE__ */ jsx7(IconRenderer, { iconName: icon }),
|
|
1334
|
+
slotContent
|
|
1335
|
+
] }) });
|
|
1336
|
+
};
|
|
1337
|
+
var ButtonDirective_default = ButtonDirective;
|
|
1338
|
+
|
|
1339
|
+
// directives/WrapperDirective.tsx
|
|
1340
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
1341
|
+
var WrapperDirective = ({
|
|
1342
|
+
props,
|
|
1343
|
+
renderSlot
|
|
1344
|
+
}) => {
|
|
1345
|
+
const className = props.class || "";
|
|
1346
|
+
const id = props.id || "";
|
|
1347
|
+
const inlineStyle = props.style ? parseCssString(props.style) : {};
|
|
1348
|
+
const wrapperProps = {};
|
|
1349
|
+
if (className) wrapperProps.className = className;
|
|
1350
|
+
if (id) wrapperProps.id = id;
|
|
1351
|
+
if (Object.keys(inlineStyle).length > 0) wrapperProps.style = inlineStyle;
|
|
1352
|
+
for (const [key, value] of Object.entries(props)) {
|
|
1353
|
+
if (key.startsWith("data-")) {
|
|
1354
|
+
wrapperProps[key] = value;
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
return /* @__PURE__ */ jsx8("div", { ...wrapperProps, children: renderSlot("default") });
|
|
1358
|
+
};
|
|
1359
|
+
var WrapperDirective_default = WrapperDirective;
|
|
1360
|
+
|
|
1361
|
+
// directives/SlideDirective.tsx
|
|
1362
|
+
import { useState as useState3, useEffect as useEffect2, useCallback, useRef as useRef2, useLayoutEffect } from "react";
|
|
1363
|
+
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1364
|
+
var slideCounter = 0;
|
|
1365
|
+
var SlideDirective = ({
|
|
1366
|
+
props,
|
|
1367
|
+
context,
|
|
1368
|
+
slots
|
|
1369
|
+
}) => {
|
|
1370
|
+
const rawContent = slots.default || "";
|
|
1371
|
+
const lines = rawContent.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
1372
|
+
const elements = lines.map((line) => context.parseMarkdown(line));
|
|
1373
|
+
const [current, setCurrent] = useState3(0);
|
|
1374
|
+
const interval = parseInt(props.interval || "3000", 10);
|
|
1375
|
+
const speed = parseInt(props.speed || "500", 10);
|
|
1376
|
+
const elRefs = useRef2([]);
|
|
1377
|
+
const [maxH, setMaxH] = useState3(0);
|
|
1378
|
+
useLayoutEffect(() => {
|
|
1379
|
+
let h = 0;
|
|
1380
|
+
elRefs.current.forEach((el) => {
|
|
1381
|
+
if (el) h = Math.max(h, el.offsetHeight);
|
|
1382
|
+
});
|
|
1383
|
+
if (h > 0) setMaxH(h);
|
|
1384
|
+
}, [elements]);
|
|
1385
|
+
const cycle = useCallback(() => {
|
|
1386
|
+
if (elements.length <= 1) return;
|
|
1387
|
+
setCurrent((prev) => (prev + 1) % elements.length);
|
|
1388
|
+
}, [elements.length]);
|
|
1389
|
+
useEffect2(() => {
|
|
1390
|
+
if (elements.length <= 1) return;
|
|
1391
|
+
const id = setInterval(cycle, interval);
|
|
1392
|
+
return () => clearInterval(id);
|
|
1393
|
+
}, [cycle, interval, elements.length]);
|
|
1394
|
+
if (elements.length === 0) return null;
|
|
1395
|
+
const rawClass = props.class || "";
|
|
1396
|
+
const inlineStyle = props.style ? parseCssString(props.style) : {};
|
|
1397
|
+
const textSizeMap = {
|
|
1398
|
+
"text-xs": "0.75rem",
|
|
1399
|
+
"text-sm": "0.875rem",
|
|
1400
|
+
"text-base": "1rem",
|
|
1401
|
+
"text-lg": "1.125rem",
|
|
1402
|
+
"text-xl": "1.25rem",
|
|
1403
|
+
"text-2xl": "1.5rem",
|
|
1404
|
+
"text-3xl": "1.875rem",
|
|
1405
|
+
"text-4xl": "2.25rem",
|
|
1406
|
+
"text-5xl": "3rem",
|
|
1407
|
+
"text-6xl": "3.75rem",
|
|
1408
|
+
"text-7xl": "4.5rem",
|
|
1409
|
+
"text-8xl": "6rem",
|
|
1410
|
+
"text-9xl": "8rem"
|
|
1411
|
+
};
|
|
1412
|
+
const textSizeMatch = rawClass.match(/\btext-(xs|sm|base|lg|xl|[2-9]xl)\b/);
|
|
1413
|
+
const forcedFontSize = textSizeMatch ? textSizeMap[textSizeMatch[0]] : null;
|
|
1414
|
+
const scopeClass = `sld-${++slideCounter}`;
|
|
1415
|
+
const className = textSizeMatch ? rawClass.replace(textSizeMatch[0], "").replace(/\s+/g, " ").trim() : rawClass;
|
|
1416
|
+
return /* @__PURE__ */ jsxs6(
|
|
1417
|
+
"div",
|
|
1418
|
+
{
|
|
1419
|
+
className: "not-prose",
|
|
1420
|
+
style: { height: maxH || "auto", position: "relative", overflow: "hidden", ...inlineStyle },
|
|
1421
|
+
children: [
|
|
1422
|
+
forcedFontSize && /* @__PURE__ */ jsx9("style", { children: `.${scopeClass} * { font-size: ${forcedFontSize} !important; line-height: normal !important; }` }),
|
|
1423
|
+
/* @__PURE__ */ jsx9(
|
|
1424
|
+
"div",
|
|
1425
|
+
{
|
|
1426
|
+
style: {
|
|
1427
|
+
position: "absolute",
|
|
1428
|
+
left: 0,
|
|
1429
|
+
right: 0,
|
|
1430
|
+
top: 0,
|
|
1431
|
+
transition: `transform ${speed}ms cubic-bezier(0.16, 1, 0.3, 1)`,
|
|
1432
|
+
transform: `translateY(${-current * maxH}px)`
|
|
1433
|
+
},
|
|
1434
|
+
children: elements.map((tokens, i) => /* @__PURE__ */ jsx9(
|
|
1435
|
+
"div",
|
|
1436
|
+
{
|
|
1437
|
+
ref: (el) => {
|
|
1438
|
+
elRefs.current[i] = el;
|
|
1439
|
+
},
|
|
1440
|
+
style: maxH ? { height: maxH, display: "flex", alignItems: "center", overflow: "hidden" } : { display: "flex", alignItems: "center" },
|
|
1441
|
+
children: /* @__PURE__ */ jsx9("div", { className: `${scopeClass} ${className}`, style: { width: "100%" }, children: context.processAndRenderElements(tokens) })
|
|
1442
|
+
},
|
|
1443
|
+
i
|
|
1444
|
+
))
|
|
1445
|
+
}
|
|
1446
|
+
)
|
|
1447
|
+
]
|
|
1448
|
+
}
|
|
1449
|
+
);
|
|
1450
|
+
};
|
|
1451
|
+
var SlideDirective_default = SlideDirective;
|
|
1452
|
+
|
|
1453
|
+
// directives/index.ts
|
|
1454
|
+
var directiveRegistry = {
|
|
1455
|
+
// Admonitions
|
|
1456
|
+
note: AdmonitionDirective_default,
|
|
1457
|
+
info: AdmonitionDirective_default,
|
|
1458
|
+
warning: AdmonitionDirective_default,
|
|
1459
|
+
danger: AdmonitionDirective_default,
|
|
1460
|
+
greentext: AdmonitionDirective_default,
|
|
1461
|
+
// Cards
|
|
1462
|
+
card: CardDirective_default,
|
|
1463
|
+
"card-m": CardDirective_default,
|
|
1464
|
+
"card-b": CardDirective_default,
|
|
1465
|
+
// Interactive
|
|
1466
|
+
details: DetailsDirective_default,
|
|
1467
|
+
modal: ModalDirective_default,
|
|
1468
|
+
button: ButtonDirective_default,
|
|
1469
|
+
// Layout / generic wrappers
|
|
1470
|
+
div: WrapperDirective_default,
|
|
1471
|
+
style: WrapperDirective_default,
|
|
1472
|
+
custom: WrapperDirective_default,
|
|
1473
|
+
raw: WrapperDirective_default,
|
|
1474
|
+
// Animation
|
|
1475
|
+
slide: SlideDirective_default
|
|
1476
|
+
};
|
|
1477
|
+
var directives_default = directiveRegistry;
|
|
1478
|
+
|
|
1479
|
+
// DirectiveRenderer.tsx
|
|
1480
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
1481
|
+
var DirectiveRenderer = ({
|
|
1482
|
+
element,
|
|
1483
|
+
context,
|
|
1484
|
+
index,
|
|
1485
|
+
allElements
|
|
1486
|
+
}) => {
|
|
1487
|
+
const { directiveType, props, slots, scopeId } = element;
|
|
1488
|
+
const Component = directives_default[directiveType];
|
|
1489
|
+
const renderSlot = (name) => {
|
|
1490
|
+
const slotContent = slots[name];
|
|
1491
|
+
if (!slotContent) return null;
|
|
1492
|
+
const parsed = context.parseMarkdown(slotContent);
|
|
1493
|
+
return context.processAndRenderElements(parsed);
|
|
1494
|
+
};
|
|
1495
|
+
const directiveProps = {
|
|
1496
|
+
directiveType,
|
|
1497
|
+
props,
|
|
1498
|
+
slots,
|
|
1499
|
+
renderSlot,
|
|
1500
|
+
context,
|
|
1501
|
+
index,
|
|
1502
|
+
allElements
|
|
1503
|
+
};
|
|
1504
|
+
if (Component) {
|
|
1505
|
+
return /* @__PURE__ */ jsx10(Component, { ...directiveProps }, index);
|
|
1506
|
+
}
|
|
1507
|
+
return /* @__PURE__ */ jsx10("div", { className: `my-4 p-4 rounded-2xl border border-border bg-background-primary/5`, children: renderSlot("default") }, index);
|
|
1508
|
+
};
|
|
1509
|
+
var DirectiveRenderer_default = DirectiveRenderer;
|
|
1510
|
+
|
|
1511
|
+
// RawHtmlRenderer.tsx
|
|
1512
|
+
import { useRef as useRef4, useEffect as useEffect4 } from "react";
|
|
1513
|
+
|
|
1514
|
+
// useTailwindCDN.ts
|
|
1515
|
+
import { useEffect as useEffect3, useRef as useRef3 } from "react";
|
|
1516
|
+
function scanTailwindCDN() {
|
|
1517
|
+
const tw = window.tailwind;
|
|
1518
|
+
if (tw?.scan) tw.scan();
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
// RawHtmlRenderer.tsx
|
|
1522
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
1523
|
+
var RawHtmlRenderer = ({
|
|
1524
|
+
content,
|
|
1525
|
+
globalStyles,
|
|
1526
|
+
wrapperClassName
|
|
1527
|
+
}) => {
|
|
1528
|
+
const containerRef = useRef4(null);
|
|
1529
|
+
useEffect4(() => {
|
|
1530
|
+
if (!containerRef.current) return;
|
|
1531
|
+
const scripts = containerRef.current.querySelectorAll("script");
|
|
1532
|
+
scripts.forEach((oldScript) => {
|
|
1533
|
+
const newScript = document.createElement("script");
|
|
1534
|
+
Array.from(oldScript.attributes).forEach(
|
|
1535
|
+
(attr) => newScript.setAttribute(attr.name, attr.value)
|
|
1536
|
+
);
|
|
1537
|
+
newScript.textContent = oldScript.textContent;
|
|
1538
|
+
oldScript.parentNode?.replaceChild(newScript, oldScript);
|
|
1539
|
+
});
|
|
1540
|
+
scanTailwindCDN();
|
|
1541
|
+
}, [content]);
|
|
1542
|
+
useEffect4(() => {
|
|
1543
|
+
if (!globalStyles) return;
|
|
1544
|
+
const styleEl = document.createElement("style");
|
|
1545
|
+
styleEl.setAttribute("data-global", "");
|
|
1546
|
+
styleEl.textContent = globalStyles;
|
|
1547
|
+
document.head.appendChild(styleEl);
|
|
1548
|
+
return () => {
|
|
1549
|
+
if (styleEl.parentNode) document.head.removeChild(styleEl);
|
|
1550
|
+
};
|
|
1551
|
+
}, [globalStyles]);
|
|
1552
|
+
return /* @__PURE__ */ jsx11("div", { className: wrapperClassName, ref: containerRef, children: /* @__PURE__ */ jsx11("div", { dangerouslySetInnerHTML: { __html: content } }) });
|
|
1553
|
+
};
|
|
1554
|
+
var RawHtmlRenderer_default = RawHtmlRenderer;
|
|
1555
|
+
|
|
1556
|
+
// context.tsx
|
|
1557
|
+
import { createContext, useContext } from "react";
|
|
1558
|
+
var RenderCtx = createContext(null);
|
|
1559
|
+
var RenderContextProvider = RenderCtx.Provider;
|
|
1560
|
+
|
|
1561
|
+
// CustomMarkdownRenderer.tsx
|
|
1562
|
+
import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1563
|
+
var CustomMarkdownRenderer = ({ content: initialContent }) => {
|
|
1564
|
+
const [modals, setModals] = useState4({});
|
|
1565
|
+
const baseId = useId3().replace(/:/g, "");
|
|
1566
|
+
const articleClass = `scope-${baseId}`;
|
|
1567
|
+
const contextRef = useRef5(null);
|
|
1568
|
+
resetScopeCounter();
|
|
1569
|
+
const allElements = useMemo(() => parseMarkdown(initialContent), [initialContent]);
|
|
1570
|
+
useEffect5(() => {
|
|
1571
|
+
const handleHashChange = () => {
|
|
1572
|
+
const hash = window.location.hash;
|
|
1573
|
+
if (hash) {
|
|
1574
|
+
const parts = hash.split("#");
|
|
1575
|
+
const id = parts[parts.length - 1];
|
|
1576
|
+
scrollToId(id);
|
|
1577
|
+
}
|
|
1578
|
+
};
|
|
1579
|
+
handleHashChange();
|
|
1580
|
+
window.addEventListener("hashchange", handleHashChange);
|
|
1581
|
+
return () => window.removeEventListener("hashchange", handleHashChange);
|
|
1582
|
+
}, [initialContent]);
|
|
1583
|
+
const renderElement = useCallback2(
|
|
1584
|
+
(element, index, _depth = 0) => {
|
|
1585
|
+
switch (element.type) {
|
|
1586
|
+
case "header": {
|
|
1587
|
+
const HeaderTag = `h${element.level}`;
|
|
1588
|
+
let text = element.text;
|
|
1589
|
+
const alignCenter = text.match(/^->\s*(.+?)\s*<-\s*$/);
|
|
1590
|
+
const alignRight = text.match(/^->\s*(.+?)\s*->\s*$/);
|
|
1591
|
+
if (alignCenter) {
|
|
1592
|
+
text = alignCenter[1];
|
|
1593
|
+
} else if (alignRight) {
|
|
1594
|
+
text = alignRight[1];
|
|
1595
|
+
}
|
|
1596
|
+
const userClasses = element.classes || "";
|
|
1597
|
+
let headerClasses = `md-h${element.level}`;
|
|
1598
|
+
if (alignCenter) headerClasses += " text-center";
|
|
1599
|
+
if (alignRight) headerClasses += " text-right";
|
|
1600
|
+
if (userClasses) headerClasses += ` ${userClasses}`;
|
|
1601
|
+
return React8.createElement(
|
|
1602
|
+
HeaderTag,
|
|
1603
|
+
{ key: index, id: element.id, className: headerClasses },
|
|
1604
|
+
renderInline(text)
|
|
1605
|
+
);
|
|
1606
|
+
}
|
|
1607
|
+
case "paragraph": {
|
|
1608
|
+
const lines = element.content.split("\n");
|
|
1609
|
+
const processedContent = lines.map((line, lineIndex) => {
|
|
1610
|
+
const hardBreakMatch = line.match(/^(.*?)(\s{2,})$/);
|
|
1611
|
+
if (hardBreakMatch) {
|
|
1612
|
+
return /* @__PURE__ */ jsxs7(React8.Fragment, { children: [
|
|
1613
|
+
renderInline(hardBreakMatch[1]),
|
|
1614
|
+
/* @__PURE__ */ jsx12("br", {})
|
|
1615
|
+
] }, lineIndex);
|
|
1616
|
+
}
|
|
1617
|
+
const isLastLine = lineIndex === lines.length - 1;
|
|
1618
|
+
return /* @__PURE__ */ jsxs7(React8.Fragment, { children: [
|
|
1619
|
+
renderInline(line),
|
|
1620
|
+
!isLastLine && " "
|
|
1621
|
+
] }, lineIndex);
|
|
1622
|
+
});
|
|
1623
|
+
const pUserClasses = element.classes || "";
|
|
1624
|
+
let pClasses = "md-p";
|
|
1625
|
+
if (pUserClasses) pClasses += ` ${pUserClasses}`;
|
|
1626
|
+
if (element.align) pClasses += ` text-${element.align}`;
|
|
1627
|
+
return /* @__PURE__ */ jsx12("p", { id: element.id, className: pClasses, children: processedContent }, index);
|
|
1628
|
+
}
|
|
1629
|
+
case "codeblock":
|
|
1630
|
+
return /* @__PURE__ */ jsx12(
|
|
1631
|
+
CodeBlock,
|
|
1632
|
+
{
|
|
1633
|
+
code: element.content,
|
|
1634
|
+
language: element.language,
|
|
1635
|
+
title: element.title
|
|
1636
|
+
},
|
|
1637
|
+
index
|
|
1638
|
+
);
|
|
1639
|
+
case "directive":
|
|
1640
|
+
return /* @__PURE__ */ jsx12(
|
|
1641
|
+
DirectiveRenderer_default,
|
|
1642
|
+
{
|
|
1643
|
+
element,
|
|
1644
|
+
context: contextRef.current,
|
|
1645
|
+
index,
|
|
1646
|
+
allElements
|
|
1647
|
+
},
|
|
1648
|
+
index
|
|
1649
|
+
);
|
|
1650
|
+
case "html": {
|
|
1651
|
+
let processedContent = element.content;
|
|
1652
|
+
let globalStyles = "";
|
|
1653
|
+
processedContent = processedContent.replace(
|
|
1654
|
+
/<style(?:\s+[^>]*)?>([\s\S]*?)<\/style>/gi,
|
|
1655
|
+
(_match, cssContent) => {
|
|
1656
|
+
globalStyles += cssContent + "\n";
|
|
1657
|
+
return "";
|
|
1658
|
+
}
|
|
1659
|
+
);
|
|
1660
|
+
const wrapperClassName = "w-full my-4";
|
|
1661
|
+
return /* @__PURE__ */ jsx12(
|
|
1662
|
+
RawHtmlRenderer_default,
|
|
1663
|
+
{
|
|
1664
|
+
content: processedContent,
|
|
1665
|
+
globalStyles: globalStyles || void 0,
|
|
1666
|
+
wrapperClassName
|
|
1667
|
+
},
|
|
1668
|
+
index
|
|
1669
|
+
);
|
|
1670
|
+
}
|
|
1671
|
+
case "html-block": {
|
|
1672
|
+
const htmlBlock = element;
|
|
1673
|
+
const props = parseHtmlAttrs(htmlBlock.attrs);
|
|
1674
|
+
return React8.createElement(
|
|
1675
|
+
htmlBlock.tag,
|
|
1676
|
+
{ key: index, ...props },
|
|
1677
|
+
...processAndRenderElements(htmlBlock.children, _depth + 1)
|
|
1678
|
+
);
|
|
1679
|
+
}
|
|
1680
|
+
case "image":
|
|
1681
|
+
return /* @__PURE__ */ jsx12(
|
|
1682
|
+
"img",
|
|
1683
|
+
{
|
|
1684
|
+
alt: element.alt,
|
|
1685
|
+
src: element.src,
|
|
1686
|
+
style: element.style,
|
|
1687
|
+
className: "max-w-full h-auto"
|
|
1688
|
+
},
|
|
1689
|
+
index
|
|
1690
|
+
);
|
|
1691
|
+
case "table":
|
|
1692
|
+
return /* @__PURE__ */ jsx12("div", { children: renderTable(element.content) }, index);
|
|
1693
|
+
case "list":
|
|
1694
|
+
return /* @__PURE__ */ jsx12("div", { children: renderList(element.content) }, index);
|
|
1695
|
+
case "blockquote":
|
|
1696
|
+
return /* @__PURE__ */ jsx12("blockquote", { className: `border-l-4 border-accent-primary/30 pl-4 italic text-text-secondary my-4 text-sm sm:text-base${element.classes ? ` ${element.classes}` : ""}`, children: renderInline(element.content) }, index);
|
|
1697
|
+
case "hr":
|
|
1698
|
+
return /* @__PURE__ */ jsx12("hr", { className: "my-8 border-border" }, index);
|
|
1699
|
+
case "toc":
|
|
1700
|
+
return /* @__PURE__ */ jsx12("div", { children: generateToc(allElements) }, index);
|
|
1701
|
+
default:
|
|
1702
|
+
return null;
|
|
1703
|
+
}
|
|
1704
|
+
},
|
|
1705
|
+
[allElements]
|
|
1706
|
+
);
|
|
1707
|
+
const processAndRenderElements = useCallback2(
|
|
1708
|
+
(elements, depth = 0) => {
|
|
1709
|
+
const result = [];
|
|
1710
|
+
let i = 0;
|
|
1711
|
+
while (i < elements.length) {
|
|
1712
|
+
const el = elements[i];
|
|
1713
|
+
if (el.type === "directive" && ["card", "card-m", "card-b"].includes(el.directiveType)) {
|
|
1714
|
+
const cards = [];
|
|
1715
|
+
while (i < elements.length && elements[i].type === "directive" && ["card", "card-m", "card-b"].includes(elements[i].directiveType)) {
|
|
1716
|
+
cards.push(elements[i]);
|
|
1717
|
+
i++;
|
|
1718
|
+
}
|
|
1719
|
+
if (cards.length === 1 || cards[0].props?.batch === "off") {
|
|
1720
|
+
for (let c = 0; c < cards.length; c++) {
|
|
1721
|
+
result.push(renderElement(cards[c], result.length, depth));
|
|
1722
|
+
}
|
|
1723
|
+
} else {
|
|
1724
|
+
const firstCardClass = cards[0].props?.["class"] || "";
|
|
1725
|
+
const justifyClasses = firstCardClass.match(/\bjustify-\S+/g) || [];
|
|
1726
|
+
const wrapperJustify = justifyClasses.length > 0 ? justifyClasses.join(" ") : "";
|
|
1727
|
+
result.push(
|
|
1728
|
+
/* @__PURE__ */ jsx12("div", { className: `not-prose flex flex-wrap gap-6 my-6 ${wrapperJustify}`, children: cards.map((card, ci) => /* @__PURE__ */ jsx12(React8.Fragment, { children: renderElement(card, ci, depth) }, ci)) }, `card-grid-${result.length}`)
|
|
1729
|
+
);
|
|
1730
|
+
}
|
|
1731
|
+
} else {
|
|
1732
|
+
result.push(renderElement(el, result.length, depth));
|
|
1733
|
+
i++;
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
return result;
|
|
1737
|
+
},
|
|
1738
|
+
[renderElement]
|
|
1739
|
+
);
|
|
1740
|
+
const generateToc = (elements) => {
|
|
1741
|
+
const headers = extractHeaders(elements);
|
|
1742
|
+
if (headers.length === 0) return null;
|
|
1743
|
+
return /* @__PURE__ */ jsxs7("nav", { className: "not-prose my-6 p-4 rounded-2xl border border-border bg-background-primary/5", children: [
|
|
1744
|
+
/* @__PURE__ */ jsx12("div", { className: "text-base font-bold mb-3", children: "Table of Contents" }),
|
|
1745
|
+
/* @__PURE__ */ jsx12("ul", { className: "space-y-1 list-none p-0 m-0", children: headers.map((h, i) => {
|
|
1746
|
+
if (h.type !== "header") return null;
|
|
1747
|
+
const indentClass = h.level <= 2 ? "pl-0" : h.level === 3 ? "pl-4" : h.level === 4 ? "pl-8" : "pl-12";
|
|
1748
|
+
return /* @__PURE__ */ jsx12("li", { className: `${indentClass} text-sm sm:text-base`, children: /* @__PURE__ */ jsx12(
|
|
1749
|
+
"a",
|
|
1750
|
+
{
|
|
1751
|
+
href: `#${h.id}`,
|
|
1752
|
+
className: "text-accent-primary hover:text-accent-primary/80 no-underline hover:underline transition-colors",
|
|
1753
|
+
onClick: (e) => {
|
|
1754
|
+
e.preventDefault();
|
|
1755
|
+
scrollToId(h.id);
|
|
1756
|
+
},
|
|
1757
|
+
children: renderInline(h.text.replace(/->|<-/g, "").trim())
|
|
1758
|
+
}
|
|
1759
|
+
) }, i);
|
|
1760
|
+
}) })
|
|
1761
|
+
] });
|
|
1762
|
+
};
|
|
1763
|
+
const contextForDirectives = {
|
|
1764
|
+
modals,
|
|
1765
|
+
setModals,
|
|
1766
|
+
articleClass,
|
|
1767
|
+
allElements,
|
|
1768
|
+
parseMarkdown,
|
|
1769
|
+
renderElement,
|
|
1770
|
+
renderInline,
|
|
1771
|
+
processAndRenderElements
|
|
1772
|
+
};
|
|
1773
|
+
contextRef.current = contextForDirectives;
|
|
1774
|
+
return /* @__PURE__ */ jsx12(RenderContextProvider, { value: contextForDirectives, children: processAndRenderElements(allElements) });
|
|
1775
|
+
};
|
|
1776
|
+
var CustomMarkdownRenderer_default = CustomMarkdownRenderer;
|
|
1777
|
+
|
|
1778
|
+
// NReditor.tsx
|
|
1779
|
+
import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1780
|
+
var customSyntaxHighlighting = HighlightStyle.define([
|
|
1781
|
+
{ tag: t2.heading, fontWeight: "bold", color: "var(--tc-heading, #e2e8f0)" },
|
|
1782
|
+
{ tag: t2.quote, color: "var(--tc-quote, #94a3b8)", fontStyle: "italic" },
|
|
1783
|
+
{ tag: t2.meta, color: "var(--tc-meta, #64748b)" },
|
|
1784
|
+
{ tag: t2.variableName, color: "var(--tc-variable, #38bdf8)" },
|
|
1785
|
+
{ tag: t2.strong, fontWeight: "bold" },
|
|
1786
|
+
{ tag: t2.emphasis, fontStyle: "italic" },
|
|
1787
|
+
{ tag: t2.strikethrough, textDecoration: "line-through" },
|
|
1788
|
+
{ tag: t2.link, color: "var(--tc-link, #38bdf8)" },
|
|
1789
|
+
{ tag: t2.url, color: "var(--tc-link, #38bdf8)" },
|
|
1790
|
+
{ tag: t2.comment, color: "var(--tc-comment, #64748b)" },
|
|
1791
|
+
{ tag: t2.keyword, color: "var(--tc-heading, #e2e8f0)", fontWeight: "bold" },
|
|
1792
|
+
{ tag: t2.typeName, color: "var(--tc-type, #a78bfa)" },
|
|
1793
|
+
{ tag: t2.string, color: "var(--tc-string, #4ade80)" },
|
|
1794
|
+
{ tag: t2.attributeName, color: "var(--tc-attribute, #fb923c)" },
|
|
1795
|
+
{ tag: t2.propertyName, color: "#0ea5e9" },
|
|
1796
|
+
{ tag: t2.className, color: "#f59e0b", fontStyle: "italic" },
|
|
1797
|
+
{ tag: t2.special(t2.emphasis), textDecoration: "underline" },
|
|
1798
|
+
{ tag: t2.special(t2.comment), backgroundColor: "var(--tc-highlight-bg, rgba(255,255,255,0.05))", padding: "0 2px", borderRadius: "2px" }
|
|
1799
|
+
]);
|
|
1800
|
+
var customEditorTheme = EditorView.theme({
|
|
1801
|
+
"&": {
|
|
1802
|
+
color: "var(--color-text-primary, #e2e8f0)",
|
|
1803
|
+
backgroundColor: "transparent !important",
|
|
1804
|
+
height: "100%",
|
|
1805
|
+
position: "relative",
|
|
1806
|
+
display: "flex",
|
|
1807
|
+
flexDirection: "column",
|
|
1808
|
+
minHeight: "0"
|
|
1809
|
+
},
|
|
1810
|
+
"&.cm-focused": { outline: "none" },
|
|
1811
|
+
".cm-scroller": {
|
|
1812
|
+
overflow: "auto !important",
|
|
1813
|
+
flex: "1",
|
|
1814
|
+
minHeight: "0",
|
|
1815
|
+
WebkitOverflowScrolling: "touch"
|
|
1816
|
+
},
|
|
1817
|
+
".cm-gutters": {
|
|
1818
|
+
backgroundColor: "transparent !important",
|
|
1819
|
+
borderRight: "1px solid var(--color-border, #334155)",
|
|
1820
|
+
color: "var(--color-text-secondary, #94a3b8)",
|
|
1821
|
+
opacity: 0.6,
|
|
1822
|
+
border: "none"
|
|
1823
|
+
},
|
|
1824
|
+
".cm-activeLineGutter": { backgroundColor: "transparent" },
|
|
1825
|
+
".cm-lineNumbers": { color: "inherit" },
|
|
1826
|
+
".cm-foldGutter": { padding: "0px", cursor: "pointer" },
|
|
1827
|
+
".cm-foldPlaceholder": {
|
|
1828
|
+
backgroundColor: "rgba(255, 255, 255, 0.05)",
|
|
1829
|
+
border: "1px solid var(--color-border, #334155)",
|
|
1830
|
+
color: "var(--tc-heading, #e2e8f0)",
|
|
1831
|
+
padding: "0 6px",
|
|
1832
|
+
borderRadius: "4px",
|
|
1833
|
+
margin: "0 4px",
|
|
1834
|
+
fontSize: "0.9em",
|
|
1835
|
+
fontWeight: "bold"
|
|
1836
|
+
},
|
|
1837
|
+
".dark .cm-foldPlaceholder": {
|
|
1838
|
+
backgroundColor: "rgba(255, 255, 255, 0.1)"
|
|
1839
|
+
},
|
|
1840
|
+
".cm-activeLine": { backgroundColor: "transparent" },
|
|
1841
|
+
".cm-cursor": { borderLeftColor: "var(--color-text-primary, #e2e8f0)" },
|
|
1842
|
+
"&.cm-focused .cm-selectionBackground, .cm-selectionBackground": {
|
|
1843
|
+
backgroundColor: "var(--tc-selection-bg, rgba(56, 189, 248, 0.2)) !important"
|
|
1844
|
+
},
|
|
1845
|
+
".cm-blockquote-line": {
|
|
1846
|
+
color: "var(--tc-blockquote-color, #94a3b8)",
|
|
1847
|
+
fontStyle: "italic",
|
|
1848
|
+
borderLeft: "2px solid var(--tc-blockquote-border, #334155)",
|
|
1849
|
+
paddingLeft: "10px"
|
|
1850
|
+
},
|
|
1851
|
+
".cm-spoiler": {
|
|
1852
|
+
backgroundColor: "var(--color-text-secondary, #94a3b8)",
|
|
1853
|
+
color: "var(--color-text-secondary, #94a3b8)",
|
|
1854
|
+
borderRadius: "3px",
|
|
1855
|
+
padding: "0 2px",
|
|
1856
|
+
cursor: "pointer",
|
|
1857
|
+
transition: "background-color 0.2s, color 0.2s"
|
|
1858
|
+
},
|
|
1859
|
+
".cm-spoiler:hover": {
|
|
1860
|
+
backgroundColor: "transparent",
|
|
1861
|
+
color: "var(--color-text-primary, #e2e8f0)"
|
|
1862
|
+
},
|
|
1863
|
+
".cm-admonition-bg": {
|
|
1864
|
+
borderLeft: "none !important",
|
|
1865
|
+
marginLeft: "0px"
|
|
1866
|
+
},
|
|
1867
|
+
".cm-admonition-button": { borderLeftColor: "var(--tc-attribute, #fb923c)" },
|
|
1868
|
+
".cm-admonition-modal": { borderLeftColor: "var(--tc-variable, #38bdf8)" },
|
|
1869
|
+
".cm-admonition-warning": { borderLeftColor: "#f59e0b" },
|
|
1870
|
+
".cm-admonition-danger": { borderLeftColor: "#ef4444" },
|
|
1871
|
+
".cm-raw-block": {
|
|
1872
|
+
fontFamily: "monospace",
|
|
1873
|
+
backgroundColor: "rgba(0, 0, 0, 0.1)"
|
|
1874
|
+
},
|
|
1875
|
+
".dark .cm-raw-block": {
|
|
1876
|
+
backgroundColor: "rgba(255, 255, 255, 0.05)"
|
|
1877
|
+
},
|
|
1878
|
+
".cm-admonition-depth-1": {
|
|
1879
|
+
boxShadow: "inset 4px 0 0 hsl(20, 70%, 50%)",
|
|
1880
|
+
backgroundColor: "hsla(20, 70%, 50%, 0.05)",
|
|
1881
|
+
paddingLeft: "12px !important"
|
|
1882
|
+
},
|
|
1883
|
+
".cm-admonition-depth-2": {
|
|
1884
|
+
boxShadow: "inset 4px 0 0 hsl(20, 70%, 50%), inset 8px 0 0 hsl(140, 70%, 50%)",
|
|
1885
|
+
backgroundColor: "hsla(140, 70%, 50%, 0.05)",
|
|
1886
|
+
paddingLeft: "16px !important"
|
|
1887
|
+
},
|
|
1888
|
+
".cm-admonition-depth-3": {
|
|
1889
|
+
boxShadow: "inset 4px 0 0 hsl(20, 70%, 50%), inset 8px 0 0 hsl(140, 70%, 50%), inset 12px 0 0 hsl(200, 70%, 50%)",
|
|
1890
|
+
backgroundColor: "hsla(200, 70%, 50%, 0.05)",
|
|
1891
|
+
paddingLeft: "20px !important"
|
|
1892
|
+
},
|
|
1893
|
+
".cm-admonition-depth-4": {
|
|
1894
|
+
boxShadow: "inset 4px 0 0 hsl(20, 70%, 50%), inset 8px 0 0 hsl(140, 70%, 50%), inset 12px 0 0 hsl(200, 70%, 50%), inset 16px 0 0 hsl(280, 70%, 50%)",
|
|
1895
|
+
backgroundColor: "hsla(280, 70%, 50%, 0.05)",
|
|
1896
|
+
paddingLeft: "24px !important"
|
|
1897
|
+
},
|
|
1898
|
+
".cm-admonition-depth-5": {
|
|
1899
|
+
boxShadow: "inset 4px 0 0 hsl(340, 70%, 50%), inset 8px 0 0 hsl(140, 70%, 50%), inset 12px 0 0 hsl(200, 70%, 50%), inset 16px 0 0 hsl(280, 70%, 50%), inset 20px 0 0 hsl(340, 70%, 50%)",
|
|
1900
|
+
backgroundColor: "hsla(340, 70%, 50%, 0.05)",
|
|
1901
|
+
paddingLeft: "28px !important"
|
|
1902
|
+
},
|
|
1903
|
+
".cm-panels": {
|
|
1904
|
+
position: "static !important",
|
|
1905
|
+
backgroundColor: "transparent !important",
|
|
1906
|
+
border: "none !important"
|
|
1907
|
+
},
|
|
1908
|
+
".cm-panel.cm-search": {
|
|
1909
|
+
position: "fixed !important",
|
|
1910
|
+
top: "20px !important",
|
|
1911
|
+
right: "20px !important",
|
|
1912
|
+
zIndex: 100,
|
|
1913
|
+
backgroundColor: "var(--color-background-primary, #0f172a)",
|
|
1914
|
+
border: "1px solid var(--color-border, #334155)",
|
|
1915
|
+
borderRadius: "12px",
|
|
1916
|
+
padding: "12px",
|
|
1917
|
+
boxShadow: "0 10px 25px -5px rgba(0, 0, 0, 0.3), 0 8px 10px -6px rgba(0, 0, 0, 0.3)",
|
|
1918
|
+
display: "flex",
|
|
1919
|
+
flexDirection: "column",
|
|
1920
|
+
gap: "8px",
|
|
1921
|
+
backdropFilter: "blur(8px)",
|
|
1922
|
+
minWidth: "280px"
|
|
1923
|
+
},
|
|
1924
|
+
".cm-search [name=close]": {
|
|
1925
|
+
position: "absolute",
|
|
1926
|
+
right: "8px",
|
|
1927
|
+
top: "8px",
|
|
1928
|
+
cursor: "pointer",
|
|
1929
|
+
opacity: 0.6,
|
|
1930
|
+
border: "none",
|
|
1931
|
+
background: "transparent",
|
|
1932
|
+
color: "var(--color-text-primary, #e2e8f0)",
|
|
1933
|
+
fontSize: "18px"
|
|
1934
|
+
},
|
|
1935
|
+
".cm-search [name=close]:hover": { opacity: 1 },
|
|
1936
|
+
".cm-textfield": {
|
|
1937
|
+
backgroundColor: "rgba(255, 255, 255, 0.05)",
|
|
1938
|
+
border: "1px solid var(--color-border, #334155)",
|
|
1939
|
+
borderRadius: "6px",
|
|
1940
|
+
color: "var(--color-text-primary, #e2e8f0)",
|
|
1941
|
+
padding: "4px 8px",
|
|
1942
|
+
outline: "none",
|
|
1943
|
+
width: "100%",
|
|
1944
|
+
marginBottom: "4px"
|
|
1945
|
+
},
|
|
1946
|
+
".cm-textfield:focus": {
|
|
1947
|
+
borderColor: "var(--color-accent-primary, #38bdf8)",
|
|
1948
|
+
backgroundColor: "rgba(255, 255, 255, 0.08)"
|
|
1949
|
+
},
|
|
1950
|
+
".cm-panel.cm-search input[type=checkbox]:checked": {
|
|
1951
|
+
backgroundColor: "var(--color-accent-primary, #38bdf8)"
|
|
1952
|
+
},
|
|
1953
|
+
".cm-panel.cm-search input[type=checkbox]": {
|
|
1954
|
+
backgroundColor: "rgba(255, 255, 255, 0.08)"
|
|
1955
|
+
},
|
|
1956
|
+
".cm-button": {
|
|
1957
|
+
backgroundImage: "linear-gradient(135deg, var(--color-accent-primary, #38bdf8), var(--color-accent-hover, #7dd3fc))",
|
|
1958
|
+
color: "var(--color-accent-text, #0f172a)",
|
|
1959
|
+
border: "none",
|
|
1960
|
+
borderRadius: "6px",
|
|
1961
|
+
padding: "4px 10px",
|
|
1962
|
+
cursor: "pointer",
|
|
1963
|
+
fontSize: "0.85em",
|
|
1964
|
+
fontWeight: "600",
|
|
1965
|
+
textTransform: "uppercase",
|
|
1966
|
+
letterSpacing: "0.05em",
|
|
1967
|
+
transition: "transform 0.1s, opacity 0.2s",
|
|
1968
|
+
marginRight: "4px",
|
|
1969
|
+
boxShadow: "0 4px 12px -2px rgba(0, 0, 0, 0.2)"
|
|
1970
|
+
},
|
|
1971
|
+
".cm-button:hover": {
|
|
1972
|
+
opacity: 0.95,
|
|
1973
|
+
transform: "translateY(-1px)",
|
|
1974
|
+
boxShadow: "0 6px 14px -2px rgba(0, 0, 0, 0.25)"
|
|
1975
|
+
},
|
|
1976
|
+
".cm-button:active": { transform: "translateY(0)" },
|
|
1977
|
+
".cm-search label": {
|
|
1978
|
+
display: "inline-flex",
|
|
1979
|
+
alignItems: "center",
|
|
1980
|
+
gap: "4px",
|
|
1981
|
+
fontSize: "0.8em",
|
|
1982
|
+
color: "var(--color-text-secondary, #94a3b8)",
|
|
1983
|
+
marginRight: "8px",
|
|
1984
|
+
cursor: "pointer"
|
|
1985
|
+
},
|
|
1986
|
+
".cm-search input[type=checkbox]": {
|
|
1987
|
+
cursor: "pointer",
|
|
1988
|
+
accentColor: "var(--color-accent-primary, #38bdf8)"
|
|
1989
|
+
}
|
|
1990
|
+
});
|
|
1991
|
+
var customFoldService = foldService.of((state, lineStart) => {
|
|
1992
|
+
const line = state.doc.lineAt(lineStart);
|
|
1993
|
+
const trimmed = line.text.trim();
|
|
1994
|
+
const dirMatch = trimmed.match(/^:::(.+)/);
|
|
1995
|
+
if (dirMatch) {
|
|
1996
|
+
let stack = 1;
|
|
1997
|
+
for (let i = line.number + 1; i <= state.doc.lines; i++) {
|
|
1998
|
+
const nextLine = state.doc.line(i);
|
|
1999
|
+
const nextText = nextLine.text.trim();
|
|
2000
|
+
if (nextText.match(/^:::(.+)/)) {
|
|
2001
|
+
stack++;
|
|
2002
|
+
} else if (nextText === ":::") {
|
|
2003
|
+
stack--;
|
|
2004
|
+
if (stack === 0) {
|
|
2005
|
+
return { from: line.to, to: nextLine.to };
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
return null;
|
|
2010
|
+
}
|
|
2011
|
+
const htmlMatch = trimmed.match(/^<([a-zA-Z][\w-]*)\b/);
|
|
2012
|
+
if (htmlMatch) {
|
|
2013
|
+
const tagName = htmlMatch[1].toLowerCase();
|
|
2014
|
+
const voidElements = /* @__PURE__ */ new Set([
|
|
2015
|
+
"area",
|
|
2016
|
+
"base",
|
|
2017
|
+
"br",
|
|
2018
|
+
"col",
|
|
2019
|
+
"embed",
|
|
2020
|
+
"hr",
|
|
2021
|
+
"img",
|
|
2022
|
+
"input",
|
|
2023
|
+
"link",
|
|
2024
|
+
"meta",
|
|
2025
|
+
"param",
|
|
2026
|
+
"source",
|
|
2027
|
+
"track",
|
|
2028
|
+
"wbr"
|
|
2029
|
+
]);
|
|
2030
|
+
if (voidElements.has(tagName) || trimmed.endsWith("/>")) return null;
|
|
2031
|
+
let stack = 1;
|
|
2032
|
+
for (let i = line.number + 1; i <= state.doc.lines; i++) {
|
|
2033
|
+
const nextLine = state.doc.line(i);
|
|
2034
|
+
const nextText = nextLine.text;
|
|
2035
|
+
let match;
|
|
2036
|
+
const tagRegex = new RegExp(`</?${tagName}\\b[^>]*>`, "gi");
|
|
2037
|
+
while ((match = tagRegex.exec(nextText)) !== null) {
|
|
2038
|
+
if (match[0].startsWith("</")) {
|
|
2039
|
+
stack--;
|
|
2040
|
+
if (stack === 0) {
|
|
2041
|
+
return { from: line.to, to: nextLine.to };
|
|
2042
|
+
}
|
|
2043
|
+
} else {
|
|
2044
|
+
if (!match[0].endsWith("/>")) {
|
|
2045
|
+
stack++;
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
return null;
|
|
2051
|
+
}
|
|
2052
|
+
return null;
|
|
2053
|
+
});
|
|
2054
|
+
var directivePlugin = ViewPlugin.fromClass(
|
|
2055
|
+
class {
|
|
2056
|
+
constructor(view) {
|
|
2057
|
+
this.decorations = this.getDecorations(view);
|
|
2058
|
+
}
|
|
2059
|
+
update(update) {
|
|
2060
|
+
if (update.docChanged || update.viewportChanged) {
|
|
2061
|
+
this.decorations = this.getDecorations(update.view);
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
getDecorations(view) {
|
|
2065
|
+
const builder = new RangeSetBuilder();
|
|
2066
|
+
const doc = view.state.doc;
|
|
2067
|
+
const visibleRanges = view.visibleRanges;
|
|
2068
|
+
if (visibleRanges.length === 0) return builder.finish();
|
|
2069
|
+
const maxTo = visibleRanges[visibleRanges.length - 1].to;
|
|
2070
|
+
const admonitionStack = [];
|
|
2071
|
+
for (let i = 1; i <= doc.lines; i++) {
|
|
2072
|
+
const line = doc.line(i);
|
|
2073
|
+
if (line.from > maxTo) break;
|
|
2074
|
+
const trimmedLine = line.text.trim();
|
|
2075
|
+
let isClosingLine = false;
|
|
2076
|
+
let closingTargetIdx = -1;
|
|
2077
|
+
const match = trimmedLine.match(/^:::(.*)/);
|
|
2078
|
+
if (match) {
|
|
2079
|
+
const rest = match[1].trim();
|
|
2080
|
+
if (rest === "") {
|
|
2081
|
+
if (admonitionStack.length > 0) {
|
|
2082
|
+
isClosingLine = true;
|
|
2083
|
+
closingTargetIdx = admonitionStack.length - 1;
|
|
2084
|
+
}
|
|
2085
|
+
} else {
|
|
2086
|
+
const typeMatch = rest.match(/^(\w+|\{)/);
|
|
2087
|
+
const type = typeMatch && typeMatch[1] !== "{" ? typeMatch[1].toLowerCase() : "generic";
|
|
2088
|
+
admonitionStack.push(type);
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
const isVisible = visibleRanges.some(
|
|
2092
|
+
(r) => line.to >= r.from && line.from <= r.to
|
|
2093
|
+
);
|
|
2094
|
+
if (isVisible && admonitionStack.length > 0) {
|
|
2095
|
+
const targetIdx = isClosingLine ? closingTargetIdx : admonitionStack.length - 1;
|
|
2096
|
+
const currentType = admonitionStack[targetIdx];
|
|
2097
|
+
const depth = targetIdx + 1;
|
|
2098
|
+
const lineClasses = ["cm-admonition-bg"];
|
|
2099
|
+
if (currentType === "raw") {
|
|
2100
|
+
lineClasses.push("cm-raw-block");
|
|
2101
|
+
lineClasses.push(`cm-admonition-depth-${Math.min(depth, 5)}`);
|
|
2102
|
+
} else {
|
|
2103
|
+
lineClasses.push(`cm-admonition-${currentType}`);
|
|
2104
|
+
lineClasses.push(`cm-admonition-depth-${Math.min(depth, 5)}`);
|
|
2105
|
+
}
|
|
2106
|
+
builder.add(
|
|
2107
|
+
line.from,
|
|
2108
|
+
line.from,
|
|
2109
|
+
Decoration.line({ class: lineClasses.join(" ") })
|
|
2110
|
+
);
|
|
2111
|
+
}
|
|
2112
|
+
if (isClosingLine) {
|
|
2113
|
+
admonitionStack.pop();
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
return builder.finish();
|
|
2117
|
+
}
|
|
2118
|
+
},
|
|
2119
|
+
{ decorations: (v) => v.decorations }
|
|
2120
|
+
);
|
|
2121
|
+
var blockquotePlugin = ViewPlugin.fromClass(
|
|
2122
|
+
class {
|
|
2123
|
+
constructor(view) {
|
|
2124
|
+
this.decorations = this.getDecorations(view);
|
|
2125
|
+
}
|
|
2126
|
+
update(update) {
|
|
2127
|
+
if (update.docChanged || update.viewportChanged) {
|
|
2128
|
+
this.decorations = this.getDecorations(update.view);
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
getDecorations(view) {
|
|
2132
|
+
const builder = new RangeSetBuilder();
|
|
2133
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2134
|
+
for (let pos = from; pos <= to; ) {
|
|
2135
|
+
const line = view.state.doc.lineAt(pos);
|
|
2136
|
+
if (line.text.trim().startsWith(">")) {
|
|
2137
|
+
builder.add(
|
|
2138
|
+
line.from,
|
|
2139
|
+
line.from,
|
|
2140
|
+
Decoration.line({ class: "cm-blockquote-line" })
|
|
2141
|
+
);
|
|
2142
|
+
}
|
|
2143
|
+
pos = line.to + 1;
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
return builder.finish();
|
|
2147
|
+
}
|
|
2148
|
+
},
|
|
2149
|
+
{ decorations: (v) => v.decorations }
|
|
2150
|
+
);
|
|
2151
|
+
var spoilerPlugin = ViewPlugin.fromClass(
|
|
2152
|
+
class {
|
|
2153
|
+
constructor(view) {
|
|
2154
|
+
this.decorations = this.getDecorations(view);
|
|
2155
|
+
}
|
|
2156
|
+
update(update) {
|
|
2157
|
+
if (update.docChanged || update.viewportChanged) {
|
|
2158
|
+
this.decorations = this.getDecorations(update.view);
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
getDecorations(view) {
|
|
2162
|
+
const builder = new RangeSetBuilder();
|
|
2163
|
+
const spoilerRegex = /!>([\s\S]+?)<!(?=\s|$)/g;
|
|
2164
|
+
const ranges = [];
|
|
2165
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2166
|
+
const text = view.state.doc.sliceString(from, to);
|
|
2167
|
+
spoilerRegex.lastIndex = 0;
|
|
2168
|
+
let match;
|
|
2169
|
+
while (match = spoilerRegex.exec(text)) {
|
|
2170
|
+
const start = from + match.index;
|
|
2171
|
+
const end = start + match[0].length;
|
|
2172
|
+
const contentStart = start + 2;
|
|
2173
|
+
const contentEnd = end - 2;
|
|
2174
|
+
if (contentStart >= contentEnd) continue;
|
|
2175
|
+
ranges.push({ from: start, to: contentStart, dec: Decoration.replace({}) });
|
|
2176
|
+
ranges.push({
|
|
2177
|
+
from: contentStart,
|
|
2178
|
+
to: contentEnd,
|
|
2179
|
+
dec: Decoration.mark({ class: "cm-spoiler" })
|
|
2180
|
+
});
|
|
2181
|
+
ranges.push({ from: contentEnd, to: end, dec: Decoration.replace({}) });
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
ranges.sort((a, b) => a.from - b.from || a.to - b.to);
|
|
2185
|
+
for (const { from, to, dec } of ranges) builder.add(from, to, dec);
|
|
2186
|
+
return builder.finish();
|
|
2187
|
+
}
|
|
2188
|
+
},
|
|
2189
|
+
{ decorations: (v) => v.decorations }
|
|
2190
|
+
);
|
|
2191
|
+
var colorTextPlugin = ViewPlugin.fromClass(
|
|
2192
|
+
class {
|
|
2193
|
+
constructor(view) {
|
|
2194
|
+
this.decorations = this.getDecorations(view);
|
|
2195
|
+
}
|
|
2196
|
+
update(update) {
|
|
2197
|
+
if (update.docChanged || update.viewportChanged) {
|
|
2198
|
+
this.decorations = this.getDecorations(update.view);
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
getDecorations(view) {
|
|
2202
|
+
const builder = new RangeSetBuilder();
|
|
2203
|
+
const colorRegex = /%([^%\s]+?)%((?:(?!%%).)*)%%/g;
|
|
2204
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2205
|
+
const text = view.state.doc.sliceString(from, to);
|
|
2206
|
+
let match;
|
|
2207
|
+
while (match = colorRegex.exec(text)) {
|
|
2208
|
+
const color = match[1];
|
|
2209
|
+
const startPos = from + match.index;
|
|
2210
|
+
const endPos = startPos + match[0].length;
|
|
2211
|
+
builder.add(
|
|
2212
|
+
startPos,
|
|
2213
|
+
endPos,
|
|
2214
|
+
Decoration.mark({ attributes: { style: `color: ${color}` } })
|
|
2215
|
+
);
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
return builder.finish();
|
|
2219
|
+
}
|
|
2220
|
+
},
|
|
2221
|
+
{ decorations: (v) => v.decorations }
|
|
2222
|
+
);
|
|
2223
|
+
var NReditor = ({
|
|
2224
|
+
value,
|
|
2225
|
+
onChange,
|
|
2226
|
+
className,
|
|
2227
|
+
debounceMs = 300,
|
|
2228
|
+
tailwindCDN = false
|
|
2229
|
+
}) => {
|
|
2230
|
+
const editorRef = useRef6(null);
|
|
2231
|
+
const [isAllFolded, setIsAllFolded] = useState5(false);
|
|
2232
|
+
const [editorMode, setEditorMode] = useState5("editor");
|
|
2233
|
+
const debouncedContent = useDebounce(value, debounceMs);
|
|
2234
|
+
const handleToggleFold = () => {
|
|
2235
|
+
if (!editorRef.current) return;
|
|
2236
|
+
if (isAllFolded) {
|
|
2237
|
+
unfoldAll(editorRef.current);
|
|
2238
|
+
setIsAllFolded(false);
|
|
2239
|
+
} else {
|
|
2240
|
+
foldAll(editorRef.current);
|
|
2241
|
+
setIsAllFolded(true);
|
|
2242
|
+
}
|
|
2243
|
+
};
|
|
2244
|
+
const extensions = React9.useMemo(
|
|
2245
|
+
() => [
|
|
2246
|
+
customStreamParserV2,
|
|
2247
|
+
lineNumbers(),
|
|
2248
|
+
foldGutter({
|
|
2249
|
+
markerDOM: (open) => {
|
|
2250
|
+
const span = document.createElement("span");
|
|
2251
|
+
span.style.cursor = "pointer";
|
|
2252
|
+
span.style.padding = "0 4px";
|
|
2253
|
+
span.style.fontSize = "12px";
|
|
2254
|
+
span.style.display = "inline-block";
|
|
2255
|
+
span.style.transition = "transform 0.2s";
|
|
2256
|
+
span.textContent = open ? "\u25BC" : "\u25B6";
|
|
2257
|
+
return span;
|
|
2258
|
+
}
|
|
2259
|
+
}),
|
|
2260
|
+
customFoldService,
|
|
2261
|
+
customEditorTheme,
|
|
2262
|
+
syntaxHighlighting(customSyntaxHighlighting),
|
|
2263
|
+
EditorView.lineWrapping,
|
|
2264
|
+
scrollPastEnd(),
|
|
2265
|
+
keymap.of([
|
|
2266
|
+
{ key: "Ctrl-Shift-[", run: foldAll },
|
|
2267
|
+
{ key: "Ctrl-Shift-]", run: unfoldAll }
|
|
2268
|
+
]),
|
|
2269
|
+
directivePlugin,
|
|
2270
|
+
blockquotePlugin,
|
|
2271
|
+
spoilerPlugin,
|
|
2272
|
+
colorTextPlugin
|
|
2273
|
+
],
|
|
2274
|
+
[]
|
|
2275
|
+
);
|
|
2276
|
+
const modeButtons = [
|
|
2277
|
+
{ key: "editor", icon: "code", label: "Editor" },
|
|
2278
|
+
{ key: "split", icon: "vertical_split", label: "Split" },
|
|
2279
|
+
{ key: "preview", icon: "visibility", label: "Preview" }
|
|
2280
|
+
];
|
|
2281
|
+
return /* @__PURE__ */ jsxs8("div", { className: `relative flex-1 flex flex-col min-h-0 ${className || ""}`, children: [
|
|
2282
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between px-2 py-1.5 border-b border-border/30 bg-background-secondary-solid/50 rounded-t-2xl shrink-0", children: [
|
|
2283
|
+
/* @__PURE__ */ jsx13(
|
|
2284
|
+
"button",
|
|
2285
|
+
{
|
|
2286
|
+
onClick: handleToggleFold,
|
|
2287
|
+
className: "p-1 px-2 text-xs font-bold bg-background-secondary-solid border border-border rounded hover:bg-border text-accent-primary transition-colors",
|
|
2288
|
+
title: isAllFolded ? "Expand all" : "Collapse all",
|
|
2289
|
+
children: isAllFolded ? "\u2569" : "\u2566"
|
|
2290
|
+
}
|
|
2291
|
+
),
|
|
2292
|
+
/* @__PURE__ */ jsx13("div", { className: "flex items-center gap-0.5 bg-black/10 dark:bg-white/5 rounded-lg p-0.5", children: modeButtons.map((btn) => /* @__PURE__ */ jsxs8(
|
|
2293
|
+
"button",
|
|
2294
|
+
{
|
|
2295
|
+
onClick: () => setEditorMode(btn.key),
|
|
2296
|
+
className: `flex items-center gap-1 px-2.5 py-1 text-xs rounded-md transition-colors ${editorMode === btn.key ? "bg-accent-primary/20 text-accent-primary font-semibold" : "text-text-secondary hover:text-text-primary hover:bg-white/5"}`,
|
|
2297
|
+
title: btn.label,
|
|
2298
|
+
children: [
|
|
2299
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-rounded text-sm", children: btn.icon }),
|
|
2300
|
+
/* @__PURE__ */ jsx13("span", { className: "hidden sm:inline", children: btn.label })
|
|
2301
|
+
]
|
|
2302
|
+
},
|
|
2303
|
+
btn.key
|
|
2304
|
+
)) })
|
|
2305
|
+
] }),
|
|
2306
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex-1 min-h-0 flex", children: [
|
|
2307
|
+
(editorMode === "editor" || editorMode === "split") && /* @__PURE__ */ jsx13(
|
|
2308
|
+
"div",
|
|
2309
|
+
{
|
|
2310
|
+
className: `${editorMode === "split" ? "w-1/2 border-r border-border/30" : "w-full"} flex-1 flex flex-col min-h-0 min-w-0`,
|
|
2311
|
+
children: /* @__PURE__ */ jsx13(
|
|
2312
|
+
CodeMirror,
|
|
2313
|
+
{
|
|
2314
|
+
value,
|
|
2315
|
+
onChange,
|
|
2316
|
+
className: "flex-1 min-h-0 min-w-0",
|
|
2317
|
+
height: "100%",
|
|
2318
|
+
onCreateEditor: (view) => {
|
|
2319
|
+
editorRef.current = view;
|
|
2320
|
+
},
|
|
2321
|
+
basicSetup: {
|
|
2322
|
+
lineNumbers: false,
|
|
2323
|
+
foldGutter: false
|
|
2324
|
+
},
|
|
2325
|
+
extensions
|
|
2326
|
+
}
|
|
2327
|
+
)
|
|
2328
|
+
}
|
|
2329
|
+
),
|
|
2330
|
+
(editorMode === "preview" || editorMode === "split") && /* @__PURE__ */ jsx13(
|
|
2331
|
+
"div",
|
|
2332
|
+
{
|
|
2333
|
+
className: `${editorMode === "split" ? "w-1/2" : "w-full"} flex-1 min-h-0 overflow-auto min-w-0`,
|
|
2334
|
+
children: /* @__PURE__ */ jsx13("div", { className: "nr-prose h-full shadow-xs overflow-auto p-4", children: /* @__PURE__ */ jsx13(CustomMarkdownRenderer_default, { content: debouncedContent }) })
|
|
2335
|
+
}
|
|
2336
|
+
)
|
|
2337
|
+
] })
|
|
2338
|
+
] });
|
|
2339
|
+
};
|
|
2340
|
+
var NReditor_default = NReditor;
|
|
2341
|
+
export {
|
|
2342
|
+
NReditor_default as default
|
|
2343
|
+
};
|
|
2344
|
+
//# sourceMappingURL=NReditor.mjs.map
|