@elixpo/lixeditor 2.5.1 → 2.5.7

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.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
- "use client";
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 <LixThemeContext.Provider value={{ theme, setTheme, toggleTheme, isDark, mounted }}>{children}</LixThemeContext.Provider>;
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
- "use client";
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
- return s.slice(2, -2).trim();
54
- if (s.startsWith("$$") && s.endsWith("$$"))
55
- return s.slice(2, -2).trim();
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 <div className="mermaid-block mermaid-block--editing">
103
- <div className="mermaid-block-header">
104
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c4b5fd" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M4 4h6v6H4zM14 4h6v6h-6zM4 14h6v6H4zM14 14h6v6h-6z" /></svg>
105
- <span>LaTeX Equation</span>
106
- <span style={{ marginLeft: "auto", fontSize: "10px", color: "var(--text-faint)" }}>Shift+Enter to save</span>
107
- </div>
108
- <textarea
109
- ref={inputRef}
110
- value={value}
111
- onChange={handleCodeChange}
112
- onKeyDown={(e) => {
113
- if (e.key === "Enter" && e.shiftKey) {
114
- e.preventDefault();
115
- save();
116
- }
117
- if (e.key === "Escape") {
118
- setEditing(false);
119
- setValue(block.props.latex || "");
120
- setLivePreview(block.props.latex || "");
121
- }
122
- }}
123
- placeholder="E = mc^2"
124
- rows={4}
125
- className="mermaid-block-textarea"
126
- />
127
- {livePreview.trim() && <div className="latex-live-preview">
128
- <div className="latex-live-preview-label">Preview</div>
129
- <div dangerouslySetInnerHTML={{ __html: renderKaTeX(livePreview) }} />
130
- </div>}
131
- <div className="mermaid-block-actions">
132
- <button onClick={() => {
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
- }} className="mermaid-btn-cancel">Cancel</button>
137
- <button onClick={save} className="mermaid-btn-save" disabled={!value.trim()}>Done</button>
138
- </div>
139
- </div>;
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 <div
144
- onClick={() => setEditing(true)}
145
- className="mermaid-block mermaid-block--empty"
146
- >
147
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M4 4h6v6H4zM14 4h6v6h-6zM4 14h6v6H4zM14 14h6v6h-6z" /></svg>
148
- <span>Click to add a block equation</span>
149
- </div>;
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 <div
152
- onClick={() => setEditing(true)}
153
- className="editor-block-equation"
154
- dangerouslySetInnerHTML={{ __html: renderKaTeX(latex) }}
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
- "use client";
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 <div className="mermaid-viewport mermaid-viewport--compact"><pre style={{ color: "#f87171", fontSize: "12px", whiteSpace: "pre-wrap", padding: "16px", margin: 0 }}>{error}</pre></div>;
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 <div className="mermaid-viewport mermaid-viewport--compact" style={{ display: "flex", alignItems: "center", justifyContent: "center" }}><span style={{ color: "var(--text-faint)", fontSize: "12px" }}>Preview will appear here...</span></div>;
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 <div className="mermaid-viewport mermaid-viewport--compact" style={{ display: "flex", alignItems: "center", justifyContent: "center" }}><span style={{ color: "var(--text-faint)", fontSize: "13px" }}>Rendering...</span></div>;
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 <div
388
- ref={containerRef}
389
- className={interactive ? "mermaid-viewport" : "mermaid-viewport mermaid-viewport--compact"}
390
- onMouseDown={handleMouseDown}
391
- >
392
- <div
393
- className="mermaid-block-svg"
394
- style={{
395
- transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})`,
396
- transformOrigin: "center center"
397
- }}
398
- dangerouslySetInnerHTML={{ __html: svgHTML }}
399
- />
400
- {interactive && <div className="mermaid-zoom-controls">
401
- <button
402
- onClick={(e) => {
403
- e.stopPropagation();
404
- setZoom((z) => Math.min(3, z + 0.2));
405
- }}
406
- className="mermaid-zoom-btn"
407
- title="Zoom in"
408
- ><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
409
- <line x1="12" y1="5" x2="12" y2="19" />
410
- <line x1="5" y1="12" x2="19" y2="12" />
411
- </svg></button>
412
- <span className="mermaid-zoom-label">
413
- {Math.round(zoom * 100)}
414
- {"%"}
415
- </span>
416
- <button
417
- onClick={(e) => {
418
- e.stopPropagation();
419
- setZoom((z) => Math.max(0.3, z - 0.2));
420
- }}
421
- className="mermaid-zoom-btn"
422
- title="Zoom out"
423
- ><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="5" y1="12" x2="19" y2="12" /></svg></button>
424
- <button
425
- onClick={(e) => {
426
- e.stopPropagation();
427
- resetView();
428
- }}
429
- className="mermaid-zoom-btn"
430
- title="Reset view"
431
- ><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
432
- <path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10" />
433
- <polyline points="1 4 1 10 7 10" />
434
- </svg></button>
435
- </div>}
436
- </div>;
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 <div className="mermaid-block mermaid-block--editing">
479
- <div className="mermaid-block-header">
480
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c4b5fd" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><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" /></svg>
481
- <span>Mermaid Diagram</span>
482
- <span style={{ marginLeft: "auto", fontSize: "10px", color: "var(--text-faint)" }}>Shift+Enter to save</span>
483
- </div>
484
- <textarea
485
- ref={inputRef}
486
- value={value}
487
- onChange={handleCodeChange}
488
- onKeyDown={(e) => {
489
- if (e.key === "Enter" && e.shiftKey) {
490
- e.preventDefault();
491
- save();
492
- }
493
- if (e.key === "Escape") {
494
- setEditing(false);
495
- setValue(block.props.diagram || "");
496
- setLivePreview(block.props.diagram || "");
497
- }
498
- if (e.key === "Tab") {
499
- e.preventDefault();
500
- const start = e.target.selectionStart;
501
- const end = e.target.selectionEnd;
502
- const newVal = value.substring(0, start) + " " + value.substring(end);
503
- setValue(newVal);
504
- setLivePreview(newVal);
505
- requestAnimationFrame(() => {
506
- e.target.selectionStart = e.target.selectionEnd = start + 4;
507
- });
508
- }
509
- }}
510
- placeholder={`graph TD
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
- rows={8}
515
- className="mermaid-block-textarea"
516
- />
517
- <div className="mermaid-live-preview">
518
- <div className="mermaid-live-preview-label">Preview</div>
519
- <MermaidPreview diagram={livePreview} isDark={isDark} interactive={false} />
520
- </div>
521
- <div className="mermaid-block-actions">
522
- <button onClick={() => {
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
- }} className="mermaid-btn-cancel">Cancel</button>
527
- <button onClick={save} className="mermaid-btn-save" disabled={!value.trim()}>Done</button>
528
- </div>
529
- </div>;
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 <div onClick={() => setEditing(true)} className="mermaid-block mermaid-block--empty">
533
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
534
- <rect x="3" y="3" width="7" height="7" rx="1.5" />
535
- <rect x="14" y="3" width="7" height="7" rx="1.5" />
536
- <rect x="8.5" y="14" width="7" height="7" rx="1.5" />
537
- <line x1="6.5" y1="10" x2="6.5" y2="14" />
538
- <line x1="17.5" y1="10" x2="17.5" y2="14" />
539
- <line x1="6.5" y1="14" x2="8.5" y2="14" />
540
- <line x1="17.5" y1="14" x2="15.5" y2="14" />
541
- </svg>
542
- <span>Click to add a Mermaid diagram</span>
543
- </div>;
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 <div className="mermaid-block mermaid-block--rendered group" onDoubleClick={() => setEditing(true)}>
546
- <MermaidPreview diagram={block.props.diagram} isDark={isDark} interactive={true} />
547
- <div className="mermaid-block-hover">
548
- <button onClick={() => setEditing(true)} className="mermaid-hover-btn" title="Edit diagram"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
549
- <path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7" />
550
- <path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z" />
551
- </svg></button>
552
- <button onClick={handleDelete} className="mermaid-hover-btn mermaid-hover-delete" title="Delete"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
553
- <polyline points="3 6 5 6 21 6" />
554
- <path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2" />
555
- </svg></button>
556
- </div>
557
- </div>;
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
- "use client";
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 <div className="toc-block border border-[var(--border-default)] rounded-xl bg-[var(--bg-surface)] px-5 py-4 my-2 select-none">
577
- <p className="text-[11px] uppercase tracking-wider text-[var(--text-muted)] font-bold mb-3">Table of Contents</p>
578
- {headings.length === 0 ? <p className="text-[13px] text-[var(--text-faint)] italic">Add headings to see the outline here.</p> : <ul className="space-y-1.5">{headings.map((h) => {
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 <li
582
- key={h.id}
583
- className="text-[13px] text-[#9b7bf7] hover:text-[#b69aff] cursor-pointer transition-colors"
584
- style={{ paddingLeft: `${(level - 1) * 16}px` }}
585
- onClick={() => editor.setTextCursorPosition(h.id)}
586
- >{text}</li>;
587
- })}</ul>}
588
- </div>;
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
- "use client";
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
- return s.slice(2, -2).trim();
602
- if (s.startsWith("\\[") && s.endsWith("\\]"))
603
- return s.slice(2, -2).trim();
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 <span className="relative inline-flex items-center">
646
- <span
647
- onClick={(e) => {
648
- e.preventDefault();
649
- e.stopPropagation();
650
- setValue(inlineContent.props.latex || "");
651
- setEditing(!editing);
652
- }}
653
- className="inline-equation-chip"
654
- dangerouslySetInnerHTML={{ __html: html }}
655
- title={inlineContent.props.latex}
656
- />
657
- {editing && <div
658
- ref={popupRef}
659
- className="inline-equation-editor"
660
- onMouseDown={(e) => e.stopPropagation()}
661
- >
662
- <input
663
- ref={inputRef}
664
- type="text"
665
- className="inline-equation-editor-input"
666
- value={value}
667
- onChange={(e) => setValue(e.target.value)}
668
- onKeyDown={(e) => {
669
- if (e.key === "Enter") {
670
- e.preventDefault();
671
- save();
672
- }
673
- if (e.key === "Escape") {
674
- setEditing(false);
675
- }
676
- }}
677
- placeholder="E = mc^2"
678
- />
679
- {previewHtml && <div className="inline-equation-editor-preview" dangerouslySetInnerHTML={{ __html: previewHtml }} />}
680
- <div className="inline-equation-editor-actions">
681
- <button className="mermaid-btn-cancel" onClick={() => setEditing(false)}>Cancel</button>
682
- <button className="mermaid-btn-save" disabled={!value.trim()} onClick={save}>Save</button>
683
- </div>
684
- </div>}
685
- </span>;
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) => <InlineEquationChip {...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
- "use client";
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
- days.push(null);
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
- return null;
744
- return <div
745
- ref={ref}
746
- className="fixed z-[100] rounded-xl shadow-2xl overflow-hidden"
747
- style={{ backgroundColor: "var(--bg-app)", border: "1px solid var(--border-default)", width: "240px", top: pos.top, left: pos.left }}
748
- onMouseDown={(e) => e.stopPropagation()}
749
- >
750
- <div className="flex items-center justify-between px-3 py-2" style={{ borderBottom: "1px solid var(--divider)" }}>
751
- <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)" }}><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5"><polyline points="15 18 9 12 15 6" /></svg></button>
752
- <span className="text-[12px] font-semibold" style={{ color: "var(--text-primary)" }}>{monthName}</span>
753
- <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)" }}><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5"><polyline points="9 18 15 12 9 6" /></svg></button>
754
- </div>
755
- <div className="grid grid-cols-7 px-2 pt-2">{["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((d) => <div key={d} className="text-center text-[10px] font-medium py-1" style={{ color: "var(--text-faint)" }}>{d}</div>)}</div>
756
- <div className="grid grid-cols-7 px-2 pb-2 gap-0.5">{days.map((d, i) => {
757
- if (!d)
758
- return <div key={`e${i}`} />;
759
- const dateStr = toDateStr(d);
760
- const isSelected = dateStr === selectedDate;
761
- const isToday = dateStr === todayStr;
762
- return <button
763
- key={d}
764
- onClick={() => {
765
- onSelect(dateStr);
766
- onClose();
767
- }}
768
- className="w-7 h-7 rounded-lg text-[11px] font-medium flex items-center justify-center transition-all"
769
- style={{
770
- backgroundColor: isSelected ? "#9b7bf7" : "transparent",
771
- color: isSelected ? "white" : isToday ? "#9b7bf7" : "var(--text-body)",
772
- border: isToday && !isSelected ? "1px solid #9b7bf7" : "1px solid transparent"
773
- }}
774
- onMouseEnter={(e) => {
775
- if (!isSelected)
776
- e.currentTarget.style.backgroundColor = "var(--bg-hover)";
777
- }}
778
- onMouseLeave={(e) => {
779
- if (!isSelected)
780
- e.currentTarget.style.backgroundColor = "transparent";
781
- }}
782
- >{d}</button>;
783
- })}</div>
784
- <div className="flex items-center justify-between px-3 py-1.5" style={{ borderTop: "1px solid var(--divider)" }}>
785
- <button
786
- onClick={() => {
787
- onSelect("");
788
- onClose();
789
- }}
790
- className="text-[10px] font-medium transition-colors"
791
- style={{ color: "var(--text-faint)" }}
792
- >Clear</button>
793
- <button
794
- onClick={() => {
795
- onSelect(todayStr);
796
- onClose();
797
- }}
798
- className="text-[10px] font-medium transition-colors"
799
- style={{ color: "#9b7bf7" }}
800
- >Today</button>
801
- </div>
802
- </div>;
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 <span className="relative inline-flex items-center">
821
- <span
822
- ref={chipRef}
823
- onClick={(e) => {
824
- e.preventDefault();
825
- e.stopPropagation();
826
- setShowPicker(!showPicker);
827
- }}
828
- 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"
829
- style={{ color: "#9b7bf7", backgroundColor: "rgba(155,123,247,0.06)", border: "1px solid rgba(155,123,247,0.15)" }}
830
- title="Click to change date (Ctrl+D to insert)"
831
- >
832
- <svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
833
- <rect x="3" y="4" width="18" height="18" rx="2" ry="2" strokeWidth={2} />
834
- <line x1="16" y1="2" x2="16" y2="6" strokeWidth={2} />
835
- <line x1="8" y1="2" x2="8" y2="6" strokeWidth={2} />
836
- <line x1="3" y1="10" x2="21" y2="10" strokeWidth={2} />
837
- </svg>
838
- {formatted}
839
- </span>
840
- {showPicker && <MiniCalendar
841
- selectedDate={d}
842
- onSelect={handleSelect}
843
- onClose={() => setShowPicker(false)}
844
- anchorEl={chipRef.current}
845
- />}
846
- </span>;
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) => <DateChip {...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
- "use client";
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) => <ImageRenderer {...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 <div
993
- ref={blockRef}
994
- className="blog-img-empty"
995
- tabIndex={0}
996
- onPaste={handlePaste}
997
- onDrop={handleDrop}
998
- onDragOver={(e) => {
999
- e.preventDefault();
1000
- setIsDragOver(true);
1001
- }}
1002
- onDragLeave={() => setIsDragOver(false)}
1003
- data-drag-over={isDragOver}
1004
- >
1005
- <input
1006
- ref={fileInputRef}
1007
- type="file"
1008
- accept="image/*"
1009
- onChange={(e) => {
1010
- if (e.target.files?.[0])
1011
- uploadFile(e.target.files[0]);
1012
- e.target.value = "";
1013
- }}
1014
- style={{ display: "none" }}
1015
- />
1016
- {mode === "uploading" && <div className="blog-img-status">
1017
- <div className="blog-img-spinner" />
1018
- <span>{uploadStatus}</span>
1019
- </div>}
1020
- {mode === "idle" && <>
1021
- <div className="blog-img-actions-row">
1022
- <button className="blog-img-action" onClick={() => fileInputRef.current?.click()}>
1023
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
1024
- <path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4" />
1025
- <polyline points="17 8 12 3 7 8" />
1026
- <line x1="12" y1="3" x2="12" y2="15" />
1027
- </svg>
1028
- {"Upload"}
1029
- </button>
1030
- <button className="blog-img-action" onClick={() => setMode("embed")}>
1031
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
1032
- <path d="M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71" />
1033
- <path d="M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71" />
1034
- </svg>
1035
- {"Embed URL"}
1036
- </button>
1037
- </div>
1038
- <p className="blog-img-hint">{"or drag & drop / paste an image"}</p>
1039
- </>}
1040
- {mode === "embed" && <div className="blog-img-input-row">
1041
- <input
1042
- ref={embedInputRef}
1043
- type="url"
1044
- value={embedUrl}
1045
- onChange={(e) => {
1046
- setEmbedUrl(e.target.value);
1047
- setEmbedError("");
1048
- }}
1049
- onKeyDown={(e) => {
1050
- if (e.key === "Enter")
1051
- handleEmbed();
1052
- if (e.key === "Escape") {
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
- placeholder="https://example.com/image.jpg"
1059
- className="blog-img-url-input"
1060
- />
1061
- <button className="blog-img-submit-btn" onClick={handleEmbed} disabled={!embedUrl.trim()}><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12" /></svg></button>
1062
- <button className="blog-img-cancel-btn" onClick={() => {
1063
- setMode("idle");
1064
- setEmbedUrl("");
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 <div ref={blockRef} className="blog-img-loaded" tabIndex={0} onPaste={handlePaste}>
1075
- <div className="blog-img-wrapper">
1076
- <img src={url} alt={caption || "Image"} className="blog-img-main" draggable={false} />
1077
- <div className="blog-img-hover-overlay"><div className="blog-img-hover-actions">
1078
- <button className="blog-img-hover-btn" onClick={handleReplace}><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1079
- <path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4" />
1080
- <polyline points="17 8 12 3 7 8" />
1081
- <line x1="12" y1="3" x2="12" y2="15" />
1082
- </svg></button>
1083
- <button className="blog-img-hover-btn" onClick={() => setEditingCaption(true)}><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1084
- <path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7" />
1085
- <path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z" />
1086
- </svg></button>
1087
- <button className="blog-img-hover-btn blog-img-hover-delete" onClick={handleDelete}><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1088
- <polyline points="3 6 5 6 21 6" />
1089
- <path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2" />
1090
- </svg></button>
1091
- </div></div>
1092
- </div>
1093
- {editingCaption ? <input
1094
- type="text"
1095
- value={captionText}
1096
- onChange={(e) => setCaptionText(e.target.value)}
1097
- onKeyDown={(e) => {
1098
- if (e.key === "Enter")
1099
- handleCaptionSave();
1100
- if (e.key === "Escape") {
1101
- setEditingCaption(false);
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
- onBlur={handleCaptionSave}
1106
- placeholder="Add a caption..."
1107
- className="blog-img-caption-input"
1108
- autoFocus
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
- "use client";
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 <div className="border border-[var(--border-default)] rounded-xl bg-[var(--bg-surface)] p-4 my-2 space-y-3">
1158
- <p className="text-[11px] text-[var(--text-muted)] font-medium">Button Block</p>
1159
- <input
1160
- type="text"
1161
- value={label}
1162
- onChange={(e) => setLabel(e.target.value)}
1163
- placeholder="Button label"
1164
- 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]"
1165
- />
1166
- <div className="flex gap-2">
1167
- <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">{BUTTON_ACTIONS.map((a) => <option key={a.value} value={a.value}>{a.label}</option>)}</select>
1168
- <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">{BUTTON_VARIANTS.map((v) => <option key={v.value} value={v.value}>{v.label}</option>)}</select>
1169
- </div>
1170
- {(action === "link" || action === "copy") && <input
1171
- type="text"
1172
- value={actionValue}
1173
- onChange={(e) => setActionValue(e.target.value)}
1174
- placeholder={action === "link" ? "https://..." : "Text to copy"}
1175
- 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]"
1176
- />}
1177
- <div className="flex justify-end gap-2">
1178
- <button onClick={() => setEditing(false)} className="px-3 py-1 text-[12px] text-[#888] hover:text-[var(--text-primary)] transition-colors">Cancel</button>
1179
- <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">Done</button>
1180
- </div>
1181
- </div>;
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 <div className="my-2" onDoubleClick={() => setEditing(true)}><button className={`px-5 py-2 rounded-lg text-[13px] font-medium transition-colors ${variantCls}`}>{label}</button></div>;
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
- "use client";
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 <div style={{
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
- <div style={{ display: "flex", alignItems: "center", gap: "8px", marginBottom: "12px" }}>
1241
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#9b7bf7" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
1242
- <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" />
1243
- <polyline points="14 2 14 8 20 8" />
1244
- <line x1="16" y1="13" x2="8" y2="13" />
1245
- <line x1="16" y1="17" x2="8" y2="17" />
1246
- <polyline points="10 9 9 9 8 9" />
1247
- </svg>
1248
- <span style={{ fontSize: "14px", fontWeight: 600, color: "var(--text-primary)" }}>Embed PDF</span>
1249
- </div>
1250
- <div style={{ display: "flex", gap: "8px" }}>
1251
- <input
1252
- type="text"
1253
- value={inputUrl}
1254
- onChange={(e) => setInputUrl(e.target.value)}
1255
- onKeyDown={(e) => e.key === "Enter" && handleSubmit()}
1256
- placeholder="Paste PDF link..."
1257
- style={{
1258
- flex: 1,
1259
- background: "var(--bg-app)",
1260
- color: "var(--text-primary)",
1261
- border: "1px solid #232d3f",
1262
- borderRadius: "8px",
1263
- padding: "8px 12px",
1264
- fontSize: "13px",
1265
- outline: "none"
1266
- }}
1267
- />
1268
- <button
1269
- onClick={handleSubmit}
1270
- disabled={!inputUrl.trim() || loading}
1271
- style={{
1272
- padding: "8px 16px",
1273
- background: "#9b7bf7",
1274
- color: "white",
1275
- border: "none",
1276
- borderRadius: "8px",
1277
- fontSize: "13px",
1278
- fontWeight: 600,
1279
- cursor: "pointer",
1280
- opacity: !inputUrl.trim() || loading ? 0.4 : 1
1281
- }}
1282
- >{loading ? "..." : "Embed"}</button>
1283
- </div>
1284
- </div>;
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 <div style={{
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
- <div style={{
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
- <iframe
1302
- src={`${url}#toolbar=0&navpanes=0&scrollbar=0&view=FitH`}
1303
- title={title || "PDF"}
1304
- style={{
1305
- width: "100%",
1306
- height: "100%",
1307
- border: "none",
1308
- pointerEvents: "none"
1309
- }}
1310
- />
1311
- <div style={{
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
- <div style={{
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
- }}>PDF</div>
1331
- </div>
1332
- <div style={{ flex: 1, padding: "16px", display: "flex", flexDirection: "column", justifyContent: "space-between" }}>
1333
- <div>
1334
- <div style={{ display: "flex", alignItems: "center", gap: "8px", marginBottom: "8px" }}>
1335
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#9b7bf7" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
1336
- <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" />
1337
- <polyline points="14 2 14 8 20 8" />
1338
- </svg>
1339
- <span style={{ fontSize: "14px", fontWeight: 600, color: "var(--text-primary)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{title || "Document"}</span>
1340
- </div>
1341
- <div style={{ display: "flex", gap: "12px", flexWrap: "wrap" }}>
1342
- {fileSize && <span style={{ fontSize: "12px", color: "var(--text-muted)", display: "flex", alignItems: "center", gap: "4px" }}>
1343
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3" /></svg>
1344
- {fileSize}
1345
- </span>}
1346
- {pageCount && <span style={{ fontSize: "12px", color: "var(--text-muted)", display: "flex", alignItems: "center", gap: "4px" }}>
1347
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
1348
- <path d="M4 19.5A2.5 2.5 0 016.5 17H20" />
1349
- <path d="M6.5 2H20v20H6.5A2.5 2.5 0 014 19.5v-15A2.5 2.5 0 016.5 2z" />
1350
- </svg>
1351
- {pageCount}
1352
- {" pages"}
1353
- </span>}
1354
- </div>
1355
- </div>
1356
- <div style={{ display: "flex", gap: "8px", marginTop: "12px" }}>
1357
- <a
1358
- href={url}
1359
- target="_blank"
1360
- rel="noopener noreferrer"
1361
- style={{
1362
- padding: "6px 12px",
1363
- background: "rgba(155,123,247,0.1)",
1364
- border: "1px solid rgba(155,123,247,0.25)",
1365
- borderRadius: "6px",
1366
- fontSize: "12px",
1367
- color: "#a78bfa",
1368
- fontWeight: 500,
1369
- textDecoration: "none",
1370
- cursor: "pointer"
1371
- }}
1372
- >Open PDF</a>
1373
- <button onClick={handleReplace} style={{
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
- }}>Replace</button>
1382
- <button onClick={handleDelete} style={{
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
- }}>Delete</button>
1391
- </div>
1392
- </div>
1393
- </div>;
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
- "use client";
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 <div
1491
- ref={tooltipRef}
1492
- className="link-preview-tooltip"
1493
- style={style}
1494
- onMouseEnter={onTooltipEnter}
1495
- onMouseLeave={onTooltipLeave}
1496
- >{loading ? <div className="link-preview-loading">
1497
- <div className="link-preview-skeleton" style={{ width: "60%", height: 12 }} />
1498
- <div className="link-preview-skeleton" style={{ width: "90%", height: 10, marginTop: 8 }} />
1499
- <div className="link-preview-skeleton" style={{ width: "40%", height: 10, marginTop: 4 }} />
1500
- </div> : data ? <a href={url} target="_blank" rel="noopener noreferrer" className="link-preview-card">
1501
- {data.image && <div className="link-preview-image"><img src={data.image} alt="" onError={(e) => {
1502
- e.target.style.display = "none";
1503
- }} /></div>}
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
- <span>{data.domain}</span>
1512
- </div>
1513
- </div>
1514
- </a> : null}</div>;
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
- "use client";
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
- blockSpecs.codeBlock = codeBlock;
1617
- if (f.equations)
1618
- blockSpecs.blockEquation = BlockEquation({});
1619
- if (f.mermaid)
1620
- blockSpecs.mermaidBlock = MermaidBlock({});
1621
- if (f.tableOfContents)
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
- inlineContentSpecs.inlineEquation = InlineEquation;
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: <span style={{ fontSize: 16 }}>{"\u2211"}</span>,
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: <span style={{ fontSize: 14 }}>{"\u25C7"}</span>,
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: <span style={{ fontSize: 14 }}>{"\u2630"}</span>,
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 <div className={`lix-editor-wrapper${""}`} ref={wrapperRef} style={{ position: "relative" }}>
1808
- <BlockNoteView
1809
- editor={editor}
1810
- onChange={handleChange}
1811
- theme={isDark ? "dark" : "light"}
1812
- slashMenu={false}
1813
- >
1814
- <SuggestionMenuController triggerCharacter="/" getItems={getItems} />
1815
- <TableHandlesController />
1816
- {children}
1817
- </BlockNoteView>
1818
- {f.linkPreview && editorLinkPreview.preview && <LinkPreviewTooltip
1819
- anchorEl={editorLinkPreview.preview.anchorEl}
1820
- url={editorLinkPreview.preview.url}
1821
- onClose={editorLinkPreview.hide}
1822
- />}
1823
- </div>;
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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1855
- if (!text)
1856
- return "";
1897
+ if (!text) return "";
1857
1898
  const s = c.styles || {};
1858
- if (s.bold)
1859
- text = `<strong>${text}</strong>`;
1860
- if (s.italic)
1861
- text = `<em>${text}</em>`;
1862
- if (s.strike)
1863
- text = `<del>${text}</del>`;
1864
- if (s.code)
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
- cellContent = cell;
1944
- else if (cell?.content)
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
- "use client";
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
- return s.slice(2, -2).trim();
2049
- if (s.startsWith("$$") && s.endsWith("$$"))
2050
- return s.slice(2, -2).trim();
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 <div className={`lix-preview ${className}`}>
2207
- <div ref={contentRef} className="lix-preview-content" />
2208
- {f.linkPreview && linkPreview.preview && <LinkPreviewTooltip
2209
- anchorEl={linkPreview.preview.anchorEl}
2210
- url={linkPreview.preview.url}
2211
- onClose={linkPreview.hide}
2212
- />}
2213
- </div>;
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
- "use client";
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 <div className="fixed inset-0 z-[9999] flex items-center justify-center bg-black/30 backdrop-blur-sm"><div
2285
- ref={ref}
2286
- className="w-full max-w-[520px] max-h-[80vh] rounded-2xl shadow-2xl overflow-hidden"
2287
- style={{ backgroundColor: "var(--card-bg)", border: "1px solid var(--border-default)", boxShadow: "var(--shadow-lg)" }}
2288
- >
2289
- <div className="flex items-center justify-between px-6 py-4" style={{ borderBottom: "1px solid var(--divider)" }}>
2290
- <div className="flex items-center gap-2.5">
2291
- <ion-icon name="keypad-outline" style={{ fontSize: "18px", color: "#9b7bf7" }} />
2292
- <h2 className="text-[15px] font-bold" style={{ color: "var(--text-primary)" }}>Keyboard Shortcuts</h2>
2293
- </div>
2294
- <button
2295
- onClick={onClose}
2296
- className="transition-colors p-1"
2297
- style={{ color: "var(--text-faint)" }}
2298
- ><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
2299
- <line x1="18" y1="6" x2="6" y2="18" />
2300
- <line x1="6" y1="6" x2="18" y2="18" />
2301
- </svg></button>
2302
- </div>
2303
- <div className="overflow-y-auto max-h-[calc(80vh-60px)] p-6 space-y-6 scrollbar-thin">{SHORTCUT_GROUPS.map((group) => <div key={group.title}>
2304
- <h3 className="text-[11px] font-semibold uppercase tracking-wider mb-3" style={{ color: "#9b7bf7" }}>{group.title}</h3>
2305
- <div className="space-y-1">{group.shortcuts.map((s, i) => <div key={i} className="flex items-center justify-between py-1.5">
2306
- <span className="text-[13px]" style={{ color: "var(--text-body)" }}>{s.desc}</span>
2307
- <div className="flex items-center gap-1">{s.keys.map((key, j) => <span key={j}>
2308
- {j > 0 && <span className="text-[10px] mx-0.5" style={{ color: "var(--text-faint)" }}>+</span>}
2309
- <kbd
2310
- className="inline-block min-w-[24px] text-center px-1.5 py-0.5 text-[11px] font-medium rounded-md"
2311
- style={{ color: "var(--text-secondary)", backgroundColor: "var(--bg-surface)", border: "1px solid var(--border-default)" }}
2312
- >{key}</kbd>
2313
- </span>)}</div>
2314
- </div>)}</div>
2315
- </div>)}</div>
2316
- </div></div>;
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,