@dalgoridim/headless-cms 0.1.0 → 0.2.1
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/ARCHITECTURE.md +125 -0
- package/README.md +242 -48
- package/dist/adapters/firestore/index.cjs +24 -3
- package/dist/adapters/firestore/index.cjs.map +1 -1
- package/dist/adapters/firestore/index.js +24 -3
- package/dist/adapters/firestore/index.js.map +1 -1
- package/dist/adapters/postgres/index.cjs +37 -11
- package/dist/adapters/postgres/index.cjs.map +1 -1
- package/dist/adapters/postgres/index.js +37 -11
- package/dist/adapters/postgres/index.js.map +1 -1
- package/dist/client/index.cjs +94 -543
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +89 -26
- package/dist/client/index.d.ts +89 -26
- package/dist/client/index.js +96 -547
- package/dist/client/index.js.map +1 -1
- package/dist/index.cjs +16 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +81 -16
- package/dist/index.d.ts +81 -16
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/server/index.cjs +63 -9
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +35 -5
- package/dist/server/index.d.ts +35 -5
- package/dist/server/index.js +61 -8
- package/dist/server/index.js.map +1 -1
- package/package.json +8 -11
package/dist/client/index.cjs
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
"use client";
|
|
3
|
-
var __create = Object.create;
|
|
4
3
|
var __defProp = Object.defineProperty;
|
|
5
4
|
var __defProps = Object.defineProperties;
|
|
6
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
6
|
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
8
7
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
9
8
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
10
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
11
9
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
12
10
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
13
11
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -35,14 +33,6 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
35
33
|
}
|
|
36
34
|
return to;
|
|
37
35
|
};
|
|
38
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
39
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
40
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
41
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
42
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
43
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
44
|
-
mod
|
|
45
|
-
));
|
|
46
36
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
47
37
|
|
|
48
38
|
// src/client/index.ts
|
|
@@ -52,22 +42,19 @@ __export(client_exports, {
|
|
|
52
42
|
CmsAuthProvider: () => CmsAuthProvider,
|
|
53
43
|
ContentEditSpan: () => ContentEditSpan,
|
|
54
44
|
EditableImage: () => EditableImage,
|
|
55
|
-
MarkdownEditor: () => MarkdownEditor,
|
|
56
45
|
PageProvider: () => PageProvider,
|
|
57
|
-
ProjectContentEditor: () => ProjectContentEditor,
|
|
58
|
-
cn: () => cn,
|
|
59
46
|
useCmsAuth: () => useCmsAuth,
|
|
47
|
+
useMarkdownEditor: () => useMarkdownEditor,
|
|
60
48
|
usePageContext: () => usePageContext
|
|
61
49
|
});
|
|
62
50
|
module.exports = __toCommonJS(client_exports);
|
|
63
51
|
|
|
64
52
|
// src/client/PageProvider.tsx
|
|
65
53
|
var import_react = require("react");
|
|
66
|
-
var import_sonner = require("sonner");
|
|
67
54
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
68
55
|
var defaultNotifier = {
|
|
69
|
-
success: (m) =>
|
|
70
|
-
error: (m) =>
|
|
56
|
+
success: (m) => console.info(`[cms] ${m}`),
|
|
57
|
+
error: (m) => console.error(`[cms] ${m}`)
|
|
71
58
|
};
|
|
72
59
|
var PageContext = (0, import_react.createContext)(void 0);
|
|
73
60
|
var dirtyKey = (collection, sectionKey) => `${collection}:${sectionKey}`;
|
|
@@ -316,99 +303,8 @@ function CmsAuthProvider({
|
|
|
316
303
|
|
|
317
304
|
// src/client/ContentEditSpan.tsx
|
|
318
305
|
var import_react3 = require("react");
|
|
319
|
-
|
|
320
|
-
// src/client/utils.ts
|
|
321
|
-
var import_clsx = require("clsx");
|
|
322
|
-
var import_tailwind_merge = require("tailwind-merge");
|
|
323
|
-
function cn(...inputs) {
|
|
324
|
-
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// src/client/ContentEditSpan.tsx
|
|
328
306
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
329
|
-
var
|
|
330
|
-
{ regex: /^\*\*(.+?)\*\*/, mark: "bold" },
|
|
331
|
-
{ regex: /^\*(.+?)\*/, mark: "italic" },
|
|
332
|
-
{ regex: /^~~br~~/, mark: "break" },
|
|
333
|
-
{ regex: /^~~(.+?)~~/, mark: "strike" },
|
|
334
|
-
{ regex: /^\^\^(.+?)\^\^/, mark: "primary" },
|
|
335
|
-
{ regex: /^__(.+?)__/, mark: "underline" },
|
|
336
|
-
{
|
|
337
|
-
regex: /^\[(.+?)\]\((https?:\/\/[^\s)]+)\)/,
|
|
338
|
-
mark: "link",
|
|
339
|
-
isLink: true
|
|
340
|
-
}
|
|
341
|
-
];
|
|
342
|
-
function parseSpecialString(input) {
|
|
343
|
-
const out = [];
|
|
344
|
-
let text = input;
|
|
345
|
-
while (text.length) {
|
|
346
|
-
let matched = false;
|
|
347
|
-
for (const p of PATTERNS) {
|
|
348
|
-
const m = p.regex.exec(text);
|
|
349
|
-
if (!m) continue;
|
|
350
|
-
matched = true;
|
|
351
|
-
if (p.mark === "break") {
|
|
352
|
-
out.push({ text: "\n", break: true });
|
|
353
|
-
} else if ("isLink" in p) {
|
|
354
|
-
out.push({ text: m[1], link: m[2] });
|
|
355
|
-
} else {
|
|
356
|
-
const inner = parseSpecialString(m[1]);
|
|
357
|
-
inner.forEach(
|
|
358
|
-
(n) => n[p.mark] = true
|
|
359
|
-
);
|
|
360
|
-
out.push(...inner);
|
|
361
|
-
}
|
|
362
|
-
text = text.slice(m[0].length);
|
|
363
|
-
break;
|
|
364
|
-
}
|
|
365
|
-
if (!matched) {
|
|
366
|
-
out.push({ text: text[0] });
|
|
367
|
-
text = text.slice(1);
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
return out;
|
|
371
|
-
}
|
|
372
|
-
function RenderStatic({
|
|
373
|
-
raw,
|
|
374
|
-
as: Component = "span",
|
|
375
|
-
className
|
|
376
|
-
}) {
|
|
377
|
-
const nodes = parseSpecialString(raw);
|
|
378
|
-
const content = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: nodes.map((l, i) => {
|
|
379
|
-
if (l.break) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("br", {}, i);
|
|
380
|
-
let el = l.text;
|
|
381
|
-
if (l.bold) el = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: el });
|
|
382
|
-
if (l.italic) el = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("em", { children: el });
|
|
383
|
-
if (l.strike) el = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("s", { children: el });
|
|
384
|
-
if (l.primary || l.underline) {
|
|
385
|
-
el = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
386
|
-
"span",
|
|
387
|
-
{
|
|
388
|
-
style: {
|
|
389
|
-
color: l.primary ? "var(--color-primary)" : void 0,
|
|
390
|
-
textDecoration: l.underline ? "underline" : void 0
|
|
391
|
-
},
|
|
392
|
-
children: el
|
|
393
|
-
}
|
|
394
|
-
);
|
|
395
|
-
}
|
|
396
|
-
if (l.link) {
|
|
397
|
-
el = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
398
|
-
"a",
|
|
399
|
-
{
|
|
400
|
-
href: l.link,
|
|
401
|
-
target: "_blank",
|
|
402
|
-
rel: "noopener noreferrer",
|
|
403
|
-
className: "inline hover:underline",
|
|
404
|
-
children: el
|
|
405
|
-
}
|
|
406
|
-
);
|
|
407
|
-
}
|
|
408
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: el }, i);
|
|
409
|
-
}) });
|
|
410
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Component, { className, children: content });
|
|
411
|
-
}
|
|
307
|
+
var defaultRenderValue = (raw) => raw;
|
|
412
308
|
function getNestedValue(obj, path) {
|
|
413
309
|
const keys = path.split(".");
|
|
414
310
|
let current = obj;
|
|
@@ -420,20 +316,22 @@ function getNestedValue(obj, path) {
|
|
|
420
316
|
return current;
|
|
421
317
|
}
|
|
422
318
|
function ContentEditSpan({
|
|
423
|
-
collection
|
|
319
|
+
collection,
|
|
424
320
|
sectionKey,
|
|
425
321
|
fieldKey,
|
|
426
322
|
className,
|
|
427
323
|
children,
|
|
428
|
-
as = "span"
|
|
324
|
+
as = "span",
|
|
325
|
+
renderValue = defaultRenderValue
|
|
429
326
|
}) {
|
|
430
327
|
var _a, _b;
|
|
431
328
|
const { sections, editField } = usePageContext();
|
|
432
329
|
const { isEditing } = useCmsAuth();
|
|
433
330
|
const section = (_a = sections[collection]) == null ? void 0 : _a[sectionKey];
|
|
434
331
|
const raw = (_b = getNestedValue(section, fieldKey)) != null ? _b : typeof children === "string" ? children : "";
|
|
332
|
+
const Component = as;
|
|
435
333
|
if (!isEditing) {
|
|
436
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
334
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Component, { className, children: renderValue(raw) });
|
|
437
335
|
}
|
|
438
336
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
439
337
|
EditableContentSpan,
|
|
@@ -444,18 +342,20 @@ function ContentEditSpan({
|
|
|
444
342
|
className,
|
|
445
343
|
raw,
|
|
446
344
|
editField,
|
|
447
|
-
as
|
|
345
|
+
as,
|
|
346
|
+
renderValue
|
|
448
347
|
}
|
|
449
348
|
);
|
|
450
349
|
}
|
|
451
350
|
function EditableContentSpan({
|
|
452
|
-
collection
|
|
351
|
+
collection,
|
|
453
352
|
sectionKey,
|
|
454
353
|
fieldKey,
|
|
455
354
|
className,
|
|
456
355
|
raw,
|
|
457
356
|
editField,
|
|
458
|
-
as: Component = "span"
|
|
357
|
+
as: Component = "span",
|
|
358
|
+
renderValue
|
|
459
359
|
}) {
|
|
460
360
|
const { isEditing } = useCmsAuth();
|
|
461
361
|
const [isFocused, setIsFocused] = (0, import_react3.useState)(false);
|
|
@@ -503,19 +403,16 @@ function EditableContentSpan({
|
|
|
503
403
|
Component,
|
|
504
404
|
{
|
|
505
405
|
ref: contentRef,
|
|
506
|
-
className
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
isFocused && "ring-2 ring-primary/50 ring-offset-2 ring-offset-neutral-900 rounded-sm px-2",
|
|
511
|
-
!isFocused && isEditing && "hover:ring-1 hover:ring-primary/30 hover:ring-offset-1 hover:ring-offset-neutral-900 hover:rounded-sm hover:px-2 cursor-text"
|
|
512
|
-
),
|
|
406
|
+
className,
|
|
407
|
+
"data-cms-editable": "",
|
|
408
|
+
"data-cms-editing": isEditing ? "" : void 0,
|
|
409
|
+
"data-cms-focused": isFocused ? "" : void 0,
|
|
513
410
|
contentEditable: isEditing,
|
|
514
411
|
suppressContentEditableWarning: true,
|
|
515
412
|
onInput: handleInput,
|
|
516
413
|
onBlur: handleBlur,
|
|
517
414
|
onFocus: handleFocus,
|
|
518
|
-
children: !isFocused &&
|
|
415
|
+
children: !isFocused && renderValue(editValue)
|
|
519
416
|
},
|
|
520
417
|
isFocused ? "editing" : "static"
|
|
521
418
|
);
|
|
@@ -523,8 +420,6 @@ function EditableContentSpan({
|
|
|
523
420
|
|
|
524
421
|
// src/client/EditableImage.tsx
|
|
525
422
|
var import_react4 = require("react");
|
|
526
|
-
var import_react_dom = require("react-dom");
|
|
527
|
-
var import_lucide_react = require("lucide-react");
|
|
528
423
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
529
424
|
function EditableImage({
|
|
530
425
|
sectionKey,
|
|
@@ -532,15 +427,13 @@ function EditableImage({
|
|
|
532
427
|
src,
|
|
533
428
|
collection,
|
|
534
429
|
docId,
|
|
535
|
-
className
|
|
430
|
+
className,
|
|
431
|
+
children
|
|
536
432
|
}) {
|
|
537
433
|
const { isEditing } = useCmsAuth();
|
|
538
434
|
const { editField, setPendingImage, pendingImages, saving } = usePageContext();
|
|
539
435
|
const [preview, setPreview] = (0, import_react4.useState)(src);
|
|
540
436
|
const [hasError, setHasError] = (0, import_react4.useState)(false);
|
|
541
|
-
const [showUrlModal, setShowUrlModal] = (0, import_react4.useState)(false);
|
|
542
|
-
const [urlInput, setUrlInput] = (0, import_react4.useState)("");
|
|
543
|
-
const [urlPreview, setUrlPreview] = (0, import_react4.useState)("");
|
|
544
437
|
const inputRef = (0, import_react4.useRef)(null);
|
|
545
438
|
const pendingImage = pendingImages.find(
|
|
546
439
|
(img) => img.sectionKey === sectionKey && img.fieldKey === fieldKey
|
|
@@ -565,442 +458,102 @@ function EditableImage({
|
|
|
565
458
|
isExternal: false
|
|
566
459
|
});
|
|
567
460
|
};
|
|
568
|
-
const
|
|
569
|
-
|
|
570
|
-
|
|
461
|
+
const openFilePicker = () => {
|
|
462
|
+
var _a;
|
|
463
|
+
if (saving) return;
|
|
464
|
+
(_a = inputRef.current) == null ? void 0 : _a.click();
|
|
465
|
+
};
|
|
466
|
+
const setExternalUrl = (value) => {
|
|
467
|
+
let valid = false;
|
|
468
|
+
try {
|
|
469
|
+
const url = new URL(value);
|
|
470
|
+
valid = url.protocol === "http:" || url.protocol === "https:";
|
|
471
|
+
} catch (e) {
|
|
472
|
+
valid = false;
|
|
473
|
+
}
|
|
474
|
+
if (!valid) return false;
|
|
475
|
+
setPreview(value);
|
|
571
476
|
setHasError(false);
|
|
572
|
-
editField(collection, sectionKey, fieldKey,
|
|
477
|
+
editField(collection, sectionKey, fieldKey, value);
|
|
573
478
|
setPendingImage({
|
|
574
479
|
file: null,
|
|
575
|
-
localUrl:
|
|
480
|
+
localUrl: value,
|
|
576
481
|
sectionKey,
|
|
577
482
|
fieldKey,
|
|
578
483
|
collection,
|
|
579
484
|
docId,
|
|
580
485
|
isExternal: true
|
|
581
486
|
});
|
|
582
|
-
|
|
583
|
-
setUrlInput("");
|
|
584
|
-
setUrlPreview("");
|
|
487
|
+
return true;
|
|
585
488
|
};
|
|
586
|
-
const
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
}
|
|
595
|
-
} catch (e) {
|
|
596
|
-
setUrlPreview("");
|
|
597
|
-
}
|
|
489
|
+
const state = {
|
|
490
|
+
src: imgSrc,
|
|
491
|
+
isEditing,
|
|
492
|
+
saving,
|
|
493
|
+
hasError,
|
|
494
|
+
openFilePicker,
|
|
495
|
+
setExternalUrl,
|
|
496
|
+
imgProps: { src: imgSrc, onError: () => setHasError(true) }
|
|
598
497
|
};
|
|
599
|
-
|
|
600
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "w-32 h-32 mx-auto rounded-2xl bg-neutral-800/50 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
601
|
-
"svg",
|
|
602
|
-
{
|
|
603
|
-
className: "w-16 h-16 text-neutral-600",
|
|
604
|
-
fill: "none",
|
|
605
|
-
viewBox: "0 0 24 24",
|
|
606
|
-
stroke: "currentColor",
|
|
607
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
608
|
-
"path",
|
|
609
|
-
{
|
|
610
|
-
strokeLinecap: "round",
|
|
611
|
-
strokeLinejoin: "round",
|
|
612
|
-
strokeWidth: 1.5,
|
|
613
|
-
d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
|
|
614
|
-
}
|
|
615
|
-
)
|
|
616
|
-
}
|
|
617
|
-
) }),
|
|
618
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "text-neutral-500 text-lg", children: "No image available" })
|
|
619
|
-
] }) }) : (
|
|
620
|
-
// eslint-disable-next-line @next/next/no-img-element
|
|
498
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className, children: [
|
|
621
499
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
622
|
-
"
|
|
500
|
+
"input",
|
|
623
501
|
{
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
502
|
+
ref: inputRef,
|
|
503
|
+
type: "file",
|
|
504
|
+
accept: "image/*",
|
|
505
|
+
disabled: saving,
|
|
506
|
+
onChange: handleFileChange,
|
|
507
|
+
style: { display: "none" }
|
|
628
508
|
}
|
|
629
|
-
)
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
}
|
|
634
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
635
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: cn("relative group", className), children: [
|
|
636
|
-
imageNode,
|
|
637
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "absolute inset-0 flex items-center justify-center bg-black/30 opacity-0 group-hover:opacity-100 transition-opacity", children: saving ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "w-8 h-8 border-4 border-white border-t-transparent rounded-full animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex gap-12", children: [
|
|
638
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
639
|
-
import_lucide_react.CameraIcon,
|
|
640
|
-
{
|
|
641
|
-
className: "w-12 h-12 text-white cursor-pointer hover:text-primary",
|
|
642
|
-
onClick: (e) => {
|
|
643
|
-
var _a;
|
|
644
|
-
e.stopPropagation();
|
|
645
|
-
(_a = inputRef.current) == null ? void 0 : _a.click();
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
),
|
|
649
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
650
|
-
import_lucide_react.Link2Icon,
|
|
651
|
-
{
|
|
652
|
-
className: "w-12 h-12 text-white cursor-pointer hover:text-primary",
|
|
653
|
-
onClick: (e) => {
|
|
654
|
-
e.stopPropagation();
|
|
655
|
-
setShowUrlModal(true);
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
)
|
|
659
|
-
] }) }),
|
|
660
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
661
|
-
"input",
|
|
662
|
-
{
|
|
663
|
-
ref: inputRef,
|
|
664
|
-
type: "file",
|
|
665
|
-
accept: "image/*",
|
|
666
|
-
disabled: saving,
|
|
667
|
-
onChange: handleFileChange,
|
|
668
|
-
className: "absolute inset-0 opacity-0 pointer-events-none"
|
|
669
|
-
}
|
|
670
|
-
)
|
|
671
|
-
] }),
|
|
672
|
-
showUrlModal && (0, import_react_dom.createPortal)(
|
|
673
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "fixed inset-0 bg-black/70 flex items-center justify-center z-9999 p-4", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "bg-neutral-900 rounded-xl p-6 max-w-sm w-full space-y-4", children: [
|
|
674
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { className: "text-lg font-bold", children: "Add Image URL" }),
|
|
675
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
676
|
-
"input",
|
|
677
|
-
{
|
|
678
|
-
type: "text",
|
|
679
|
-
value: urlInput,
|
|
680
|
-
onChange: (e) => handleUrlChange(e.target.value),
|
|
681
|
-
placeholder: "https://example.com/image.png",
|
|
682
|
-
className: "w-full px-3 py-2 rounded bg-neutral-800 border border-neutral-700"
|
|
683
|
-
}
|
|
684
|
-
),
|
|
685
|
-
urlPreview ? (
|
|
686
|
-
// eslint-disable-next-line @next/next/no-img-element
|
|
687
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
688
|
-
"img",
|
|
689
|
-
{
|
|
690
|
-
src: urlPreview,
|
|
691
|
-
alt: "",
|
|
692
|
-
className: "w-full h-40 object-contain rounded",
|
|
693
|
-
onError: () => setHasError(true)
|
|
694
|
-
}
|
|
695
|
-
)
|
|
696
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "h-40 flex items-center justify-center text-neutral-500", children: "Invalid URL" }),
|
|
697
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex justify-end gap-2", children: [
|
|
698
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
699
|
-
"button",
|
|
700
|
-
{
|
|
701
|
-
onClick: () => setShowUrlModal(false),
|
|
702
|
-
className: "px-3 py-1 bg-neutral-700 rounded text-sm",
|
|
703
|
-
children: [
|
|
704
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.XIcon, { className: "w-4 h-4 inline" }),
|
|
705
|
-
" Cancel"
|
|
706
|
-
]
|
|
707
|
-
}
|
|
708
|
-
),
|
|
709
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
710
|
-
"button",
|
|
711
|
-
{
|
|
712
|
-
onClick: handleUrlConfirm,
|
|
713
|
-
disabled: !urlPreview,
|
|
714
|
-
className: "px-3 py-1 bg-primary rounded text-sm disabled:opacity-50",
|
|
715
|
-
children: [
|
|
716
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.CheckIcon, { className: "w-4 h-4 inline" }),
|
|
717
|
-
" Confirm"
|
|
718
|
-
]
|
|
719
|
-
}
|
|
720
|
-
)
|
|
721
|
-
] })
|
|
722
|
-
] }) }),
|
|
723
|
-
document.body
|
|
509
|
+
),
|
|
510
|
+
children ? children(state) : (
|
|
511
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
512
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("img", __spreadProps(__spreadValues({}, state.imgProps), { alt: "" }))
|
|
724
513
|
)
|
|
725
514
|
] });
|
|
726
515
|
}
|
|
727
516
|
|
|
728
517
|
// src/client/MarkdownEditor.tsx
|
|
729
518
|
var import_react5 = require("react");
|
|
730
|
-
|
|
731
|
-
var import_react_markdown = __toESM(require("react-markdown"), 1);
|
|
732
|
-
var import_remark_gfm = __toESM(require("remark-gfm"), 1);
|
|
733
|
-
var import_lucide_react2 = require("lucide-react");
|
|
734
|
-
var import_sonner2 = require("sonner");
|
|
735
|
-
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
736
|
-
function MarkdownEditor({
|
|
519
|
+
function useMarkdownEditor({
|
|
737
520
|
initialValue,
|
|
738
|
-
onSave,
|
|
739
|
-
trigger,
|
|
740
|
-
title = "Edit Content"
|
|
741
|
-
}) {
|
|
742
|
-
const [open, setOpen] = (0, import_react5.useState)(false);
|
|
743
|
-
const [content, setContent] = (0, import_react5.useState)(initialValue);
|
|
744
|
-
const [isPreview, setIsPreview] = (0, import_react5.useState)(false);
|
|
745
|
-
const handleOpen = () => {
|
|
746
|
-
setContent(initialValue);
|
|
747
|
-
setOpen(true);
|
|
748
|
-
};
|
|
749
|
-
const handleSave = () => {
|
|
750
|
-
onSave(content);
|
|
751
|
-
setOpen(false);
|
|
752
|
-
};
|
|
753
|
-
const handleCancel = () => {
|
|
754
|
-
setContent(initialValue);
|
|
755
|
-
setOpen(false);
|
|
756
|
-
};
|
|
757
|
-
const insertMarkdown = (before, after = "", placeholder = "text") => {
|
|
758
|
-
const textarea = document.querySelector(
|
|
759
|
-
"textarea[data-markdown-editor]"
|
|
760
|
-
);
|
|
761
|
-
if (!textarea) return;
|
|
762
|
-
const start = textarea.selectionStart;
|
|
763
|
-
const end = textarea.selectionEnd;
|
|
764
|
-
const selectedText = content.substring(start, end) || placeholder;
|
|
765
|
-
const newText = content.substring(0, start) + before + selectedText + after + content.substring(end);
|
|
766
|
-
setContent(newText);
|
|
767
|
-
setTimeout(() => {
|
|
768
|
-
textarea.focus();
|
|
769
|
-
const newCursorPos = start + before.length + selectedText.length;
|
|
770
|
-
textarea.setSelectionRange(newCursorPos, newCursorPos);
|
|
771
|
-
}, 0);
|
|
772
|
-
};
|
|
773
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
774
|
-
trigger ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { onClick: handleOpen, children: trigger }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
775
|
-
"button",
|
|
776
|
-
{
|
|
777
|
-
type: "button",
|
|
778
|
-
onClick: handleOpen,
|
|
779
|
-
className: "inline-flex items-center gap-2 px-3 py-1.5 text-sm rounded-lg border border-neutral-700 hover:bg-neutral-800 transition-colors",
|
|
780
|
-
children: [
|
|
781
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.EditIcon, { className: "w-4 h-4" }),
|
|
782
|
-
"Edit Content"
|
|
783
|
-
]
|
|
784
|
-
}
|
|
785
|
-
),
|
|
786
|
-
open && (0, import_react_dom2.createPortal)(
|
|
787
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "fixed inset-0 z-[10001] flex items-center justify-center bg-black/70 p-4", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "md:max-w-6xl w-full h-[90vh] flex flex-col bg-neutral-950 border border-neutral-800 rounded-xl overflow-hidden", children: [
|
|
788
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "px-6 pt-6 pb-4 border-b border-neutral-800", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
789
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("h2", { className: "text-2xl font-bold flex items-center gap-3", children: [
|
|
790
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "p-2 bg-primary/10 rounded-lg", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.TypeIcon, { className: "w-5 h-5 text-primary" }) }),
|
|
791
|
-
title
|
|
792
|
-
] }),
|
|
793
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
794
|
-
"button",
|
|
795
|
-
{
|
|
796
|
-
type: "button",
|
|
797
|
-
onClick: () => setIsPreview(!isPreview),
|
|
798
|
-
className: cn(
|
|
799
|
-
"flex items-center gap-2 px-4 py-2 rounded-lg transition-all font-medium",
|
|
800
|
-
isPreview ? "bg-primary text-white" : "bg-neutral-800 hover:bg-neutral-700 text-neutral-300"
|
|
801
|
-
),
|
|
802
|
-
children: isPreview ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
803
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.EditIcon, { className: "w-4 h-4" }),
|
|
804
|
-
"Edit"
|
|
805
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
806
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.EyeIcon, { className: "w-4 h-4" }),
|
|
807
|
-
"Preview"
|
|
808
|
-
] })
|
|
809
|
-
}
|
|
810
|
-
)
|
|
811
|
-
] }) }),
|
|
812
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex-1 overflow-hidden flex flex-col", children: [
|
|
813
|
-
!isPreview && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-1 px-4 py-3 border-b border-neutral-800 bg-neutral-900/50 overflow-x-auto", children: [
|
|
814
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
815
|
-
ToolbarButton,
|
|
816
|
-
{
|
|
817
|
-
icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.Heading1Icon, { className: "w-4 h-4" }),
|
|
818
|
-
label: "Heading 1",
|
|
819
|
-
onClick: () => insertMarkdown("# ", "", "Heading")
|
|
820
|
-
}
|
|
821
|
-
),
|
|
822
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
823
|
-
ToolbarButton,
|
|
824
|
-
{
|
|
825
|
-
icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.Heading2Icon, { className: "w-4 h-4" }),
|
|
826
|
-
label: "Heading 2",
|
|
827
|
-
onClick: () => insertMarkdown("## ", "", "Heading")
|
|
828
|
-
}
|
|
829
|
-
),
|
|
830
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-px h-6 bg-neutral-700 mx-1" }),
|
|
831
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
832
|
-
ToolbarButton,
|
|
833
|
-
{
|
|
834
|
-
icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.BoldIcon, { className: "w-4 h-4" }),
|
|
835
|
-
label: "Bold",
|
|
836
|
-
onClick: () => insertMarkdown("**", "**", "bold text")
|
|
837
|
-
}
|
|
838
|
-
),
|
|
839
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
840
|
-
ToolbarButton,
|
|
841
|
-
{
|
|
842
|
-
icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.ItalicIcon, { className: "w-4 h-4" }),
|
|
843
|
-
label: "Italic",
|
|
844
|
-
onClick: () => insertMarkdown("*", "*", "italic text")
|
|
845
|
-
}
|
|
846
|
-
),
|
|
847
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-px h-6 bg-neutral-700 mx-1" }),
|
|
848
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
849
|
-
ToolbarButton,
|
|
850
|
-
{
|
|
851
|
-
icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.LinkIcon, { className: "w-4 h-4" }),
|
|
852
|
-
label: "Link",
|
|
853
|
-
onClick: () => insertMarkdown("[", "](url)", "link text")
|
|
854
|
-
}
|
|
855
|
-
),
|
|
856
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
857
|
-
ToolbarButton,
|
|
858
|
-
{
|
|
859
|
-
icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.ImageIcon, { className: "w-4 h-4" }),
|
|
860
|
-
label: "Image",
|
|
861
|
-
onClick: () => insertMarkdown("", "alt text")
|
|
862
|
-
}
|
|
863
|
-
),
|
|
864
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-px h-6 bg-neutral-700 mx-1" }),
|
|
865
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
866
|
-
ToolbarButton,
|
|
867
|
-
{
|
|
868
|
-
icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.ListIcon, { className: "w-4 h-4" }),
|
|
869
|
-
label: "List",
|
|
870
|
-
onClick: () => insertMarkdown("- ", "", "list item")
|
|
871
|
-
}
|
|
872
|
-
),
|
|
873
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
874
|
-
ToolbarButton,
|
|
875
|
-
{
|
|
876
|
-
icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.CodeIcon, { className: "w-4 h-4" }),
|
|
877
|
-
label: "Code",
|
|
878
|
-
onClick: () => insertMarkdown("```\n", "\n```", "code")
|
|
879
|
-
}
|
|
880
|
-
)
|
|
881
|
-
] }),
|
|
882
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex-1 overflow-auto p-6", children: isPreview ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "prose prose-invert prose-lg max-w-none", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default], children: content }) }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "h-full flex flex-col", children: [
|
|
883
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
884
|
-
"textarea",
|
|
885
|
-
{
|
|
886
|
-
"data-markdown-editor": true,
|
|
887
|
-
value: content,
|
|
888
|
-
onChange: (e) => setContent(e.target.value),
|
|
889
|
-
className: "h-full w-full resize-none rounded-md font-mono text-sm bg-neutral-900/50 border border-neutral-800 p-3 outline-none focus:border-primary",
|
|
890
|
-
placeholder: "# Project Title\n\n## Overview\nWrite your description here..."
|
|
891
|
-
}
|
|
892
|
-
),
|
|
893
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "mt-4 p-4 bg-neutral-900/50 border border-neutral-800 rounded-lg", children: [
|
|
894
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("h4", { className: "text-sm font-semibold mb-3 text-neutral-300 flex items-center gap-2", children: [
|
|
895
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.CodeIcon, { className: "w-4 h-4 text-primary" }),
|
|
896
|
-
"Markdown Guide"
|
|
897
|
-
] }),
|
|
898
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "grid grid-cols-2 md:grid-cols-3 gap-3 text-xs", children: [
|
|
899
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GuideItem, { code: "# Heading 1", desc: "Main heading" }),
|
|
900
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GuideItem, { code: "## Heading 2", desc: "Sub heading" }),
|
|
901
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GuideItem, { code: "**bold**", desc: "Bold text" }),
|
|
902
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GuideItem, { code: "*italic*", desc: "Italic text" }),
|
|
903
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GuideItem, { code: "[link](url)", desc: "Hyperlink" }),
|
|
904
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GuideItem, { code: "- list item", desc: "Bullet list" })
|
|
905
|
-
] })
|
|
906
|
-
] })
|
|
907
|
-
] }) })
|
|
908
|
-
] }),
|
|
909
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "px-6 py-4 border-t border-neutral-800 bg-neutral-900/30", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between w-full", children: [
|
|
910
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "text-sm text-neutral-500", children: [
|
|
911
|
-
content.length,
|
|
912
|
-
" characters"
|
|
913
|
-
] }),
|
|
914
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex gap-2", children: [
|
|
915
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
916
|
-
"button",
|
|
917
|
-
{
|
|
918
|
-
type: "button",
|
|
919
|
-
onClick: handleCancel,
|
|
920
|
-
className: "inline-flex items-center gap-2 px-4 py-2 text-sm rounded-md border border-neutral-700 hover:bg-neutral-800 transition-colors",
|
|
921
|
-
children: [
|
|
922
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.XIcon, { className: "w-4 h-4" }),
|
|
923
|
-
"Cancel"
|
|
924
|
-
]
|
|
925
|
-
}
|
|
926
|
-
),
|
|
927
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
928
|
-
"button",
|
|
929
|
-
{
|
|
930
|
-
type: "button",
|
|
931
|
-
onClick: handleSave,
|
|
932
|
-
className: "inline-flex items-center gap-2 px-4 py-2 text-sm rounded-md bg-primary text-white hover:opacity-90 transition-opacity",
|
|
933
|
-
children: [
|
|
934
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.SaveIcon, { className: "w-4 h-4" }),
|
|
935
|
-
"Save Content"
|
|
936
|
-
]
|
|
937
|
-
}
|
|
938
|
-
)
|
|
939
|
-
] })
|
|
940
|
-
] }) })
|
|
941
|
-
] }) }),
|
|
942
|
-
document.body
|
|
943
|
-
)
|
|
944
|
-
] });
|
|
945
|
-
}
|
|
946
|
-
function ToolbarButton({
|
|
947
|
-
icon,
|
|
948
|
-
label,
|
|
949
|
-
onClick
|
|
950
|
-
}) {
|
|
951
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
952
|
-
"button",
|
|
953
|
-
{
|
|
954
|
-
type: "button",
|
|
955
|
-
onClick,
|
|
956
|
-
title: label,
|
|
957
|
-
className: "p-2 rounded-lg hover:bg-neutral-800 text-neutral-400 hover:text-white transition-colors",
|
|
958
|
-
children: icon
|
|
959
|
-
}
|
|
960
|
-
);
|
|
961
|
-
}
|
|
962
|
-
function GuideItem({ code, desc }) {
|
|
963
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
964
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { className: "text-primary bg-primary/10 px-2 py-1 rounded text-xs font-mono", children: code }),
|
|
965
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-neutral-500", children: desc })
|
|
966
|
-
] });
|
|
967
|
-
}
|
|
968
|
-
function ProjectContentEditor({
|
|
969
|
-
content,
|
|
970
521
|
onSave
|
|
971
522
|
}) {
|
|
972
|
-
const [
|
|
973
|
-
const
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
disabled: saving,
|
|
996
|
-
children: [
|
|
997
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.EditIcon, { className: "w-4 h-4" }),
|
|
998
|
-
saving ? "Saving..." : "Edit Full Content"
|
|
999
|
-
]
|
|
1000
|
-
}
|
|
1001
|
-
)
|
|
1002
|
-
}
|
|
523
|
+
const [value, setValue] = (0, import_react5.useState)(initialValue);
|
|
524
|
+
const textareaRef = (0, import_react5.useRef)(null);
|
|
525
|
+
const insert = (0, import_react5.useCallback)(
|
|
526
|
+
(before, after = "", placeholder = "text") => {
|
|
527
|
+
var _a, _b;
|
|
528
|
+
const textarea = textareaRef.current;
|
|
529
|
+
const start = (_a = textarea == null ? void 0 : textarea.selectionStart) != null ? _a : value.length;
|
|
530
|
+
const end = (_b = textarea == null ? void 0 : textarea.selectionEnd) != null ? _b : value.length;
|
|
531
|
+
const selected = value.substring(start, end) || placeholder;
|
|
532
|
+
const next = value.substring(0, start) + before + selected + after + value.substring(end);
|
|
533
|
+
setValue(next);
|
|
534
|
+
setTimeout(() => {
|
|
535
|
+
if (!textarea) return;
|
|
536
|
+
textarea.focus();
|
|
537
|
+
const caret = start + before.length + selected.length;
|
|
538
|
+
textarea.setSelectionRange(caret, caret);
|
|
539
|
+
}, 0);
|
|
540
|
+
},
|
|
541
|
+
[value]
|
|
542
|
+
);
|
|
543
|
+
const reset = (0, import_react5.useCallback)(
|
|
544
|
+
(to = initialValue) => setValue(to),
|
|
545
|
+
[initialValue]
|
|
1003
546
|
);
|
|
547
|
+
const save = (0, import_react5.useCallback)(() => onSave(value), [onSave, value]);
|
|
548
|
+
return {
|
|
549
|
+
value,
|
|
550
|
+
setValue,
|
|
551
|
+
textareaRef,
|
|
552
|
+
insert,
|
|
553
|
+
reset,
|
|
554
|
+
save,
|
|
555
|
+
charCount: value.length
|
|
556
|
+
};
|
|
1004
557
|
}
|
|
1005
558
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1006
559
|
0 && (module.exports = {
|
|
@@ -1008,11 +561,9 @@ function ProjectContentEditor({
|
|
|
1008
561
|
CmsAuthProvider,
|
|
1009
562
|
ContentEditSpan,
|
|
1010
563
|
EditableImage,
|
|
1011
|
-
MarkdownEditor,
|
|
1012
564
|
PageProvider,
|
|
1013
|
-
ProjectContentEditor,
|
|
1014
|
-
cn,
|
|
1015
565
|
useCmsAuth,
|
|
566
|
+
useMarkdownEditor,
|
|
1016
567
|
usePageContext
|
|
1017
568
|
});
|
|
1018
569
|
//# sourceMappingURL=index.cjs.map
|