@elixpo/lixeditor 2.5.1 → 2.5.2
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/index.cjs +912 -886
- package/dist/index.cjs.map +2 -2
- package/dist/index.js +905 -883
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { useCallback as useCallback7, useMemo, forwardRef, useImperativeHandle,
|
|
|
8
8
|
|
|
9
9
|
// src/hooks/useLixTheme.js
|
|
10
10
|
import { createContext, useContext, useState, useEffect } from "react";
|
|
11
|
-
|
|
11
|
+
import { jsx } from "react/jsx-runtime";
|
|
12
12
|
var LixThemeContext = createContext(null);
|
|
13
13
|
function LixThemeProvider({ children, defaultTheme = "light", storageKey = "lixeditor_theme" }) {
|
|
14
14
|
const [theme, setTheme] = useState(defaultTheme);
|
|
@@ -16,26 +16,22 @@ function LixThemeProvider({ children, defaultTheme = "light", storageKey = "lixe
|
|
|
16
16
|
useEffect(() => {
|
|
17
17
|
if (storageKey) {
|
|
18
18
|
const saved = localStorage.getItem(storageKey);
|
|
19
|
-
if (saved === "dark" || saved === "light")
|
|
20
|
-
setTheme(saved);
|
|
19
|
+
if (saved === "dark" || saved === "light") setTheme(saved);
|
|
21
20
|
}
|
|
22
21
|
setMounted(true);
|
|
23
22
|
}, [storageKey]);
|
|
24
23
|
useEffect(() => {
|
|
25
|
-
if (!mounted)
|
|
26
|
-
return;
|
|
24
|
+
if (!mounted) return;
|
|
27
25
|
document.documentElement.setAttribute("data-theme", theme);
|
|
28
|
-
if (storageKey)
|
|
29
|
-
localStorage.setItem(storageKey, theme);
|
|
26
|
+
if (storageKey) localStorage.setItem(storageKey, theme);
|
|
30
27
|
}, [theme, mounted, storageKey]);
|
|
31
28
|
const toggleTheme = () => setTheme((t) => t === "dark" ? "light" : "dark");
|
|
32
29
|
const isDark = theme === "dark";
|
|
33
|
-
return
|
|
30
|
+
return /* @__PURE__ */ jsx(LixThemeContext.Provider, { value: { theme, setTheme, toggleTheme, isDark, mounted }, children });
|
|
34
31
|
}
|
|
35
32
|
function useLixTheme() {
|
|
36
33
|
const ctx = useContext(LixThemeContext);
|
|
37
|
-
if (ctx)
|
|
38
|
-
return ctx;
|
|
34
|
+
if (ctx) return ctx;
|
|
39
35
|
const isDark = typeof document !== "undefined" && document.documentElement.getAttribute("data-theme") === "dark";
|
|
40
36
|
return { theme: isDark ? "dark" : "light", isDark, toggleTheme: () => {
|
|
41
37
|
}, setTheme: () => {
|
|
@@ -46,17 +42,13 @@ function useLixTheme() {
|
|
|
46
42
|
import { createReactBlockSpec } from "@blocknote/react";
|
|
47
43
|
import { useState as useState2, useEffect as useEffect2, useRef, useCallback } from "react";
|
|
48
44
|
import katex from "katex";
|
|
49
|
-
|
|
45
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
50
46
|
function stripDelimiters(raw) {
|
|
51
47
|
let s = raw.trim();
|
|
52
|
-
if (s.startsWith("\\[") && s.endsWith("\\]"))
|
|
53
|
-
|
|
54
|
-
if (s.startsWith("
|
|
55
|
-
|
|
56
|
-
if (s.startsWith("\\(") && s.endsWith("\\)"))
|
|
57
|
-
return s.slice(2, -2).trim();
|
|
58
|
-
if (s.startsWith("$") && s.endsWith("$") && s.length > 2)
|
|
59
|
-
return s.slice(1, -1).trim();
|
|
48
|
+
if (s.startsWith("\\[") && s.endsWith("\\]")) return s.slice(2, -2).trim();
|
|
49
|
+
if (s.startsWith("$$") && s.endsWith("$$")) return s.slice(2, -2).trim();
|
|
50
|
+
if (s.startsWith("\\(") && s.endsWith("\\)")) return s.slice(2, -2).trim();
|
|
51
|
+
if (s.startsWith("$") && s.endsWith("$") && s.length > 2) return s.slice(1, -1).trim();
|
|
60
52
|
return s;
|
|
61
53
|
}
|
|
62
54
|
function renderKaTeX(latex, displayMode = true) {
|
|
@@ -82,8 +74,7 @@ var BlockEquation = createReactBlockSpec(
|
|
|
82
74
|
const inputRef = useRef(null);
|
|
83
75
|
const debounceRef = useRef(null);
|
|
84
76
|
useEffect2(() => {
|
|
85
|
-
if (editing)
|
|
86
|
-
inputRef.current?.focus();
|
|
77
|
+
if (editing) inputRef.current?.focus();
|
|
87
78
|
}, [editing]);
|
|
88
79
|
const handleCodeChange = useCallback((e) => {
|
|
89
80
|
const v = e.target.value;
|
|
@@ -99,60 +90,70 @@ var BlockEquation = createReactBlockSpec(
|
|
|
99
90
|
setEditing(false);
|
|
100
91
|
};
|
|
101
92
|
if (editing) {
|
|
102
|
-
return
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
93
|
+
return /* @__PURE__ */ jsxs("div", { className: "mermaid-block mermaid-block--editing", children: [
|
|
94
|
+
/* @__PURE__ */ jsxs("div", { className: "mermaid-block-header", children: [
|
|
95
|
+
/* @__PURE__ */ jsx2("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "#c4b5fd", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx2("path", { d: "M4 4h6v6H4zM14 4h6v6h-6zM4 14h6v6H4zM14 14h6v6h-6z" }) }),
|
|
96
|
+
/* @__PURE__ */ jsx2("span", { children: "LaTeX Equation" }),
|
|
97
|
+
/* @__PURE__ */ jsx2("span", { style: { marginLeft: "auto", fontSize: "10px", color: "var(--text-faint)" }, children: "Shift+Enter to save" })
|
|
98
|
+
] }),
|
|
99
|
+
/* @__PURE__ */ jsx2(
|
|
100
|
+
"textarea",
|
|
101
|
+
{
|
|
102
|
+
ref: inputRef,
|
|
103
|
+
value,
|
|
104
|
+
onChange: handleCodeChange,
|
|
105
|
+
onKeyDown: (e) => {
|
|
106
|
+
if (e.key === "Enter" && e.shiftKey) {
|
|
107
|
+
e.preventDefault();
|
|
108
|
+
save();
|
|
109
|
+
}
|
|
110
|
+
if (e.key === "Escape") {
|
|
111
|
+
setEditing(false);
|
|
112
|
+
setValue(block.props.latex || "");
|
|
113
|
+
setLivePreview(block.props.latex || "");
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
placeholder: "E = mc^2",
|
|
117
|
+
rows: 4,
|
|
118
|
+
className: "mermaid-block-textarea"
|
|
119
|
+
}
|
|
120
|
+
),
|
|
121
|
+
livePreview.trim() && /* @__PURE__ */ jsxs("div", { className: "latex-live-preview", children: [
|
|
122
|
+
/* @__PURE__ */ jsx2("div", { className: "latex-live-preview-label", children: "Preview" }),
|
|
123
|
+
/* @__PURE__ */ jsx2("div", { dangerouslySetInnerHTML: { __html: renderKaTeX(livePreview) } })
|
|
124
|
+
] }),
|
|
125
|
+
/* @__PURE__ */ jsxs("div", { className: "mermaid-block-actions", children: [
|
|
126
|
+
/* @__PURE__ */ jsx2("button", { onClick: () => {
|
|
133
127
|
setEditing(false);
|
|
134
128
|
setValue(block.props.latex || "");
|
|
135
129
|
setLivePreview(block.props.latex || "");
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
130
|
+
}, className: "mermaid-btn-cancel", children: "Cancel" }),
|
|
131
|
+
/* @__PURE__ */ jsx2("button", { onClick: save, className: "mermaid-btn-save", disabled: !value.trim(), children: "Done" })
|
|
132
|
+
] })
|
|
133
|
+
] });
|
|
140
134
|
}
|
|
141
135
|
const latex = block.props.latex;
|
|
142
136
|
if (!latex) {
|
|
143
|
-
return
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
137
|
+
return /* @__PURE__ */ jsxs(
|
|
138
|
+
"div",
|
|
139
|
+
{
|
|
140
|
+
onClick: () => setEditing(true),
|
|
141
|
+
className: "mermaid-block mermaid-block--empty",
|
|
142
|
+
children: [
|
|
143
|
+
/* @__PURE__ */ jsx2("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx2("path", { d: "M4 4h6v6H4zM14 4h6v6h-6zM4 14h6v6H4zM14 14h6v6h-6z" }) }),
|
|
144
|
+
/* @__PURE__ */ jsx2("span", { children: "Click to add a block equation" })
|
|
145
|
+
]
|
|
146
|
+
}
|
|
147
|
+
);
|
|
150
148
|
}
|
|
151
|
-
return
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
149
|
+
return /* @__PURE__ */ jsx2(
|
|
150
|
+
"div",
|
|
151
|
+
{
|
|
152
|
+
onClick: () => setEditing(true),
|
|
153
|
+
className: "editor-block-equation",
|
|
154
|
+
dangerouslySetInnerHTML: { __html: renderKaTeX(latex) }
|
|
155
|
+
}
|
|
156
|
+
);
|
|
156
157
|
}
|
|
157
158
|
}
|
|
158
159
|
);
|
|
@@ -160,7 +161,7 @@ var BlockEquation = createReactBlockSpec(
|
|
|
160
161
|
// src/blocks/MermaidBlock.jsx
|
|
161
162
|
import { createReactBlockSpec as createReactBlockSpec2 } from "@blocknote/react";
|
|
162
163
|
import { useState as useState3, useEffect as useEffect3, useRef as useRef2, useCallback as useCallback2 } from "react";
|
|
163
|
-
|
|
164
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
164
165
|
var darkConfig = {
|
|
165
166
|
startOnLoad: false,
|
|
166
167
|
securityLevel: "loose",
|
|
@@ -275,12 +276,10 @@ function MermaidPreview({ diagram, isDark, interactive }) {
|
|
|
275
276
|
let cancelled = false;
|
|
276
277
|
const id = `mermaid-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
|
|
277
278
|
queueRender(async () => {
|
|
278
|
-
if (cancelled)
|
|
279
|
-
return;
|
|
279
|
+
if (cancelled) return;
|
|
280
280
|
try {
|
|
281
281
|
const mermaid = await getMermaid(isDark);
|
|
282
|
-
if (cancelled)
|
|
283
|
-
return;
|
|
282
|
+
if (cancelled) return;
|
|
284
283
|
let diagramText = diagram.trim();
|
|
285
284
|
diagramText = diagramText.replace(/^\s*gitgraph/i, "gitGraph");
|
|
286
285
|
diagramText = diagramText.replace(/^\s*sequencediagram/i, "sequenceDiagram");
|
|
@@ -327,11 +326,9 @@ function MermaidPreview({ diagram, isDark, interactive }) {
|
|
|
327
326
|
};
|
|
328
327
|
}, [diagram, isDark]);
|
|
329
328
|
useEffect3(() => {
|
|
330
|
-
if (!interactive)
|
|
331
|
-
return;
|
|
329
|
+
if (!interactive) return;
|
|
332
330
|
const el = containerRef.current;
|
|
333
|
-
if (!el)
|
|
334
|
-
return;
|
|
331
|
+
if (!el) return;
|
|
335
332
|
const handleWheel = (e) => {
|
|
336
333
|
e.preventDefault();
|
|
337
334
|
e.stopPropagation();
|
|
@@ -344,16 +341,14 @@ function MermaidPreview({ diagram, isDark, interactive }) {
|
|
|
344
341
|
return () => el.removeEventListener("wheel", handleWheel);
|
|
345
342
|
}, [svgHTML, interactive]);
|
|
346
343
|
const handleMouseDown = useCallback2((e) => {
|
|
347
|
-
if (!interactive || e.button !== 0)
|
|
348
|
-
return;
|
|
344
|
+
if (!interactive || e.button !== 0) return;
|
|
349
345
|
e.preventDefault();
|
|
350
346
|
dragging.current = true;
|
|
351
347
|
dragStart.current = { x: e.clientX, y: e.clientY };
|
|
352
348
|
panStart.current = { ...pan };
|
|
353
349
|
}, [pan, interactive]);
|
|
354
350
|
const handleMouseMove = useCallback2((e) => {
|
|
355
|
-
if (!dragging.current)
|
|
356
|
-
return;
|
|
351
|
+
if (!dragging.current) return;
|
|
357
352
|
const dx = e.clientX - dragStart.current.x;
|
|
358
353
|
const dy = e.clientY - dragStart.current.y;
|
|
359
354
|
setPan({ x: panStart.current.x + dx, y: panStart.current.y + dy });
|
|
@@ -362,8 +357,7 @@ function MermaidPreview({ diagram, isDark, interactive }) {
|
|
|
362
357
|
dragging.current = false;
|
|
363
358
|
}, []);
|
|
364
359
|
useEffect3(() => {
|
|
365
|
-
if (!interactive)
|
|
366
|
-
return;
|
|
360
|
+
if (!interactive) return;
|
|
367
361
|
window.addEventListener("mousemove", handleMouseMove);
|
|
368
362
|
window.addEventListener("mouseup", handleMouseUp);
|
|
369
363
|
return () => {
|
|
@@ -376,64 +370,83 @@ function MermaidPreview({ diagram, isDark, interactive }) {
|
|
|
376
370
|
setPan({ x: 0, y: 0 });
|
|
377
371
|
}, []);
|
|
378
372
|
if (error) {
|
|
379
|
-
return
|
|
373
|
+
return /* @__PURE__ */ jsx3("div", { className: "mermaid-viewport mermaid-viewport--compact", children: /* @__PURE__ */ jsx3("pre", { style: { color: "#f87171", fontSize: "12px", whiteSpace: "pre-wrap", padding: "16px", margin: 0 }, children: error }) });
|
|
380
374
|
}
|
|
381
375
|
if (!diagram?.trim()) {
|
|
382
|
-
return
|
|
376
|
+
return /* @__PURE__ */ jsx3("div", { className: "mermaid-viewport mermaid-viewport--compact", style: { display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx3("span", { style: { color: "var(--text-faint)", fontSize: "12px" }, children: "Preview will appear here..." }) });
|
|
383
377
|
}
|
|
384
378
|
if (!svgHTML) {
|
|
385
|
-
return
|
|
379
|
+
return /* @__PURE__ */ jsx3("div", { className: "mermaid-viewport mermaid-viewport--compact", style: { display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx3("span", { style: { color: "var(--text-faint)", fontSize: "13px" }, children: "Rendering..." }) });
|
|
386
380
|
}
|
|
387
|
-
return
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
381
|
+
return /* @__PURE__ */ jsxs2(
|
|
382
|
+
"div",
|
|
383
|
+
{
|
|
384
|
+
ref: containerRef,
|
|
385
|
+
className: interactive ? "mermaid-viewport" : "mermaid-viewport mermaid-viewport--compact",
|
|
386
|
+
onMouseDown: handleMouseDown,
|
|
387
|
+
children: [
|
|
388
|
+
/* @__PURE__ */ jsx3(
|
|
389
|
+
"div",
|
|
390
|
+
{
|
|
391
|
+
className: "mermaid-block-svg",
|
|
392
|
+
style: {
|
|
393
|
+
transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})`,
|
|
394
|
+
transformOrigin: "center center"
|
|
395
|
+
},
|
|
396
|
+
dangerouslySetInnerHTML: { __html: svgHTML }
|
|
397
|
+
}
|
|
398
|
+
),
|
|
399
|
+
interactive && /* @__PURE__ */ jsxs2("div", { className: "mermaid-zoom-controls", children: [
|
|
400
|
+
/* @__PURE__ */ jsx3(
|
|
401
|
+
"button",
|
|
402
|
+
{
|
|
403
|
+
onClick: (e) => {
|
|
404
|
+
e.stopPropagation();
|
|
405
|
+
setZoom((z) => Math.min(3, z + 0.2));
|
|
406
|
+
},
|
|
407
|
+
className: "mermaid-zoom-btn",
|
|
408
|
+
title: "Zoom in",
|
|
409
|
+
children: /* @__PURE__ */ jsxs2("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
410
|
+
/* @__PURE__ */ jsx3("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
|
|
411
|
+
/* @__PURE__ */ jsx3("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
|
|
412
|
+
] })
|
|
413
|
+
}
|
|
414
|
+
),
|
|
415
|
+
/* @__PURE__ */ jsxs2("span", { className: "mermaid-zoom-label", children: [
|
|
416
|
+
Math.round(zoom * 100),
|
|
417
|
+
"%"
|
|
418
|
+
] }),
|
|
419
|
+
/* @__PURE__ */ jsx3(
|
|
420
|
+
"button",
|
|
421
|
+
{
|
|
422
|
+
onClick: (e) => {
|
|
423
|
+
e.stopPropagation();
|
|
424
|
+
setZoom((z) => Math.max(0.3, z - 0.2));
|
|
425
|
+
},
|
|
426
|
+
className: "mermaid-zoom-btn",
|
|
427
|
+
title: "Zoom out",
|
|
428
|
+
children: /* @__PURE__ */ jsx3("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx3("line", { x1: "5", y1: "12", x2: "19", y2: "12" }) })
|
|
429
|
+
}
|
|
430
|
+
),
|
|
431
|
+
/* @__PURE__ */ jsx3(
|
|
432
|
+
"button",
|
|
433
|
+
{
|
|
434
|
+
onClick: (e) => {
|
|
435
|
+
e.stopPropagation();
|
|
436
|
+
resetView();
|
|
437
|
+
},
|
|
438
|
+
className: "mermaid-zoom-btn",
|
|
439
|
+
title: "Reset view",
|
|
440
|
+
children: /* @__PURE__ */ jsxs2("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
441
|
+
/* @__PURE__ */ jsx3("path", { d: "M3.51 15a9 9 0 1 0 2.13-9.36L1 10" }),
|
|
442
|
+
/* @__PURE__ */ jsx3("polyline", { points: "1 4 1 10 7 10" })
|
|
443
|
+
] })
|
|
444
|
+
}
|
|
445
|
+
)
|
|
446
|
+
] })
|
|
447
|
+
]
|
|
448
|
+
}
|
|
449
|
+
);
|
|
437
450
|
}
|
|
438
451
|
var MermaidBlock = createReactBlockSpec2(
|
|
439
452
|
{
|
|
@@ -452,8 +465,7 @@ var MermaidBlock = createReactBlockSpec2(
|
|
|
452
465
|
const inputRef = useRef2(null);
|
|
453
466
|
const debounceRef = useRef2(null);
|
|
454
467
|
useEffect3(() => {
|
|
455
|
-
if (editing && inputRef.current)
|
|
456
|
-
inputRef.current.focus();
|
|
468
|
+
if (editing && inputRef.current) inputRef.current.focus();
|
|
457
469
|
}, [editing]);
|
|
458
470
|
const handleCodeChange = useCallback2((e) => {
|
|
459
471
|
const v = e.target.value;
|
|
@@ -475,93 +487,96 @@ var MermaidBlock = createReactBlockSpec2(
|
|
|
475
487
|
}
|
|
476
488
|
}, [editor, block.id]);
|
|
477
489
|
if (editing) {
|
|
478
|
-
return
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
490
|
+
return /* @__PURE__ */ jsxs2("div", { className: "mermaid-block mermaid-block--editing", children: [
|
|
491
|
+
/* @__PURE__ */ jsxs2("div", { className: "mermaid-block-header", children: [
|
|
492
|
+
/* @__PURE__ */ jsx3("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "#c4b5fd", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx3("path", { d: "M12 3l1.912 5.813a2 2 0 001.275 1.275L21 12l-5.813 1.912a2 2 0 00-1.275 1.275L12 21l-1.912-5.813a2 2 0 00-1.275-1.275L3 12l5.813-1.912a2 2 0 001.275-1.275L12 3z" }) }),
|
|
493
|
+
/* @__PURE__ */ jsx3("span", { children: "Mermaid Diagram" }),
|
|
494
|
+
/* @__PURE__ */ jsx3("span", { style: { marginLeft: "auto", fontSize: "10px", color: "var(--text-faint)" }, children: "Shift+Enter to save" })
|
|
495
|
+
] }),
|
|
496
|
+
/* @__PURE__ */ jsx3(
|
|
497
|
+
"textarea",
|
|
498
|
+
{
|
|
499
|
+
ref: inputRef,
|
|
500
|
+
value,
|
|
501
|
+
onChange: handleCodeChange,
|
|
502
|
+
onKeyDown: (e) => {
|
|
503
|
+
if (e.key === "Enter" && e.shiftKey) {
|
|
504
|
+
e.preventDefault();
|
|
505
|
+
save();
|
|
506
|
+
}
|
|
507
|
+
if (e.key === "Escape") {
|
|
508
|
+
setEditing(false);
|
|
509
|
+
setValue(block.props.diagram || "");
|
|
510
|
+
setLivePreview(block.props.diagram || "");
|
|
511
|
+
}
|
|
512
|
+
if (e.key === "Tab") {
|
|
513
|
+
e.preventDefault();
|
|
514
|
+
const start = e.target.selectionStart;
|
|
515
|
+
const end = e.target.selectionEnd;
|
|
516
|
+
const newVal = value.substring(0, start) + " " + value.substring(end);
|
|
517
|
+
setValue(newVal);
|
|
518
|
+
setLivePreview(newVal);
|
|
519
|
+
requestAnimationFrame(() => {
|
|
520
|
+
e.target.selectionStart = e.target.selectionEnd = start + 4;
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
},
|
|
524
|
+
placeholder: `graph TD
|
|
511
525
|
A[Start] --> B{Decision}
|
|
512
526
|
B -->|Yes| C[OK]
|
|
513
|
-
B -->|No| D[End]
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
527
|
+
B -->|No| D[End]`,
|
|
528
|
+
rows: 8,
|
|
529
|
+
className: "mermaid-block-textarea"
|
|
530
|
+
}
|
|
531
|
+
),
|
|
532
|
+
/* @__PURE__ */ jsxs2("div", { className: "mermaid-live-preview", children: [
|
|
533
|
+
/* @__PURE__ */ jsx3("div", { className: "mermaid-live-preview-label", children: "Preview" }),
|
|
534
|
+
/* @__PURE__ */ jsx3(MermaidPreview, { diagram: livePreview, isDark, interactive: false })
|
|
535
|
+
] }),
|
|
536
|
+
/* @__PURE__ */ jsxs2("div", { className: "mermaid-block-actions", children: [
|
|
537
|
+
/* @__PURE__ */ jsx3("button", { onClick: () => {
|
|
523
538
|
setEditing(false);
|
|
524
539
|
setValue(block.props.diagram || "");
|
|
525
540
|
setLivePreview(block.props.diagram || "");
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
541
|
+
}, className: "mermaid-btn-cancel", children: "Cancel" }),
|
|
542
|
+
/* @__PURE__ */ jsx3("button", { onClick: save, className: "mermaid-btn-save", disabled: !value.trim(), children: "Done" })
|
|
543
|
+
] })
|
|
544
|
+
] });
|
|
530
545
|
}
|
|
531
546
|
if (!block.props.diagram) {
|
|
532
|
-
return
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
547
|
+
return /* @__PURE__ */ jsxs2("div", { onClick: () => setEditing(true), className: "mermaid-block mermaid-block--empty", children: [
|
|
548
|
+
/* @__PURE__ */ jsxs2("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
549
|
+
/* @__PURE__ */ jsx3("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1.5" }),
|
|
550
|
+
/* @__PURE__ */ jsx3("rect", { x: "14", y: "3", width: "7", height: "7", rx: "1.5" }),
|
|
551
|
+
/* @__PURE__ */ jsx3("rect", { x: "8.5", y: "14", width: "7", height: "7", rx: "1.5" }),
|
|
552
|
+
/* @__PURE__ */ jsx3("line", { x1: "6.5", y1: "10", x2: "6.5", y2: "14" }),
|
|
553
|
+
/* @__PURE__ */ jsx3("line", { x1: "17.5", y1: "10", x2: "17.5", y2: "14" }),
|
|
554
|
+
/* @__PURE__ */ jsx3("line", { x1: "6.5", y1: "14", x2: "8.5", y2: "14" }),
|
|
555
|
+
/* @__PURE__ */ jsx3("line", { x1: "17.5", y1: "14", x2: "15.5", y2: "14" })
|
|
556
|
+
] }),
|
|
557
|
+
/* @__PURE__ */ jsx3("span", { children: "Click to add a Mermaid diagram" })
|
|
558
|
+
] });
|
|
544
559
|
}
|
|
545
|
-
return
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
560
|
+
return /* @__PURE__ */ jsxs2("div", { className: "mermaid-block mermaid-block--rendered group", onDoubleClick: () => setEditing(true), children: [
|
|
561
|
+
/* @__PURE__ */ jsx3(MermaidPreview, { diagram: block.props.diagram, isDark, interactive: true }),
|
|
562
|
+
/* @__PURE__ */ jsxs2("div", { className: "mermaid-block-hover", children: [
|
|
563
|
+
/* @__PURE__ */ jsx3("button", { onClick: () => setEditing(true), className: "mermaid-hover-btn", title: "Edit diagram", children: /* @__PURE__ */ jsxs2("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
564
|
+
/* @__PURE__ */ jsx3("path", { d: "M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7" }),
|
|
565
|
+
/* @__PURE__ */ jsx3("path", { d: "M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z" })
|
|
566
|
+
] }) }),
|
|
567
|
+
/* @__PURE__ */ jsx3("button", { onClick: handleDelete, className: "mermaid-hover-btn mermaid-hover-delete", title: "Delete", children: /* @__PURE__ */ jsxs2("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
568
|
+
/* @__PURE__ */ jsx3("polyline", { points: "3 6 5 6 21 6" }),
|
|
569
|
+
/* @__PURE__ */ jsx3("path", { d: "M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2" })
|
|
570
|
+
] }) })
|
|
571
|
+
] })
|
|
572
|
+
] });
|
|
558
573
|
}
|
|
559
574
|
}
|
|
560
575
|
);
|
|
561
576
|
|
|
562
577
|
// src/blocks/TableOfContents.jsx
|
|
563
578
|
import { createReactBlockSpec as createReactBlockSpec3 } from "@blocknote/react";
|
|
564
|
-
|
|
579
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
565
580
|
var TableOfContents = createReactBlockSpec3(
|
|
566
581
|
{
|
|
567
582
|
type: "tableOfContents",
|
|
@@ -573,19 +588,23 @@ var TableOfContents = createReactBlockSpec3(
|
|
|
573
588
|
const headings = editor.document.filter(
|
|
574
589
|
(b) => b.type === "heading" && b.content?.length > 0
|
|
575
590
|
);
|
|
576
|
-
return
|
|
577
|
-
|
|
578
|
-
|
|
591
|
+
return /* @__PURE__ */ jsxs3("div", { className: "toc-block border border-[var(--border-default)] rounded-xl bg-[var(--bg-surface)] px-5 py-4 my-2 select-none", children: [
|
|
592
|
+
/* @__PURE__ */ jsx4("p", { className: "text-[11px] uppercase tracking-wider text-[var(--text-muted)] font-bold mb-3", children: "Table of Contents" }),
|
|
593
|
+
headings.length === 0 ? /* @__PURE__ */ jsx4("p", { className: "text-[13px] text-[var(--text-faint)] italic", children: "Add headings to see the outline here." }) : /* @__PURE__ */ jsx4("ul", { className: "space-y-1.5", children: headings.map((h) => {
|
|
579
594
|
const level = h.props?.level || 1;
|
|
580
595
|
const text = h.content.map((c) => c.text || "").join("");
|
|
581
|
-
return
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
596
|
+
return /* @__PURE__ */ jsx4(
|
|
597
|
+
"li",
|
|
598
|
+
{
|
|
599
|
+
className: "text-[13px] text-[#9b7bf7] hover:text-[#b69aff] cursor-pointer transition-colors",
|
|
600
|
+
style: { paddingLeft: `${(level - 1) * 16}px` },
|
|
601
|
+
onClick: () => editor.setTextCursorPosition(h.id),
|
|
602
|
+
children: text
|
|
603
|
+
},
|
|
604
|
+
h.id
|
|
605
|
+
);
|
|
606
|
+
}) })
|
|
607
|
+
] });
|
|
589
608
|
}
|
|
590
609
|
}
|
|
591
610
|
);
|
|
@@ -594,17 +613,13 @@ var TableOfContents = createReactBlockSpec3(
|
|
|
594
613
|
import { createReactInlineContentSpec } from "@blocknote/react";
|
|
595
614
|
import { useState as useState4, useRef as useRef3, useEffect as useEffect4, useCallback as useCallback3 } from "react";
|
|
596
615
|
import katex2 from "katex";
|
|
597
|
-
|
|
616
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
598
617
|
function stripDelimiters2(raw) {
|
|
599
618
|
let s = raw.trim();
|
|
600
|
-
if (s.startsWith("\\(") && s.endsWith("\\)"))
|
|
601
|
-
|
|
602
|
-
if (s.startsWith("
|
|
603
|
-
|
|
604
|
-
if (s.startsWith("$$") && s.endsWith("$$"))
|
|
605
|
-
return s.slice(2, -2).trim();
|
|
606
|
-
if (s.startsWith("$") && s.endsWith("$") && s.length > 2)
|
|
607
|
-
return s.slice(1, -1).trim();
|
|
619
|
+
if (s.startsWith("\\(") && s.endsWith("\\)")) return s.slice(2, -2).trim();
|
|
620
|
+
if (s.startsWith("\\[") && s.endsWith("\\]")) return s.slice(2, -2).trim();
|
|
621
|
+
if (s.startsWith("$$") && s.endsWith("$$")) return s.slice(2, -2).trim();
|
|
622
|
+
if (s.startsWith("$") && s.endsWith("$") && s.length > 2) return s.slice(1, -1).trim();
|
|
608
623
|
return s;
|
|
609
624
|
}
|
|
610
625
|
function renderKaTeXInline(latex) {
|
|
@@ -620,12 +635,10 @@ function InlineEquationChip({ inlineContent }) {
|
|
|
620
635
|
const inputRef = useRef3(null);
|
|
621
636
|
const popupRef = useRef3(null);
|
|
622
637
|
useEffect4(() => {
|
|
623
|
-
if (editing && inputRef.current)
|
|
624
|
-
inputRef.current.focus();
|
|
638
|
+
if (editing && inputRef.current) inputRef.current.focus();
|
|
625
639
|
}, [editing]);
|
|
626
640
|
useEffect4(() => {
|
|
627
|
-
if (!editing)
|
|
628
|
-
return;
|
|
641
|
+
if (!editing) return;
|
|
629
642
|
function handleClick(e) {
|
|
630
643
|
if (popupRef.current && !popupRef.current.contains(e.target)) {
|
|
631
644
|
setEditing(false);
|
|
@@ -642,47 +655,57 @@ function InlineEquationChip({ inlineContent }) {
|
|
|
642
655
|
}, [value, inlineContent]);
|
|
643
656
|
const html = renderKaTeXInline(inlineContent.props.latex);
|
|
644
657
|
const previewHtml = value.trim() ? renderKaTeXInline(value) : "";
|
|
645
|
-
return
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
e
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
ref
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
658
|
+
return /* @__PURE__ */ jsxs4("span", { className: "relative inline-flex items-center", children: [
|
|
659
|
+
/* @__PURE__ */ jsx5(
|
|
660
|
+
"span",
|
|
661
|
+
{
|
|
662
|
+
onClick: (e) => {
|
|
663
|
+
e.preventDefault();
|
|
664
|
+
e.stopPropagation();
|
|
665
|
+
setValue(inlineContent.props.latex || "");
|
|
666
|
+
setEditing(!editing);
|
|
667
|
+
},
|
|
668
|
+
className: "inline-equation-chip",
|
|
669
|
+
dangerouslySetInnerHTML: { __html: html },
|
|
670
|
+
title: inlineContent.props.latex
|
|
671
|
+
}
|
|
672
|
+
),
|
|
673
|
+
editing && /* @__PURE__ */ jsxs4(
|
|
674
|
+
"div",
|
|
675
|
+
{
|
|
676
|
+
ref: popupRef,
|
|
677
|
+
className: "inline-equation-editor",
|
|
678
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
679
|
+
children: [
|
|
680
|
+
/* @__PURE__ */ jsx5(
|
|
681
|
+
"input",
|
|
682
|
+
{
|
|
683
|
+
ref: inputRef,
|
|
684
|
+
type: "text",
|
|
685
|
+
className: "inline-equation-editor-input",
|
|
686
|
+
value,
|
|
687
|
+
onChange: (e) => setValue(e.target.value),
|
|
688
|
+
onKeyDown: (e) => {
|
|
689
|
+
if (e.key === "Enter") {
|
|
690
|
+
e.preventDefault();
|
|
691
|
+
save();
|
|
692
|
+
}
|
|
693
|
+
if (e.key === "Escape") {
|
|
694
|
+
setEditing(false);
|
|
695
|
+
}
|
|
696
|
+
},
|
|
697
|
+
placeholder: "E = mc^2"
|
|
698
|
+
}
|
|
699
|
+
),
|
|
700
|
+
previewHtml && /* @__PURE__ */ jsx5("div", { className: "inline-equation-editor-preview", dangerouslySetInnerHTML: { __html: previewHtml } }),
|
|
701
|
+
/* @__PURE__ */ jsxs4("div", { className: "inline-equation-editor-actions", children: [
|
|
702
|
+
/* @__PURE__ */ jsx5("button", { className: "mermaid-btn-cancel", onClick: () => setEditing(false), children: "Cancel" }),
|
|
703
|
+
/* @__PURE__ */ jsx5("button", { className: "mermaid-btn-save", disabled: !value.trim(), onClick: save, children: "Save" })
|
|
704
|
+
] })
|
|
705
|
+
]
|
|
706
|
+
}
|
|
707
|
+
)
|
|
708
|
+
] });
|
|
686
709
|
}
|
|
687
710
|
var InlineEquation = createReactInlineContentSpec(
|
|
688
711
|
{
|
|
@@ -693,32 +716,30 @@ var InlineEquation = createReactInlineContentSpec(
|
|
|
693
716
|
content: "none"
|
|
694
717
|
},
|
|
695
718
|
{
|
|
696
|
-
render: (props) =>
|
|
719
|
+
render: (props) => /* @__PURE__ */ jsx5(InlineEquationChip, { ...props })
|
|
697
720
|
}
|
|
698
721
|
);
|
|
699
722
|
|
|
700
723
|
// src/blocks/DateInline.jsx
|
|
701
724
|
import { createReactInlineContentSpec as createReactInlineContentSpec2 } from "@blocknote/react";
|
|
702
725
|
import { useState as useState5, useRef as useRef4, useEffect as useEffect5, useCallback as useCallback4 } from "react";
|
|
703
|
-
|
|
726
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
704
727
|
function MiniCalendar({ selectedDate, onSelect, onClose, anchorEl }) {
|
|
705
728
|
const ref = useRef4(null);
|
|
706
729
|
const [viewDate, setViewDate] = useState5(() => {
|
|
707
|
-
const d = selectedDate ? new Date(selectedDate) : new Date();
|
|
730
|
+
const d = selectedDate ? new Date(selectedDate) : /* @__PURE__ */ new Date();
|
|
708
731
|
return { year: d.getFullYear(), month: d.getMonth() };
|
|
709
732
|
});
|
|
710
733
|
const [pos, setPos] = useState5(null);
|
|
711
734
|
useEffect5(() => {
|
|
712
735
|
function handleClick(e) {
|
|
713
|
-
if (ref.current && !ref.current.contains(e.target))
|
|
714
|
-
onClose();
|
|
736
|
+
if (ref.current && !ref.current.contains(e.target)) onClose();
|
|
715
737
|
}
|
|
716
738
|
document.addEventListener("mousedown", handleClick);
|
|
717
739
|
return () => document.removeEventListener("mousedown", handleClick);
|
|
718
740
|
}, [onClose]);
|
|
719
741
|
useEffect5(() => {
|
|
720
|
-
if (!anchorEl)
|
|
721
|
-
return;
|
|
742
|
+
if (!anchorEl) return;
|
|
722
743
|
const rect = anchorEl.getBoundingClientRect();
|
|
723
744
|
const calWidth = 240;
|
|
724
745
|
let left = rect.left;
|
|
@@ -728,78 +749,88 @@ function MiniCalendar({ selectedDate, onSelect, onClose, anchorEl }) {
|
|
|
728
749
|
const { year, month } = viewDate;
|
|
729
750
|
const firstDay = new Date(year, month, 1).getDay();
|
|
730
751
|
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
|
731
|
-
const today = new Date();
|
|
752
|
+
const today = /* @__PURE__ */ new Date();
|
|
732
753
|
const todayStr = today.toISOString().split("T")[0];
|
|
733
754
|
const monthName = new Date(year, month).toLocaleDateString("en-US", { month: "long", year: "numeric" });
|
|
734
755
|
const days = [];
|
|
735
|
-
for (let i = 0; i < firstDay; i++)
|
|
736
|
-
|
|
737
|
-
for (let d = 1; d <= daysInMonth; d++)
|
|
738
|
-
days.push(d);
|
|
756
|
+
for (let i = 0; i < firstDay; i++) days.push(null);
|
|
757
|
+
for (let d = 1; d <= daysInMonth; d++) days.push(d);
|
|
739
758
|
const prev = () => setViewDate((v) => v.month === 0 ? { year: v.year - 1, month: 11 } : { ...v, month: v.month - 1 });
|
|
740
759
|
const next = () => setViewDate((v) => v.month === 11 ? { year: v.year + 1, month: 0 } : { ...v, month: v.month + 1 });
|
|
741
760
|
const toDateStr = (d) => `${year}-${String(month + 1).padStart(2, "0")}-${String(d).padStart(2, "0")}`;
|
|
742
|
-
if (!pos)
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
761
|
+
if (!pos) return null;
|
|
762
|
+
return /* @__PURE__ */ jsxs5(
|
|
763
|
+
"div",
|
|
764
|
+
{
|
|
765
|
+
ref,
|
|
766
|
+
className: "fixed z-[100] rounded-xl shadow-2xl overflow-hidden",
|
|
767
|
+
style: { backgroundColor: "var(--bg-app)", border: "1px solid var(--border-default)", width: "240px", top: pos.top, left: pos.left },
|
|
768
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
769
|
+
children: [
|
|
770
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between px-3 py-2", style: { borderBottom: "1px solid var(--divider)" }, children: [
|
|
771
|
+
/* @__PURE__ */ jsx6("button", { onClick: prev, className: "w-6 h-6 flex items-center justify-center rounded hover:bg-[var(--bg-hover)] transition-colors", style: { color: "var(--text-muted)" }, children: /* @__PURE__ */ jsx6("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: /* @__PURE__ */ jsx6("polyline", { points: "15 18 9 12 15 6" }) }) }),
|
|
772
|
+
/* @__PURE__ */ jsx6("span", { className: "text-[12px] font-semibold", style: { color: "var(--text-primary)" }, children: monthName }),
|
|
773
|
+
/* @__PURE__ */ jsx6("button", { onClick: next, className: "w-6 h-6 flex items-center justify-center rounded hover:bg-[var(--bg-hover)] transition-colors", style: { color: "var(--text-muted)" }, children: /* @__PURE__ */ jsx6("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: /* @__PURE__ */ jsx6("polyline", { points: "9 18 15 12 9 6" }) }) })
|
|
774
|
+
] }),
|
|
775
|
+
/* @__PURE__ */ jsx6("div", { className: "grid grid-cols-7 px-2 pt-2", children: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((d) => /* @__PURE__ */ jsx6("div", { className: "text-center text-[10px] font-medium py-1", style: { color: "var(--text-faint)" }, children: d }, d)) }),
|
|
776
|
+
/* @__PURE__ */ jsx6("div", { className: "grid grid-cols-7 px-2 pb-2 gap-0.5", children: days.map((d, i) => {
|
|
777
|
+
if (!d) return /* @__PURE__ */ jsx6("div", {}, `e${i}`);
|
|
778
|
+
const dateStr = toDateStr(d);
|
|
779
|
+
const isSelected = dateStr === selectedDate;
|
|
780
|
+
const isToday = dateStr === todayStr;
|
|
781
|
+
return /* @__PURE__ */ jsx6(
|
|
782
|
+
"button",
|
|
783
|
+
{
|
|
784
|
+
onClick: () => {
|
|
785
|
+
onSelect(dateStr);
|
|
786
|
+
onClose();
|
|
787
|
+
},
|
|
788
|
+
className: "w-7 h-7 rounded-lg text-[11px] font-medium flex items-center justify-center transition-all",
|
|
789
|
+
style: {
|
|
790
|
+
backgroundColor: isSelected ? "#9b7bf7" : "transparent",
|
|
791
|
+
color: isSelected ? "white" : isToday ? "#9b7bf7" : "var(--text-body)",
|
|
792
|
+
border: isToday && !isSelected ? "1px solid #9b7bf7" : "1px solid transparent"
|
|
793
|
+
},
|
|
794
|
+
onMouseEnter: (e) => {
|
|
795
|
+
if (!isSelected) e.currentTarget.style.backgroundColor = "var(--bg-hover)";
|
|
796
|
+
},
|
|
797
|
+
onMouseLeave: (e) => {
|
|
798
|
+
if (!isSelected) e.currentTarget.style.backgroundColor = "transparent";
|
|
799
|
+
},
|
|
800
|
+
children: d
|
|
801
|
+
},
|
|
802
|
+
d
|
|
803
|
+
);
|
|
804
|
+
}) }),
|
|
805
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between px-3 py-1.5", style: { borderTop: "1px solid var(--divider)" }, children: [
|
|
806
|
+
/* @__PURE__ */ jsx6(
|
|
807
|
+
"button",
|
|
808
|
+
{
|
|
809
|
+
onClick: () => {
|
|
810
|
+
onSelect("");
|
|
811
|
+
onClose();
|
|
812
|
+
},
|
|
813
|
+
className: "text-[10px] font-medium transition-colors",
|
|
814
|
+
style: { color: "var(--text-faint)" },
|
|
815
|
+
children: "Clear"
|
|
816
|
+
}
|
|
817
|
+
),
|
|
818
|
+
/* @__PURE__ */ jsx6(
|
|
819
|
+
"button",
|
|
820
|
+
{
|
|
821
|
+
onClick: () => {
|
|
822
|
+
onSelect(todayStr);
|
|
823
|
+
onClose();
|
|
824
|
+
},
|
|
825
|
+
className: "text-[10px] font-medium transition-colors",
|
|
826
|
+
style: { color: "#9b7bf7" },
|
|
827
|
+
children: "Today"
|
|
828
|
+
}
|
|
829
|
+
)
|
|
830
|
+
] })
|
|
831
|
+
]
|
|
832
|
+
}
|
|
833
|
+
);
|
|
803
834
|
}
|
|
804
835
|
function DateChip({ inlineContent }) {
|
|
805
836
|
const [showPicker, setShowPicker] = useState5(false);
|
|
@@ -817,51 +848,58 @@ function DateChip({ inlineContent }) {
|
|
|
817
848
|
}
|
|
818
849
|
setShowPicker(false);
|
|
819
850
|
}, [inlineContent]);
|
|
820
|
-
return
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
e
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
851
|
+
return /* @__PURE__ */ jsxs5("span", { className: "relative inline-flex items-center", children: [
|
|
852
|
+
/* @__PURE__ */ jsxs5(
|
|
853
|
+
"span",
|
|
854
|
+
{
|
|
855
|
+
ref: chipRef,
|
|
856
|
+
onClick: (e) => {
|
|
857
|
+
e.preventDefault();
|
|
858
|
+
e.stopPropagation();
|
|
859
|
+
setShowPicker(!showPicker);
|
|
860
|
+
},
|
|
861
|
+
className: "inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-[13px] font-medium mx-0.5 cursor-pointer transition-all hover:ring-2 hover:ring-[#9b7bf7]/30",
|
|
862
|
+
style: { color: "#9b7bf7", backgroundColor: "rgba(155,123,247,0.06)", border: "1px solid rgba(155,123,247,0.15)" },
|
|
863
|
+
title: "Click to change date (Ctrl+D to insert)",
|
|
864
|
+
children: [
|
|
865
|
+
/* @__PURE__ */ jsxs5("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [
|
|
866
|
+
/* @__PURE__ */ jsx6("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2", strokeWidth: 2 }),
|
|
867
|
+
/* @__PURE__ */ jsx6("line", { x1: "16", y1: "2", x2: "16", y2: "6", strokeWidth: 2 }),
|
|
868
|
+
/* @__PURE__ */ jsx6("line", { x1: "8", y1: "2", x2: "8", y2: "6", strokeWidth: 2 }),
|
|
869
|
+
/* @__PURE__ */ jsx6("line", { x1: "3", y1: "10", x2: "21", y2: "10", strokeWidth: 2 })
|
|
870
|
+
] }),
|
|
871
|
+
formatted
|
|
872
|
+
]
|
|
873
|
+
}
|
|
874
|
+
),
|
|
875
|
+
showPicker && /* @__PURE__ */ jsx6(
|
|
876
|
+
MiniCalendar,
|
|
877
|
+
{
|
|
878
|
+
selectedDate: d,
|
|
879
|
+
onSelect: handleSelect,
|
|
880
|
+
onClose: () => setShowPicker(false),
|
|
881
|
+
anchorEl: chipRef.current
|
|
882
|
+
}
|
|
883
|
+
)
|
|
884
|
+
] });
|
|
847
885
|
}
|
|
848
886
|
var DateInline = createReactInlineContentSpec2(
|
|
849
887
|
{
|
|
850
888
|
type: "dateInline",
|
|
851
889
|
propSchema: {
|
|
852
|
-
date: { default: new Date().toISOString().split("T")[0] }
|
|
890
|
+
date: { default: (/* @__PURE__ */ new Date()).toISOString().split("T")[0] }
|
|
853
891
|
},
|
|
854
892
|
content: "none"
|
|
855
893
|
},
|
|
856
894
|
{
|
|
857
|
-
render: (props) =>
|
|
895
|
+
render: (props) => /* @__PURE__ */ jsx6(DateChip, { ...props })
|
|
858
896
|
}
|
|
859
897
|
);
|
|
860
898
|
|
|
861
899
|
// src/blocks/ImageBlock.jsx
|
|
862
900
|
import { createReactBlockSpec as createReactBlockSpec4 } from "@blocknote/react";
|
|
863
901
|
import { useState as useState6, useRef as useRef5, useCallback as useCallback5, useEffect as useEffect6 } from "react";
|
|
864
|
-
|
|
902
|
+
import { Fragment, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
865
903
|
var BlogImageBlock = createReactBlockSpec4(
|
|
866
904
|
{
|
|
867
905
|
type: "image",
|
|
@@ -875,7 +913,7 @@ var BlogImageBlock = createReactBlockSpec4(
|
|
|
875
913
|
content: "none"
|
|
876
914
|
},
|
|
877
915
|
{
|
|
878
|
-
render: (props) =>
|
|
916
|
+
render: (props) => /* @__PURE__ */ jsx7(ImageRenderer, { ...props })
|
|
879
917
|
}
|
|
880
918
|
);
|
|
881
919
|
function ImageRenderer({ block, editor }) {
|
|
@@ -891,13 +929,11 @@ function ImageRenderer({ block, editor }) {
|
|
|
891
929
|
const blockRef = useRef5(null);
|
|
892
930
|
const embedInputRef = useRef5(null);
|
|
893
931
|
useEffect6(() => {
|
|
894
|
-
if (mode === "embed")
|
|
895
|
-
setTimeout(() => embedInputRef.current?.focus(), 50);
|
|
932
|
+
if (mode === "embed") setTimeout(() => embedInputRef.current?.focus(), 50);
|
|
896
933
|
}, [mode]);
|
|
897
934
|
useEffect6(() => {
|
|
898
935
|
const el = blockRef.current;
|
|
899
|
-
if (!el)
|
|
900
|
-
return;
|
|
936
|
+
if (!el) return;
|
|
901
937
|
function handleKey(e) {
|
|
902
938
|
if ((e.key === "Backspace" || e.key === "Delete") && mode === "idle" && !url) {
|
|
903
939
|
e.preventDefault();
|
|
@@ -911,8 +947,7 @@ function ImageRenderer({ block, editor }) {
|
|
|
911
947
|
return () => el.removeEventListener("keydown", handleKey);
|
|
912
948
|
}, [editor, block.id, mode, url]);
|
|
913
949
|
const uploadFile = useCallback5(async (file) => {
|
|
914
|
-
if (!file || !file.type.startsWith("image/"))
|
|
915
|
-
return;
|
|
950
|
+
if (!file || !file.type.startsWith("image/")) return;
|
|
916
951
|
setMode("uploading");
|
|
917
952
|
setUploadStatus("Processing...");
|
|
918
953
|
try {
|
|
@@ -932,8 +967,7 @@ function ImageRenderer({ block, editor }) {
|
|
|
932
967
|
}, [editor, block.id]);
|
|
933
968
|
const handlePaste = useCallback5((e) => {
|
|
934
969
|
const items = e.clipboardData?.items;
|
|
935
|
-
if (!items)
|
|
936
|
-
return;
|
|
970
|
+
if (!items) return;
|
|
937
971
|
for (const item of items) {
|
|
938
972
|
if (item.type.startsWith("image/")) {
|
|
939
973
|
e.preventDefault();
|
|
@@ -946,13 +980,11 @@ function ImageRenderer({ block, editor }) {
|
|
|
946
980
|
e.preventDefault();
|
|
947
981
|
setIsDragOver(false);
|
|
948
982
|
const file = e.dataTransfer?.files?.[0];
|
|
949
|
-
if (file?.type.startsWith("image/"))
|
|
950
|
-
uploadFile(file);
|
|
983
|
+
if (file?.type.startsWith("image/")) uploadFile(file);
|
|
951
984
|
}, [uploadFile]);
|
|
952
985
|
const handleEmbed = useCallback5(() => {
|
|
953
986
|
const trimmed = embedUrl.trim();
|
|
954
|
-
if (!trimmed)
|
|
955
|
-
return;
|
|
987
|
+
if (!trimmed) return;
|
|
956
988
|
if (!trimmed.startsWith("http")) {
|
|
957
989
|
setEmbedError("URL must start with http:// or https://");
|
|
958
990
|
return;
|
|
@@ -989,137 +1021,151 @@ function ImageRenderer({ block, editor }) {
|
|
|
989
1021
|
setEditingCaption(false);
|
|
990
1022
|
}, [editor, block.id, captionText]);
|
|
991
1023
|
if (!url) {
|
|
992
|
-
return
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1024
|
+
return /* @__PURE__ */ jsxs6(
|
|
1025
|
+
"div",
|
|
1026
|
+
{
|
|
1027
|
+
ref: blockRef,
|
|
1028
|
+
className: "blog-img-empty",
|
|
1029
|
+
tabIndex: 0,
|
|
1030
|
+
onPaste: handlePaste,
|
|
1031
|
+
onDrop: handleDrop,
|
|
1032
|
+
onDragOver: (e) => {
|
|
1033
|
+
e.preventDefault();
|
|
1034
|
+
setIsDragOver(true);
|
|
1035
|
+
},
|
|
1036
|
+
onDragLeave: () => setIsDragOver(false),
|
|
1037
|
+
"data-drag-over": isDragOver,
|
|
1038
|
+
children: [
|
|
1039
|
+
/* @__PURE__ */ jsx7(
|
|
1040
|
+
"input",
|
|
1041
|
+
{
|
|
1042
|
+
ref: fileInputRef,
|
|
1043
|
+
type: "file",
|
|
1044
|
+
accept: "image/*",
|
|
1045
|
+
onChange: (e) => {
|
|
1046
|
+
if (e.target.files?.[0]) uploadFile(e.target.files[0]);
|
|
1047
|
+
e.target.value = "";
|
|
1048
|
+
},
|
|
1049
|
+
style: { display: "none" }
|
|
1050
|
+
}
|
|
1051
|
+
),
|
|
1052
|
+
mode === "uploading" && /* @__PURE__ */ jsxs6("div", { className: "blog-img-status", children: [
|
|
1053
|
+
/* @__PURE__ */ jsx7("div", { className: "blog-img-spinner" }),
|
|
1054
|
+
/* @__PURE__ */ jsx7("span", { children: uploadStatus })
|
|
1055
|
+
] }),
|
|
1056
|
+
mode === "idle" && /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
1057
|
+
/* @__PURE__ */ jsxs6("div", { className: "blog-img-actions-row", children: [
|
|
1058
|
+
/* @__PURE__ */ jsxs6("button", { className: "blog-img-action", onClick: () => fileInputRef.current?.click(), children: [
|
|
1059
|
+
/* @__PURE__ */ jsxs6("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1060
|
+
/* @__PURE__ */ jsx7("path", { d: "M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4" }),
|
|
1061
|
+
/* @__PURE__ */ jsx7("polyline", { points: "17 8 12 3 7 8" }),
|
|
1062
|
+
/* @__PURE__ */ jsx7("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
|
|
1063
|
+
] }),
|
|
1064
|
+
"Upload"
|
|
1065
|
+
] }),
|
|
1066
|
+
/* @__PURE__ */ jsxs6("button", { className: "blog-img-action", onClick: () => setMode("embed"), children: [
|
|
1067
|
+
/* @__PURE__ */ jsxs6("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1068
|
+
/* @__PURE__ */ jsx7("path", { d: "M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71" }),
|
|
1069
|
+
/* @__PURE__ */ jsx7("path", { d: "M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71" })
|
|
1070
|
+
] }),
|
|
1071
|
+
"Embed URL"
|
|
1072
|
+
] })
|
|
1073
|
+
] }),
|
|
1074
|
+
/* @__PURE__ */ jsx7("p", { className: "blog-img-hint", children: "or drag & drop / paste an image" })
|
|
1075
|
+
] }),
|
|
1076
|
+
mode === "embed" && /* @__PURE__ */ jsxs6("div", { className: "blog-img-input-row", children: [
|
|
1077
|
+
/* @__PURE__ */ jsx7(
|
|
1078
|
+
"input",
|
|
1079
|
+
{
|
|
1080
|
+
ref: embedInputRef,
|
|
1081
|
+
type: "url",
|
|
1082
|
+
value: embedUrl,
|
|
1083
|
+
onChange: (e) => {
|
|
1084
|
+
setEmbedUrl(e.target.value);
|
|
1085
|
+
setEmbedError("");
|
|
1086
|
+
},
|
|
1087
|
+
onKeyDown: (e) => {
|
|
1088
|
+
if (e.key === "Enter") handleEmbed();
|
|
1089
|
+
if (e.key === "Escape") {
|
|
1090
|
+
setMode("idle");
|
|
1091
|
+
setEmbedUrl("");
|
|
1092
|
+
setEmbedError("");
|
|
1093
|
+
}
|
|
1094
|
+
},
|
|
1095
|
+
placeholder: "https://example.com/image.jpg",
|
|
1096
|
+
className: "blog-img-url-input"
|
|
1097
|
+
}
|
|
1098
|
+
),
|
|
1099
|
+
/* @__PURE__ */ jsx7("button", { className: "blog-img-submit-btn", onClick: handleEmbed, disabled: !embedUrl.trim(), children: /* @__PURE__ */ jsx7("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx7("polyline", { points: "20 6 9 17 4 12" }) }) }),
|
|
1100
|
+
/* @__PURE__ */ jsx7("button", { className: "blog-img-cancel-btn", onClick: () => {
|
|
1053
1101
|
setMode("idle");
|
|
1054
1102
|
setEmbedUrl("");
|
|
1055
1103
|
setEmbedError("");
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
setEmbedError("");
|
|
1066
|
-
}}><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
|
|
1067
|
-
<line x1="18" y1="6" x2="6" y2="18" />
|
|
1068
|
-
<line x1="6" y1="6" x2="18" y2="18" />
|
|
1069
|
-
</svg></button>
|
|
1070
|
-
{embedError && <span className="blog-img-error">{embedError}</span>}
|
|
1071
|
-
</div>}
|
|
1072
|
-
</div>;
|
|
1104
|
+
}, children: /* @__PURE__ */ jsxs6("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1105
|
+
/* @__PURE__ */ jsx7("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
1106
|
+
/* @__PURE__ */ jsx7("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
1107
|
+
] }) }),
|
|
1108
|
+
embedError && /* @__PURE__ */ jsx7("span", { className: "blog-img-error", children: embedError })
|
|
1109
|
+
] })
|
|
1110
|
+
]
|
|
1111
|
+
}
|
|
1112
|
+
);
|
|
1073
1113
|
}
|
|
1074
|
-
return
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1114
|
+
return /* @__PURE__ */ jsxs6("div", { ref: blockRef, className: "blog-img-loaded", tabIndex: 0, onPaste: handlePaste, children: [
|
|
1115
|
+
/* @__PURE__ */ jsxs6("div", { className: "blog-img-wrapper", children: [
|
|
1116
|
+
/* @__PURE__ */ jsx7("img", { src: url, alt: caption || "Image", className: "blog-img-main", draggable: false }),
|
|
1117
|
+
/* @__PURE__ */ jsx7("div", { className: "blog-img-hover-overlay", children: /* @__PURE__ */ jsxs6("div", { className: "blog-img-hover-actions", children: [
|
|
1118
|
+
/* @__PURE__ */ jsx7("button", { className: "blog-img-hover-btn", onClick: handleReplace, children: /* @__PURE__ */ jsxs6("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1119
|
+
/* @__PURE__ */ jsx7("path", { d: "M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4" }),
|
|
1120
|
+
/* @__PURE__ */ jsx7("polyline", { points: "17 8 12 3 7 8" }),
|
|
1121
|
+
/* @__PURE__ */ jsx7("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
|
|
1122
|
+
] }) }),
|
|
1123
|
+
/* @__PURE__ */ jsx7("button", { className: "blog-img-hover-btn", onClick: () => setEditingCaption(true), children: /* @__PURE__ */ jsxs6("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1124
|
+
/* @__PURE__ */ jsx7("path", { d: "M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7" }),
|
|
1125
|
+
/* @__PURE__ */ jsx7("path", { d: "M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z" })
|
|
1126
|
+
] }) }),
|
|
1127
|
+
/* @__PURE__ */ jsx7("button", { className: "blog-img-hover-btn blog-img-hover-delete", onClick: handleDelete, children: /* @__PURE__ */ jsxs6("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1128
|
+
/* @__PURE__ */ jsx7("polyline", { points: "3 6 5 6 21 6" }),
|
|
1129
|
+
/* @__PURE__ */ jsx7("path", { d: "M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2" })
|
|
1130
|
+
] }) })
|
|
1131
|
+
] }) })
|
|
1132
|
+
] }),
|
|
1133
|
+
editingCaption ? /* @__PURE__ */ jsx7(
|
|
1134
|
+
"input",
|
|
1135
|
+
{
|
|
1136
|
+
type: "text",
|
|
1137
|
+
value: captionText,
|
|
1138
|
+
onChange: (e) => setCaptionText(e.target.value),
|
|
1139
|
+
onKeyDown: (e) => {
|
|
1140
|
+
if (e.key === "Enter") handleCaptionSave();
|
|
1141
|
+
if (e.key === "Escape") {
|
|
1142
|
+
setEditingCaption(false);
|
|
1143
|
+
setCaptionText(caption || "");
|
|
1144
|
+
}
|
|
1145
|
+
},
|
|
1146
|
+
onBlur: handleCaptionSave,
|
|
1147
|
+
placeholder: "Add a caption...",
|
|
1148
|
+
className: "blog-img-caption-input",
|
|
1149
|
+
autoFocus: true
|
|
1150
|
+
}
|
|
1151
|
+
) : /* @__PURE__ */ jsx7(
|
|
1152
|
+
"p",
|
|
1153
|
+
{
|
|
1154
|
+
className: `blog-img-caption ${caption ? "" : "blog-img-caption--empty"}`,
|
|
1155
|
+
onClick: () => {
|
|
1102
1156
|
setCaptionText(caption || "");
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
/> : <p
|
|
1110
|
-
className={`blog-img-caption ${caption ? "" : "blog-img-caption--empty"}`}
|
|
1111
|
-
onClick={() => {
|
|
1112
|
-
setCaptionText(caption || "");
|
|
1113
|
-
setEditingCaption(true);
|
|
1114
|
-
}}
|
|
1115
|
-
>{caption || "Add a caption..."}</p>}
|
|
1116
|
-
</div>;
|
|
1157
|
+
setEditingCaption(true);
|
|
1158
|
+
},
|
|
1159
|
+
children: caption || "Add a caption..."
|
|
1160
|
+
}
|
|
1161
|
+
)
|
|
1162
|
+
] });
|
|
1117
1163
|
}
|
|
1118
1164
|
|
|
1119
1165
|
// src/blocks/ButtonBlock.jsx
|
|
1120
1166
|
import { createReactBlockSpec as createReactBlockSpec5 } from "@blocknote/react";
|
|
1121
1167
|
import { useState as useState7, useEffect as useEffect7, useRef as useRef6 } from "react";
|
|
1122
|
-
|
|
1168
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1123
1169
|
var BUTTON_ACTIONS = [
|
|
1124
1170
|
{ value: "link", label: "Open Link" },
|
|
1125
1171
|
{ value: "copy", label: "Copy Text" },
|
|
@@ -1154,34 +1200,40 @@ var ButtonBlock = createReactBlockSpec5(
|
|
|
1154
1200
|
setEditing(false);
|
|
1155
1201
|
};
|
|
1156
1202
|
if (editing) {
|
|
1157
|
-
return
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1203
|
+
return /* @__PURE__ */ jsxs7("div", { className: "border border-[var(--border-default)] rounded-xl bg-[var(--bg-surface)] p-4 my-2 space-y-3", children: [
|
|
1204
|
+
/* @__PURE__ */ jsx8("p", { className: "text-[11px] text-[var(--text-muted)] font-medium", children: "Button Block" }),
|
|
1205
|
+
/* @__PURE__ */ jsx8(
|
|
1206
|
+
"input",
|
|
1207
|
+
{
|
|
1208
|
+
type: "text",
|
|
1209
|
+
value: label,
|
|
1210
|
+
onChange: (e) => setLabel(e.target.value),
|
|
1211
|
+
placeholder: "Button label",
|
|
1212
|
+
className: "w-full bg-[var(--bg-app)] border border-[var(--border-default)] rounded-lg px-3 py-2 text-[13px] text-[var(--text-primary)] outline-none focus:border-[var(--border-hover)] placeholder-[#6b7a8d]"
|
|
1213
|
+
}
|
|
1214
|
+
),
|
|
1215
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex gap-2", children: [
|
|
1216
|
+
/* @__PURE__ */ jsx8("select", { value: action, onChange: (e) => setAction(e.target.value), className: "bg-[var(--bg-app)] border border-[var(--border-default)] rounded-lg px-3 py-2 text-[13px] text-[var(--text-primary)] outline-none flex-1", children: BUTTON_ACTIONS.map((a) => /* @__PURE__ */ jsx8("option", { value: a.value, children: a.label }, a.value)) }),
|
|
1217
|
+
/* @__PURE__ */ jsx8("select", { value: variant, onChange: (e) => setVariant(e.target.value), className: "bg-[var(--bg-app)] border border-[var(--border-default)] rounded-lg px-3 py-2 text-[13px] text-[var(--text-primary)] outline-none", children: BUTTON_VARIANTS.map((v) => /* @__PURE__ */ jsx8("option", { value: v.value, children: v.label }, v.value)) })
|
|
1218
|
+
] }),
|
|
1219
|
+
(action === "link" || action === "copy") && /* @__PURE__ */ jsx8(
|
|
1220
|
+
"input",
|
|
1221
|
+
{
|
|
1222
|
+
type: "text",
|
|
1223
|
+
value: actionValue,
|
|
1224
|
+
onChange: (e) => setActionValue(e.target.value),
|
|
1225
|
+
placeholder: action === "link" ? "https://..." : "Text to copy",
|
|
1226
|
+
className: "w-full bg-[var(--bg-app)] border border-[var(--border-default)] rounded-lg px-3 py-2 text-[13px] text-[var(--text-primary)] outline-none focus:border-[var(--border-hover)] placeholder-[#6b7a8d]"
|
|
1227
|
+
}
|
|
1228
|
+
),
|
|
1229
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex justify-end gap-2", children: [
|
|
1230
|
+
/* @__PURE__ */ jsx8("button", { onClick: () => setEditing(false), className: "px-3 py-1 text-[12px] text-[#888] hover:text-[var(--text-primary)] transition-colors", children: "Cancel" }),
|
|
1231
|
+
/* @__PURE__ */ jsx8("button", { onClick: save, className: "px-3 py-1 text-[12px] bg-[#9b7bf7] text-[var(--text-primary)] rounded-md font-medium hover:bg-[#b69aff] transition-colors", children: "Done" })
|
|
1232
|
+
] })
|
|
1233
|
+
] });
|
|
1182
1234
|
}
|
|
1183
1235
|
const variantCls = BUTTON_VARIANTS.find((v) => v.value === variant)?.cls || BUTTON_VARIANTS[0].cls;
|
|
1184
|
-
return
|
|
1236
|
+
return /* @__PURE__ */ jsx8("div", { className: "my-2", onDoubleClick: () => setEditing(true), children: /* @__PURE__ */ jsx8("button", { className: `px-5 py-2 rounded-lg text-[13px] font-medium transition-colors ${variantCls}`, children: label }) });
|
|
1185
1237
|
}
|
|
1186
1238
|
}
|
|
1187
1239
|
);
|
|
@@ -1189,7 +1241,7 @@ var ButtonBlock = createReactBlockSpec5(
|
|
|
1189
1241
|
// src/blocks/PDFEmbedBlock.jsx
|
|
1190
1242
|
import { createReactBlockSpec as createReactBlockSpec6 } from "@blocknote/react";
|
|
1191
1243
|
import { useState as useState8 } from "react";
|
|
1192
|
-
|
|
1244
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1193
1245
|
var PDFEmbedBlock = createReactBlockSpec6(
|
|
1194
1246
|
{
|
|
1195
1247
|
type: "pdfEmbed",
|
|
@@ -1208,8 +1260,7 @@ var PDFEmbedBlock = createReactBlockSpec6(
|
|
|
1208
1260
|
const [loading, setLoading] = useState8(false);
|
|
1209
1261
|
const handleSubmit = () => {
|
|
1210
1262
|
const trimmed = inputUrl.trim();
|
|
1211
|
-
if (!trimmed)
|
|
1212
|
-
return;
|
|
1263
|
+
if (!trimmed) return;
|
|
1213
1264
|
setLoading(true);
|
|
1214
1265
|
const fileName = decodeURIComponent(trimmed.split("/").pop()?.split("?")[0] || "document.pdf");
|
|
1215
1266
|
editor.updateBlock(block, {
|
|
@@ -1231,90 +1282,100 @@ var PDFEmbedBlock = createReactBlockSpec6(
|
|
|
1231
1282
|
editor.removeBlocks([block]);
|
|
1232
1283
|
};
|
|
1233
1284
|
if (!url) {
|
|
1234
|
-
return
|
|
1285
|
+
return /* @__PURE__ */ jsxs8("div", { style: {
|
|
1235
1286
|
background: "rgba(155, 123, 247, 0.04)",
|
|
1236
1287
|
border: "1.5px dashed rgba(155, 123, 247, 0.25)",
|
|
1237
1288
|
borderRadius: "12px",
|
|
1238
1289
|
padding: "24px"
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1290
|
+
}, children: [
|
|
1291
|
+
/* @__PURE__ */ jsxs8("div", { style: { display: "flex", alignItems: "center", gap: "8px", marginBottom: "12px" }, children: [
|
|
1292
|
+
/* @__PURE__ */ jsxs8("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "#9b7bf7", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1293
|
+
/* @__PURE__ */ jsx9("path", { d: "M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" }),
|
|
1294
|
+
/* @__PURE__ */ jsx9("polyline", { points: "14 2 14 8 20 8" }),
|
|
1295
|
+
/* @__PURE__ */ jsx9("line", { x1: "16", y1: "13", x2: "8", y2: "13" }),
|
|
1296
|
+
/* @__PURE__ */ jsx9("line", { x1: "16", y1: "17", x2: "8", y2: "17" }),
|
|
1297
|
+
/* @__PURE__ */ jsx9("polyline", { points: "10 9 9 9 8 9" })
|
|
1298
|
+
] }),
|
|
1299
|
+
/* @__PURE__ */ jsx9("span", { style: { fontSize: "14px", fontWeight: 600, color: "var(--text-primary)" }, children: "Embed PDF" })
|
|
1300
|
+
] }),
|
|
1301
|
+
/* @__PURE__ */ jsxs8("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
1302
|
+
/* @__PURE__ */ jsx9(
|
|
1303
|
+
"input",
|
|
1304
|
+
{
|
|
1305
|
+
type: "text",
|
|
1306
|
+
value: inputUrl,
|
|
1307
|
+
onChange: (e) => setInputUrl(e.target.value),
|
|
1308
|
+
onKeyDown: (e) => e.key === "Enter" && handleSubmit(),
|
|
1309
|
+
placeholder: "Paste PDF link...",
|
|
1310
|
+
style: {
|
|
1311
|
+
flex: 1,
|
|
1312
|
+
background: "var(--bg-app)",
|
|
1313
|
+
color: "var(--text-primary)",
|
|
1314
|
+
border: "1px solid #232d3f",
|
|
1315
|
+
borderRadius: "8px",
|
|
1316
|
+
padding: "8px 12px",
|
|
1317
|
+
fontSize: "13px",
|
|
1318
|
+
outline: "none"
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
),
|
|
1322
|
+
/* @__PURE__ */ jsx9(
|
|
1323
|
+
"button",
|
|
1324
|
+
{
|
|
1325
|
+
onClick: handleSubmit,
|
|
1326
|
+
disabled: !inputUrl.trim() || loading,
|
|
1327
|
+
style: {
|
|
1328
|
+
padding: "8px 16px",
|
|
1329
|
+
background: "#9b7bf7",
|
|
1330
|
+
color: "white",
|
|
1331
|
+
border: "none",
|
|
1332
|
+
borderRadius: "8px",
|
|
1333
|
+
fontSize: "13px",
|
|
1334
|
+
fontWeight: 600,
|
|
1335
|
+
cursor: "pointer",
|
|
1336
|
+
opacity: !inputUrl.trim() || loading ? 0.4 : 1
|
|
1337
|
+
},
|
|
1338
|
+
children: loading ? "..." : "Embed"
|
|
1339
|
+
}
|
|
1340
|
+
)
|
|
1341
|
+
] })
|
|
1342
|
+
] });
|
|
1285
1343
|
}
|
|
1286
|
-
return
|
|
1344
|
+
return /* @__PURE__ */ jsxs8("div", { style: {
|
|
1287
1345
|
display: "flex",
|
|
1288
1346
|
borderRadius: "12px",
|
|
1289
1347
|
overflow: "hidden",
|
|
1290
1348
|
border: "1px solid #232d3f",
|
|
1291
1349
|
background: "var(--bg-surface)"
|
|
1292
|
-
}
|
|
1293
|
-
|
|
1350
|
+
}, children: [
|
|
1351
|
+
/* @__PURE__ */ jsxs8("div", { style: {
|
|
1294
1352
|
width: "200px",
|
|
1295
1353
|
minHeight: "160px",
|
|
1296
1354
|
flexShrink: 0,
|
|
1297
1355
|
background: "#0d1117",
|
|
1298
1356
|
position: "relative",
|
|
1299
1357
|
overflow: "hidden"
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1358
|
+
}, children: [
|
|
1359
|
+
/* @__PURE__ */ jsx9(
|
|
1360
|
+
"iframe",
|
|
1361
|
+
{
|
|
1362
|
+
src: `${url}#toolbar=0&navpanes=0&scrollbar=0&view=FitH`,
|
|
1363
|
+
title: title || "PDF",
|
|
1364
|
+
style: {
|
|
1365
|
+
width: "100%",
|
|
1366
|
+
height: "100%",
|
|
1367
|
+
border: "none",
|
|
1368
|
+
pointerEvents: "none"
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
),
|
|
1372
|
+
/* @__PURE__ */ jsx9("div", { style: {
|
|
1312
1373
|
position: "absolute",
|
|
1313
1374
|
inset: 0,
|
|
1314
1375
|
background: "linear-gradient(135deg, rgba(155,123,247,0.08) 0%, transparent 60%)",
|
|
1315
1376
|
pointerEvents: "none"
|
|
1316
|
-
}}
|
|
1317
|
-
|
|
1377
|
+
} }),
|
|
1378
|
+
/* @__PURE__ */ jsx9("div", { style: {
|
|
1318
1379
|
position: "absolute",
|
|
1319
1380
|
bottom: "8px",
|
|
1320
1381
|
left: "8px",
|
|
@@ -1327,50 +1388,54 @@ var PDFEmbedBlock = createReactBlockSpec6(
|
|
|
1327
1388
|
color: "#c4b5fd",
|
|
1328
1389
|
letterSpacing: "0.5px",
|
|
1329
1390
|
textTransform: "uppercase"
|
|
1330
|
-
}}
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1391
|
+
}, children: "PDF" })
|
|
1392
|
+
] }),
|
|
1393
|
+
/* @__PURE__ */ jsxs8("div", { style: { flex: 1, padding: "16px", display: "flex", flexDirection: "column", justifyContent: "space-between" }, children: [
|
|
1394
|
+
/* @__PURE__ */ jsxs8("div", { children: [
|
|
1395
|
+
/* @__PURE__ */ jsxs8("div", { style: { display: "flex", alignItems: "center", gap: "8px", marginBottom: "8px" }, children: [
|
|
1396
|
+
/* @__PURE__ */ jsxs8("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "#9b7bf7", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1397
|
+
/* @__PURE__ */ jsx9("path", { d: "M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" }),
|
|
1398
|
+
/* @__PURE__ */ jsx9("polyline", { points: "14 2 14 8 20 8" })
|
|
1399
|
+
] }),
|
|
1400
|
+
/* @__PURE__ */ jsx9("span", { style: { fontSize: "14px", fontWeight: 600, color: "var(--text-primary)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: title || "Document" })
|
|
1401
|
+
] }),
|
|
1402
|
+
/* @__PURE__ */ jsxs8("div", { style: { display: "flex", gap: "12px", flexWrap: "wrap" }, children: [
|
|
1403
|
+
fileSize && /* @__PURE__ */ jsxs8("span", { style: { fontSize: "12px", color: "var(--text-muted)", display: "flex", alignItems: "center", gap: "4px" }, children: [
|
|
1404
|
+
/* @__PURE__ */ jsx9("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx9("path", { d: "M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3" }) }),
|
|
1405
|
+
fileSize
|
|
1406
|
+
] }),
|
|
1407
|
+
pageCount && /* @__PURE__ */ jsxs8("span", { style: { fontSize: "12px", color: "var(--text-muted)", display: "flex", alignItems: "center", gap: "4px" }, children: [
|
|
1408
|
+
/* @__PURE__ */ jsxs8("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
1409
|
+
/* @__PURE__ */ jsx9("path", { d: "M4 19.5A2.5 2.5 0 016.5 17H20" }),
|
|
1410
|
+
/* @__PURE__ */ jsx9("path", { d: "M6.5 2H20v20H6.5A2.5 2.5 0 014 19.5v-15A2.5 2.5 0 016.5 2z" })
|
|
1411
|
+
] }),
|
|
1412
|
+
pageCount,
|
|
1413
|
+
" pages"
|
|
1414
|
+
] })
|
|
1415
|
+
] })
|
|
1416
|
+
] }),
|
|
1417
|
+
/* @__PURE__ */ jsxs8("div", { style: { display: "flex", gap: "8px", marginTop: "12px" }, children: [
|
|
1418
|
+
/* @__PURE__ */ jsx9(
|
|
1419
|
+
"a",
|
|
1420
|
+
{
|
|
1421
|
+
href: url,
|
|
1422
|
+
target: "_blank",
|
|
1423
|
+
rel: "noopener noreferrer",
|
|
1424
|
+
style: {
|
|
1425
|
+
padding: "6px 12px",
|
|
1426
|
+
background: "rgba(155,123,247,0.1)",
|
|
1427
|
+
border: "1px solid rgba(155,123,247,0.25)",
|
|
1428
|
+
borderRadius: "6px",
|
|
1429
|
+
fontSize: "12px",
|
|
1430
|
+
color: "#a78bfa",
|
|
1431
|
+
fontWeight: 500,
|
|
1432
|
+
textDecoration: "none",
|
|
1433
|
+
cursor: "pointer"
|
|
1434
|
+
},
|
|
1435
|
+
children: "Open PDF"
|
|
1436
|
+
}
|
|
1437
|
+
),
|
|
1438
|
+
/* @__PURE__ */ jsx9("button", { onClick: handleReplace, style: {
|
|
1374
1439
|
padding: "6px 12px",
|
|
1375
1440
|
background: "rgba(255,255,255,0.04)",
|
|
1376
1441
|
border: "1px solid #232d3f",
|
|
@@ -1378,8 +1443,8 @@ var PDFEmbedBlock = createReactBlockSpec6(
|
|
|
1378
1443
|
fontSize: "12px",
|
|
1379
1444
|
color: "var(--text-muted)",
|
|
1380
1445
|
cursor: "pointer"
|
|
1381
|
-
}}
|
|
1382
|
-
|
|
1446
|
+
}, children: "Replace" }),
|
|
1447
|
+
/* @__PURE__ */ jsx9("button", { onClick: handleDelete, style: {
|
|
1383
1448
|
padding: "6px 12px",
|
|
1384
1449
|
background: "rgba(248,113,113,0.06)",
|
|
1385
1450
|
border: "1px solid rgba(248,113,113,0.2)",
|
|
@@ -1387,29 +1452,27 @@ var PDFEmbedBlock = createReactBlockSpec6(
|
|
|
1387
1452
|
fontSize: "12px",
|
|
1388
1453
|
color: "#f87171",
|
|
1389
1454
|
cursor: "pointer"
|
|
1390
|
-
}}
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1455
|
+
}, children: "Delete" })
|
|
1456
|
+
] })
|
|
1457
|
+
] })
|
|
1458
|
+
] });
|
|
1394
1459
|
}
|
|
1395
1460
|
}
|
|
1396
1461
|
);
|
|
1397
1462
|
|
|
1398
1463
|
// src/editor/LinkPreviewTooltip.jsx
|
|
1399
1464
|
import { useState as useState9, useEffect as useEffect8, useRef as useRef7, useCallback as useCallback6 } from "react";
|
|
1400
|
-
|
|
1465
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1401
1466
|
var previewCache = /* @__PURE__ */ new Map();
|
|
1402
1467
|
var linkPreviewEndpoint = "/api/link-preview";
|
|
1403
1468
|
function setLinkPreviewEndpoint(endpoint) {
|
|
1404
1469
|
linkPreviewEndpoint = endpoint;
|
|
1405
1470
|
}
|
|
1406
1471
|
async function fetchPreview(url) {
|
|
1407
|
-
if (previewCache.has(url))
|
|
1408
|
-
return previewCache.get(url);
|
|
1472
|
+
if (previewCache.has(url)) return previewCache.get(url);
|
|
1409
1473
|
try {
|
|
1410
1474
|
const res = await fetch(`${linkPreviewEndpoint}?url=${encodeURIComponent(url)}`);
|
|
1411
|
-
if (!res.ok)
|
|
1412
|
-
throw new Error("fetch failed");
|
|
1475
|
+
if (!res.ok) throw new Error("fetch failed");
|
|
1413
1476
|
const data = await res.json();
|
|
1414
1477
|
previewCache.set(url, data);
|
|
1415
1478
|
return data;
|
|
@@ -1426,8 +1489,7 @@ function LinkPreviewTooltip({ anchorEl, url, onClose }) {
|
|
|
1426
1489
|
const hoverRef = useRef7(false);
|
|
1427
1490
|
const hideTimerRef = useRef7(null);
|
|
1428
1491
|
useEffect8(() => {
|
|
1429
|
-
if (!url)
|
|
1430
|
-
return;
|
|
1492
|
+
if (!url) return;
|
|
1431
1493
|
setLoading(true);
|
|
1432
1494
|
fetchPreview(url).then((d) => {
|
|
1433
1495
|
setData(d);
|
|
@@ -1451,13 +1513,11 @@ function LinkPreviewTooltip({ anchorEl, url, onClose }) {
|
|
|
1451
1513
|
const scheduleHide = useCallback6(() => {
|
|
1452
1514
|
clearTimeout(hideTimerRef.current);
|
|
1453
1515
|
hideTimerRef.current = setTimeout(() => {
|
|
1454
|
-
if (!hoverRef.current)
|
|
1455
|
-
onClose();
|
|
1516
|
+
if (!hoverRef.current) onClose();
|
|
1456
1517
|
}, 200);
|
|
1457
1518
|
}, [onClose]);
|
|
1458
1519
|
useEffect8(() => {
|
|
1459
|
-
if (!anchorEl)
|
|
1460
|
-
return;
|
|
1520
|
+
if (!anchorEl) return;
|
|
1461
1521
|
const onEnter = () => {
|
|
1462
1522
|
hoverRef.current = true;
|
|
1463
1523
|
clearTimeout(hideTimerRef.current);
|
|
@@ -1484,34 +1544,37 @@ function LinkPreviewTooltip({ anchorEl, url, onClose }) {
|
|
|
1484
1544
|
useEffect8(() => {
|
|
1485
1545
|
return () => clearTimeout(hideTimerRef.current);
|
|
1486
1546
|
}, []);
|
|
1487
|
-
if (!url || !posRef.current)
|
|
1488
|
-
return null;
|
|
1547
|
+
if (!url || !posRef.current) return null;
|
|
1489
1548
|
const style = posRef.current.useBottom ? { bottom: posRef.current.bottom, left: posRef.current.left } : { top: posRef.current.top, left: posRef.current.left };
|
|
1490
|
-
return
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
<div className="link-preview-body">
|
|
1505
|
-
<div className="link-preview-title">{data.title}</div>
|
|
1506
|
-
{data.description && <div className="link-preview-desc">{data.description.length > 120 ? data.description.slice(0, 120) + "..." : data.description}</div>}
|
|
1507
|
-
<div className="link-preview-domain">
|
|
1508
|
-
{data.favicon && <img src={data.favicon} alt="" className="link-preview-favicon" onError={(e) => {
|
|
1549
|
+
return /* @__PURE__ */ jsx10(
|
|
1550
|
+
"div",
|
|
1551
|
+
{
|
|
1552
|
+
ref: tooltipRef,
|
|
1553
|
+
className: "link-preview-tooltip",
|
|
1554
|
+
style,
|
|
1555
|
+
onMouseEnter: onTooltipEnter,
|
|
1556
|
+
onMouseLeave: onTooltipLeave,
|
|
1557
|
+
children: loading ? /* @__PURE__ */ jsxs9("div", { className: "link-preview-loading", children: [
|
|
1558
|
+
/* @__PURE__ */ jsx10("div", { className: "link-preview-skeleton", style: { width: "60%", height: 12 } }),
|
|
1559
|
+
/* @__PURE__ */ jsx10("div", { className: "link-preview-skeleton", style: { width: "90%", height: 10, marginTop: 8 } }),
|
|
1560
|
+
/* @__PURE__ */ jsx10("div", { className: "link-preview-skeleton", style: { width: "40%", height: 10, marginTop: 4 } })
|
|
1561
|
+
] }) : data ? /* @__PURE__ */ jsxs9("a", { href: url, target: "_blank", rel: "noopener noreferrer", className: "link-preview-card", children: [
|
|
1562
|
+
data.image && /* @__PURE__ */ jsx10("div", { className: "link-preview-image", children: /* @__PURE__ */ jsx10("img", { src: data.image, alt: "", onError: (e) => {
|
|
1509
1563
|
e.target.style.display = "none";
|
|
1510
|
-
}}
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1564
|
+
} }) }),
|
|
1565
|
+
/* @__PURE__ */ jsxs9("div", { className: "link-preview-body", children: [
|
|
1566
|
+
/* @__PURE__ */ jsx10("div", { className: "link-preview-title", children: data.title }),
|
|
1567
|
+
data.description && /* @__PURE__ */ jsx10("div", { className: "link-preview-desc", children: data.description.length > 120 ? data.description.slice(0, 120) + "..." : data.description }),
|
|
1568
|
+
/* @__PURE__ */ jsxs9("div", { className: "link-preview-domain", children: [
|
|
1569
|
+
data.favicon && /* @__PURE__ */ jsx10("img", { src: data.favicon, alt: "", className: "link-preview-favicon", onError: (e) => {
|
|
1570
|
+
e.target.style.display = "none";
|
|
1571
|
+
} }),
|
|
1572
|
+
/* @__PURE__ */ jsx10("span", { children: data.domain })
|
|
1573
|
+
] })
|
|
1574
|
+
] })
|
|
1575
|
+
] }) : null
|
|
1576
|
+
}
|
|
1577
|
+
);
|
|
1515
1578
|
}
|
|
1516
1579
|
function useLinkPreview() {
|
|
1517
1580
|
const [preview, setPreview] = useState9(null);
|
|
@@ -1536,7 +1599,7 @@ function useLinkPreview() {
|
|
|
1536
1599
|
}
|
|
1537
1600
|
|
|
1538
1601
|
// src/editor/LixEditor.jsx
|
|
1539
|
-
|
|
1602
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1540
1603
|
var DEFAULT_LANGUAGES = {
|
|
1541
1604
|
text: { name: "Text" },
|
|
1542
1605
|
javascript: { name: "JavaScript", aliases: ["js"] },
|
|
@@ -1612,38 +1675,26 @@ var LixEditor = forwardRef(function LixEditor2({
|
|
|
1612
1675
|
}) : void 0;
|
|
1613
1676
|
const schema = useMemo(() => {
|
|
1614
1677
|
const blockSpecs = { ...defaultBlockSpecs };
|
|
1615
|
-
if (codeBlock)
|
|
1616
|
-
|
|
1617
|
-
if (f.
|
|
1618
|
-
|
|
1619
|
-
if (f.
|
|
1620
|
-
|
|
1621
|
-
if (f.
|
|
1622
|
-
blockSpecs.tableOfContents = TableOfContents({});
|
|
1623
|
-
if (f.images)
|
|
1624
|
-
blockSpecs.image = BlogImageBlock({});
|
|
1625
|
-
if (f.buttons)
|
|
1626
|
-
blockSpecs.buttonBlock = ButtonBlock({});
|
|
1627
|
-
if (f.pdf)
|
|
1628
|
-
blockSpecs.pdfEmbed = PDFEmbedBlock({});
|
|
1678
|
+
if (codeBlock) blockSpecs.codeBlock = codeBlock;
|
|
1679
|
+
if (f.equations) blockSpecs.blockEquation = BlockEquation({});
|
|
1680
|
+
if (f.mermaid) blockSpecs.mermaidBlock = MermaidBlock({});
|
|
1681
|
+
if (f.tableOfContents) blockSpecs.tableOfContents = TableOfContents({});
|
|
1682
|
+
if (f.images) blockSpecs.image = BlogImageBlock({});
|
|
1683
|
+
if (f.buttons) blockSpecs.buttonBlock = ButtonBlock({});
|
|
1684
|
+
if (f.pdf) blockSpecs.pdfEmbed = PDFEmbedBlock({});
|
|
1629
1685
|
for (const spec of extraBlockSpecs) {
|
|
1630
|
-
if (spec.type && spec.spec)
|
|
1631
|
-
blockSpecs[spec.type] = spec.spec;
|
|
1686
|
+
if (spec.type && spec.spec) blockSpecs[spec.type] = spec.spec;
|
|
1632
1687
|
}
|
|
1633
1688
|
const inlineContentSpecs = { ...defaultInlineContentSpecs };
|
|
1634
|
-
if (f.equations)
|
|
1635
|
-
|
|
1636
|
-
if (f.dates)
|
|
1637
|
-
inlineContentSpecs.dateInline = DateInline;
|
|
1689
|
+
if (f.equations) inlineContentSpecs.inlineEquation = InlineEquation;
|
|
1690
|
+
if (f.dates) inlineContentSpecs.dateInline = DateInline;
|
|
1638
1691
|
for (const spec of extraInlineSpecs) {
|
|
1639
|
-
if (spec.type && spec.spec)
|
|
1640
|
-
inlineContentSpecs[spec.type] = spec.spec;
|
|
1692
|
+
if (spec.type && spec.spec) inlineContentSpecs[spec.type] = spec.spec;
|
|
1641
1693
|
}
|
|
1642
1694
|
return BlockNoteSchema.create({ blockSpecs, inlineContentSpecs });
|
|
1643
1695
|
}, []);
|
|
1644
1696
|
const sanitized = useMemo(() => {
|
|
1645
|
-
if (!initialContent)
|
|
1646
|
-
return void 0;
|
|
1697
|
+
if (!initialContent) return void 0;
|
|
1647
1698
|
let blocks = initialContent;
|
|
1648
1699
|
if (typeof blocks === "string") {
|
|
1649
1700
|
try {
|
|
@@ -1652,8 +1703,7 @@ var LixEditor = forwardRef(function LixEditor2({
|
|
|
1652
1703
|
return void 0;
|
|
1653
1704
|
}
|
|
1654
1705
|
}
|
|
1655
|
-
if (!Array.isArray(blocks) || blocks.length === 0)
|
|
1656
|
-
return void 0;
|
|
1706
|
+
if (!Array.isArray(blocks) || blocks.length === 0) return void 0;
|
|
1657
1707
|
return blocks;
|
|
1658
1708
|
}, [initialContent]);
|
|
1659
1709
|
const editor = useCreateBlockNote({
|
|
@@ -1670,15 +1720,12 @@ var LixEditor = forwardRef(function LixEditor2({
|
|
|
1670
1720
|
getMarkdown: async () => await editor.blocksToMarkdownLossy(editor.document)
|
|
1671
1721
|
}), [editor]);
|
|
1672
1722
|
useEffect9(() => {
|
|
1673
|
-
if (onReady)
|
|
1674
|
-
onReady();
|
|
1723
|
+
if (onReady) onReady();
|
|
1675
1724
|
}, []);
|
|
1676
1725
|
useEffect9(() => {
|
|
1677
|
-
if (!f.markdownLinks || !editor)
|
|
1678
|
-
return;
|
|
1726
|
+
if (!f.markdownLinks || !editor) return;
|
|
1679
1727
|
const tiptap = editor._tiptapEditor;
|
|
1680
|
-
if (!tiptap)
|
|
1681
|
-
return;
|
|
1728
|
+
if (!tiptap) return;
|
|
1682
1729
|
const handleInput = () => {
|
|
1683
1730
|
const { state, view } = tiptap;
|
|
1684
1731
|
const { $from } = state.selection;
|
|
@@ -1706,8 +1753,7 @@ var LixEditor = forwardRef(function LixEditor2({
|
|
|
1706
1753
|
return;
|
|
1707
1754
|
}
|
|
1708
1755
|
const match = textBefore.match(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)$/);
|
|
1709
|
-
if (!match)
|
|
1710
|
-
return;
|
|
1756
|
+
if (!match) return;
|
|
1711
1757
|
const [fullMatch, linkText, url] = match;
|
|
1712
1758
|
const from = $from.pos - fullMatch.length;
|
|
1713
1759
|
const linkMark = state.schema.marks.link.create({ href: url });
|
|
@@ -1718,31 +1764,24 @@ var LixEditor = forwardRef(function LixEditor2({
|
|
|
1718
1764
|
return () => tiptap.off("update", handleInput);
|
|
1719
1765
|
}, [editor, f.markdownLinks]);
|
|
1720
1766
|
useEffect9(() => {
|
|
1721
|
-
if (!f.linkPreview)
|
|
1722
|
-
return;
|
|
1767
|
+
if (!f.linkPreview) return;
|
|
1723
1768
|
const wrapper = wrapperRef.current;
|
|
1724
|
-
if (!wrapper)
|
|
1725
|
-
return;
|
|
1769
|
+
if (!wrapper) return;
|
|
1726
1770
|
const handleMouseOver = (e) => {
|
|
1727
1771
|
const link = e.target.closest("a[href]");
|
|
1728
|
-
if (!link || link.closest(".bn-link-toolbar") || link.closest(".bn-toolbar"))
|
|
1729
|
-
return;
|
|
1772
|
+
if (!link || link.closest(".bn-link-toolbar") || link.closest(".bn-toolbar")) return;
|
|
1730
1773
|
const href = link.getAttribute("href");
|
|
1731
|
-
if (href && href.startsWith("http"))
|
|
1732
|
-
editorLinkPreview.show(link, href);
|
|
1774
|
+
if (href && href.startsWith("http")) editorLinkPreview.show(link, href);
|
|
1733
1775
|
};
|
|
1734
1776
|
const handleMouseOut = (e) => {
|
|
1735
1777
|
const link = e.target.closest("a[href]");
|
|
1736
|
-
if (!link)
|
|
1737
|
-
return;
|
|
1778
|
+
if (!link) return;
|
|
1738
1779
|
editorLinkPreview.cancel();
|
|
1739
1780
|
};
|
|
1740
1781
|
const handleClick = (e) => {
|
|
1741
|
-
if (!(e.ctrlKey || e.metaKey))
|
|
1742
|
-
return;
|
|
1782
|
+
if (!(e.ctrlKey || e.metaKey)) return;
|
|
1743
1783
|
const link = e.target.closest("a[href]");
|
|
1744
|
-
if (!link || link.closest(".bn-link-toolbar"))
|
|
1745
|
-
return;
|
|
1784
|
+
if (!link || link.closest(".bn-link-toolbar")) return;
|
|
1746
1785
|
const href = link.getAttribute("href");
|
|
1747
1786
|
if (href && href.startsWith("http")) {
|
|
1748
1787
|
e.preventDefault();
|
|
@@ -1751,8 +1790,7 @@ var LixEditor = forwardRef(function LixEditor2({
|
|
|
1751
1790
|
}
|
|
1752
1791
|
};
|
|
1753
1792
|
const handleKeyDown = (e) => {
|
|
1754
|
-
if (e.ctrlKey || e.metaKey)
|
|
1755
|
-
wrapper.classList.add("ctrl-held");
|
|
1793
|
+
if (e.ctrlKey || e.metaKey) wrapper.classList.add("ctrl-held");
|
|
1756
1794
|
};
|
|
1757
1795
|
const handleKeyUp = () => wrapper.classList.remove("ctrl-held");
|
|
1758
1796
|
wrapper.addEventListener("mouseover", handleMouseOver);
|
|
@@ -1776,7 +1814,7 @@ var LixEditor = forwardRef(function LixEditor2({
|
|
|
1776
1814
|
title: "Block Equation",
|
|
1777
1815
|
subtext: "LaTeX block equation",
|
|
1778
1816
|
group: "Advanced",
|
|
1779
|
-
icon:
|
|
1817
|
+
icon: /* @__PURE__ */ jsx11("span", { style: { fontSize: 16 }, children: "\u2211" }),
|
|
1780
1818
|
onItemClick: () => editor.insertBlocks([{ type: "blockEquation" }], editor.getTextCursorPosition().block, "after")
|
|
1781
1819
|
});
|
|
1782
1820
|
}
|
|
@@ -1785,7 +1823,7 @@ var LixEditor = forwardRef(function LixEditor2({
|
|
|
1785
1823
|
title: "Diagram",
|
|
1786
1824
|
subtext: "Mermaid diagram (flowchart, sequence, etc.)",
|
|
1787
1825
|
group: "Advanced",
|
|
1788
|
-
icon:
|
|
1826
|
+
icon: /* @__PURE__ */ jsx11("span", { style: { fontSize: 14 }, children: "\u25C7" }),
|
|
1789
1827
|
onItemClick: () => editor.insertBlocks([{ type: "mermaidBlock" }], editor.getTextCursorPosition().block, "after")
|
|
1790
1828
|
});
|
|
1791
1829
|
}
|
|
@@ -1794,33 +1832,39 @@ var LixEditor = forwardRef(function LixEditor2({
|
|
|
1794
1832
|
title: "Table of Contents",
|
|
1795
1833
|
subtext: "Auto-generated document outline",
|
|
1796
1834
|
group: "Advanced",
|
|
1797
|
-
icon:
|
|
1835
|
+
icon: /* @__PURE__ */ jsx11("span", { style: { fontSize: 14 }, children: "\u2630" }),
|
|
1798
1836
|
onItemClick: () => editor.insertBlocks([{ type: "tableOfContents" }], editor.getTextCursorPosition().block, "after")
|
|
1799
1837
|
});
|
|
1800
1838
|
}
|
|
1801
1839
|
return [...defaults, ...custom, ...extraSlashItems].filter((item) => item.title.toLowerCase().includes(query.toLowerCase()));
|
|
1802
1840
|
}, [editor, f, extraSlashItems]);
|
|
1803
1841
|
const handleChange = useCallback7(() => {
|
|
1804
|
-
if (onChange)
|
|
1805
|
-
onChange(editor);
|
|
1842
|
+
if (onChange) onChange(editor);
|
|
1806
1843
|
}, [editor, onChange]);
|
|
1807
|
-
return
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1844
|
+
return /* @__PURE__ */ jsxs10("div", { className: `lix-editor-wrapper${""}`, ref: wrapperRef, style: { position: "relative" }, children: [
|
|
1845
|
+
/* @__PURE__ */ jsxs10(
|
|
1846
|
+
BlockNoteView,
|
|
1847
|
+
{
|
|
1848
|
+
editor,
|
|
1849
|
+
onChange: handleChange,
|
|
1850
|
+
theme: isDark ? "dark" : "light",
|
|
1851
|
+
slashMenu: false,
|
|
1852
|
+
children: [
|
|
1853
|
+
/* @__PURE__ */ jsx11(SuggestionMenuController, { triggerCharacter: "/", getItems }),
|
|
1854
|
+
/* @__PURE__ */ jsx11(TableHandlesController, {}),
|
|
1855
|
+
children
|
|
1856
|
+
]
|
|
1857
|
+
}
|
|
1858
|
+
),
|
|
1859
|
+
f.linkPreview && editorLinkPreview.preview && /* @__PURE__ */ jsx11(
|
|
1860
|
+
LinkPreviewTooltip,
|
|
1861
|
+
{
|
|
1862
|
+
anchorEl: editorLinkPreview.preview.anchorEl,
|
|
1863
|
+
url: editorLinkPreview.preview.url,
|
|
1864
|
+
onClose: editorLinkPreview.hide
|
|
1865
|
+
}
|
|
1866
|
+
)
|
|
1867
|
+
] });
|
|
1824
1868
|
});
|
|
1825
1869
|
var LixEditor_default = LixEditor;
|
|
1826
1870
|
|
|
@@ -1829,11 +1873,9 @@ import { useEffect as useEffect10, useRef as useRef9, useState as useState11, us
|
|
|
1829
1873
|
|
|
1830
1874
|
// src/preview/renderBlocks.js
|
|
1831
1875
|
function renderBlocksToHTML(blocks) {
|
|
1832
|
-
if (!blocks || !blocks.length)
|
|
1833
|
-
return "";
|
|
1876
|
+
if (!blocks || !blocks.length) return "";
|
|
1834
1877
|
function inlineToHTML(content) {
|
|
1835
|
-
if (!content || !Array.isArray(content))
|
|
1836
|
-
return "";
|
|
1878
|
+
if (!content || !Array.isArray(content)) return "";
|
|
1837
1879
|
return content.map((c) => {
|
|
1838
1880
|
if (c.type === "inlineEquation" && c.props?.latex) {
|
|
1839
1881
|
return `<span class="lix-inline-equation" data-latex="${encodeURIComponent(c.props.latex)}"></span>`;
|
|
@@ -1852,23 +1894,15 @@ function renderBlocksToHTML(blocks) {
|
|
|
1852
1894
|
return `<a href="${c.href}">${linkText || c.href}</a>`;
|
|
1853
1895
|
}
|
|
1854
1896
|
let text = (c.text || "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1855
|
-
if (!text)
|
|
1856
|
-
return "";
|
|
1897
|
+
if (!text) return "";
|
|
1857
1898
|
const s = c.styles || {};
|
|
1858
|
-
if (s.bold)
|
|
1859
|
-
|
|
1860
|
-
if (s.
|
|
1861
|
-
|
|
1862
|
-
if (s.
|
|
1863
|
-
|
|
1864
|
-
if (s.
|
|
1865
|
-
text = `<code>${text}</code>`;
|
|
1866
|
-
if (s.underline)
|
|
1867
|
-
text = `<u>${text}</u>`;
|
|
1868
|
-
if (s.textColor)
|
|
1869
|
-
text = `<span style="color:${s.textColor}">${text}</span>`;
|
|
1870
|
-
if (s.backgroundColor)
|
|
1871
|
-
text = `<span style="background:${s.backgroundColor};border-radius:3px;padding:0 2px">${text}</span>`;
|
|
1899
|
+
if (s.bold) text = `<strong>${text}</strong>`;
|
|
1900
|
+
if (s.italic) text = `<em>${text}</em>`;
|
|
1901
|
+
if (s.strike) text = `<del>${text}</del>`;
|
|
1902
|
+
if (s.code) text = `<code>${text}</code>`;
|
|
1903
|
+
if (s.underline) text = `<u>${text}</u>`;
|
|
1904
|
+
if (s.textColor) text = `<span style="color:${s.textColor}">${text}</span>`;
|
|
1905
|
+
if (s.backgroundColor) text = `<span style="background:${s.backgroundColor};border-radius:3px;padding:0 2px">${text}</span>`;
|
|
1872
1906
|
return text;
|
|
1873
1907
|
}).join("");
|
|
1874
1908
|
}
|
|
@@ -1882,8 +1916,7 @@ function renderBlocksToHTML(blocks) {
|
|
|
1882
1916
|
headings.push({ id, text: text.trim(), level: block.props?.level || 1 });
|
|
1883
1917
|
}
|
|
1884
1918
|
}
|
|
1885
|
-
if (block.children?.length)
|
|
1886
|
-
collectHeadings(block.children);
|
|
1919
|
+
if (block.children?.length) collectHeadings(block.children);
|
|
1887
1920
|
}
|
|
1888
1921
|
}
|
|
1889
1922
|
collectHeadings(blocks);
|
|
@@ -1909,12 +1942,10 @@ function renderBlocksToHTML(blocks) {
|
|
|
1909
1942
|
return `<li class="lix-check${checked ? " lix-check--checked" : ""}">${cb}<span class="lix-check-text">${content}</span>${childrenHTML}</li>`;
|
|
1910
1943
|
}
|
|
1911
1944
|
case "blockEquation":
|
|
1912
|
-
if (block.props?.latex)
|
|
1913
|
-
return `<div class="lix-block-equation" data-latex="${encodeURIComponent(block.props.latex)}"></div>${childrenHTML}`;
|
|
1945
|
+
if (block.props?.latex) return `<div class="lix-block-equation" data-latex="${encodeURIComponent(block.props.latex)}"></div>${childrenHTML}`;
|
|
1914
1946
|
return childrenHTML;
|
|
1915
1947
|
case "mermaidBlock":
|
|
1916
|
-
if (block.props?.diagram)
|
|
1917
|
-
return `<div class="lix-mermaid-block" data-diagram="${encodeURIComponent(block.props.diagram)}"></div>${childrenHTML}`;
|
|
1948
|
+
if (block.props?.diagram) return `<div class="lix-mermaid-block" data-diagram="${encodeURIComponent(block.props.diagram)}"></div>${childrenHTML}`;
|
|
1918
1949
|
return childrenHTML;
|
|
1919
1950
|
case "divider":
|
|
1920
1951
|
return `<hr class="lix-divider" />${childrenHTML}`;
|
|
@@ -1930,8 +1961,7 @@ function renderBlocksToHTML(blocks) {
|
|
|
1930
1961
|
return childrenHTML;
|
|
1931
1962
|
case "table": {
|
|
1932
1963
|
const rows = block.content?.rows || [];
|
|
1933
|
-
if (!rows.length)
|
|
1934
|
-
return childrenHTML;
|
|
1964
|
+
if (!rows.length) return childrenHTML;
|
|
1935
1965
|
const headerRows = block.content?.headerRows || 0;
|
|
1936
1966
|
let table = "<table>";
|
|
1937
1967
|
rows.forEach((row, ri) => {
|
|
@@ -1939,12 +1969,9 @@ function renderBlocksToHTML(blocks) {
|
|
|
1939
1969
|
(row.cells || []).forEach((cell) => {
|
|
1940
1970
|
const tag = ri < headerRows ? "th" : "td";
|
|
1941
1971
|
let cellContent;
|
|
1942
|
-
if (Array.isArray(cell))
|
|
1943
|
-
|
|
1944
|
-
else
|
|
1945
|
-
cellContent = Array.isArray(cell.content) ? cell.content : [];
|
|
1946
|
-
else
|
|
1947
|
-
cellContent = [];
|
|
1972
|
+
if (Array.isArray(cell)) cellContent = cell;
|
|
1973
|
+
else if (cell?.content) cellContent = Array.isArray(cell.content) ? cell.content : [];
|
|
1974
|
+
else cellContent = [];
|
|
1948
1975
|
table += `<${tag}>${inlineToHTML(cellContent)}</${tag}>`;
|
|
1949
1976
|
});
|
|
1950
1977
|
table += "</tr>";
|
|
@@ -1954,14 +1981,12 @@ function renderBlocksToHTML(blocks) {
|
|
|
1954
1981
|
}
|
|
1955
1982
|
case "paragraph":
|
|
1956
1983
|
default:
|
|
1957
|
-
if (content)
|
|
1958
|
-
return `<p>${content}</p>${childrenHTML}`;
|
|
1984
|
+
if (content) return `<p>${content}</p>${childrenHTML}`;
|
|
1959
1985
|
return childrenHTML || "";
|
|
1960
1986
|
}
|
|
1961
1987
|
}
|
|
1962
1988
|
function renderListGroup(blockList) {
|
|
1963
|
-
if (!blockList?.length)
|
|
1964
|
-
return "";
|
|
1989
|
+
if (!blockList?.length) return "";
|
|
1965
1990
|
const out = [];
|
|
1966
1991
|
let i = 0;
|
|
1967
1992
|
while (i < blockList.length) {
|
|
@@ -2009,7 +2034,7 @@ function renderBlocksToHTML(blocks) {
|
|
|
2009
2034
|
}
|
|
2010
2035
|
|
|
2011
2036
|
// src/preview/LixPreview.jsx
|
|
2012
|
-
|
|
2037
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2013
2038
|
function LixPreview({ blocks, html, features = {}, className = "" }) {
|
|
2014
2039
|
const { isDark } = useLixTheme();
|
|
2015
2040
|
const contentRef = useRef9(null);
|
|
@@ -2027,8 +2052,7 @@ function LixPreview({ blocks, html, features = {}, className = "" }) {
|
|
|
2027
2052
|
const effectGenRef = useRef9(0);
|
|
2028
2053
|
useEffect10(() => {
|
|
2029
2054
|
const root = contentRef.current;
|
|
2030
|
-
if (!root)
|
|
2031
|
-
return;
|
|
2055
|
+
if (!root) return;
|
|
2032
2056
|
const gen = ++effectGenRef.current;
|
|
2033
2057
|
root.innerHTML = renderedHTML || "";
|
|
2034
2058
|
function isStale() {
|
|
@@ -2039,24 +2063,18 @@ function LixPreview({ blocks, html, features = {}, className = "" }) {
|
|
|
2039
2063
|
const inlineEls = root.querySelectorAll(".lix-inline-equation[data-latex]");
|
|
2040
2064
|
if (eqEls.length || inlineEls.length) {
|
|
2041
2065
|
import("katex").then((mod) => {
|
|
2042
|
-
if (isStale())
|
|
2043
|
-
return;
|
|
2066
|
+
if (isStale()) return;
|
|
2044
2067
|
const katex3 = mod.default || mod;
|
|
2045
2068
|
const strip = (raw) => {
|
|
2046
2069
|
let s = raw.trim();
|
|
2047
|
-
if (s.startsWith("\\[") && s.endsWith("\\]"))
|
|
2048
|
-
|
|
2049
|
-
if (s.startsWith("
|
|
2050
|
-
|
|
2051
|
-
if (s.startsWith("\\(") && s.endsWith("\\)"))
|
|
2052
|
-
return s.slice(2, -2).trim();
|
|
2053
|
-
if (s.startsWith("$") && s.endsWith("$") && s.length > 2)
|
|
2054
|
-
return s.slice(1, -1).trim();
|
|
2070
|
+
if (s.startsWith("\\[") && s.endsWith("\\]")) return s.slice(2, -2).trim();
|
|
2071
|
+
if (s.startsWith("$$") && s.endsWith("$$")) return s.slice(2, -2).trim();
|
|
2072
|
+
if (s.startsWith("\\(") && s.endsWith("\\)")) return s.slice(2, -2).trim();
|
|
2073
|
+
if (s.startsWith("$") && s.endsWith("$") && s.length > 2) return s.slice(1, -1).trim();
|
|
2055
2074
|
return s;
|
|
2056
2075
|
};
|
|
2057
2076
|
eqEls.forEach((el) => {
|
|
2058
|
-
if (!el.isConnected)
|
|
2059
|
-
return;
|
|
2077
|
+
if (!el.isConnected) return;
|
|
2060
2078
|
try {
|
|
2061
2079
|
el.innerHTML = katex3.renderToString(strip(decodeURIComponent(el.dataset.latex)), { displayMode: true, throwOnError: false });
|
|
2062
2080
|
} catch (err) {
|
|
@@ -2064,8 +2082,7 @@ function LixPreview({ blocks, html, features = {}, className = "" }) {
|
|
|
2064
2082
|
}
|
|
2065
2083
|
});
|
|
2066
2084
|
inlineEls.forEach((el) => {
|
|
2067
|
-
if (!el.isConnected)
|
|
2068
|
-
return;
|
|
2085
|
+
if (!el.isConnected) return;
|
|
2069
2086
|
try {
|
|
2070
2087
|
el.innerHTML = katex3.renderToString(strip(decodeURIComponent(el.dataset.latex)), { displayMode: false, throwOnError: false });
|
|
2071
2088
|
} catch (err) {
|
|
@@ -2080,8 +2097,7 @@ function LixPreview({ blocks, html, features = {}, className = "" }) {
|
|
|
2080
2097
|
const mermaidEls = root.querySelectorAll(".lix-mermaid-block[data-diagram]");
|
|
2081
2098
|
if (mermaidEls.length) {
|
|
2082
2099
|
import("mermaid").then((mod) => {
|
|
2083
|
-
if (isStale())
|
|
2084
|
-
return;
|
|
2100
|
+
if (isStale()) return;
|
|
2085
2101
|
const mermaid = mod.default || mod;
|
|
2086
2102
|
mermaid.initialize({
|
|
2087
2103
|
startOnLoad: false,
|
|
@@ -2110,8 +2126,7 @@ function LixPreview({ blocks, html, features = {}, className = "" }) {
|
|
|
2110
2126
|
}
|
|
2111
2127
|
}
|
|
2112
2128
|
} catch (err) {
|
|
2113
|
-
if (el.isConnected)
|
|
2114
|
-
el.innerHTML = `<pre style="color:#f87171;font-size:12px">${err.message || "Diagram error"}</pre>`;
|
|
2129
|
+
if (el.isConnected) el.innerHTML = `<pre style="color:#f87171;font-size:12px">${err.message || "Diagram error"}</pre>`;
|
|
2115
2130
|
try {
|
|
2116
2131
|
document.getElementById(id)?.remove();
|
|
2117
2132
|
document.getElementById("c-" + id)?.remove();
|
|
@@ -2128,22 +2143,18 @@ function LixPreview({ blocks, html, features = {}, className = "" }) {
|
|
|
2128
2143
|
const codeEls = root.querySelectorAll('pre > code[class*="language-"]');
|
|
2129
2144
|
if (codeEls.length) {
|
|
2130
2145
|
import("shiki").then(({ createHighlighter }) => {
|
|
2131
|
-
if (isStale())
|
|
2132
|
-
return;
|
|
2146
|
+
if (isStale()) return;
|
|
2133
2147
|
const langs = /* @__PURE__ */ new Set();
|
|
2134
2148
|
codeEls.forEach((el) => {
|
|
2135
2149
|
const m = el.className.match(/language-(\w+)/);
|
|
2136
|
-
if (m?.[1] && m[1] !== "text")
|
|
2137
|
-
langs.add(m[1]);
|
|
2150
|
+
if (m?.[1] && m[1] !== "text") langs.add(m[1]);
|
|
2138
2151
|
});
|
|
2139
2152
|
return createHighlighter({ themes: ["vitesse-dark", "vitesse-light"], langs: [...langs] }).then((hl) => {
|
|
2140
|
-
if (isStale())
|
|
2141
|
-
return;
|
|
2153
|
+
if (isStale()) return;
|
|
2142
2154
|
const theme = isDark ? "vitesse-dark" : "vitesse-light";
|
|
2143
2155
|
codeEls.forEach((codeEl) => {
|
|
2144
2156
|
const pre = codeEl.parentElement;
|
|
2145
|
-
if (!pre || pre.dataset.highlighted)
|
|
2146
|
-
return;
|
|
2157
|
+
if (!pre || pre.dataset.highlighted) return;
|
|
2147
2158
|
pre.dataset.highlighted = "true";
|
|
2148
2159
|
const m = codeEl.className.match(/language-(\w+)/);
|
|
2149
2160
|
const lang = m?.[1] || "text";
|
|
@@ -2154,8 +2165,7 @@ function LixPreview({ blocks, html, features = {}, className = "" }) {
|
|
|
2154
2165
|
const tmp = document.createElement("div");
|
|
2155
2166
|
tmp.innerHTML = html2;
|
|
2156
2167
|
const shikiPre = tmp.querySelector("pre");
|
|
2157
|
-
if (shikiPre)
|
|
2158
|
-
codeEl.innerHTML = shikiPre.querySelector("code")?.innerHTML || codeEl.innerHTML;
|
|
2168
|
+
if (shikiPre) codeEl.innerHTML = shikiPre.querySelector("code")?.innerHTML || codeEl.innerHTML;
|
|
2159
2169
|
} catch {
|
|
2160
2170
|
}
|
|
2161
2171
|
}
|
|
@@ -2189,8 +2199,7 @@ function LixPreview({ blocks, html, features = {}, className = "" }) {
|
|
|
2189
2199
|
const handlers = [];
|
|
2190
2200
|
externalLinks.forEach((link) => {
|
|
2191
2201
|
const href = link.getAttribute("href");
|
|
2192
|
-
if (!href)
|
|
2193
|
-
return;
|
|
2202
|
+
if (!href) return;
|
|
2194
2203
|
const onEnter = () => linkPreviewRef.current.show(link, href);
|
|
2195
2204
|
const onLeave = () => linkPreviewRef.current.cancel();
|
|
2196
2205
|
link.addEventListener("mouseenter", onEnter);
|
|
@@ -2203,19 +2212,22 @@ function LixPreview({ blocks, html, features = {}, className = "" }) {
|
|
|
2203
2212
|
});
|
|
2204
2213
|
}
|
|
2205
2214
|
}, [renderedHTML, isDark]);
|
|
2206
|
-
return
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2215
|
+
return /* @__PURE__ */ jsxs11("div", { className: `lix-preview ${className}`, children: [
|
|
2216
|
+
/* @__PURE__ */ jsx12("div", { ref: contentRef, className: "lix-preview-content" }),
|
|
2217
|
+
f.linkPreview && linkPreview.preview && /* @__PURE__ */ jsx12(
|
|
2218
|
+
LinkPreviewTooltip,
|
|
2219
|
+
{
|
|
2220
|
+
anchorEl: linkPreview.preview.anchorEl,
|
|
2221
|
+
url: linkPreview.preview.url,
|
|
2222
|
+
onClose: linkPreview.hide
|
|
2223
|
+
}
|
|
2224
|
+
)
|
|
2225
|
+
] });
|
|
2214
2226
|
}
|
|
2215
2227
|
|
|
2216
2228
|
// src/editor/KeyboardShortcutsModal.jsx
|
|
2217
2229
|
import { useEffect as useEffect11, useRef as useRef10 } from "react";
|
|
2218
|
-
|
|
2230
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2219
2231
|
var SHORTCUT_GROUPS = [
|
|
2220
2232
|
{
|
|
2221
2233
|
title: "General",
|
|
@@ -2267,12 +2279,10 @@ function KeyboardShortcutsModal({ onClose }) {
|
|
|
2267
2279
|
const ref = useRef10(null);
|
|
2268
2280
|
useEffect11(() => {
|
|
2269
2281
|
function handleKey(e) {
|
|
2270
|
-
if (e.key === "Escape")
|
|
2271
|
-
onClose();
|
|
2282
|
+
if (e.key === "Escape") onClose();
|
|
2272
2283
|
}
|
|
2273
2284
|
function handleClick(e) {
|
|
2274
|
-
if (ref.current && !ref.current.contains(e.target))
|
|
2275
|
-
onClose();
|
|
2285
|
+
if (ref.current && !ref.current.contains(e.target)) onClose();
|
|
2276
2286
|
}
|
|
2277
2287
|
document.addEventListener("keydown", handleKey);
|
|
2278
2288
|
document.addEventListener("mousedown", handleClick);
|
|
@@ -2281,39 +2291,51 @@ function KeyboardShortcutsModal({ onClose }) {
|
|
|
2281
2291
|
document.removeEventListener("mousedown", handleClick);
|
|
2282
2292
|
};
|
|
2283
2293
|
}, [onClose]);
|
|
2284
|
-
return
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2294
|
+
return /* @__PURE__ */ jsx13("div", { className: "fixed inset-0 z-[9999] flex items-center justify-center bg-black/30 backdrop-blur-sm", children: /* @__PURE__ */ jsxs12(
|
|
2295
|
+
"div",
|
|
2296
|
+
{
|
|
2297
|
+
ref,
|
|
2298
|
+
className: "w-full max-w-[520px] max-h-[80vh] rounded-2xl shadow-2xl overflow-hidden",
|
|
2299
|
+
style: { backgroundColor: "var(--card-bg)", border: "1px solid var(--border-default)", boxShadow: "var(--shadow-lg)" },
|
|
2300
|
+
children: [
|
|
2301
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between px-6 py-4", style: { borderBottom: "1px solid var(--divider)" }, children: [
|
|
2302
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2.5", children: [
|
|
2303
|
+
/* @__PURE__ */ jsx13("ion-icon", { name: "keypad-outline", style: { fontSize: "18px", color: "#9b7bf7" } }),
|
|
2304
|
+
/* @__PURE__ */ jsx13("h2", { className: "text-[15px] font-bold", style: { color: "var(--text-primary)" }, children: "Keyboard Shortcuts" })
|
|
2305
|
+
] }),
|
|
2306
|
+
/* @__PURE__ */ jsx13(
|
|
2307
|
+
"button",
|
|
2308
|
+
{
|
|
2309
|
+
onClick: onClose,
|
|
2310
|
+
className: "transition-colors p-1",
|
|
2311
|
+
style: { color: "var(--text-faint)" },
|
|
2312
|
+
children: /* @__PURE__ */ jsxs12("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2313
|
+
/* @__PURE__ */ jsx13("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
2314
|
+
/* @__PURE__ */ jsx13("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
2315
|
+
] })
|
|
2316
|
+
}
|
|
2317
|
+
)
|
|
2318
|
+
] }),
|
|
2319
|
+
/* @__PURE__ */ jsx13("div", { className: "overflow-y-auto max-h-[calc(80vh-60px)] p-6 space-y-6 scrollbar-thin", children: SHORTCUT_GROUPS.map((group) => /* @__PURE__ */ jsxs12("div", { children: [
|
|
2320
|
+
/* @__PURE__ */ jsx13("h3", { className: "text-[11px] font-semibold uppercase tracking-wider mb-3", style: { color: "#9b7bf7" }, children: group.title }),
|
|
2321
|
+
/* @__PURE__ */ jsx13("div", { className: "space-y-1", children: group.shortcuts.map((s, i) => /* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between py-1.5", children: [
|
|
2322
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[13px]", style: { color: "var(--text-body)" }, children: s.desc }),
|
|
2323
|
+
/* @__PURE__ */ jsx13("div", { className: "flex items-center gap-1", children: s.keys.map((key, j) => /* @__PURE__ */ jsxs12("span", { children: [
|
|
2324
|
+
j > 0 && /* @__PURE__ */ jsx13("span", { className: "text-[10px] mx-0.5", style: { color: "var(--text-faint)" }, children: "+" }),
|
|
2325
|
+
/* @__PURE__ */ jsx13(
|
|
2326
|
+
"kbd",
|
|
2327
|
+
{
|
|
2328
|
+
className: "inline-block min-w-[24px] text-center px-1.5 py-0.5 text-[11px] font-medium rounded-md",
|
|
2329
|
+
style: { color: "var(--text-secondary)", backgroundColor: "var(--bg-surface)", border: "1px solid var(--border-default)" },
|
|
2330
|
+
children: key
|
|
2331
|
+
}
|
|
2332
|
+
)
|
|
2333
|
+
] }, j)) })
|
|
2334
|
+
] }, i)) })
|
|
2335
|
+
] }, group.title)) })
|
|
2336
|
+
]
|
|
2337
|
+
}
|
|
2338
|
+
) });
|
|
2317
2339
|
}
|
|
2318
2340
|
export {
|
|
2319
2341
|
BlockEquation,
|