@kyro-cms/admin 0.9.1 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1196 -1727
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +891 -1422
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/ActionBar.tsx +25 -174
- package/src/components/Admin.tsx +1 -3
- package/src/components/AuditLogsPage.tsx +2 -13
- package/src/components/AutoForm.tsx +160 -265
- package/src/components/DetailView.tsx +38 -66
- package/src/components/FieldRenderer.tsx +1 -1
- package/src/components/ListView.tsx +26 -198
- package/src/components/MediaGallery.tsx +117 -175
- package/src/components/RestPlayground.tsx +54 -47
- package/src/components/fields/BlocksField.tsx +8 -10
- package/src/components/fields/RelationshipBlockField.tsx +2 -3
- package/src/components/fields/RelationshipField.tsx +2 -3
- package/src/components/fix_imports.cjs +23 -0
- package/src/components/fix_imports2.cjs +19 -0
- package/src/components/replace_svgs.cjs +63 -0
- package/src/components/ui/Dropdown.tsx +7 -2
- package/src/components/ui/Modal.tsx +24 -27
- package/src/components/ui/PromptModal.tsx +2 -10
- package/src/components/ui/SlidePanel.tsx +2 -10
- package/src/components/ui/SplitButton.tsx +107 -0
- package/src/components/ui/Toaster.tsx +0 -1
- package/src/components/ui/icons.tsx +1 -0
- package/src/components/users/UsersList.tsx +8 -85
- package/src/hooks/useAutoFormState.ts +89 -161
- package/src/hooks/useQueue.ts +60 -0
- package/src/layouts/AdminLayout.astro +22 -2
- package/src/layouts/AuthLayout.astro +66 -18
- package/src/lib/autoform-store.ts +6 -2
- package/src/lib/globals.ts +5 -3
- package/src/pages/auth/register.astro +5 -2
package/dist/index.cjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React56 = require('react');
|
|
4
4
|
var zustand = require('zustand');
|
|
5
5
|
var middleware = require('zustand/middleware');
|
|
6
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
7
6
|
var lucideReact = require('lucide-react');
|
|
7
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
8
8
|
var reactDom = require('react-dom');
|
|
9
9
|
var react = require('@tiptap/react');
|
|
10
10
|
var StarterKit = require('@tiptap/starter-kit');
|
|
@@ -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 React56__default = /*#__PURE__*/_interopDefault(React56);
|
|
45
45
|
var StarterKit__default = /*#__PURE__*/_interopDefault(StarterKit);
|
|
46
46
|
var Link4__default = /*#__PURE__*/_interopDefault(Link4);
|
|
47
47
|
var Image3__default = /*#__PURE__*/_interopDefault(Image3);
|
|
@@ -486,7 +486,7 @@ function PageHeader({
|
|
|
486
486
|
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" }) })
|
|
487
487
|
}
|
|
488
488
|
),
|
|
489
|
-
breadcrumbs?.map((crumb, i) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
489
|
+
breadcrumbs?.map((crumb, i) => /* @__PURE__ */ jsxRuntime.jsxs(React56__default.default.Fragment, { children: [
|
|
490
490
|
i > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-20 text-[10px]", children: "/" }),
|
|
491
491
|
crumb.href || crumb.onClick ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
492
492
|
"a",
|
|
@@ -510,7 +510,7 @@ function PageHeader({
|
|
|
510
510
|
] }),
|
|
511
511
|
description && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mt-1", children: [
|
|
512
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(
|
|
513
|
+
metadata && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: metadata.map((item, i) => /* @__PURE__ */ jsxRuntime.jsxs(React56__default.default.Fragment, { children: [
|
|
514
514
|
i === 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-20 ml-1", children: "\xB7" }),
|
|
515
515
|
item
|
|
516
516
|
] }, i)) }),
|
|
@@ -576,6 +576,89 @@ function CountBadge({ count, max = 99 }) {
|
|
|
576
576
|
if (count === 0) return null;
|
|
577
577
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center justify-center min-w-[20px] h-5 px-1.5 text-xs font-medium bg-gray-200 text-gray-700 rounded-full", children: count > max ? `${max}+` : count });
|
|
578
578
|
}
|
|
579
|
+
function Button({
|
|
580
|
+
variant = "secondary",
|
|
581
|
+
size = "md",
|
|
582
|
+
loading = false,
|
|
583
|
+
children,
|
|
584
|
+
className = "",
|
|
585
|
+
disabled,
|
|
586
|
+
...props
|
|
587
|
+
}) {
|
|
588
|
+
const baseClass = "kyro-btn";
|
|
589
|
+
const variantClass = `kyro-btn-${variant}`;
|
|
590
|
+
const sizeClass = `kyro-btn-${size}`;
|
|
591
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
592
|
+
"button",
|
|
593
|
+
{
|
|
594
|
+
type: "button",
|
|
595
|
+
className: `${baseClass} ${variantClass} ${sizeClass} ${className}`,
|
|
596
|
+
disabled: disabled || loading,
|
|
597
|
+
...props,
|
|
598
|
+
children: [
|
|
599
|
+
loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "kyro-btn-loading", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "kyro-btn-spinner", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "3", fill: "none", strokeDasharray: "60 30" }) }) }) : null,
|
|
600
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: loading ? "kyro-btn-text-hidden" : "", children })
|
|
601
|
+
]
|
|
602
|
+
}
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
function Pagination({ page, totalPages, totalDocs, limit, onPageChange, onLimitChange }) {
|
|
606
|
+
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: [
|
|
608
|
+
totalDocs !== void 0 && limit ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-[var(--kyro-text-secondary)] font-medium", children: [
|
|
609
|
+
"Showing ",
|
|
610
|
+
(page - 1) * limit + 1,
|
|
611
|
+
" to ",
|
|
612
|
+
Math.min(page * limit, totalDocs),
|
|
613
|
+
" of ",
|
|
614
|
+
totalDocs
|
|
615
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", {}),
|
|
616
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
617
|
+
onLimitChange && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
618
|
+
"select",
|
|
619
|
+
{
|
|
620
|
+
value: limit,
|
|
621
|
+
onChange: (e) => onLimitChange(Number(e.target.value)),
|
|
622
|
+
className: "text-xs border border-[var(--kyro-border)] rounded-lg px-2 py-1 bg-[var(--kyro-bg)] text-[var(--kyro-text-secondary)]",
|
|
623
|
+
children: [
|
|
624
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: 10, children: "10/page" }),
|
|
625
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: 25, children: "25/page" }),
|
|
626
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: 50, children: "50/page" }),
|
|
627
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: 100, children: "100/page" })
|
|
628
|
+
]
|
|
629
|
+
}
|
|
630
|
+
),
|
|
631
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-[var(--kyro-text-secondary)] font-medium", children: [
|
|
632
|
+
"Page ",
|
|
633
|
+
page,
|
|
634
|
+
" of ",
|
|
635
|
+
totalPages
|
|
636
|
+
] }),
|
|
637
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-1", children: [
|
|
638
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
639
|
+
Button,
|
|
640
|
+
{
|
|
641
|
+
variant: "ghost",
|
|
642
|
+
size: "sm",
|
|
643
|
+
disabled: page <= 1,
|
|
644
|
+
onClick: () => onPageChange(page - 1),
|
|
645
|
+
children: "\u2190 Previous"
|
|
646
|
+
}
|
|
647
|
+
),
|
|
648
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
649
|
+
Button,
|
|
650
|
+
{
|
|
651
|
+
variant: "ghost",
|
|
652
|
+
size: "sm",
|
|
653
|
+
disabled: page >= totalPages,
|
|
654
|
+
onClick: () => onPageChange(page + 1),
|
|
655
|
+
children: "Next \u2192"
|
|
656
|
+
}
|
|
657
|
+
)
|
|
658
|
+
] })
|
|
659
|
+
] })
|
|
660
|
+
] });
|
|
661
|
+
}
|
|
579
662
|
|
|
580
663
|
// src/lib/resolve-field-value.ts
|
|
581
664
|
function resolveFieldValue(fields2, formData, fieldName) {
|
|
@@ -647,14 +730,14 @@ function ListView({
|
|
|
647
730
|
window.location.href = `${adminPath}/${collectionSlug}/${id}`;
|
|
648
731
|
}
|
|
649
732
|
};
|
|
650
|
-
const [docs, setDocs] =
|
|
651
|
-
const [totalDocs, setTotalDocs] =
|
|
652
|
-
const [loading, setLoading] =
|
|
653
|
-
const [page, setPage] =
|
|
654
|
-
const [limit, setLimit] =
|
|
655
|
-
const [selectedIds, setSelectedIds] =
|
|
656
|
-
const [search, setSearch] =
|
|
657
|
-
const [filters, setFilters] =
|
|
733
|
+
const [docs, setDocs] = React56.useState(initialDocs);
|
|
734
|
+
const [totalDocs, setTotalDocs] = React56.useState(initialTotal);
|
|
735
|
+
const [loading, setLoading] = React56.useState(false);
|
|
736
|
+
const [page, setPage] = React56.useState(1);
|
|
737
|
+
const [limit, setLimit] = React56.useState(10);
|
|
738
|
+
const [selectedIds, setSelectedIds] = React56.useState(/* @__PURE__ */ new Set());
|
|
739
|
+
const [search, setSearch] = React56.useState("");
|
|
740
|
+
const [filters, setFilters] = React56.useState([]);
|
|
658
741
|
const { confirm, alert } = useUIStore();
|
|
659
742
|
const addFilter = () => {
|
|
660
743
|
setFilters([...filters, { field: "", operator: "equals", value: "" }]);
|
|
@@ -670,9 +753,9 @@ function ListView({
|
|
|
670
753
|
const updateFilter = (index, updates) => {
|
|
671
754
|
setFilters(filters.map((f, i) => i === index ? { ...f, ...updates } : f));
|
|
672
755
|
};
|
|
673
|
-
const [sort, setSort] =
|
|
674
|
-
const [showFilters, setShowFilters] =
|
|
675
|
-
const [showColumns, setShowColumns] =
|
|
756
|
+
const [sort, setSort] = React56.useState(null);
|
|
757
|
+
const [showFilters, setShowFilters] = React56.useState(false);
|
|
758
|
+
const [showColumns, setShowColumns] = React56.useState(false);
|
|
676
759
|
function flattenFields(fields2) {
|
|
677
760
|
const result = [];
|
|
678
761
|
for (const field3 of fields2 || []) {
|
|
@@ -691,12 +774,12 @@ function ListView({
|
|
|
691
774
|
}
|
|
692
775
|
return result;
|
|
693
776
|
}
|
|
694
|
-
const allFields =
|
|
777
|
+
const allFields = React56.useMemo(
|
|
695
778
|
() => flattenFields(collection.fields),
|
|
696
779
|
[collection.fields]
|
|
697
780
|
);
|
|
698
781
|
const titleField = typeof collection.admin?.useAsTitle === "string" ? collection.admin.useAsTitle : allFields.find((f) => f.type !== "group" && typeof f.name === "string")?.name;
|
|
699
|
-
const [visibleColumns, setVisibleColumns] =
|
|
782
|
+
const [visibleColumns, setVisibleColumns] = React56.useState(() => {
|
|
700
783
|
let cols;
|
|
701
784
|
if (collection.admin?.defaultColumns) {
|
|
702
785
|
cols = [...collection.admin?.defaultColumns || []];
|
|
@@ -711,7 +794,7 @@ function ListView({
|
|
|
711
794
|
}
|
|
712
795
|
return new Set(cols);
|
|
713
796
|
});
|
|
714
|
-
const toggleColumn =
|
|
797
|
+
const toggleColumn = React56.useCallback((fieldName) => {
|
|
715
798
|
setVisibleColumns((prev) => {
|
|
716
799
|
const next = new Set(prev);
|
|
717
800
|
if (next.has(fieldName)) {
|
|
@@ -730,7 +813,7 @@ function ListView({
|
|
|
730
813
|
}
|
|
731
814
|
return fieldName;
|
|
732
815
|
}
|
|
733
|
-
const handleSort =
|
|
816
|
+
const handleSort = React56.useCallback((fieldName) => {
|
|
734
817
|
const resolvedField = resolveSortField(fieldName);
|
|
735
818
|
setSort((prev) => {
|
|
736
819
|
if (prev && prev.field === resolvedField) {
|
|
@@ -742,12 +825,12 @@ function ListView({
|
|
|
742
825
|
return { field: resolvedField, direction: "asc" };
|
|
743
826
|
});
|
|
744
827
|
}, []);
|
|
745
|
-
const displayFields =
|
|
828
|
+
const displayFields = React56.useMemo(
|
|
746
829
|
() => {
|
|
747
830
|
const fields2 = allFields.filter((f) => !!f.name && visibleColumns.has(f.name));
|
|
748
|
-
if (visibleColumns.has("
|
|
831
|
+
if (visibleColumns.has("status")) {
|
|
749
832
|
fields2.push({
|
|
750
|
-
name: "
|
|
833
|
+
name: "status",
|
|
751
834
|
type: "select",
|
|
752
835
|
label: "Status",
|
|
753
836
|
options: [
|
|
@@ -772,7 +855,7 @@ function ListView({
|
|
|
772
855
|
const val = resolveFieldValue(collection.fields, doc, field3.name);
|
|
773
856
|
return val ?? null;
|
|
774
857
|
}
|
|
775
|
-
const fetchDocs =
|
|
858
|
+
const fetchDocs = React56.useCallback(async () => {
|
|
776
859
|
setLoading(true);
|
|
777
860
|
try {
|
|
778
861
|
const params = new URLSearchParams({
|
|
@@ -797,13 +880,13 @@ function ListView({
|
|
|
797
880
|
setLoading(false);
|
|
798
881
|
}
|
|
799
882
|
}, [collectionSlug, page, limit, search, sort, filters]);
|
|
800
|
-
|
|
883
|
+
React56.useEffect(() => {
|
|
801
884
|
if (docs.length === 0 && initialTotal === 0) {
|
|
802
885
|
fetchDocs();
|
|
803
886
|
}
|
|
804
887
|
}, []);
|
|
805
|
-
const isFirstRender =
|
|
806
|
-
|
|
888
|
+
const isFirstRender = React56.useRef(true);
|
|
889
|
+
React56.useEffect(() => {
|
|
807
890
|
if (isFirstRender.current) {
|
|
808
891
|
isFirstRender.current = false;
|
|
809
892
|
return;
|
|
@@ -886,24 +969,7 @@ function ListView({
|
|
|
886
969
|
),
|
|
887
970
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "surface-tile p-4 flex flex-col lg:flex-row gap-4 items-start lg:items-center", children: [
|
|
888
971
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1 max-w-md", children: [
|
|
889
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
890
|
-
"svg",
|
|
891
|
-
{
|
|
892
|
-
className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-[var(--kyro-text-secondary)]",
|
|
893
|
-
fill: "none",
|
|
894
|
-
stroke: "currentColor",
|
|
895
|
-
viewBox: "0 0 24 24",
|
|
896
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
897
|
-
"path",
|
|
898
|
-
{
|
|
899
|
-
strokeLinecap: "round",
|
|
900
|
-
strokeLinejoin: "round",
|
|
901
|
-
strokeWidth: "2",
|
|
902
|
-
d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
|
903
|
-
}
|
|
904
|
-
)
|
|
905
|
-
}
|
|
906
|
-
),
|
|
972
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "w-4 h-4" }),
|
|
907
973
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
908
974
|
"input",
|
|
909
975
|
{
|
|
@@ -923,24 +989,7 @@ function ListView({
|
|
|
923
989
|
onClick: () => setShowFilters(!showFilters),
|
|
924
990
|
className: `flex items-center gap-2 px-4 py-2 rounded-xl font-bold text-sm transition-all ${showFilters || filters.length > 0 ? "bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)]" : "bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-text-primary)]"}`,
|
|
925
991
|
children: [
|
|
926
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
927
|
-
"svg",
|
|
928
|
-
{
|
|
929
|
-
className: "w-4 h-4",
|
|
930
|
-
fill: "none",
|
|
931
|
-
stroke: "currentColor",
|
|
932
|
-
viewBox: "0 0 24 24",
|
|
933
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
934
|
-
"path",
|
|
935
|
-
{
|
|
936
|
-
strokeLinecap: "round",
|
|
937
|
-
strokeLinejoin: "round",
|
|
938
|
-
strokeWidth: "2",
|
|
939
|
-
d: "M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z"
|
|
940
|
-
}
|
|
941
|
-
)
|
|
942
|
-
}
|
|
943
|
-
),
|
|
992
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className: "w-4 h-4" }),
|
|
944
993
|
"Filters",
|
|
945
994
|
filters.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 px-1.5 py-0.5 bg-[var(--kyro-sidebar-text-active)] text-[var(--kyro-sidebar-active)] rounded-full text-xs", children: filters.length })
|
|
946
995
|
]
|
|
@@ -954,24 +1003,7 @@ function ListView({
|
|
|
954
1003
|
onClick: () => setShowColumns(!showColumns),
|
|
955
1004
|
className: "flex items-center gap-2 px-4 py-2 rounded-xl font-bold text-sm bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-text-primary)] transition-all",
|
|
956
1005
|
children: [
|
|
957
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
958
|
-
"svg",
|
|
959
|
-
{
|
|
960
|
-
className: "w-4 h-4",
|
|
961
|
-
fill: "none",
|
|
962
|
-
stroke: "currentColor",
|
|
963
|
-
viewBox: "0 0 24 24",
|
|
964
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
965
|
-
"path",
|
|
966
|
-
{
|
|
967
|
-
strokeLinecap: "round",
|
|
968
|
-
strokeLinejoin: "round",
|
|
969
|
-
strokeWidth: "2",
|
|
970
|
-
d: "M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2"
|
|
971
|
-
}
|
|
972
|
-
)
|
|
973
|
-
}
|
|
974
|
-
),
|
|
1006
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Columns3, { className: "w-4 h-4" }),
|
|
975
1007
|
"Columns"
|
|
976
1008
|
]
|
|
977
1009
|
}
|
|
@@ -1023,24 +1055,7 @@ function ListView({
|
|
|
1023
1055
|
onClick: addFilter,
|
|
1024
1056
|
className: "flex items-center gap-2 px-3 py-1.5 text-sm font-bold text-[var(--kyro-sidebar-active)] hover:bg-[var(--kyro-surface-accent)] rounded-lg transition-all",
|
|
1025
1057
|
children: [
|
|
1026
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1027
|
-
"svg",
|
|
1028
|
-
{
|
|
1029
|
-
className: "w-4 h-4",
|
|
1030
|
-
fill: "none",
|
|
1031
|
-
stroke: "currentColor",
|
|
1032
|
-
viewBox: "0 0 24 24",
|
|
1033
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1034
|
-
"path",
|
|
1035
|
-
{
|
|
1036
|
-
strokeLinecap: "round",
|
|
1037
|
-
strokeLinejoin: "round",
|
|
1038
|
-
strokeWidth: "2",
|
|
1039
|
-
d: "M12 5v14M5 12h14"
|
|
1040
|
-
}
|
|
1041
|
-
)
|
|
1042
|
-
}
|
|
1043
|
-
),
|
|
1058
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "w-4 h-4" }),
|
|
1044
1059
|
"Add Filter"
|
|
1045
1060
|
]
|
|
1046
1061
|
}
|
|
@@ -1091,24 +1106,7 @@ function ListView({
|
|
|
1091
1106
|
type: "button",
|
|
1092
1107
|
onClick: () => removeFilter(index),
|
|
1093
1108
|
className: "p-2 text-[var(--kyro-text-muted)] hover:text-red-500 transition-colors",
|
|
1094
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1095
|
-
"svg",
|
|
1096
|
-
{
|
|
1097
|
-
className: "w-4 h-4",
|
|
1098
|
-
fill: "none",
|
|
1099
|
-
stroke: "currentColor",
|
|
1100
|
-
viewBox: "0 0 24 24",
|
|
1101
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1102
|
-
"path",
|
|
1103
|
-
{
|
|
1104
|
-
strokeLinecap: "round",
|
|
1105
|
-
strokeLinejoin: "round",
|
|
1106
|
-
strokeWidth: "2",
|
|
1107
|
-
d: "M6 18L18 6M6 6l12 12"
|
|
1108
|
-
}
|
|
1109
|
-
)
|
|
1110
|
-
}
|
|
1111
|
-
)
|
|
1109
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" })
|
|
1112
1110
|
}
|
|
1113
1111
|
)
|
|
1114
1112
|
] }, index)),
|
|
@@ -1128,24 +1126,7 @@ function ListView({
|
|
|
1128
1126
|
onClick: handleBulkDelete,
|
|
1129
1127
|
className: "flex items-center gap-2 px-4 py-2 bg-red-500 text-white rounded-lg font-bold text-sm hover:bg-red-600 transition-all",
|
|
1130
1128
|
children: [
|
|
1131
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1132
|
-
"svg",
|
|
1133
|
-
{
|
|
1134
|
-
className: "w-4 h-4",
|
|
1135
|
-
fill: "none",
|
|
1136
|
-
stroke: "currentColor",
|
|
1137
|
-
viewBox: "0 0 24 24",
|
|
1138
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1139
|
-
"path",
|
|
1140
|
-
{
|
|
1141
|
-
strokeLinecap: "round",
|
|
1142
|
-
strokeLinejoin: "round",
|
|
1143
|
-
strokeWidth: "2",
|
|
1144
|
-
d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
|
1145
|
-
}
|
|
1146
|
-
)
|
|
1147
|
-
}
|
|
1148
|
-
),
|
|
1129
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "w-4 h-4" }),
|
|
1149
1130
|
"Delete Selected"
|
|
1150
1131
|
]
|
|
1151
1132
|
}
|
|
@@ -1162,24 +1143,7 @@ function ListView({
|
|
|
1162
1143
|
] })
|
|
1163
1144
|
] }),
|
|
1164
1145
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "surface-tile overflow-hidden", children: loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2 p-4", children: /* @__PURE__ */ jsxRuntime.jsx(Shimmer, { variant: "table-row", count: 8 }) }) : docs.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-16 px-8", children: [
|
|
1165
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 h-16 rounded-2xl bg-[var(--kyro-surface-accent)] flex items-center justify-center mb-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1166
|
-
"svg",
|
|
1167
|
-
{
|
|
1168
|
-
className: "w-8 h-8 text-[var(--kyro-text-muted)]",
|
|
1169
|
-
fill: "none",
|
|
1170
|
-
stroke: "currentColor",
|
|
1171
|
-
viewBox: "0 0 24 24",
|
|
1172
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1173
|
-
"path",
|
|
1174
|
-
{
|
|
1175
|
-
strokeLinecap: "round",
|
|
1176
|
-
strokeLinejoin: "round",
|
|
1177
|
-
strokeWidth: "1.5",
|
|
1178
|
-
d: "M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"
|
|
1179
|
-
}
|
|
1180
|
-
)
|
|
1181
|
-
}
|
|
1182
|
-
) }),
|
|
1146
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 h-16 rounded-2xl bg-[var(--kyro-surface-accent)] flex items-center justify-center mb-4", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Archive, { className: "w-4 h-4" }) }),
|
|
1183
1147
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium text-[var(--kyro-text-primary)] text-base", children: "No documents found" }),
|
|
1184
1148
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-[var(--kyro-text-secondary)] mt-1", children: hasActiveFilters ? "Try adjusting your filters or search query." : `Get started by creating your first ${(collection.singularLabel || collection.label || collectionSlug).toLowerCase()}.` }),
|
|
1185
1149
|
!hasActiveFilters && canCreate && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -1189,24 +1153,7 @@ function ListView({
|
|
|
1189
1153
|
onClick: handleCreate,
|
|
1190
1154
|
className: "mt-4 kyro-btn kyro-btn-md kyro-btn-primary shadow-md flex items-center gap-2",
|
|
1191
1155
|
children: [
|
|
1192
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1193
|
-
"svg",
|
|
1194
|
-
{
|
|
1195
|
-
className: "w-3.5 h-3.5",
|
|
1196
|
-
fill: "none",
|
|
1197
|
-
stroke: "currentColor",
|
|
1198
|
-
viewBox: "0 0 24 24",
|
|
1199
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1200
|
-
"path",
|
|
1201
|
-
{
|
|
1202
|
-
strokeLinecap: "round",
|
|
1203
|
-
strokeLinejoin: "round",
|
|
1204
|
-
strokeWidth: "2.5",
|
|
1205
|
-
d: "M12 5v14M5 12h14"
|
|
1206
|
-
}
|
|
1207
|
-
)
|
|
1208
|
-
}
|
|
1209
|
-
),
|
|
1156
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "w-4 h-4" }),
|
|
1210
1157
|
"Create",
|
|
1211
1158
|
" ",
|
|
1212
1159
|
String(collection.singularLabel || collection.label || collectionSlug)
|
|
@@ -1231,24 +1178,7 @@ function ListView({
|
|
|
1231
1178
|
onClick: () => handleSort(field3.name),
|
|
1232
1179
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1233
1180
|
checkTabbedValue(displayFields, field3.type) ?? (field3.label || field3.name),
|
|
1234
|
-
sort && sort.field === field3.name && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1235
|
-
"svg",
|
|
1236
|
-
{
|
|
1237
|
-
className: `w-3 h-3 ${sort.direction === "desc" ? "rotate-180" : ""}`,
|
|
1238
|
-
fill: "none",
|
|
1239
|
-
stroke: "currentColor",
|
|
1240
|
-
viewBox: "0 0 24 24",
|
|
1241
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1242
|
-
"path",
|
|
1243
|
-
{
|
|
1244
|
-
strokeLinecap: "round",
|
|
1245
|
-
strokeLinejoin: "round",
|
|
1246
|
-
strokeWidth: "2",
|
|
1247
|
-
d: "M5 15l7-7 7 7"
|
|
1248
|
-
}
|
|
1249
|
-
)
|
|
1250
|
-
}
|
|
1251
|
-
)
|
|
1181
|
+
sort && sort.field === field3.name && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "w-4 h-4" })
|
|
1252
1182
|
] })
|
|
1253
1183
|
},
|
|
1254
1184
|
field3.name
|
|
@@ -1311,24 +1241,7 @@ function ListView({
|
|
|
1311
1241
|
onClick: () => handleEdit(doc.id),
|
|
1312
1242
|
className: "flex items-center gap-2 px-3 py-1.5 hover:bg-[var(--kyro-surface-accent)] rounded-lg text-sm font-bold text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-text-primary)] transition-all",
|
|
1313
1243
|
title: canUpdate ? "Edit" : "View",
|
|
1314
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1315
|
-
"svg",
|
|
1316
|
-
{
|
|
1317
|
-
className: "w-4 h-4",
|
|
1318
|
-
fill: "none",
|
|
1319
|
-
stroke: "currentColor",
|
|
1320
|
-
viewBox: "0 0 24 24",
|
|
1321
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1322
|
-
"path",
|
|
1323
|
-
{
|
|
1324
|
-
strokeLinecap: "round",
|
|
1325
|
-
strokeLinejoin: "round",
|
|
1326
|
-
strokeWidth: "2",
|
|
1327
|
-
d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
|
|
1328
|
-
}
|
|
1329
|
-
)
|
|
1330
|
-
}
|
|
1331
|
-
)
|
|
1244
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "w-4 h-4" })
|
|
1332
1245
|
}
|
|
1333
1246
|
),
|
|
1334
1247
|
canDelete && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1338,24 +1251,7 @@ function ListView({
|
|
|
1338
1251
|
onClick: () => handleDeleteSingle(doc.id),
|
|
1339
1252
|
className: "inline-flex items-center justify-center w-8 h-8 rounded-md text-[var(--kyro-text-muted)] hover:bg-red-50 hover:text-red-500 dark:hover:bg-red-500/10 transition-colors",
|
|
1340
1253
|
title: "Delete",
|
|
1341
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1342
|
-
"svg",
|
|
1343
|
-
{
|
|
1344
|
-
className: "w-4 h-4",
|
|
1345
|
-
fill: "none",
|
|
1346
|
-
stroke: "currentColor",
|
|
1347
|
-
viewBox: "0 0 24 24",
|
|
1348
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1349
|
-
"path",
|
|
1350
|
-
{
|
|
1351
|
-
strokeLinecap: "round",
|
|
1352
|
-
strokeLinejoin: "round",
|
|
1353
|
-
strokeWidth: "2",
|
|
1354
|
-
d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
|
1355
|
-
}
|
|
1356
|
-
)
|
|
1357
|
-
}
|
|
1358
|
-
)
|
|
1254
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "w-4 h-4" })
|
|
1359
1255
|
}
|
|
1360
1256
|
)
|
|
1361
1257
|
] })
|
|
@@ -1366,60 +1262,20 @@ function ListView({
|
|
|
1366
1262
|
doc.id
|
|
1367
1263
|
)) })
|
|
1368
1264
|
] }) }) }),
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
] }),
|
|
1384
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1385
|
-
"select",
|
|
1386
|
-
{
|
|
1387
|
-
value: limit,
|
|
1388
|
-
onChange: (e) => {
|
|
1389
|
-
setLimit(Number(e.target.value));
|
|
1390
|
-
setPage(1);
|
|
1391
|
-
},
|
|
1392
|
-
className: "px-2 py-1 bg-[var(--kyro-bg)] border border-[var(--kyro-border)] rounded-lg text-sm font-medium text-[var(--kyro-text-primary)]",
|
|
1393
|
-
children: [
|
|
1394
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: 10, children: "10 / page" }),
|
|
1395
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: 25, children: "25 / page" }),
|
|
1396
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: 50, children: "50 / page" }),
|
|
1397
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: 100, children: "100 / page" })
|
|
1398
|
-
]
|
|
1399
|
-
}
|
|
1400
|
-
)
|
|
1401
|
-
] }),
|
|
1402
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
|
|
1403
|
-
page > 1 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1404
|
-
"button",
|
|
1405
|
-
{
|
|
1406
|
-
type: "button",
|
|
1407
|
-
onClick: () => setPage(page - 1),
|
|
1408
|
-
className: "px-4 py-2 border border-[var(--kyro-border)] rounded-lg text-sm font-medium text-[var(--kyro-text-primary)] hover:bg-[var(--kyro-surface-accent)] transition-colors",
|
|
1409
|
-
children: "\u2190 Previous"
|
|
1410
|
-
}
|
|
1411
|
-
),
|
|
1412
|
-
page < totalPages && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1413
|
-
"button",
|
|
1414
|
-
{
|
|
1415
|
-
type: "button",
|
|
1416
|
-
onClick: () => setPage(page + 1),
|
|
1417
|
-
className: "px-4 py-2 bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)] rounded-lg text-sm font-bold hover:opacity-90 transition-all",
|
|
1418
|
-
children: "Next \u2192"
|
|
1419
|
-
}
|
|
1420
|
-
)
|
|
1421
|
-
] })
|
|
1422
|
-
] })
|
|
1265
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1266
|
+
Pagination,
|
|
1267
|
+
{
|
|
1268
|
+
page,
|
|
1269
|
+
totalPages,
|
|
1270
|
+
totalDocs,
|
|
1271
|
+
limit,
|
|
1272
|
+
onPageChange: setPage,
|
|
1273
|
+
onLimitChange: (newLimit) => {
|
|
1274
|
+
setLimit(newLimit);
|
|
1275
|
+
setPage(1);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
)
|
|
1423
1279
|
] });
|
|
1424
1280
|
}
|
|
1425
1281
|
function formatCellValue(value, type) {
|
|
@@ -1493,26 +1349,26 @@ function UploadField({
|
|
|
1493
1349
|
onChange,
|
|
1494
1350
|
disabled
|
|
1495
1351
|
}) {
|
|
1496
|
-
const inputRef =
|
|
1497
|
-
const urlInputRef =
|
|
1498
|
-
const [uploading, setUploading] =
|
|
1499
|
-
const [showPicker, setShowPicker] =
|
|
1500
|
-
const [isPickerFullscreen, setIsPickerFullscreen] =
|
|
1501
|
-
const [mediaItems, setMediaItems] =
|
|
1502
|
-
const [folders, setFolders] =
|
|
1503
|
-
const [selectedFolder, setSelectedFolder] =
|
|
1504
|
-
const [mediaLoading, setMediaLoading] =
|
|
1505
|
-
const [pickerSearch, setPickerSearch] =
|
|
1506
|
-
const [showUrlInput, setShowUrlInput] =
|
|
1507
|
-
const [urlValue, setUrlValue] =
|
|
1508
|
-
const [urlError, setUrlError] =
|
|
1509
|
-
const [selectedItems, setSelectedItems] =
|
|
1352
|
+
const inputRef = React56.useRef(null);
|
|
1353
|
+
const urlInputRef = React56.useRef(null);
|
|
1354
|
+
const [uploading, setUploading] = React56.useState(false);
|
|
1355
|
+
const [showPicker, setShowPicker] = React56.useState(false);
|
|
1356
|
+
const [isPickerFullscreen, setIsPickerFullscreen] = React56.useState(false);
|
|
1357
|
+
const [mediaItems, setMediaItems] = React56.useState([]);
|
|
1358
|
+
const [folders, setFolders] = React56.useState([]);
|
|
1359
|
+
const [selectedFolder, setSelectedFolder] = React56.useState("");
|
|
1360
|
+
const [mediaLoading, setMediaLoading] = React56.useState(false);
|
|
1361
|
+
const [pickerSearch, setPickerSearch] = React56.useState("");
|
|
1362
|
+
const [showUrlInput, setShowUrlInput] = React56.useState(false);
|
|
1363
|
+
const [urlValue, setUrlValue] = React56.useState("");
|
|
1364
|
+
const [urlError, setUrlError] = React56.useState("");
|
|
1365
|
+
const [selectedItems, setSelectedItems] = React56.useState([]);
|
|
1510
1366
|
const fieldLabel = field3?.label || field3?.name || "File";
|
|
1511
1367
|
const maxCount = field3.maxCount ?? (field3.hasMany ? 999 : 1);
|
|
1512
1368
|
const isMultiple = maxCount > 1;
|
|
1513
1369
|
const currentValue = Array.isArray(value) ? value : value ? [value] : [];
|
|
1514
1370
|
const canAddMore = currentValue.length < maxCount;
|
|
1515
|
-
|
|
1371
|
+
React56.useEffect(() => {
|
|
1516
1372
|
const fetchMissingDetails = async () => {
|
|
1517
1373
|
const idsToFetch = currentValue.filter((item) => typeof item === "string").map((id) => id);
|
|
1518
1374
|
const objectIdsToFetch = currentValue.filter(
|
|
@@ -1546,7 +1402,7 @@ function UploadField({
|
|
|
1546
1402
|
};
|
|
1547
1403
|
fetchMissingDetails();
|
|
1548
1404
|
}, [value]);
|
|
1549
|
-
|
|
1405
|
+
React56.useEffect(() => {
|
|
1550
1406
|
if (showPicker) {
|
|
1551
1407
|
loadFolders();
|
|
1552
1408
|
loadMedia();
|
|
@@ -1672,7 +1528,7 @@ function UploadField({
|
|
|
1672
1528
|
newValue.splice(index, 1);
|
|
1673
1529
|
onChange(isMultiple ? newValue : newValue[0] || null);
|
|
1674
1530
|
};
|
|
1675
|
-
const filteredMedia =
|
|
1531
|
+
const filteredMedia = React56.useMemo(() => {
|
|
1676
1532
|
return mediaItems.filter((item) => {
|
|
1677
1533
|
return !pickerSearch || item.filename?.toLowerCase().includes(pickerSearch.toLowerCase()) || item.title?.toLowerCase().includes(pickerSearch.toLowerCase());
|
|
1678
1534
|
});
|
|
@@ -2079,12 +1935,12 @@ function SlidePanel({
|
|
|
2079
1935
|
showOverlay = false,
|
|
2080
1936
|
accentClass
|
|
2081
1937
|
}) {
|
|
2082
|
-
const panelRef =
|
|
2083
|
-
const [hydrated, setHydrated] =
|
|
2084
|
-
|
|
1938
|
+
const panelRef = React56.useRef(null);
|
|
1939
|
+
const [hydrated, setHydrated] = React56.useState(false);
|
|
1940
|
+
React56.useEffect(() => {
|
|
2085
1941
|
setHydrated(true);
|
|
2086
1942
|
}, []);
|
|
2087
|
-
|
|
1943
|
+
React56.useEffect(() => {
|
|
2088
1944
|
const handleEscape = (e) => {
|
|
2089
1945
|
if (e.key === "Escape") onClose();
|
|
2090
1946
|
};
|
|
@@ -2129,18 +1985,7 @@ function SlidePanel({
|
|
|
2129
1985
|
type: "button",
|
|
2130
1986
|
onClick: onClose,
|
|
2131
1987
|
className: "p-1.5 text-[var(--kyro-text-muted)] hover:text-[var(--kyro-text-primary)] hover:bg-[var(--kyro-surface-accent)] rounded-lg transition-colors",
|
|
2132
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2133
|
-
"svg",
|
|
2134
|
-
{
|
|
2135
|
-
width: "16",
|
|
2136
|
-
height: "16",
|
|
2137
|
-
viewBox: "0 0 24 24",
|
|
2138
|
-
fill: "none",
|
|
2139
|
-
stroke: "currentColor",
|
|
2140
|
-
strokeWidth: "2",
|
|
2141
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6L6 18M6 6l12 12" })
|
|
2142
|
-
}
|
|
2143
|
-
)
|
|
1988
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" })
|
|
2144
1989
|
}
|
|
2145
1990
|
)
|
|
2146
1991
|
] }),
|
|
@@ -2161,54 +2006,158 @@ function SlidePanel({
|
|
|
2161
2006
|
document.body
|
|
2162
2007
|
);
|
|
2163
2008
|
}
|
|
2164
|
-
function
|
|
2009
|
+
function ModalContent({ children }) {
|
|
2010
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[var(--kyro-text-secondary)]", children });
|
|
2011
|
+
}
|
|
2012
|
+
function ModalActions({ children }) {
|
|
2013
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end gap-3 mt-6", children });
|
|
2014
|
+
}
|
|
2015
|
+
function Modal({
|
|
2165
2016
|
open,
|
|
2166
2017
|
onClose,
|
|
2167
|
-
onSubmit,
|
|
2168
2018
|
title,
|
|
2169
|
-
|
|
2170
|
-
|
|
2019
|
+
children,
|
|
2020
|
+
footer,
|
|
2021
|
+
size = "md",
|
|
2022
|
+
variant = "default"
|
|
2171
2023
|
}) {
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2024
|
+
React56.useEffect(() => {
|
|
2025
|
+
const handleEscape = (e) => {
|
|
2026
|
+
if (e.key === "Escape") onClose();
|
|
2027
|
+
};
|
|
2028
|
+
if (open) {
|
|
2029
|
+
document.addEventListener("keydown", handleEscape);
|
|
2030
|
+
document.body.style.overflow = "hidden";
|
|
2179
2031
|
}
|
|
2180
|
-
|
|
2032
|
+
return () => {
|
|
2033
|
+
document.removeEventListener("keydown", handleEscape);
|
|
2034
|
+
document.body.style.overflow = "";
|
|
2035
|
+
};
|
|
2036
|
+
}, [open, onClose]);
|
|
2181
2037
|
if (!open) return null;
|
|
2038
|
+
const sizeClasses = {
|
|
2039
|
+
sm: "max-w-sm",
|
|
2040
|
+
md: "max-w-md",
|
|
2041
|
+
lg: "max-w-lg",
|
|
2042
|
+
full: "w-full h-full max-w-none rounded-none border-0"
|
|
2043
|
+
};
|
|
2044
|
+
const isLightbox = variant === "lightbox";
|
|
2182
2045
|
return reactDom.createPortal(
|
|
2183
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-[9999] flex items-center justify-center", children: [
|
|
2046
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-[9999] flex items-center justify-center p-4", children: [
|
|
2184
2047
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2185
2048
|
"div",
|
|
2186
2049
|
{
|
|
2187
|
-
className:
|
|
2050
|
+
className: `absolute inset-0 transition-all duration-500 ${isLightbox ? "bg-black/95 backdrop-blur-none" : "bg-[var(--kyro-black)]/40 backdrop-blur-md"}`,
|
|
2188
2051
|
onClick: onClose
|
|
2189
2052
|
}
|
|
2190
2053
|
),
|
|
2191
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
{
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
viewBox: "0 0 24 24",
|
|
2206
|
-
fill: "none",
|
|
2207
|
-
stroke: "currentColor",
|
|
2208
|
-
strokeWidth: "2",
|
|
2209
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6L6 18M6 6l12 12" })
|
|
2054
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2055
|
+
"div",
|
|
2056
|
+
{
|
|
2057
|
+
className: `relative ${sizeClasses[size]} ${isLightbox ? "bg-transparent text-white" : "bg-[var(--kyro-surface)]"} ${!isLightbox && size !== "full" ? "rounded-[var(--kyro-radius-lg)]" : ""} shadow-2xl animate-in fade-in zoom-in-95 duration-300 ${!isLightbox ? "border" : ""} ${variant === "danger" ? "border-red-500/30" : "border-[var(--kyro-border)]"} flex flex-col overflow-hidden`,
|
|
2058
|
+
children: [
|
|
2059
|
+
!isLightbox && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-8 py-6 border-b border-[var(--kyro-border)] bg-[var(--kyro-surface-accent)]/50 backdrop-blur-md", children: [
|
|
2060
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl font-bold text-[var(--kyro-text-primary)]", children: title }),
|
|
2061
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2062
|
+
"button",
|
|
2063
|
+
{
|
|
2064
|
+
type: "button",
|
|
2065
|
+
onClick: onClose,
|
|
2066
|
+
className: "p-2 text-[var(--kyro-text-muted)] hover:text-[var(--kyro-text-primary)] rounded-xl hover:bg-[var(--kyro-surface)] transition-all duration-200",
|
|
2067
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" })
|
|
2210
2068
|
}
|
|
2211
2069
|
)
|
|
2070
|
+
] }),
|
|
2071
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex-1 overflow-auto ${isLightbox ? "" : "px-8 py-8"}`, children }),
|
|
2072
|
+
footer && !isLightbox && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end gap-3 px-8 py-6 border-t border-[var(--kyro-border)] bg-[var(--kyro-surface-accent)]/50", children: footer })
|
|
2073
|
+
]
|
|
2074
|
+
}
|
|
2075
|
+
)
|
|
2076
|
+
] }),
|
|
2077
|
+
document.body
|
|
2078
|
+
);
|
|
2079
|
+
}
|
|
2080
|
+
function ConfirmModal({
|
|
2081
|
+
open,
|
|
2082
|
+
onClose,
|
|
2083
|
+
onConfirm,
|
|
2084
|
+
title,
|
|
2085
|
+
message,
|
|
2086
|
+
confirmLabel = "Confirm",
|
|
2087
|
+
cancelLabel = "Cancel",
|
|
2088
|
+
variant = "default",
|
|
2089
|
+
loading = false
|
|
2090
|
+
}) {
|
|
2091
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2092
|
+
Modal,
|
|
2093
|
+
{
|
|
2094
|
+
open,
|
|
2095
|
+
onClose,
|
|
2096
|
+
title,
|
|
2097
|
+
size: "sm",
|
|
2098
|
+
footer: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2099
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2100
|
+
"button",
|
|
2101
|
+
{
|
|
2102
|
+
type: "button",
|
|
2103
|
+
onClick: onClose,
|
|
2104
|
+
disabled: loading,
|
|
2105
|
+
className: "kyro-btn kyro-btn-md kyro-btn-secondary",
|
|
2106
|
+
children: cancelLabel
|
|
2107
|
+
}
|
|
2108
|
+
),
|
|
2109
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2110
|
+
"button",
|
|
2111
|
+
{
|
|
2112
|
+
type: "button",
|
|
2113
|
+
onClick: onConfirm,
|
|
2114
|
+
disabled: loading,
|
|
2115
|
+
className: `kyro-btn kyro-btn-md ${variant === "danger" ? "kyro-btn-danger" : "kyro-btn-primary"}`,
|
|
2116
|
+
children: loading ? "Loading..." : confirmLabel
|
|
2117
|
+
}
|
|
2118
|
+
)
|
|
2119
|
+
] }),
|
|
2120
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[var(--kyro-text-secondary)]", children: message })
|
|
2121
|
+
}
|
|
2122
|
+
);
|
|
2123
|
+
}
|
|
2124
|
+
function PromptModal({
|
|
2125
|
+
open,
|
|
2126
|
+
onClose,
|
|
2127
|
+
onSubmit,
|
|
2128
|
+
title,
|
|
2129
|
+
placeholder = "",
|
|
2130
|
+
defaultValue = ""
|
|
2131
|
+
}) {
|
|
2132
|
+
const [value, setValue] = React56.useState(defaultValue);
|
|
2133
|
+
const handleSubmit = (e) => {
|
|
2134
|
+
e.preventDefault();
|
|
2135
|
+
if (value.trim()) {
|
|
2136
|
+
onSubmit(value.trim());
|
|
2137
|
+
setValue("");
|
|
2138
|
+
onClose();
|
|
2139
|
+
}
|
|
2140
|
+
};
|
|
2141
|
+
if (!open) return null;
|
|
2142
|
+
return reactDom.createPortal(
|
|
2143
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-[9999] flex items-center justify-center", children: [
|
|
2144
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2145
|
+
"div",
|
|
2146
|
+
{
|
|
2147
|
+
className: "absolute inset-0 bg-black/50 backdrop-blur-sm",
|
|
2148
|
+
onClick: onClose
|
|
2149
|
+
}
|
|
2150
|
+
),
|
|
2151
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full max-w-lg mx-4 bg-[var(--kyro-surface)] rounded-lg shadow-2xl animate-in fade-in zoom-in-95 duration-200 border border-[var(--kyro-border)]", children: [
|
|
2152
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-4 border-b border-[var(--kyro-border)]", children: [
|
|
2153
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-[var(--kyro-text-primary)]", children: title }),
|
|
2154
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2155
|
+
"button",
|
|
2156
|
+
{
|
|
2157
|
+
type: "button",
|
|
2158
|
+
onClick: onClose,
|
|
2159
|
+
className: "p-1 text-[var(--kyro-text-muted)] hover:text-[var(--kyro-text-primary)] rounded-lg hover:bg-[var(--kyro-surface-accent)] transition-colors",
|
|
2160
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" })
|
|
2212
2161
|
}
|
|
2213
2162
|
)
|
|
2214
2163
|
] }),
|
|
@@ -2293,35 +2242,35 @@ function MediaGallery({
|
|
|
2293
2242
|
const canUpload = permissions?.media?.create !== false;
|
|
2294
2243
|
const canDelete = permissions?.media?.delete !== false;
|
|
2295
2244
|
const canUpdate = permissions?.media?.update !== false;
|
|
2296
|
-
const [items, setItems] =
|
|
2297
|
-
const [loading, setLoading] =
|
|
2298
|
-
const [folders, setFolders] =
|
|
2299
|
-
const [currentFolder, setCurrentFolder] =
|
|
2300
|
-
const [search, setSearch] =
|
|
2301
|
-
const [filter, setFilter] =
|
|
2302
|
-
const [view, setView] =
|
|
2303
|
-
const [panelItem, setPanelItem] =
|
|
2304
|
-
const [showPreview, setShowPreview] =
|
|
2305
|
-
const [showCrop, setShowCrop] =
|
|
2306
|
-
const [uploading, setUploading] =
|
|
2307
|
-
const [uploadProgress, setUploadProgress] =
|
|
2245
|
+
const [items, setItems] = React56.useState([]);
|
|
2246
|
+
const [loading, setLoading] = React56.useState(true);
|
|
2247
|
+
const [folders, setFolders] = React56.useState([]);
|
|
2248
|
+
const [currentFolder, setCurrentFolder] = React56.useState("");
|
|
2249
|
+
const [search, setSearch] = React56.useState("");
|
|
2250
|
+
const [filter, setFilter] = React56.useState("all");
|
|
2251
|
+
const [view, setView] = React56.useState("grid");
|
|
2252
|
+
const [panelItem, setPanelItem] = React56.useState(null);
|
|
2253
|
+
const [showPreview, setShowPreview] = React56.useState(false);
|
|
2254
|
+
const [showCrop, setShowCrop] = React56.useState(false);
|
|
2255
|
+
const [uploading, setUploading] = React56.useState(false);
|
|
2256
|
+
const [uploadProgress, setUploadProgress] = React56.useState(
|
|
2308
2257
|
{}
|
|
2309
2258
|
);
|
|
2310
|
-
const [showNewFolderModal, setShowNewFolderModal] =
|
|
2311
|
-
const [storageConfigured, setStorageConfigured] =
|
|
2312
|
-
const [storageChecked, setStorageChecked] =
|
|
2313
|
-
const [showStorageConfigModal, setShowStorageConfigModal] =
|
|
2314
|
-
const [page, setPage] =
|
|
2315
|
-
const [total, setTotal] =
|
|
2316
|
-
const [totalPages, setTotalPages] =
|
|
2259
|
+
const [showNewFolderModal, setShowNewFolderModal] = React56.useState(false);
|
|
2260
|
+
const [storageConfigured, setStorageConfigured] = React56.useState(null);
|
|
2261
|
+
const [storageChecked, setStorageChecked] = React56.useState(false);
|
|
2262
|
+
const [showStorageConfigModal, setShowStorageConfigModal] = React56.useState(false);
|
|
2263
|
+
const [page, setPage] = React56.useState(1);
|
|
2264
|
+
const [total, setTotal] = React56.useState(0);
|
|
2265
|
+
const [totalPages, setTotalPages] = React56.useState(1);
|
|
2317
2266
|
const limit = 40;
|
|
2318
|
-
const [selectedIds, setSelectedIds] =
|
|
2267
|
+
const [selectedIds, setSelectedIds] = React56.useState(/* @__PURE__ */ new Set());
|
|
2319
2268
|
const { confirm, alert } = useUIStore();
|
|
2320
|
-
const [isDragging, setIsDragging] =
|
|
2321
|
-
const fileInputRef =
|
|
2322
|
-
const [crop, setCrop] =
|
|
2323
|
-
const imgRef =
|
|
2324
|
-
const loadMedia =
|
|
2269
|
+
const [isDragging, setIsDragging] = React56.useState(false);
|
|
2270
|
+
const fileInputRef = React56.useRef(null);
|
|
2271
|
+
const [crop, setCrop] = React56.useState();
|
|
2272
|
+
const imgRef = React56.useRef(null);
|
|
2273
|
+
const loadMedia = React56.useCallback(async () => {
|
|
2325
2274
|
setLoading(true);
|
|
2326
2275
|
try {
|
|
2327
2276
|
const params = new URLSearchParams({
|
|
@@ -2344,7 +2293,7 @@ function MediaGallery({
|
|
|
2344
2293
|
setLoading(false);
|
|
2345
2294
|
}
|
|
2346
2295
|
}, [page, currentFolder, search, filter]);
|
|
2347
|
-
const loadFolders =
|
|
2296
|
+
const loadFolders = React56.useCallback(async () => {
|
|
2348
2297
|
try {
|
|
2349
2298
|
const result = await apiGet(withCacheBust("/api/media/folders"));
|
|
2350
2299
|
setFolders(Array.isArray(result) ? result : result.folders || []);
|
|
@@ -2352,7 +2301,7 @@ function MediaGallery({
|
|
|
2352
2301
|
console.error("Failed to load folders:", error);
|
|
2353
2302
|
}
|
|
2354
2303
|
}, []);
|
|
2355
|
-
const checkStorage =
|
|
2304
|
+
const checkStorage = React56.useCallback(async () => {
|
|
2356
2305
|
try {
|
|
2357
2306
|
const res = await apiGet("/api/globals/storage-settings");
|
|
2358
2307
|
const isConfigured = !!res?.data?.provider;
|
|
@@ -2361,23 +2310,23 @@ function MediaGallery({
|
|
|
2361
2310
|
setStorageConfigured(false);
|
|
2362
2311
|
}
|
|
2363
2312
|
}, []);
|
|
2364
|
-
|
|
2313
|
+
React56.useEffect(() => {
|
|
2365
2314
|
if (!pickerMode) checkStorage();
|
|
2366
2315
|
}, [checkStorage, pickerMode]);
|
|
2367
|
-
|
|
2316
|
+
React56.useEffect(() => {
|
|
2368
2317
|
if (pickerMode) return;
|
|
2369
2318
|
if (storageConfigured === false && !storageChecked) {
|
|
2370
2319
|
setStorageChecked(true);
|
|
2371
2320
|
setShowStorageConfigModal(true);
|
|
2372
2321
|
}
|
|
2373
2322
|
}, [pickerMode, storageConfigured, storageChecked]);
|
|
2374
|
-
|
|
2323
|
+
React56.useEffect(() => {
|
|
2375
2324
|
loadMedia();
|
|
2376
2325
|
}, [loadMedia]);
|
|
2377
|
-
|
|
2326
|
+
React56.useEffect(() => {
|
|
2378
2327
|
loadFolders();
|
|
2379
2328
|
}, [loadFolders]);
|
|
2380
|
-
|
|
2329
|
+
React56.useEffect(() => {
|
|
2381
2330
|
if (pickerMode) return;
|
|
2382
2331
|
const handlePaste = (e) => {
|
|
2383
2332
|
const files = e.clipboardData?.files;
|
|
@@ -2551,7 +2500,7 @@ function MediaGallery({
|
|
|
2551
2500
|
setUploading(false);
|
|
2552
2501
|
}
|
|
2553
2502
|
};
|
|
2554
|
-
const stats =
|
|
2503
|
+
const stats = React56.useMemo(() => {
|
|
2555
2504
|
return items.reduce(
|
|
2556
2505
|
(acc, item) => {
|
|
2557
2506
|
acc.totalSize += item.fileSize || 0;
|
|
@@ -2588,24 +2537,7 @@ function MediaGallery({
|
|
|
2588
2537
|
] }) }),
|
|
2589
2538
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-3 flex-wrap lg:flex-nowrap ${pickerMode ? "w-full" : ""}`, children: [
|
|
2590
2539
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative group flex-1 min-w-[200px]", children: [
|
|
2591
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2592
|
-
"svg",
|
|
2593
|
-
{
|
|
2594
|
-
className: "absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-[var(--kyro-text-secondary)] opacity-40 group-focus-within:opacity-100 transition-opacity",
|
|
2595
|
-
fill: "none",
|
|
2596
|
-
stroke: "currentColor",
|
|
2597
|
-
viewBox: "0 0 24 24",
|
|
2598
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2599
|
-
"path",
|
|
2600
|
-
{
|
|
2601
|
-
strokeLinecap: "round",
|
|
2602
|
-
strokeLinejoin: "round",
|
|
2603
|
-
strokeWidth: "2.5",
|
|
2604
|
-
d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
|
2605
|
-
}
|
|
2606
|
-
)
|
|
2607
|
-
}
|
|
2608
|
-
),
|
|
2540
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "w-4 h-4" }),
|
|
2609
2541
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2610
2542
|
"input",
|
|
2611
2543
|
{
|
|
@@ -2772,45 +2704,11 @@ function MediaGallery({
|
|
|
2772
2704
|
{
|
|
2773
2705
|
onClick: (e) => handleSelectOne(item.id, e),
|
|
2774
2706
|
className: `kyro-btn-primary p-1.5 rounded-lg transition-all ${selectedIds.has(item.id) ? "" : "bg-white/10 text-white hover:bg-white/20"}`,
|
|
2775
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2776
|
-
"svg",
|
|
2777
|
-
{
|
|
2778
|
-
className: "w-3 h-3",
|
|
2779
|
-
fill: "none",
|
|
2780
|
-
stroke: "currentColor",
|
|
2781
|
-
viewBox: "0 0 24 24",
|
|
2782
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2783
|
-
"path",
|
|
2784
|
-
{
|
|
2785
|
-
strokeLinecap: "round",
|
|
2786
|
-
strokeLinejoin: "round",
|
|
2787
|
-
strokeWidth: "3",
|
|
2788
|
-
d: "M5 13l4 4L19 7"
|
|
2789
|
-
}
|
|
2790
|
-
)
|
|
2791
|
-
}
|
|
2792
|
-
)
|
|
2707
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "w-4 h-4" })
|
|
2793
2708
|
}
|
|
2794
2709
|
) })
|
|
2795
2710
|
] }) }),
|
|
2796
|
-
selectedIds.has(item.id) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-3 left-3 w-6 h-6 rounded-lg bg-[var(--kyro-primary)] text-white flex items-center justify-center shadow-lg border-2 border-white/20 animate-in zoom-in duration-300", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2797
|
-
"svg",
|
|
2798
|
-
{
|
|
2799
|
-
className: "w-3 h-3",
|
|
2800
|
-
fill: "none",
|
|
2801
|
-
stroke: "currentColor",
|
|
2802
|
-
viewBox: "0 0 24 24",
|
|
2803
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2804
|
-
"path",
|
|
2805
|
-
{
|
|
2806
|
-
strokeLinecap: "round",
|
|
2807
|
-
strokeLinejoin: "round",
|
|
2808
|
-
strokeWidth: "3",
|
|
2809
|
-
d: "M5 13l4 4L19 7"
|
|
2810
|
-
}
|
|
2811
|
-
)
|
|
2812
|
-
}
|
|
2813
|
-
) })
|
|
2711
|
+
selectedIds.has(item.id) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-3 left-3 w-6 h-6 rounded-lg bg-[var(--kyro-primary)] text-white flex items-center justify-center shadow-lg border-2 border-white/20 animate-in zoom-in duration-300", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "w-4 h-4" }) })
|
|
2814
2712
|
]
|
|
2815
2713
|
},
|
|
2816
2714
|
item.id
|
|
@@ -2890,34 +2788,14 @@ function MediaGallery({
|
|
|
2890
2788
|
item.id
|
|
2891
2789
|
)) })
|
|
2892
2790
|
] }) }) }),
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2791
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2792
|
+
Pagination,
|
|
2793
|
+
{
|
|
2896
2794
|
page,
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2902
|
-
"button",
|
|
2903
|
-
{
|
|
2904
|
-
disabled: page === 1,
|
|
2905
|
-
onClick: () => setPage(page - 1),
|
|
2906
|
-
className: "px-4 py-2 border border-[var(--kyro-border)] rounded-xl text-xs font-bold text-[var(--kyro-text-secondary)] hover:bg-[var(--kyro-surface-accent)] disabled:opacity-30 transition-all",
|
|
2907
|
-
children: "Previous"
|
|
2908
|
-
}
|
|
2909
|
-
),
|
|
2910
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2911
|
-
"button",
|
|
2912
|
-
{
|
|
2913
|
-
disabled: page === totalPages,
|
|
2914
|
-
onClick: () => setPage(page + 1),
|
|
2915
|
-
className: "px-6 py-2 bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)] rounded-xl text-xs font-bold shadow-lg hover:opacity-90 disabled:opacity-30 transition-all",
|
|
2916
|
-
children: "Next"
|
|
2917
|
-
}
|
|
2918
|
-
)
|
|
2919
|
-
] })
|
|
2920
|
-
] })
|
|
2795
|
+
totalPages,
|
|
2796
|
+
onPageChange: setPage
|
|
2797
|
+
}
|
|
2798
|
+
)
|
|
2921
2799
|
] })
|
|
2922
2800
|
] }),
|
|
2923
2801
|
!pickerMode && uploading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed bottom-12 left-1/2 -translate-x-1/2 z-[60] w-full max-w-lg", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-[var(--kyro-surface)] border border-[var(--kyro-border)] rounded-[2rem] shadow-2xl p-6 ring-1 ring-white/10 animate-in slide-in-from-bottom-12 duration-700", children: [
|
|
@@ -3143,86 +3021,100 @@ function MediaGallery({
|
|
|
3143
3021
|
] })
|
|
3144
3022
|
}
|
|
3145
3023
|
),
|
|
3146
|
-
showPreview && panelItem &&
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
}
|
|
3164
|
-
)
|
|
3165
|
-
] }),
|
|
3166
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 w-full flex items-center justify-center p-12", children: panelItem.type === "image" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3167
|
-
"img",
|
|
3168
|
-
{
|
|
3169
|
-
src: getAbsoluteUrl(panelItem.url),
|
|
3170
|
-
alt: "",
|
|
3171
|
-
className: "max-h-full max-w-full object-contain shadow-2xl rounded-lg animate-in zoom-in-95 duration-500"
|
|
3172
|
-
}
|
|
3173
|
-
) : panelItem.type === "video" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3174
|
-
"video",
|
|
3175
|
-
{
|
|
3176
|
-
src: getAbsoluteUrl(panelItem.url),
|
|
3177
|
-
controls: true,
|
|
3178
|
-
autoPlay: true,
|
|
3179
|
-
className: "max-h-full max-w-full rounded-lg shadow-2xl"
|
|
3180
|
-
}
|
|
3181
|
-
) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-white text-center", children: [
|
|
3182
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.File, { className: "w-24 h-24 mx-auto mb-6 opacity-20" }),
|
|
3183
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xl font-bold opacity-50", children: "Preview not available for this file type" })
|
|
3184
|
-
] }) })
|
|
3185
|
-
] }),
|
|
3186
|
-
document.body
|
|
3187
|
-
),
|
|
3188
|
-
!pickerMode && showCrop && panelItem && reactDom.createPortal(
|
|
3189
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-[9999] bg-black/95 flex flex-col p-8", children: [
|
|
3190
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-8", children: [
|
|
3191
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-white font-bold text-2xl tracking-tighter", children: "Crop Image" }),
|
|
3192
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3", children: [
|
|
3193
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3194
|
-
"button",
|
|
3195
|
-
{
|
|
3196
|
-
type: "button",
|
|
3197
|
-
onClick: () => setShowCrop(false),
|
|
3198
|
-
className: "px-4 py-2 border border-white/20 text-white/80 hover:bg-white/10 rounded-lg font-bold text-sm transition-colors",
|
|
3199
|
-
children: "Cancel"
|
|
3200
|
-
}
|
|
3201
|
-
),
|
|
3024
|
+
showPreview && panelItem && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3025
|
+
Modal,
|
|
3026
|
+
{
|
|
3027
|
+
open: showPreview,
|
|
3028
|
+
onClose: () => setShowPreview(false),
|
|
3029
|
+
title: "",
|
|
3030
|
+
size: "full",
|
|
3031
|
+
variant: "lightbox",
|
|
3032
|
+
children: [
|
|
3033
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between p-6", children: [
|
|
3034
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
3035
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-white font-bold text-lg tracking-tight", children: panelItem.filename }),
|
|
3036
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-white/40 text-[10px] font-bold tracking-widest mt-1", children: [
|
|
3037
|
+
formatFileSize(panelItem.fileSize),
|
|
3038
|
+
" \xB7 ",
|
|
3039
|
+
panelItem.mimeType
|
|
3040
|
+
] })
|
|
3041
|
+
] }),
|
|
3202
3042
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3203
3043
|
"button",
|
|
3204
3044
|
{
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
className: "px-4 py-2 bg-[var(--kyro-sidebar-active)] hover:opacity-90 text-[var(--kyro-sidebar-text-active)] rounded-lg font-bold text-sm transition-colors",
|
|
3209
|
-
children: uploading ? "Saving..." : "Save Crop"
|
|
3045
|
+
onClick: () => setShowPreview(false),
|
|
3046
|
+
className: "p-3 bg-white/10 hover:bg-white/20 text-white rounded-2xl transition-all active:scale-90",
|
|
3047
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-6 h-6" })
|
|
3210
3048
|
}
|
|
3211
3049
|
)
|
|
3212
|
-
] })
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3050
|
+
] }),
|
|
3051
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 w-full flex items-center justify-center p-12", children: panelItem.type === "image" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3052
|
+
"img",
|
|
3053
|
+
{
|
|
3054
|
+
src: getAbsoluteUrl(panelItem.url),
|
|
3055
|
+
alt: "",
|
|
3056
|
+
className: "max-h-full max-w-full object-contain shadow-2xl rounded-lg animate-in zoom-in-95 duration-500"
|
|
3057
|
+
}
|
|
3058
|
+
) : panelItem.type === "video" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3059
|
+
"video",
|
|
3060
|
+
{
|
|
3061
|
+
src: getAbsoluteUrl(panelItem.url),
|
|
3062
|
+
controls: true,
|
|
3063
|
+
autoPlay: true,
|
|
3064
|
+
className: "max-h-full max-w-full rounded-lg shadow-2xl"
|
|
3065
|
+
}
|
|
3066
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-white text-center", children: [
|
|
3067
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.File, { className: "w-24 h-24 mx-auto mb-6 opacity-20" }),
|
|
3068
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xl font-bold opacity-50", children: "Preview not available for this file type" })
|
|
3069
|
+
] }) })
|
|
3070
|
+
]
|
|
3071
|
+
}
|
|
3072
|
+
),
|
|
3073
|
+
!pickerMode && showCrop && panelItem && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3074
|
+
Modal,
|
|
3075
|
+
{
|
|
3076
|
+
open: showCrop,
|
|
3077
|
+
onClose: () => setShowCrop(false),
|
|
3078
|
+
title: "",
|
|
3079
|
+
size: "full",
|
|
3080
|
+
variant: "lightbox",
|
|
3081
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-full p-8", children: [
|
|
3082
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-8", children: [
|
|
3083
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-white font-bold text-2xl tracking-tighter", children: "Crop Image" }),
|
|
3084
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3", children: [
|
|
3085
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3086
|
+
"button",
|
|
3087
|
+
{
|
|
3088
|
+
type: "button",
|
|
3089
|
+
onClick: () => setShowCrop(false),
|
|
3090
|
+
className: "px-4 py-2 border border-white/20 text-white/80 hover:bg-white/10 rounded-lg font-bold text-sm transition-colors",
|
|
3091
|
+
children: "Cancel"
|
|
3092
|
+
}
|
|
3093
|
+
),
|
|
3094
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3095
|
+
"button",
|
|
3096
|
+
{
|
|
3097
|
+
type: "button",
|
|
3098
|
+
disabled: uploading,
|
|
3099
|
+
onClick: onCropComplete,
|
|
3100
|
+
className: "px-4 py-2 bg-[var(--kyro-sidebar-active)] hover:opacity-90 text-[var(--kyro-sidebar-text-active)] rounded-lg font-bold text-sm transition-colors",
|
|
3101
|
+
children: uploading ? "Saving..." : "Save Crop"
|
|
3102
|
+
}
|
|
3103
|
+
)
|
|
3104
|
+
] })
|
|
3105
|
+
] }),
|
|
3106
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 w-full flex items-center justify-center overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsx(ReactCrop__default.default, { crop, onChange: (c) => setCrop(c), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3107
|
+
"img",
|
|
3108
|
+
{
|
|
3109
|
+
ref: imgRef,
|
|
3110
|
+
src: panelItem.url,
|
|
3111
|
+
alt: "Crop preview",
|
|
3112
|
+
className: "max-h-[70vh] object-contain",
|
|
3113
|
+
onLoad: onImageLoad
|
|
3114
|
+
}
|
|
3115
|
+
) }) })
|
|
3116
|
+
] })
|
|
3117
|
+
}
|
|
3226
3118
|
),
|
|
3227
3119
|
!pickerMode && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3228
3120
|
PromptModal,
|
|
@@ -3234,61 +3126,49 @@ function MediaGallery({
|
|
|
3234
3126
|
placeholder: "Folder name"
|
|
3235
3127
|
}
|
|
3236
3128
|
),
|
|
3237
|
-
!pickerMode &&
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3129
|
+
!pickerMode && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3130
|
+
Modal,
|
|
3131
|
+
{
|
|
3132
|
+
open: showStorageConfigModal,
|
|
3133
|
+
onClose: () => setShowStorageConfigModal(false),
|
|
3134
|
+
title: "Storage Not Configured",
|
|
3135
|
+
size: "md",
|
|
3136
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
3137
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 h-16 mx-auto mb-4 rounded-full bg-[var(--kyro-sidebar-active)] flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Server, { className: "w-8 h-8 text-[var(--kyro-sidebar-text-active)]" }) }),
|
|
3138
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[var(--kyro-text-secondary)] mb-6 text-sm", children: "Before uploading media, you need to configure your storage settings. Choose where files should be stored and how URLs are generated." }),
|
|
3139
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3", children: [
|
|
3140
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3141
|
+
"a",
|
|
3142
|
+
{
|
|
3143
|
+
href: "/settings/storage-settings",
|
|
3144
|
+
className: "flex-1 px-4 py-3 bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)] rounded-xl font-bold text-center hover:opacity-90 transition-colors",
|
|
3145
|
+
children: "Configure Storage"
|
|
3146
|
+
}
|
|
3147
|
+
),
|
|
3148
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3149
|
+
"button",
|
|
3248
3150
|
{
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3151
|
+
type: "button",
|
|
3152
|
+
onClick: () => {
|
|
3153
|
+
apiPost("/api/globals/storage-settings", {
|
|
3154
|
+
provider: "local",
|
|
3155
|
+
local: {
|
|
3156
|
+
uploadDir: "./public/uploads",
|
|
3157
|
+
baseUrl: "/uploads"
|
|
3158
|
+
}
|
|
3159
|
+
}).then(() => {
|
|
3160
|
+
setShowStorageConfigModal(false);
|
|
3161
|
+
setStorageConfigured(true);
|
|
3162
|
+
window.location.reload();
|
|
3163
|
+
});
|
|
3164
|
+
},
|
|
3165
|
+
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",
|
|
3166
|
+
children: "Use Defaults"
|
|
3253
3167
|
}
|
|
3254
3168
|
)
|
|
3255
|
-
}
|
|
3256
|
-
) }),
|
|
3257
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xl font-bold text-[var(--kyro-text-primary)] mb-2", children: "Storage Not Configured" }),
|
|
3258
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[var(--kyro-text-secondary)] mb-6 text-sm", children: "Before uploading media, you need to configure your storage settings. Choose where files should be stored and how URLs are generated." }),
|
|
3259
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3", children: [
|
|
3260
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3261
|
-
"a",
|
|
3262
|
-
{
|
|
3263
|
-
href: "/settings/storage-settings",
|
|
3264
|
-
className: "flex-1 px-4 py-3 bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)] rounded-xl font-bold text-center hover:opacity-90 transition-colors",
|
|
3265
|
-
children: "Configure Storage"
|
|
3266
|
-
}
|
|
3267
|
-
),
|
|
3268
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3269
|
-
"button",
|
|
3270
|
-
{
|
|
3271
|
-
type: "button",
|
|
3272
|
-
onClick: () => {
|
|
3273
|
-
apiPost("/api/globals/storage-settings", {
|
|
3274
|
-
provider: "local",
|
|
3275
|
-
local: {
|
|
3276
|
-
uploadDir: "./public/uploads",
|
|
3277
|
-
baseUrl: "/uploads"
|
|
3278
|
-
}
|
|
3279
|
-
}).then(() => {
|
|
3280
|
-
setShowStorageConfigModal(false);
|
|
3281
|
-
setStorageConfigured(true);
|
|
3282
|
-
window.location.reload();
|
|
3283
|
-
});
|
|
3284
|
-
},
|
|
3285
|
-
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",
|
|
3286
|
-
children: "Use Defaults"
|
|
3287
|
-
}
|
|
3288
|
-
)
|
|
3169
|
+
] })
|
|
3289
3170
|
] })
|
|
3290
|
-
|
|
3291
|
-
document.body
|
|
3171
|
+
}
|
|
3292
3172
|
),
|
|
3293
3173
|
!pickerMode && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3294
3174
|
"input",
|
|
@@ -3325,9 +3205,9 @@ var MenuBar = ({
|
|
|
3325
3205
|
setIsExpanded,
|
|
3326
3206
|
onOpenMediaPicker
|
|
3327
3207
|
}) => {
|
|
3328
|
-
const [activeDropdown, setActiveDropdown] =
|
|
3329
|
-
const menuBarRef =
|
|
3330
|
-
|
|
3208
|
+
const [activeDropdown, setActiveDropdown] = React56.useState(null);
|
|
3209
|
+
const menuBarRef = React56.useRef(null);
|
|
3210
|
+
React56.useEffect(() => {
|
|
3331
3211
|
function handleClickOutside(event) {
|
|
3332
3212
|
if (menuBarRef.current && !menuBarRef.current.contains(event.target)) {
|
|
3333
3213
|
setActiveDropdown(null);
|
|
@@ -3787,14 +3667,14 @@ function RichTextField({
|
|
|
3787
3667
|
error,
|
|
3788
3668
|
disabled
|
|
3789
3669
|
}) {
|
|
3790
|
-
const [isExpanded, setIsExpanded] =
|
|
3791
|
-
const [panelWidth, setPanelWidth] =
|
|
3792
|
-
const [isMediaPickerOpen, setIsMediaPickerOpen] =
|
|
3793
|
-
const [isMounted, setIsMounted] =
|
|
3794
|
-
|
|
3670
|
+
const [isExpanded, setIsExpanded] = React56.useState(false);
|
|
3671
|
+
const [panelWidth, setPanelWidth] = React56.useState(0);
|
|
3672
|
+
const [isMediaPickerOpen, setIsMediaPickerOpen] = React56.useState(false);
|
|
3673
|
+
const [isMounted, setIsMounted] = React56.useState(false);
|
|
3674
|
+
React56.useEffect(() => {
|
|
3795
3675
|
setIsMounted(true);
|
|
3796
3676
|
}, []);
|
|
3797
|
-
|
|
3677
|
+
React56.useEffect(() => {
|
|
3798
3678
|
if (!isExpanded) {
|
|
3799
3679
|
setPanelWidth(0);
|
|
3800
3680
|
return;
|
|
@@ -3860,7 +3740,7 @@ function RichTextField({
|
|
|
3860
3740
|
}
|
|
3861
3741
|
}
|
|
3862
3742
|
});
|
|
3863
|
-
|
|
3743
|
+
React56.useEffect(() => {
|
|
3864
3744
|
if (editor && value && JSON.stringify(value) !== JSON.stringify(editor.getJSON())) {
|
|
3865
3745
|
editor.commands.setContent(value);
|
|
3866
3746
|
}
|
|
@@ -4129,9 +4009,9 @@ function mergeThemes(base, overrides) {
|
|
|
4129
4009
|
fields: base.fields ? { ...base.fields, ...overrides.fields } : overrides.fields
|
|
4130
4010
|
};
|
|
4131
4011
|
}
|
|
4132
|
-
var ThemeContext =
|
|
4012
|
+
var ThemeContext = React56.createContext(null);
|
|
4133
4013
|
function useTheme() {
|
|
4134
|
-
const context =
|
|
4014
|
+
const context = React56.useContext(ThemeContext);
|
|
4135
4015
|
if (!context) {
|
|
4136
4016
|
return {
|
|
4137
4017
|
mode: "light",
|
|
@@ -4242,16 +4122,16 @@ function ThemeProvider({
|
|
|
4242
4122
|
light: lightOverrides,
|
|
4243
4123
|
dark: darkOverrides
|
|
4244
4124
|
}) {
|
|
4245
|
-
const [mode, setMode] =
|
|
4246
|
-
const [baseLight, setBaseLight] =
|
|
4125
|
+
const [mode, setMode] = React56.useState(defaultMode);
|
|
4126
|
+
const [baseLight, setBaseLight] = React56.useState(
|
|
4247
4127
|
lightOverrides || {}
|
|
4248
4128
|
);
|
|
4249
|
-
const [baseDark, setBaseDark] =
|
|
4129
|
+
const [baseDark, setBaseDark] = React56.useState(
|
|
4250
4130
|
darkOverrides || {}
|
|
4251
4131
|
);
|
|
4252
4132
|
const lightTheme = mergeThemes(LIGHT_THEME, baseLight);
|
|
4253
4133
|
const darkTheme = mergeThemes(DARK_THEME, baseDark);
|
|
4254
|
-
const getResolvedTheme =
|
|
4134
|
+
const getResolvedTheme = React56.useCallback(() => {
|
|
4255
4135
|
if (mode === "system") {
|
|
4256
4136
|
if (typeof window !== "undefined") {
|
|
4257
4137
|
return window.matchMedia("(prefers-color-scheme: dark)").matches ? darkTheme : lightTheme;
|
|
@@ -4260,13 +4140,13 @@ function ThemeProvider({
|
|
|
4260
4140
|
}
|
|
4261
4141
|
return mode === "dark" ? darkTheme : lightTheme;
|
|
4262
4142
|
}, [mode, lightTheme, darkTheme]);
|
|
4263
|
-
const [theme, setTheme] =
|
|
4264
|
-
|
|
4143
|
+
const [theme, setTheme] = React56.useState(getResolvedTheme());
|
|
4144
|
+
React56.useEffect(() => {
|
|
4265
4145
|
const resolved = getResolvedTheme();
|
|
4266
4146
|
setTheme(resolved);
|
|
4267
4147
|
applyThemeToDOM(resolved);
|
|
4268
4148
|
}, [getResolvedTheme]);
|
|
4269
|
-
|
|
4149
|
+
React56.useEffect(() => {
|
|
4270
4150
|
if (mode !== "system") return;
|
|
4271
4151
|
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
4272
4152
|
const handler = () => {
|
|
@@ -4277,11 +4157,11 @@ function ThemeProvider({
|
|
|
4277
4157
|
mediaQuery.addEventListener("change", handler);
|
|
4278
4158
|
return () => mediaQuery.removeEventListener("change", handler);
|
|
4279
4159
|
}, [mode, getResolvedTheme]);
|
|
4280
|
-
const updateTheme =
|
|
4160
|
+
const updateTheme = React56.useCallback((overrides) => {
|
|
4281
4161
|
setBaseLight((prev) => ({ ...prev, ...overrides }));
|
|
4282
4162
|
setBaseDark((prev) => ({ ...prev, ...overrides }));
|
|
4283
4163
|
}, []);
|
|
4284
|
-
const getCssVar =
|
|
4164
|
+
const getCssVar = React56.useCallback((key) => `var(--kyro-${key})`, []);
|
|
4285
4165
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4286
4166
|
ThemeContext.Provider,
|
|
4287
4167
|
{
|
|
@@ -4300,7 +4180,7 @@ function ThemeProvider({
|
|
|
4300
4180
|
}
|
|
4301
4181
|
var LightThemeProvider = (props) => /* @__PURE__ */ jsxRuntime.jsx(ThemeProvider, { defaultMode: "light", ...props });
|
|
4302
4182
|
var DarkThemeProvider = (props) => /* @__PURE__ */ jsxRuntime.jsx(ThemeProvider, { defaultMode: "dark", ...props });
|
|
4303
|
-
var CodeMirrorEditor =
|
|
4183
|
+
var CodeMirrorEditor = React56.lazy(
|
|
4304
4184
|
() => import('@uiw/react-codemirror').then((mod) => ({ default: mod.default }))
|
|
4305
4185
|
);
|
|
4306
4186
|
var LANGUAGES = [
|
|
@@ -4352,16 +4232,16 @@ var CodeField = ({
|
|
|
4352
4232
|
error,
|
|
4353
4233
|
disabled
|
|
4354
4234
|
}) => {
|
|
4355
|
-
const [isMounted, setIsMounted] =
|
|
4356
|
-
const [isDark, setIsDark] =
|
|
4357
|
-
const [extensions, setExtensions] =
|
|
4358
|
-
const [loading, setLoading] =
|
|
4359
|
-
const [copied, setCopied] =
|
|
4360
|
-
const [isFullScreen, setIsFullScreen] =
|
|
4235
|
+
const [isMounted, setIsMounted] = React56.useState(false);
|
|
4236
|
+
const [isDark, setIsDark] = React56.useState(false);
|
|
4237
|
+
const [extensions, setExtensions] = React56.useState([]);
|
|
4238
|
+
const [loading, setLoading] = React56.useState(false);
|
|
4239
|
+
const [copied, setCopied] = React56.useState(false);
|
|
4240
|
+
const [isFullScreen, setIsFullScreen] = React56.useState(false);
|
|
4361
4241
|
const { theme } = useTheme();
|
|
4362
4242
|
const accent = theme.colors?.accent || theme.colors?.primary || "#6366f1";
|
|
4363
4243
|
const language = field3.language?.toLowerCase() || "javascript";
|
|
4364
|
-
|
|
4244
|
+
React56.useEffect(() => {
|
|
4365
4245
|
setIsMounted(true);
|
|
4366
4246
|
setIsDark(document.documentElement.classList.contains("dark"));
|
|
4367
4247
|
const observer = new MutationObserver(() => {
|
|
@@ -4373,7 +4253,7 @@ var CodeField = ({
|
|
|
4373
4253
|
});
|
|
4374
4254
|
return () => observer.disconnect();
|
|
4375
4255
|
}, []);
|
|
4376
|
-
|
|
4256
|
+
React56.useEffect(() => {
|
|
4377
4257
|
if (!isMounted) return;
|
|
4378
4258
|
const loadExtensions = async () => {
|
|
4379
4259
|
setLoading(true);
|
|
@@ -4390,16 +4270,16 @@ var CodeField = ({
|
|
|
4390
4270
|
};
|
|
4391
4271
|
loadExtensions();
|
|
4392
4272
|
}, [language, isMounted]);
|
|
4393
|
-
const handleChange =
|
|
4273
|
+
const handleChange = React56.useCallback(
|
|
4394
4274
|
(val) => onChange?.(val),
|
|
4395
4275
|
[onChange]
|
|
4396
4276
|
);
|
|
4397
|
-
const handleCopy =
|
|
4277
|
+
const handleCopy = React56.useCallback(() => {
|
|
4398
4278
|
navigator.clipboard.writeText(value);
|
|
4399
4279
|
setCopied(true);
|
|
4400
4280
|
setTimeout(() => setCopied(false), 1500);
|
|
4401
4281
|
}, [value]);
|
|
4402
|
-
const toggleFullScreen =
|
|
4282
|
+
const toggleFullScreen = React56.useCallback(() => {
|
|
4403
4283
|
setIsFullScreen((prev) => !prev);
|
|
4404
4284
|
document.body.style.overflow = !isFullScreen ? "hidden" : "";
|
|
4405
4285
|
}, [isFullScreen]);
|
|
@@ -4489,7 +4369,7 @@ var CodeField = ({
|
|
|
4489
4369
|
}
|
|
4490
4370
|
),
|
|
4491
4371
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4492
|
-
|
|
4372
|
+
React56.Suspense,
|
|
4493
4373
|
{
|
|
4494
4374
|
fallback: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4495
4375
|
"div",
|
|
@@ -4609,18 +4489,18 @@ var MarkdownField = ({
|
|
|
4609
4489
|
error,
|
|
4610
4490
|
disabled
|
|
4611
4491
|
}) => {
|
|
4612
|
-
const [showPreview, setShowPreview] =
|
|
4613
|
-
const [isMounted, setIsMounted] =
|
|
4614
|
-
|
|
4492
|
+
const [showPreview, setShowPreview] = React56.useState(false);
|
|
4493
|
+
const [isMounted, setIsMounted] = React56.useState(false);
|
|
4494
|
+
React56.useEffect(() => {
|
|
4615
4495
|
setIsMounted(true);
|
|
4616
4496
|
}, []);
|
|
4617
|
-
const handleChange =
|
|
4497
|
+
const handleChange = React56.useCallback(
|
|
4618
4498
|
(e) => {
|
|
4619
4499
|
onChange?.(e.target.value);
|
|
4620
4500
|
},
|
|
4621
4501
|
[onChange]
|
|
4622
4502
|
);
|
|
4623
|
-
const wordCount =
|
|
4503
|
+
const wordCount = React56.useMemo(() => {
|
|
4624
4504
|
if (!value) return 0;
|
|
4625
4505
|
return value.trim().split(/\s+/).filter(Boolean).length;
|
|
4626
4506
|
}, [value]);
|
|
@@ -4725,8 +4605,8 @@ function SecretField({
|
|
|
4725
4605
|
error,
|
|
4726
4606
|
disabled
|
|
4727
4607
|
}) {
|
|
4728
|
-
const [copied, setCopied] =
|
|
4729
|
-
const [regenerating, setRegenerating] =
|
|
4608
|
+
const [copied, setCopied] = React56.useState(false);
|
|
4609
|
+
const [regenerating, setRegenerating] = React56.useState(false);
|
|
4730
4610
|
const fullValue = value ?? "";
|
|
4731
4611
|
const displayValue = fullValue.length > 8 ? fullValue.slice(0, -8) + "*".repeat(8) : fullValue;
|
|
4732
4612
|
const handleCopy = async () => {
|
|
@@ -4882,6 +4762,7 @@ var useAutoFormStore = zustand.create()(
|
|
|
4882
4762
|
loadingDiffs: false,
|
|
4883
4763
|
isAutoSaving: false,
|
|
4884
4764
|
autoSaveStatus: "idle",
|
|
4765
|
+
backgroundProcessing: false,
|
|
4885
4766
|
// Auto-save state
|
|
4886
4767
|
lastAutoSaveTime: 0,
|
|
4887
4768
|
lastSavedAt: null,
|
|
@@ -4957,6 +4838,7 @@ var useAutoFormStore = zustand.create()(
|
|
|
4957
4838
|
setLoadingDiffs: (loading) => set({ loadingDiffs: loading }),
|
|
4958
4839
|
setIsAutoSaving: (saving) => set({ isAutoSaving: saving }),
|
|
4959
4840
|
setAutoSaveStatus: (status) => set({ autoSaveStatus: status }),
|
|
4841
|
+
setBackgroundProcessing: (processing) => set({ backgroundProcessing: processing }),
|
|
4960
4842
|
setSidebarCollapsed: (collapsed) => set({ sidebarCollapsed: collapsed }),
|
|
4961
4843
|
setLastSavedAt: (time) => set({ lastSavedAt: time }),
|
|
4962
4844
|
setRetryCount: (count) => set({ retryCount: count }),
|
|
@@ -5453,6 +5335,14 @@ function SelectField({
|
|
|
5453
5335
|
}
|
|
5454
5336
|
);
|
|
5455
5337
|
}
|
|
5338
|
+
function EmptyState({ icon, title, description, action }) {
|
|
5339
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-3 justify-center py-16 px-8", children: [
|
|
5340
|
+
icon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 h-16 rounded-2xl bg-[var(--kyro-surface-accent)] flex items-center justify-center mb-4", children: icon }),
|
|
5341
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium text-[var(--kyro-text-primary)] text-base", children: title }),
|
|
5342
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-[var(--kyro-text-secondary)] mt-1", children: description }),
|
|
5343
|
+
action
|
|
5344
|
+
] });
|
|
5345
|
+
}
|
|
5456
5346
|
function getLabel(opt) {
|
|
5457
5347
|
const mainTabs = opt?.mainTabs;
|
|
5458
5348
|
return opt?.title || mainTabs?.title || opt?.name || opt?.label || opt?.email || opt?.filename || opt?.slug || "Untitled";
|
|
@@ -5464,22 +5354,22 @@ function RelationshipField({
|
|
|
5464
5354
|
error,
|
|
5465
5355
|
disabled
|
|
5466
5356
|
}) {
|
|
5467
|
-
const [isOpen, setIsOpen] =
|
|
5468
|
-
const [search, setSearch] =
|
|
5469
|
-
const [options, setOptions] =
|
|
5470
|
-
const [loading, setLoading] =
|
|
5471
|
-
const [selectedDocs, setSelectedDocs] =
|
|
5472
|
-
const fetchedIdsRef =
|
|
5473
|
-
const containerRef =
|
|
5474
|
-
const onChangeRef =
|
|
5357
|
+
const [isOpen, setIsOpen] = React56.useState(false);
|
|
5358
|
+
const [search, setSearch] = React56.useState("");
|
|
5359
|
+
const [options, setOptions] = React56.useState([]);
|
|
5360
|
+
const [loading, setLoading] = React56.useState(false);
|
|
5361
|
+
const [selectedDocs, setSelectedDocs] = React56.useState([]);
|
|
5362
|
+
const fetchedIdsRef = React56.useRef(/* @__PURE__ */ new Set());
|
|
5363
|
+
const containerRef = React56.useRef(null);
|
|
5364
|
+
const onChangeRef = React56.useRef(() => {
|
|
5475
5365
|
});
|
|
5476
5366
|
onChangeRef.current = onChange || (() => {
|
|
5477
5367
|
});
|
|
5478
5368
|
const isMultiple = field3.hasMany;
|
|
5479
5369
|
const relationTo = Array.isArray(field3.relationTo) ? field3.relationTo : [field3.relationTo];
|
|
5480
5370
|
const isPolymorphic = relationTo.length > 1;
|
|
5481
|
-
const [activeRelation, setActiveRelation] =
|
|
5482
|
-
const extractIds =
|
|
5371
|
+
const [activeRelation, setActiveRelation] = React56.useState(relationTo[0]);
|
|
5372
|
+
const extractIds = React56.useCallback(() => {
|
|
5483
5373
|
if (!value) return [];
|
|
5484
5374
|
const items = isMultiple ? Array.isArray(value) ? value : [] : value ? [value] : [];
|
|
5485
5375
|
return items.map((item) => {
|
|
@@ -5489,7 +5379,7 @@ function RelationshipField({
|
|
|
5489
5379
|
return String(item);
|
|
5490
5380
|
}).filter(Boolean);
|
|
5491
5381
|
}, [value, isMultiple]);
|
|
5492
|
-
const fetchSelectedDocs =
|
|
5382
|
+
const fetchSelectedDocs = React56.useCallback((ids) => {
|
|
5493
5383
|
if (ids.length === 0) return;
|
|
5494
5384
|
ids.forEach((id) => {
|
|
5495
5385
|
if (fetchedIdsRef.current.has(id)) return;
|
|
@@ -5516,11 +5406,11 @@ function RelationshipField({
|
|
|
5516
5406
|
});
|
|
5517
5407
|
});
|
|
5518
5408
|
}, [isPolymorphic, value, activeRelation, isMultiple]);
|
|
5519
|
-
|
|
5409
|
+
React56.useEffect(() => {
|
|
5520
5410
|
const ids = extractIds();
|
|
5521
5411
|
fetchSelectedDocs(ids);
|
|
5522
5412
|
}, [extractIds, fetchSelectedDocs]);
|
|
5523
|
-
const fetchOptions =
|
|
5413
|
+
const fetchOptions = React56.useCallback((query = "") => {
|
|
5524
5414
|
setLoading(true);
|
|
5525
5415
|
const searchFields = ["title", "name", "label", "email"];
|
|
5526
5416
|
const url = `/api/${activeRelation}?${buildSearchQuery(query, searchFields)}`;
|
|
@@ -5537,13 +5427,13 @@ function RelationshipField({
|
|
|
5537
5427
|
setLoading(false);
|
|
5538
5428
|
});
|
|
5539
5429
|
}, [activeRelation]);
|
|
5540
|
-
|
|
5430
|
+
React56.useEffect(() => {
|
|
5541
5431
|
if (isOpen) {
|
|
5542
5432
|
setOptions([]);
|
|
5543
5433
|
fetchOptions(search);
|
|
5544
5434
|
}
|
|
5545
5435
|
}, [isOpen, activeRelation]);
|
|
5546
|
-
|
|
5436
|
+
React56.useEffect(() => {
|
|
5547
5437
|
const handleClickOutside = (event) => {
|
|
5548
5438
|
if (containerRef.current && !containerRef.current.contains(event.target)) {
|
|
5549
5439
|
setIsOpen(false);
|
|
@@ -5668,7 +5558,7 @@ function RelationshipField({
|
|
|
5668
5558
|
}
|
|
5669
5559
|
) })
|
|
5670
5560
|
] }),
|
|
5671
|
-
isOpen && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative z-20 w-full mt-1 border border-[var(--kyro-border)] rounded-lg shadow-lg bg-[var(--kyro-surface)] max-h-64 overflow-auto", children: loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 text-center text-sm text-[var(--kyro-text-muted)]", children: "Loading..." }) : options.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
5561
|
+
isOpen && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative z-20 w-full mt-1 border border-[var(--kyro-border)] rounded-lg shadow-lg bg-[var(--kyro-surface)] max-h-64 overflow-auto", children: loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 text-center text-sm text-[var(--kyro-text-muted)]", children: "Loading..." }) : options.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { title: "No results found" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-1", children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5672
5562
|
"button",
|
|
5673
5563
|
{
|
|
5674
5564
|
type: "button",
|
|
@@ -5691,7 +5581,7 @@ function RelationshipField({
|
|
|
5691
5581
|
] });
|
|
5692
5582
|
}
|
|
5693
5583
|
var RelationshipField_default = RelationshipField;
|
|
5694
|
-
var BlocksContext =
|
|
5584
|
+
var BlocksContext = React56.createContext(null);
|
|
5695
5585
|
function createBlocksStore(allowedBlocks = [], dynamicCategories = []) {
|
|
5696
5586
|
return vanilla.createStore((set, get) => ({
|
|
5697
5587
|
blocks: [],
|
|
@@ -5846,7 +5736,7 @@ function getDefaultData(type) {
|
|
|
5846
5736
|
return defaults[type] || {};
|
|
5847
5737
|
}
|
|
5848
5738
|
function useBlockById(id) {
|
|
5849
|
-
const store =
|
|
5739
|
+
const store = React56.useContext(BlocksContext);
|
|
5850
5740
|
if (!store) return void 0;
|
|
5851
5741
|
return zustand.useStore(store, (state) => {
|
|
5852
5742
|
const findRecursive = (blocksList) => {
|
|
@@ -5871,7 +5761,7 @@ function useBlockById(id) {
|
|
|
5871
5761
|
});
|
|
5872
5762
|
}
|
|
5873
5763
|
function useBlockActions() {
|
|
5874
|
-
const store =
|
|
5764
|
+
const store = React56.useContext(BlocksContext);
|
|
5875
5765
|
if (!store) {
|
|
5876
5766
|
throw new Error("useBlockActions must be used within a BlocksContext.Provider");
|
|
5877
5767
|
}
|
|
@@ -6255,7 +6145,7 @@ var ListField = ({
|
|
|
6255
6145
|
onChange,
|
|
6256
6146
|
compact = false
|
|
6257
6147
|
}) => {
|
|
6258
|
-
const [inputValue, setInputValue] =
|
|
6148
|
+
const [inputValue, setInputValue] = React56__default.default.useState("");
|
|
6259
6149
|
const handleAdd = () => {
|
|
6260
6150
|
if (inputValue.trim()) {
|
|
6261
6151
|
onChange([...items, inputValue.trim()]);
|
|
@@ -6511,7 +6401,7 @@ var AccordionField = ({
|
|
|
6511
6401
|
onChange,
|
|
6512
6402
|
compact = false
|
|
6513
6403
|
}) => {
|
|
6514
|
-
const [openIndex, setOpenIndex] =
|
|
6404
|
+
const [openIndex, setOpenIndex] = React56__default.default.useState(0);
|
|
6515
6405
|
const handleTitleChange = (index, value) => {
|
|
6516
6406
|
const newItems = [...items];
|
|
6517
6407
|
newItems[index] = { ...newItems[index], title: value };
|
|
@@ -6937,7 +6827,7 @@ function ArrayLayout({
|
|
|
6937
6827
|
const firstField = fields2[0];
|
|
6938
6828
|
const labelField = firstField?.name || "user";
|
|
6939
6829
|
const isRelationship = firstField?.type === "relationship";
|
|
6940
|
-
const [openIndex, setOpenIndex] =
|
|
6830
|
+
const [openIndex, setOpenIndex] = React56__default.default.useState(0);
|
|
6941
6831
|
function getItemLabel(item) {
|
|
6942
6832
|
for (const key of ["label", "title", "name"]) {
|
|
6943
6833
|
const val = item[key];
|
|
@@ -7292,7 +7182,7 @@ var FieldRenderer = ({
|
|
|
7292
7182
|
{
|
|
7293
7183
|
field: field3,
|
|
7294
7184
|
value,
|
|
7295
|
-
onChange,
|
|
7185
|
+
onChange: onChangeKeystroke,
|
|
7296
7186
|
disabled,
|
|
7297
7187
|
error
|
|
7298
7188
|
}
|
|
@@ -7477,11 +7367,11 @@ var ChildBlocksTree = ({
|
|
|
7477
7367
|
depth = 0,
|
|
7478
7368
|
maxDepth = MAX_DEPTH
|
|
7479
7369
|
}) => {
|
|
7480
|
-
const [showAddModal, setShowAddModal] =
|
|
7481
|
-
const [expandedIds, setExpandedIds] =
|
|
7482
|
-
const [editingBlockId, setEditingBlockId] =
|
|
7483
|
-
const [confirmDeleteId, setConfirmDeleteId] =
|
|
7484
|
-
const store =
|
|
7370
|
+
const [showAddModal, setShowAddModal] = React56.useState(false);
|
|
7371
|
+
const [expandedIds, setExpandedIds] = React56.useState(/* @__PURE__ */ new Set());
|
|
7372
|
+
const [editingBlockId, setEditingBlockId] = React56.useState(null);
|
|
7373
|
+
const [confirmDeleteId, setConfirmDeleteId] = React56.useState(null);
|
|
7374
|
+
const store = React56.useContext(BlocksContext);
|
|
7485
7375
|
if (!store) throw new Error("ChildBlocksTree must be used within a BlocksContext");
|
|
7486
7376
|
const dynamicCategories = zustand.useStore(store, (s) => s.dynamicCategories);
|
|
7487
7377
|
const allowedBlocks = zustand.useStore(store, (s) => s.allowedBlocks);
|
|
@@ -7698,11 +7588,11 @@ var NestedChildBlocks = ({
|
|
|
7698
7588
|
depth,
|
|
7699
7589
|
maxDepth
|
|
7700
7590
|
}) => {
|
|
7701
|
-
const [showAddModal, setShowAddModal] =
|
|
7702
|
-
const [expandedIds, setExpandedIds] =
|
|
7703
|
-
const [editingBlockId, setEditingBlockId] =
|
|
7704
|
-
const [confirmDeleteId, setConfirmDeleteId] =
|
|
7705
|
-
const store =
|
|
7591
|
+
const [showAddModal, setShowAddModal] = React56.useState(false);
|
|
7592
|
+
const [expandedIds, setExpandedIds] = React56.useState(/* @__PURE__ */ new Set());
|
|
7593
|
+
const [editingBlockId, setEditingBlockId] = React56.useState(null);
|
|
7594
|
+
const [confirmDeleteId, setConfirmDeleteId] = React56.useState(null);
|
|
7595
|
+
const store = React56.useContext(BlocksContext);
|
|
7706
7596
|
if (!store) throw new Error("NestedChildBlocks must be used within a BlocksContext");
|
|
7707
7597
|
const dynamicCategories = zustand.useStore(store, (s) => s.dynamicCategories);
|
|
7708
7598
|
const allowedBlocks = zustand.useStore(store, (s) => s.allowedBlocks);
|
|
@@ -8206,13 +8096,13 @@ var RelationshipBlockField = ({
|
|
|
8206
8096
|
onChange,
|
|
8207
8097
|
compact = false
|
|
8208
8098
|
}) => {
|
|
8209
|
-
const [isOpen, setIsOpen] =
|
|
8210
|
-
const [search, setSearch] =
|
|
8211
|
-
const [options, setOptions] =
|
|
8212
|
-
const [loading, setLoading] =
|
|
8213
|
-
const [collections2, setCollections] =
|
|
8214
|
-
const [loadingCollections, setLoadingCollections] =
|
|
8215
|
-
|
|
8099
|
+
const [isOpen, setIsOpen] = React56.useState(false);
|
|
8100
|
+
const [search, setSearch] = React56.useState("");
|
|
8101
|
+
const [options, setOptions] = React56.useState([]);
|
|
8102
|
+
const [loading, setLoading] = React56.useState(false);
|
|
8103
|
+
const [collections2, setCollections] = React56.useState([]);
|
|
8104
|
+
const [loadingCollections, setLoadingCollections] = React56.useState(true);
|
|
8105
|
+
React56.useEffect(() => {
|
|
8216
8106
|
apiGet("/api/collections").then((data) => {
|
|
8217
8107
|
setCollections(
|
|
8218
8108
|
(data.collections || []).map((c) => c.slug || c.name || c)
|
|
@@ -8228,7 +8118,7 @@ var RelationshipBlockField = ({
|
|
|
8228
8118
|
setLoading(false);
|
|
8229
8119
|
}).catch(() => setLoading(false));
|
|
8230
8120
|
};
|
|
8231
|
-
|
|
8121
|
+
React56.useEffect(() => {
|
|
8232
8122
|
if (isOpen) fetchOptions(search);
|
|
8233
8123
|
}, [isOpen, search, relationTo, labelField]);
|
|
8234
8124
|
const getLabel2 = (opt) => {
|
|
@@ -8302,7 +8192,7 @@ var RelationshipBlockField = ({
|
|
|
8302
8192
|
),
|
|
8303
8193
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-3 top-1/2 -translate-y-1/2", children: loading && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LoaderCircle, { className: "w-4 h-4 text-[var(--kyro-text-muted)] animate-spin" }) })
|
|
8304
8194
|
] }),
|
|
8305
|
-
isOpen && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute z-20 w-full mt-1 border border-[var(--kyro-border)] rounded-lg shadow-lg bg-[var(--kyro-surface)] max-h-48 overflow-auto", children: loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3 text-center text-sm text-[var(--kyro-text-muted)]", children: "Loading..." }) : options.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8195
|
+
isOpen && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute z-20 w-full mt-1 border border-[var(--kyro-border)] rounded-lg shadow-lg bg-[var(--kyro-surface)] max-h-48 overflow-auto", children: loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3 text-center text-sm text-[var(--kyro-text-muted)]", children: "Loading..." }) : options.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { title: "No results found" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-1", children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8306
8196
|
"button",
|
|
8307
8197
|
{
|
|
8308
8198
|
type: "button",
|
|
@@ -8558,7 +8448,7 @@ var SortableBlockComponent = ({
|
|
|
8558
8448
|
} = sortable.useSortable({ id: block3.id });
|
|
8559
8449
|
const { removeBlock } = useBlockActions();
|
|
8560
8450
|
const isEditing = editingBlockId === block3.id;
|
|
8561
|
-
const [showDeleteConfirm, setShowDeleteConfirm] =
|
|
8451
|
+
const [showDeleteConfirm, setShowDeleteConfirm] = React56.useState(false);
|
|
8562
8452
|
const style = {
|
|
8563
8453
|
transform: utilities.CSS.Transform.toString(transform),
|
|
8564
8454
|
transition,
|
|
@@ -8752,7 +8642,7 @@ var SortableBlockComponent = ({
|
|
|
8752
8642
|
)
|
|
8753
8643
|
] });
|
|
8754
8644
|
};
|
|
8755
|
-
var SortableBlock =
|
|
8645
|
+
var SortableBlock = React56__default.default.memo(SortableBlockComponent);
|
|
8756
8646
|
var BlocksField = ({
|
|
8757
8647
|
field: field3,
|
|
8758
8648
|
value,
|
|
@@ -8763,9 +8653,9 @@ var BlocksField = ({
|
|
|
8763
8653
|
documentStatus,
|
|
8764
8654
|
justSaved
|
|
8765
8655
|
}) => {
|
|
8766
|
-
const [isDrawerOpen, setIsDrawerOpen] =
|
|
8767
|
-
const [isDropdownOpen, setIsDropdownOpen] =
|
|
8768
|
-
const dropdownRef =
|
|
8656
|
+
const [isDrawerOpen, setIsDrawerOpen] = React56.useState(false);
|
|
8657
|
+
const [isDropdownOpen, setIsDropdownOpen] = React56.useState(false);
|
|
8658
|
+
const dropdownRef = React56.useRef(null);
|
|
8769
8659
|
const pickerMode = field3.admin?.pickerMode || "drawer";
|
|
8770
8660
|
const allowedBlocks = field3.blocks || [];
|
|
8771
8661
|
const groupedBlocks = allowedBlocks.reduce((acc, block3) => {
|
|
@@ -8795,18 +8685,18 @@ var BlocksField = ({
|
|
|
8795
8685
|
title,
|
|
8796
8686
|
blocks: blocks3
|
|
8797
8687
|
}));
|
|
8798
|
-
const storeRef =
|
|
8688
|
+
const storeRef = React56.useRef(null);
|
|
8799
8689
|
if (!storeRef.current) {
|
|
8800
8690
|
storeRef.current = createBlocksStore(allowedBlocks, dynamicCategories);
|
|
8801
8691
|
}
|
|
8802
8692
|
const store = storeRef.current;
|
|
8803
8693
|
const blocks2 = zustand.useStore(store, (s) => s.blocks);
|
|
8804
|
-
const [activeDrag, setActiveDrag] =
|
|
8805
|
-
const [editingBlockId, setEditingBlockId] =
|
|
8806
|
-
const prevBlocksLengthRef =
|
|
8807
|
-
const prevBlockIdsRef =
|
|
8808
|
-
const isInitializedRef =
|
|
8809
|
-
|
|
8694
|
+
const [activeDrag, setActiveDrag] = React56.useState(null);
|
|
8695
|
+
const [editingBlockId, setEditingBlockId] = React56.useState(null);
|
|
8696
|
+
const prevBlocksLengthRef = React56.useRef(blocks2.length);
|
|
8697
|
+
const prevBlockIdsRef = React56.useRef(new Set(blocks2.map((b) => b.id)));
|
|
8698
|
+
const isInitializedRef = React56.useRef(false);
|
|
8699
|
+
React56.useEffect(() => {
|
|
8810
8700
|
if (isInitializedRef.current) {
|
|
8811
8701
|
if (blocks2.length > prevBlocksLengthRef.current) {
|
|
8812
8702
|
const newBlock = blocks2.find((b) => b.id && !prevBlockIdsRef.current.has(b.id));
|
|
@@ -8818,7 +8708,7 @@ var BlocksField = ({
|
|
|
8818
8708
|
prevBlocksLengthRef.current = blocks2.length;
|
|
8819
8709
|
prevBlockIdsRef.current = new Set(blocks2.map((b) => b.id));
|
|
8820
8710
|
}, [blocks2]);
|
|
8821
|
-
|
|
8711
|
+
React56.useEffect(() => {
|
|
8822
8712
|
if (onBlocksChange) {
|
|
8823
8713
|
store.getState().setOnBlocksChange(onBlocksChange);
|
|
8824
8714
|
}
|
|
@@ -8827,14 +8717,11 @@ var BlocksField = ({
|
|
|
8827
8717
|
});
|
|
8828
8718
|
};
|
|
8829
8719
|
}, [onBlocksChange, store]);
|
|
8830
|
-
const lastValueRef =
|
|
8831
|
-
|
|
8720
|
+
const lastValueRef = React56.useRef(null);
|
|
8721
|
+
React56.useEffect(() => {
|
|
8832
8722
|
const valueArray = Array.isArray(value) ? value : [];
|
|
8833
8723
|
const lastValueArray = lastValueRef.current || [];
|
|
8834
|
-
|
|
8835
|
-
const lastValueIds = lastValueArray.map((b) => b.id).join(",");
|
|
8836
|
-
if (valueIds !== lastValueIds) {
|
|
8837
|
-
console.log("BlocksField sync: value=", value, "valueIds=", valueIds, "lastValueIds=", lastValueIds);
|
|
8724
|
+
if (JSON.stringify(valueArray) !== JSON.stringify(lastValueArray)) {
|
|
8838
8725
|
const valueArrayCopy = [...valueArray];
|
|
8839
8726
|
prevBlocksLengthRef.current = valueArrayCopy.length;
|
|
8840
8727
|
prevBlockIdsRef.current = new Set(valueArrayCopy.map((b) => b.id));
|
|
@@ -8843,27 +8730,27 @@ var BlocksField = ({
|
|
|
8843
8730
|
isInitializedRef.current = true;
|
|
8844
8731
|
} else if (valueArray.length === 0 && !isInitializedRef.current) {
|
|
8845
8732
|
isInitializedRef.current = true;
|
|
8733
|
+
lastValueRef.current = [];
|
|
8846
8734
|
}
|
|
8847
8735
|
}, [value, field3.name, store]);
|
|
8848
|
-
const onChangeRef =
|
|
8736
|
+
const onChangeRef = React56.useRef(onChange);
|
|
8849
8737
|
onChangeRef.current = onChange;
|
|
8850
|
-
|
|
8738
|
+
React56.useEffect(() => {
|
|
8851
8739
|
if (!onChangeRef.current) return;
|
|
8852
8740
|
const lastValue = lastValueRef.current;
|
|
8853
8741
|
if (!lastValue) return;
|
|
8854
|
-
|
|
8855
|
-
|
|
8856
|
-
if (currentIds !== lastIds) {
|
|
8742
|
+
if (JSON.stringify(blocks2) !== JSON.stringify(lastValue)) {
|
|
8743
|
+
lastValueRef.current = [...blocks2];
|
|
8857
8744
|
onChangeRef.current(blocks2);
|
|
8858
8745
|
}
|
|
8859
8746
|
}, [blocks2]);
|
|
8860
|
-
const handleAddBlock =
|
|
8747
|
+
const handleAddBlock = React56.useCallback(
|
|
8861
8748
|
(blockType) => {
|
|
8862
8749
|
store.getState().addBlock(blockType);
|
|
8863
8750
|
},
|
|
8864
8751
|
[store]
|
|
8865
8752
|
);
|
|
8866
|
-
const duplicateBlock =
|
|
8753
|
+
const duplicateBlock = React56.useCallback(
|
|
8867
8754
|
(blockId) => {
|
|
8868
8755
|
const blockIndex = blocks2.findIndex((b) => b.id === blockId);
|
|
8869
8756
|
if (blockIndex === -1) return;
|
|
@@ -8928,7 +8815,7 @@ var BlocksField = ({
|
|
|
8928
8815
|
};
|
|
8929
8816
|
const activeBlock = activeDrag ? blockCategories.flatMap((cat) => cat.blocks).find((b) => `drawer-${b.type}` === activeDrag.id) || blocks2.find((b) => b.id === activeDrag.id) : null;
|
|
8930
8817
|
activeBlock ? "label" in activeBlock ? activeBlock.label : activeBlock.type : "Block";
|
|
8931
|
-
|
|
8818
|
+
React56.useEffect(() => {
|
|
8932
8819
|
if (!isDropdownOpen) return;
|
|
8933
8820
|
const handleClick = (e) => {
|
|
8934
8821
|
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
@@ -9088,12 +8975,45 @@ function normalizeUploadFields(value) {
|
|
|
9088
8975
|
}
|
|
9089
8976
|
return value;
|
|
9090
8977
|
}
|
|
9091
|
-
function
|
|
9092
|
-
|
|
9093
|
-
|
|
9094
|
-
|
|
9095
|
-
|
|
9096
|
-
|
|
8978
|
+
function useQueue() {
|
|
8979
|
+
const queue = React56.useRef([]);
|
|
8980
|
+
const isProcessing = React56.useRef(false);
|
|
8981
|
+
const queueTask = React56.useCallback((fn, options) => {
|
|
8982
|
+
queue.current.push(fn);
|
|
8983
|
+
async function processQueue() {
|
|
8984
|
+
if (isProcessing.current) return;
|
|
8985
|
+
if (typeof options?.beforeProcess === "function") {
|
|
8986
|
+
const shouldContinue = options.beforeProcess();
|
|
8987
|
+
if (shouldContinue === false) return;
|
|
8988
|
+
}
|
|
8989
|
+
while (queue.current.length > 0) {
|
|
8990
|
+
const latestTask = queue.current.pop();
|
|
8991
|
+
queue.current = [];
|
|
8992
|
+
isProcessing.current = true;
|
|
8993
|
+
try {
|
|
8994
|
+
await latestTask();
|
|
8995
|
+
} catch (err) {
|
|
8996
|
+
console.error("Error in queued function:", err);
|
|
8997
|
+
} finally {
|
|
8998
|
+
isProcessing.current = false;
|
|
8999
|
+
if (typeof options?.afterProcess === "function") {
|
|
9000
|
+
options.afterProcess();
|
|
9001
|
+
}
|
|
9002
|
+
}
|
|
9003
|
+
}
|
|
9004
|
+
}
|
|
9005
|
+
processQueue();
|
|
9006
|
+
}, []);
|
|
9007
|
+
return { queueTask };
|
|
9008
|
+
}
|
|
9009
|
+
|
|
9010
|
+
// src/hooks/useAutoFormState.ts
|
|
9011
|
+
function useAutoFormState({
|
|
9012
|
+
config,
|
|
9013
|
+
initialData,
|
|
9014
|
+
collectionSlug,
|
|
9015
|
+
globalSlug,
|
|
9016
|
+
onChange,
|
|
9097
9017
|
onActionSuccess,
|
|
9098
9018
|
onActionError
|
|
9099
9019
|
}) {
|
|
@@ -9121,24 +9041,27 @@ function useAutoFormState({
|
|
|
9121
9041
|
} = store;
|
|
9122
9042
|
const versionsEnabled = !!config.versions;
|
|
9123
9043
|
const currentContextKey = globalSlug || initialData?.id || collectionSlug;
|
|
9124
|
-
const needsResetRef =
|
|
9044
|
+
const needsResetRef = React56.useRef(false);
|
|
9125
9045
|
if (!globalSlug && currentContextKey && formData && Object.keys(formData).length > 0 && formData.id !== currentContextKey) {
|
|
9126
9046
|
needsResetRef.current = true;
|
|
9127
9047
|
}
|
|
9128
|
-
|
|
9048
|
+
React56.useEffect(() => {
|
|
9129
9049
|
if (needsResetRef.current) {
|
|
9130
9050
|
needsResetRef.current = false;
|
|
9131
9051
|
resetForm();
|
|
9132
9052
|
}
|
|
9133
9053
|
}, [resetForm]);
|
|
9134
|
-
const localSaveTimerRef =
|
|
9135
|
-
const serverSaveTimerRef =
|
|
9136
|
-
const retryTimerRef =
|
|
9137
|
-
const isOnlineRef =
|
|
9138
|
-
const lastAutoSaveTimeRef =
|
|
9139
|
-
const autoSaveSkipRef =
|
|
9140
|
-
const restorePromptedRef =
|
|
9141
|
-
const
|
|
9054
|
+
const localSaveTimerRef = React56.useRef(null);
|
|
9055
|
+
const serverSaveTimerRef = React56.useRef(null);
|
|
9056
|
+
const retryTimerRef = React56.useRef(null);
|
|
9057
|
+
const isOnlineRef = React56.useRef(typeof navigator !== "undefined" ? navigator.onLine : true);
|
|
9058
|
+
const lastAutoSaveTimeRef = React56.useRef(0);
|
|
9059
|
+
const autoSaveSkipRef = React56.useRef(false);
|
|
9060
|
+
const restorePromptedRef = React56.useRef(null);
|
|
9061
|
+
const previousFormDataRef = React56.useRef("");
|
|
9062
|
+
const astroSyncDataRef = React56.useRef("");
|
|
9063
|
+
const { queueTask } = useQueue();
|
|
9064
|
+
const getDocumentKey = React56.useCallback(
|
|
9142
9065
|
(id) => {
|
|
9143
9066
|
if (globalSlug) return `global:${globalSlug}`;
|
|
9144
9067
|
if (collectionSlug && id) return `${collectionSlug}:${id}`;
|
|
@@ -9146,7 +9069,7 @@ function useAutoFormState({
|
|
|
9146
9069
|
},
|
|
9147
9070
|
[collectionSlug, globalSlug]
|
|
9148
9071
|
);
|
|
9149
|
-
const persistBrowserDraft =
|
|
9072
|
+
const persistBrowserDraft = React56.useCallback(
|
|
9150
9073
|
(documentKey, data, options) => {
|
|
9151
9074
|
setDraftCache(documentKey, {
|
|
9152
9075
|
data,
|
|
@@ -9157,24 +9080,7 @@ function useAutoFormState({
|
|
|
9157
9080
|
},
|
|
9158
9081
|
[lastSavedData.updatedAt, setDraftCache]
|
|
9159
9082
|
);
|
|
9160
|
-
const
|
|
9161
|
-
const state = useAutoFormStore.getState();
|
|
9162
|
-
const documentKey = getDocumentKey(state.formData.id);
|
|
9163
|
-
if (documentKey) {
|
|
9164
|
-
clearDraftCache(documentKey);
|
|
9165
|
-
}
|
|
9166
|
-
const draftUrl = globalSlug ? resolveApi(`/api/globals/${globalSlug}/draft`) : collectionSlug && state.formData.id ? resolveApi(`/api/${collectionSlug}/${state.formData.id}/draft`) : null;
|
|
9167
|
-
if (draftUrl && versionsEnabled) {
|
|
9168
|
-
try {
|
|
9169
|
-
await fetchWithAuth(draftUrl, {
|
|
9170
|
-
method: "DELETE"
|
|
9171
|
-
});
|
|
9172
|
-
} catch (err) {
|
|
9173
|
-
console.error("Failed to clear draft snapshot:", err);
|
|
9174
|
-
}
|
|
9175
|
-
}
|
|
9176
|
-
}, [clearDraftCache, collectionSlug, globalSlug, getDocumentKey]);
|
|
9177
|
-
const fetchVersions = React54.useCallback(async () => {
|
|
9083
|
+
const fetchVersions = React56.useCallback(async () => {
|
|
9178
9084
|
const url = globalSlug ? resolveApi(`/api/globals/${globalSlug}/versions`) : collectionSlug && formData.id ? resolveApi(`/api/${collectionSlug}/${formData.id}/versions`) : null;
|
|
9179
9085
|
if (!url) return;
|
|
9180
9086
|
setLoadingVersions(true);
|
|
@@ -9188,7 +9094,7 @@ function useAutoFormState({
|
|
|
9188
9094
|
setLoadingVersions(false);
|
|
9189
9095
|
}
|
|
9190
9096
|
}, [formData.id, collectionSlug, globalSlug, setLoadingVersions, setVersions]);
|
|
9191
|
-
const performLocalAutoSave =
|
|
9097
|
+
const performLocalAutoSave = React56.useCallback(() => {
|
|
9192
9098
|
const state = useAutoFormStore.getState();
|
|
9193
9099
|
const latestFormData = state.formData;
|
|
9194
9100
|
if (autoSaveSkipRef.current || !collectionSlug || !latestFormData.id) return;
|
|
@@ -9198,7 +9104,7 @@ function useAutoFormState({
|
|
|
9198
9104
|
persistBrowserDraft(documentKey, latestFormData);
|
|
9199
9105
|
}
|
|
9200
9106
|
}, [collectionSlug, getDocumentKey, persistBrowserDraft]);
|
|
9201
|
-
const
|
|
9107
|
+
const doAutosaveFetch = React56.useCallback(async (options) => {
|
|
9202
9108
|
const state = useAutoFormStore.getState();
|
|
9203
9109
|
const latestFormData = state.formData;
|
|
9204
9110
|
const currentLastSaved = state.lastSavedData;
|
|
@@ -9215,29 +9121,22 @@ function useAutoFormState({
|
|
|
9215
9121
|
}
|
|
9216
9122
|
setIsAutoSaving(true);
|
|
9217
9123
|
setAutoSaveStatus("saving");
|
|
9124
|
+
state.setBackgroundProcessing(true);
|
|
9218
9125
|
try {
|
|
9219
|
-
const
|
|
9220
|
-
const
|
|
9221
|
-
|
|
9222
|
-
|
|
9223
|
-
|
|
9224
|
-
|
|
9225
|
-
|
|
9226
|
-
|
|
9227
|
-
|
|
9228
|
-
|
|
9229
|
-
|
|
9230
|
-
|
|
9231
|
-
|
|
9232
|
-
body: JSON.stringify({
|
|
9233
|
-
delta: normalizeUploadFields(delta),
|
|
9234
|
-
baseUpdatedAt: currentLastSaved.updatedAt ?? null,
|
|
9235
|
-
draftUpdatedAt
|
|
9236
|
-
})
|
|
9237
|
-
}
|
|
9238
|
-
);
|
|
9126
|
+
const url = globalSlug ? resolveApi(`/api/globals/${globalSlug}?autosave=true`) : resolveApi(`/api/${collectionSlug}/${latestFormData.id}?autosave=true`);
|
|
9127
|
+
const response = await fetchWithAuth(url, {
|
|
9128
|
+
method: "PATCH",
|
|
9129
|
+
headers: {
|
|
9130
|
+
"Content-Type": "application/json",
|
|
9131
|
+
"X-Draft": "true"
|
|
9132
|
+
},
|
|
9133
|
+
keepalive: options?.keepalive,
|
|
9134
|
+
body: JSON.stringify({
|
|
9135
|
+
...normalizeUploadFields(latestFormData),
|
|
9136
|
+
baseUpdatedAt: currentLastSaved.updatedAt ?? null
|
|
9137
|
+
})
|
|
9138
|
+
});
|
|
9239
9139
|
if (response.ok) {
|
|
9240
|
-
const result = await response.json();
|
|
9241
9140
|
lastAutoSaveTimeRef.current = Date.now();
|
|
9242
9141
|
state.setRetryCount(0);
|
|
9243
9142
|
state.setLastSavedAt(Date.now());
|
|
@@ -9246,8 +9145,8 @@ function useAutoFormState({
|
|
|
9246
9145
|
setDraftCache(documentKey, {
|
|
9247
9146
|
data: latestFormData,
|
|
9248
9147
|
baseUpdatedAt: currentLastSaved.updatedAt ?? null,
|
|
9249
|
-
draftUpdatedAt:
|
|
9250
|
-
lastSyncedAt:
|
|
9148
|
+
draftUpdatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9149
|
+
lastSyncedAt: (await response.clone().json()).data?.updatedAt || (/* @__PURE__ */ new Date()).toISOString()
|
|
9251
9150
|
});
|
|
9252
9151
|
}
|
|
9253
9152
|
setAutoSaveStatus("success");
|
|
@@ -9256,24 +9155,27 @@ function useAutoFormState({
|
|
|
9256
9155
|
setAutoSaveStatus("idle");
|
|
9257
9156
|
}
|
|
9258
9157
|
}, 2e3);
|
|
9158
|
+
} else if (response.status === 409) {
|
|
9159
|
+
setAutoSaveStatus("conflict");
|
|
9259
9160
|
} else {
|
|
9260
9161
|
throw new Error(`Draft auto-save failed with status ${response.status}`);
|
|
9261
9162
|
}
|
|
9262
9163
|
} catch (err) {
|
|
9263
9164
|
console.error("Auto-save failed:", err);
|
|
9264
|
-
const
|
|
9265
|
-
const currentRetryCount =
|
|
9165
|
+
const currentState = useAutoFormStore.getState();
|
|
9166
|
+
const currentRetryCount = currentState.retryCount;
|
|
9266
9167
|
if (currentRetryCount < 5) {
|
|
9267
|
-
|
|
9168
|
+
currentState.setRetryCount(currentRetryCount + 1);
|
|
9268
9169
|
setAutoSaveStatus("retrying");
|
|
9269
9170
|
const delay = Math.min(1e3 * Math.pow(2, currentRetryCount), 6e4);
|
|
9270
9171
|
if (retryTimerRef.current) clearTimeout(retryTimerRef.current);
|
|
9271
|
-
retryTimerRef.current = setTimeout(() =>
|
|
9172
|
+
retryTimerRef.current = setTimeout(() => performAutosave(options), delay);
|
|
9272
9173
|
} else {
|
|
9273
9174
|
setAutoSaveStatus("offline");
|
|
9274
9175
|
}
|
|
9275
9176
|
} finally {
|
|
9276
9177
|
setIsAutoSaving(false);
|
|
9178
|
+
useAutoFormStore.getState().setBackgroundProcessing(false);
|
|
9277
9179
|
}
|
|
9278
9180
|
}, [
|
|
9279
9181
|
collectionSlug,
|
|
@@ -9285,8 +9187,20 @@ function useAutoFormState({
|
|
|
9285
9187
|
setIsAutoSaving,
|
|
9286
9188
|
versionsEnabled
|
|
9287
9189
|
]);
|
|
9288
|
-
const
|
|
9289
|
-
|
|
9190
|
+
const performAutosave = React56.useCallback((options) => {
|
|
9191
|
+
queueTask(
|
|
9192
|
+
() => doAutosaveFetch(options),
|
|
9193
|
+
{
|
|
9194
|
+
beforeProcess: () => {
|
|
9195
|
+
return true;
|
|
9196
|
+
},
|
|
9197
|
+
afterProcess: () => {
|
|
9198
|
+
}
|
|
9199
|
+
}
|
|
9200
|
+
);
|
|
9201
|
+
}, [doAutosaveFetch, queueTask]);
|
|
9202
|
+
const saveDocument = React56.useCallback(
|
|
9203
|
+
async (dataOverride, isDraft = true) => {
|
|
9290
9204
|
const state = useAutoFormStore.getState();
|
|
9291
9205
|
const payload = dataOverride || state.formData;
|
|
9292
9206
|
const url = globalSlug ? resolveApi(`/api/globals/${globalSlug}`) : resolveApi(`/api/${collectionSlug}/${payload.id}`);
|
|
@@ -9294,7 +9208,10 @@ function useAutoFormState({
|
|
|
9294
9208
|
url,
|
|
9295
9209
|
{
|
|
9296
9210
|
method: "PATCH",
|
|
9297
|
-
headers: {
|
|
9211
|
+
headers: {
|
|
9212
|
+
"Content-Type": "application/json",
|
|
9213
|
+
"X-Draft": String(isDraft)
|
|
9214
|
+
},
|
|
9298
9215
|
body: JSON.stringify({
|
|
9299
9216
|
...normalizeUploadFields(payload),
|
|
9300
9217
|
baseUpdatedAt: state.lastSavedData.updatedAt ?? null
|
|
@@ -9308,53 +9225,26 @@ function useAutoFormState({
|
|
|
9308
9225
|
},
|
|
9309
9226
|
[collectionSlug, globalSlug, setAutoSaveStatus]
|
|
9310
9227
|
);
|
|
9311
|
-
|
|
9312
|
-
const state = useAutoFormStore.getState();
|
|
9313
|
-
const url = globalSlug ? resolveApi(`/api/globals/${globalSlug}/publish`) : resolveApi(`/api/${collectionSlug}/${state.formData.id}/publish`);
|
|
9314
|
-
const response = await fetchWithAuth(
|
|
9315
|
-
url,
|
|
9316
|
-
{
|
|
9317
|
-
method: "POST",
|
|
9318
|
-
headers: { "Content-Type": "application/json" },
|
|
9319
|
-
body: JSON.stringify({
|
|
9320
|
-
baseUpdatedAt: state.lastSavedData.updatedAt ?? null
|
|
9321
|
-
})
|
|
9322
|
-
}
|
|
9323
|
-
);
|
|
9324
|
-
if (response.status === 409) {
|
|
9325
|
-
setAutoSaveStatus("conflict");
|
|
9326
|
-
}
|
|
9327
|
-
return response;
|
|
9328
|
-
}, [collectionSlug, globalSlug, setAutoSaveStatus]);
|
|
9329
|
-
const unpublishDocument = React54.useCallback(async () => {
|
|
9330
|
-
const state = useAutoFormStore.getState();
|
|
9331
|
-
const url = globalSlug ? resolveApi(`/api/globals/${globalSlug}/unpublish`) : resolveApi(`/api/${collectionSlug}/${state.formData.id}/unpublish`);
|
|
9332
|
-
const response = await fetchWithAuth(
|
|
9333
|
-
url,
|
|
9334
|
-
{
|
|
9335
|
-
method: "POST",
|
|
9336
|
-
headers: { "Content-Type": "application/json" }
|
|
9337
|
-
}
|
|
9338
|
-
);
|
|
9339
|
-
return response;
|
|
9340
|
-
}, [collectionSlug, globalSlug]);
|
|
9341
|
-
React54.useEffect(() => {
|
|
9228
|
+
React56.useEffect(() => {
|
|
9342
9229
|
const handleToggle = () => {
|
|
9343
9230
|
setSidebarCollapsed(!sidebarCollapsed);
|
|
9344
9231
|
};
|
|
9345
9232
|
window.addEventListener("toggle-sidebar", handleToggle);
|
|
9346
9233
|
return () => window.removeEventListener("toggle-sidebar", handleToggle);
|
|
9347
9234
|
}, [sidebarCollapsed, setSidebarCollapsed]);
|
|
9348
|
-
const lastLoadedSlugRef =
|
|
9349
|
-
const
|
|
9350
|
-
|
|
9235
|
+
const lastLoadedSlugRef = React56.useRef(null);
|
|
9236
|
+
const lastInitialDataRef = React56.useRef("");
|
|
9237
|
+
const initialDataLoadedRef = React56.useRef(false);
|
|
9238
|
+
React56.useEffect(() => {
|
|
9351
9239
|
const currentSlug = globalSlug || initialData?.id;
|
|
9352
|
-
|
|
9240
|
+
const serialized = JSON.stringify(initialData);
|
|
9241
|
+
if (initialDataLoadedRef.current && lastLoadedSlugRef.current === currentSlug && lastInitialDataRef.current === serialized) return;
|
|
9353
9242
|
loadDocument(initialData || {}, initialData || {});
|
|
9354
9243
|
initialDataLoadedRef.current = true;
|
|
9355
9244
|
lastLoadedSlugRef.current = currentSlug;
|
|
9245
|
+
lastInitialDataRef.current = serialized;
|
|
9356
9246
|
}, [collectionSlug, formData.id, globalSlug, initialData, loadDocument]);
|
|
9357
|
-
|
|
9247
|
+
React56.useEffect(() => {
|
|
9358
9248
|
if (!collectionSlug || !initialData?.id) return;
|
|
9359
9249
|
const documentKey = getDocumentKey(initialData.id);
|
|
9360
9250
|
if (!documentKey) return;
|
|
@@ -9363,24 +9253,9 @@ function useAutoFormState({
|
|
|
9363
9253
|
const maybeRestoreDraft = async () => {
|
|
9364
9254
|
if (!versionsEnabled) return;
|
|
9365
9255
|
const browserDraft = getDraftCache(documentKey);
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
|
|
9369
|
-
resolveApi(`/api/${collectionSlug}/${initialData.id}/draft`)
|
|
9370
|
-
);
|
|
9371
|
-
if (response.ok) {
|
|
9372
|
-
const result = await response.json();
|
|
9373
|
-
serverDraft = result.data || null;
|
|
9374
|
-
}
|
|
9375
|
-
} catch (err) {
|
|
9376
|
-
console.error("Failed to fetch server draft:", err);
|
|
9377
|
-
}
|
|
9378
|
-
const drafts = [browserDraft, serverDraft].filter(Boolean);
|
|
9379
|
-
const candidate = drafts.sort(
|
|
9380
|
-
(a, b) => new Date(b.draftUpdatedAt).getTime() - new Date(a.draftUpdatedAt).getTime()
|
|
9381
|
-
)[0];
|
|
9382
|
-
if (!candidate) return;
|
|
9383
|
-
if (JSON.stringify(candidate.data) === JSON.stringify(initialData)) {
|
|
9256
|
+
if (!browserDraft) return;
|
|
9257
|
+
if (JSON.stringify(browserDraft.data) === JSON.stringify(initialData)) {
|
|
9258
|
+
clearDraftCache(documentKey);
|
|
9384
9259
|
return;
|
|
9385
9260
|
}
|
|
9386
9261
|
restorePromptedRef.current = documentKey;
|
|
@@ -9392,20 +9267,12 @@ function useAutoFormState({
|
|
|
9392
9267
|
onConfirm: async () => {
|
|
9393
9268
|
if (cancelled) return;
|
|
9394
9269
|
const currentFormData = useAutoFormStore.getState().formData;
|
|
9395
|
-
const mergedData = { ...currentFormData, ...
|
|
9270
|
+
const mergedData = { ...currentFormData, ...browserDraft.data };
|
|
9396
9271
|
setFormData(mergedData);
|
|
9397
9272
|
onActionSuccess?.("Recovered autosaved draft");
|
|
9398
9273
|
},
|
|
9399
9274
|
onCancel: async () => {
|
|
9400
9275
|
clearDraftCache(documentKey);
|
|
9401
|
-
try {
|
|
9402
|
-
await fetchWithAuth(
|
|
9403
|
-
resolveApi(`/api/${collectionSlug}/${initialData.id}/draft`),
|
|
9404
|
-
{ method: "DELETE" }
|
|
9405
|
-
);
|
|
9406
|
-
} catch (err) {
|
|
9407
|
-
console.error("Failed to discard server draft:", err);
|
|
9408
|
-
}
|
|
9409
9276
|
}
|
|
9410
9277
|
});
|
|
9411
9278
|
};
|
|
@@ -9421,7 +9288,8 @@ function useAutoFormState({
|
|
|
9421
9288
|
getDraftCache,
|
|
9422
9289
|
initialData,
|
|
9423
9290
|
onActionSuccess,
|
|
9424
|
-
setFormData
|
|
9291
|
+
setFormData,
|
|
9292
|
+
versionsEnabled
|
|
9425
9293
|
]);
|
|
9426
9294
|
function findFieldDeep(fields2, name) {
|
|
9427
9295
|
for (const f of fields2) {
|
|
@@ -9439,7 +9307,7 @@ function useAutoFormState({
|
|
|
9439
9307
|
}
|
|
9440
9308
|
return void 0;
|
|
9441
9309
|
}
|
|
9442
|
-
|
|
9310
|
+
React56.useEffect(() => {
|
|
9443
9311
|
const fields2 = config.fields;
|
|
9444
9312
|
const metaTitleField = findFieldDeep(fields2, "metaTitle");
|
|
9445
9313
|
if (!metaTitleField) return;
|
|
@@ -9449,7 +9317,7 @@ function useAutoFormState({
|
|
|
9449
9317
|
setField("metaTitle", titleStr);
|
|
9450
9318
|
}
|
|
9451
9319
|
}, [formData, config.fields, setField]);
|
|
9452
|
-
|
|
9320
|
+
React56.useEffect(() => {
|
|
9453
9321
|
const fields2 = config.fields;
|
|
9454
9322
|
const slugField = fields2.find(
|
|
9455
9323
|
(f) => f.name === "slug" && f.admin?.autoGenerate
|
|
@@ -9464,25 +9332,30 @@ function useAutoFormState({
|
|
|
9464
9332
|
}
|
|
9465
9333
|
}
|
|
9466
9334
|
}, [formData, isSlugLocked, config.fields, setField]);
|
|
9467
|
-
|
|
9335
|
+
React56.useEffect(() => {
|
|
9468
9336
|
if (sidebarCollapsed) return;
|
|
9469
9337
|
if (!globalSlug && (!collectionSlug || !formData.id)) return;
|
|
9470
9338
|
const state = useAutoFormStore.getState();
|
|
9471
9339
|
if (!state.hasDirtyFields()) return;
|
|
9472
9340
|
if (getLastChangeSource() !== "keystroke") return;
|
|
9473
9341
|
setChangeSource("other");
|
|
9342
|
+
const serialized = JSON.stringify(formData);
|
|
9343
|
+
if (serialized === previousFormDataRef.current) return;
|
|
9474
9344
|
if (localSaveTimerRef.current) clearTimeout(localSaveTimerRef.current);
|
|
9475
|
-
if (serverSaveTimerRef.current) clearTimeout(serverSaveTimerRef.current);
|
|
9476
9345
|
localSaveTimerRef.current = setTimeout(performLocalAutoSave, 1500);
|
|
9477
|
-
serverSaveTimerRef.current
|
|
9478
|
-
|
|
9479
|
-
|
|
9346
|
+
if (serverSaveTimerRef.current) clearTimeout(serverSaveTimerRef.current);
|
|
9347
|
+
serverSaveTimerRef.current = setTimeout(() => {
|
|
9348
|
+
previousFormDataRef.current = serialized;
|
|
9349
|
+
performAutosave();
|
|
9350
|
+
}, 8e3);
|
|
9351
|
+
}, [formData, sidebarCollapsed, collectionSlug, globalSlug, performLocalAutoSave, performAutosave]);
|
|
9352
|
+
React56.useEffect(() => {
|
|
9480
9353
|
if (!globalSlug && (!collectionSlug || !formData.id)) return;
|
|
9481
9354
|
const flushDraft = () => {
|
|
9482
9355
|
if (autoSaveSkipRef.current) return;
|
|
9483
9356
|
const state = useAutoFormStore.getState();
|
|
9484
9357
|
if (!state.hasDirtyFields()) return;
|
|
9485
|
-
void
|
|
9358
|
+
void performAutosave({ keepalive: true });
|
|
9486
9359
|
};
|
|
9487
9360
|
const handleVisibilityChange = () => {
|
|
9488
9361
|
if (document.hidden) {
|
|
@@ -9512,32 +9385,31 @@ function useAutoFormState({
|
|
|
9512
9385
|
window.removeEventListener("offline", handleOffline);
|
|
9513
9386
|
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
9514
9387
|
};
|
|
9515
|
-
}, [collectionSlug, globalSlug, formData.id,
|
|
9516
|
-
|
|
9388
|
+
}, [collectionSlug, globalSlug, formData.id, performAutosave]);
|
|
9389
|
+
React56.useEffect(() => {
|
|
9390
|
+
const serialized = JSON.stringify(formData);
|
|
9391
|
+
if (serialized === astroSyncDataRef.current) return;
|
|
9392
|
+
astroSyncDataRef.current = serialized;
|
|
9517
9393
|
const hiddenInput = document.getElementById("form-data");
|
|
9518
9394
|
if (hiddenInput) {
|
|
9519
|
-
hiddenInput.value =
|
|
9395
|
+
hiddenInput.value = serialized;
|
|
9520
9396
|
}
|
|
9521
9397
|
onChange?.(formData);
|
|
9522
9398
|
}, [formData, onChange]);
|
|
9523
|
-
|
|
9399
|
+
React56.useEffect(() => {
|
|
9524
9400
|
if (globalSlug || formData.id) fetchVersions();
|
|
9525
9401
|
}, [formData.id, globalSlug, fetchVersions]);
|
|
9526
9402
|
const documentStatus = (() => {
|
|
9527
9403
|
if (!formData.id && !globalSlug) return "draft";
|
|
9528
9404
|
if (!versionsEnabled) return "published";
|
|
9529
|
-
|
|
9530
|
-
return formData.publishStatus || "published";
|
|
9405
|
+
return formData.status || "published";
|
|
9531
9406
|
})();
|
|
9532
|
-
const hasUnpublishedChanges = (!!formData.id || !!globalSlug) &&
|
|
9407
|
+
const hasUnpublishedChanges = (!!formData.id || !!globalSlug) && documentStatus === "draft";
|
|
9533
9408
|
return {
|
|
9534
9409
|
...store,
|
|
9535
9410
|
fetchVersions,
|
|
9536
|
-
performAutoSave:
|
|
9411
|
+
performAutoSave: performAutosave,
|
|
9537
9412
|
saveDocument,
|
|
9538
|
-
publishDocument,
|
|
9539
|
-
unpublishDocument,
|
|
9540
|
-
clearDraftArtifacts,
|
|
9541
9413
|
autoSaveSkipRef,
|
|
9542
9414
|
lastAutoSaveTimeRef,
|
|
9543
9415
|
documentStatus,
|
|
@@ -9545,129 +9417,120 @@ function useAutoFormState({
|
|
|
9545
9417
|
versionsEnabled
|
|
9546
9418
|
};
|
|
9547
9419
|
}
|
|
9548
|
-
function
|
|
9549
|
-
|
|
9550
|
-
}
|
|
9551
|
-
function ModalActions({ children }) {
|
|
9552
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end gap-3 mt-6", children });
|
|
9553
|
-
}
|
|
9554
|
-
function Modal({
|
|
9555
|
-
open,
|
|
9556
|
-
onClose,
|
|
9557
|
-
title,
|
|
9420
|
+
function Dropdown({
|
|
9421
|
+
trigger,
|
|
9558
9422
|
children,
|
|
9559
|
-
|
|
9560
|
-
|
|
9561
|
-
variant = "default"
|
|
9423
|
+
align = "right",
|
|
9424
|
+
direction = "up"
|
|
9562
9425
|
}) {
|
|
9563
|
-
|
|
9564
|
-
|
|
9565
|
-
|
|
9426
|
+
const [open, setOpen] = React56.useState(false);
|
|
9427
|
+
const ref = React56.useRef(null);
|
|
9428
|
+
React56.useEffect(() => {
|
|
9429
|
+
const handleClickOutside = (e) => {
|
|
9430
|
+
if (ref.current && !ref.current.contains(e.target)) {
|
|
9431
|
+
setOpen(false);
|
|
9432
|
+
}
|
|
9566
9433
|
};
|
|
9567
9434
|
if (open) {
|
|
9568
|
-
document.addEventListener("
|
|
9569
|
-
document.body.style.overflow = "hidden";
|
|
9435
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
9570
9436
|
}
|
|
9571
|
-
return () =>
|
|
9572
|
-
|
|
9573
|
-
|
|
9574
|
-
}
|
|
9575
|
-
|
|
9576
|
-
|
|
9577
|
-
|
|
9578
|
-
|
|
9579
|
-
|
|
9580
|
-
|
|
9581
|
-
|
|
9582
|
-
|
|
9583
|
-
|
|
9584
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9585
|
-
"div",
|
|
9586
|
-
{
|
|
9587
|
-
className: "absolute inset-0 bg-[var(--kyro-black)]/40 backdrop-blur-md transition-all duration-500",
|
|
9588
|
-
onClick: onClose
|
|
9589
|
-
}
|
|
9590
|
-
),
|
|
9591
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9592
|
-
"div",
|
|
9593
|
-
{
|
|
9594
|
-
className: `relative w-full ${sizeClasses[size]} bg-[var(--kyro-surface)] rounded-[var(--kyro-radius-lg)] shadow-2xl animate-in fade-in zoom-in-95 duration-300 border ${variant === "danger" ? "border-red-500/30" : "border-[var(--kyro-border)]"} overflow-hidden`,
|
|
9595
|
-
children: [
|
|
9596
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-8 py-6 border-b border-[var(--kyro-border)] bg-[var(--kyro-surface-accent)]/50 backdrop-blur-md", children: [
|
|
9597
|
-
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl font-bold text-[var(--kyro-text-primary)]", children: title }),
|
|
9598
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9599
|
-
"button",
|
|
9600
|
-
{
|
|
9601
|
-
type: "button",
|
|
9602
|
-
onClick: onClose,
|
|
9603
|
-
className: "p-2 text-[var(--kyro-text-muted)] hover:text-[var(--kyro-text-primary)] rounded-xl hover:bg-[var(--kyro-surface)] transition-all duration-200",
|
|
9604
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9605
|
-
"svg",
|
|
9606
|
-
{
|
|
9607
|
-
width: "20",
|
|
9608
|
-
height: "20",
|
|
9609
|
-
viewBox: "0 0 24 24",
|
|
9610
|
-
fill: "none",
|
|
9611
|
-
stroke: "currentColor",
|
|
9612
|
-
strokeWidth: "2.5",
|
|
9613
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6L6 18M6 6l12 12" })
|
|
9614
|
-
}
|
|
9615
|
-
)
|
|
9616
|
-
}
|
|
9617
|
-
)
|
|
9618
|
-
] }),
|
|
9619
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-8 py-8", children }),
|
|
9620
|
-
footer && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end gap-3 px-8 py-6 border-t border-[var(--kyro-border)] bg-[var(--kyro-surface-accent)]/50", children: footer })
|
|
9621
|
-
]
|
|
9622
|
-
}
|
|
9623
|
-
)
|
|
9624
|
-
] }),
|
|
9625
|
-
document.body
|
|
9626
|
-
);
|
|
9437
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
9438
|
+
}, [open]);
|
|
9439
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", ref, children: [
|
|
9440
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { onClick: () => setOpen(!open), className: "cursor-pointer", children: trigger }),
|
|
9441
|
+
open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
9442
|
+
"div",
|
|
9443
|
+
{
|
|
9444
|
+
className: `absolute z-[100] min-w-[200px] py-2 bg-[var(--kyro-surface)] rounded-2xl shadow-2xl border border-[var(--kyro-border)] animate-in fade-in zoom-in-95 duration-100 ${align === "right" ? "right-0" : "left-0"} ${direction === "down" ? "top-full mt-2" : "bottom-full mb-2"}`,
|
|
9445
|
+
onClick: () => setOpen(false),
|
|
9446
|
+
children
|
|
9447
|
+
}
|
|
9448
|
+
)
|
|
9449
|
+
] });
|
|
9627
9450
|
}
|
|
9628
|
-
function
|
|
9629
|
-
|
|
9630
|
-
|
|
9631
|
-
|
|
9632
|
-
|
|
9633
|
-
|
|
9634
|
-
|
|
9635
|
-
cancelLabel = "Cancel",
|
|
9636
|
-
variant = "default",
|
|
9637
|
-
loading = false
|
|
9451
|
+
function DropdownItem({
|
|
9452
|
+
children,
|
|
9453
|
+
onClick,
|
|
9454
|
+
icon,
|
|
9455
|
+
danger,
|
|
9456
|
+
disabled,
|
|
9457
|
+
className = ""
|
|
9638
9458
|
}) {
|
|
9639
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9640
|
-
|
|
9459
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-1.5", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9460
|
+
"button",
|
|
9641
9461
|
{
|
|
9642
|
-
|
|
9643
|
-
|
|
9644
|
-
|
|
9645
|
-
|
|
9646
|
-
|
|
9647
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9648
|
-
|
|
9649
|
-
|
|
9650
|
-
type: "button",
|
|
9651
|
-
onClick: onClose,
|
|
9652
|
-
disabled: loading,
|
|
9653
|
-
className: "kyro-btn kyro-btn-md kyro-btn-secondary",
|
|
9654
|
-
children: cancelLabel
|
|
9655
|
-
}
|
|
9656
|
-
),
|
|
9657
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9658
|
-
"button",
|
|
9659
|
-
{
|
|
9660
|
-
type: "button",
|
|
9661
|
-
onClick: onConfirm,
|
|
9662
|
-
disabled: loading,
|
|
9663
|
-
className: `kyro-btn kyro-btn-md ${variant === "danger" ? "kyro-btn-danger" : "kyro-btn-primary"}`,
|
|
9664
|
-
children: loading ? "Loading..." : confirmLabel
|
|
9665
|
-
}
|
|
9666
|
-
)
|
|
9667
|
-
] }),
|
|
9668
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[var(--kyro-text-secondary)]", children: message })
|
|
9462
|
+
type: "button",
|
|
9463
|
+
onClick,
|
|
9464
|
+
disabled,
|
|
9465
|
+
className: `w-full flex items-center gap-3 px-3 py-2.5 text-[11px] font-medium tracking-wide text-left transition-all rounded-xl ${danger ? "text-red-500 hover:bg-red-500/10" : "text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-text-primary)] hover:bg-[var(--kyro-surface-accent)]"} ${disabled ? "opacity-50 cursor-not-allowed" : ""} ${className}`,
|
|
9466
|
+
children: [
|
|
9467
|
+
icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-4 h-4 opacity-70", children: icon }),
|
|
9468
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children })
|
|
9469
|
+
]
|
|
9669
9470
|
}
|
|
9670
|
-
);
|
|
9471
|
+
) });
|
|
9472
|
+
}
|
|
9473
|
+
function DropdownSeparator() {
|
|
9474
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "my-1 border-t border-[var(--kyro-border)] opacity-50" });
|
|
9475
|
+
}
|
|
9476
|
+
function SplitButton({
|
|
9477
|
+
status,
|
|
9478
|
+
saveStatus,
|
|
9479
|
+
hasChanges,
|
|
9480
|
+
onPublish,
|
|
9481
|
+
children,
|
|
9482
|
+
disabled,
|
|
9483
|
+
direction = "down"
|
|
9484
|
+
}) {
|
|
9485
|
+
const isPublishedIdle = status === "published" && !hasChanges && saveStatus !== "saving" && saveStatus !== "error";
|
|
9486
|
+
const isDisabled = disabled || saveStatus === "saving" || isPublishedIdle;
|
|
9487
|
+
const btnBase = "kyro-btn kyro-btn-sm text-[11px] font-regular tracking-widest transition-all duration-300 rounded-lg";
|
|
9488
|
+
const getBtnClass = () => {
|
|
9489
|
+
if (saveStatus === "saving") return `${btnBase} bg-[var(--kyro-primary)]/70 border-[var(--kyro-primary)]/70 text-[var(--kyro-sidebar-text-active)] cursor-wait`;
|
|
9490
|
+
if (saveStatus === "saved") return `${btnBase} bg-[var(--kyro-success)] border-[var(--kyro-success)] text-[var(--kyro-sidebar-text-active)]`;
|
|
9491
|
+
if (saveStatus === "error") return `${btnBase} bg-[var(--kyro-error)] border-[var(--kyro-error)] text-[var(--kyro-sidebar-text-active)]`;
|
|
9492
|
+
if (isPublishedIdle) return `${btnBase} bg-[var(--kyro-gray-200)] border-[var(--kyro-gray-200)] text-[var(--kyro-text-muted)] cursor-not-allowed`;
|
|
9493
|
+
return `${btnBase} bg-[var(--kyro-primary)] border-[var(--kyro-primary)] hover:bg-[var(--kyro-primary-hover)]`;
|
|
9494
|
+
};
|
|
9495
|
+
const chevronBase = "kyro-btn kyro-btn-md px-2 rounded-l-none border-l-[1px] border-white/20 transition-all duration-300";
|
|
9496
|
+
const getChevronClass = () => {
|
|
9497
|
+
if (saveStatus === "saving") return `${chevronBase} bg-[var(--kyro-primary)]/70 text-[var(--kyro-sidebar-text-active)] border-[var(--kyro-primary)]/70`;
|
|
9498
|
+
if (saveStatus === "saved") return `${chevronBase} bg-[var(--kyro-success)] text-[var(--kyro-sidebar-text-active)] border-[var(--kyro-success)]`;
|
|
9499
|
+
if (saveStatus === "error") return `${chevronBase} bg-[var(--kyro-error)] text-[var(--kyro-sidebar-text-active)] border-[var(--kyro-error)]`;
|
|
9500
|
+
if (isPublishedIdle) return `${chevronBase} bg-[var(--kyro-gray-200)] text-[var(--kyro-text-muted)] border-[var(--kyro-gray-200)]`;
|
|
9501
|
+
return `${chevronBase} bg-[var(--kyro-primary)] text-[var(--kyro-sidebar-text-active)] border-[var(--kyro-primary)] hover:bg-[var(--kyro-primary-hover)]`;
|
|
9502
|
+
};
|
|
9503
|
+
const getLabel2 = () => {
|
|
9504
|
+
if (saveStatus === "saving") return "Publishing...";
|
|
9505
|
+
if (saveStatus === "saved") return "Published \u2713";
|
|
9506
|
+
if (saveStatus === "error") return "Retry";
|
|
9507
|
+
if (isPublishedIdle) return "Published";
|
|
9508
|
+
return "Publish Changes";
|
|
9509
|
+
};
|
|
9510
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center", children: [
|
|
9511
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9512
|
+
"button",
|
|
9513
|
+
{
|
|
9514
|
+
type: "button",
|
|
9515
|
+
onClick: onPublish,
|
|
9516
|
+
disabled: isDisabled,
|
|
9517
|
+
className: `${getBtnClass()} ${!children ? "rounded-r-lg border-r border-[var(--kyro-border)]" : ""}`,
|
|
9518
|
+
children: [
|
|
9519
|
+
saveStatus === "saving" && /* @__PURE__ */ jsxRuntime.jsx(Spinner, { size: "sm", className: "inline mr-1.5" }),
|
|
9520
|
+
isPublishedIdle && /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", className: "inline mr-1", children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" }) }),
|
|
9521
|
+
getLabel2()
|
|
9522
|
+
]
|
|
9523
|
+
}
|
|
9524
|
+
),
|
|
9525
|
+
children && /* @__PURE__ */ jsxRuntime.jsx(
|
|
9526
|
+
Dropdown,
|
|
9527
|
+
{
|
|
9528
|
+
trigger: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: getChevronClass(), disabled: saveStatus === "saving", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" }) }) }),
|
|
9529
|
+
direction,
|
|
9530
|
+
children
|
|
9531
|
+
}
|
|
9532
|
+
)
|
|
9533
|
+
] });
|
|
9671
9534
|
}
|
|
9672
9535
|
var SeoPreview = ({ title, description, slug }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-[var(--kyro-surface)] border border-[var(--kyro-border)] rounded-lg p-6 max-w-2xl shadow-sm transition-colors duration-300", children: [
|
|
9673
9536
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-2", children: [
|
|
@@ -9689,7 +9552,7 @@ function TabsLayout({
|
|
|
9689
9552
|
onTabDataChange,
|
|
9690
9553
|
renderField
|
|
9691
9554
|
}) {
|
|
9692
|
-
const [activeTab, setActiveTab] =
|
|
9555
|
+
const [activeTab, setActiveTab] = React56.useState(0);
|
|
9693
9556
|
const fieldTabs = field3.tabs || [];
|
|
9694
9557
|
const currentTab = fieldTabs[activeTab] || fieldTabs[0];
|
|
9695
9558
|
const tabData = field3.name ? formData[field3.name] || {} : formData;
|
|
@@ -9776,8 +9639,6 @@ function AutoForm({
|
|
|
9776
9639
|
setAutoSaveStatus,
|
|
9777
9640
|
fetchVersions,
|
|
9778
9641
|
saveDocument,
|
|
9779
|
-
publishDocument,
|
|
9780
|
-
clearDraftArtifacts,
|
|
9781
9642
|
autoSaveSkipRef,
|
|
9782
9643
|
lastAutoSaveTimeRef,
|
|
9783
9644
|
documentStatus,
|
|
@@ -9792,10 +9653,16 @@ function AutoForm({
|
|
|
9792
9653
|
onActionSuccess,
|
|
9793
9654
|
onActionError
|
|
9794
9655
|
});
|
|
9795
|
-
const menuRef =
|
|
9796
|
-
const scheduleRef =
|
|
9797
|
-
const [showSchedulePicker, setShowSchedulePicker] =
|
|
9656
|
+
const menuRef = React56.useRef(null);
|
|
9657
|
+
const scheduleRef = React56.useRef(null);
|
|
9658
|
+
const [showSchedulePicker, setShowSchedulePicker] = React56.useState(false);
|
|
9659
|
+
const [localSaveStatus, setLocalSaveStatus] = React56.useState("idle");
|
|
9660
|
+
const [now, setNow] = React56.useState(Date.now());
|
|
9798
9661
|
const disabled = propDisabled;
|
|
9662
|
+
React56.useEffect(() => {
|
|
9663
|
+
const id = setInterval(() => setNow(Date.now()), 1e4);
|
|
9664
|
+
return () => clearInterval(id);
|
|
9665
|
+
}, []);
|
|
9799
9666
|
const resolveAdminFlag = (value, currentData) => {
|
|
9800
9667
|
if (typeof value === "function") {
|
|
9801
9668
|
try {
|
|
@@ -9870,7 +9737,7 @@ function AutoForm({
|
|
|
9870
9737
|
return [...prev, versionId];
|
|
9871
9738
|
});
|
|
9872
9739
|
};
|
|
9873
|
-
|
|
9740
|
+
React56.useEffect(() => {
|
|
9874
9741
|
const handleShortcuts = (e) => {
|
|
9875
9742
|
if ((e.metaKey || e.ctrlKey) && e.key === "s") {
|
|
9876
9743
|
e.preventDefault();
|
|
@@ -9893,12 +9760,12 @@ function AutoForm({
|
|
|
9893
9760
|
window.addEventListener("keydown", handleShortcuts);
|
|
9894
9761
|
return () => window.removeEventListener("keydown", handleShortcuts);
|
|
9895
9762
|
}, []);
|
|
9896
|
-
|
|
9763
|
+
React56.useEffect(() => {
|
|
9897
9764
|
const handler = () => setView("version");
|
|
9898
9765
|
window.addEventListener("kyro:show-version-history", handler);
|
|
9899
9766
|
return () => window.removeEventListener("kyro:show-version-history", handler);
|
|
9900
9767
|
}, []);
|
|
9901
|
-
|
|
9768
|
+
React56.useEffect(() => {
|
|
9902
9769
|
const handleClickOutside = (e) => {
|
|
9903
9770
|
if (menuRef.current && !menuRef.current.contains(e.target)) {
|
|
9904
9771
|
setIsMenuOpen(false);
|
|
@@ -9909,7 +9776,7 @@ function AutoForm({
|
|
|
9909
9776
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
9910
9777
|
}
|
|
9911
9778
|
}, [isMenuOpen]);
|
|
9912
|
-
|
|
9779
|
+
React56.useEffect(() => {
|
|
9913
9780
|
const handleClickOutside = (e) => {
|
|
9914
9781
|
if (scheduleRef.current && !scheduleRef.current.contains(e.target)) {
|
|
9915
9782
|
setShowSchedulePicker(false);
|
|
@@ -9990,18 +9857,16 @@ function AutoForm({
|
|
|
9990
9857
|
message: "Unpublish this document?",
|
|
9991
9858
|
onConfirm: async () => {
|
|
9992
9859
|
try {
|
|
9993
|
-
const response = await
|
|
9994
|
-
|
|
9995
|
-
|
|
9996
|
-
method: "POST"
|
|
9997
|
-
}
|
|
9860
|
+
const response = await saveDocument(
|
|
9861
|
+
{ ...formData, status: "draft" },
|
|
9862
|
+
false
|
|
9998
9863
|
);
|
|
9999
|
-
if (response
|
|
9864
|
+
if (response?.ok) {
|
|
10000
9865
|
onActionSuccess?.("Document unpublished successfully");
|
|
10001
9866
|
location.reload();
|
|
10002
9867
|
} else {
|
|
10003
|
-
const error = await response
|
|
10004
|
-
toast.error(error
|
|
9868
|
+
const error = await response?.json().catch(() => ({}));
|
|
9869
|
+
toast.error(error?.error || "Failed to unpublish");
|
|
10005
9870
|
}
|
|
10006
9871
|
} catch (err) {
|
|
10007
9872
|
toast.error("Failed to unpublish");
|
|
@@ -10012,12 +9877,7 @@ function AutoForm({
|
|
|
10012
9877
|
const handleSaveDraft = async () => {
|
|
10013
9878
|
const isNewDoc = !formData.id;
|
|
10014
9879
|
autoSaveSkipRef.current = true;
|
|
10015
|
-
|
|
10016
|
-
const originalText = btn?.textContent || "";
|
|
10017
|
-
if (btn) {
|
|
10018
|
-
btn.textContent = "Saving...";
|
|
10019
|
-
btn.setAttribute("disabled", "true");
|
|
10020
|
-
}
|
|
9880
|
+
setLocalSaveStatus("saving");
|
|
10021
9881
|
try {
|
|
10022
9882
|
const data = normalizeUploadFields({ ...formData });
|
|
10023
9883
|
const isPost = isNewDoc && !globalSlug;
|
|
@@ -10033,9 +9893,12 @@ function AutoForm({
|
|
|
10033
9893
|
setLastSavedData({ ...formData, ...savedData });
|
|
10034
9894
|
lastAutoSaveTimeRef.current = Date.now();
|
|
10035
9895
|
setAutoSaveStatus("success");
|
|
10036
|
-
|
|
9896
|
+
setLocalSaveStatus("saved");
|
|
10037
9897
|
if (versionsEnabled) fetchVersions();
|
|
10038
|
-
setTimeout(() =>
|
|
9898
|
+
setTimeout(() => {
|
|
9899
|
+
setAutoSaveStatus("idle");
|
|
9900
|
+
setLocalSaveStatus("idle");
|
|
9901
|
+
}, 2e3);
|
|
10039
9902
|
onActionSuccess?.(
|
|
10040
9903
|
isPost ? "Document created successfully" : "Changes saved"
|
|
10041
9904
|
);
|
|
@@ -10049,78 +9912,63 @@ function AutoForm({
|
|
|
10049
9912
|
if (response.status === 409) {
|
|
10050
9913
|
setAutoSaveStatus("conflict");
|
|
10051
9914
|
}
|
|
9915
|
+
setLocalSaveStatus("error");
|
|
10052
9916
|
toast.error(error.error || "Failed to save");
|
|
9917
|
+
setTimeout(() => setLocalSaveStatus("idle"), 3e3);
|
|
10053
9918
|
}
|
|
10054
9919
|
} catch (err) {
|
|
9920
|
+
setLocalSaveStatus("error");
|
|
10055
9921
|
toast.error("Failed to save document");
|
|
9922
|
+
setTimeout(() => setLocalSaveStatus("idle"), 3e3);
|
|
10056
9923
|
} finally {
|
|
10057
9924
|
autoSaveSkipRef.current = false;
|
|
10058
|
-
if (btn) {
|
|
10059
|
-
btn.textContent = originalText;
|
|
10060
|
-
btn.removeAttribute("disabled");
|
|
10061
|
-
}
|
|
10062
9925
|
}
|
|
10063
9926
|
};
|
|
10064
9927
|
const handlePublish = async () => {
|
|
10065
9928
|
const isNewDoc = !formData.id;
|
|
10066
9929
|
autoSaveSkipRef.current = true;
|
|
10067
|
-
|
|
10068
|
-
const originalText = btn?.textContent || "";
|
|
10069
|
-
if (btn) {
|
|
10070
|
-
btn.textContent = "Publishing...";
|
|
10071
|
-
btn.setAttribute("disabled", "true");
|
|
10072
|
-
}
|
|
9930
|
+
setLocalSaveStatus("saving");
|
|
10073
9931
|
try {
|
|
10074
9932
|
if (isNewDoc && !globalSlug) {
|
|
10075
|
-
const
|
|
9933
|
+
const data2 = normalizeUploadFields({ ...formData });
|
|
10076
9934
|
const response2 = await fetchWithAuth(`/api/${collectionSlug}`, {
|
|
10077
9935
|
method: "POST",
|
|
10078
9936
|
headers: { "Content-Type": "application/json" },
|
|
10079
|
-
body: JSON.stringify(
|
|
9937
|
+
body: JSON.stringify(data2)
|
|
10080
9938
|
});
|
|
10081
9939
|
if (!response2.ok) {
|
|
10082
9940
|
const error = await response2.json().catch(() => ({}));
|
|
10083
9941
|
if (response2.status === 409) setAutoSaveStatus("conflict");
|
|
9942
|
+
setLocalSaveStatus("error");
|
|
10084
9943
|
toast.error(error.error || "Failed to create document");
|
|
9944
|
+
setTimeout(() => setLocalSaveStatus("idle"), 3e3);
|
|
10085
9945
|
return;
|
|
10086
9946
|
}
|
|
10087
9947
|
const result = await response2.json();
|
|
10088
|
-
const savedData = result.data ||
|
|
9948
|
+
const savedData = result.data || data2;
|
|
10089
9949
|
setFormData({ ...formData, ...savedData });
|
|
10090
9950
|
setLastSavedData({ ...formData, ...savedData });
|
|
10091
|
-
} else if (hasUnsavedChanges) {
|
|
10092
|
-
const response2 = await saveDocument(formData);
|
|
10093
|
-
if (!response2.ok) {
|
|
10094
|
-
const error = await response2.json().catch(() => ({}));
|
|
10095
|
-
if (response2.status === 409) setAutoSaveStatus("conflict");
|
|
10096
|
-
toast.error(error.error || "Failed to save before publishing");
|
|
10097
|
-
return;
|
|
10098
|
-
}
|
|
10099
|
-
const result = await response2.json();
|
|
10100
|
-
if (result.data) {
|
|
10101
|
-
setFormData({ ...formData, ...result.data });
|
|
10102
|
-
setLastSavedData({ ...formData, ...result.data });
|
|
10103
|
-
}
|
|
10104
9951
|
}
|
|
10105
|
-
const
|
|
10106
|
-
|
|
10107
|
-
|
|
9952
|
+
const data = normalizeUploadFields({ ...formData });
|
|
9953
|
+
const response = await saveDocument(data, false);
|
|
9954
|
+
if (response?.ok) {
|
|
9955
|
+
setLocalSaveStatus("saved");
|
|
10108
9956
|
onActionSuccess?.("Published successfully");
|
|
10109
|
-
await new Promise((r) => setTimeout(r,
|
|
9957
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
10110
9958
|
location.reload();
|
|
10111
9959
|
} else {
|
|
10112
|
-
const error = await response
|
|
10113
|
-
if (response
|
|
10114
|
-
|
|
9960
|
+
const error = await response?.json().catch(() => ({}));
|
|
9961
|
+
if (response?.status === 409) setAutoSaveStatus("conflict");
|
|
9962
|
+
setLocalSaveStatus("error");
|
|
9963
|
+
toast.error(error?.error || "Failed to publish");
|
|
9964
|
+
setTimeout(() => setLocalSaveStatus("idle"), 3e3);
|
|
10115
9965
|
}
|
|
10116
9966
|
} catch (err) {
|
|
9967
|
+
setLocalSaveStatus("error");
|
|
10117
9968
|
toast.error("Failed to publish");
|
|
9969
|
+
setTimeout(() => setLocalSaveStatus("idle"), 3e3);
|
|
10118
9970
|
} finally {
|
|
10119
9971
|
autoSaveSkipRef.current = false;
|
|
10120
|
-
if (btn) {
|
|
10121
|
-
btn.textContent = originalText;
|
|
10122
|
-
btn.removeAttribute("disabled");
|
|
10123
|
-
}
|
|
10124
9972
|
}
|
|
10125
9973
|
};
|
|
10126
9974
|
const handleSchedulePublish = async (scheduledFor) => {
|
|
@@ -10437,12 +10285,12 @@ function AutoForm({
|
|
|
10437
10285
|
const docTitle = String(
|
|
10438
10286
|
formData.mainTabs?.title || (typeof formData.title === "object" ? "" : formData.title) || (typeof formData.name === "object" ? "" : formData.name) || "Untitled"
|
|
10439
10287
|
);
|
|
10440
|
-
const docStatus = documentStatus ?? formData.
|
|
10288
|
+
const docStatus = documentStatus ?? formData.status ?? "draft";
|
|
10441
10289
|
const isNew = !formData.id;
|
|
10442
10290
|
const lastModified = formData.updatedAt ? new Date(formData.updatedAt).toLocaleString() : "Just now";
|
|
10443
10291
|
const createdAt = formData.createdAt ? new Date(formData.createdAt).toLocaleString() : "Just now";
|
|
10444
|
-
|
|
10445
|
-
const statusLabel = hasUnpublishedChanges ?
|
|
10292
|
+
!formData.id || documentStatus === "draft";
|
|
10293
|
+
const statusLabel = hasUnpublishedChanges ? "Draft (unpublished changes)" : docStatus === "published" ? "Published" : "Draft";
|
|
10446
10294
|
const statusColor = docStatus === "published" && !hasUnsavedChanges ? "bg-[var(--kyro-success)]" : hasUnpublishedChanges ? "bg-[var(--kyro-warning)]" : "bg-[var(--kyro-text-muted)]";
|
|
10447
10295
|
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";
|
|
10448
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: [
|
|
@@ -10453,24 +10301,7 @@ function AutoForm({
|
|
|
10453
10301
|
{
|
|
10454
10302
|
href: `/${collectionSlug}`,
|
|
10455
10303
|
className: "p-2 border border-[var(--kyro-border)] rounded-xl hover:bg-[var(--kyro-bg-secondary)] transition-colors",
|
|
10456
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10457
|
-
"svg",
|
|
10458
|
-
{
|
|
10459
|
-
className: "w-4 h-4",
|
|
10460
|
-
fill: "none",
|
|
10461
|
-
stroke: "currentColor",
|
|
10462
|
-
viewBox: "0 0 24 24",
|
|
10463
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10464
|
-
"path",
|
|
10465
|
-
{
|
|
10466
|
-
strokeLinecap: "round",
|
|
10467
|
-
strokeLinejoin: "round",
|
|
10468
|
-
strokeWidth: "2.5",
|
|
10469
|
-
d: "M15 19l-7-7 7-7"
|
|
10470
|
-
}
|
|
10471
|
-
)
|
|
10472
|
-
}
|
|
10473
|
-
)
|
|
10304
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "w-4 h-4" })
|
|
10474
10305
|
}
|
|
10475
10306
|
),
|
|
10476
10307
|
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-bold tracking-tighter", children: docTitle }),
|
|
@@ -10513,18 +10344,7 @@ function AutoForm({
|
|
|
10513
10344
|
"Saving draft..."
|
|
10514
10345
|
] }),
|
|
10515
10346
|
autoSaveStatus === "success" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[var(--kyro-success)] flex items-center gap-1", children: [
|
|
10516
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10517
|
-
"svg",
|
|
10518
|
-
{
|
|
10519
|
-
width: "12",
|
|
10520
|
-
height: "12",
|
|
10521
|
-
viewBox: "0 0 24 24",
|
|
10522
|
-
fill: "none",
|
|
10523
|
-
stroke: "currentColor",
|
|
10524
|
-
strokeWidth: "3",
|
|
10525
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 6L9 17l-5-5" })
|
|
10526
|
-
}
|
|
10527
|
-
),
|
|
10347
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "w-4 h-4" }),
|
|
10528
10348
|
lastSavedAt ? `Saved ${Math.floor((Date.now() - lastSavedAt) / 6e4)}m ago` : "Draft saved"
|
|
10529
10349
|
] }),
|
|
10530
10350
|
autoSaveStatus === "retrying" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[var(--kyro-warning)] flex items-center gap-1.5", children: [
|
|
@@ -10584,13 +10404,23 @@ function AutoForm({
|
|
|
10584
10404
|
onClick: async () => {
|
|
10585
10405
|
setFormData(lastSavedData);
|
|
10586
10406
|
markSaved();
|
|
10587
|
-
await clearDraftArtifacts();
|
|
10588
10407
|
},
|
|
10589
10408
|
className: "text-[var(--kyro-primary)] hover:underline",
|
|
10590
10409
|
children: "Revert changes"
|
|
10591
10410
|
}
|
|
10592
10411
|
)
|
|
10593
10412
|
] }),
|
|
10413
|
+
lastSavedAt && autoSaveStatus !== "saving" && autoSaveStatus !== "retrying" && autoSaveStatus !== "success" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "border-l border-[var(--kyro-border)] pl-4", children: [
|
|
10414
|
+
"Draft saved ",
|
|
10415
|
+
(() => {
|
|
10416
|
+
const diffMs = now - lastSavedAt;
|
|
10417
|
+
const diffMin = Math.floor(diffMs / 6e4);
|
|
10418
|
+
const diffSec = Math.floor(diffMs / 1e3);
|
|
10419
|
+
if (diffMin >= 1) return `${diffMin}m ago`;
|
|
10420
|
+
if (diffSec >= 5) return `${diffSec}s ago`;
|
|
10421
|
+
return "just now";
|
|
10422
|
+
})()
|
|
10423
|
+
] }),
|
|
10594
10424
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "border-l border-[var(--kyro-border)] pl-4", children: [
|
|
10595
10425
|
"Modified ",
|
|
10596
10426
|
lastModified
|
|
@@ -10622,18 +10452,7 @@ function AutoForm({
|
|
|
10622
10452
|
className: `kyro-btn p-2.5 rounded-xl transition-all flex items-center gap-2 ${showPreview ? "shadow-lg" : "text-[var(--kyro-text-secondary)] hover:bg-[var(--kyro-bg-secondary)]"}`,
|
|
10623
10453
|
title: "Live Preview",
|
|
10624
10454
|
children: [
|
|
10625
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10626
|
-
"svg",
|
|
10627
|
-
{
|
|
10628
|
-
width: "20",
|
|
10629
|
-
height: "20",
|
|
10630
|
-
viewBox: "0 0 24 24",
|
|
10631
|
-
fill: "none",
|
|
10632
|
-
stroke: "currentColor",
|
|
10633
|
-
strokeWidth: "2",
|
|
10634
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6M15 3h6v6M10 14L21 3" })
|
|
10635
|
-
}
|
|
10636
|
-
),
|
|
10455
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "w-4 h-4" }),
|
|
10637
10456
|
showPreview && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold tracking-widest pr-1", children: "Active" })
|
|
10638
10457
|
]
|
|
10639
10458
|
}
|
|
@@ -10664,164 +10483,98 @@ function AutoForm({
|
|
|
10664
10483
|
)
|
|
10665
10484
|
}
|
|
10666
10485
|
),
|
|
10667
|
-
|
|
10668
|
-
|
|
10669
|
-
|
|
10670
|
-
|
|
10671
|
-
|
|
10672
|
-
|
|
10486
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10487
|
+
SplitButton,
|
|
10488
|
+
{
|
|
10489
|
+
status: documentStatus,
|
|
10490
|
+
saveStatus: localSaveStatus,
|
|
10491
|
+
hasChanges: hasUnsavedChanges,
|
|
10492
|
+
onPublish: handlePublish,
|
|
10493
|
+
disabled: localSaveStatus === "saving"
|
|
10494
|
+
}
|
|
10495
|
+
),
|
|
10496
|
+
!isNew && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10497
|
+
Dropdown,
|
|
10498
|
+
{
|
|
10499
|
+
trigger: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10673
10500
|
"button",
|
|
10674
10501
|
{
|
|
10675
|
-
id: "btn-publish",
|
|
10676
10502
|
type: "button",
|
|
10677
|
-
|
|
10678
|
-
|
|
10679
|
-
children:
|
|
10503
|
+
className: "kyro-btn p-2.5 rounded-xl border border-[var(--kyro-border)] hover:bg-[var(--kyro-bg-secondary)] transition-all",
|
|
10504
|
+
title: "More actions",
|
|
10505
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: [
|
|
10506
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "5", r: "1.5" }),
|
|
10507
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "1.5" }),
|
|
10508
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "19", r: "1.5" })
|
|
10509
|
+
] })
|
|
10680
10510
|
}
|
|
10681
10511
|
),
|
|
10682
|
-
|
|
10683
|
-
|
|
10684
|
-
|
|
10685
|
-
|
|
10686
|
-
|
|
10687
|
-
|
|
10688
|
-
|
|
10689
|
-
|
|
10690
|
-
|
|
10691
|
-
] }),
|
|
10692
|
-
isMenuOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 top-full mt-2 w-56 rounded-lg border border-[var(--kyro-border)] bg-[var(--kyro-surface)] shadow-2xl z-50 overflow-hidden", children: [
|
|
10693
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10694
|
-
"button",
|
|
10695
|
-
{
|
|
10696
|
-
type: "button",
|
|
10697
|
-
onClick: () => {
|
|
10698
|
-
handleSaveDraft();
|
|
10699
|
-
setIsMenuOpen(false);
|
|
10700
|
-
},
|
|
10701
|
-
className: "w-full px-4 py-2.5 text-left text-xs font-medium text-[var(--kyro-text-primary)] hover:bg-[var(--kyro-surface-accent)] flex items-center gap-3 transition-colors",
|
|
10702
|
-
children: [
|
|
10703
|
-
/* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
10704
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z" }),
|
|
10705
|
-
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "17 21 17 13 7 13 7 21" }),
|
|
10706
|
-
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "7 3 7 8 15 8" })
|
|
10512
|
+
direction: "down",
|
|
10513
|
+
children: [
|
|
10514
|
+
!globalSlug && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10515
|
+
DropdownItem,
|
|
10516
|
+
{
|
|
10517
|
+
onClick: handleCreateNew,
|
|
10518
|
+
icon: /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
10519
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
|
|
10520
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
|
|
10707
10521
|
] }),
|
|
10708
|
-
"
|
|
10709
|
-
|
|
10710
|
-
|
|
10711
|
-
|
|
10712
|
-
|
|
10713
|
-
|
|
10714
|
-
|
|
10715
|
-
|
|
10716
|
-
|
|
10717
|
-
|
|
10718
|
-
|
|
10719
|
-
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
|
|
10724
|
-
|
|
10725
|
-
|
|
10726
|
-
|
|
10727
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10728
|
-
"button",
|
|
10729
|
-
{
|
|
10730
|
-
type: "button",
|
|
10731
|
-
onClick: () => {
|
|
10732
|
-
setIsMenuOpen(false);
|
|
10733
|
-
setShowSchedulePicker(true);
|
|
10734
|
-
},
|
|
10735
|
-
className: "w-full px-4 py-2.5 text-left text-xs font-medium text-[var(--kyro-text-primary)] hover:bg-[var(--kyro-surface-accent)] flex items-center gap-3 transition-colors",
|
|
10736
|
-
children: [
|
|
10737
|
-
/* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
10522
|
+
children: "Create New"
|
|
10523
|
+
}
|
|
10524
|
+
),
|
|
10525
|
+
!globalSlug && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10526
|
+
DropdownItem,
|
|
10527
|
+
{
|
|
10528
|
+
onClick: handleDuplicate,
|
|
10529
|
+
icon: /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
10530
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
|
|
10531
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
|
|
10532
|
+
] }),
|
|
10533
|
+
children: "Duplicate"
|
|
10534
|
+
}
|
|
10535
|
+
),
|
|
10536
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10537
|
+
DropdownItem,
|
|
10538
|
+
{
|
|
10539
|
+
onClick: () => setShowSchedulePicker(true),
|
|
10540
|
+
icon: /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
10738
10541
|
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }),
|
|
10739
10542
|
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "16", y1: "2", x2: "16", y2: "6" }),
|
|
10740
10543
|
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "8", y1: "2", x2: "8", y2: "6" }),
|
|
10741
10544
|
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "3", y1: "10", x2: "21", y2: "10" })
|
|
10742
10545
|
] }),
|
|
10743
|
-
"Schedule Publish"
|
|
10744
|
-
]
|
|
10745
|
-
}
|
|
10746
|
-
),
|
|
10747
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px bg-[var(--kyro-border)]" }),
|
|
10748
|
-
!globalSlug && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10749
|
-
"button",
|
|
10750
|
-
{
|
|
10751
|
-
type: "button",
|
|
10752
|
-
onClick: () => {
|
|
10753
|
-
handleCreateNew();
|
|
10754
|
-
setIsMenuOpen(false);
|
|
10755
|
-
},
|
|
10756
|
-
className: "w-full px-4 py-2.5 text-left text-xs font-medium text-[var(--kyro-text-primary)] hover:bg-[var(--kyro-surface-accent)] flex items-center gap-3 transition-colors",
|
|
10757
|
-
children: [
|
|
10758
|
-
/* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
10759
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
|
|
10760
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
|
|
10761
|
-
] }),
|
|
10762
|
-
"Create New"
|
|
10763
|
-
]
|
|
10764
|
-
}
|
|
10765
|
-
),
|
|
10766
|
-
!isNew && !globalSlug && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10767
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10768
|
-
"button",
|
|
10769
|
-
{
|
|
10770
|
-
type: "button",
|
|
10771
|
-
onClick: () => {
|
|
10772
|
-
handleDuplicate();
|
|
10773
|
-
setIsMenuOpen(false);
|
|
10774
|
-
},
|
|
10775
|
-
className: "w-full px-4 py-2.5 text-left text-xs font-medium text-[var(--kyro-text-primary)] hover:bg-[var(--kyro-surface-accent)] flex items-center gap-3 transition-colors",
|
|
10776
|
-
children: [
|
|
10777
|
-
/* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
10778
|
-
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
|
|
10779
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
|
|
10780
|
-
] }),
|
|
10781
|
-
"Duplicate"
|
|
10782
|
-
]
|
|
10546
|
+
children: "Schedule Publish"
|
|
10783
10547
|
}
|
|
10784
10548
|
),
|
|
10785
|
-
documentStatus === "published" && /* @__PURE__ */ jsxRuntime.
|
|
10786
|
-
|
|
10549
|
+
documentStatus === "published" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10550
|
+
DropdownItem,
|
|
10787
10551
|
{
|
|
10788
|
-
|
|
10789
|
-
|
|
10790
|
-
|
|
10791
|
-
|
|
10792
|
-
},
|
|
10793
|
-
|
|
10794
|
-
children: [
|
|
10795
|
-
/* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
10796
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24" }),
|
|
10797
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "1", y1: "1", x2: "23", y2: "23" })
|
|
10798
|
-
] }),
|
|
10799
|
-
"Unpublish"
|
|
10800
|
-
]
|
|
10552
|
+
onClick: handleUnpublish,
|
|
10553
|
+
icon: /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
10554
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24" }),
|
|
10555
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "1", y1: "1", x2: "23", y2: "23" })
|
|
10556
|
+
] }),
|
|
10557
|
+
children: "Unpublish"
|
|
10801
10558
|
}
|
|
10802
10559
|
),
|
|
10803
|
-
/* @__PURE__ */ jsxRuntime.
|
|
10804
|
-
|
|
10805
|
-
|
|
10806
|
-
|
|
10807
|
-
|
|
10808
|
-
|
|
10809
|
-
|
|
10810
|
-
|
|
10811
|
-
},
|
|
10812
|
-
className: "w-full px-4 py-2.5 text-left text-xs font-medium text-red-600 hover:bg-red-50 flex items-center gap-3 transition-colors",
|
|
10813
|
-
children: [
|
|
10814
|
-
/* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
10560
|
+
!globalSlug && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10561
|
+
/* @__PURE__ */ jsxRuntime.jsx(DropdownSeparator, {}),
|
|
10562
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10563
|
+
DropdownItem,
|
|
10564
|
+
{
|
|
10565
|
+
onClick: handleDelete,
|
|
10566
|
+
danger: true,
|
|
10567
|
+
icon: /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
10815
10568
|
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "3 6 5 6 21 6" }),
|
|
10816
10569
|
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
|
|
10817
10570
|
] }),
|
|
10818
|
-
"Delete"
|
|
10819
|
-
|
|
10820
|
-
|
|
10821
|
-
)
|
|
10822
|
-
]
|
|
10823
|
-
|
|
10824
|
-
|
|
10571
|
+
children: "Delete"
|
|
10572
|
+
}
|
|
10573
|
+
)
|
|
10574
|
+
] })
|
|
10575
|
+
]
|
|
10576
|
+
}
|
|
10577
|
+
),
|
|
10825
10578
|
showSchedulePicker && /* @__PURE__ */ jsxRuntime.jsx("div", { ref: scheduleRef, className: "relative", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 top-2 p-4 rounded-lg border border-[var(--kyro-border)] bg-[var(--kyro-surface)] shadow-2xl z-50", children: [
|
|
10826
10579
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium mb-2", children: "Schedule Publish" }),
|
|
10827
10580
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -10941,17 +10694,7 @@ function AutoForm({
|
|
|
10941
10694
|
type: "button",
|
|
10942
10695
|
onClick: () => setCompareDiffs([]),
|
|
10943
10696
|
className: "p-1 rounded hover:bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-muted)]",
|
|
10944
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10945
|
-
"svg",
|
|
10946
|
-
{
|
|
10947
|
-
className: "w-3.5 h-3.5",
|
|
10948
|
-
viewBox: "0 0 24 24",
|
|
10949
|
-
fill: "none",
|
|
10950
|
-
stroke: "currentColor",
|
|
10951
|
-
strokeWidth: "2.5",
|
|
10952
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6L6 18M6 6l12 12" })
|
|
10953
|
-
}
|
|
10954
|
-
)
|
|
10697
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" })
|
|
10955
10698
|
}
|
|
10956
10699
|
)
|
|
10957
10700
|
] }),
|
|
@@ -10982,17 +10725,7 @@ function AutoForm({
|
|
|
10982
10725
|
"div",
|
|
10983
10726
|
{
|
|
10984
10727
|
className: `w-4 h-4 rounded-full border ${isSelected ? "border-[var(--kyro-primary)] bg-[var(--kyro-primary)]" : "border-[var(--kyro-border)]"}`,
|
|
10985
|
-
children: isSelected && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10986
|
-
"svg",
|
|
10987
|
-
{
|
|
10988
|
-
className: "w-full h-full text-white p-0.5",
|
|
10989
|
-
viewBox: "0 0 24 24",
|
|
10990
|
-
fill: "none",
|
|
10991
|
-
stroke: "currentColor",
|
|
10992
|
-
strokeWidth: "3",
|
|
10993
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 6L9 17l-5-5" })
|
|
10994
|
-
}
|
|
10995
|
-
)
|
|
10728
|
+
children: isSelected && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "w-4 h-4" })
|
|
10996
10729
|
}
|
|
10997
10730
|
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold text-[var(--kyro-text-muted)] w-5", children: versions.length - i }) }),
|
|
10998
10731
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-4 min-w-0", children: [
|
|
@@ -11085,18 +10818,7 @@ function AutoForm({
|
|
|
11085
10818
|
"div",
|
|
11086
10819
|
{
|
|
11087
10820
|
className: `w-4 h-4 rounded border transition-all flex items-center justify-center ${item.checked ? "bg-[var(--kyro-primary)] border-[var(--kyro-primary)]" : "border-[var(--kyro-border)] group-hover:border-[var(--kyro-text-secondary)]"}`,
|
|
11088
|
-
children: item.checked && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11089
|
-
"svg",
|
|
11090
|
-
{
|
|
11091
|
-
width: "10",
|
|
11092
|
-
height: "10",
|
|
11093
|
-
viewBox: "0 0 24 24",
|
|
11094
|
-
fill: "none",
|
|
11095
|
-
stroke: "white",
|
|
11096
|
-
strokeWidth: "4",
|
|
11097
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 6L9 17l-5-5" })
|
|
11098
|
-
}
|
|
11099
|
-
)
|
|
10821
|
+
children: item.checked && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "w-4 h-4" })
|
|
11100
10822
|
}
|
|
11101
10823
|
),
|
|
11102
10824
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-[var(--kyro-text-secondary)] group-hover:text-[var(--kyro-text-primary)] transition-colors", children: item.label })
|
|
@@ -11131,7 +10853,7 @@ function AutoForm({
|
|
|
11131
10853
|
"Saving..."
|
|
11132
10854
|
] }),
|
|
11133
10855
|
autoSaveStatus === "success" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[var(--kyro-success)] flex items-center gap-1", children: [
|
|
11134
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10856
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "w-4 h-4" }),
|
|
11135
10857
|
lastSavedAt ? `Saved ${Math.floor((Date.now() - lastSavedAt) / 6e4)}m ago` : "Saved"
|
|
11136
10858
|
] }),
|
|
11137
10859
|
autoSaveStatus === "retrying" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[var(--kyro-warning)] flex items-center gap-1.5", children: [
|
|
@@ -11156,85 +10878,29 @@ function AutoForm({
|
|
|
11156
10878
|
type: "button",
|
|
11157
10879
|
style: { width: 0, height: 0, opacity: 0, padding: 0, margin: 0, border: "none", position: "absolute" },
|
|
11158
10880
|
onClick: async () => {
|
|
11159
|
-
console.log("[AutoForm] Hidden save button clicked");
|
|
11160
10881
|
try {
|
|
11161
10882
|
const response = await saveDocument();
|
|
11162
10883
|
if (response.ok) {
|
|
11163
|
-
const result = await response.json();
|
|
11164
|
-
const savedData = result.data || formData;
|
|
11165
|
-
setFormData({ ...formData, ...savedData });
|
|
11166
|
-
setLastSavedData({ ...formData, ...savedData });
|
|
11167
|
-
onActionSuccess?.("Changes saved");
|
|
11168
|
-
}
|
|
11169
|
-
} catch (e) {
|
|
11170
|
-
console.error("Save error exception:", e);
|
|
11171
|
-
onActionError?.("Save failed: " + e.message);
|
|
11172
|
-
}
|
|
11173
|
-
}
|
|
11174
|
-
}
|
|
11175
|
-
)
|
|
11176
|
-
] }),
|
|
11177
|
-
/* @__PURE__ */ jsxRuntime.jsxs("main", { className: "w-full", children: [
|
|
11178
|
-
view === "edit" && renderEditView(),
|
|
11179
|
-
view === "version" && renderVersionView(),
|
|
11180
|
-
view === "api" && renderApiView()
|
|
11181
|
-
] })
|
|
11182
|
-
] });
|
|
11183
|
-
}
|
|
11184
|
-
function Dropdown({
|
|
11185
|
-
trigger,
|
|
11186
|
-
children,
|
|
11187
|
-
align = "right"
|
|
11188
|
-
}) {
|
|
11189
|
-
const [open, setOpen] = React54.useState(false);
|
|
11190
|
-
const ref = React54.useRef(null);
|
|
11191
|
-
React54.useEffect(() => {
|
|
11192
|
-
const handleClickOutside = (e) => {
|
|
11193
|
-
if (ref.current && !ref.current.contains(e.target)) {
|
|
11194
|
-
setOpen(false);
|
|
11195
|
-
}
|
|
11196
|
-
};
|
|
11197
|
-
if (open) {
|
|
11198
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
11199
|
-
}
|
|
11200
|
-
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
11201
|
-
}, [open]);
|
|
11202
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", ref, children: [
|
|
11203
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { onClick: () => setOpen(!open), className: "cursor-pointer", children: trigger }),
|
|
11204
|
-
open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11205
|
-
"div",
|
|
11206
|
-
{
|
|
11207
|
-
className: `absolute z-[100] mt-2 min-w-[200px] py-2 bg-[var(--kyro-surface)] rounded-2xl shadow-2xl border border-[var(--kyro-border)] animate-in fade-in zoom-in-95 duration-100 ${align === "right" ? "right-0 bottom-full mb-2" : "left-0 bottom-full mb-2"}`,
|
|
11208
|
-
onClick: () => setOpen(false),
|
|
11209
|
-
children
|
|
11210
|
-
}
|
|
11211
|
-
)
|
|
11212
|
-
] });
|
|
11213
|
-
}
|
|
11214
|
-
function DropdownItem({
|
|
11215
|
-
children,
|
|
11216
|
-
onClick,
|
|
11217
|
-
icon,
|
|
11218
|
-
danger,
|
|
11219
|
-
disabled,
|
|
11220
|
-
className = ""
|
|
11221
|
-
}) {
|
|
11222
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-1.5", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11223
|
-
"button",
|
|
11224
|
-
{
|
|
11225
|
-
type: "button",
|
|
11226
|
-
onClick,
|
|
11227
|
-
disabled,
|
|
11228
|
-
className: `w-full flex items-center gap-3 px-3 py-2.5 text-[11px] font-medium tracking-wide text-left transition-all rounded-xl ${danger ? "text-red-500 hover:bg-red-500/10" : "text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-text-primary)] hover:bg-[var(--kyro-surface-accent)]"} ${disabled ? "opacity-50 cursor-not-allowed" : ""} ${className}`,
|
|
11229
|
-
children: [
|
|
11230
|
-
icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-4 h-4 opacity-70", children: icon }),
|
|
11231
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children })
|
|
11232
|
-
]
|
|
11233
|
-
}
|
|
11234
|
-
) });
|
|
11235
|
-
}
|
|
11236
|
-
function DropdownSeparator() {
|
|
11237
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "my-1 border-t border-[var(--kyro-border)] opacity-50" });
|
|
10884
|
+
const result = await response.json();
|
|
10885
|
+
const savedData = result.data || formData;
|
|
10886
|
+
setFormData({ ...formData, ...savedData });
|
|
10887
|
+
setLastSavedData({ ...formData, ...savedData });
|
|
10888
|
+
onActionSuccess?.("Changes saved");
|
|
10889
|
+
}
|
|
10890
|
+
} catch (e) {
|
|
10891
|
+
console.error("Save error exception:", e);
|
|
10892
|
+
onActionError?.("Save failed: " + e.message);
|
|
10893
|
+
}
|
|
10894
|
+
}
|
|
10895
|
+
}
|
|
10896
|
+
)
|
|
10897
|
+
] }),
|
|
10898
|
+
/* @__PURE__ */ jsxRuntime.jsxs("main", { className: "w-full", children: [
|
|
10899
|
+
view === "edit" && renderEditView(),
|
|
10900
|
+
view === "version" && renderVersionView(),
|
|
10901
|
+
view === "api" && renderApiView()
|
|
10902
|
+
] })
|
|
10903
|
+
] });
|
|
11238
10904
|
}
|
|
11239
10905
|
function ActionBar({
|
|
11240
10906
|
status,
|
|
@@ -11257,82 +10923,27 @@ function ActionBar({
|
|
|
11257
10923
|
if (hasChanges) return "Unsaved changes";
|
|
11258
10924
|
return null;
|
|
11259
10925
|
};
|
|
11260
|
-
const getSaveButtonClass = () => {
|
|
11261
|
-
const base = "kyro-btn kyro-btn-md text-[11px] font-bold tracking-widest transition-all duration-300";
|
|
11262
|
-
if (saveStatus === "saving") return `${base} bg-[var(--kyro-gray-400)] text-white opacity-70 cursor-wait`;
|
|
11263
|
-
if (saveStatus === "saved") return `${base} bg-[var(--kyro-success)] border-[var(--kyro-success)] text-white shadow-[0_0_15px_rgba(34,197,94,0.3)]`;
|
|
11264
|
-
if (saveStatus === "error") return `${base} bg-[var(--kyro-error)] border-[var(--kyro-error)] text-white shadow-[0_0_15px_rgba(239,68,68,0.3)]`;
|
|
11265
|
-
if (hasChanges) return `${base} bg-[var(--kyro-warning)] border-[var(--kyro-warning)] text-black shadow-[0_0_15px_rgba(255,174,0,0.3)] animate-pulse`;
|
|
11266
|
-
return `${base} bg-[var(--kyro-gray-500)] border-[var(--kyro-gray-500)] text-white hover:bg-[var(--kyro-gray-600)]`;
|
|
11267
|
-
};
|
|
11268
10926
|
const getStatusBadge = () => {
|
|
11269
10927
|
const statusConfig2 = {
|
|
11270
10928
|
draft: {
|
|
11271
10929
|
label: "Draft",
|
|
11272
10930
|
class: "bg-gray-100 text-gray-600 border-gray-200",
|
|
11273
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11274
|
-
"svg",
|
|
11275
|
-
{
|
|
11276
|
-
width: "12",
|
|
11277
|
-
height: "12",
|
|
11278
|
-
viewBox: "0 0 24 24",
|
|
11279
|
-
fill: "none",
|
|
11280
|
-
stroke: "currentColor",
|
|
11281
|
-
strokeWidth: "2.5",
|
|
11282
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2v20M2 12h20" })
|
|
11283
|
-
}
|
|
11284
|
-
)
|
|
10931
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "w-3 h-3" })
|
|
11285
10932
|
},
|
|
11286
10933
|
published: {
|
|
11287
10934
|
label: "Published",
|
|
11288
10935
|
class: "bg-green-100 text-green-700 border-green-200",
|
|
11289
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11290
|
-
"svg",
|
|
11291
|
-
{
|
|
11292
|
-
width: "12",
|
|
11293
|
-
height: "12",
|
|
11294
|
-
viewBox: "0 0 24 24",
|
|
11295
|
-
fill: "none",
|
|
11296
|
-
stroke: "currentColor",
|
|
11297
|
-
strokeWidth: "2.5",
|
|
11298
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z" })
|
|
11299
|
-
}
|
|
11300
|
-
)
|
|
10936
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "w-3 h-3" })
|
|
11301
10937
|
},
|
|
11302
10938
|
scheduled: {
|
|
11303
10939
|
label: "Scheduled",
|
|
11304
10940
|
class: "bg-blue-100 text-blue-700 border-blue-200",
|
|
11305
|
-
icon: /* @__PURE__ */ jsxRuntime.
|
|
11306
|
-
"svg",
|
|
11307
|
-
{
|
|
11308
|
-
width: "12",
|
|
11309
|
-
height: "12",
|
|
11310
|
-
viewBox: "0 0 24 24",
|
|
11311
|
-
fill: "none",
|
|
11312
|
-
stroke: "currentColor",
|
|
11313
|
-
strokeWidth: "2.5",
|
|
11314
|
-
children: [
|
|
11315
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
11316
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 6v6l4 2" })
|
|
11317
|
-
]
|
|
11318
|
-
}
|
|
11319
|
-
)
|
|
10941
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "w-3 h-3" })
|
|
11320
10942
|
},
|
|
11321
10943
|
archived: {
|
|
11322
10944
|
label: "Archived",
|
|
11323
10945
|
class: "bg-yellow-100 text-yellow-700 border-yellow-200",
|
|
11324
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11325
|
-
"svg",
|
|
11326
|
-
{
|
|
11327
|
-
width: "12",
|
|
11328
|
-
height: "12",
|
|
11329
|
-
viewBox: "0 0 24 24",
|
|
11330
|
-
fill: "none",
|
|
11331
|
-
stroke: "currentColor",
|
|
11332
|
-
strokeWidth: "2.5",
|
|
11333
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 8v13H3V8M1 3h22v5H1zM10 12h4" })
|
|
11334
|
-
}
|
|
11335
|
-
)
|
|
10946
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Archive, { className: "w-3 h-3" })
|
|
11336
10947
|
}
|
|
11337
10948
|
};
|
|
11338
10949
|
const config = statusConfig2[status];
|
|
@@ -11358,7 +10969,7 @@ function ActionBar({
|
|
|
11358
10969
|
getSaveStatusText() && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11359
10970
|
"span",
|
|
11360
10971
|
{
|
|
11361
|
-
className: `text-sm ${saveStatus === "error" ? "text-
|
|
10972
|
+
className: `text-sm ${saveStatus === "error" ? "text-[var(--kyro-error)]" : "text-[var(--kyro-text-muted)]"}`,
|
|
11362
10973
|
children: [
|
|
11363
10974
|
saveStatus === "saving" ? /* @__PURE__ */ jsxRuntime.jsx(Spinner, { size: "sm", className: "inline mr-1" }) : null,
|
|
11364
10975
|
getSaveStatusText()
|
|
@@ -11367,7 +10978,7 @@ function ActionBar({
|
|
|
11367
10978
|
)
|
|
11368
10979
|
] }),
|
|
11369
10980
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs space-y-0.5", children: [
|
|
11370
|
-
updatedAt && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-
|
|
10981
|
+
updatedAt && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[var(--kyro-text-muted)]", children: [
|
|
11371
10982
|
"Updated: ",
|
|
11372
10983
|
formatDate2(updatedAt)
|
|
11373
10984
|
] }),
|
|
@@ -11384,20 +10995,9 @@ function ActionBar({
|
|
|
11384
10995
|
type: "button",
|
|
11385
10996
|
onClick: onPublish,
|
|
11386
10997
|
disabled: saveStatus === "saving",
|
|
11387
|
-
className: "kyro-btn
|
|
10998
|
+
className: "kyro-btn kyro-btn-primary kyro-btn-md flex items-center gap-2",
|
|
11388
10999
|
children: [
|
|
11389
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11390
|
-
"svg",
|
|
11391
|
-
{
|
|
11392
|
-
width: "16",
|
|
11393
|
-
height: "16",
|
|
11394
|
-
viewBox: "0 0 24 24",
|
|
11395
|
-
fill: "none",
|
|
11396
|
-
stroke: "currentColor",
|
|
11397
|
-
strokeWidth: "2.5",
|
|
11398
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z" })
|
|
11399
|
-
}
|
|
11400
|
-
),
|
|
11000
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "w-4 h-4" }),
|
|
11401
11001
|
"Publish"
|
|
11402
11002
|
]
|
|
11403
11003
|
}
|
|
@@ -11408,114 +11008,39 @@ function ActionBar({
|
|
|
11408
11008
|
type: "button",
|
|
11409
11009
|
onClick: onUnpublish,
|
|
11410
11010
|
disabled: saveStatus === "saving",
|
|
11411
|
-
className: "kyro-btn kyro-btn-
|
|
11011
|
+
className: "kyro-btn kyro-btn-secondary kyro-btn-md flex items-center gap-2",
|
|
11412
11012
|
children: [
|
|
11413
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11414
|
-
"svg",
|
|
11415
|
-
{
|
|
11416
|
-
width: "16",
|
|
11417
|
-
height: "16",
|
|
11418
|
-
viewBox: "0 0 24 24",
|
|
11419
|
-
fill: "none",
|
|
11420
|
-
stroke: "currentColor",
|
|
11421
|
-
strokeWidth: "2.5",
|
|
11422
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8M3 3v5h5" })
|
|
11423
|
-
}
|
|
11424
|
-
),
|
|
11013
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Undo, { className: "w-4 h-4" }),
|
|
11425
11014
|
"Unpublish"
|
|
11426
11015
|
]
|
|
11427
11016
|
}
|
|
11428
11017
|
),
|
|
11429
|
-
status === "published" && !hasChanges && saveStatus !== "saving" && saveStatus !== "error" ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5 px-4 py-2 rounded-lg text-[11px] font-bold tracking-widest bg-green-100 text-green-700 border border-green-200 cursor-not-allowed shadow-sm", children: [
|
|
11430
|
-
/* @__PURE__ */ jsxRuntime.jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z" }) }),
|
|
11431
|
-
"Published"
|
|
11432
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
11433
|
-
"button",
|
|
11434
|
-
{
|
|
11435
|
-
type: "button",
|
|
11436
|
-
onClick: onSave,
|
|
11437
|
-
disabled: saveStatus === "saving" || !hasChanges && saveStatus !== "error",
|
|
11438
|
-
className: getSaveButtonClass(),
|
|
11439
|
-
children: saveStatus === "saving" ? "Saving..." : saveStatus === "saved" ? "Saved" : hasChanges && status === "published" ? "Save Draft" : status === "draft" && hasChanges ? "Save Draft" : "Save"
|
|
11440
|
-
}
|
|
11441
|
-
),
|
|
11442
11018
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11443
|
-
|
|
11019
|
+
SplitButton,
|
|
11444
11020
|
{
|
|
11445
|
-
|
|
11446
|
-
|
|
11447
|
-
|
|
11448
|
-
|
|
11449
|
-
height: "16",
|
|
11450
|
-
viewBox: "0 0 24 24",
|
|
11451
|
-
fill: "none",
|
|
11452
|
-
stroke: "currentColor",
|
|
11453
|
-
strokeWidth: "2",
|
|
11454
|
-
children: [
|
|
11455
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "1" }),
|
|
11456
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "5", r: "1" }),
|
|
11457
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "19", r: "1" })
|
|
11458
|
-
]
|
|
11459
|
-
}
|
|
11460
|
-
) }),
|
|
11021
|
+
status,
|
|
11022
|
+
saveStatus,
|
|
11023
|
+
hasChanges,
|
|
11024
|
+
onPublish: onSave,
|
|
11461
11025
|
children: [
|
|
11462
11026
|
onDuplicate && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11463
11027
|
DropdownItem,
|
|
11464
11028
|
{
|
|
11465
|
-
|
|
11466
|
-
icon: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11467
|
-
"svg",
|
|
11468
|
-
{
|
|
11469
|
-
viewBox: "0 0 24 24",
|
|
11470
|
-
fill: "none",
|
|
11471
|
-
stroke: "currentColor",
|
|
11472
|
-
strokeWidth: "2",
|
|
11473
|
-
children: [
|
|
11474
|
-
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }),
|
|
11475
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
|
|
11476
|
-
]
|
|
11477
|
-
}
|
|
11478
|
-
),
|
|
11029
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "w-4 h-4" }),
|
|
11479
11030
|
children: "Duplicate"
|
|
11480
11031
|
}
|
|
11481
11032
|
),
|
|
11482
11033
|
onViewHistory && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11483
11034
|
DropdownItem,
|
|
11484
11035
|
{
|
|
11485
|
-
|
|
11486
|
-
icon: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11487
|
-
"svg",
|
|
11488
|
-
{
|
|
11489
|
-
viewBox: "0 0 24 24",
|
|
11490
|
-
fill: "none",
|
|
11491
|
-
stroke: "currentColor",
|
|
11492
|
-
strokeWidth: "2",
|
|
11493
|
-
children: [
|
|
11494
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
11495
|
-
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "12,6 12,12 16,14" })
|
|
11496
|
-
]
|
|
11497
|
-
}
|
|
11498
|
-
),
|
|
11036
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "w-4 h-4" }),
|
|
11499
11037
|
children: "View History"
|
|
11500
11038
|
}
|
|
11501
11039
|
),
|
|
11502
11040
|
onPreview && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11503
11041
|
DropdownItem,
|
|
11504
11042
|
{
|
|
11505
|
-
|
|
11506
|
-
icon: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11507
|
-
"svg",
|
|
11508
|
-
{
|
|
11509
|
-
viewBox: "0 0 24 24",
|
|
11510
|
-
fill: "none",
|
|
11511
|
-
stroke: "currentColor",
|
|
11512
|
-
strokeWidth: "2",
|
|
11513
|
-
children: [
|
|
11514
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" }),
|
|
11515
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "3" })
|
|
11516
|
-
]
|
|
11517
|
-
}
|
|
11518
|
-
),
|
|
11043
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eye, { className: "w-4 h-4" }),
|
|
11519
11044
|
children: "Preview"
|
|
11520
11045
|
}
|
|
11521
11046
|
),
|
|
@@ -11525,16 +11050,7 @@ function ActionBar({
|
|
|
11525
11050
|
{
|
|
11526
11051
|
onClick: onDelete,
|
|
11527
11052
|
danger: true,
|
|
11528
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11529
|
-
"svg",
|
|
11530
|
-
{
|
|
11531
|
-
viewBox: "0 0 24 24",
|
|
11532
|
-
fill: "none",
|
|
11533
|
-
stroke: "currentColor",
|
|
11534
|
-
strokeWidth: "2",
|
|
11535
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
|
|
11536
|
-
}
|
|
11537
|
-
),
|
|
11053
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "w-4 h-4" }),
|
|
11538
11054
|
children: "Delete"
|
|
11539
11055
|
}
|
|
11540
11056
|
)
|
|
@@ -11544,62 +11060,6 @@ function ActionBar({
|
|
|
11544
11060
|
] })
|
|
11545
11061
|
] });
|
|
11546
11062
|
}
|
|
11547
|
-
function Toast({ type, message, onClose }) {
|
|
11548
|
-
const [isPaused, setIsPaused] = React54__default.default.useState(false);
|
|
11549
|
-
const timerRef = React54__default.default.useRef(null);
|
|
11550
|
-
const startTimer = () => {
|
|
11551
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
11552
|
-
timerRef.current = setTimeout(onClose, 5e3);
|
|
11553
|
-
};
|
|
11554
|
-
const clearTimer = () => {
|
|
11555
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
11556
|
-
};
|
|
11557
|
-
React54__default.default.useEffect(() => {
|
|
11558
|
-
if (!isPaused) {
|
|
11559
|
-
startTimer();
|
|
11560
|
-
} else {
|
|
11561
|
-
clearTimer();
|
|
11562
|
-
}
|
|
11563
|
-
return clearTimer;
|
|
11564
|
-
}, [isPaused, onClose]);
|
|
11565
|
-
const Icon = {
|
|
11566
|
-
success: lucideReact.CircleCheck,
|
|
11567
|
-
error: lucideReact.ShieldAlert,
|
|
11568
|
-
warning: lucideReact.TriangleAlert,
|
|
11569
|
-
info: lucideReact.Info
|
|
11570
|
-
}[type];
|
|
11571
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11572
|
-
"div",
|
|
11573
|
-
{
|
|
11574
|
-
className: `kyro-toast kyro-toast-${type} group animate-in fade-in slide-in-from-right-4 duration-300`,
|
|
11575
|
-
onMouseEnter: () => setIsPaused(true),
|
|
11576
|
-
onMouseLeave: () => setIsPaused(false),
|
|
11577
|
-
children: [
|
|
11578
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "kyro-toast-accent" }),
|
|
11579
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "kyro-toast-icon-container", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-4 h-4" }) }),
|
|
11580
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "kyro-toast-content", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "kyro-toast-message", children: message }) }),
|
|
11581
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11582
|
-
"button",
|
|
11583
|
-
{
|
|
11584
|
-
type: "button",
|
|
11585
|
-
className: "kyro-toast-close group-hover:opacity-100 opacity-40 transition-opacity",
|
|
11586
|
-
onClick: onClose,
|
|
11587
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3.5 h-3.5" })
|
|
11588
|
-
}
|
|
11589
|
-
)
|
|
11590
|
-
]
|
|
11591
|
-
}
|
|
11592
|
-
);
|
|
11593
|
-
}
|
|
11594
|
-
function ToastProvider({ children }) {
|
|
11595
|
-
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
11596
|
-
}
|
|
11597
|
-
function useToast() {
|
|
11598
|
-
const addToast = useToastStore((state) => state.addToast);
|
|
11599
|
-
const removeToast = useToastStore((state) => state.removeToast);
|
|
11600
|
-
const toasts = useToastStore((state) => state.toasts);
|
|
11601
|
-
return { toasts, addToast, removeToast };
|
|
11602
|
-
}
|
|
11603
11063
|
function DetailView({
|
|
11604
11064
|
config,
|
|
11605
11065
|
collection,
|
|
@@ -11611,34 +11071,33 @@ function DetailView({
|
|
|
11611
11071
|
onError,
|
|
11612
11072
|
mode = "collection"
|
|
11613
11073
|
}) {
|
|
11614
|
-
const { addToast } = useToast();
|
|
11615
11074
|
const { confirm, alert } = useUIStore();
|
|
11616
|
-
const [data, setData] =
|
|
11617
|
-
const [originalData, setOriginalData] =
|
|
11618
|
-
const [loading, setLoading] =
|
|
11619
|
-
const [saving, setSaving] =
|
|
11620
|
-
const [saveStatus, setSaveStatus] =
|
|
11621
|
-
const [deleting, setDeleting] =
|
|
11622
|
-
const [status, setStatus] =
|
|
11623
|
-
const [createdAt, setCreatedAt] =
|
|
11624
|
-
const [updatedAt, setUpdatedAt] =
|
|
11625
|
-
const [publishedAt, setPublishedAt] =
|
|
11626
|
-
const [justSaved, setJustSaved] =
|
|
11075
|
+
const [data, setData] = React56.useState({});
|
|
11076
|
+
const [originalData, setOriginalData] = React56.useState({});
|
|
11077
|
+
const [loading, setLoading] = React56.useState(true);
|
|
11078
|
+
const [saving, setSaving] = React56.useState(false);
|
|
11079
|
+
const [saveStatus, setSaveStatus] = React56.useState("idle");
|
|
11080
|
+
const [deleting, setDeleting] = React56.useState(false);
|
|
11081
|
+
const [status, setStatus] = React56.useState("draft");
|
|
11082
|
+
const [createdAt, setCreatedAt] = React56.useState(null);
|
|
11083
|
+
const [updatedAt, setUpdatedAt] = React56.useState(null);
|
|
11084
|
+
const [publishedAt, setPublishedAt] = React56.useState(null);
|
|
11085
|
+
const [justSaved, setJustSaved] = React56.useState(false);
|
|
11627
11086
|
const fields2 = global?.fields || collection?.fields || [];
|
|
11628
11087
|
const label = global?.label || collection?.label || "Document";
|
|
11629
11088
|
const slug = global?.slug || collection?.slug || "";
|
|
11630
11089
|
const hasChanges = JSON.stringify(data) !== JSON.stringify(originalData);
|
|
11631
|
-
|
|
11090
|
+
React56.useEffect(() => {
|
|
11632
11091
|
if (hasChanges && status === "published") {
|
|
11633
11092
|
setStatus("draft");
|
|
11634
11093
|
}
|
|
11635
11094
|
}, [hasChanges, status]);
|
|
11636
|
-
|
|
11095
|
+
React56.useEffect(() => {
|
|
11637
11096
|
if (hasChanges && saveStatus === "saved") {
|
|
11638
11097
|
setSaveStatus("idle");
|
|
11639
11098
|
}
|
|
11640
11099
|
}, [hasChanges, saveStatus]);
|
|
11641
|
-
|
|
11100
|
+
React56.useEffect(() => {
|
|
11642
11101
|
if (mode === "global") {
|
|
11643
11102
|
loadGlobal();
|
|
11644
11103
|
} else if (documentId) {
|
|
@@ -11652,7 +11111,7 @@ function DetailView({
|
|
|
11652
11111
|
const docData = result.data || {};
|
|
11653
11112
|
setData(docData);
|
|
11654
11113
|
setOriginalData(docData);
|
|
11655
|
-
setStatus(docData?.
|
|
11114
|
+
setStatus(docData?.status || result.status || "draft");
|
|
11656
11115
|
setCreatedAt(result.createdAt || docData.createdAt || null);
|
|
11657
11116
|
setUpdatedAt(result.updatedAt || docData.updatedAt || null);
|
|
11658
11117
|
setPublishedAt(result.publishedAt || docData.publishedAt || null);
|
|
@@ -11677,26 +11136,28 @@ function DetailView({
|
|
|
11677
11136
|
setLoading(false);
|
|
11678
11137
|
}
|
|
11679
11138
|
};
|
|
11680
|
-
const handleSave =
|
|
11139
|
+
const handleSave = React56.useCallback(
|
|
11681
11140
|
async (isAutosave = false) => {
|
|
11682
11141
|
try {
|
|
11683
11142
|
setSaveStatus("saving");
|
|
11684
11143
|
const endpoint = mode === "global" ? `/api/globals/${slug}` : `/api/${slug}/${documentId}`;
|
|
11685
|
-
const
|
|
11144
|
+
const isDraft = status === "draft" || data?.status === "draft";
|
|
11145
|
+
const result = await apiPatch(endpoint, data, { autoToast: false, headers: { "X-Draft": String(isDraft) } });
|
|
11686
11146
|
const savedData = result && (result.data || result) || data;
|
|
11687
11147
|
if (!isAutosave) {
|
|
11688
11148
|
setOriginalData(savedData);
|
|
11689
11149
|
onSave();
|
|
11690
11150
|
}
|
|
11691
11151
|
setData(savedData);
|
|
11692
|
-
setStatus(savedData?.
|
|
11152
|
+
setStatus(savedData?.status || status);
|
|
11693
11153
|
setSaveStatus("saved");
|
|
11694
11154
|
setUpdatedAt((/* @__PURE__ */ new Date()).toISOString());
|
|
11695
11155
|
setJustSaved(true);
|
|
11696
11156
|
setTimeout(() => setJustSaved(false), 3e3);
|
|
11697
11157
|
if (!isAutosave) {
|
|
11698
|
-
const
|
|
11699
|
-
|
|
11158
|
+
const isDraft2 = status === "draft" || savedData?.status === "draft";
|
|
11159
|
+
if (isDraft2) toast.warning("Draft saved");
|
|
11160
|
+
else toast.success("Updated");
|
|
11700
11161
|
}
|
|
11701
11162
|
setTimeout(() => {
|
|
11702
11163
|
setSaveStatus("idle");
|
|
@@ -11705,24 +11166,28 @@ function DetailView({
|
|
|
11705
11166
|
setSaveStatus("error");
|
|
11706
11167
|
if (!isAutosave) {
|
|
11707
11168
|
onError("Failed to save changes");
|
|
11708
|
-
|
|
11169
|
+
toast.error("Failed to save changes");
|
|
11709
11170
|
}
|
|
11710
11171
|
} finally {
|
|
11711
11172
|
setSaving(false);
|
|
11712
11173
|
}
|
|
11713
11174
|
},
|
|
11714
|
-
[data, mode, slug, documentId, onSave, onError]
|
|
11175
|
+
[data, mode, slug, documentId, status, onSave, onError]
|
|
11715
11176
|
);
|
|
11716
11177
|
const handlePublish = async () => {
|
|
11717
11178
|
try {
|
|
11718
11179
|
setSaving(true);
|
|
11719
|
-
await
|
|
11180
|
+
await apiPatch(`/api/${slug}/${documentId}`, data, {
|
|
11181
|
+
autoToast: false,
|
|
11182
|
+
headers: { "X-Draft": "false" }
|
|
11183
|
+
});
|
|
11720
11184
|
setStatus("published");
|
|
11721
11185
|
setPublishedAt((/* @__PURE__ */ new Date()).toISOString());
|
|
11722
|
-
|
|
11186
|
+
toast.success("Published successfully");
|
|
11187
|
+
onSave();
|
|
11723
11188
|
} catch {
|
|
11724
11189
|
onError("Failed to publish");
|
|
11725
|
-
|
|
11190
|
+
toast.error("Failed to publish");
|
|
11726
11191
|
} finally {
|
|
11727
11192
|
setSaving(false);
|
|
11728
11193
|
}
|
|
@@ -11730,12 +11195,16 @@ function DetailView({
|
|
|
11730
11195
|
const handleUnpublish = async () => {
|
|
11731
11196
|
try {
|
|
11732
11197
|
setSaving(true);
|
|
11733
|
-
await
|
|
11198
|
+
await apiPatch(`/api/${slug}/${documentId}`, { status: "draft" }, {
|
|
11199
|
+
autoToast: false,
|
|
11200
|
+
headers: { "X-Draft": "false" }
|
|
11201
|
+
});
|
|
11734
11202
|
setStatus("draft");
|
|
11735
|
-
|
|
11203
|
+
toast.warning("Document unpublished");
|
|
11204
|
+
onSave();
|
|
11736
11205
|
} catch {
|
|
11737
11206
|
onError("Failed to unpublish");
|
|
11738
|
-
|
|
11207
|
+
toast.error("Failed to unpublish");
|
|
11739
11208
|
} finally {
|
|
11740
11209
|
setSaving(false);
|
|
11741
11210
|
}
|
|
@@ -11744,11 +11213,11 @@ function DetailView({
|
|
|
11744
11213
|
try {
|
|
11745
11214
|
setSaving(true);
|
|
11746
11215
|
await apiPost(`/api/${slug}/${documentId}/duplicate`, void 0, { autoToast: false });
|
|
11747
|
-
|
|
11216
|
+
toast.success("Document duplicated");
|
|
11748
11217
|
} catch (err) {
|
|
11749
11218
|
const message = err instanceof Error ? err.message : "Failed to duplicate document";
|
|
11750
11219
|
onError(message);
|
|
11751
|
-
|
|
11220
|
+
toast.error(message);
|
|
11752
11221
|
} finally {
|
|
11753
11222
|
setSaving(false);
|
|
11754
11223
|
}
|
|
@@ -11763,10 +11232,10 @@ function DetailView({
|
|
|
11763
11232
|
setDeleting(true);
|
|
11764
11233
|
await apiDelete(`/api/${slug}/${documentId}`, { autoToast: false });
|
|
11765
11234
|
onDelete?.();
|
|
11766
|
-
|
|
11235
|
+
toast.error("Document deleted");
|
|
11767
11236
|
} catch (err) {
|
|
11768
11237
|
const message = err instanceof Error ? err.message : "Failed to delete document";
|
|
11769
|
-
|
|
11238
|
+
toast.error(message);
|
|
11770
11239
|
} finally {
|
|
11771
11240
|
setDeleting(false);
|
|
11772
11241
|
}
|
|
@@ -11849,8 +11318,8 @@ function DetailView({
|
|
|
11849
11318
|
layout: isSingleLayout ? "single" : "split",
|
|
11850
11319
|
globalSlug: mode === "global" ? slug : void 0,
|
|
11851
11320
|
collectionSlug: mode === "collection" ? slug : void 0,
|
|
11852
|
-
onActionSuccess: (message) =>
|
|
11853
|
-
onActionError: (message) =>
|
|
11321
|
+
onActionSuccess: (message) => toast.success(message),
|
|
11322
|
+
onActionError: (message) => toast.error(message),
|
|
11854
11323
|
documentStatus: status,
|
|
11855
11324
|
justSaved
|
|
11856
11325
|
}
|
|
@@ -11865,44 +11334,14 @@ function DetailView({
|
|
|
11865
11334
|
children: "Delete"
|
|
11866
11335
|
}
|
|
11867
11336
|
),
|
|
11868
|
-
|
|
11869
|
-
|
|
11870
|
-
"Published"
|
|
11871
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11872
|
-
"button",
|
|
11337
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11338
|
+
SplitButton,
|
|
11873
11339
|
{
|
|
11874
|
-
|
|
11875
|
-
|
|
11876
|
-
|
|
11877
|
-
|
|
11878
|
-
|
|
11879
|
-
saving ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
11880
|
-
"svg",
|
|
11881
|
-
{
|
|
11882
|
-
className: "w-4 h-4 animate-spin",
|
|
11883
|
-
viewBox: "0 0 24 24",
|
|
11884
|
-
fill: "none",
|
|
11885
|
-
stroke: "currentColor",
|
|
11886
|
-
strokeWidth: "2",
|
|
11887
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
|
|
11888
|
-
}
|
|
11889
|
-
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11890
|
-
"svg",
|
|
11891
|
-
{
|
|
11892
|
-
className: "w-4 h-4",
|
|
11893
|
-
viewBox: "0 0 24 24",
|
|
11894
|
-
fill: "none",
|
|
11895
|
-
stroke: "currentColor",
|
|
11896
|
-
strokeWidth: "2",
|
|
11897
|
-
children: [
|
|
11898
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z" }),
|
|
11899
|
-
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "17 21 17 13 7 13 7 21" }),
|
|
11900
|
-
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "7 3 7 8 15 8" })
|
|
11901
|
-
]
|
|
11902
|
-
}
|
|
11903
|
-
),
|
|
11904
|
-
saving ? "Saving..." : mode === "global" ? "Save Configuration" : "Save Document"
|
|
11905
|
-
]
|
|
11340
|
+
status,
|
|
11341
|
+
saveStatus: saving ? "saving" : "idle",
|
|
11342
|
+
hasChanges,
|
|
11343
|
+
onPublish: () => handleSave(false),
|
|
11344
|
+
disabled: saving
|
|
11906
11345
|
}
|
|
11907
11346
|
)
|
|
11908
11347
|
] })
|
|
@@ -11989,8 +11428,8 @@ function CreateView({
|
|
|
11989
11428
|
onSuccess,
|
|
11990
11429
|
onError
|
|
11991
11430
|
}) {
|
|
11992
|
-
const [data, setData] =
|
|
11993
|
-
const [saving, setSaving] =
|
|
11431
|
+
const [data, setData] = React56.useState({});
|
|
11432
|
+
const [saving, setSaving] = React56.useState(false);
|
|
11994
11433
|
const fields2 = collection.fields || [];
|
|
11995
11434
|
const label = collection.label || collection.slug;
|
|
11996
11435
|
const handleSubmit = async (e) => {
|
|
@@ -12032,15 +11471,71 @@ function CreateView({
|
|
|
12032
11471
|
) }) }) }) })
|
|
12033
11472
|
] });
|
|
12034
11473
|
}
|
|
11474
|
+
function Toast({ type, message, onClose }) {
|
|
11475
|
+
const [isPaused, setIsPaused] = React56__default.default.useState(false);
|
|
11476
|
+
const timerRef = React56__default.default.useRef(null);
|
|
11477
|
+
const startTimer = () => {
|
|
11478
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
11479
|
+
timerRef.current = setTimeout(onClose, 5e3);
|
|
11480
|
+
};
|
|
11481
|
+
const clearTimer = () => {
|
|
11482
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
11483
|
+
};
|
|
11484
|
+
React56__default.default.useEffect(() => {
|
|
11485
|
+
if (!isPaused) {
|
|
11486
|
+
startTimer();
|
|
11487
|
+
} else {
|
|
11488
|
+
clearTimer();
|
|
11489
|
+
}
|
|
11490
|
+
return clearTimer;
|
|
11491
|
+
}, [isPaused, onClose]);
|
|
11492
|
+
const Icon = {
|
|
11493
|
+
success: lucideReact.CircleCheck,
|
|
11494
|
+
error: lucideReact.ShieldAlert,
|
|
11495
|
+
warning: lucideReact.TriangleAlert,
|
|
11496
|
+
info: lucideReact.Info
|
|
11497
|
+
}[type];
|
|
11498
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11499
|
+
"div",
|
|
11500
|
+
{
|
|
11501
|
+
className: `kyro-toast kyro-toast-${type} group animate-in fade-in slide-in-from-right-4 duration-300`,
|
|
11502
|
+
onMouseEnter: () => setIsPaused(true),
|
|
11503
|
+
onMouseLeave: () => setIsPaused(false),
|
|
11504
|
+
children: [
|
|
11505
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "kyro-toast-accent" }),
|
|
11506
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "kyro-toast-icon-container", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-4 h-4" }) }),
|
|
11507
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "kyro-toast-content", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "kyro-toast-message", children: message }) }),
|
|
11508
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11509
|
+
"button",
|
|
11510
|
+
{
|
|
11511
|
+
type: "button",
|
|
11512
|
+
className: "kyro-toast-close group-hover:opacity-100 opacity-40 transition-opacity",
|
|
11513
|
+
onClick: onClose,
|
|
11514
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3.5 h-3.5" })
|
|
11515
|
+
}
|
|
11516
|
+
)
|
|
11517
|
+
]
|
|
11518
|
+
}
|
|
11519
|
+
);
|
|
11520
|
+
}
|
|
11521
|
+
function ToastProvider({ children }) {
|
|
11522
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
11523
|
+
}
|
|
11524
|
+
function useToast() {
|
|
11525
|
+
const addToast = useToastStore((state) => state.addToast);
|
|
11526
|
+
const removeToast = useToastStore((state) => state.removeToast);
|
|
11527
|
+
const toasts = useToastStore((state) => state.toasts);
|
|
11528
|
+
return { toasts, addToast, removeToast };
|
|
11529
|
+
}
|
|
12035
11530
|
function LoginPage({ onAuth, theme = "light" }) {
|
|
12036
|
-
const [mode, setMode] =
|
|
12037
|
-
const [email, setEmail] =
|
|
12038
|
-
const [password, setPassword] =
|
|
12039
|
-
const [confirmPassword, setConfirmPassword] =
|
|
12040
|
-
const [loading, setLoading] =
|
|
12041
|
-
const [toasts, setToasts] =
|
|
12042
|
-
const [isFirstUser, setIsFirstUser] =
|
|
12043
|
-
|
|
11531
|
+
const [mode, setMode] = React56.useState("login");
|
|
11532
|
+
const [email, setEmail] = React56.useState("");
|
|
11533
|
+
const [password, setPassword] = React56.useState("");
|
|
11534
|
+
const [confirmPassword, setConfirmPassword] = React56.useState("");
|
|
11535
|
+
const [loading, setLoading] = React56.useState(false);
|
|
11536
|
+
const [toasts, setToasts] = React56.useState([]);
|
|
11537
|
+
const [isFirstUser, setIsFirstUser] = React56.useState(false);
|
|
11538
|
+
React56.useEffect(() => {
|
|
12044
11539
|
checkIfFirstUser();
|
|
12045
11540
|
}, []);
|
|
12046
11541
|
const checkIfFirstUser = async () => {
|
|
@@ -12186,14 +11681,14 @@ function LoginPage({ onAuth, theme = "light" }) {
|
|
|
12186
11681
|
}
|
|
12187
11682
|
function Dashboard({ collections: collections2, onNavigate, user }) {
|
|
12188
11683
|
const { permissions } = useAuthStore();
|
|
12189
|
-
const [stats, setStats] =
|
|
11684
|
+
const [stats, setStats] = React56.useState({
|
|
12190
11685
|
totalDocs: 0,
|
|
12191
11686
|
totalMedia: 0,
|
|
12192
11687
|
totalUsers: 0,
|
|
12193
11688
|
recentActivity: []
|
|
12194
11689
|
});
|
|
12195
|
-
const [loading, setLoading] =
|
|
12196
|
-
|
|
11690
|
+
const [loading, setLoading] = React56.useState(true);
|
|
11691
|
+
React56.useEffect(() => {
|
|
12197
11692
|
const timer = setTimeout(() => {
|
|
12198
11693
|
setStats({
|
|
12199
11694
|
totalDocs: 124,
|
|
@@ -12514,15 +12009,15 @@ function Dashboard({ collections: collections2, onNavigate, user }) {
|
|
|
12514
12009
|
] });
|
|
12515
12010
|
}
|
|
12516
12011
|
function UserManagement() {
|
|
12517
|
-
const [users, setUsers] =
|
|
12518
|
-
const [loading, setLoading] =
|
|
12519
|
-
const [searchQuery, setSearchQuery] =
|
|
12520
|
-
const [showCreateModal, setShowCreateModal] =
|
|
12521
|
-
const [createForm, setCreateForm] =
|
|
12522
|
-
const [createError, setCreateError] =
|
|
12523
|
-
const [creating, setCreating] =
|
|
12012
|
+
const [users, setUsers] = React56.useState([]);
|
|
12013
|
+
const [loading, setLoading] = React56.useState(true);
|
|
12014
|
+
const [searchQuery, setSearchQuery] = React56.useState("");
|
|
12015
|
+
const [showCreateModal, setShowCreateModal] = React56.useState(false);
|
|
12016
|
+
const [createForm, setCreateForm] = React56.useState({ name: "", email: "", password: "", role: "customer" });
|
|
12017
|
+
const [createError, setCreateError] = React56.useState("");
|
|
12018
|
+
const [creating, setCreating] = React56.useState(false);
|
|
12524
12019
|
const { confirm, alert } = useUIStore();
|
|
12525
|
-
|
|
12020
|
+
React56.useEffect(() => {
|
|
12526
12021
|
loadUsers();
|
|
12527
12022
|
}, []);
|
|
12528
12023
|
const loadUsers = async () => {
|
|
@@ -12787,8 +12282,8 @@ function UserManagement() {
|
|
|
12787
12282
|
] });
|
|
12788
12283
|
}
|
|
12789
12284
|
function AvatarCell({ user }) {
|
|
12790
|
-
const [url, setUrl] =
|
|
12791
|
-
|
|
12285
|
+
const [url, setUrl] = React56.useState(null);
|
|
12286
|
+
React56.useEffect(() => {
|
|
12792
12287
|
const avatar = user.avatar;
|
|
12793
12288
|
if (typeof avatar === "string" && /^[0-9a-f-]+$/i.test(avatar)) {
|
|
12794
12289
|
apiGet(`/api/media/${avatar}`).then((media) => setUrl(media?.thumbnailUrl || media?.url || null)).catch(() => setUrl(null));
|
|
@@ -12800,15 +12295,15 @@ function AvatarCell({ user }) {
|
|
|
12800
12295
|
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() });
|
|
12801
12296
|
}
|
|
12802
12297
|
function BrandingHub() {
|
|
12803
|
-
const [siteName, setSiteName] =
|
|
12804
|
-
const [adminTitle, setAdminTitle] =
|
|
12805
|
-
const [primaryColor, setPrimaryColor] =
|
|
12806
|
-
const [dashboardGreeting, setDashboardGreeting] =
|
|
12298
|
+
const [siteName, setSiteName] = React56.useState("Kyro CMS");
|
|
12299
|
+
const [adminTitle, setAdminTitle] = React56.useState("Command Center");
|
|
12300
|
+
const [primaryColor, setPrimaryColor] = React56.useState("#6366f1");
|
|
12301
|
+
const [dashboardGreeting, setDashboardGreeting] = React56.useState(
|
|
12807
12302
|
"Welcome back to your Command Center."
|
|
12808
12303
|
);
|
|
12809
|
-
const [saving, setSaving] =
|
|
12810
|
-
const [saved, setSaved] =
|
|
12811
|
-
|
|
12304
|
+
const [saving, setSaving] = React56.useState(false);
|
|
12305
|
+
const [saved, setSaved] = React56.useState(false);
|
|
12306
|
+
React56.useEffect(() => {
|
|
12812
12307
|
const fetchBranding = async () => {
|
|
12813
12308
|
try {
|
|
12814
12309
|
const result = await apiGet("/api/globals/site-settings");
|
|
@@ -13004,15 +12499,15 @@ function BrandingHub() {
|
|
|
13004
12499
|
}
|
|
13005
12500
|
var API_BASE2 = typeof __KYRO_API_PATH__ !== "undefined" ? __KYRO_API_PATH__ : "/api";
|
|
13006
12501
|
function DeveloperCenter({ collections: collections2 }) {
|
|
13007
|
-
const [keys, setKeys] =
|
|
13008
|
-
const [loading, setLoading] =
|
|
13009
|
-
const [showKey, setShowKey] =
|
|
13010
|
-
const [testEndpoint, setTestEndpoint] =
|
|
13011
|
-
const [playgroundResult, setPlaygroundResult] =
|
|
13012
|
-
const [exploring, setExploring] =
|
|
12502
|
+
const [keys, setKeys] = React56.useState([]);
|
|
12503
|
+
const [loading, setLoading] = React56.useState(false);
|
|
12504
|
+
const [showKey, setShowKey] = React56.useState(null);
|
|
12505
|
+
const [testEndpoint, setTestEndpoint] = React56.useState("");
|
|
12506
|
+
const [playgroundResult, setPlaygroundResult] = React56.useState(null);
|
|
12507
|
+
const [exploring, setExploring] = React56.useState(false);
|
|
13013
12508
|
const { confirm, alert } = useUIStore();
|
|
13014
|
-
const [showCreateModal, setShowCreateModal] =
|
|
13015
|
-
const [newKeyName, setNewKeyName] =
|
|
12509
|
+
const [showCreateModal, setShowCreateModal] = React56.useState(false);
|
|
12510
|
+
const [newKeyName, setNewKeyName] = React56.useState("");
|
|
13016
12511
|
const loadKeys = async () => {
|
|
13017
12512
|
try {
|
|
13018
12513
|
const data = await apiGet("/api/keys");
|
|
@@ -13021,7 +12516,7 @@ function DeveloperCenter({ collections: collections2 }) {
|
|
|
13021
12516
|
console.error(e);
|
|
13022
12517
|
}
|
|
13023
12518
|
};
|
|
13024
|
-
|
|
12519
|
+
React56.useEffect(() => {
|
|
13025
12520
|
loadKeys();
|
|
13026
12521
|
}, []);
|
|
13027
12522
|
const handleGenerateKey = async () => {
|
|
@@ -13339,12 +12834,12 @@ function DeveloperCenter({ collections: collections2 }) {
|
|
|
13339
12834
|
] });
|
|
13340
12835
|
}
|
|
13341
12836
|
function useResourceManager(options) {
|
|
13342
|
-
const [items, setItems] =
|
|
13343
|
-
const [loading, setLoading] =
|
|
13344
|
-
const [error, setError] =
|
|
13345
|
-
const [isCreateModalOpen, setIsCreateModalOpen] =
|
|
12837
|
+
const [items, setItems] = React56.useState([]);
|
|
12838
|
+
const [loading, setLoading] = React56.useState(false);
|
|
12839
|
+
const [error, setError] = React56.useState(null);
|
|
12840
|
+
const [isCreateModalOpen, setIsCreateModalOpen] = React56.useState(false);
|
|
13346
12841
|
const { confirm } = useUIStore();
|
|
13347
|
-
const load =
|
|
12842
|
+
const load = React56.useCallback(async () => {
|
|
13348
12843
|
setLoading(true);
|
|
13349
12844
|
setError(null);
|
|
13350
12845
|
try {
|
|
@@ -13361,10 +12856,10 @@ function useResourceManager(options) {
|
|
|
13361
12856
|
setLoading(false);
|
|
13362
12857
|
}
|
|
13363
12858
|
}, [options.endpoint, options.transformLoad]);
|
|
13364
|
-
|
|
12859
|
+
React56.useEffect(() => {
|
|
13365
12860
|
load();
|
|
13366
12861
|
}, [load]);
|
|
13367
|
-
const remove =
|
|
12862
|
+
const remove = React56.useCallback((id, resourceName = "item") => {
|
|
13368
12863
|
confirm({
|
|
13369
12864
|
title: `Delete ${resourceName}`,
|
|
13370
12865
|
message: `Are you sure you want to delete this ${resourceName.toLowerCase()}? This action cannot be undone.`,
|
|
@@ -13382,7 +12877,7 @@ function useResourceManager(options) {
|
|
|
13382
12877
|
}
|
|
13383
12878
|
});
|
|
13384
12879
|
}, [options.endpoint, confirm]);
|
|
13385
|
-
const create3 =
|
|
12880
|
+
const create3 = React56.useCallback(async (data) => {
|
|
13386
12881
|
setError(null);
|
|
13387
12882
|
try {
|
|
13388
12883
|
const created = await apiPost(options.endpoint, data);
|
|
@@ -13397,7 +12892,7 @@ function useResourceManager(options) {
|
|
|
13397
12892
|
throw e;
|
|
13398
12893
|
}
|
|
13399
12894
|
}, [options.endpoint]);
|
|
13400
|
-
const update =
|
|
12895
|
+
const update = React56.useCallback(async (id, data) => {
|
|
13401
12896
|
setError(null);
|
|
13402
12897
|
try {
|
|
13403
12898
|
const updated = await apiPatch(`${options.endpoint}/${id}`, data);
|
|
@@ -13437,17 +12932,17 @@ function WebhookManager() {
|
|
|
13437
12932
|
endpoint: "/api/webhooks"
|
|
13438
12933
|
});
|
|
13439
12934
|
const { confirm } = useUIStore();
|
|
13440
|
-
const [showTestModal, setShowTestModal] =
|
|
13441
|
-
const [showHelpModal, setShowHelpModal] =
|
|
13442
|
-
const [testResult, setTestResult] =
|
|
13443
|
-
const [testId, setTestId] =
|
|
13444
|
-
const [formData, setFormData] =
|
|
12935
|
+
const [showTestModal, setShowTestModal] = React56.useState(false);
|
|
12936
|
+
const [showHelpModal, setShowHelpModal] = React56.useState(false);
|
|
12937
|
+
const [testResult, setTestResult] = React56.useState(null);
|
|
12938
|
+
const [testId, setTestId] = React56.useState(null);
|
|
12939
|
+
const [formData, setFormData] = React56.useState({
|
|
13445
12940
|
name: "",
|
|
13446
12941
|
url: "",
|
|
13447
12942
|
events: [],
|
|
13448
12943
|
secret: ""
|
|
13449
12944
|
});
|
|
13450
|
-
const [createError, setCreateError] =
|
|
12945
|
+
const [createError, setCreateError] = React56.useState("");
|
|
13451
12946
|
const handleCreate = async () => {
|
|
13452
12947
|
if (!formData.name.trim() || !formData.url.trim()) {
|
|
13453
12948
|
setCreateError("Name and URL are required");
|
|
@@ -13899,13 +13394,13 @@ function CommandPalette({
|
|
|
13899
13394
|
onNavigate
|
|
13900
13395
|
}) {
|
|
13901
13396
|
const { user, permissions } = useAuthStore();
|
|
13902
|
-
const [query, setQuery] =
|
|
13903
|
-
const [selectedIndex, setSelectedIndex] =
|
|
13904
|
-
const [loading, setLoading] =
|
|
13905
|
-
const [searchResults, setSearchResults] =
|
|
13906
|
-
const inputRef =
|
|
13907
|
-
const debounceRef =
|
|
13908
|
-
|
|
13397
|
+
const [query, setQuery] = React56.useState("");
|
|
13398
|
+
const [selectedIndex, setSelectedIndex] = React56.useState(0);
|
|
13399
|
+
const [loading, setLoading] = React56.useState(false);
|
|
13400
|
+
const [searchResults, setSearchResults] = React56.useState([]);
|
|
13401
|
+
const inputRef = React56.useRef(null);
|
|
13402
|
+
const debounceRef = React56.useRef(null);
|
|
13403
|
+
React56.useEffect(() => {
|
|
13909
13404
|
if (isOpen) {
|
|
13910
13405
|
setQuery("");
|
|
13911
13406
|
setSelectedIndex(0);
|
|
@@ -13914,7 +13409,7 @@ function CommandPalette({
|
|
|
13914
13409
|
setTimeout(() => inputRef.current?.focus(), 100);
|
|
13915
13410
|
}
|
|
13916
13411
|
}, [isOpen]);
|
|
13917
|
-
const performSearch =
|
|
13412
|
+
const performSearch = React56.useCallback(async (searchQuery) => {
|
|
13918
13413
|
if (!searchQuery || searchQuery.length < 2) {
|
|
13919
13414
|
setSearchResults([]);
|
|
13920
13415
|
return;
|
|
@@ -13935,7 +13430,7 @@ function CommandPalette({
|
|
|
13935
13430
|
setLoading(false);
|
|
13936
13431
|
}
|
|
13937
13432
|
}, []);
|
|
13938
|
-
|
|
13433
|
+
React56.useEffect(() => {
|
|
13939
13434
|
if (debounceRef.current) {
|
|
13940
13435
|
clearTimeout(debounceRef.current);
|
|
13941
13436
|
}
|
|
@@ -14182,7 +13677,7 @@ function CommandPalette({
|
|
|
14182
13677
|
}
|
|
14183
13678
|
function GlobalModal() {
|
|
14184
13679
|
const { modal, closeModal } = useUIStore();
|
|
14185
|
-
const [loading, setLoading] =
|
|
13680
|
+
const [loading, setLoading] = React56.useState(false);
|
|
14186
13681
|
if (!modal.open || !modal.config) return null;
|
|
14187
13682
|
const { config } = modal;
|
|
14188
13683
|
const handleConfirm = async () => {
|
|
@@ -14222,24 +13717,24 @@ function GlobalModal() {
|
|
|
14222
13717
|
);
|
|
14223
13718
|
}
|
|
14224
13719
|
function Admin({ config, theme = "light", onThemeChange }) {
|
|
14225
|
-
const [authenticated, setAuthenticated] =
|
|
14226
|
-
const [currentUser, setCurrentUser] =
|
|
14227
|
-
const collections2 =
|
|
13720
|
+
const [authenticated, setAuthenticated] = React56.useState(false);
|
|
13721
|
+
const [currentUser, setCurrentUser] = React56.useState(null);
|
|
13722
|
+
const collections2 = React56.useMemo(
|
|
14228
13723
|
() => toCollectionMap(toArray(config.collections)),
|
|
14229
13724
|
[config.collections]
|
|
14230
13725
|
);
|
|
14231
|
-
const globals2 =
|
|
13726
|
+
const globals2 = React56.useMemo(
|
|
14232
13727
|
() => toGlobalMap(toArray(config.globals)),
|
|
14233
13728
|
[config.globals]
|
|
14234
13729
|
);
|
|
14235
|
-
const [activeCollection, setActiveCollection] =
|
|
14236
|
-
const [activeGlobal, setActiveGlobal] =
|
|
14237
|
-
const [currentView, setCurrentView] =
|
|
14238
|
-
const [activeDocumentId, setActiveDocumentId] =
|
|
14239
|
-
const [isCommandPaletteOpen, setIsCommandPaletteOpen] =
|
|
13730
|
+
const [activeCollection, setActiveCollection] = React56.useState(null);
|
|
13731
|
+
const [activeGlobal, setActiveGlobal] = React56.useState(null);
|
|
13732
|
+
const [currentView, setCurrentView] = React56.useState("list");
|
|
13733
|
+
const [activeDocumentId, setActiveDocumentId] = React56.useState(null);
|
|
13734
|
+
const [isCommandPaletteOpen, setIsCommandPaletteOpen] = React56.useState(false);
|
|
14240
13735
|
const toasts = useToastStore((state) => state.toasts);
|
|
14241
13736
|
const removeToast = useToastStore((state) => state.removeToast);
|
|
14242
|
-
|
|
13737
|
+
React56.useEffect(() => {
|
|
14243
13738
|
const checkAuth = async () => {
|
|
14244
13739
|
try {
|
|
14245
13740
|
const response = await fetch("/api/users/me");
|
|
@@ -14254,7 +13749,7 @@ function Admin({ config, theme = "light", onThemeChange }) {
|
|
|
14254
13749
|
};
|
|
14255
13750
|
checkAuth();
|
|
14256
13751
|
}, []);
|
|
14257
|
-
|
|
13752
|
+
React56.useEffect(() => {
|
|
14258
13753
|
if (authenticated && !activeCollection) {
|
|
14259
13754
|
const firstCol = Object.keys(collections2)[0];
|
|
14260
13755
|
if (firstCol) setActiveCollection(firstCol);
|
|
@@ -14266,7 +13761,7 @@ function Admin({ config, theme = "light", onThemeChange }) {
|
|
|
14266
13761
|
if (id) setActiveDocumentId(id);
|
|
14267
13762
|
setIsCommandPaletteOpen(false);
|
|
14268
13763
|
};
|
|
14269
|
-
|
|
13764
|
+
React56.useEffect(() => {
|
|
14270
13765
|
const handleKeyDown = (e) => {
|
|
14271
13766
|
if ((e.metaKey || e.ctrlKey) && e.key === "k") {
|
|
14272
13767
|
e.preventDefault();
|
|
@@ -14345,7 +13840,7 @@ function Admin({ config, theme = "light", onThemeChange }) {
|
|
|
14345
13840
|
);
|
|
14346
13841
|
}
|
|
14347
13842
|
};
|
|
14348
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ThemeProvider, { ...{ mode: theme, onChange: onThemeChange }, children: /* @__PURE__ */ jsxRuntime.
|
|
13843
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ThemeProvider, { ...{ mode: theme, onChange: onThemeChange }, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "kyro-admin min-h-screen bg-[var(--kyro-bg)] text-[var(--kyro-text-primary)]", children: [
|
|
14349
13844
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-screen overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx("main", { className: "flex-1 flex flex-col min-w-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto", children: [
|
|
14350
13845
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14351
13846
|
CommandPalette,
|
|
@@ -14369,7 +13864,7 @@ function Admin({ config, theme = "light", onThemeChange }) {
|
|
|
14369
13864
|
},
|
|
14370
13865
|
t.id
|
|
14371
13866
|
)) })
|
|
14372
|
-
] }) })
|
|
13867
|
+
] }) });
|
|
14373
13868
|
}
|
|
14374
13869
|
function BulkActionsBar({
|
|
14375
13870
|
selectedCount,
|
|
@@ -14600,32 +14095,6 @@ function Header({ title, onMenuClick, actions }) {
|
|
|
14600
14095
|
] })
|
|
14601
14096
|
] });
|
|
14602
14097
|
}
|
|
14603
|
-
function Button({
|
|
14604
|
-
variant = "secondary",
|
|
14605
|
-
size = "md",
|
|
14606
|
-
loading = false,
|
|
14607
|
-
children,
|
|
14608
|
-
className = "",
|
|
14609
|
-
disabled,
|
|
14610
|
-
...props
|
|
14611
|
-
}) {
|
|
14612
|
-
const baseClass = "kyro-btn";
|
|
14613
|
-
const variantClass = `kyro-btn-${variant}`;
|
|
14614
|
-
const sizeClass = `kyro-btn-${size}`;
|
|
14615
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14616
|
-
"button",
|
|
14617
|
-
{
|
|
14618
|
-
type: "button",
|
|
14619
|
-
className: `${baseClass} ${variantClass} ${sizeClass} ${className}`,
|
|
14620
|
-
disabled: disabled || loading,
|
|
14621
|
-
...props,
|
|
14622
|
-
children: [
|
|
14623
|
-
loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "kyro-btn-loading", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "kyro-btn-spinner", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "3", fill: "none", strokeDasharray: "60 30" }) }) }) : null,
|
|
14624
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: loading ? "kyro-btn-text-hidden" : "", children })
|
|
14625
|
-
]
|
|
14626
|
-
}
|
|
14627
|
-
);
|
|
14628
|
-
}
|
|
14629
14098
|
|
|
14630
14099
|
// src/hooks/lifecycle.ts
|
|
14631
14100
|
var registry = {
|
|
@@ -14692,10 +14161,10 @@ function getApiUrl(path2) {
|
|
|
14692
14161
|
return `${base}${path2}`;
|
|
14693
14162
|
}
|
|
14694
14163
|
function useKyroQuery(slug, options = {}) {
|
|
14695
|
-
const [data, setData] =
|
|
14696
|
-
const [loading, setLoading] =
|
|
14697
|
-
const [error, setError] =
|
|
14698
|
-
const fetchData =
|
|
14164
|
+
const [data, setData] = React56.useState(null);
|
|
14165
|
+
const [loading, setLoading] = React56.useState(true);
|
|
14166
|
+
const [error, setError] = React56.useState(null);
|
|
14167
|
+
const fetchData = React56.useCallback(async () => {
|
|
14699
14168
|
setLoading(true);
|
|
14700
14169
|
setError(null);
|
|
14701
14170
|
try {
|
|
@@ -14717,15 +14186,15 @@ function useKyroQuery(slug, options = {}) {
|
|
|
14717
14186
|
setLoading(false);
|
|
14718
14187
|
}
|
|
14719
14188
|
}, [slug, options.page, options.limit, options.sort, options.order]);
|
|
14720
|
-
|
|
14189
|
+
React56.useEffect(() => {
|
|
14721
14190
|
fetchData();
|
|
14722
14191
|
}, [fetchData]);
|
|
14723
14192
|
return { data, loading, error, refetch: fetchData };
|
|
14724
14193
|
}
|
|
14725
14194
|
function useKyroMutation(slug, method = "POST") {
|
|
14726
|
-
const [loading, setLoading] =
|
|
14727
|
-
const [error, setError] =
|
|
14728
|
-
const mutate =
|
|
14195
|
+
const [loading, setLoading] = React56.useState(false);
|
|
14196
|
+
const [error, setError] = React56.useState(null);
|
|
14197
|
+
const mutate = React56.useCallback(
|
|
14729
14198
|
async (data) => {
|
|
14730
14199
|
setLoading(true);
|
|
14731
14200
|
setError(null);
|