@kyro-cms/admin 0.9.4 → 0.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +966 -585
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +29 -9
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +649 -268
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/ActionBar.tsx +254 -70
- package/src/components/Admin.tsx +10 -17
- package/src/components/ApiKeysManager.tsx +1 -0
- package/src/components/AuditLogsPage.tsx +3 -3
- package/src/components/AutoForm.tsx +51 -34
- package/src/components/DetailView.tsx +37 -13
- package/src/components/GraphQLPlayground.tsx +460 -224
- package/src/components/ListView.tsx +3 -3
- package/src/components/LoginPage.tsx +5 -30
- package/src/components/MediaGallery.tsx +122 -15
- package/src/components/RestPlayground.tsx +443 -519
- package/src/components/Sidebar.astro +6 -2
- package/src/components/UserManagement.tsx +4 -4
- package/src/components/WebhookManager.tsx +4 -4
- package/src/components/blocks/AccordionBlock.tsx +1 -1
- package/src/components/blocks/ArrayBlock.tsx +1 -1
- package/src/components/blocks/ChildBlocksTree.tsx +6 -6
- package/src/components/blocks/CodeBlock.tsx +1 -1
- package/src/components/blocks/FileBlock.tsx +1 -1
- package/src/components/blocks/HeroBlock.tsx +1 -1
- package/src/components/blocks/ListBlock.tsx +1 -1
- package/src/components/blocks/RelationshipBlock.tsx +1 -1
- package/src/components/blocks/RichTextBlock.tsx +1 -1
- package/src/components/blocks/VideoBlock.tsx +1 -1
- package/src/components/fields/BlocksField.tsx +17 -19
- package/src/components/ui/PageHeader.tsx +205 -83
- package/src/components/ui/Pagination.tsx +2 -2
- package/src/components/ui/SlidePanel.tsx +4 -4
- package/src/layouts/AdminLayout.astro +64 -4
- package/src/lib/useResourceManager.ts +1 -0
- package/src/pages/graphql-explorer.astro +7 -51
- package/src/pages/graphql.astro +7 -119
- package/src/pages/index.astro +4 -63
- package/src/pages/rest-playground.astro +3 -29
- package/src/styles/main.css +32 -9
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React = require('react');
|
|
4
4
|
var zustand = require('zustand');
|
|
5
5
|
var middleware = require('zustand/middleware');
|
|
6
6
|
var lucideReact = require('lucide-react');
|
|
@@ -41,7 +41,7 @@ var worker_threads = require('worker_threads');
|
|
|
41
41
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
42
42
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
43
43
|
|
|
44
|
-
var
|
|
44
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
45
45
|
var StarterKit__default = /*#__PURE__*/_interopDefault(StarterKit);
|
|
46
46
|
var Link4__default = /*#__PURE__*/_interopDefault(Link4);
|
|
47
47
|
var Image3__default = /*#__PURE__*/_interopDefault(Image3);
|
|
@@ -458,6 +458,84 @@ function Shimmer({ variant, count = 1, className = "" }) {
|
|
|
458
458
|
i
|
|
459
459
|
)) });
|
|
460
460
|
}
|
|
461
|
+
function BackButton({ back }) {
|
|
462
|
+
if (back.href) {
|
|
463
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
464
|
+
"a",
|
|
465
|
+
{
|
|
466
|
+
href: back.href,
|
|
467
|
+
onClick: (e) => {
|
|
468
|
+
if (back.onClick) {
|
|
469
|
+
e.preventDefault();
|
|
470
|
+
back.onClick();
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
className: "p-1.5 rounded-lg hover:bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-secondary)] transition-all",
|
|
474
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 12H5M12 19l-7-7 7-7" }) })
|
|
475
|
+
}
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
479
|
+
"button",
|
|
480
|
+
{
|
|
481
|
+
type: "button",
|
|
482
|
+
onClick: back.onClick,
|
|
483
|
+
className: "p-1.5 rounded-lg hover:bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-secondary)] transition-all",
|
|
484
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 12H5M12 19l-7-7 7-7" }) })
|
|
485
|
+
}
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
function DesktopBreadcrumbs({ breadcrumbs }) {
|
|
489
|
+
return breadcrumbs?.map((crumb, i) => /* @__PURE__ */ jsxRuntime.jsxs(React__default.default.Fragment, { children: [
|
|
490
|
+
i > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-20 text-[10px]", children: "/" }),
|
|
491
|
+
crumb.href || crumb.onClick ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
492
|
+
"a",
|
|
493
|
+
{
|
|
494
|
+
href: crumb.href,
|
|
495
|
+
onClick: (e) => {
|
|
496
|
+
if (crumb.onClick) {
|
|
497
|
+
e.preventDefault();
|
|
498
|
+
crumb.onClick();
|
|
499
|
+
}
|
|
500
|
+
},
|
|
501
|
+
className: "text-[10px] font-bold tracking-widest text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-primary)] transition-all",
|
|
502
|
+
children: crumb.label
|
|
503
|
+
}
|
|
504
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold tracking-widest opacity-40", children: crumb.label })
|
|
505
|
+
] }, i));
|
|
506
|
+
}
|
|
507
|
+
function ActionsSlot({ actions }) {
|
|
508
|
+
if (Array.isArray(actions)) {
|
|
509
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3", children: actions.map((act, i) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
510
|
+
"button",
|
|
511
|
+
{
|
|
512
|
+
type: "button",
|
|
513
|
+
onClick: act.onClick,
|
|
514
|
+
className: `flex items-center gap-2 px-6 py-2.5 rounded-xl font-bold text-sm transition-all shadow-lg shadow-[var(--kyro-primary)]/10 ${act.variant === "outline" ? "border border-[var(--kyro-border)] text-[var(--kyro-text-secondary)] hover:bg-[var(--kyro-surface-accent)]" : act.variant === "ghost" ? "text-[var(--kyro-text-secondary)] hover:bg-[var(--kyro-surface-accent)] shadow-none" : "kyro-btn-primary hover:opacity-90"} ${act.className || ""}`,
|
|
515
|
+
children: [
|
|
516
|
+
act.icon && /* @__PURE__ */ jsxRuntime.jsx(act.icon, { className: "w-4 h-4" }),
|
|
517
|
+
act.label
|
|
518
|
+
]
|
|
519
|
+
},
|
|
520
|
+
i
|
|
521
|
+
)) });
|
|
522
|
+
}
|
|
523
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: actions });
|
|
524
|
+
}
|
|
525
|
+
function SingleAction({ action }) {
|
|
526
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
527
|
+
"button",
|
|
528
|
+
{
|
|
529
|
+
type: "button",
|
|
530
|
+
onClick: action.onClick,
|
|
531
|
+
className: `kyro-btn kyro-btn-primary flex items-center gap-2 px-6 py-2.5 rounded-xl font-bold text-sm hover:opacity-90 transition-all shadow-lg shadow-[var(--kyro-primary)]/10 w-full lg:w-auto justify-center ${action.className || ""}`,
|
|
532
|
+
children: [
|
|
533
|
+
action.icon && /* @__PURE__ */ jsxRuntime.jsx(action.icon, { className: "w-4 h-4" }),
|
|
534
|
+
action.label
|
|
535
|
+
]
|
|
536
|
+
}
|
|
537
|
+
);
|
|
538
|
+
}
|
|
461
539
|
function PageHeader({
|
|
462
540
|
title,
|
|
463
541
|
description,
|
|
@@ -469,80 +547,79 @@ function PageHeader({
|
|
|
469
547
|
actions,
|
|
470
548
|
children
|
|
471
549
|
}) {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
e.preventDefault();
|
|
498
|
-
crumb.onClick();
|
|
550
|
+
const lastBreadcrumb = breadcrumbs?.[breadcrumbs.length - 1];
|
|
551
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "surface-tile px-3 md:px-6 py-3 md:pt-4 mb-4 md:mb-8", children: [
|
|
552
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:hidden space-y-2", children: [
|
|
553
|
+
(breadcrumbs || back) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
554
|
+
back && /* @__PURE__ */ jsxRuntime.jsx(BackButton, { back }),
|
|
555
|
+
/* @__PURE__ */ jsxRuntime.jsxs("details", { className: "group [&::-webkit-details-marker]:hidden flex-1 min-w-0", children: [
|
|
556
|
+
/* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "flex items-center gap-2 cursor-pointer list-none", children: [
|
|
557
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 text-[10px] font-bold tracking-widest text-[var(--kyro-text-secondary)] truncate", children: lastBreadcrumb?.label || "" }),
|
|
558
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-3 h-3 text-[var(--kyro-text-secondary)] opacity-40 group-open:rotate-180 transition-transform", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 9l6 6 6-6" }) })
|
|
559
|
+
] }),
|
|
560
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 pt-2 border-t border-[var(--kyro-border)] space-y-2", children: [
|
|
561
|
+
breadcrumbs && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: breadcrumbs.map((crumb, i) => /* @__PURE__ */ jsxRuntime.jsxs(React__default.default.Fragment, { children: [
|
|
562
|
+
i > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-20 text-[10px]", children: "/" }),
|
|
563
|
+
crumb.href || crumb.onClick ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
564
|
+
"a",
|
|
565
|
+
{
|
|
566
|
+
href: crumb.href,
|
|
567
|
+
onClick: (e) => {
|
|
568
|
+
if (crumb.onClick) {
|
|
569
|
+
e.preventDefault();
|
|
570
|
+
crumb.onClick();
|
|
571
|
+
}
|
|
572
|
+
},
|
|
573
|
+
className: "text-[10px] font-bold tracking-widest text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-primary)] transition-all",
|
|
574
|
+
children: crumb.label
|
|
499
575
|
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
] }
|
|
576
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold tracking-widest opacity-40", children: crumb.label })
|
|
577
|
+
] }, i)) }),
|
|
578
|
+
metadata && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 flex-wrap", children: metadata.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(React__default.default.Fragment, { children: item }, i)) }),
|
|
579
|
+
children
|
|
580
|
+
] })
|
|
581
|
+
] })
|
|
506
582
|
] }),
|
|
507
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-
|
|
508
|
-
Icon && /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-
|
|
509
|
-
title && /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-
|
|
583
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
584
|
+
Icon && /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-5 h-5 text-[var(--kyro-primary)] shrink-0" }),
|
|
585
|
+
title && /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-bold tracking-tighter text-[var(--kyro-text-primary)] truncate", children: title }),
|
|
586
|
+
metadata && !description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-2 w-2 rounded-full bg-[var(--kyro-primary)] shrink-0" })
|
|
510
587
|
] }),
|
|
511
|
-
description && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2
|
|
512
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[var(--kyro-text-secondary)] font-medium opacity-60 line-clamp-1", children: description }),
|
|
513
|
-
metadata && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: metadata.map((item, i) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
588
|
+
description && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-1", children: [
|
|
589
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[var(--kyro-text-secondary)] font-medium opacity-60 line-clamp-1 min-w-0 text-xs", children: description }),
|
|
590
|
+
metadata && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: metadata.map((item, i) => /* @__PURE__ */ jsxRuntime.jsxs(React__default.default.Fragment, { children: [
|
|
514
591
|
i === 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-20 ml-1", children: "\xB7" }),
|
|
515
592
|
item
|
|
516
|
-
] }, i)) })
|
|
517
|
-
children
|
|
593
|
+
] }, i)) })
|
|
518
594
|
] })
|
|
519
595
|
] }),
|
|
520
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-
|
|
521
|
-
|
|
522
|
-
"
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
)
|
|
596
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "hidden md:flex md:flex-row md:items-center justify-between gap-6", children: [
|
|
597
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
598
|
+
(breadcrumbs || back) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-3", children: [
|
|
599
|
+
back && /* @__PURE__ */ jsxRuntime.jsx(BackButton, { back }),
|
|
600
|
+
breadcrumbs && /* @__PURE__ */ jsxRuntime.jsx(DesktopBreadcrumbs, { breadcrumbs })
|
|
601
|
+
] }),
|
|
602
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
603
|
+
Icon && /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-6 h-6 text-[var(--kyro-primary)]" }),
|
|
604
|
+
title && /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-bold tracking-tighter text-[var(--kyro-text-primary)] truncate", children: title })
|
|
605
|
+
] }),
|
|
606
|
+
(description || metadata) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-1 mt-1", children: [
|
|
607
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[var(--kyro-text-secondary)] font-medium opacity-60 line-clamp-1 min-w-0", children: description }),
|
|
608
|
+
metadata && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: metadata.map((item, i) => /* @__PURE__ */ jsxRuntime.jsxs(React__default.default.Fragment, { children: [
|
|
609
|
+
i === 0 && (description || i > 0) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-20 ml-1", children: "\xB7" }),
|
|
610
|
+
item
|
|
611
|
+
] }, i)) }),
|
|
612
|
+
children
|
|
613
|
+
] })
|
|
614
|
+
] }),
|
|
615
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 flex-wrap shrink-0", children: [
|
|
616
|
+
actions && /* @__PURE__ */ jsxRuntime.jsx(ActionsSlot, { actions }),
|
|
617
|
+
action && /* @__PURE__ */ jsxRuntime.jsx(SingleAction, { action })
|
|
618
|
+
] })
|
|
619
|
+
] }),
|
|
620
|
+
(actions || action) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:hidden flex items-center gap-2 mt-3 pt-3 border-t border-[var(--kyro-border)]", children: [
|
|
621
|
+
action && /* @__PURE__ */ jsxRuntime.jsx(SingleAction, { action }),
|
|
622
|
+
actions && /* @__PURE__ */ jsxRuntime.jsx(ActionsSlot, { actions })
|
|
546
623
|
] })
|
|
547
624
|
] });
|
|
548
625
|
}
|
|
@@ -604,7 +681,7 @@ function Button({
|
|
|
604
681
|
}
|
|
605
682
|
function Pagination({ page, totalPages, totalDocs, limit, onPageChange, onLimitChange }) {
|
|
606
683
|
if (totalPages <= 1) return null;
|
|
607
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-t border-[var(--kyro-border)]", children: [
|
|
684
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col sm:flex-row items-center justify-between gap-3 px-4 py-3 border-t border-[var(--kyro-border)]", children: [
|
|
608
685
|
totalDocs !== void 0 && limit ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-[var(--kyro-text-secondary)] font-medium", children: [
|
|
609
686
|
"Showing ",
|
|
610
687
|
(page - 1) * limit + 1,
|
|
@@ -613,7 +690,7 @@ function Pagination({ page, totalPages, totalDocs, limit, onPageChange, onLimitC
|
|
|
613
690
|
" of ",
|
|
614
691
|
totalDocs
|
|
615
692
|
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", {}),
|
|
616
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
693
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-wrap justify-center", children: [
|
|
617
694
|
onLimitChange && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
618
695
|
"select",
|
|
619
696
|
{
|
|
@@ -730,14 +807,14 @@ function ListView({
|
|
|
730
807
|
window.location.href = `${adminPath}/${collectionSlug}/${id}`;
|
|
731
808
|
}
|
|
732
809
|
};
|
|
733
|
-
const [docs, setDocs] =
|
|
734
|
-
const [totalDocs, setTotalDocs] =
|
|
735
|
-
const [loading, setLoading] =
|
|
736
|
-
const [page, setPage] =
|
|
737
|
-
const [limit, setLimit] =
|
|
738
|
-
const [selectedIds, setSelectedIds] =
|
|
739
|
-
const [search, setSearch] =
|
|
740
|
-
const [filters, setFilters] =
|
|
810
|
+
const [docs, setDocs] = React.useState(initialDocs);
|
|
811
|
+
const [totalDocs, setTotalDocs] = React.useState(initialTotal);
|
|
812
|
+
const [loading, setLoading] = React.useState(false);
|
|
813
|
+
const [page, setPage] = React.useState(1);
|
|
814
|
+
const [limit, setLimit] = React.useState(10);
|
|
815
|
+
const [selectedIds, setSelectedIds] = React.useState(/* @__PURE__ */ new Set());
|
|
816
|
+
const [search, setSearch] = React.useState("");
|
|
817
|
+
const [filters, setFilters] = React.useState([]);
|
|
741
818
|
const { confirm, alert } = useUIStore();
|
|
742
819
|
const addFilter = () => {
|
|
743
820
|
setFilters([...filters, { field: "", operator: "equals", value: "" }]);
|
|
@@ -753,9 +830,9 @@ function ListView({
|
|
|
753
830
|
const updateFilter = (index, updates) => {
|
|
754
831
|
setFilters(filters.map((f, i) => i === index ? { ...f, ...updates } : f));
|
|
755
832
|
};
|
|
756
|
-
const [sort, setSort] =
|
|
757
|
-
const [showFilters, setShowFilters] =
|
|
758
|
-
const [showColumns, setShowColumns] =
|
|
833
|
+
const [sort, setSort] = React.useState(null);
|
|
834
|
+
const [showFilters, setShowFilters] = React.useState(false);
|
|
835
|
+
const [showColumns, setShowColumns] = React.useState(false);
|
|
759
836
|
function flattenFields(fields2) {
|
|
760
837
|
const result = [];
|
|
761
838
|
for (const field3 of fields2 || []) {
|
|
@@ -774,12 +851,12 @@ function ListView({
|
|
|
774
851
|
}
|
|
775
852
|
return result;
|
|
776
853
|
}
|
|
777
|
-
const allFields =
|
|
854
|
+
const allFields = React.useMemo(
|
|
778
855
|
() => flattenFields(collection.fields),
|
|
779
856
|
[collection.fields]
|
|
780
857
|
);
|
|
781
858
|
const titleField = typeof collection.admin?.useAsTitle === "string" ? collection.admin.useAsTitle : allFields.find((f) => f.type !== "group" && typeof f.name === "string")?.name;
|
|
782
|
-
const [visibleColumns, setVisibleColumns] =
|
|
859
|
+
const [visibleColumns, setVisibleColumns] = React.useState(() => {
|
|
783
860
|
let cols;
|
|
784
861
|
if (collection.admin?.defaultColumns) {
|
|
785
862
|
cols = [...collection.admin?.defaultColumns || []];
|
|
@@ -794,7 +871,7 @@ function ListView({
|
|
|
794
871
|
}
|
|
795
872
|
return new Set(cols);
|
|
796
873
|
});
|
|
797
|
-
const toggleColumn =
|
|
874
|
+
const toggleColumn = React.useCallback((fieldName) => {
|
|
798
875
|
setVisibleColumns((prev) => {
|
|
799
876
|
const next = new Set(prev);
|
|
800
877
|
if (next.has(fieldName)) {
|
|
@@ -813,7 +890,7 @@ function ListView({
|
|
|
813
890
|
}
|
|
814
891
|
return fieldName;
|
|
815
892
|
}
|
|
816
|
-
const handleSort =
|
|
893
|
+
const handleSort = React.useCallback((fieldName) => {
|
|
817
894
|
const resolvedField = resolveSortField(fieldName);
|
|
818
895
|
setSort((prev) => {
|
|
819
896
|
if (prev && prev.field === resolvedField) {
|
|
@@ -825,7 +902,7 @@ function ListView({
|
|
|
825
902
|
return { field: resolvedField, direction: "asc" };
|
|
826
903
|
});
|
|
827
904
|
}, []);
|
|
828
|
-
const displayFields =
|
|
905
|
+
const displayFields = React.useMemo(
|
|
829
906
|
() => {
|
|
830
907
|
const fields2 = allFields.filter((f) => !!f.name && visibleColumns.has(f.name));
|
|
831
908
|
if (visibleColumns.has("status")) {
|
|
@@ -855,7 +932,7 @@ function ListView({
|
|
|
855
932
|
const val = resolveFieldValue(collection.fields, doc, field3.name);
|
|
856
933
|
return val ?? null;
|
|
857
934
|
}
|
|
858
|
-
const fetchDocs =
|
|
935
|
+
const fetchDocs = React.useCallback(async () => {
|
|
859
936
|
setLoading(true);
|
|
860
937
|
try {
|
|
861
938
|
const params = new URLSearchParams({
|
|
@@ -880,13 +957,13 @@ function ListView({
|
|
|
880
957
|
setLoading(false);
|
|
881
958
|
}
|
|
882
959
|
}, [collectionSlug, page, limit, search, sort, filters]);
|
|
883
|
-
|
|
960
|
+
React.useEffect(() => {
|
|
884
961
|
if (docs.length === 0 && initialTotal === 0) {
|
|
885
962
|
fetchDocs();
|
|
886
963
|
}
|
|
887
964
|
}, []);
|
|
888
|
-
const isFirstRender =
|
|
889
|
-
|
|
965
|
+
const isFirstRender = React.useRef(true);
|
|
966
|
+
React.useEffect(() => {
|
|
890
967
|
if (isFirstRender.current) {
|
|
891
968
|
isFirstRender.current = false;
|
|
892
969
|
return;
|
|
@@ -968,8 +1045,8 @@ function ListView({
|
|
|
968
1045
|
}
|
|
969
1046
|
),
|
|
970
1047
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "surface-tile p-4 flex flex-col lg:flex-row gap-4 items-start lg:items-center", children: [
|
|
971
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1 max-w-md", children: [
|
|
972
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "w-4 h-4" }),
|
|
1048
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1 w-full lg:max-w-md", children: [
|
|
1049
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-[var(--kyro-text-muted)]" }),
|
|
973
1050
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
974
1051
|
"input",
|
|
975
1052
|
{
|
|
@@ -1161,7 +1238,7 @@ function ListView({
|
|
|
1161
1238
|
}
|
|
1162
1239
|
)
|
|
1163
1240
|
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full text-left", children: [
|
|
1164
|
-
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "text-[var(--kyro-text-secondary)] font-bold text-[10px] tracking-[0.3em] border-b border-[var(--kyro-border)]", children: [
|
|
1241
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "text-[var(--kyro-text-secondary)] font-bold text-[10px] tracking-[0.3em] border-b border-[var(--kyro-border)] whitespace-nowrap", children: [
|
|
1165
1242
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-4 w-10", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1166
1243
|
"input",
|
|
1167
1244
|
{
|
|
@@ -1349,26 +1426,26 @@ function UploadField({
|
|
|
1349
1426
|
onChange,
|
|
1350
1427
|
disabled
|
|
1351
1428
|
}) {
|
|
1352
|
-
const inputRef =
|
|
1353
|
-
const urlInputRef =
|
|
1354
|
-
const [uploading, setUploading] =
|
|
1355
|
-
const [showPicker, setShowPicker] =
|
|
1356
|
-
const [isPickerFullscreen, setIsPickerFullscreen] =
|
|
1357
|
-
const [mediaItems, setMediaItems] =
|
|
1358
|
-
const [folders, setFolders] =
|
|
1359
|
-
const [selectedFolder, setSelectedFolder] =
|
|
1360
|
-
const [mediaLoading, setMediaLoading] =
|
|
1361
|
-
const [pickerSearch, setPickerSearch] =
|
|
1362
|
-
const [showUrlInput, setShowUrlInput] =
|
|
1363
|
-
const [urlValue, setUrlValue] =
|
|
1364
|
-
const [urlError, setUrlError] =
|
|
1365
|
-
const [selectedItems, setSelectedItems] =
|
|
1429
|
+
const inputRef = React.useRef(null);
|
|
1430
|
+
const urlInputRef = React.useRef(null);
|
|
1431
|
+
const [uploading, setUploading] = React.useState(false);
|
|
1432
|
+
const [showPicker, setShowPicker] = React.useState(false);
|
|
1433
|
+
const [isPickerFullscreen, setIsPickerFullscreen] = React.useState(false);
|
|
1434
|
+
const [mediaItems, setMediaItems] = React.useState([]);
|
|
1435
|
+
const [folders, setFolders] = React.useState([]);
|
|
1436
|
+
const [selectedFolder, setSelectedFolder] = React.useState("");
|
|
1437
|
+
const [mediaLoading, setMediaLoading] = React.useState(false);
|
|
1438
|
+
const [pickerSearch, setPickerSearch] = React.useState("");
|
|
1439
|
+
const [showUrlInput, setShowUrlInput] = React.useState(false);
|
|
1440
|
+
const [urlValue, setUrlValue] = React.useState("");
|
|
1441
|
+
const [urlError, setUrlError] = React.useState("");
|
|
1442
|
+
const [selectedItems, setSelectedItems] = React.useState([]);
|
|
1366
1443
|
const fieldLabel = field3?.label || field3?.name || "File";
|
|
1367
1444
|
const maxCount = field3.maxCount ?? (field3.hasMany ? 999 : 1);
|
|
1368
1445
|
const isMultiple = maxCount > 1;
|
|
1369
1446
|
const currentValue = Array.isArray(value) ? value : value ? [value] : [];
|
|
1370
1447
|
const canAddMore = currentValue.length < maxCount;
|
|
1371
|
-
|
|
1448
|
+
React.useEffect(() => {
|
|
1372
1449
|
const fetchMissingDetails = async () => {
|
|
1373
1450
|
const idsToFetch = currentValue.filter((item) => typeof item === "string").map((id) => id);
|
|
1374
1451
|
const objectIdsToFetch = currentValue.filter(
|
|
@@ -1402,7 +1479,7 @@ function UploadField({
|
|
|
1402
1479
|
};
|
|
1403
1480
|
fetchMissingDetails();
|
|
1404
1481
|
}, [value]);
|
|
1405
|
-
|
|
1482
|
+
React.useEffect(() => {
|
|
1406
1483
|
if (showPicker) {
|
|
1407
1484
|
loadFolders();
|
|
1408
1485
|
loadMedia();
|
|
@@ -1528,7 +1605,7 @@ function UploadField({
|
|
|
1528
1605
|
newValue.splice(index, 1);
|
|
1529
1606
|
onChange(isMultiple ? newValue : newValue[0] || null);
|
|
1530
1607
|
};
|
|
1531
|
-
const filteredMedia =
|
|
1608
|
+
const filteredMedia = React.useMemo(() => {
|
|
1532
1609
|
return mediaItems.filter((item) => {
|
|
1533
1610
|
return !pickerSearch || item.filename?.toLowerCase().includes(pickerSearch.toLowerCase()) || item.title?.toLowerCase().includes(pickerSearch.toLowerCase());
|
|
1534
1611
|
});
|
|
@@ -1935,12 +2012,12 @@ function SlidePanel({
|
|
|
1935
2012
|
showOverlay = false,
|
|
1936
2013
|
accentClass
|
|
1937
2014
|
}) {
|
|
1938
|
-
const panelRef =
|
|
1939
|
-
const [hydrated, setHydrated] =
|
|
1940
|
-
|
|
2015
|
+
const panelRef = React.useRef(null);
|
|
2016
|
+
const [hydrated, setHydrated] = React.useState(false);
|
|
2017
|
+
React.useEffect(() => {
|
|
1941
2018
|
setHydrated(true);
|
|
1942
2019
|
}, []);
|
|
1943
|
-
|
|
2020
|
+
React.useEffect(() => {
|
|
1944
2021
|
const handleEscape = (e) => {
|
|
1945
2022
|
if (e.key === "Escape") onClose();
|
|
1946
2023
|
};
|
|
@@ -1954,10 +2031,10 @@ function SlidePanel({
|
|
|
1954
2031
|
};
|
|
1955
2032
|
}, [open, onClose]);
|
|
1956
2033
|
const widthClasses = {
|
|
1957
|
-
sm: "w-[320px]",
|
|
1958
|
-
md: "w-[400px]",
|
|
1959
|
-
lg: "w-[550px]",
|
|
1960
|
-
xl: "w-[700px]"
|
|
2034
|
+
sm: "w-full sm:w-[320px]",
|
|
2035
|
+
md: "w-full sm:w-[400px]",
|
|
2036
|
+
lg: "w-full sm:w-[550px]",
|
|
2037
|
+
xl: "w-full sm:w-[700px]"
|
|
1961
2038
|
};
|
|
1962
2039
|
if (!open || !hydrated) return null;
|
|
1963
2040
|
return reactDom.createPortal(
|
|
@@ -2021,7 +2098,7 @@ function Modal({
|
|
|
2021
2098
|
size = "md",
|
|
2022
2099
|
variant = "default"
|
|
2023
2100
|
}) {
|
|
2024
|
-
|
|
2101
|
+
React.useEffect(() => {
|
|
2025
2102
|
const handleEscape = (e) => {
|
|
2026
2103
|
if (e.key === "Escape") onClose();
|
|
2027
2104
|
};
|
|
@@ -2129,7 +2206,7 @@ function PromptModal({
|
|
|
2129
2206
|
placeholder = "",
|
|
2130
2207
|
defaultValue = ""
|
|
2131
2208
|
}) {
|
|
2132
|
-
const [value, setValue] =
|
|
2209
|
+
const [value, setValue] = React.useState(defaultValue);
|
|
2133
2210
|
const handleSubmit = (e) => {
|
|
2134
2211
|
e.preventDefault();
|
|
2135
2212
|
if (value.trim()) {
|
|
@@ -2242,35 +2319,36 @@ function MediaGallery({
|
|
|
2242
2319
|
const canUpload = permissions?.media?.create !== false;
|
|
2243
2320
|
const canDelete = permissions?.media?.delete !== false;
|
|
2244
2321
|
const canUpdate = permissions?.media?.update !== false;
|
|
2245
|
-
const [items, setItems] =
|
|
2246
|
-
const [loading, setLoading] =
|
|
2247
|
-
const [folders, setFolders] =
|
|
2248
|
-
const [currentFolder, setCurrentFolder] =
|
|
2249
|
-
const [search, setSearch] =
|
|
2250
|
-
const [filter, setFilter] =
|
|
2251
|
-
const [view, setView] =
|
|
2252
|
-
const [panelItem, setPanelItem] =
|
|
2253
|
-
const [showPreview, setShowPreview] =
|
|
2254
|
-
const [showCrop, setShowCrop] =
|
|
2255
|
-
const [uploading, setUploading] =
|
|
2256
|
-
const [uploadProgress, setUploadProgress] =
|
|
2322
|
+
const [items, setItems] = React.useState([]);
|
|
2323
|
+
const [loading, setLoading] = React.useState(true);
|
|
2324
|
+
const [folders, setFolders] = React.useState([]);
|
|
2325
|
+
const [currentFolder, setCurrentFolder] = React.useState("");
|
|
2326
|
+
const [search, setSearch] = React.useState("");
|
|
2327
|
+
const [filter, setFilter] = React.useState("all");
|
|
2328
|
+
const [view, setView] = React.useState("grid");
|
|
2329
|
+
const [panelItem, setPanelItem] = React.useState(null);
|
|
2330
|
+
const [showPreview, setShowPreview] = React.useState(false);
|
|
2331
|
+
const [showCrop, setShowCrop] = React.useState(false);
|
|
2332
|
+
const [uploading, setUploading] = React.useState(false);
|
|
2333
|
+
const [uploadProgress, setUploadProgress] = React.useState(
|
|
2257
2334
|
{}
|
|
2258
2335
|
);
|
|
2259
|
-
const [showNewFolderModal, setShowNewFolderModal] =
|
|
2260
|
-
const [
|
|
2261
|
-
const [
|
|
2262
|
-
const [
|
|
2263
|
-
const [
|
|
2264
|
-
const [
|
|
2265
|
-
const [
|
|
2336
|
+
const [showNewFolderModal, setShowNewFolderModal] = React.useState(false);
|
|
2337
|
+
const [showMobileFilters, setShowMobileFilters] = React.useState(false);
|
|
2338
|
+
const [storageConfigured, setStorageConfigured] = React.useState(null);
|
|
2339
|
+
const [storageChecked, setStorageChecked] = React.useState(false);
|
|
2340
|
+
const [showStorageConfigModal, setShowStorageConfigModal] = React.useState(false);
|
|
2341
|
+
const [page, setPage] = React.useState(1);
|
|
2342
|
+
const [total, setTotal] = React.useState(0);
|
|
2343
|
+
const [totalPages, setTotalPages] = React.useState(1);
|
|
2266
2344
|
const limit = 40;
|
|
2267
|
-
const [selectedIds, setSelectedIds] =
|
|
2345
|
+
const [selectedIds, setSelectedIds] = React.useState(/* @__PURE__ */ new Set());
|
|
2268
2346
|
const { confirm, alert } = useUIStore();
|
|
2269
|
-
const [isDragging, setIsDragging] =
|
|
2270
|
-
const fileInputRef =
|
|
2271
|
-
const [crop, setCrop] =
|
|
2272
|
-
const imgRef =
|
|
2273
|
-
const loadMedia =
|
|
2347
|
+
const [isDragging, setIsDragging] = React.useState(false);
|
|
2348
|
+
const fileInputRef = React.useRef(null);
|
|
2349
|
+
const [crop, setCrop] = React.useState();
|
|
2350
|
+
const imgRef = React.useRef(null);
|
|
2351
|
+
const loadMedia = React.useCallback(async () => {
|
|
2274
2352
|
setLoading(true);
|
|
2275
2353
|
try {
|
|
2276
2354
|
const params = new URLSearchParams({
|
|
@@ -2293,7 +2371,7 @@ function MediaGallery({
|
|
|
2293
2371
|
setLoading(false);
|
|
2294
2372
|
}
|
|
2295
2373
|
}, [page, currentFolder, search, filter]);
|
|
2296
|
-
const loadFolders =
|
|
2374
|
+
const loadFolders = React.useCallback(async () => {
|
|
2297
2375
|
try {
|
|
2298
2376
|
const result = await apiGet(withCacheBust("/api/media/folders"));
|
|
2299
2377
|
setFolders(Array.isArray(result) ? result : result.folders || []);
|
|
@@ -2301,7 +2379,7 @@ function MediaGallery({
|
|
|
2301
2379
|
console.error("Failed to load folders:", error);
|
|
2302
2380
|
}
|
|
2303
2381
|
}, []);
|
|
2304
|
-
const checkStorage =
|
|
2382
|
+
const checkStorage = React.useCallback(async () => {
|
|
2305
2383
|
try {
|
|
2306
2384
|
const res = await apiGet("/api/globals/storage-settings");
|
|
2307
2385
|
const isConfigured = !!res?.data?.provider;
|
|
@@ -2310,23 +2388,23 @@ function MediaGallery({
|
|
|
2310
2388
|
setStorageConfigured(false);
|
|
2311
2389
|
}
|
|
2312
2390
|
}, []);
|
|
2313
|
-
|
|
2391
|
+
React.useEffect(() => {
|
|
2314
2392
|
if (!pickerMode) checkStorage();
|
|
2315
2393
|
}, [checkStorage, pickerMode]);
|
|
2316
|
-
|
|
2394
|
+
React.useEffect(() => {
|
|
2317
2395
|
if (pickerMode) return;
|
|
2318
2396
|
if (storageConfigured === false && !storageChecked) {
|
|
2319
2397
|
setStorageChecked(true);
|
|
2320
2398
|
setShowStorageConfigModal(true);
|
|
2321
2399
|
}
|
|
2322
2400
|
}, [pickerMode, storageConfigured, storageChecked]);
|
|
2323
|
-
|
|
2401
|
+
React.useEffect(() => {
|
|
2324
2402
|
loadMedia();
|
|
2325
2403
|
}, [loadMedia]);
|
|
2326
|
-
|
|
2404
|
+
React.useEffect(() => {
|
|
2327
2405
|
loadFolders();
|
|
2328
2406
|
}, [loadFolders]);
|
|
2329
|
-
|
|
2407
|
+
React.useEffect(() => {
|
|
2330
2408
|
if (pickerMode) return;
|
|
2331
2409
|
const handlePaste = (e) => {
|
|
2332
2410
|
const files = e.clipboardData?.files;
|
|
@@ -2410,6 +2488,7 @@ function MediaGallery({
|
|
|
2410
2488
|
await apiPost("/api/media/folders", { name });
|
|
2411
2489
|
loadFolders();
|
|
2412
2490
|
setShowNewFolderModal(false);
|
|
2491
|
+
toast.success(`Folder "${name}" created`);
|
|
2413
2492
|
} catch (error) {
|
|
2414
2493
|
console.error("Failed to create folder:", error);
|
|
2415
2494
|
toast.error("Failed to create folder");
|
|
@@ -2427,6 +2506,7 @@ function MediaGallery({
|
|
|
2427
2506
|
if (currentFolder === folder) setCurrentFolder("");
|
|
2428
2507
|
loadFolders();
|
|
2429
2508
|
loadMedia();
|
|
2509
|
+
toast.success(`Folder "${folder}" deleted`);
|
|
2430
2510
|
} catch (error) {
|
|
2431
2511
|
console.error("Failed to delete folder:", error);
|
|
2432
2512
|
toast.error("Failed to delete folder");
|
|
@@ -2441,8 +2521,10 @@ function MediaGallery({
|
|
|
2441
2521
|
if (panelItem?.id === id) {
|
|
2442
2522
|
setPanelItem(result.doc);
|
|
2443
2523
|
}
|
|
2524
|
+
toast.success("Metadata updated");
|
|
2444
2525
|
} catch (error) {
|
|
2445
2526
|
console.error("Failed to update metadata:", error);
|
|
2527
|
+
toast.error("Failed to update metadata");
|
|
2446
2528
|
}
|
|
2447
2529
|
};
|
|
2448
2530
|
const onImageLoad = (e) => {
|
|
@@ -2491,6 +2573,7 @@ function MediaGallery({
|
|
|
2491
2573
|
await apiUpload("/api/media", formData);
|
|
2492
2574
|
loadMedia();
|
|
2493
2575
|
setShowCrop(false);
|
|
2576
|
+
toast.success("Cropped image saved");
|
|
2494
2577
|
}
|
|
2495
2578
|
}
|
|
2496
2579
|
} catch (err) {
|
|
@@ -2500,7 +2583,7 @@ function MediaGallery({
|
|
|
2500
2583
|
setUploading(false);
|
|
2501
2584
|
}
|
|
2502
2585
|
};
|
|
2503
|
-
const stats =
|
|
2586
|
+
const stats = React.useMemo(() => {
|
|
2504
2587
|
return items.reduce(
|
|
2505
2588
|
(acc, item) => {
|
|
2506
2589
|
acc.totalSize += item.fileSize || 0;
|
|
@@ -2526,7 +2609,7 @@ function MediaGallery({
|
|
|
2526
2609
|
}
|
|
2527
2610
|
},
|
|
2528
2611
|
children: [
|
|
2529
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-col lg:flex-row lg:items-center justify-between gap-6 border-b border-[var(--kyro-border)] backdrop-blur-md sticky top-0
|
|
2612
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-col lg:flex-row lg:items-center justify-between gap-6 border-b border-[var(--kyro-border)] backdrop-blur-md sticky top-0 ${pickerMode ? "p-2" : "p-6 rounded-xl surface-tile"}`, children: [
|
|
2530
2613
|
!pickerMode && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2531
2614
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl font-bold tracking-tighter text-[var(--kyro-text-primary)]", children: "Media Library" }),
|
|
2532
2615
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3 mt-1", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] font-bold tracking-widest text-[var(--kyro-text-secondary)] opacity-50", children: [
|
|
@@ -2537,7 +2620,7 @@ function MediaGallery({
|
|
|
2537
2620
|
] }) }),
|
|
2538
2621
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-3 flex-wrap lg:flex-nowrap ${pickerMode ? "w-full" : ""}`, children: [
|
|
2539
2622
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative group flex-1 min-w-[200px]", children: [
|
|
2540
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "w-4 h-4" }),
|
|
2623
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-[var(--kyro-text-muted)]" }),
|
|
2541
2624
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2542
2625
|
"input",
|
|
2543
2626
|
{
|
|
@@ -2550,21 +2633,31 @@ function MediaGallery({
|
|
|
2550
2633
|
)
|
|
2551
2634
|
] }),
|
|
2552
2635
|
!pickerMode && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2553
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex
|
|
2554
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2636
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2637
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex bg-[var(--kyro-surface-accent)] p-1 rounded-xl border border-[var(--kyro-border)]", children: [
|
|
2638
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2639
|
+
"button",
|
|
2640
|
+
{
|
|
2641
|
+
onClick: () => setView("grid"),
|
|
2642
|
+
className: `p-2 rounded-lg transition-all ${view === "grid" ? "bg-[var(--kyro-surface)] shadow-sm text-[var(--kyro-text-primary)]" : "text-[var(--kyro-text-secondary)] opacity-50 hover:opacity-100"}`,
|
|
2643
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Grid3X3, { className: "w-4 h-4" })
|
|
2644
|
+
}
|
|
2645
|
+
),
|
|
2646
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2647
|
+
"button",
|
|
2648
|
+
{
|
|
2649
|
+
onClick: () => setView("list"),
|
|
2650
|
+
className: `p-2 rounded-lg transition-all ${view === "list" ? "bg-[var(--kyro-surface)] shadow-sm text-[var(--kyro-text-primary)]" : "text-[var(--kyro-text-secondary)] opacity-50 hover:opacity-100"}`,
|
|
2651
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.File, { className: "w-4 h-4" })
|
|
2652
|
+
}
|
|
2653
|
+
)
|
|
2654
|
+
] }),
|
|
2562
2655
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2563
2656
|
"button",
|
|
2564
2657
|
{
|
|
2565
|
-
onClick: () =>
|
|
2566
|
-
className:
|
|
2567
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.
|
|
2658
|
+
onClick: () => setShowMobileFilters(true),
|
|
2659
|
+
className: "md:hidden p-2 rounded-xl bg-[var(--kyro-surface-accent)] border border-[var(--kyro-border)] text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-text-primary)] transition-colors",
|
|
2660
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className: "w-4 h-4" })
|
|
2568
2661
|
}
|
|
2569
2662
|
)
|
|
2570
2663
|
] }),
|
|
@@ -2663,7 +2756,7 @@ function MediaGallery({
|
|
|
2663
2756
|
] })
|
|
2664
2757
|
] }) }),
|
|
2665
2758
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col min-h-0 bg-[var(--kyro-bg)]", children: [
|
|
2666
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex-1 overflow-y-auto custom-scrollbar ${pickerMode ? "px-2 py-4" : "py-8 px-4"}`, children: loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-4
|
|
2759
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex-1 overflow-y-auto custom-scrollbar ${pickerMode ? "px-2 py-4" : "py-4 px-2 md:py-8 md:px-4"}`, children: loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-4 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5", children: /* @__PURE__ */ jsxRuntime.jsx(Shimmer, { variant: "media-card", count: 12 }) }) : items.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-32 text-center", children: [
|
|
2667
2760
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-24 h-24 rounded-[2rem] bg-[var(--kyro-surface-accent)] flex items-center justify-center mb-8 rotate-12 group-hover:rotate-0 transition-transform duration-500", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Grid3X3, { className: "w-10 h-10 text-[var(--kyro-text-muted)] opacity-30" }) }),
|
|
2668
2761
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xl font-bold text-[var(--kyro-text-primary)] tracking-tight", children: "No assets found" }),
|
|
2669
2762
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[var(--kyro-text-secondary)] mt-2 max-w-xs mx-auto text-sm font-medium leading-relaxed", children: "Upload your first file or create a folder to organize your media assets." }),
|
|
@@ -2863,6 +2956,105 @@ function MediaGallery({
|
|
|
2863
2956
|
)
|
|
2864
2957
|
] })
|
|
2865
2958
|
] }),
|
|
2959
|
+
showMobileFilters && !pickerMode && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-[70] md:hidden", children: [
|
|
2960
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2961
|
+
"div",
|
|
2962
|
+
{
|
|
2963
|
+
className: "fixed inset-0 bg-black/50 backdrop-blur-sm",
|
|
2964
|
+
onClick: () => setShowMobileFilters(false)
|
|
2965
|
+
}
|
|
2966
|
+
),
|
|
2967
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed bottom-0 left-0 right-0 bg-[var(--kyro-surface)] rounded-t-3xl shadow-2xl max-h-[70vh] overflow-y-auto animate-in slide-in-from-bottom-12 duration-300", children: [
|
|
2968
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sticky top-0 bg-[var(--kyro-surface)] z-10 flex items-center justify-between p-6 pb-4 border-b border-[var(--kyro-border)]", children: [
|
|
2969
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-bold tracking-tight text-[var(--kyro-text-primary)]", children: "Filters" }),
|
|
2970
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2971
|
+
"button",
|
|
2972
|
+
{
|
|
2973
|
+
onClick: () => setShowMobileFilters(false),
|
|
2974
|
+
className: "p-2 rounded-xl hover:bg-[var(--kyro-surface-accent)] transition-colors text-[var(--kyro-text-muted)]",
|
|
2975
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" })
|
|
2976
|
+
}
|
|
2977
|
+
)
|
|
2978
|
+
] }),
|
|
2979
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6 space-y-8", children: [
|
|
2980
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2981
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold tracking-[0.2em] text-[var(--kyro-text-secondary)] opacity-40 block mb-4", children: "Quick Filters" }),
|
|
2982
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: ["all", "image", "video", "audio", "document", "archive"].map((t) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2983
|
+
"button",
|
|
2984
|
+
{
|
|
2985
|
+
onClick: () => {
|
|
2986
|
+
setFilter(t);
|
|
2987
|
+
setShowMobileFilters(false);
|
|
2988
|
+
},
|
|
2989
|
+
className: `px-4 py-2 rounded-xl text-[11px] font-bold capitalize transition-all border ${filter === t ? "bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)] border-transparent" : "bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-secondary)] border-[var(--kyro-border)] hover:border-[var(--kyro-text-muted)]"}`,
|
|
2990
|
+
children: t
|
|
2991
|
+
},
|
|
2992
|
+
t
|
|
2993
|
+
)) })
|
|
2994
|
+
] }),
|
|
2995
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2996
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-4", children: [
|
|
2997
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold tracking-[0.2em] text-[var(--kyro-text-secondary)] opacity-40", children: "Folders" }),
|
|
2998
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2999
|
+
"button",
|
|
3000
|
+
{
|
|
3001
|
+
onClick: () => {
|
|
3002
|
+
setShowNewFolderModal(true);
|
|
3003
|
+
setShowMobileFilters(false);
|
|
3004
|
+
},
|
|
3005
|
+
className: "p-1.5 hover:bg-[var(--kyro-surface-accent)] rounded-lg transition-colors text-[var(--kyro-text-primary)]",
|
|
3006
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderPlus, { className: "w-4 h-4" })
|
|
3007
|
+
}
|
|
3008
|
+
)
|
|
3009
|
+
] }),
|
|
3010
|
+
/* @__PURE__ */ jsxRuntime.jsxs("nav", { className: "space-y-1", children: [
|
|
3011
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3012
|
+
"button",
|
|
3013
|
+
{
|
|
3014
|
+
onClick: () => {
|
|
3015
|
+
setCurrentFolder("");
|
|
3016
|
+
setShowMobileFilters(false);
|
|
3017
|
+
},
|
|
3018
|
+
className: `w-full flex items-center gap-3 px-4 py-2.5 rounded-xl text-xs font-bold transition-all ${currentFolder === "" ? "bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)] shadow-md" : "text-[var(--kyro-text-secondary)] hover:bg-[var(--kyro-surface-accent)] hover:text-[var(--kyro-text-primary)]"}`,
|
|
3019
|
+
children: [
|
|
3020
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderInput, { className: "w-4 h-4 opacity-70" }),
|
|
3021
|
+
"All Assets"
|
|
3022
|
+
]
|
|
3023
|
+
}
|
|
3024
|
+
),
|
|
3025
|
+
folders.map((folder) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group relative", children: [
|
|
3026
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3027
|
+
"button",
|
|
3028
|
+
{
|
|
3029
|
+
onClick: () => {
|
|
3030
|
+
setCurrentFolder(folder);
|
|
3031
|
+
setShowMobileFilters(false);
|
|
3032
|
+
},
|
|
3033
|
+
className: `w-full flex items-center gap-3 px-4 py-2.5 rounded-xl text-xs font-bold transition-all ${currentFolder === folder ? "bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)] shadow-md" : "text-[var(--kyro-text-secondary)] hover:bg-[var(--kyro-surface-accent)] hover:text-[var(--kyro-text-primary)]"}`,
|
|
3034
|
+
children: [
|
|
3035
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-4 h-4 flex items-center justify-center opacity-70", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Folder, { fill: currentFolder === folder ? "currentColor" : "none" }) }),
|
|
3036
|
+
folder
|
|
3037
|
+
]
|
|
3038
|
+
}
|
|
3039
|
+
),
|
|
3040
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3041
|
+
"button",
|
|
3042
|
+
{
|
|
3043
|
+
onClick: (e) => {
|
|
3044
|
+
e.stopPropagation();
|
|
3045
|
+
handleDeleteFolder(folder);
|
|
3046
|
+
setShowMobileFilters(false);
|
|
3047
|
+
},
|
|
3048
|
+
className: "absolute right-2 top-1/2 -translate-y-1/2 p-1.5 text-red-500 opacity-0 group-hover:opacity-100 transition-all hover:bg-red-50 rounded-lg",
|
|
3049
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "w-3.5 h-3.5" })
|
|
3050
|
+
}
|
|
3051
|
+
)
|
|
3052
|
+
] }, folder))
|
|
3053
|
+
] })
|
|
3054
|
+
] })
|
|
3055
|
+
] })
|
|
3056
|
+
] })
|
|
3057
|
+
] }),
|
|
2866
3058
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2867
3059
|
SlidePanel,
|
|
2868
3060
|
{
|
|
@@ -3160,6 +3352,8 @@ function MediaGallery({
|
|
|
3160
3352
|
setShowStorageConfigModal(false);
|
|
3161
3353
|
setStorageConfigured(true);
|
|
3162
3354
|
window.location.reload();
|
|
3355
|
+
}).catch(() => {
|
|
3356
|
+
toast.error("Failed to configure storage");
|
|
3163
3357
|
});
|
|
3164
3358
|
},
|
|
3165
3359
|
className: "flex-1 px-4 py-3 border border-[var(--kyro-border)] text-[var(--kyro-text-secondary)] rounded-xl font-bold hover:bg-[var(--kyro-surface-accent)] transition-colors",
|
|
@@ -3205,9 +3399,9 @@ var MenuBar = ({
|
|
|
3205
3399
|
setIsExpanded,
|
|
3206
3400
|
onOpenMediaPicker
|
|
3207
3401
|
}) => {
|
|
3208
|
-
const [activeDropdown, setActiveDropdown] =
|
|
3209
|
-
const menuBarRef =
|
|
3210
|
-
|
|
3402
|
+
const [activeDropdown, setActiveDropdown] = React.useState(null);
|
|
3403
|
+
const menuBarRef = React.useRef(null);
|
|
3404
|
+
React.useEffect(() => {
|
|
3211
3405
|
function handleClickOutside(event) {
|
|
3212
3406
|
if (menuBarRef.current && !menuBarRef.current.contains(event.target)) {
|
|
3213
3407
|
setActiveDropdown(null);
|
|
@@ -3667,14 +3861,14 @@ function RichTextField({
|
|
|
3667
3861
|
error,
|
|
3668
3862
|
disabled
|
|
3669
3863
|
}) {
|
|
3670
|
-
const [isExpanded, setIsExpanded] =
|
|
3671
|
-
const [panelWidth, setPanelWidth] =
|
|
3672
|
-
const [isMediaPickerOpen, setIsMediaPickerOpen] =
|
|
3673
|
-
const [isMounted, setIsMounted] =
|
|
3674
|
-
|
|
3864
|
+
const [isExpanded, setIsExpanded] = React.useState(false);
|
|
3865
|
+
const [panelWidth, setPanelWidth] = React.useState(0);
|
|
3866
|
+
const [isMediaPickerOpen, setIsMediaPickerOpen] = React.useState(false);
|
|
3867
|
+
const [isMounted, setIsMounted] = React.useState(false);
|
|
3868
|
+
React.useEffect(() => {
|
|
3675
3869
|
setIsMounted(true);
|
|
3676
3870
|
}, []);
|
|
3677
|
-
|
|
3871
|
+
React.useEffect(() => {
|
|
3678
3872
|
if (!isExpanded) {
|
|
3679
3873
|
setPanelWidth(0);
|
|
3680
3874
|
return;
|
|
@@ -3740,7 +3934,7 @@ function RichTextField({
|
|
|
3740
3934
|
}
|
|
3741
3935
|
}
|
|
3742
3936
|
});
|
|
3743
|
-
|
|
3937
|
+
React.useEffect(() => {
|
|
3744
3938
|
if (editor && value && JSON.stringify(value) !== JSON.stringify(editor.getJSON())) {
|
|
3745
3939
|
editor.commands.setContent(value);
|
|
3746
3940
|
}
|
|
@@ -4009,9 +4203,9 @@ function mergeThemes(base, overrides) {
|
|
|
4009
4203
|
fields: base.fields ? { ...base.fields, ...overrides.fields } : overrides.fields
|
|
4010
4204
|
};
|
|
4011
4205
|
}
|
|
4012
|
-
var ThemeContext =
|
|
4206
|
+
var ThemeContext = React.createContext(null);
|
|
4013
4207
|
function useTheme() {
|
|
4014
|
-
const context =
|
|
4208
|
+
const context = React.useContext(ThemeContext);
|
|
4015
4209
|
if (!context) {
|
|
4016
4210
|
return {
|
|
4017
4211
|
mode: "light",
|
|
@@ -4122,16 +4316,16 @@ function ThemeProvider({
|
|
|
4122
4316
|
light: lightOverrides,
|
|
4123
4317
|
dark: darkOverrides
|
|
4124
4318
|
}) {
|
|
4125
|
-
const [mode, setMode] =
|
|
4126
|
-
const [baseLight, setBaseLight] =
|
|
4319
|
+
const [mode, setMode] = React.useState(defaultMode);
|
|
4320
|
+
const [baseLight, setBaseLight] = React.useState(
|
|
4127
4321
|
lightOverrides || {}
|
|
4128
4322
|
);
|
|
4129
|
-
const [baseDark, setBaseDark] =
|
|
4323
|
+
const [baseDark, setBaseDark] = React.useState(
|
|
4130
4324
|
darkOverrides || {}
|
|
4131
4325
|
);
|
|
4132
4326
|
const lightTheme = mergeThemes(LIGHT_THEME, baseLight);
|
|
4133
4327
|
const darkTheme = mergeThemes(DARK_THEME, baseDark);
|
|
4134
|
-
const getResolvedTheme =
|
|
4328
|
+
const getResolvedTheme = React.useCallback(() => {
|
|
4135
4329
|
if (mode === "system") {
|
|
4136
4330
|
if (typeof window !== "undefined") {
|
|
4137
4331
|
return window.matchMedia("(prefers-color-scheme: dark)").matches ? darkTheme : lightTheme;
|
|
@@ -4140,13 +4334,13 @@ function ThemeProvider({
|
|
|
4140
4334
|
}
|
|
4141
4335
|
return mode === "dark" ? darkTheme : lightTheme;
|
|
4142
4336
|
}, [mode, lightTheme, darkTheme]);
|
|
4143
|
-
const [theme, setTheme] =
|
|
4144
|
-
|
|
4337
|
+
const [theme, setTheme] = React.useState(getResolvedTheme());
|
|
4338
|
+
React.useEffect(() => {
|
|
4145
4339
|
const resolved = getResolvedTheme();
|
|
4146
4340
|
setTheme(resolved);
|
|
4147
4341
|
applyThemeToDOM(resolved);
|
|
4148
4342
|
}, [getResolvedTheme]);
|
|
4149
|
-
|
|
4343
|
+
React.useEffect(() => {
|
|
4150
4344
|
if (mode !== "system") return;
|
|
4151
4345
|
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
4152
4346
|
const handler = () => {
|
|
@@ -4157,11 +4351,11 @@ function ThemeProvider({
|
|
|
4157
4351
|
mediaQuery.addEventListener("change", handler);
|
|
4158
4352
|
return () => mediaQuery.removeEventListener("change", handler);
|
|
4159
4353
|
}, [mode, getResolvedTheme]);
|
|
4160
|
-
const updateTheme =
|
|
4354
|
+
const updateTheme = React.useCallback((overrides) => {
|
|
4161
4355
|
setBaseLight((prev) => ({ ...prev, ...overrides }));
|
|
4162
4356
|
setBaseDark((prev) => ({ ...prev, ...overrides }));
|
|
4163
4357
|
}, []);
|
|
4164
|
-
const getCssVar =
|
|
4358
|
+
const getCssVar = React.useCallback((key) => `var(--kyro-${key})`, []);
|
|
4165
4359
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4166
4360
|
ThemeContext.Provider,
|
|
4167
4361
|
{
|
|
@@ -4180,7 +4374,7 @@ function ThemeProvider({
|
|
|
4180
4374
|
}
|
|
4181
4375
|
var LightThemeProvider = (props) => /* @__PURE__ */ jsxRuntime.jsx(ThemeProvider, { defaultMode: "light", ...props });
|
|
4182
4376
|
var DarkThemeProvider = (props) => /* @__PURE__ */ jsxRuntime.jsx(ThemeProvider, { defaultMode: "dark", ...props });
|
|
4183
|
-
var CodeMirrorEditor =
|
|
4377
|
+
var CodeMirrorEditor = React.lazy(
|
|
4184
4378
|
() => import('@uiw/react-codemirror').then((mod) => ({ default: mod.default }))
|
|
4185
4379
|
);
|
|
4186
4380
|
var LANGUAGES = [
|
|
@@ -4232,16 +4426,16 @@ var CodeField = ({
|
|
|
4232
4426
|
error,
|
|
4233
4427
|
disabled
|
|
4234
4428
|
}) => {
|
|
4235
|
-
const [isMounted, setIsMounted] =
|
|
4236
|
-
const [isDark, setIsDark] =
|
|
4237
|
-
const [extensions, setExtensions] =
|
|
4238
|
-
const [loading, setLoading] =
|
|
4239
|
-
const [copied, setCopied] =
|
|
4240
|
-
const [isFullScreen, setIsFullScreen] =
|
|
4429
|
+
const [isMounted, setIsMounted] = React.useState(false);
|
|
4430
|
+
const [isDark, setIsDark] = React.useState(false);
|
|
4431
|
+
const [extensions, setExtensions] = React.useState([]);
|
|
4432
|
+
const [loading, setLoading] = React.useState(false);
|
|
4433
|
+
const [copied, setCopied] = React.useState(false);
|
|
4434
|
+
const [isFullScreen, setIsFullScreen] = React.useState(false);
|
|
4241
4435
|
const { theme } = useTheme();
|
|
4242
4436
|
const accent = theme.colors?.accent || theme.colors?.primary || "#6366f1";
|
|
4243
4437
|
const language = field3.language?.toLowerCase() || "javascript";
|
|
4244
|
-
|
|
4438
|
+
React.useEffect(() => {
|
|
4245
4439
|
setIsMounted(true);
|
|
4246
4440
|
setIsDark(document.documentElement.classList.contains("dark"));
|
|
4247
4441
|
const observer = new MutationObserver(() => {
|
|
@@ -4253,7 +4447,7 @@ var CodeField = ({
|
|
|
4253
4447
|
});
|
|
4254
4448
|
return () => observer.disconnect();
|
|
4255
4449
|
}, []);
|
|
4256
|
-
|
|
4450
|
+
React.useEffect(() => {
|
|
4257
4451
|
if (!isMounted) return;
|
|
4258
4452
|
const loadExtensions = async () => {
|
|
4259
4453
|
setLoading(true);
|
|
@@ -4270,16 +4464,16 @@ var CodeField = ({
|
|
|
4270
4464
|
};
|
|
4271
4465
|
loadExtensions();
|
|
4272
4466
|
}, [language, isMounted]);
|
|
4273
|
-
const handleChange =
|
|
4467
|
+
const handleChange = React.useCallback(
|
|
4274
4468
|
(val) => onChange?.(val),
|
|
4275
4469
|
[onChange]
|
|
4276
4470
|
);
|
|
4277
|
-
const handleCopy =
|
|
4471
|
+
const handleCopy = React.useCallback(() => {
|
|
4278
4472
|
navigator.clipboard.writeText(value);
|
|
4279
4473
|
setCopied(true);
|
|
4280
4474
|
setTimeout(() => setCopied(false), 1500);
|
|
4281
4475
|
}, [value]);
|
|
4282
|
-
const toggleFullScreen =
|
|
4476
|
+
const toggleFullScreen = React.useCallback(() => {
|
|
4283
4477
|
setIsFullScreen((prev) => !prev);
|
|
4284
4478
|
document.body.style.overflow = !isFullScreen ? "hidden" : "";
|
|
4285
4479
|
}, [isFullScreen]);
|
|
@@ -4369,7 +4563,7 @@ var CodeField = ({
|
|
|
4369
4563
|
}
|
|
4370
4564
|
),
|
|
4371
4565
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4372
|
-
|
|
4566
|
+
React.Suspense,
|
|
4373
4567
|
{
|
|
4374
4568
|
fallback: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4375
4569
|
"div",
|
|
@@ -4489,18 +4683,18 @@ var MarkdownField = ({
|
|
|
4489
4683
|
error,
|
|
4490
4684
|
disabled
|
|
4491
4685
|
}) => {
|
|
4492
|
-
const [showPreview, setShowPreview] =
|
|
4493
|
-
const [isMounted, setIsMounted] =
|
|
4494
|
-
|
|
4686
|
+
const [showPreview, setShowPreview] = React.useState(false);
|
|
4687
|
+
const [isMounted, setIsMounted] = React.useState(false);
|
|
4688
|
+
React.useEffect(() => {
|
|
4495
4689
|
setIsMounted(true);
|
|
4496
4690
|
}, []);
|
|
4497
|
-
const handleChange =
|
|
4691
|
+
const handleChange = React.useCallback(
|
|
4498
4692
|
(e) => {
|
|
4499
4693
|
onChange?.(e.target.value);
|
|
4500
4694
|
},
|
|
4501
4695
|
[onChange]
|
|
4502
4696
|
);
|
|
4503
|
-
const wordCount =
|
|
4697
|
+
const wordCount = React.useMemo(() => {
|
|
4504
4698
|
if (!value) return 0;
|
|
4505
4699
|
return value.trim().split(/\s+/).filter(Boolean).length;
|
|
4506
4700
|
}, [value]);
|
|
@@ -4605,8 +4799,8 @@ function SecretField({
|
|
|
4605
4799
|
error,
|
|
4606
4800
|
disabled
|
|
4607
4801
|
}) {
|
|
4608
|
-
const [copied, setCopied] =
|
|
4609
|
-
const [regenerating, setRegenerating] =
|
|
4802
|
+
const [copied, setCopied] = React.useState(false);
|
|
4803
|
+
const [regenerating, setRegenerating] = React.useState(false);
|
|
4610
4804
|
const fullValue = value ?? "";
|
|
4611
4805
|
const displayValue = fullValue.length > 8 ? fullValue.slice(0, -8) + "*".repeat(8) : fullValue;
|
|
4612
4806
|
const handleCopy = async () => {
|
|
@@ -5354,22 +5548,22 @@ function RelationshipField({
|
|
|
5354
5548
|
error,
|
|
5355
5549
|
disabled
|
|
5356
5550
|
}) {
|
|
5357
|
-
const [isOpen, setIsOpen] =
|
|
5358
|
-
const [search, setSearch] =
|
|
5359
|
-
const [options, setOptions] =
|
|
5360
|
-
const [loading, setLoading] =
|
|
5361
|
-
const [selectedDocs, setSelectedDocs] =
|
|
5362
|
-
const fetchedIdsRef =
|
|
5363
|
-
const containerRef =
|
|
5364
|
-
const onChangeRef =
|
|
5551
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
5552
|
+
const [search, setSearch] = React.useState("");
|
|
5553
|
+
const [options, setOptions] = React.useState([]);
|
|
5554
|
+
const [loading, setLoading] = React.useState(false);
|
|
5555
|
+
const [selectedDocs, setSelectedDocs] = React.useState([]);
|
|
5556
|
+
const fetchedIdsRef = React.useRef(/* @__PURE__ */ new Set());
|
|
5557
|
+
const containerRef = React.useRef(null);
|
|
5558
|
+
const onChangeRef = React.useRef(() => {
|
|
5365
5559
|
});
|
|
5366
5560
|
onChangeRef.current = onChange || (() => {
|
|
5367
5561
|
});
|
|
5368
5562
|
const isMultiple = field3.hasMany;
|
|
5369
5563
|
const relationTo = Array.isArray(field3.relationTo) ? field3.relationTo : [field3.relationTo];
|
|
5370
5564
|
const isPolymorphic = relationTo.length > 1;
|
|
5371
|
-
const [activeRelation, setActiveRelation] =
|
|
5372
|
-
const extractIds =
|
|
5565
|
+
const [activeRelation, setActiveRelation] = React.useState(relationTo[0]);
|
|
5566
|
+
const extractIds = React.useCallback(() => {
|
|
5373
5567
|
if (!value) return [];
|
|
5374
5568
|
const items = isMultiple ? Array.isArray(value) ? value : [] : value ? [value] : [];
|
|
5375
5569
|
return items.map((item) => {
|
|
@@ -5379,7 +5573,7 @@ function RelationshipField({
|
|
|
5379
5573
|
return String(item);
|
|
5380
5574
|
}).filter(Boolean);
|
|
5381
5575
|
}, [value, isMultiple]);
|
|
5382
|
-
const fetchSelectedDocs =
|
|
5576
|
+
const fetchSelectedDocs = React.useCallback((ids) => {
|
|
5383
5577
|
if (ids.length === 0) return;
|
|
5384
5578
|
ids.forEach((id) => {
|
|
5385
5579
|
if (fetchedIdsRef.current.has(id)) return;
|
|
@@ -5406,11 +5600,11 @@ function RelationshipField({
|
|
|
5406
5600
|
});
|
|
5407
5601
|
});
|
|
5408
5602
|
}, [isPolymorphic, value, activeRelation, isMultiple]);
|
|
5409
|
-
|
|
5603
|
+
React.useEffect(() => {
|
|
5410
5604
|
const ids = extractIds();
|
|
5411
5605
|
fetchSelectedDocs(ids);
|
|
5412
5606
|
}, [extractIds, fetchSelectedDocs]);
|
|
5413
|
-
const fetchOptions =
|
|
5607
|
+
const fetchOptions = React.useCallback((query = "") => {
|
|
5414
5608
|
setLoading(true);
|
|
5415
5609
|
const searchFields = ["title", "name", "label", "email"];
|
|
5416
5610
|
const url = `/api/${activeRelation}?${buildSearchQuery(query, searchFields)}`;
|
|
@@ -5427,13 +5621,13 @@ function RelationshipField({
|
|
|
5427
5621
|
setLoading(false);
|
|
5428
5622
|
});
|
|
5429
5623
|
}, [activeRelation]);
|
|
5430
|
-
|
|
5624
|
+
React.useEffect(() => {
|
|
5431
5625
|
if (isOpen) {
|
|
5432
5626
|
setOptions([]);
|
|
5433
5627
|
fetchOptions(search);
|
|
5434
5628
|
}
|
|
5435
5629
|
}, [isOpen, activeRelation]);
|
|
5436
|
-
|
|
5630
|
+
React.useEffect(() => {
|
|
5437
5631
|
const handleClickOutside = (event) => {
|
|
5438
5632
|
if (containerRef.current && !containerRef.current.contains(event.target)) {
|
|
5439
5633
|
setIsOpen(false);
|
|
@@ -5581,7 +5775,7 @@ function RelationshipField({
|
|
|
5581
5775
|
] });
|
|
5582
5776
|
}
|
|
5583
5777
|
var RelationshipField_default = RelationshipField;
|
|
5584
|
-
var BlocksContext =
|
|
5778
|
+
var BlocksContext = React.createContext(null);
|
|
5585
5779
|
function createBlocksStore(allowedBlocks = [], dynamicCategories = []) {
|
|
5586
5780
|
return vanilla.createStore((set, get) => ({
|
|
5587
5781
|
blocks: [],
|
|
@@ -5736,7 +5930,7 @@ function getDefaultData(type) {
|
|
|
5736
5930
|
return defaults[type] || {};
|
|
5737
5931
|
}
|
|
5738
5932
|
function useBlockById(id) {
|
|
5739
|
-
const store =
|
|
5933
|
+
const store = React.useContext(BlocksContext);
|
|
5740
5934
|
if (!store) return void 0;
|
|
5741
5935
|
return zustand.useStore(store, (state) => {
|
|
5742
5936
|
const findRecursive = (blocksList) => {
|
|
@@ -5761,7 +5955,7 @@ function useBlockById(id) {
|
|
|
5761
5955
|
});
|
|
5762
5956
|
}
|
|
5763
5957
|
function useBlockActions() {
|
|
5764
|
-
const store =
|
|
5958
|
+
const store = React.useContext(BlocksContext);
|
|
5765
5959
|
if (!store) {
|
|
5766
5960
|
throw new Error("useBlockActions must be used within a BlocksContext.Provider");
|
|
5767
5961
|
}
|
|
@@ -6121,7 +6315,7 @@ var VideoBlock = ({
|
|
|
6121
6315
|
{
|
|
6122
6316
|
type: "button",
|
|
6123
6317
|
onClick: () => removeBlock(block3.id),
|
|
6124
|
-
className: "p-1 hover:bg-
|
|
6318
|
+
className: "p-1 hover:bg-[var(--kyro-danger-bg)] rounded text-[var(--kyro-danger)]",
|
|
6125
6319
|
title: "Remove",
|
|
6126
6320
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3 h-3" })
|
|
6127
6321
|
}
|
|
@@ -6145,7 +6339,7 @@ var ListField = ({
|
|
|
6145
6339
|
onChange,
|
|
6146
6340
|
compact = false
|
|
6147
6341
|
}) => {
|
|
6148
|
-
const [inputValue, setInputValue] =
|
|
6342
|
+
const [inputValue, setInputValue] = React__default.default.useState("");
|
|
6149
6343
|
const handleAdd = () => {
|
|
6150
6344
|
if (inputValue.trim()) {
|
|
6151
6345
|
onChange([...items, inputValue.trim()]);
|
|
@@ -6231,7 +6425,7 @@ var ListBlock = ({
|
|
|
6231
6425
|
{
|
|
6232
6426
|
type: "button",
|
|
6233
6427
|
onClick: () => removeBlock(block3.id),
|
|
6234
|
-
className: "p-1 hover:bg-
|
|
6428
|
+
className: "p-1 hover:bg-[var(--kyro-danger-bg)] rounded text-[var(--kyro-danger)]",
|
|
6235
6429
|
title: "Remove",
|
|
6236
6430
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3 h-3" })
|
|
6237
6431
|
}
|
|
@@ -6280,7 +6474,7 @@ var CodeBlock = ({
|
|
|
6280
6474
|
{
|
|
6281
6475
|
type: "button",
|
|
6282
6476
|
onClick: () => removeBlock(block3.id),
|
|
6283
|
-
className: "p-1.5 hover:bg-
|
|
6477
|
+
className: "p-1.5 hover:bg-[var(--kyro-danger-bg)] rounded-lg transition-all text-[var(--kyro-text-muted)] hover:text-[var(--kyro-danger)]",
|
|
6284
6478
|
title: "Remove",
|
|
6285
6479
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" })
|
|
6286
6480
|
}
|
|
@@ -6379,7 +6573,7 @@ var FileBlock = ({
|
|
|
6379
6573
|
{
|
|
6380
6574
|
type: "button",
|
|
6381
6575
|
onClick: () => removeBlock(block3.id),
|
|
6382
|
-
className: "p-1 hover:bg-
|
|
6576
|
+
className: "p-1 hover:bg-[var(--kyro-danger-bg)] rounded text-[var(--kyro-danger)]",
|
|
6383
6577
|
title: "Remove",
|
|
6384
6578
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3 h-3" })
|
|
6385
6579
|
}
|
|
@@ -6401,7 +6595,7 @@ var AccordionField = ({
|
|
|
6401
6595
|
onChange,
|
|
6402
6596
|
compact = false
|
|
6403
6597
|
}) => {
|
|
6404
|
-
const [openIndex, setOpenIndex] =
|
|
6598
|
+
const [openIndex, setOpenIndex] = React__default.default.useState(0);
|
|
6405
6599
|
const handleTitleChange = (index, value) => {
|
|
6406
6600
|
const newItems = [...items];
|
|
6407
6601
|
newItems[index] = { ...newItems[index], title: value };
|
|
@@ -6625,7 +6819,7 @@ var AccordionBlock = ({
|
|
|
6625
6819
|
{
|
|
6626
6820
|
type: "button",
|
|
6627
6821
|
onClick: () => removeBlock(block3.id),
|
|
6628
|
-
className: "p-1 hover:bg-
|
|
6822
|
+
className: "p-1 hover:bg-[var(--kyro-danger-bg)] rounded text-[var(--kyro-danger)]",
|
|
6629
6823
|
title: "Remove",
|
|
6630
6824
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3 h-3" })
|
|
6631
6825
|
}
|
|
@@ -6677,7 +6871,7 @@ var RichTextBlock = ({
|
|
|
6677
6871
|
{
|
|
6678
6872
|
type: "button",
|
|
6679
6873
|
onClick: () => removeBlock(block3.id),
|
|
6680
|
-
className: "p-1 hover:bg-
|
|
6874
|
+
className: "p-1 hover:bg-[var(--kyro-danger-bg)] rounded text-[var(--kyro-danger)]",
|
|
6681
6875
|
title: "Remove",
|
|
6682
6876
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3 h-3" })
|
|
6683
6877
|
}
|
|
@@ -6827,7 +7021,7 @@ function ArrayLayout({
|
|
|
6827
7021
|
const firstField = fields2[0];
|
|
6828
7022
|
const labelField = firstField?.name || "user";
|
|
6829
7023
|
const isRelationship = firstField?.type === "relationship";
|
|
6830
|
-
const [openIndex, setOpenIndex] =
|
|
7024
|
+
const [openIndex, setOpenIndex] = React__default.default.useState(0);
|
|
6831
7025
|
function getItemLabel(item) {
|
|
6832
7026
|
for (const key of ["label", "title", "name"]) {
|
|
6833
7027
|
const val = item[key];
|
|
@@ -7367,11 +7561,11 @@ var ChildBlocksTree = ({
|
|
|
7367
7561
|
depth = 0,
|
|
7368
7562
|
maxDepth = MAX_DEPTH
|
|
7369
7563
|
}) => {
|
|
7370
|
-
const [showAddModal, setShowAddModal] =
|
|
7371
|
-
const [expandedIds, setExpandedIds] =
|
|
7372
|
-
const [editingBlockId, setEditingBlockId] =
|
|
7373
|
-
const [confirmDeleteId, setConfirmDeleteId] =
|
|
7374
|
-
const store =
|
|
7564
|
+
const [showAddModal, setShowAddModal] = React.useState(false);
|
|
7565
|
+
const [expandedIds, setExpandedIds] = React.useState(/* @__PURE__ */ new Set());
|
|
7566
|
+
const [editingBlockId, setEditingBlockId] = React.useState(null);
|
|
7567
|
+
const [confirmDeleteId, setConfirmDeleteId] = React.useState(null);
|
|
7568
|
+
const store = React.useContext(BlocksContext);
|
|
7375
7569
|
if (!store) throw new Error("ChildBlocksTree must be used within a BlocksContext");
|
|
7376
7570
|
const dynamicCategories = zustand.useStore(store, (s) => s.dynamicCategories);
|
|
7377
7571
|
const allowedBlocks = zustand.useStore(store, (s) => s.allowedBlocks);
|
|
@@ -7464,7 +7658,7 @@ var ChildBlocksTree = ({
|
|
|
7464
7658
|
handleRemoveChild(child.id);
|
|
7465
7659
|
setConfirmDeleteId(null);
|
|
7466
7660
|
},
|
|
7467
|
-
className: "px-2 py-1 text-xs bg-
|
|
7661
|
+
className: "px-2 py-1 text-xs bg-[var(--kyro-danger)] text-white rounded",
|
|
7468
7662
|
children: "Remove"
|
|
7469
7663
|
}
|
|
7470
7664
|
),
|
|
@@ -7487,8 +7681,8 @@ var ChildBlocksTree = ({
|
|
|
7487
7681
|
e.stopPropagation();
|
|
7488
7682
|
setConfirmDeleteId(child.id);
|
|
7489
7683
|
},
|
|
7490
|
-
className: "p-1.5 rounded-md transition-opacity cursor-pointer hover:bg-
|
|
7491
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3.5 h-3.5 text-
|
|
7684
|
+
className: "p-1.5 rounded-md transition-opacity cursor-pointer hover:bg-[var(--kyro-danger-bg)]",
|
|
7685
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3.5 h-3.5 text-[var(--kyro-danger)] invisible group-hover/column:visible" })
|
|
7492
7686
|
}
|
|
7493
7687
|
)
|
|
7494
7688
|
]
|
|
@@ -7588,11 +7782,11 @@ var NestedChildBlocks = ({
|
|
|
7588
7782
|
depth,
|
|
7589
7783
|
maxDepth
|
|
7590
7784
|
}) => {
|
|
7591
|
-
const [showAddModal, setShowAddModal] =
|
|
7592
|
-
const [expandedIds, setExpandedIds] =
|
|
7593
|
-
const [editingBlockId, setEditingBlockId] =
|
|
7594
|
-
const [confirmDeleteId, setConfirmDeleteId] =
|
|
7595
|
-
const store =
|
|
7785
|
+
const [showAddModal, setShowAddModal] = React.useState(false);
|
|
7786
|
+
const [expandedIds, setExpandedIds] = React.useState(/* @__PURE__ */ new Set());
|
|
7787
|
+
const [editingBlockId, setEditingBlockId] = React.useState(null);
|
|
7788
|
+
const [confirmDeleteId, setConfirmDeleteId] = React.useState(null);
|
|
7789
|
+
const store = React.useContext(BlocksContext);
|
|
7596
7790
|
if (!store) throw new Error("NestedChildBlocks must be used within a BlocksContext");
|
|
7597
7791
|
const dynamicCategories = zustand.useStore(store, (s) => s.dynamicCategories);
|
|
7598
7792
|
const allowedBlocks = zustand.useStore(store, (s) => s.allowedBlocks);
|
|
@@ -7685,7 +7879,7 @@ var NestedChildBlocks = ({
|
|
|
7685
7879
|
handleRemoveChild(child.id);
|
|
7686
7880
|
setConfirmDeleteId(null);
|
|
7687
7881
|
},
|
|
7688
|
-
className: "px-2 py-1 text-xs bg-
|
|
7882
|
+
className: "px-2 py-1 text-xs bg-[var(--kyro-danger)] text-white rounded",
|
|
7689
7883
|
children: "Remove"
|
|
7690
7884
|
}
|
|
7691
7885
|
),
|
|
@@ -7708,8 +7902,8 @@ var NestedChildBlocks = ({
|
|
|
7708
7902
|
e.stopPropagation();
|
|
7709
7903
|
setConfirmDeleteId(child.id);
|
|
7710
7904
|
},
|
|
7711
|
-
className: "p-1.5 rounded-md invisible group-hover:visible transition-opacity cursor-pointer hover:bg-
|
|
7712
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3.5 h-3.5 text-
|
|
7905
|
+
className: "p-1.5 rounded-md invisible group-hover:visible transition-opacity cursor-pointer hover:bg-[var(--kyro-danger-bg)]",
|
|
7906
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3.5 h-3.5 text-[var(--kyro-danger)]" })
|
|
7713
7907
|
}
|
|
7714
7908
|
)
|
|
7715
7909
|
]
|
|
@@ -7842,7 +8036,7 @@ var HeroBlock = ({
|
|
|
7842
8036
|
{
|
|
7843
8037
|
type: "button",
|
|
7844
8038
|
onClick: () => removeBlock(block3.id),
|
|
7845
|
-
className: "p-1 hover:bg-
|
|
8039
|
+
className: "p-1 hover:bg-[var(--kyro-danger-bg)] rounded text-[var(--kyro-danger)]",
|
|
7846
8040
|
title: "Remove",
|
|
7847
8041
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3 h-3" })
|
|
7848
8042
|
}
|
|
@@ -8070,7 +8264,7 @@ var ArrayBlock = ({
|
|
|
8070
8264
|
{
|
|
8071
8265
|
type: "button",
|
|
8072
8266
|
onClick: () => removeBlock(block3.id),
|
|
8073
|
-
className: "p-1 hover:bg-
|
|
8267
|
+
className: "p-1 hover:bg-[var(--kyro-danger-bg)] rounded text-[var(--kyro-danger)]",
|
|
8074
8268
|
title: "Remove",
|
|
8075
8269
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3 h-3" })
|
|
8076
8270
|
}
|
|
@@ -8096,13 +8290,13 @@ var RelationshipBlockField = ({
|
|
|
8096
8290
|
onChange,
|
|
8097
8291
|
compact = false
|
|
8098
8292
|
}) => {
|
|
8099
|
-
const [isOpen, setIsOpen] =
|
|
8100
|
-
const [search, setSearch] =
|
|
8101
|
-
const [options, setOptions] =
|
|
8102
|
-
const [loading, setLoading] =
|
|
8103
|
-
const [collections2, setCollections] =
|
|
8104
|
-
const [loadingCollections, setLoadingCollections] =
|
|
8105
|
-
|
|
8293
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
8294
|
+
const [search, setSearch] = React.useState("");
|
|
8295
|
+
const [options, setOptions] = React.useState([]);
|
|
8296
|
+
const [loading, setLoading] = React.useState(false);
|
|
8297
|
+
const [collections2, setCollections] = React.useState([]);
|
|
8298
|
+
const [loadingCollections, setLoadingCollections] = React.useState(true);
|
|
8299
|
+
React.useEffect(() => {
|
|
8106
8300
|
apiGet("/api/collections").then((data) => {
|
|
8107
8301
|
setCollections(
|
|
8108
8302
|
(data.collections || []).map((c) => c.slug || c.name || c)
|
|
@@ -8118,7 +8312,7 @@ var RelationshipBlockField = ({
|
|
|
8118
8312
|
setLoading(false);
|
|
8119
8313
|
}).catch(() => setLoading(false));
|
|
8120
8314
|
};
|
|
8121
|
-
|
|
8315
|
+
React.useEffect(() => {
|
|
8122
8316
|
if (isOpen) fetchOptions(search);
|
|
8123
8317
|
}, [isOpen, search, relationTo, labelField]);
|
|
8124
8318
|
const getLabel2 = (opt) => {
|
|
@@ -8287,7 +8481,7 @@ var RelationshipBlock = ({
|
|
|
8287
8481
|
{
|
|
8288
8482
|
type: "button",
|
|
8289
8483
|
onClick: () => removeBlock(block3.id),
|
|
8290
|
-
className: "p-1 hover:bg-
|
|
8484
|
+
className: "p-1 hover:bg-[var(--kyro-danger-bg)] rounded text-[var(--kyro-danger)]",
|
|
8291
8485
|
title: "Remove",
|
|
8292
8486
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3 h-3" })
|
|
8293
8487
|
}
|
|
@@ -8448,7 +8642,7 @@ var SortableBlockComponent = ({
|
|
|
8448
8642
|
} = sortable.useSortable({ id: block3.id });
|
|
8449
8643
|
const { removeBlock } = useBlockActions();
|
|
8450
8644
|
const isEditing = editingBlockId === block3.id;
|
|
8451
|
-
const [showDeleteConfirm, setShowDeleteConfirm] =
|
|
8645
|
+
const [showDeleteConfirm, setShowDeleteConfirm] = React.useState(false);
|
|
8452
8646
|
const style = {
|
|
8453
8647
|
transform: utilities.CSS.Transform.toString(transform),
|
|
8454
8648
|
transition,
|
|
@@ -8487,7 +8681,7 @@ var SortableBlockComponent = ({
|
|
|
8487
8681
|
removeBlock(block3.id);
|
|
8488
8682
|
setShowDeleteConfirm(false);
|
|
8489
8683
|
},
|
|
8490
|
-
className: "px-1.5 py-0.5 text-[9px] bg-
|
|
8684
|
+
className: "px-1.5 py-0.5 text-[9px] bg-[var(--kyro-danger)] text-white rounded font-semibold transition-colors hover:brightness-90",
|
|
8491
8685
|
children: "Remove"
|
|
8492
8686
|
}
|
|
8493
8687
|
),
|
|
@@ -8522,7 +8716,7 @@ var SortableBlockComponent = ({
|
|
|
8522
8716
|
e.stopPropagation();
|
|
8523
8717
|
setShowDeleteConfirm(true);
|
|
8524
8718
|
},
|
|
8525
|
-
className: "p-0.5 hover:bg-
|
|
8719
|
+
className: "p-0.5 hover:bg-[var(--kyro-danger-bg)] hover:text-[var(--kyro-danger)] rounded text-[var(--kyro-text-muted)] transition-colors",
|
|
8526
8720
|
title: "Remove",
|
|
8527
8721
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3 h-3" })
|
|
8528
8722
|
}
|
|
@@ -8541,11 +8735,11 @@ var SortableBlockComponent = ({
|
|
|
8541
8735
|
)
|
|
8542
8736
|
] });
|
|
8543
8737
|
}
|
|
8544
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: setNodeRef, style, className: "relative group pl-8 mb-2", children: [
|
|
8738
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: setNodeRef, style, className: "relative group md:pl-8 mb-2", children: [
|
|
8545
8739
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8546
8740
|
"div",
|
|
8547
8741
|
{
|
|
8548
|
-
className: "absolute left-0 top-1/2 -translate-y-1/2 p-1.5 cursor-grab active:cursor-grabbing text-[var(--kyro-text-muted)] opacity-0 group-hover:opacity-100 transition-opacity hover:bg-[var(--kyro-surface-accent)] rounded",
|
|
8742
|
+
className: "hidden md:absolute left-0 top-1/2 -translate-y-1/2 p-1.5 cursor-grab active:cursor-grabbing text-[var(--kyro-text-muted)] opacity-0 group-hover:opacity-100 transition-opacity hover:bg-[var(--kyro-surface-accent)] rounded",
|
|
8549
8743
|
...attributes,
|
|
8550
8744
|
...listeners,
|
|
8551
8745
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GripVertical, { className: "w-4 h-4" })
|
|
@@ -8586,7 +8780,7 @@ var SortableBlockComponent = ({
|
|
|
8586
8780
|
removeBlock(block3.id);
|
|
8587
8781
|
setShowDeleteConfirm(false);
|
|
8588
8782
|
},
|
|
8589
|
-
className: "px-2.5 py-1 text-[10px] bg-
|
|
8783
|
+
className: "px-2.5 py-1 text-[10px] bg-[var(--kyro-danger)] text-white rounded font-semibold transition-colors hover:brightness-90",
|
|
8590
8784
|
children: "Remove"
|
|
8591
8785
|
}
|
|
8592
8786
|
),
|
|
@@ -8623,7 +8817,7 @@ var SortableBlockComponent = ({
|
|
|
8623
8817
|
e.stopPropagation();
|
|
8624
8818
|
setShowDeleteConfirm(true);
|
|
8625
8819
|
},
|
|
8626
|
-
className: "p-1 hover:bg-
|
|
8820
|
+
className: "p-1 hover:bg-[var(--kyro-danger-bg)] hover:text-[var(--kyro-danger)] rounded text-[var(--kyro-text-muted)] transition-colors",
|
|
8627
8821
|
title: "Remove Block",
|
|
8628
8822
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3.5 h-3.5" })
|
|
8629
8823
|
}
|
|
@@ -8642,7 +8836,7 @@ var SortableBlockComponent = ({
|
|
|
8642
8836
|
)
|
|
8643
8837
|
] });
|
|
8644
8838
|
};
|
|
8645
|
-
var SortableBlock =
|
|
8839
|
+
var SortableBlock = React__default.default.memo(SortableBlockComponent);
|
|
8646
8840
|
var BlocksField = ({
|
|
8647
8841
|
field: field3,
|
|
8648
8842
|
value,
|
|
@@ -8653,9 +8847,9 @@ var BlocksField = ({
|
|
|
8653
8847
|
documentStatus,
|
|
8654
8848
|
justSaved
|
|
8655
8849
|
}) => {
|
|
8656
|
-
const [isDrawerOpen, setIsDrawerOpen] =
|
|
8657
|
-
const [isDropdownOpen, setIsDropdownOpen] =
|
|
8658
|
-
const dropdownRef =
|
|
8850
|
+
const [isDrawerOpen, setIsDrawerOpen] = React.useState(false);
|
|
8851
|
+
const [isDropdownOpen, setIsDropdownOpen] = React.useState(false);
|
|
8852
|
+
const dropdownRef = React.useRef(null);
|
|
8659
8853
|
const pickerMode = field3.admin?.pickerMode || "drawer";
|
|
8660
8854
|
const allowedBlocks = field3.blocks || [];
|
|
8661
8855
|
const groupedBlocks = allowedBlocks.reduce((acc, block3) => {
|
|
@@ -8685,18 +8879,18 @@ var BlocksField = ({
|
|
|
8685
8879
|
title,
|
|
8686
8880
|
blocks: blocks3
|
|
8687
8881
|
}));
|
|
8688
|
-
const storeRef =
|
|
8882
|
+
const storeRef = React.useRef(null);
|
|
8689
8883
|
if (!storeRef.current) {
|
|
8690
8884
|
storeRef.current = createBlocksStore(allowedBlocks, dynamicCategories);
|
|
8691
8885
|
}
|
|
8692
8886
|
const store = storeRef.current;
|
|
8693
8887
|
const blocks2 = zustand.useStore(store, (s) => s.blocks);
|
|
8694
|
-
const [activeDrag, setActiveDrag] =
|
|
8695
|
-
const [editingBlockId, setEditingBlockId] =
|
|
8696
|
-
const prevBlocksLengthRef =
|
|
8697
|
-
const prevBlockIdsRef =
|
|
8698
|
-
const isInitializedRef =
|
|
8699
|
-
|
|
8888
|
+
const [activeDrag, setActiveDrag] = React.useState(null);
|
|
8889
|
+
const [editingBlockId, setEditingBlockId] = React.useState(null);
|
|
8890
|
+
const prevBlocksLengthRef = React.useRef(blocks2.length);
|
|
8891
|
+
const prevBlockIdsRef = React.useRef(new Set(blocks2.map((b) => b.id)));
|
|
8892
|
+
const isInitializedRef = React.useRef(false);
|
|
8893
|
+
React.useEffect(() => {
|
|
8700
8894
|
if (isInitializedRef.current) {
|
|
8701
8895
|
if (blocks2.length > prevBlocksLengthRef.current) {
|
|
8702
8896
|
const newBlock = blocks2.find((b) => b.id && !prevBlockIdsRef.current.has(b.id));
|
|
@@ -8708,7 +8902,7 @@ var BlocksField = ({
|
|
|
8708
8902
|
prevBlocksLengthRef.current = blocks2.length;
|
|
8709
8903
|
prevBlockIdsRef.current = new Set(blocks2.map((b) => b.id));
|
|
8710
8904
|
}, [blocks2]);
|
|
8711
|
-
|
|
8905
|
+
React.useEffect(() => {
|
|
8712
8906
|
if (onBlocksChange) {
|
|
8713
8907
|
store.getState().setOnBlocksChange(onBlocksChange);
|
|
8714
8908
|
}
|
|
@@ -8717,8 +8911,8 @@ var BlocksField = ({
|
|
|
8717
8911
|
});
|
|
8718
8912
|
};
|
|
8719
8913
|
}, [onBlocksChange, store]);
|
|
8720
|
-
const lastValueRef =
|
|
8721
|
-
|
|
8914
|
+
const lastValueRef = React.useRef(null);
|
|
8915
|
+
React.useEffect(() => {
|
|
8722
8916
|
const valueArray = Array.isArray(value) ? value : [];
|
|
8723
8917
|
const lastValueArray = lastValueRef.current || [];
|
|
8724
8918
|
if (JSON.stringify(valueArray) !== JSON.stringify(lastValueArray)) {
|
|
@@ -8733,9 +8927,9 @@ var BlocksField = ({
|
|
|
8733
8927
|
lastValueRef.current = [];
|
|
8734
8928
|
}
|
|
8735
8929
|
}, [value, field3.name, store]);
|
|
8736
|
-
const onChangeRef =
|
|
8930
|
+
const onChangeRef = React.useRef(onChange);
|
|
8737
8931
|
onChangeRef.current = onChange;
|
|
8738
|
-
|
|
8932
|
+
React.useEffect(() => {
|
|
8739
8933
|
if (!onChangeRef.current) return;
|
|
8740
8934
|
const lastValue = lastValueRef.current;
|
|
8741
8935
|
if (!lastValue) return;
|
|
@@ -8744,13 +8938,13 @@ var BlocksField = ({
|
|
|
8744
8938
|
onChangeRef.current(blocks2);
|
|
8745
8939
|
}
|
|
8746
8940
|
}, [blocks2]);
|
|
8747
|
-
const handleAddBlock =
|
|
8941
|
+
const handleAddBlock = React.useCallback(
|
|
8748
8942
|
(blockType) => {
|
|
8749
8943
|
store.getState().addBlock(blockType);
|
|
8750
8944
|
},
|
|
8751
8945
|
[store]
|
|
8752
8946
|
);
|
|
8753
|
-
const duplicateBlock =
|
|
8947
|
+
const duplicateBlock = React.useCallback(
|
|
8754
8948
|
(blockId) => {
|
|
8755
8949
|
const blockIndex = blocks2.findIndex((b) => b.id === blockId);
|
|
8756
8950
|
if (blockIndex === -1) return;
|
|
@@ -8813,9 +9007,9 @@ var BlocksField = ({
|
|
|
8813
9007
|
}
|
|
8814
9008
|
}
|
|
8815
9009
|
};
|
|
8816
|
-
const activeBlock = activeDrag ?
|
|
9010
|
+
const activeBlock = activeDrag ? dynamicCategories.flatMap((cat) => cat.blocks).find((b) => `drawer-${b.type}` === activeDrag.id) || blocks2.find((b) => b.id === activeDrag.id) : null;
|
|
8817
9011
|
activeBlock ? "label" in activeBlock ? activeBlock.label : activeBlock.type : "Block";
|
|
8818
|
-
|
|
9012
|
+
React.useEffect(() => {
|
|
8819
9013
|
if (!isDropdownOpen) return;
|
|
8820
9014
|
const handleClick = (e) => {
|
|
8821
9015
|
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
@@ -8976,9 +9170,9 @@ function normalizeUploadFields(value) {
|
|
|
8976
9170
|
return value;
|
|
8977
9171
|
}
|
|
8978
9172
|
function useQueue() {
|
|
8979
|
-
const queue =
|
|
8980
|
-
const isProcessing =
|
|
8981
|
-
const queueTask =
|
|
9173
|
+
const queue = React.useRef([]);
|
|
9174
|
+
const isProcessing = React.useRef(false);
|
|
9175
|
+
const queueTask = React.useCallback((fn, options) => {
|
|
8982
9176
|
queue.current.push(fn);
|
|
8983
9177
|
async function processQueue() {
|
|
8984
9178
|
if (isProcessing.current) return;
|
|
@@ -9041,27 +9235,27 @@ function useAutoFormState({
|
|
|
9041
9235
|
} = store;
|
|
9042
9236
|
const versionsEnabled = !!config.versions;
|
|
9043
9237
|
const currentContextKey = globalSlug || initialData?.id || collectionSlug;
|
|
9044
|
-
const needsResetRef =
|
|
9238
|
+
const needsResetRef = React.useRef(false);
|
|
9045
9239
|
if (!globalSlug && currentContextKey && formData && Object.keys(formData).length > 0 && formData.id !== currentContextKey) {
|
|
9046
9240
|
needsResetRef.current = true;
|
|
9047
9241
|
}
|
|
9048
|
-
|
|
9242
|
+
React.useEffect(() => {
|
|
9049
9243
|
if (needsResetRef.current) {
|
|
9050
9244
|
needsResetRef.current = false;
|
|
9051
9245
|
resetForm();
|
|
9052
9246
|
}
|
|
9053
9247
|
}, [resetForm]);
|
|
9054
|
-
const localSaveTimerRef =
|
|
9055
|
-
const serverSaveTimerRef =
|
|
9056
|
-
const retryTimerRef =
|
|
9057
|
-
const isOnlineRef =
|
|
9058
|
-
const lastAutoSaveTimeRef =
|
|
9059
|
-
const autoSaveSkipRef =
|
|
9060
|
-
const restorePromptedRef =
|
|
9061
|
-
const previousFormDataRef =
|
|
9062
|
-
const astroSyncDataRef =
|
|
9248
|
+
const localSaveTimerRef = React.useRef(null);
|
|
9249
|
+
const serverSaveTimerRef = React.useRef(null);
|
|
9250
|
+
const retryTimerRef = React.useRef(null);
|
|
9251
|
+
const isOnlineRef = React.useRef(typeof navigator !== "undefined" ? navigator.onLine : true);
|
|
9252
|
+
const lastAutoSaveTimeRef = React.useRef(0);
|
|
9253
|
+
const autoSaveSkipRef = React.useRef(false);
|
|
9254
|
+
const restorePromptedRef = React.useRef(null);
|
|
9255
|
+
const previousFormDataRef = React.useRef("");
|
|
9256
|
+
const astroSyncDataRef = React.useRef("");
|
|
9063
9257
|
const { queueTask } = useQueue();
|
|
9064
|
-
const getDocumentKey =
|
|
9258
|
+
const getDocumentKey = React.useCallback(
|
|
9065
9259
|
(id) => {
|
|
9066
9260
|
if (globalSlug) return `global:${globalSlug}`;
|
|
9067
9261
|
if (collectionSlug && id) return `${collectionSlug}:${id}`;
|
|
@@ -9069,7 +9263,7 @@ function useAutoFormState({
|
|
|
9069
9263
|
},
|
|
9070
9264
|
[collectionSlug, globalSlug]
|
|
9071
9265
|
);
|
|
9072
|
-
const persistBrowserDraft =
|
|
9266
|
+
const persistBrowserDraft = React.useCallback(
|
|
9073
9267
|
(documentKey, data, options) => {
|
|
9074
9268
|
setDraftCache(documentKey, {
|
|
9075
9269
|
data,
|
|
@@ -9080,7 +9274,7 @@ function useAutoFormState({
|
|
|
9080
9274
|
},
|
|
9081
9275
|
[lastSavedData.updatedAt, setDraftCache]
|
|
9082
9276
|
);
|
|
9083
|
-
const fetchVersions =
|
|
9277
|
+
const fetchVersions = React.useCallback(async () => {
|
|
9084
9278
|
const url = globalSlug ? resolveApi(`/api/globals/${globalSlug}/versions`) : collectionSlug && formData.id ? resolveApi(`/api/${collectionSlug}/${formData.id}/versions`) : null;
|
|
9085
9279
|
if (!url) return;
|
|
9086
9280
|
setLoadingVersions(true);
|
|
@@ -9094,7 +9288,7 @@ function useAutoFormState({
|
|
|
9094
9288
|
setLoadingVersions(false);
|
|
9095
9289
|
}
|
|
9096
9290
|
}, [formData.id, collectionSlug, globalSlug, setLoadingVersions, setVersions]);
|
|
9097
|
-
const performLocalAutoSave =
|
|
9291
|
+
const performLocalAutoSave = React.useCallback(() => {
|
|
9098
9292
|
const state = useAutoFormStore.getState();
|
|
9099
9293
|
const latestFormData = state.formData;
|
|
9100
9294
|
if (autoSaveSkipRef.current || !collectionSlug || !latestFormData.id) return;
|
|
@@ -9104,7 +9298,7 @@ function useAutoFormState({
|
|
|
9104
9298
|
persistBrowserDraft(documentKey, latestFormData);
|
|
9105
9299
|
}
|
|
9106
9300
|
}, [collectionSlug, getDocumentKey, persistBrowserDraft]);
|
|
9107
|
-
const doAutosaveFetch =
|
|
9301
|
+
const doAutosaveFetch = React.useCallback(async (options) => {
|
|
9108
9302
|
const state = useAutoFormStore.getState();
|
|
9109
9303
|
const latestFormData = state.formData;
|
|
9110
9304
|
const currentLastSaved = state.lastSavedData;
|
|
@@ -9187,7 +9381,7 @@ function useAutoFormState({
|
|
|
9187
9381
|
setIsAutoSaving,
|
|
9188
9382
|
versionsEnabled
|
|
9189
9383
|
]);
|
|
9190
|
-
const performAutosave =
|
|
9384
|
+
const performAutosave = React.useCallback((options) => {
|
|
9191
9385
|
queueTask(
|
|
9192
9386
|
() => doAutosaveFetch(options),
|
|
9193
9387
|
{
|
|
@@ -9199,7 +9393,7 @@ function useAutoFormState({
|
|
|
9199
9393
|
}
|
|
9200
9394
|
);
|
|
9201
9395
|
}, [doAutosaveFetch, queueTask]);
|
|
9202
|
-
const saveDocument =
|
|
9396
|
+
const saveDocument = React.useCallback(
|
|
9203
9397
|
async (dataOverride, isDraft = true) => {
|
|
9204
9398
|
const state = useAutoFormStore.getState();
|
|
9205
9399
|
const payload = dataOverride || state.formData;
|
|
@@ -9225,17 +9419,17 @@ function useAutoFormState({
|
|
|
9225
9419
|
},
|
|
9226
9420
|
[collectionSlug, globalSlug, setAutoSaveStatus]
|
|
9227
9421
|
);
|
|
9228
|
-
|
|
9422
|
+
React.useEffect(() => {
|
|
9229
9423
|
const handleToggle = () => {
|
|
9230
9424
|
setSidebarCollapsed(!sidebarCollapsed);
|
|
9231
9425
|
};
|
|
9232
9426
|
window.addEventListener("toggle-sidebar", handleToggle);
|
|
9233
9427
|
return () => window.removeEventListener("toggle-sidebar", handleToggle);
|
|
9234
9428
|
}, [sidebarCollapsed, setSidebarCollapsed]);
|
|
9235
|
-
const lastLoadedSlugRef =
|
|
9236
|
-
const lastInitialDataRef =
|
|
9237
|
-
const initialDataLoadedRef =
|
|
9238
|
-
|
|
9429
|
+
const lastLoadedSlugRef = React.useRef(null);
|
|
9430
|
+
const lastInitialDataRef = React.useRef("");
|
|
9431
|
+
const initialDataLoadedRef = React.useRef(false);
|
|
9432
|
+
React.useEffect(() => {
|
|
9239
9433
|
const currentSlug = globalSlug || initialData?.id;
|
|
9240
9434
|
const serialized = JSON.stringify(initialData);
|
|
9241
9435
|
if (initialDataLoadedRef.current && lastLoadedSlugRef.current === currentSlug && lastInitialDataRef.current === serialized) return;
|
|
@@ -9244,7 +9438,7 @@ function useAutoFormState({
|
|
|
9244
9438
|
lastLoadedSlugRef.current = currentSlug;
|
|
9245
9439
|
lastInitialDataRef.current = serialized;
|
|
9246
9440
|
}, [collectionSlug, formData.id, globalSlug, initialData, loadDocument]);
|
|
9247
|
-
|
|
9441
|
+
React.useEffect(() => {
|
|
9248
9442
|
if (!collectionSlug || !initialData?.id) return;
|
|
9249
9443
|
const documentKey = getDocumentKey(initialData.id);
|
|
9250
9444
|
if (!documentKey) return;
|
|
@@ -9307,7 +9501,7 @@ function useAutoFormState({
|
|
|
9307
9501
|
}
|
|
9308
9502
|
return void 0;
|
|
9309
9503
|
}
|
|
9310
|
-
|
|
9504
|
+
React.useEffect(() => {
|
|
9311
9505
|
const fields2 = config.fields;
|
|
9312
9506
|
const metaTitleField = findFieldDeep(fields2, "metaTitle");
|
|
9313
9507
|
if (!metaTitleField) return;
|
|
@@ -9317,7 +9511,7 @@ function useAutoFormState({
|
|
|
9317
9511
|
setField("metaTitle", titleStr);
|
|
9318
9512
|
}
|
|
9319
9513
|
}, [formData, config.fields, setField]);
|
|
9320
|
-
|
|
9514
|
+
React.useEffect(() => {
|
|
9321
9515
|
const fields2 = config.fields;
|
|
9322
9516
|
const slugField = fields2.find(
|
|
9323
9517
|
(f) => f.name === "slug" && f.admin?.autoGenerate
|
|
@@ -9332,7 +9526,7 @@ function useAutoFormState({
|
|
|
9332
9526
|
}
|
|
9333
9527
|
}
|
|
9334
9528
|
}, [formData, isSlugLocked, config.fields, setField]);
|
|
9335
|
-
|
|
9529
|
+
React.useEffect(() => {
|
|
9336
9530
|
if (sidebarCollapsed) return;
|
|
9337
9531
|
if (!globalSlug && (!collectionSlug || !formData.id)) return;
|
|
9338
9532
|
const state = useAutoFormStore.getState();
|
|
@@ -9349,7 +9543,7 @@ function useAutoFormState({
|
|
|
9349
9543
|
performAutosave();
|
|
9350
9544
|
}, 8e3);
|
|
9351
9545
|
}, [formData, sidebarCollapsed, collectionSlug, globalSlug, performLocalAutoSave, performAutosave]);
|
|
9352
|
-
|
|
9546
|
+
React.useEffect(() => {
|
|
9353
9547
|
if (!globalSlug && (!collectionSlug || !formData.id)) return;
|
|
9354
9548
|
const flushDraft = () => {
|
|
9355
9549
|
if (autoSaveSkipRef.current) return;
|
|
@@ -9386,7 +9580,7 @@ function useAutoFormState({
|
|
|
9386
9580
|
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
9387
9581
|
};
|
|
9388
9582
|
}, [collectionSlug, globalSlug, formData.id, performAutosave]);
|
|
9389
|
-
|
|
9583
|
+
React.useEffect(() => {
|
|
9390
9584
|
const serialized = JSON.stringify(formData);
|
|
9391
9585
|
if (serialized === astroSyncDataRef.current) return;
|
|
9392
9586
|
astroSyncDataRef.current = serialized;
|
|
@@ -9396,7 +9590,7 @@ function useAutoFormState({
|
|
|
9396
9590
|
}
|
|
9397
9591
|
onChange?.(formData);
|
|
9398
9592
|
}, [formData, onChange]);
|
|
9399
|
-
|
|
9593
|
+
React.useEffect(() => {
|
|
9400
9594
|
if (globalSlug || formData.id) fetchVersions();
|
|
9401
9595
|
}, [formData.id, globalSlug, fetchVersions]);
|
|
9402
9596
|
const documentStatus = (() => {
|
|
@@ -9423,9 +9617,9 @@ function Dropdown({
|
|
|
9423
9617
|
align = "right",
|
|
9424
9618
|
direction = "up"
|
|
9425
9619
|
}) {
|
|
9426
|
-
const [open, setOpen] =
|
|
9427
|
-
const ref =
|
|
9428
|
-
|
|
9620
|
+
const [open, setOpen] = React.useState(false);
|
|
9621
|
+
const ref = React.useRef(null);
|
|
9622
|
+
React.useEffect(() => {
|
|
9429
9623
|
const handleClickOutside = (e) => {
|
|
9430
9624
|
if (ref.current && !ref.current.contains(e.target)) {
|
|
9431
9625
|
setOpen(false);
|
|
@@ -9552,7 +9746,7 @@ function TabsLayout({
|
|
|
9552
9746
|
onTabDataChange,
|
|
9553
9747
|
renderField
|
|
9554
9748
|
}) {
|
|
9555
|
-
const [activeTab, setActiveTab] =
|
|
9749
|
+
const [activeTab, setActiveTab] = React.useState(0);
|
|
9556
9750
|
const fieldTabs = field3.tabs || [];
|
|
9557
9751
|
const currentTab = fieldTabs[activeTab] || fieldTabs[0];
|
|
9558
9752
|
const tabData = field3.name ? formData[field3.name] || {} : formData;
|
|
@@ -9653,13 +9847,13 @@ function AutoForm({
|
|
|
9653
9847
|
onActionSuccess,
|
|
9654
9848
|
onActionError
|
|
9655
9849
|
});
|
|
9656
|
-
const menuRef =
|
|
9657
|
-
const scheduleRef =
|
|
9658
|
-
const [showSchedulePicker, setShowSchedulePicker] =
|
|
9659
|
-
const [localSaveStatus, setLocalSaveStatus] =
|
|
9660
|
-
const [now, setNow] =
|
|
9850
|
+
const menuRef = React.useRef(null);
|
|
9851
|
+
const scheduleRef = React.useRef(null);
|
|
9852
|
+
const [showSchedulePicker, setShowSchedulePicker] = React.useState(false);
|
|
9853
|
+
const [localSaveStatus, setLocalSaveStatus] = React.useState("idle");
|
|
9854
|
+
const [now, setNow] = React.useState(Date.now());
|
|
9661
9855
|
const disabled = propDisabled;
|
|
9662
|
-
|
|
9856
|
+
React.useEffect(() => {
|
|
9663
9857
|
const id = setInterval(() => setNow(Date.now()), 1e4);
|
|
9664
9858
|
return () => clearInterval(id);
|
|
9665
9859
|
}, []);
|
|
@@ -9737,7 +9931,7 @@ function AutoForm({
|
|
|
9737
9931
|
return [...prev, versionId];
|
|
9738
9932
|
});
|
|
9739
9933
|
};
|
|
9740
|
-
|
|
9934
|
+
React.useEffect(() => {
|
|
9741
9935
|
const handleShortcuts = (e) => {
|
|
9742
9936
|
if ((e.metaKey || e.ctrlKey) && e.key === "s") {
|
|
9743
9937
|
e.preventDefault();
|
|
@@ -9760,12 +9954,12 @@ function AutoForm({
|
|
|
9760
9954
|
window.addEventListener("keydown", handleShortcuts);
|
|
9761
9955
|
return () => window.removeEventListener("keydown", handleShortcuts);
|
|
9762
9956
|
}, []);
|
|
9763
|
-
|
|
9957
|
+
React.useEffect(() => {
|
|
9764
9958
|
const handler = () => setView("version");
|
|
9765
9959
|
window.addEventListener("kyro:show-version-history", handler);
|
|
9766
9960
|
return () => window.removeEventListener("kyro:show-version-history", handler);
|
|
9767
9961
|
}, []);
|
|
9768
|
-
|
|
9962
|
+
React.useEffect(() => {
|
|
9769
9963
|
const handleClickOutside = (e) => {
|
|
9770
9964
|
if (menuRef.current && !menuRef.current.contains(e.target)) {
|
|
9771
9965
|
setIsMenuOpen(false);
|
|
@@ -9776,7 +9970,7 @@ function AutoForm({
|
|
|
9776
9970
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
9777
9971
|
}
|
|
9778
9972
|
}, [isMenuOpen]);
|
|
9779
|
-
|
|
9973
|
+
React.useEffect(() => {
|
|
9780
9974
|
const handleClickOutside = (e) => {
|
|
9781
9975
|
if (scheduleRef.current && !scheduleRef.current.contains(e.target)) {
|
|
9782
9976
|
setShowSchedulePicker(false);
|
|
@@ -10061,7 +10255,7 @@ function AutoForm({
|
|
|
10061
10255
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10062
10256
|
"div",
|
|
10063
10257
|
{
|
|
10064
|
-
className: "kyro-form-row flex gap-6 items-end",
|
|
10258
|
+
className: "kyro-form-row flex flex-col md:flex-row gap-4 md:gap-6 items-start md:items-end w-full",
|
|
10065
10259
|
children: rowFields?.map((f) => {
|
|
10066
10260
|
const fAdmin = f.admin || {};
|
|
10067
10261
|
const actionUrl = fAdmin?.action;
|
|
@@ -10293,24 +10487,24 @@ function AutoForm({
|
|
|
10293
10487
|
const statusLabel = hasUnpublishedChanges ? "Draft (unpublished changes)" : docStatus === "published" ? "Published" : "Draft";
|
|
10294
10488
|
const statusColor = docStatus === "published" && !hasUnsavedChanges ? "bg-[var(--kyro-success)]" : hasUnpublishedChanges ? "bg-[var(--kyro-warning)]" : "bg-[var(--kyro-text-muted)]";
|
|
10295
10489
|
const statusBadgeBg = docStatus === "published" && !hasUnpublishedChanges ? "bg-[var(--kyro-success)]/10 text-[var(--kyro-success)] border-[var(--kyro-success)]/20" : hasUnpublishedChanges ? "bg-[var(--kyro-warning)]/10 text-[var(--kyro-warning)] border-[var(--kyro-warning)]/20" : "bg-[var(--kyro-text-muted)]/10 text-[var(--kyro-text-muted)] border-[var(--kyro-text-muted)]/20";
|
|
10296
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "surface-tile px-8 py-6 flex items-center justify-between sticky top-0 z-50 border-b border-[var(--kyro-border)] mb-8 bg-[var(--kyro-surface)] backdrop-blur-md", children: [
|
|
10297
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
10298
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
10490
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "surface-tile px-3 md:px-8 py-2 md:py-6 flex items-center justify-between max-md:static sticky top-0 z-50 border-b border-[var(--kyro-border)] mb-0 md:mb-8 bg-[var(--kyro-surface)] backdrop-blur-md", children: [
|
|
10491
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 md:gap-2 min-w-0", children: [
|
|
10492
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 md:gap-3 flex-wrap min-w-0", children: [
|
|
10299
10493
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10300
10494
|
"a",
|
|
10301
10495
|
{
|
|
10302
10496
|
href: `/${collectionSlug}`,
|
|
10303
|
-
className: "p-2 border border-[var(--kyro-border)] rounded-xl hover:bg-[var(--kyro-bg-secondary)] transition-colors",
|
|
10497
|
+
className: "p-1.5 md:p-2 border-0 md:border border-[var(--kyro-border)] rounded-xl hover:bg-[var(--kyro-bg-secondary)] transition-colors shrink-0",
|
|
10304
10498
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "w-4 h-4" })
|
|
10305
10499
|
}
|
|
10306
10500
|
),
|
|
10307
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-bold tracking-tighter", children: docTitle }),
|
|
10308
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: `inline-flex items-center gap-1.5 px-2 rounded-full text-[10px] font-regular border ${statusBadgeBg}`, children: [
|
|
10501
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg md:text-xl font-bold tracking-tighter truncate min-w-0", children: docTitle }),
|
|
10502
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: `shrink-0 inline-flex items-center gap-1.5 px-2 rounded-full text-[10px] font-regular border ${statusBadgeBg}`, children: [
|
|
10309
10503
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `h-1.5 w-1.5 rounded-full ${statusColor}` }),
|
|
10310
10504
|
statusLabel
|
|
10311
10505
|
] })
|
|
10312
10506
|
] }),
|
|
10313
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 text-[11px] font-medium tracking-wide opacity-60 ml-12", children: [
|
|
10507
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 text-[11px] font-medium tracking-wide opacity-60 md:ml-12", children: [
|
|
10314
10508
|
autoSaveStatus === "saving" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5 text-[var(--kyro-text-muted)]", children: [
|
|
10315
10509
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10316
10510
|
"svg",
|
|
@@ -10431,7 +10625,7 @@ function AutoForm({
|
|
|
10431
10625
|
] })
|
|
10432
10626
|
] })
|
|
10433
10627
|
] }),
|
|
10434
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-6", children: [
|
|
10628
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-md:hidden flex items-center gap-6", children: [
|
|
10435
10629
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1 bg-[var(--kyro-bg-secondary)] p-1 rounded-xl border border-[var(--kyro-border)]", children: ["edit", "version", "api"].map((v) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
10436
10630
|
"button",
|
|
10437
10631
|
{
|
|
@@ -10616,15 +10810,15 @@ function AutoForm({
|
|
|
10616
10810
|
};
|
|
10617
10811
|
const renderEditView = () => {
|
|
10618
10812
|
if (layout === "single") {
|
|
10619
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full space-y-8", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "surface-tile p-8 space-y-8", children: config.fields.map((f) => renderField(f)) }) });
|
|
10813
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full space-y-6 md:space-y-8", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "surface-tile p-4 md:p-8 space-y-6 md:space-y-8", children: config.fields.map((f) => renderField(f)) }) });
|
|
10620
10814
|
}
|
|
10621
10815
|
const hasSidebarFields = config.fields.some((f) => f.admin?.position === "sidebar") && !showPreview;
|
|
10622
10816
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10623
10817
|
"div",
|
|
10624
10818
|
{
|
|
10625
|
-
className: `w-full mx-auto grid gap-8 pb-32 transition-all duration-700 ${showPreview ? "grid-cols-1 lg:grid-cols-2" : sidebarCollapsed || !hasSidebarFields ? "grid-cols-1" : "grid-cols-1 lg:grid-cols-[1fr_380px]"}`,
|
|
10819
|
+
className: `w-full mx-auto grid gap-4 md:gap-8 pb-32 transition-all duration-700 ${showPreview ? "grid-cols-1 lg:grid-cols-2" : sidebarCollapsed || !hasSidebarFields ? "grid-cols-1" : "grid-cols-1 lg:grid-cols-[1fr_380px]"}`,
|
|
10626
10820
|
children: [
|
|
10627
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-8 animate-in fade-in slide-in-from-left-4 duration-500", children: config.tabs ? renderField({ type: "tabs", tabs: config.tabs }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "surface-tile p-8 space-y-8", children: config.fields.filter(
|
|
10821
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-6 md:space-y-8 animate-in fade-in slide-in-from-left-4 duration-500", children: config.tabs ? renderField({ type: "tabs", tabs: config.tabs }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "surface-tile p-4 md:p-8 space-y-6 md:space-y-8", children: config.fields.filter(
|
|
10628
10822
|
(f) => !f.admin?.position || f.admin.position === "main"
|
|
10629
10823
|
).map((f) => renderField(f)) }) }),
|
|
10630
10824
|
showPreview ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-36 h-[calc(100vh-280px)] animate-in fade-in slide-in-from-right-10 duration-700", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full h-full rounded-3xl border border-[var(--kyro-border)] bg-[var(--kyro-bg-secondary)] shadow-2xl overflow-hidden relative group", children: [
|
|
@@ -10641,9 +10835,18 @@ function AutoForm({
|
|
|
10641
10835
|
}
|
|
10642
10836
|
),
|
|
10643
10837
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 bg-transparent pointer-events-none border-[12px] border-[var(--kyro-surface)] rounded-3xl" })
|
|
10644
|
-
] }) }) : sidebarCollapsed ? null : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-6 animate-in fade-in slide-in-from-right-4 duration-500", children: config.fields.some((f) => f.admin?.position === "sidebar") && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10645
|
-
/* @__PURE__ */ jsxRuntime.
|
|
10646
|
-
|
|
10838
|
+
] }) }) : sidebarCollapsed ? null : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4 md:space-y-6 animate-in fade-in slide-in-from-right-4 duration-500", children: config.fields.some((f) => f.admin?.position === "sidebar") && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10839
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "hidden lg:block surface-tile p-6 space-y-6", children: [
|
|
10840
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-[10px] font-bold tracking-[0.2em] opacity-40", children: "Settings" }),
|
|
10841
|
+
config.fields.filter((f) => f.admin?.position === "sidebar").map((f) => renderField(f))
|
|
10842
|
+
] }),
|
|
10843
|
+
/* @__PURE__ */ jsxRuntime.jsxs("details", { className: "lg:hidden surface-tile p-4 space-y-4 group", children: [
|
|
10844
|
+
/* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "cursor-pointer font-semibold text-xs tracking-widest opacity-40 text-[var(--kyro-text-secondary)] select-none flex items-center gap-2", children: [
|
|
10845
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-3 h-3 transition-transform group-open:rotate-90", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 18l6-6-6-6" }) }),
|
|
10846
|
+
"Settings"
|
|
10847
|
+
] }),
|
|
10848
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4 pt-4 border-t border-[var(--kyro-border)]", children: config.fields.filter((f) => f.admin?.position === "sidebar").map((f) => renderField(f)) })
|
|
10849
|
+
] })
|
|
10647
10850
|
] }) })
|
|
10648
10851
|
]
|
|
10649
10852
|
}
|
|
@@ -10895,7 +11098,7 @@ function AutoForm({
|
|
|
10895
11098
|
}
|
|
10896
11099
|
)
|
|
10897
11100
|
] }),
|
|
10898
|
-
/* @__PURE__ */ jsxRuntime.jsxs("main", { className: "w-full", children: [
|
|
11101
|
+
/* @__PURE__ */ jsxRuntime.jsxs("main", { className: "w-full pt-6 md:pt-0", children: [
|
|
10899
11102
|
view === "edit" && renderEditView(),
|
|
10900
11103
|
view === "version" && renderVersionView(),
|
|
10901
11104
|
view === "api" && renderApiView()
|
|
@@ -10913,9 +11116,13 @@ function ActionBar({
|
|
|
10913
11116
|
onViewHistory,
|
|
10914
11117
|
onPreview,
|
|
10915
11118
|
onDelete,
|
|
11119
|
+
onBack,
|
|
11120
|
+
onToggleSidebar,
|
|
10916
11121
|
publishedAt,
|
|
10917
11122
|
updatedAt
|
|
10918
11123
|
}) {
|
|
11124
|
+
const view = useAutoFormStore((s) => s.view) || "edit";
|
|
11125
|
+
const setView = useAutoFormStore((s) => s.setView);
|
|
10919
11126
|
const getSaveStatusText = () => {
|
|
10920
11127
|
if (saveStatus === "saving") return "Saving...";
|
|
10921
11128
|
if (saveStatus === "saved") return "Saved";
|
|
@@ -10962,101 +11169,268 @@ function ActionBar({
|
|
|
10962
11169
|
if (!dateStr) return "Never";
|
|
10963
11170
|
return new Date(dateStr).toLocaleString();
|
|
10964
11171
|
};
|
|
10965
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10966
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex
|
|
10967
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-
|
|
11172
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
11173
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:hidden flex flex-col gap-3 py-3 px-4 bg-[var(--kyro-bg)] border-t border-[var(--kyro-border)]", children: [
|
|
11174
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
|
|
11175
|
+
onBack && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11176
|
+
"button",
|
|
11177
|
+
{
|
|
11178
|
+
type: "button",
|
|
11179
|
+
onClick: onBack,
|
|
11180
|
+
className: "p-2 rounded-lg hover:bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-secondary)] transition-all",
|
|
11181
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 12H5M12 19l-7-7 7-7" }) })
|
|
11182
|
+
}
|
|
11183
|
+
),
|
|
11184
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 ml-auto", children: [
|
|
11185
|
+
onPreview && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11186
|
+
"button",
|
|
11187
|
+
{
|
|
11188
|
+
type: "button",
|
|
11189
|
+
onClick: onPreview,
|
|
11190
|
+
className: "p-2 rounded-lg hover:bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-secondary)] transition-all",
|
|
11191
|
+
title: "Preview",
|
|
11192
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eye, { className: "w-4 h-4" })
|
|
11193
|
+
}
|
|
11194
|
+
),
|
|
11195
|
+
onViewHistory && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11196
|
+
"button",
|
|
11197
|
+
{
|
|
11198
|
+
type: "button",
|
|
11199
|
+
onClick: onViewHistory,
|
|
11200
|
+
className: "p-2 rounded-lg hover:bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-secondary)] transition-all",
|
|
11201
|
+
title: "View History",
|
|
11202
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "w-4 h-4" })
|
|
11203
|
+
}
|
|
11204
|
+
),
|
|
11205
|
+
onDuplicate && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11206
|
+
"button",
|
|
11207
|
+
{
|
|
11208
|
+
type: "button",
|
|
11209
|
+
onClick: onDuplicate,
|
|
11210
|
+
className: "p-2 rounded-lg hover:bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-secondary)] transition-all",
|
|
11211
|
+
title: "Duplicate",
|
|
11212
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "w-4 h-4" })
|
|
11213
|
+
}
|
|
11214
|
+
),
|
|
11215
|
+
onDelete && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11216
|
+
"button",
|
|
11217
|
+
{
|
|
11218
|
+
type: "button",
|
|
11219
|
+
onClick: onDelete,
|
|
11220
|
+
className: "p-2 rounded-lg hover:bg-[var(--kyro-danger-bg)] text-[var(--kyro-error)] transition-all",
|
|
11221
|
+
title: "Delete",
|
|
11222
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "w-4 h-4" })
|
|
11223
|
+
}
|
|
11224
|
+
),
|
|
11225
|
+
onToggleSidebar && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11226
|
+
"button",
|
|
11227
|
+
{
|
|
11228
|
+
type: "button",
|
|
11229
|
+
onClick: onToggleSidebar,
|
|
11230
|
+
className: "p-2 rounded-lg hover:bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-secondary)] transition-all",
|
|
11231
|
+
title: "Toggle Sidebar",
|
|
11232
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
11233
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
|
|
11234
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "9", y1: "3", x2: "9", y2: "21" })
|
|
11235
|
+
] })
|
|
11236
|
+
}
|
|
11237
|
+
)
|
|
11238
|
+
] })
|
|
11239
|
+
] }),
|
|
11240
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1 bg-[var(--kyro-bg-secondary)] p-0.5 rounded-lg border border-[var(--kyro-border)] self-start", children: ["edit", "version", "api"].map((v) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
11241
|
+
"button",
|
|
11242
|
+
{
|
|
11243
|
+
type: "button",
|
|
11244
|
+
onClick: () => setView(v),
|
|
11245
|
+
className: `px-4 py-1.5 text-xs font-bold rounded-md transition-all ${view === v ? "bg-[var(--kyro-surface)] shadow-sm border border-[var(--kyro-border)] text-[var(--kyro-text-primary)]" : "text-[var(--kyro-text-secondary)] opacity-50 hover:opacity-100"}`,
|
|
11246
|
+
children: v === "edit" ? "Edit" : v === "version" ? "Version" : "API"
|
|
11247
|
+
},
|
|
11248
|
+
v
|
|
11249
|
+
)) }),
|
|
11250
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
|
|
10968
11251
|
getStatusBadge(),
|
|
10969
11252
|
getSaveStatusText() && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10970
11253
|
"span",
|
|
10971
11254
|
{
|
|
10972
|
-
className: `text-
|
|
11255
|
+
className: `text-xs ${saveStatus === "error" ? "text-[var(--kyro-error)]" : "text-[var(--kyro-text-muted)]"}`,
|
|
10973
11256
|
children: [
|
|
10974
11257
|
saveStatus === "saving" ? /* @__PURE__ */ jsxRuntime.jsx(Spinner, { size: "sm", className: "inline mr-1" }) : null,
|
|
10975
11258
|
getSaveStatusText()
|
|
10976
11259
|
]
|
|
10977
11260
|
}
|
|
10978
|
-
)
|
|
11261
|
+
),
|
|
11262
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] text-[var(--kyro-text-muted)] ml-auto", children: [
|
|
11263
|
+
updatedAt && `Updated ${formatDate2(updatedAt)}`,
|
|
11264
|
+
publishedAt && status === "published" && ` \xB7 Published ${formatDate2(publishedAt)}`
|
|
11265
|
+
] })
|
|
10979
11266
|
] }),
|
|
10980
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
10981
|
-
|
|
10982
|
-
"
|
|
10983
|
-
|
|
11267
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
11268
|
+
status === "draft" && onPublish && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11269
|
+
"button",
|
|
11270
|
+
{
|
|
11271
|
+
type: "button",
|
|
11272
|
+
onClick: onPublish,
|
|
11273
|
+
disabled: saveStatus === "saving",
|
|
11274
|
+
className: "kyro-btn kyro-btn-primary kyro-btn-md flex items-center gap-2 flex-1 justify-center",
|
|
11275
|
+
children: [
|
|
11276
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "w-4 h-4" }),
|
|
11277
|
+
"Publish"
|
|
11278
|
+
]
|
|
11279
|
+
}
|
|
11280
|
+
),
|
|
11281
|
+
status === "published" && onUnpublish && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11282
|
+
"button",
|
|
11283
|
+
{
|
|
11284
|
+
type: "button",
|
|
11285
|
+
onClick: onUnpublish,
|
|
11286
|
+
disabled: saveStatus === "saving",
|
|
11287
|
+
className: "kyro-btn kyro-btn-secondary kyro-btn-md flex items-center gap-2 flex-1 justify-center",
|
|
11288
|
+
children: [
|
|
11289
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Undo, { className: "w-4 h-4" }),
|
|
11290
|
+
"Unpublish"
|
|
11291
|
+
]
|
|
11292
|
+
}
|
|
11293
|
+
),
|
|
11294
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11295
|
+
SplitButton,
|
|
11296
|
+
{
|
|
11297
|
+
status,
|
|
11298
|
+
saveStatus,
|
|
11299
|
+
hasChanges,
|
|
11300
|
+
onPublish: onSave,
|
|
11301
|
+
children: [
|
|
11302
|
+
onDuplicate && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11303
|
+
DropdownItem,
|
|
11304
|
+
{
|
|
11305
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "w-4 h-4" }),
|
|
11306
|
+
children: "Duplicate"
|
|
11307
|
+
}
|
|
11308
|
+
),
|
|
11309
|
+
onViewHistory && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11310
|
+
DropdownItem,
|
|
11311
|
+
{
|
|
11312
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "w-4 h-4" }),
|
|
11313
|
+
children: "View History"
|
|
11314
|
+
}
|
|
11315
|
+
),
|
|
11316
|
+
onPreview && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11317
|
+
DropdownItem,
|
|
11318
|
+
{
|
|
11319
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eye, { className: "w-4 h-4" }),
|
|
11320
|
+
children: "Preview"
|
|
11321
|
+
}
|
|
11322
|
+
),
|
|
11323
|
+
(onDuplicate || onViewHistory || onPreview) && /* @__PURE__ */ jsxRuntime.jsx(DropdownSeparator, {}),
|
|
11324
|
+
onDelete && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11325
|
+
DropdownItem,
|
|
11326
|
+
{
|
|
11327
|
+
onClick: onDelete,
|
|
11328
|
+
danger: true,
|
|
11329
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "w-4 h-4" }),
|
|
11330
|
+
children: "Delete"
|
|
11331
|
+
}
|
|
11332
|
+
)
|
|
11333
|
+
]
|
|
11334
|
+
}
|
|
11335
|
+
) })
|
|
11336
|
+
] })
|
|
11337
|
+
] }),
|
|
11338
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "hidden md:flex flex-row items-center justify-between gap-4 py-3 px-6 bg-transparent border-0 static z-40", children: [
|
|
11339
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-row items-center gap-4", children: [
|
|
11340
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
11341
|
+
getStatusBadge(),
|
|
11342
|
+
getSaveStatusText() && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11343
|
+
"span",
|
|
11344
|
+
{
|
|
11345
|
+
className: `text-sm ${saveStatus === "error" ? "text-[var(--kyro-error)]" : "text-[var(--kyro-text-muted)]"}`,
|
|
11346
|
+
children: [
|
|
11347
|
+
saveStatus === "saving" ? /* @__PURE__ */ jsxRuntime.jsx(Spinner, { size: "sm", className: "inline mr-1" }) : null,
|
|
11348
|
+
getSaveStatusText()
|
|
11349
|
+
]
|
|
11350
|
+
}
|
|
11351
|
+
)
|
|
10984
11352
|
] }),
|
|
10985
|
-
|
|
10986
|
-
"
|
|
10987
|
-
|
|
11353
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs space-y-0.5", children: [
|
|
11354
|
+
updatedAt && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[var(--kyro-text-muted)]", children: [
|
|
11355
|
+
"Updated: ",
|
|
11356
|
+
formatDate2(updatedAt)
|
|
11357
|
+
] }),
|
|
11358
|
+
publishedAt && status === "published" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[var(--kyro-primary)] font-medium", children: [
|
|
11359
|
+
"Published: ",
|
|
11360
|
+
formatDate2(publishedAt)
|
|
11361
|
+
] })
|
|
10988
11362
|
] })
|
|
11363
|
+
] }),
|
|
11364
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
|
|
11365
|
+
status === "draft" && onPublish && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11366
|
+
"button",
|
|
11367
|
+
{
|
|
11368
|
+
type: "button",
|
|
11369
|
+
onClick: onPublish,
|
|
11370
|
+
disabled: saveStatus === "saving",
|
|
11371
|
+
className: "kyro-btn kyro-btn-primary kyro-btn-md flex items-center gap-2",
|
|
11372
|
+
children: [
|
|
11373
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "w-4 h-4" }),
|
|
11374
|
+
"Publish"
|
|
11375
|
+
]
|
|
11376
|
+
}
|
|
11377
|
+
),
|
|
11378
|
+
status === "published" && onUnpublish && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11379
|
+
"button",
|
|
11380
|
+
{
|
|
11381
|
+
type: "button",
|
|
11382
|
+
onClick: onUnpublish,
|
|
11383
|
+
disabled: saveStatus === "saving",
|
|
11384
|
+
className: "kyro-btn kyro-btn-secondary kyro-btn-md flex items-center gap-2",
|
|
11385
|
+
children: [
|
|
11386
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Undo, { className: "w-4 h-4" }),
|
|
11387
|
+
"Unpublish"
|
|
11388
|
+
]
|
|
11389
|
+
}
|
|
11390
|
+
),
|
|
11391
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11392
|
+
SplitButton,
|
|
11393
|
+
{
|
|
11394
|
+
status,
|
|
11395
|
+
saveStatus,
|
|
11396
|
+
hasChanges,
|
|
11397
|
+
onPublish: onSave,
|
|
11398
|
+
children: [
|
|
11399
|
+
onDuplicate && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11400
|
+
DropdownItem,
|
|
11401
|
+
{
|
|
11402
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "w-4 h-4" }),
|
|
11403
|
+
children: "Duplicate"
|
|
11404
|
+
}
|
|
11405
|
+
),
|
|
11406
|
+
onViewHistory && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11407
|
+
DropdownItem,
|
|
11408
|
+
{
|
|
11409
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "w-4 h-4" }),
|
|
11410
|
+
children: "View History"
|
|
11411
|
+
}
|
|
11412
|
+
),
|
|
11413
|
+
onPreview && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11414
|
+
DropdownItem,
|
|
11415
|
+
{
|
|
11416
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eye, { className: "w-4 h-4" }),
|
|
11417
|
+
children: "Preview"
|
|
11418
|
+
}
|
|
11419
|
+
),
|
|
11420
|
+
(onDuplicate || onViewHistory || onPreview) && /* @__PURE__ */ jsxRuntime.jsx(DropdownSeparator, {}),
|
|
11421
|
+
onDelete && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11422
|
+
DropdownItem,
|
|
11423
|
+
{
|
|
11424
|
+
onClick: onDelete,
|
|
11425
|
+
danger: true,
|
|
11426
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "w-4 h-4" }),
|
|
11427
|
+
children: "Delete"
|
|
11428
|
+
}
|
|
11429
|
+
)
|
|
11430
|
+
]
|
|
11431
|
+
}
|
|
11432
|
+
)
|
|
10989
11433
|
] })
|
|
10990
|
-
] }),
|
|
10991
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
10992
|
-
status === "draft" && onPublish && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10993
|
-
"button",
|
|
10994
|
-
{
|
|
10995
|
-
type: "button",
|
|
10996
|
-
onClick: onPublish,
|
|
10997
|
-
disabled: saveStatus === "saving",
|
|
10998
|
-
className: "kyro-btn kyro-btn-primary kyro-btn-md flex items-center gap-2",
|
|
10999
|
-
children: [
|
|
11000
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "w-4 h-4" }),
|
|
11001
|
-
"Publish"
|
|
11002
|
-
]
|
|
11003
|
-
}
|
|
11004
|
-
),
|
|
11005
|
-
status === "published" && onUnpublish && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11006
|
-
"button",
|
|
11007
|
-
{
|
|
11008
|
-
type: "button",
|
|
11009
|
-
onClick: onUnpublish,
|
|
11010
|
-
disabled: saveStatus === "saving",
|
|
11011
|
-
className: "kyro-btn kyro-btn-secondary kyro-btn-md flex items-center gap-2",
|
|
11012
|
-
children: [
|
|
11013
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Undo, { className: "w-4 h-4" }),
|
|
11014
|
-
"Unpublish"
|
|
11015
|
-
]
|
|
11016
|
-
}
|
|
11017
|
-
),
|
|
11018
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11019
|
-
SplitButton,
|
|
11020
|
-
{
|
|
11021
|
-
status,
|
|
11022
|
-
saveStatus,
|
|
11023
|
-
hasChanges,
|
|
11024
|
-
onPublish: onSave,
|
|
11025
|
-
children: [
|
|
11026
|
-
onDuplicate && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11027
|
-
DropdownItem,
|
|
11028
|
-
{
|
|
11029
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "w-4 h-4" }),
|
|
11030
|
-
children: "Duplicate"
|
|
11031
|
-
}
|
|
11032
|
-
),
|
|
11033
|
-
onViewHistory && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11034
|
-
DropdownItem,
|
|
11035
|
-
{
|
|
11036
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "w-4 h-4" }),
|
|
11037
|
-
children: "View History"
|
|
11038
|
-
}
|
|
11039
|
-
),
|
|
11040
|
-
onPreview && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11041
|
-
DropdownItem,
|
|
11042
|
-
{
|
|
11043
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eye, { className: "w-4 h-4" }),
|
|
11044
|
-
children: "Preview"
|
|
11045
|
-
}
|
|
11046
|
-
),
|
|
11047
|
-
(onDuplicate || onViewHistory || onPreview) && /* @__PURE__ */ jsxRuntime.jsx(DropdownSeparator, {}),
|
|
11048
|
-
onDelete && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11049
|
-
DropdownItem,
|
|
11050
|
-
{
|
|
11051
|
-
onClick: onDelete,
|
|
11052
|
-
danger: true,
|
|
11053
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "w-4 h-4" }),
|
|
11054
|
-
children: "Delete"
|
|
11055
|
-
}
|
|
11056
|
-
)
|
|
11057
|
-
]
|
|
11058
|
-
}
|
|
11059
|
-
)
|
|
11060
11434
|
] })
|
|
11061
11435
|
] });
|
|
11062
11436
|
}
|
|
@@ -11072,32 +11446,32 @@ function DetailView({
|
|
|
11072
11446
|
mode = "collection"
|
|
11073
11447
|
}) {
|
|
11074
11448
|
const { confirm, alert } = useUIStore();
|
|
11075
|
-
const [data, setData] =
|
|
11076
|
-
const [originalData, setOriginalData] =
|
|
11077
|
-
const [loading, setLoading] =
|
|
11078
|
-
const [saving, setSaving] =
|
|
11079
|
-
const [saveStatus, setSaveStatus] =
|
|
11080
|
-
const [deleting, setDeleting] =
|
|
11081
|
-
const [status, setStatus] =
|
|
11082
|
-
const [createdAt, setCreatedAt] =
|
|
11083
|
-
const [updatedAt, setUpdatedAt] =
|
|
11084
|
-
const [publishedAt, setPublishedAt] =
|
|
11085
|
-
const [justSaved, setJustSaved] =
|
|
11449
|
+
const [data, setData] = React.useState({});
|
|
11450
|
+
const [originalData, setOriginalData] = React.useState({});
|
|
11451
|
+
const [loading, setLoading] = React.useState(true);
|
|
11452
|
+
const [saving, setSaving] = React.useState(false);
|
|
11453
|
+
const [saveStatus, setSaveStatus] = React.useState("idle");
|
|
11454
|
+
const [deleting, setDeleting] = React.useState(false);
|
|
11455
|
+
const [status, setStatus] = React.useState("draft");
|
|
11456
|
+
const [createdAt, setCreatedAt] = React.useState(null);
|
|
11457
|
+
const [updatedAt, setUpdatedAt] = React.useState(null);
|
|
11458
|
+
const [publishedAt, setPublishedAt] = React.useState(null);
|
|
11459
|
+
const [justSaved, setJustSaved] = React.useState(false);
|
|
11086
11460
|
const fields2 = global?.fields || collection?.fields || [];
|
|
11087
11461
|
const label = global?.label || collection?.label || "Document";
|
|
11088
11462
|
const slug = global?.slug || collection?.slug || "";
|
|
11089
11463
|
const hasChanges = JSON.stringify(data) !== JSON.stringify(originalData);
|
|
11090
|
-
|
|
11464
|
+
React.useEffect(() => {
|
|
11091
11465
|
if (hasChanges && status === "published") {
|
|
11092
11466
|
setStatus("draft");
|
|
11093
11467
|
}
|
|
11094
11468
|
}, [hasChanges, status]);
|
|
11095
|
-
|
|
11469
|
+
React.useEffect(() => {
|
|
11096
11470
|
if (hasChanges && saveStatus === "saved") {
|
|
11097
11471
|
setSaveStatus("idle");
|
|
11098
11472
|
}
|
|
11099
11473
|
}, [hasChanges, saveStatus]);
|
|
11100
|
-
|
|
11474
|
+
React.useEffect(() => {
|
|
11101
11475
|
if (mode === "global") {
|
|
11102
11476
|
loadGlobal();
|
|
11103
11477
|
} else if (documentId) {
|
|
@@ -11136,7 +11510,7 @@ function DetailView({
|
|
|
11136
11510
|
setLoading(false);
|
|
11137
11511
|
}
|
|
11138
11512
|
};
|
|
11139
|
-
const handleSave =
|
|
11513
|
+
const handleSave = React.useCallback(
|
|
11140
11514
|
async (isAutosave = false) => {
|
|
11141
11515
|
try {
|
|
11142
11516
|
setSaveStatus("saving");
|
|
@@ -11280,7 +11654,27 @@ function DetailView({
|
|
|
11280
11654
|
]
|
|
11281
11655
|
}
|
|
11282
11656
|
),
|
|
11283
|
-
|
|
11657
|
+
isSingleLayout ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "md:hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11658
|
+
ActionBar,
|
|
11659
|
+
{
|
|
11660
|
+
status,
|
|
11661
|
+
saveStatus,
|
|
11662
|
+
hasChanges,
|
|
11663
|
+
onSave: () => handleSave(false),
|
|
11664
|
+
onPublish: handlePublish,
|
|
11665
|
+
onUnpublish: status === "published" ? handleUnpublish : void 0,
|
|
11666
|
+
onDuplicate: handleDuplicate,
|
|
11667
|
+
onViewHistory: () => {
|
|
11668
|
+
window.dispatchEvent(new CustomEvent("kyro:show-version-history"));
|
|
11669
|
+
},
|
|
11670
|
+
onPreview: () => window.open(`/preview/${slug}/${documentId}`, "_blank"),
|
|
11671
|
+
onDelete: handleDeleteTrigger,
|
|
11672
|
+
onBack,
|
|
11673
|
+
onToggleSidebar: () => window.dispatchEvent(new CustomEvent("toggle-sidebar")),
|
|
11674
|
+
publishedAt,
|
|
11675
|
+
updatedAt
|
|
11676
|
+
}
|
|
11677
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
11284
11678
|
ActionBar,
|
|
11285
11679
|
{
|
|
11286
11680
|
status,
|
|
@@ -11295,6 +11689,8 @@ function DetailView({
|
|
|
11295
11689
|
},
|
|
11296
11690
|
onPreview: () => window.open(`/preview/${slug}/${documentId}`, "_blank"),
|
|
11297
11691
|
onDelete: handleDeleteTrigger,
|
|
11692
|
+
onBack,
|
|
11693
|
+
onToggleSidebar: () => window.dispatchEvent(new CustomEvent("toggle-sidebar")),
|
|
11298
11694
|
publishedAt,
|
|
11299
11695
|
updatedAt
|
|
11300
11696
|
}
|
|
@@ -11302,9 +11698,9 @@ function DetailView({
|
|
|
11302
11698
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11303
11699
|
"div",
|
|
11304
11700
|
{
|
|
11305
|
-
className: isSingleLayout ? "w-full pb-32 pt-8" : "w-full mx-auto grid grid-cols-1 lg:grid-cols-[1fr_360px] gap-8 pb-32",
|
|
11701
|
+
className: isSingleLayout ? "w-full pb-32 pt-4 md:pt-8" : "w-full mx-auto grid grid-cols-1 lg:grid-cols-[1fr_360px] gap-4 md:gap-8 pt-4 md:pt-0 pb-32",
|
|
11306
11702
|
children: [
|
|
11307
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-8 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "surface-tile p-8", children: [
|
|
11703
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4 md:space-y-8 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "surface-tile p-4 md:p-8", children: [
|
|
11308
11704
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-8 px-1", children: [
|
|
11309
11705
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-[10px] font-bold tracking-[0.2em] opacity-40", children: "Core Configuration" }),
|
|
11310
11706
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px flex-1 bg-[var(--kyro-border)] ml-6 opacity-30" })
|
|
@@ -11346,10 +11742,10 @@ function DetailView({
|
|
|
11346
11742
|
)
|
|
11347
11743
|
] })
|
|
11348
11744
|
] }) }),
|
|
11349
|
-
!isSingleLayout && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6 animate-in fade-in slide-in-from-right-4 duration-500", children: [
|
|
11350
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "surface-tile p-8", children: [
|
|
11351
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-[10px] font-bold tracking-[0.2em] opacity-40 mb-6", children: "Metadata" }),
|
|
11352
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
|
|
11745
|
+
!isSingleLayout && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 md:space-y-6 animate-in fade-in slide-in-from-right-4 duration-500", children: [
|
|
11746
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "surface-tile p-4 md:p-8", children: [
|
|
11747
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-[10px] font-bold tracking-[0.2em] opacity-40 mb-4 md:mb-6", children: "Metadata" }),
|
|
11748
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 md:space-y-6", children: [
|
|
11353
11749
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
11354
11750
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold tracking-widest opacity-40", children: "Dynamic Status" }),
|
|
11355
11751
|
/* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -11383,9 +11779,9 @@ function DetailView({
|
|
|
11383
11779
|
] })
|
|
11384
11780
|
] })
|
|
11385
11781
|
] }),
|
|
11386
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "surface-tile p-8 bg-[var(--kyro-bg-secondary)]", children: [
|
|
11387
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-[10px] font-bold tracking-[0.2em] opacity-40 mb-4", children: "Quick Links" }),
|
|
11388
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
11782
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "surface-tile p-4 md:p-8 bg-[var(--kyro-bg-secondary)]", children: [
|
|
11783
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-[10px] font-bold tracking-[0.2em] opacity-40 mb-3 md:mb-4", children: "Quick Links" }),
|
|
11784
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 md:space-y-3", children: [
|
|
11389
11785
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11390
11786
|
"button",
|
|
11391
11787
|
{
|
|
@@ -11428,8 +11824,8 @@ function CreateView({
|
|
|
11428
11824
|
onSuccess,
|
|
11429
11825
|
onError
|
|
11430
11826
|
}) {
|
|
11431
|
-
const [data, setData] =
|
|
11432
|
-
const [saving, setSaving] =
|
|
11827
|
+
const [data, setData] = React.useState({});
|
|
11828
|
+
const [saving, setSaving] = React.useState(false);
|
|
11433
11829
|
const fields2 = collection.fields || [];
|
|
11434
11830
|
const label = collection.label || collection.slug;
|
|
11435
11831
|
const handleSubmit = async (e) => {
|
|
@@ -11472,8 +11868,8 @@ function CreateView({
|
|
|
11472
11868
|
] });
|
|
11473
11869
|
}
|
|
11474
11870
|
function Toast({ type, message, onClose }) {
|
|
11475
|
-
const [isPaused, setIsPaused] =
|
|
11476
|
-
const timerRef =
|
|
11871
|
+
const [isPaused, setIsPaused] = React__default.default.useState(false);
|
|
11872
|
+
const timerRef = React__default.default.useRef(null);
|
|
11477
11873
|
const startTimer = () => {
|
|
11478
11874
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
11479
11875
|
timerRef.current = setTimeout(onClose, 5e3);
|
|
@@ -11481,7 +11877,7 @@ function Toast({ type, message, onClose }) {
|
|
|
11481
11877
|
const clearTimer = () => {
|
|
11482
11878
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
11483
11879
|
};
|
|
11484
|
-
|
|
11880
|
+
React__default.default.useEffect(() => {
|
|
11485
11881
|
if (!isPaused) {
|
|
11486
11882
|
startTimer();
|
|
11487
11883
|
} else {
|
|
@@ -11527,15 +11923,20 @@ function useToast() {
|
|
|
11527
11923
|
const toasts = useToastStore((state) => state.toasts);
|
|
11528
11924
|
return { toasts, addToast, removeToast };
|
|
11529
11925
|
}
|
|
11926
|
+
function Toaster() {
|
|
11927
|
+
const toasts = useToastStore((state) => state.toasts);
|
|
11928
|
+
const removeToast = useToastStore((state) => state.removeToast);
|
|
11929
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "kyro-toasts-container", style: { position: "fixed", bottom: "24px", right: "24px", display: "flex", flexDirection: "column", gap: "12px", zIndex: 9999, pointerEvents: "none" }, children: toasts.map((t) => /* @__PURE__ */ jsxRuntime.jsx("div", { style: { pointerEvents: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsx(Toast, { type: t.type, message: t.message, onClose: () => removeToast(t.id) }) }, t.id)) });
|
|
11930
|
+
}
|
|
11530
11931
|
function LoginPage({ onAuth, theme = "light" }) {
|
|
11531
|
-
const [mode, setMode] =
|
|
11532
|
-
const [email, setEmail] =
|
|
11533
|
-
const [password, setPassword] =
|
|
11534
|
-
const [confirmPassword, setConfirmPassword] =
|
|
11535
|
-
const [loading, setLoading] =
|
|
11536
|
-
const [
|
|
11537
|
-
const
|
|
11538
|
-
|
|
11932
|
+
const [mode, setMode] = React.useState("login");
|
|
11933
|
+
const [email, setEmail] = React.useState("");
|
|
11934
|
+
const [password, setPassword] = React.useState("");
|
|
11935
|
+
const [confirmPassword, setConfirmPassword] = React.useState("");
|
|
11936
|
+
const [loading, setLoading] = React.useState(false);
|
|
11937
|
+
const [isFirstUser, setIsFirstUser] = React.useState(false);
|
|
11938
|
+
const addToast = useToastStore((state) => state.addToast);
|
|
11939
|
+
React.useEffect(() => {
|
|
11539
11940
|
checkIfFirstUser();
|
|
11540
11941
|
}, []);
|
|
11541
11942
|
const checkIfFirstUser = async () => {
|
|
@@ -11546,13 +11947,6 @@ function LoginPage({ onAuth, theme = "light" }) {
|
|
|
11546
11947
|
setMode("register");
|
|
11547
11948
|
}
|
|
11548
11949
|
};
|
|
11549
|
-
const addToast = (type, message) => {
|
|
11550
|
-
const id = Math.random().toString(36).substring(7);
|
|
11551
|
-
setToasts((prev) => [...prev, { id, type, message }]);
|
|
11552
|
-
setTimeout(() => {
|
|
11553
|
-
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
11554
|
-
}, 5e3);
|
|
11555
|
-
};
|
|
11556
11950
|
const handleSubmit = async (e) => {
|
|
11557
11951
|
e.preventDefault();
|
|
11558
11952
|
setLoading(true);
|
|
@@ -11578,7 +11972,7 @@ function LoginPage({ onAuth, theme = "light" }) {
|
|
|
11578
11972
|
setLoading(false);
|
|
11579
11973
|
}
|
|
11580
11974
|
};
|
|
11581
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ThemeProvider, { defaultMode: theme, children: /* @__PURE__ */ jsxRuntime.
|
|
11975
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ThemeProvider, { defaultMode: theme, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "kyro-login-page", children: [
|
|
11582
11976
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "kyro-login-container", children: [
|
|
11583
11977
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "kyro-login-header", children: [
|
|
11584
11978
|
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "kyro-login-title", children: isFirstUser ? "Create Admin Account" : mode === "login" ? "Sign In" : "Create Account" }),
|
|
@@ -11668,27 +12062,19 @@ function LoginPage({ onAuth, theme = "light" }) {
|
|
|
11668
12062
|
)
|
|
11669
12063
|
] }) }) })
|
|
11670
12064
|
] }),
|
|
11671
|
-
|
|
11672
|
-
|
|
11673
|
-
{
|
|
11674
|
-
type: toast2.type,
|
|
11675
|
-
message: toast2.message,
|
|
11676
|
-
onClose: () => setToasts((prev) => prev.filter((t) => t.id !== toast2.id))
|
|
11677
|
-
},
|
|
11678
|
-
toast2.id
|
|
11679
|
-
))
|
|
11680
|
-
] }) }) });
|
|
12065
|
+
/* @__PURE__ */ jsxRuntime.jsx(Toaster, {})
|
|
12066
|
+
] }) });
|
|
11681
12067
|
}
|
|
11682
12068
|
function Dashboard({ collections: collections2, onNavigate, user }) {
|
|
11683
12069
|
const { permissions } = useAuthStore();
|
|
11684
|
-
const [stats, setStats] =
|
|
12070
|
+
const [stats, setStats] = React.useState({
|
|
11685
12071
|
totalDocs: 0,
|
|
11686
12072
|
totalMedia: 0,
|
|
11687
12073
|
totalUsers: 0,
|
|
11688
12074
|
recentActivity: []
|
|
11689
12075
|
});
|
|
11690
|
-
const [loading, setLoading] =
|
|
11691
|
-
|
|
12076
|
+
const [loading, setLoading] = React.useState(true);
|
|
12077
|
+
React.useEffect(() => {
|
|
11692
12078
|
const timer = setTimeout(() => {
|
|
11693
12079
|
setStats({
|
|
11694
12080
|
totalDocs: 124,
|
|
@@ -12009,15 +12395,15 @@ function Dashboard({ collections: collections2, onNavigate, user }) {
|
|
|
12009
12395
|
] });
|
|
12010
12396
|
}
|
|
12011
12397
|
function UserManagement() {
|
|
12012
|
-
const [users, setUsers] =
|
|
12013
|
-
const [loading, setLoading] =
|
|
12014
|
-
const [searchQuery, setSearchQuery] =
|
|
12015
|
-
const [showCreateModal, setShowCreateModal] =
|
|
12016
|
-
const [createForm, setCreateForm] =
|
|
12017
|
-
const [createError, setCreateError] =
|
|
12018
|
-
const [creating, setCreating] =
|
|
12398
|
+
const [users, setUsers] = React.useState([]);
|
|
12399
|
+
const [loading, setLoading] = React.useState(true);
|
|
12400
|
+
const [searchQuery, setSearchQuery] = React.useState("");
|
|
12401
|
+
const [showCreateModal, setShowCreateModal] = React.useState(false);
|
|
12402
|
+
const [createForm, setCreateForm] = React.useState({ name: "", email: "", password: "", role: "customer" });
|
|
12403
|
+
const [createError, setCreateError] = React.useState("");
|
|
12404
|
+
const [creating, setCreating] = React.useState(false);
|
|
12019
12405
|
const { confirm, alert } = useUIStore();
|
|
12020
|
-
|
|
12406
|
+
React.useEffect(() => {
|
|
12021
12407
|
loadUsers();
|
|
12022
12408
|
}, []);
|
|
12023
12409
|
const loadUsers = async () => {
|
|
@@ -12099,7 +12485,7 @@ function UserManagement() {
|
|
|
12099
12485
|
const filteredUsers = users.filter(
|
|
12100
12486
|
(u) => u.email.toLowerCase().includes(searchQuery.toLowerCase()) || u.name?.toLowerCase().includes(searchQuery.toLowerCase())
|
|
12101
12487
|
);
|
|
12102
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full space-y-6 animate-in fade-in slide-in-from-bottom-4 duration-700 px-8 pb-12", children: [
|
|
12488
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full space-y-6 animate-in fade-in slide-in-from-bottom-4 duration-700 px-4 md:px-8 pb-12", children: [
|
|
12103
12489
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12104
12490
|
PageHeader,
|
|
12105
12491
|
{
|
|
@@ -12137,8 +12523,8 @@ function UserManagement() {
|
|
|
12137
12523
|
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "px-4 py-1.5 text-[10px] font-bold tracking-widest opacity-40 hover:opacity-100 transition-all", children: "LOCKED" })
|
|
12138
12524
|
] })
|
|
12139
12525
|
] }),
|
|
12140
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "surface-tile overflow-
|
|
12141
|
-
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "text-[var(--kyro-text-secondary)] font-bold text-[9px] tracking-[0.2em] uppercase border-b border-[var(--kyro-border)]", children: [
|
|
12526
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "surface-tile overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full text-left", children: [
|
|
12527
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "text-[var(--kyro-text-secondary)] font-bold text-[9px] tracking-[0.2em] uppercase border-b border-[var(--kyro-border)] whitespace-nowrap", children: [
|
|
12142
12528
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-6 py-4 w-64", children: "Member Identity" }),
|
|
12143
12529
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-6 py-4", children: "Administrative Role" }),
|
|
12144
12530
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-6 py-4", children: "Security Status" }),
|
|
@@ -12282,8 +12668,8 @@ function UserManagement() {
|
|
|
12282
12668
|
] });
|
|
12283
12669
|
}
|
|
12284
12670
|
function AvatarCell({ user }) {
|
|
12285
|
-
const [url, setUrl] =
|
|
12286
|
-
|
|
12671
|
+
const [url, setUrl] = React.useState(null);
|
|
12672
|
+
React.useEffect(() => {
|
|
12287
12673
|
const avatar = user.avatar;
|
|
12288
12674
|
if (typeof avatar === "string" && /^[0-9a-f-]+$/i.test(avatar)) {
|
|
12289
12675
|
apiGet(`/api/media/${avatar}`).then((media) => setUrl(media?.thumbnailUrl || media?.url || null)).catch(() => setUrl(null));
|
|
@@ -12295,15 +12681,15 @@ function AvatarCell({ user }) {
|
|
|
12295
12681
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 h-8 rounded-lg bg-[var(--kyro-surface-accent)] border border-[var(--kyro-border)] flex items-center justify-center text-xs font-bold text-[var(--kyro-primary)] flex-shrink-0", children: user.name ? user.name[0] : user.email[0].toUpperCase() });
|
|
12296
12682
|
}
|
|
12297
12683
|
function BrandingHub() {
|
|
12298
|
-
const [siteName, setSiteName] =
|
|
12299
|
-
const [adminTitle, setAdminTitle] =
|
|
12300
|
-
const [primaryColor, setPrimaryColor] =
|
|
12301
|
-
const [dashboardGreeting, setDashboardGreeting] =
|
|
12684
|
+
const [siteName, setSiteName] = React.useState("Kyro CMS");
|
|
12685
|
+
const [adminTitle, setAdminTitle] = React.useState("Command Center");
|
|
12686
|
+
const [primaryColor, setPrimaryColor] = React.useState("#6366f1");
|
|
12687
|
+
const [dashboardGreeting, setDashboardGreeting] = React.useState(
|
|
12302
12688
|
"Welcome back to your Command Center."
|
|
12303
12689
|
);
|
|
12304
|
-
const [saving, setSaving] =
|
|
12305
|
-
const [saved, setSaved] =
|
|
12306
|
-
|
|
12690
|
+
const [saving, setSaving] = React.useState(false);
|
|
12691
|
+
const [saved, setSaved] = React.useState(false);
|
|
12692
|
+
React.useEffect(() => {
|
|
12307
12693
|
const fetchBranding = async () => {
|
|
12308
12694
|
try {
|
|
12309
12695
|
const result = await apiGet("/api/globals/site-settings");
|
|
@@ -12499,15 +12885,15 @@ function BrandingHub() {
|
|
|
12499
12885
|
}
|
|
12500
12886
|
var API_BASE2 = typeof __KYRO_API_PATH__ !== "undefined" ? __KYRO_API_PATH__ : "/api";
|
|
12501
12887
|
function DeveloperCenter({ collections: collections2 }) {
|
|
12502
|
-
const [keys, setKeys] =
|
|
12503
|
-
const [loading, setLoading] =
|
|
12504
|
-
const [showKey, setShowKey] =
|
|
12505
|
-
const [testEndpoint, setTestEndpoint] =
|
|
12506
|
-
const [playgroundResult, setPlaygroundResult] =
|
|
12507
|
-
const [exploring, setExploring] =
|
|
12888
|
+
const [keys, setKeys] = React.useState([]);
|
|
12889
|
+
const [loading, setLoading] = React.useState(false);
|
|
12890
|
+
const [showKey, setShowKey] = React.useState(null);
|
|
12891
|
+
const [testEndpoint, setTestEndpoint] = React.useState("");
|
|
12892
|
+
const [playgroundResult, setPlaygroundResult] = React.useState(null);
|
|
12893
|
+
const [exploring, setExploring] = React.useState(false);
|
|
12508
12894
|
const { confirm, alert } = useUIStore();
|
|
12509
|
-
const [showCreateModal, setShowCreateModal] =
|
|
12510
|
-
const [newKeyName, setNewKeyName] =
|
|
12895
|
+
const [showCreateModal, setShowCreateModal] = React.useState(false);
|
|
12896
|
+
const [newKeyName, setNewKeyName] = React.useState("");
|
|
12511
12897
|
const loadKeys = async () => {
|
|
12512
12898
|
try {
|
|
12513
12899
|
const data = await apiGet("/api/keys");
|
|
@@ -12516,7 +12902,7 @@ function DeveloperCenter({ collections: collections2 }) {
|
|
|
12516
12902
|
console.error(e);
|
|
12517
12903
|
}
|
|
12518
12904
|
};
|
|
12519
|
-
|
|
12905
|
+
React.useEffect(() => {
|
|
12520
12906
|
loadKeys();
|
|
12521
12907
|
}, []);
|
|
12522
12908
|
const handleGenerateKey = async () => {
|
|
@@ -12834,12 +13220,12 @@ function DeveloperCenter({ collections: collections2 }) {
|
|
|
12834
13220
|
] });
|
|
12835
13221
|
}
|
|
12836
13222
|
function useResourceManager(options) {
|
|
12837
|
-
const [items, setItems] =
|
|
12838
|
-
const [loading, setLoading] =
|
|
12839
|
-
const [error, setError] =
|
|
12840
|
-
const [isCreateModalOpen, setIsCreateModalOpen] =
|
|
13223
|
+
const [items, setItems] = React.useState([]);
|
|
13224
|
+
const [loading, setLoading] = React.useState(false);
|
|
13225
|
+
const [error, setError] = React.useState(null);
|
|
13226
|
+
const [isCreateModalOpen, setIsCreateModalOpen] = React.useState(false);
|
|
12841
13227
|
const { confirm } = useUIStore();
|
|
12842
|
-
const load =
|
|
13228
|
+
const load = React.useCallback(async () => {
|
|
12843
13229
|
setLoading(true);
|
|
12844
13230
|
setError(null);
|
|
12845
13231
|
try {
|
|
@@ -12856,10 +13242,10 @@ function useResourceManager(options) {
|
|
|
12856
13242
|
setLoading(false);
|
|
12857
13243
|
}
|
|
12858
13244
|
}, [options.endpoint, options.transformLoad]);
|
|
12859
|
-
|
|
13245
|
+
React.useEffect(() => {
|
|
12860
13246
|
load();
|
|
12861
13247
|
}, [load]);
|
|
12862
|
-
const remove =
|
|
13248
|
+
const remove = React.useCallback((id, resourceName = "item") => {
|
|
12863
13249
|
confirm({
|
|
12864
13250
|
title: `Delete ${resourceName}`,
|
|
12865
13251
|
message: `Are you sure you want to delete this ${resourceName.toLowerCase()}? This action cannot be undone.`,
|
|
@@ -12869,6 +13255,7 @@ function useResourceManager(options) {
|
|
|
12869
13255
|
await apiDelete(`${options.endpoint}/${id}`);
|
|
12870
13256
|
setItems((prev) => prev.filter((item) => item.id !== id));
|
|
12871
13257
|
options.onSuccess?.("delete", id);
|
|
13258
|
+
toast.success(`${resourceName} deleted`);
|
|
12872
13259
|
} catch (e) {
|
|
12873
13260
|
const message = e instanceof Error ? e.message : `Failed to delete ${resourceName}`;
|
|
12874
13261
|
toast.error(message);
|
|
@@ -12877,7 +13264,7 @@ function useResourceManager(options) {
|
|
|
12877
13264
|
}
|
|
12878
13265
|
});
|
|
12879
13266
|
}, [options.endpoint, confirm]);
|
|
12880
|
-
const create3 =
|
|
13267
|
+
const create3 = React.useCallback(async (data) => {
|
|
12881
13268
|
setError(null);
|
|
12882
13269
|
try {
|
|
12883
13270
|
const created = await apiPost(options.endpoint, data);
|
|
@@ -12892,7 +13279,7 @@ function useResourceManager(options) {
|
|
|
12892
13279
|
throw e;
|
|
12893
13280
|
}
|
|
12894
13281
|
}, [options.endpoint]);
|
|
12895
|
-
const update =
|
|
13282
|
+
const update = React.useCallback(async (id, data) => {
|
|
12896
13283
|
setError(null);
|
|
12897
13284
|
try {
|
|
12898
13285
|
const updated = await apiPatch(`${options.endpoint}/${id}`, data);
|
|
@@ -12932,17 +13319,17 @@ function WebhookManager() {
|
|
|
12932
13319
|
endpoint: "/api/webhooks"
|
|
12933
13320
|
});
|
|
12934
13321
|
const { confirm } = useUIStore();
|
|
12935
|
-
const [showTestModal, setShowTestModal] =
|
|
12936
|
-
const [showHelpModal, setShowHelpModal] =
|
|
12937
|
-
const [testResult, setTestResult] =
|
|
12938
|
-
const [testId, setTestId] =
|
|
12939
|
-
const [formData, setFormData] =
|
|
13322
|
+
const [showTestModal, setShowTestModal] = React.useState(false);
|
|
13323
|
+
const [showHelpModal, setShowHelpModal] = React.useState(false);
|
|
13324
|
+
const [testResult, setTestResult] = React.useState(null);
|
|
13325
|
+
const [testId, setTestId] = React.useState(null);
|
|
13326
|
+
const [formData, setFormData] = React.useState({
|
|
12940
13327
|
name: "",
|
|
12941
13328
|
url: "",
|
|
12942
13329
|
events: [],
|
|
12943
13330
|
secret: ""
|
|
12944
13331
|
});
|
|
12945
|
-
const [createError, setCreateError] =
|
|
13332
|
+
const [createError, setCreateError] = React.useState("");
|
|
12946
13333
|
const handleCreate = async () => {
|
|
12947
13334
|
if (!formData.name.trim() || !formData.url.trim()) {
|
|
12948
13335
|
setCreateError("Name and URL are required");
|
|
@@ -13097,12 +13484,12 @@ function WebhookManager() {
|
|
|
13097
13484
|
] })
|
|
13098
13485
|
] })
|
|
13099
13486
|
] }),
|
|
13100
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid sm:grid-cols-3 gap-6 pt-2", children: [
|
|
13487
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-3 gap-6 pt-2", children: [
|
|
13101
13488
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
13102
13489
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] font-bold uppercase tracking-widest opacity-30", children: "Destination" }),
|
|
13103
13490
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-mono text-xs opacity-60 truncate max-w-[200px]", title: webhook.url, children: webhook.url })
|
|
13104
13491
|
] }),
|
|
13105
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 border-l border-[var(--kyro-border)] pl-6", children: [
|
|
13492
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 sm:border-l border-t sm:border-t-0 border-[var(--kyro-border)] pt-4 sm:pt-0 sm:pl-6 mt-4 sm:mt-0", children: [
|
|
13106
13493
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] font-bold uppercase tracking-widest opacity-30", children: "Events" }),
|
|
13107
13494
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-1", children: [
|
|
13108
13495
|
webhook.events.slice(0, 2).map((event) => /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "outline", className: "text-[8px] font-bold px-1.5 opacity-60", children: event }, event)),
|
|
@@ -13113,7 +13500,7 @@ function WebhookManager() {
|
|
|
13113
13500
|
] })
|
|
13114
13501
|
] })
|
|
13115
13502
|
] }),
|
|
13116
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 border-l border-[var(--kyro-border)] pl-6", children: [
|
|
13503
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 sm:border-l border-t sm:border-t-0 border-[var(--kyro-border)] pt-4 sm:pt-0 sm:pl-6 mt-4 sm:mt-0", children: [
|
|
13117
13504
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] font-bold uppercase tracking-widest opacity-30", children: "Activity" }),
|
|
13118
13505
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[10px] font-bold opacity-60 flex items-center gap-1.5", children: [
|
|
13119
13506
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "w-3 h-3" }),
|
|
@@ -13216,7 +13603,7 @@ function WebhookManager() {
|
|
|
13216
13603
|
] }),
|
|
13217
13604
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
13218
13605
|
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-xs font-bold mb-1.5 text-[var(--kyro-text-secondary)] uppercase tracking-wider", children: "Subscribed Events" }),
|
|
13219
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-4", children: eventOptions.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
13606
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: eventOptions.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
13220
13607
|
"button",
|
|
13221
13608
|
{
|
|
13222
13609
|
type: "button",
|
|
@@ -13394,13 +13781,13 @@ function CommandPalette({
|
|
|
13394
13781
|
onNavigate
|
|
13395
13782
|
}) {
|
|
13396
13783
|
const { user, permissions } = useAuthStore();
|
|
13397
|
-
const [query, setQuery] =
|
|
13398
|
-
const [selectedIndex, setSelectedIndex] =
|
|
13399
|
-
const [loading, setLoading] =
|
|
13400
|
-
const [searchResults, setSearchResults] =
|
|
13401
|
-
const inputRef =
|
|
13402
|
-
const debounceRef =
|
|
13403
|
-
|
|
13784
|
+
const [query, setQuery] = React.useState("");
|
|
13785
|
+
const [selectedIndex, setSelectedIndex] = React.useState(0);
|
|
13786
|
+
const [loading, setLoading] = React.useState(false);
|
|
13787
|
+
const [searchResults, setSearchResults] = React.useState([]);
|
|
13788
|
+
const inputRef = React.useRef(null);
|
|
13789
|
+
const debounceRef = React.useRef(null);
|
|
13790
|
+
React.useEffect(() => {
|
|
13404
13791
|
if (isOpen) {
|
|
13405
13792
|
setQuery("");
|
|
13406
13793
|
setSelectedIndex(0);
|
|
@@ -13409,7 +13796,7 @@ function CommandPalette({
|
|
|
13409
13796
|
setTimeout(() => inputRef.current?.focus(), 100);
|
|
13410
13797
|
}
|
|
13411
13798
|
}, [isOpen]);
|
|
13412
|
-
const performSearch =
|
|
13799
|
+
const performSearch = React.useCallback(async (searchQuery) => {
|
|
13413
13800
|
if (!searchQuery || searchQuery.length < 2) {
|
|
13414
13801
|
setSearchResults([]);
|
|
13415
13802
|
return;
|
|
@@ -13430,7 +13817,7 @@ function CommandPalette({
|
|
|
13430
13817
|
setLoading(false);
|
|
13431
13818
|
}
|
|
13432
13819
|
}, []);
|
|
13433
|
-
|
|
13820
|
+
React.useEffect(() => {
|
|
13434
13821
|
if (debounceRef.current) {
|
|
13435
13822
|
clearTimeout(debounceRef.current);
|
|
13436
13823
|
}
|
|
@@ -13677,7 +14064,7 @@ function CommandPalette({
|
|
|
13677
14064
|
}
|
|
13678
14065
|
function GlobalModal() {
|
|
13679
14066
|
const { modal, closeModal } = useUIStore();
|
|
13680
|
-
const [loading, setLoading] =
|
|
14067
|
+
const [loading, setLoading] = React.useState(false);
|
|
13681
14068
|
if (!modal.open || !modal.config) return null;
|
|
13682
14069
|
const { config } = modal;
|
|
13683
14070
|
const handleConfirm = async () => {
|
|
@@ -13717,24 +14104,22 @@ function GlobalModal() {
|
|
|
13717
14104
|
);
|
|
13718
14105
|
}
|
|
13719
14106
|
function Admin({ config, theme = "light", onThemeChange }) {
|
|
13720
|
-
const [authenticated, setAuthenticated] =
|
|
13721
|
-
const [currentUser, setCurrentUser] =
|
|
13722
|
-
const collections2 =
|
|
14107
|
+
const [authenticated, setAuthenticated] = React.useState(false);
|
|
14108
|
+
const [currentUser, setCurrentUser] = React.useState(null);
|
|
14109
|
+
const collections2 = React.useMemo(
|
|
13723
14110
|
() => toCollectionMap(toArray(config.collections)),
|
|
13724
14111
|
[config.collections]
|
|
13725
14112
|
);
|
|
13726
|
-
const globals2 =
|
|
14113
|
+
const globals2 = React.useMemo(
|
|
13727
14114
|
() => toGlobalMap(toArray(config.globals)),
|
|
13728
14115
|
[config.globals]
|
|
13729
14116
|
);
|
|
13730
|
-
const [activeCollection, setActiveCollection] =
|
|
13731
|
-
const [activeGlobal, setActiveGlobal] =
|
|
13732
|
-
const [currentView, setCurrentView] =
|
|
13733
|
-
const [activeDocumentId, setActiveDocumentId] =
|
|
13734
|
-
const [isCommandPaletteOpen, setIsCommandPaletteOpen] =
|
|
13735
|
-
|
|
13736
|
-
const removeToast = useToastStore((state) => state.removeToast);
|
|
13737
|
-
React56.useEffect(() => {
|
|
14117
|
+
const [activeCollection, setActiveCollection] = React.useState(null);
|
|
14118
|
+
const [activeGlobal, setActiveGlobal] = React.useState(null);
|
|
14119
|
+
const [currentView, setCurrentView] = React.useState("list");
|
|
14120
|
+
const [activeDocumentId, setActiveDocumentId] = React.useState(null);
|
|
14121
|
+
const [isCommandPaletteOpen, setIsCommandPaletteOpen] = React.useState(false);
|
|
14122
|
+
React.useEffect(() => {
|
|
13738
14123
|
const checkAuth = async () => {
|
|
13739
14124
|
try {
|
|
13740
14125
|
const response = await fetch("/api/users/me");
|
|
@@ -13749,7 +14134,7 @@ function Admin({ config, theme = "light", onThemeChange }) {
|
|
|
13749
14134
|
};
|
|
13750
14135
|
checkAuth();
|
|
13751
14136
|
}, []);
|
|
13752
|
-
|
|
14137
|
+
React.useEffect(() => {
|
|
13753
14138
|
if (authenticated && !activeCollection) {
|
|
13754
14139
|
const firstCol = Object.keys(collections2)[0];
|
|
13755
14140
|
if (firstCol) setActiveCollection(firstCol);
|
|
@@ -13761,7 +14146,7 @@ function Admin({ config, theme = "light", onThemeChange }) {
|
|
|
13761
14146
|
if (id) setActiveDocumentId(id);
|
|
13762
14147
|
setIsCommandPaletteOpen(false);
|
|
13763
14148
|
};
|
|
13764
|
-
|
|
14149
|
+
React.useEffect(() => {
|
|
13765
14150
|
const handleKeyDown = (e) => {
|
|
13766
14151
|
if ((e.metaKey || e.ctrlKey) && e.key === "k") {
|
|
13767
14152
|
e.preventDefault();
|
|
@@ -13769,7 +14154,11 @@ function Admin({ config, theme = "light", onThemeChange }) {
|
|
|
13769
14154
|
}
|
|
13770
14155
|
};
|
|
13771
14156
|
window.addEventListener("keydown", handleKeyDown);
|
|
13772
|
-
|
|
14157
|
+
window.openCommandPalette = () => setIsCommandPaletteOpen(true);
|
|
14158
|
+
return () => {
|
|
14159
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
14160
|
+
delete window.openCommandPalette;
|
|
14161
|
+
};
|
|
13773
14162
|
}, []);
|
|
13774
14163
|
if (!authenticated) {
|
|
13775
14164
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -13855,15 +14244,7 @@ function Admin({ config, theme = "light", onThemeChange }) {
|
|
|
13855
14244
|
renderContent()
|
|
13856
14245
|
] }) }) }),
|
|
13857
14246
|
/* @__PURE__ */ jsxRuntime.jsx(GlobalModal, {}),
|
|
13858
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13859
|
-
Toast,
|
|
13860
|
-
{
|
|
13861
|
-
type: t.type,
|
|
13862
|
-
message: t.message,
|
|
13863
|
-
onClose: () => removeToast(t.id)
|
|
13864
|
-
},
|
|
13865
|
-
t.id
|
|
13866
|
-
)) })
|
|
14247
|
+
/* @__PURE__ */ jsxRuntime.jsx(Toaster, {})
|
|
13867
14248
|
] }) });
|
|
13868
14249
|
}
|
|
13869
14250
|
function BulkActionsBar({
|
|
@@ -14161,10 +14542,10 @@ function getApiUrl(path2) {
|
|
|
14161
14542
|
return `${base}${path2}`;
|
|
14162
14543
|
}
|
|
14163
14544
|
function useKyroQuery(slug, options = {}) {
|
|
14164
|
-
const [data, setData] =
|
|
14165
|
-
const [loading, setLoading] =
|
|
14166
|
-
const [error, setError] =
|
|
14167
|
-
const fetchData =
|
|
14545
|
+
const [data, setData] = React.useState(null);
|
|
14546
|
+
const [loading, setLoading] = React.useState(true);
|
|
14547
|
+
const [error, setError] = React.useState(null);
|
|
14548
|
+
const fetchData = React.useCallback(async () => {
|
|
14168
14549
|
setLoading(true);
|
|
14169
14550
|
setError(null);
|
|
14170
14551
|
try {
|
|
@@ -14186,15 +14567,15 @@ function useKyroQuery(slug, options = {}) {
|
|
|
14186
14567
|
setLoading(false);
|
|
14187
14568
|
}
|
|
14188
14569
|
}, [slug, options.page, options.limit, options.sort, options.order]);
|
|
14189
|
-
|
|
14570
|
+
React.useEffect(() => {
|
|
14190
14571
|
fetchData();
|
|
14191
14572
|
}, [fetchData]);
|
|
14192
14573
|
return { data, loading, error, refetch: fetchData };
|
|
14193
14574
|
}
|
|
14194
14575
|
function useKyroMutation(slug, method = "POST") {
|
|
14195
|
-
const [loading, setLoading] =
|
|
14196
|
-
const [error, setError] =
|
|
14197
|
-
const mutate =
|
|
14576
|
+
const [loading, setLoading] = React.useState(false);
|
|
14577
|
+
const [error, setError] = React.useState(null);
|
|
14578
|
+
const mutate = React.useCallback(
|
|
14198
14579
|
async (data) => {
|
|
14199
14580
|
setLoading(true);
|
|
14200
14581
|
setError(null);
|