@commercetools-demo/puck-content-manager 0.5.2 → 0.6.0
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.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +735 -468
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +791 -460
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -19
package/dist/index.mjs
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
// src/ContentManager.tsx
|
|
2
2
|
import { useState } from "react";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
3
|
+
import {
|
|
4
|
+
PuckApiProvider,
|
|
5
|
+
usePuckContents,
|
|
6
|
+
usePuckTemplates
|
|
7
|
+
} from "@commercetools-demo/puck-api";
|
|
8
|
+
import {
|
|
9
|
+
Badge,
|
|
10
|
+
Button,
|
|
11
|
+
Card,
|
|
12
|
+
DataTable,
|
|
13
|
+
Dialog,
|
|
14
|
+
FormField,
|
|
15
|
+
Icon,
|
|
16
|
+
IconButton,
|
|
17
|
+
LoadingSpinner,
|
|
18
|
+
Select,
|
|
19
|
+
Stack,
|
|
20
|
+
Text,
|
|
21
|
+
TextInput
|
|
22
|
+
} from "@commercetools/nimbus";
|
|
23
|
+
import { Add, Close, Delete, Edit } from "@commercetools/nimbus-icons";
|
|
16
24
|
|
|
17
25
|
// src/EnsureIntlProvider.tsx
|
|
18
26
|
import { useContext } from "react";
|
|
@@ -38,25 +46,28 @@ var EnsureIntlProvider = ({ children }) => {
|
|
|
38
46
|
);
|
|
39
47
|
};
|
|
40
48
|
|
|
49
|
+
// src/EnsureNimbusProvider.tsx
|
|
50
|
+
import { NimbusProvider } from "@commercetools/nimbus";
|
|
51
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
52
|
+
var EnsureNimbusProvider = ({
|
|
53
|
+
locale = "en",
|
|
54
|
+
children
|
|
55
|
+
}) => /* @__PURE__ */ jsx2(NimbusProvider, { locale, children });
|
|
56
|
+
|
|
41
57
|
// src/ContentManager.tsx
|
|
42
|
-
import { jsx as
|
|
43
|
-
var columns = [
|
|
44
|
-
{ key: "name", label: "Name" },
|
|
45
|
-
{ key: "contentType", label: "Content Type" },
|
|
46
|
-
{ key: "status", label: "Status" },
|
|
47
|
-
{ key: "updatedAt", label: "Updated" },
|
|
48
|
-
{ key: "actions", label: "Actions", shouldIgnoreRowClick: true }
|
|
49
|
-
];
|
|
58
|
+
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
50
59
|
var ContentList = ({ defaultContentType, onEdit }) => {
|
|
51
|
-
const { contents, loading, error,
|
|
52
|
-
const
|
|
60
|
+
const { contents, loading, error, createContent, deleteContent } = usePuckContents(defaultContentType);
|
|
61
|
+
const { templates } = usePuckTemplates("content");
|
|
62
|
+
const [search, setSearch] = useState("");
|
|
53
63
|
const [showCreate, setShowCreate] = useState(false);
|
|
54
64
|
const [createName, setCreateName] = useState("");
|
|
55
65
|
const [createType, setCreateType] = useState(defaultContentType ?? "");
|
|
66
|
+
const [templateKey, setTemplateKey] = useState("");
|
|
56
67
|
const [createError, setCreateError] = useState(null);
|
|
57
68
|
const [creating, setCreating] = useState(false);
|
|
58
69
|
const [deleting, setDeleting] = useState(null);
|
|
59
|
-
const
|
|
70
|
+
const [pendingDelete, setPendingDelete] = useState(null);
|
|
60
71
|
const handleCreate = async () => {
|
|
61
72
|
setCreateError(null);
|
|
62
73
|
if (!createName.trim()) {
|
|
@@ -69,168 +80,231 @@ var ContentList = ({ defaultContentType, onEdit }) => {
|
|
|
69
80
|
}
|
|
70
81
|
setCreating(true);
|
|
71
82
|
try {
|
|
83
|
+
const template = templateKey ? templates.find((t) => t.key === templateKey) : void 0;
|
|
72
84
|
const input = {
|
|
73
85
|
name: createName.trim(),
|
|
74
86
|
contentType: createType.trim(),
|
|
75
|
-
data: { content: [], root: { props: {} } }
|
|
87
|
+
data: template?.value.puckData ?? { content: [], root: { props: {} } }
|
|
76
88
|
};
|
|
77
89
|
await createContent(input);
|
|
78
90
|
setShowCreate(false);
|
|
79
91
|
setCreateName("");
|
|
80
92
|
setCreateType(defaultContentType ?? "");
|
|
93
|
+
setTemplateKey("");
|
|
81
94
|
} catch (err) {
|
|
82
95
|
setCreateError(err.message);
|
|
83
96
|
} finally {
|
|
84
97
|
setCreating(false);
|
|
85
98
|
}
|
|
86
99
|
};
|
|
87
|
-
const handleDelete = async (
|
|
88
|
-
|
|
89
|
-
setDeleting(key);
|
|
100
|
+
const handleDelete = async (item) => {
|
|
101
|
+
setDeleting(item.key);
|
|
90
102
|
try {
|
|
91
|
-
await deleteContent(key);
|
|
103
|
+
await deleteContent(item.key);
|
|
104
|
+
setPendingDelete(null);
|
|
92
105
|
} finally {
|
|
93
106
|
setDeleting(null);
|
|
94
107
|
}
|
|
95
108
|
};
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
109
|
+
const term = search.trim().toLowerCase();
|
|
110
|
+
const filteredContents = term ? contents.filter(
|
|
111
|
+
(c) => c.value.name.toLowerCase().includes(term) || c.value.contentType.toLowerCase().includes(term)
|
|
112
|
+
) : contents;
|
|
113
|
+
const rows = filteredContents.map((c) => ({ ...c, id: c.key }));
|
|
114
|
+
const columns = [
|
|
115
|
+
{
|
|
116
|
+
id: "name",
|
|
117
|
+
header: "Name",
|
|
118
|
+
accessor: (row) => row.value.name,
|
|
119
|
+
render: ({ row }) => /* @__PURE__ */ jsx3(Text, { fontWeight: "bold", children: row.value.name })
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
id: "contentType",
|
|
123
|
+
header: "Content Type",
|
|
124
|
+
accessor: (row) => row.value.contentType,
|
|
125
|
+
render: ({ row }) => /* @__PURE__ */ jsx3(
|
|
126
|
+
"code",
|
|
102
127
|
{
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
128
|
+
style: {
|
|
129
|
+
background: "#f4f4f4",
|
|
130
|
+
padding: "2px 6px",
|
|
131
|
+
borderRadius: "4px",
|
|
132
|
+
fontSize: "11px",
|
|
133
|
+
fontFamily: "monospace"
|
|
134
|
+
},
|
|
135
|
+
children: row.value.contentType
|
|
106
136
|
}
|
|
107
137
|
)
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
/* @__PURE__ */ jsxs(Spacings.Inline, { scale: "s", children: [
|
|
139
|
-
/* @__PURE__ */ jsx2(
|
|
140
|
-
PrimaryButton,
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: "status",
|
|
141
|
+
header: "Status",
|
|
142
|
+
accessor: () => "",
|
|
143
|
+
isSortable: false,
|
|
144
|
+
render: ({ row }) => {
|
|
145
|
+
const hasDraft = !!row.states.draft;
|
|
146
|
+
const hasPublished = !!row.states.published;
|
|
147
|
+
return /* @__PURE__ */ jsxs(Stack, { direction: "row", gap: "100", wrap: "wrap", children: [
|
|
148
|
+
hasDraft && /* @__PURE__ */ jsx3(Badge, { colorPalette: "warning", size: "xs", children: "Draft" }),
|
|
149
|
+
hasPublished && /* @__PURE__ */ jsx3(Badge, { colorPalette: "positive", size: "xs", children: "Published" }),
|
|
150
|
+
!hasDraft && !hasPublished && /* @__PURE__ */ jsx3(Badge, { colorPalette: "neutral", size: "xs", children: "No state" })
|
|
151
|
+
] });
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
id: "updatedAt",
|
|
156
|
+
header: "Updated",
|
|
157
|
+
accessor: (row) => row.value.updatedAt,
|
|
158
|
+
render: ({ row }) => /* @__PURE__ */ jsx3(Text, { color: "neutral.11", children: new Date(row.value.updatedAt).toLocaleDateString() })
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
id: "actions",
|
|
162
|
+
header: "Actions",
|
|
163
|
+
accessor: () => "",
|
|
164
|
+
isSortable: false,
|
|
165
|
+
render: ({ row }) => /* @__PURE__ */ jsxs(Stack, { direction: "row", gap: "100", alignItems: "center", children: [
|
|
166
|
+
/* @__PURE__ */ jsx3(
|
|
167
|
+
IconButton,
|
|
141
168
|
{
|
|
142
|
-
label:
|
|
143
|
-
|
|
144
|
-
|
|
169
|
+
"aria-label": `Edit ${row.value.name}`,
|
|
170
|
+
variant: "ghost",
|
|
171
|
+
size: "xs",
|
|
172
|
+
onPress: () => onEdit(row),
|
|
173
|
+
children: /* @__PURE__ */ jsx3(Edit, {})
|
|
145
174
|
}
|
|
146
175
|
),
|
|
147
|
-
/* @__PURE__ */
|
|
176
|
+
/* @__PURE__ */ jsx3(
|
|
177
|
+
IconButton,
|
|
178
|
+
{
|
|
179
|
+
"aria-label": `Delete ${row.value.name}`,
|
|
180
|
+
variant: "ghost",
|
|
181
|
+
colorPalette: "critical",
|
|
182
|
+
size: "xs",
|
|
183
|
+
isDisabled: deleting === row.key,
|
|
184
|
+
onPress: () => setPendingDelete(row),
|
|
185
|
+
children: /* @__PURE__ */ jsx3(Delete, {})
|
|
186
|
+
}
|
|
187
|
+
)
|
|
148
188
|
] })
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
189
|
+
}
|
|
190
|
+
];
|
|
191
|
+
return /* @__PURE__ */ jsxs("div", { style: { maxWidth: "1200px", margin: "0 auto", padding: "32px 24px" }, children: [
|
|
192
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "column", gap: "600", children: [
|
|
193
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", children: [
|
|
194
|
+
/* @__PURE__ */ jsx3(Text, { as: "h1", fontSize: "2xl", fontWeight: "700", children: "Content Items" }),
|
|
195
|
+
/* @__PURE__ */ jsxs(Button, { variant: "solid", onPress: () => setShowCreate((v) => !v), children: [
|
|
196
|
+
/* @__PURE__ */ jsx3(Icon, { as: Add }),
|
|
197
|
+
" New Content"
|
|
198
|
+
] })
|
|
199
|
+
] }),
|
|
200
|
+
showCreate && /* @__PURE__ */ jsx3(Card.Root, { variant: "outlined", children: /* @__PURE__ */ jsx3(Card.Body, { children: /* @__PURE__ */ jsxs(Stack, { direction: "column", gap: "400", children: [
|
|
201
|
+
/* @__PURE__ */ jsx3(Text, { as: "h4", fontSize: "xl", fontWeight: "700", children: "Create Content Item" }),
|
|
202
|
+
createError && /* @__PURE__ */ jsx3(Text, { color: "critical.11", children: createError }),
|
|
203
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "row", gap: "400", children: [
|
|
204
|
+
/* @__PURE__ */ jsx3("div", { style: { flex: 1 }, children: /* @__PURE__ */ jsxs(FormField.Root, { children: [
|
|
205
|
+
/* @__PURE__ */ jsx3(FormField.Label, { children: "Name" }),
|
|
206
|
+
/* @__PURE__ */ jsx3(FormField.Input, { children: /* @__PURE__ */ jsx3(
|
|
207
|
+
TextInput,
|
|
208
|
+
{
|
|
209
|
+
value: createName,
|
|
210
|
+
onChange: (v) => setCreateName(v),
|
|
211
|
+
placeholder: "e.g. Homepage Hero"
|
|
212
|
+
}
|
|
213
|
+
) })
|
|
214
|
+
] }) }),
|
|
215
|
+
/* @__PURE__ */ jsx3("div", { style: { flex: 1 }, children: /* @__PURE__ */ jsxs(FormField.Root, { children: [
|
|
216
|
+
/* @__PURE__ */ jsx3(FormField.Label, { children: "Content Type" }),
|
|
217
|
+
/* @__PURE__ */ jsx3(FormField.Input, { children: /* @__PURE__ */ jsx3(
|
|
218
|
+
TextInput,
|
|
219
|
+
{
|
|
220
|
+
value: createType,
|
|
221
|
+
onChange: (v) => setCreateType(v),
|
|
222
|
+
placeholder: "e.g. hero, banner"
|
|
223
|
+
}
|
|
224
|
+
) })
|
|
225
|
+
] }) })
|
|
226
|
+
] }),
|
|
227
|
+
/* @__PURE__ */ jsxs(FormField.Root, { children: [
|
|
228
|
+
/* @__PURE__ */ jsx3(FormField.Label, { children: "Template" }),
|
|
229
|
+
/* @__PURE__ */ jsx3(FormField.Input, { children: /* @__PURE__ */ jsx3(
|
|
230
|
+
Select.Root,
|
|
231
|
+
{
|
|
232
|
+
"aria-label": "Template",
|
|
233
|
+
selectedKey: templateKey || "empty",
|
|
234
|
+
onSelectionChange: (key) => setTemplateKey(key == null || key === "empty" ? "" : String(key)),
|
|
235
|
+
children: /* @__PURE__ */ jsxs(Select.Options, { children: [
|
|
236
|
+
/* @__PURE__ */ jsx3(Select.Option, { id: "empty", children: "Empty" }),
|
|
237
|
+
templates.map((t) => /* @__PURE__ */ jsx3(Select.Option, { id: t.key, children: t.value.name }, t.key))
|
|
238
|
+
] })
|
|
239
|
+
}
|
|
240
|
+
) })
|
|
241
|
+
] }),
|
|
242
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "row", gap: "200", children: [
|
|
243
|
+
/* @__PURE__ */ jsx3(Button, { variant: "solid", onPress: () => void handleCreate(), isDisabled: creating, children: creating ? "Creating\u2026" : "Create" }),
|
|
244
|
+
/* @__PURE__ */ jsx3(Button, { variant: "outline", onPress: () => setShowCreate(false), children: "Cancel" })
|
|
245
|
+
] })
|
|
246
|
+
] }) }) }),
|
|
247
|
+
/* @__PURE__ */ jsx3("div", { style: { maxWidth: 360 }, children: /* @__PURE__ */ jsx3(
|
|
152
248
|
TextInput,
|
|
153
249
|
{
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
250
|
+
"aria-label": "Search content",
|
|
251
|
+
placeholder: "Search by name or content type\u2026",
|
|
252
|
+
value: search,
|
|
253
|
+
onChange: (v) => setSearch(v),
|
|
254
|
+
width: "100%",
|
|
255
|
+
trailingElement: search !== "" ? /* @__PURE__ */ jsx3(
|
|
256
|
+
IconButton,
|
|
257
|
+
{
|
|
258
|
+
"aria-label": "Clear search",
|
|
259
|
+
variant: "ghost",
|
|
260
|
+
colorPalette: "neutral",
|
|
261
|
+
size: "2xs",
|
|
262
|
+
onPress: () => setSearch(""),
|
|
263
|
+
children: /* @__PURE__ */ jsx3(Close, {})
|
|
264
|
+
}
|
|
265
|
+
) : void 0
|
|
157
266
|
}
|
|
158
267
|
) }),
|
|
159
|
-
/* @__PURE__ */
|
|
160
|
-
|
|
161
|
-
{
|
|
162
|
-
label: "Filter",
|
|
163
|
-
iconLeft: /* @__PURE__ */ jsx2(SearchIcon, {}),
|
|
164
|
-
onClick: handleFilter
|
|
165
|
-
}
|
|
166
|
-
),
|
|
167
|
-
/* @__PURE__ */ jsx2(
|
|
168
|
-
FlatButton,
|
|
169
|
-
{
|
|
170
|
-
label: "Clear",
|
|
171
|
-
onClick: () => {
|
|
172
|
-
setFilterType("");
|
|
173
|
-
void fetchContents(void 0);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
),
|
|
177
|
-
/* @__PURE__ */ jsx2(FlatButton, { label: "Refresh", onClick: () => void refresh() })
|
|
268
|
+
error && /* @__PURE__ */ jsx3(Text, { color: "critical.11", children: error }),
|
|
269
|
+
loading ? /* @__PURE__ */ jsx3("div", { style: { display: "flex", justifyContent: "center", padding: "48px" }, children: /* @__PURE__ */ jsx3(LoadingSpinner, {}) }) : contents.length === 0 ? /* @__PURE__ */ jsx3(Stack, { direction: "column", gap: "400", alignItems: "center", children: /* @__PURE__ */ jsx3(Text, { color: "neutral.11", children: "No content items found." }) }) : /* @__PURE__ */ jsx3(DataTable, { columns, rows, "aria-label": "Content items" })
|
|
178
270
|
] }),
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
DataTable,
|
|
271
|
+
/* @__PURE__ */ jsx3(
|
|
272
|
+
Dialog.Root,
|
|
182
273
|
{
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
case "actions":
|
|
215
|
-
return /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
216
|
-
/* @__PURE__ */ jsx2(PrimaryButton, { label: "Edit", size: "20", onClick: () => onEdit(row) }),
|
|
217
|
-
/* @__PURE__ */ jsx2(
|
|
218
|
-
FlatButton,
|
|
219
|
-
{
|
|
220
|
-
tone: "critical",
|
|
221
|
-
label: deleting === row.key ? "\u2026" : "Delete",
|
|
222
|
-
isDisabled: deleting === row.key,
|
|
223
|
-
onClick: () => void handleDelete(row.key)
|
|
224
|
-
}
|
|
225
|
-
)
|
|
226
|
-
] });
|
|
227
|
-
default:
|
|
228
|
-
return null;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
274
|
+
isOpen: pendingDelete !== null,
|
|
275
|
+
onOpenChange: (open) => {
|
|
276
|
+
if (!open) setPendingDelete(null);
|
|
277
|
+
},
|
|
278
|
+
children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
|
279
|
+
/* @__PURE__ */ jsxs(Dialog.Header, { children: [
|
|
280
|
+
/* @__PURE__ */ jsx3(Dialog.Title, { children: "Delete content item?" }),
|
|
281
|
+
/* @__PURE__ */ jsx3(Dialog.CloseTrigger, {})
|
|
282
|
+
] }),
|
|
283
|
+
/* @__PURE__ */ jsx3(Dialog.Body, { children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
284
|
+
"Are you sure you want to delete",
|
|
285
|
+
" ",
|
|
286
|
+
/* @__PURE__ */ jsx3(Text, { as: "span", fontWeight: "700", children: pendingDelete?.value.name }),
|
|
287
|
+
" ",
|
|
288
|
+
"and all its versions? This cannot be undone."
|
|
289
|
+
] }) }),
|
|
290
|
+
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
|
291
|
+
/* @__PURE__ */ jsx3(Button, { slot: "close", variant: "outline", isDisabled: deleting !== null, children: "Cancel" }),
|
|
292
|
+
/* @__PURE__ */ jsx3(
|
|
293
|
+
Button,
|
|
294
|
+
{
|
|
295
|
+
colorPalette: "critical",
|
|
296
|
+
isDisabled: deleting !== null,
|
|
297
|
+
onPress: () => {
|
|
298
|
+
if (pendingDelete) void handleDelete(pendingDelete);
|
|
299
|
+
},
|
|
300
|
+
children: deleting !== null ? "Deleting\u2026" : "Delete"
|
|
301
|
+
}
|
|
302
|
+
)
|
|
303
|
+
] })
|
|
304
|
+
] })
|
|
231
305
|
}
|
|
232
306
|
)
|
|
233
|
-
] })
|
|
307
|
+
] });
|
|
234
308
|
};
|
|
235
309
|
var ContentManagerList = ({
|
|
236
310
|
baseURL,
|
|
@@ -239,27 +313,35 @@ var ContentManagerList = ({
|
|
|
239
313
|
jwtToken,
|
|
240
314
|
defaultContentType,
|
|
241
315
|
onEdit
|
|
242
|
-
}) => /* @__PURE__ */
|
|
316
|
+
}) => /* @__PURE__ */ jsx3(EnsureNimbusProvider, { children: /* @__PURE__ */ jsx3(EnsureIntlProvider, { children: /* @__PURE__ */ jsx3(
|
|
243
317
|
PuckApiProvider,
|
|
244
318
|
{
|
|
245
319
|
baseURL,
|
|
246
320
|
projectKey,
|
|
247
321
|
businessUnitKey,
|
|
248
322
|
jwtToken,
|
|
249
|
-
children: /* @__PURE__ */
|
|
323
|
+
children: /* @__PURE__ */ jsx3(ContentList, { defaultContentType, onEdit })
|
|
250
324
|
}
|
|
251
|
-
) });
|
|
325
|
+
) }) });
|
|
252
326
|
|
|
253
327
|
// src/ContentEditor.tsx
|
|
254
328
|
import { useCallback, useMemo, useRef, useState as useState2 } from "react";
|
|
255
329
|
import { Puck } from "@measured/puck";
|
|
256
330
|
import "@measured/puck/puck.css";
|
|
257
|
-
import {
|
|
331
|
+
import {
|
|
332
|
+
PuckApiProvider as PuckApiProvider2,
|
|
333
|
+
usePuckContent,
|
|
334
|
+
usePuckTemplates as usePuckTemplates2
|
|
335
|
+
} from "@commercetools-demo/puck-api";
|
|
258
336
|
import {
|
|
259
337
|
ComponentSearchProvider,
|
|
260
338
|
ComponentsPanel,
|
|
261
339
|
ComponentItemFilter,
|
|
262
|
-
|
|
340
|
+
CreateTemplateDialog,
|
|
341
|
+
EditorToolbar,
|
|
342
|
+
nimbusFieldTypes,
|
|
343
|
+
stripPuckDataToTemplate,
|
|
344
|
+
useDirtyState
|
|
263
345
|
} from "@commercetools-demo/puck-editor";
|
|
264
346
|
import {
|
|
265
347
|
VersionHistoryProvider,
|
|
@@ -269,10 +351,8 @@ import {
|
|
|
269
351
|
useVersionHistoryPanel,
|
|
270
352
|
useVersionDiff
|
|
271
353
|
} from "@commercetools-demo/puck-version-history";
|
|
272
|
-
import LoadingSpinner2 from "@commercetools
|
|
273
|
-
import
|
|
274
|
-
import Spacings2 from "@commercetools-uikit/spacings";
|
|
275
|
-
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
354
|
+
import { LoadingSpinner as LoadingSpinner2, Stack as Stack2, Text as Text2 } from "@commercetools/nimbus";
|
|
355
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
276
356
|
var ContentEditorInner = ({
|
|
277
357
|
contentKey,
|
|
278
358
|
config,
|
|
@@ -292,9 +372,12 @@ var ContentEditorInner = ({
|
|
|
292
372
|
revertToPublished,
|
|
293
373
|
loadVersions
|
|
294
374
|
} = usePuckContent(contentKey);
|
|
375
|
+
const { createTemplate } = usePuckTemplates2("content");
|
|
295
376
|
const latestDataRef = useRef(null);
|
|
296
|
-
const [hasUnsavedChanges, setHasUnsavedChanges] = useState2(false);
|
|
297
377
|
const [isApplyingVersion, setIsApplyingVersion] = useState2(false);
|
|
378
|
+
const [reloadNonce, setReloadNonce] = useState2(0);
|
|
379
|
+
const [templateDialogOpen, setTemplateDialogOpen] = useState2(false);
|
|
380
|
+
const [templateSaving, setTemplateSaving] = useState2(false);
|
|
298
381
|
const currentData = states.draft?.data ?? content?.data ?? {
|
|
299
382
|
content: [],
|
|
300
383
|
root: { props: {} }
|
|
@@ -310,39 +393,44 @@ var ContentEditorInner = ({
|
|
|
310
393
|
);
|
|
311
394
|
const isPreviewingRef = useRef(false);
|
|
312
395
|
isPreviewingRef.current = versionHistory.isPreviewingHistory;
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
396
|
+
const canvasKey = `${contentKey}:${versionHistory.selectedVersionId ?? "current"}:${reloadNonce}`;
|
|
397
|
+
const { isDirty: hasUnsavedChanges, markChange, markSaved } = useDirtyState(canvasKey);
|
|
398
|
+
const handleChange = useCallback(
|
|
399
|
+
(data) => {
|
|
400
|
+
if (isPreviewingRef.current) return;
|
|
401
|
+
latestDataRef.current = data;
|
|
402
|
+
markChange(data);
|
|
403
|
+
},
|
|
404
|
+
[markChange]
|
|
405
|
+
);
|
|
318
406
|
const handleSave = useCallback(async () => {
|
|
319
407
|
const data = latestDataRef.current;
|
|
320
408
|
if (!data) return;
|
|
321
409
|
try {
|
|
322
410
|
await saveDraft(data);
|
|
323
|
-
|
|
411
|
+
markSaved(data);
|
|
324
412
|
onSave?.(data);
|
|
325
413
|
} catch (err) {
|
|
326
414
|
onError?.(err);
|
|
327
415
|
}
|
|
328
|
-
}, [saveDraft, onSave, onError]);
|
|
416
|
+
}, [saveDraft, onSave, onError, markSaved]);
|
|
329
417
|
const handlePublish = useCallback(
|
|
330
418
|
async (data) => {
|
|
331
419
|
try {
|
|
332
420
|
await saveDraft(data);
|
|
333
|
-
|
|
421
|
+
markSaved(data);
|
|
334
422
|
await publish(false);
|
|
335
423
|
onPublish?.(data);
|
|
336
424
|
} catch (err) {
|
|
337
425
|
onError?.(err);
|
|
338
426
|
}
|
|
339
427
|
},
|
|
340
|
-
[saveDraft, publish, onPublish, onError]
|
|
428
|
+
[saveDraft, publish, onPublish, onError, markSaved]
|
|
341
429
|
);
|
|
342
430
|
const handleRevert = useCallback(async () => {
|
|
343
431
|
try {
|
|
344
432
|
await revertToPublished();
|
|
345
|
-
|
|
433
|
+
setReloadNonce((n) => n + 1);
|
|
346
434
|
} catch (err) {
|
|
347
435
|
onError?.(err);
|
|
348
436
|
}
|
|
@@ -353,7 +441,7 @@ var ContentEditorInner = ({
|
|
|
353
441
|
setIsApplyingVersion(true);
|
|
354
442
|
try {
|
|
355
443
|
await saveDraft(versionData);
|
|
356
|
-
|
|
444
|
+
markSaved(versionData);
|
|
357
445
|
onSave?.(versionData);
|
|
358
446
|
versionHistory.clearSelection();
|
|
359
447
|
} catch (err) {
|
|
@@ -361,7 +449,7 @@ var ContentEditorInner = ({
|
|
|
361
449
|
} finally {
|
|
362
450
|
setIsApplyingVersion(false);
|
|
363
451
|
}
|
|
364
|
-
}, [versionHistory, saveDraft, onSave, onError]);
|
|
452
|
+
}, [versionHistory, saveDraft, onSave, onError, markSaved]);
|
|
365
453
|
const contentConfig = useMemo(() => {
|
|
366
454
|
const otherRootFields = Object.fromEntries(
|
|
367
455
|
Object.entries(config.root?.fields ?? {}).filter(([k]) => k !== "title")
|
|
@@ -383,22 +471,38 @@ var ContentEditorInner = ({
|
|
|
383
471
|
}
|
|
384
472
|
};
|
|
385
473
|
}, [config]);
|
|
474
|
+
const handleCreateTemplate = useCallback(
|
|
475
|
+
async (name, withoutData) => {
|
|
476
|
+
const source = latestDataRef.current ?? currentData;
|
|
477
|
+
const puckData = withoutData ? stripPuckDataToTemplate(source, contentConfig) : source;
|
|
478
|
+
setTemplateSaving(true);
|
|
479
|
+
try {
|
|
480
|
+
await createTemplate({ name, kind: "content", puckData });
|
|
481
|
+
setTemplateDialogOpen(false);
|
|
482
|
+
} catch (err) {
|
|
483
|
+
onError?.(err);
|
|
484
|
+
} finally {
|
|
485
|
+
setTemplateSaving(false);
|
|
486
|
+
}
|
|
487
|
+
},
|
|
488
|
+
[createTemplate, currentData, contentConfig, onError]
|
|
489
|
+
);
|
|
386
490
|
if (loading) {
|
|
387
|
-
return /* @__PURE__ */
|
|
388
|
-
/* @__PURE__ */
|
|
389
|
-
/* @__PURE__ */
|
|
491
|
+
return /* @__PURE__ */ jsx4("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", height: "100vh" }, children: /* @__PURE__ */ jsxs2(Stack2, { direction: "column", gap: "400", alignItems: "center", children: [
|
|
492
|
+
/* @__PURE__ */ jsx4(LoadingSpinner2, {}),
|
|
493
|
+
/* @__PURE__ */ jsx4(Text2, { color: "neutral.11", children: "Loading editor\u2026" })
|
|
390
494
|
] }) });
|
|
391
495
|
}
|
|
392
496
|
if (error) {
|
|
393
|
-
return /* @__PURE__ */
|
|
394
|
-
/* @__PURE__ */
|
|
497
|
+
return /* @__PURE__ */ jsx4("div", { style: { padding: "32px" }, children: /* @__PURE__ */ jsxs2(Text2, { color: "critical.11", children: [
|
|
498
|
+
/* @__PURE__ */ jsx4("strong", { children: "Error loading content:" }),
|
|
395
499
|
" ",
|
|
396
500
|
error
|
|
397
501
|
] }) });
|
|
398
502
|
}
|
|
399
503
|
const activeData = versionHistory.previewData ?? currentData;
|
|
400
504
|
const toolbarStates = states;
|
|
401
|
-
return /* @__PURE__ */
|
|
505
|
+
return /* @__PURE__ */ jsx4(
|
|
402
506
|
VersionHistoryProvider,
|
|
403
507
|
{
|
|
404
508
|
diff,
|
|
@@ -411,44 +515,70 @@ var ContentEditorInner = ({
|
|
|
411
515
|
onApply: () => void handleApplyVersion(),
|
|
412
516
|
onDiscard: versionHistory.clearSelection,
|
|
413
517
|
onLoadVersions: versionHistory.openPanel,
|
|
414
|
-
children: /* @__PURE__ */
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
518
|
+
children: /* @__PURE__ */ jsxs2(ComponentSearchProvider, { children: [
|
|
519
|
+
/* @__PURE__ */ jsx4(
|
|
520
|
+
Puck,
|
|
521
|
+
{
|
|
522
|
+
config: contentConfig,
|
|
523
|
+
data: activeData,
|
|
524
|
+
onChange: handleChange,
|
|
525
|
+
onPublish: handlePublish,
|
|
526
|
+
overrides: {
|
|
527
|
+
fieldTypes: nimbusFieldTypes,
|
|
528
|
+
header: () => versionHistory.isPreviewingHistory ? /* @__PURE__ */ jsxs2(
|
|
529
|
+
Stack2,
|
|
530
|
+
{
|
|
531
|
+
gridArea: "header",
|
|
532
|
+
direction: "row",
|
|
533
|
+
gap: "200",
|
|
534
|
+
alignItems: "center",
|
|
535
|
+
justifyContent: "flex-end",
|
|
536
|
+
padding: "200",
|
|
537
|
+
children: [
|
|
538
|
+
/* @__PURE__ */ jsx4(
|
|
539
|
+
VersionPreviewBanner,
|
|
540
|
+
{
|
|
541
|
+
timestamp: versionHistory.selectedVersion.timestamp,
|
|
542
|
+
onApply: () => void handleApplyVersion(),
|
|
543
|
+
onDiscard: versionHistory.clearSelection,
|
|
544
|
+
isApplying: isApplyingVersion
|
|
545
|
+
}
|
|
546
|
+
),
|
|
547
|
+
/* @__PURE__ */ jsx4(VersionHistoryButton, { disabled: isApplyingVersion })
|
|
548
|
+
]
|
|
549
|
+
}
|
|
550
|
+
) : /* @__PURE__ */ jsx4(
|
|
551
|
+
EditorToolbar,
|
|
425
552
|
{
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
553
|
+
title: content?.name ?? "Content",
|
|
554
|
+
saving,
|
|
555
|
+
isDirty: hasUnsavedChanges,
|
|
556
|
+
states: toolbarStates,
|
|
557
|
+
onSave: () => void handleSave(),
|
|
558
|
+
onPublish: () => void handlePublish(activeData),
|
|
559
|
+
onRevert: () => void handleRevert(),
|
|
560
|
+
onCreateTemplate: () => setTemplateDialogOpen(true),
|
|
561
|
+
createTemplateLabel: "Create a template from this content",
|
|
562
|
+
showPublishButton: true
|
|
430
563
|
}
|
|
431
564
|
),
|
|
432
|
-
/* @__PURE__ */
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
componentItem: ({ children, name }) => /* @__PURE__ */ jsx3(ComponentItemFilter, { name, children }),
|
|
447
|
-
fields: ({ children, isLoading }) => /* @__PURE__ */ jsx3(VersionAwareFieldsPanel, { isLoading, children })
|
|
565
|
+
components: ({ children }) => /* @__PURE__ */ jsx4(ComponentsPanel, { children }),
|
|
566
|
+
componentItem: ({ children, name }) => /* @__PURE__ */ jsx4(ComponentItemFilter, { name, children }),
|
|
567
|
+
fields: ({ children, isLoading }) => /* @__PURE__ */ jsx4(VersionAwareFieldsPanel, { isLoading, children })
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
`${versionHistory.selectedVersionId ?? "current"}:${reloadNonce}`
|
|
571
|
+
),
|
|
572
|
+
/* @__PURE__ */ jsx4(
|
|
573
|
+
CreateTemplateDialog,
|
|
574
|
+
{
|
|
575
|
+
isOpen: templateDialogOpen,
|
|
576
|
+
onOpenChange: (open) => setTemplateDialogOpen(open),
|
|
577
|
+
onConfirm: handleCreateTemplate,
|
|
578
|
+
saving: templateSaving
|
|
448
579
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
) })
|
|
580
|
+
)
|
|
581
|
+
] })
|
|
452
582
|
}
|
|
453
583
|
);
|
|
454
584
|
};
|
|
@@ -457,19 +587,21 @@ var ContentEditor = ({
|
|
|
457
587
|
projectKey,
|
|
458
588
|
businessUnitKey,
|
|
459
589
|
jwtToken,
|
|
590
|
+
locale,
|
|
460
591
|
contentKey,
|
|
461
592
|
config,
|
|
462
593
|
onPublish,
|
|
463
594
|
onSave,
|
|
464
595
|
onError
|
|
465
|
-
}) => /* @__PURE__ */
|
|
596
|
+
}) => /* @__PURE__ */ jsx4(EnsureNimbusProvider, { locale, children: /* @__PURE__ */ jsx4(EnsureIntlProvider, { children: /* @__PURE__ */ jsx4(
|
|
466
597
|
PuckApiProvider2,
|
|
467
598
|
{
|
|
468
599
|
baseURL,
|
|
469
600
|
projectKey,
|
|
470
601
|
businessUnitKey,
|
|
471
602
|
jwtToken,
|
|
472
|
-
|
|
603
|
+
locale,
|
|
604
|
+
children: /* @__PURE__ */ jsx4(
|
|
473
605
|
ContentEditorInner,
|
|
474
606
|
{
|
|
475
607
|
contentKey,
|
|
@@ -480,7 +612,7 @@ var ContentEditor = ({
|
|
|
480
612
|
}
|
|
481
613
|
)
|
|
482
614
|
}
|
|
483
|
-
) });
|
|
615
|
+
) }) });
|
|
484
616
|
|
|
485
617
|
// src/ContentManagerRouter.tsx
|
|
486
618
|
import { useState as useState3, useCallback as useCallback2, useMemo as useMemo2, useRef as useRef2 } from "react";
|
|
@@ -498,9 +630,16 @@ import {
|
|
|
498
630
|
ComponentSearchProvider as ComponentSearchProvider2,
|
|
499
631
|
ComponentsPanel as ComponentsPanel2,
|
|
500
632
|
ComponentItemFilter as ComponentItemFilter2,
|
|
633
|
+
CreateTemplateDialog as CreateTemplateDialog2,
|
|
501
634
|
defaultPuckConfig,
|
|
502
|
-
EditorToolbar as EditorToolbar2
|
|
635
|
+
EditorToolbar as EditorToolbar2,
|
|
636
|
+
nimbusFieldTypes as nimbusFieldTypes2,
|
|
637
|
+
PropertiesResizer,
|
|
638
|
+
stripPuckDataToTemplate as stripPuckDataToTemplate2,
|
|
639
|
+
UnsavedChangesDialog,
|
|
640
|
+
useDirtyState as useDirtyState2
|
|
503
641
|
} from "@commercetools-demo/puck-editor";
|
|
642
|
+
import { PuckRenderer } from "@commercetools-demo/puck-renderer";
|
|
504
643
|
import {
|
|
505
644
|
VersionHistoryProvider as VersionHistoryProvider2,
|
|
506
645
|
VersionHistoryButton as VersionHistoryButton2,
|
|
@@ -512,21 +651,33 @@ import {
|
|
|
512
651
|
import {
|
|
513
652
|
PuckApiProvider as PuckApiProvider3,
|
|
514
653
|
usePuckContents as usePuckContents2,
|
|
515
|
-
usePuckContent as usePuckContent2
|
|
654
|
+
usePuckContent as usePuckContent2,
|
|
655
|
+
usePuckTemplates as usePuckTemplates3
|
|
516
656
|
} from "@commercetools-demo/puck-api";
|
|
517
|
-
import
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
657
|
+
import {
|
|
658
|
+
Badge as Badge2,
|
|
659
|
+
Button as Button2,
|
|
660
|
+
Card as Card2,
|
|
661
|
+
DataTable as DataTable2,
|
|
662
|
+
Dialog as Dialog2,
|
|
663
|
+
FormField as FormField2,
|
|
664
|
+
Icon as Icon2,
|
|
665
|
+
IconButton as IconButton2,
|
|
666
|
+
LoadingSpinner as LoadingSpinner3,
|
|
667
|
+
Select as Select2,
|
|
668
|
+
Stack as Stack3,
|
|
669
|
+
Text as Text3,
|
|
670
|
+
TextInput as TextInput2
|
|
671
|
+
} from "@commercetools/nimbus";
|
|
672
|
+
import {
|
|
673
|
+
Add as Add2,
|
|
674
|
+
ChevronLeft,
|
|
675
|
+
Close as Close2,
|
|
676
|
+
Delete as Delete2,
|
|
677
|
+
Edit as Edit2,
|
|
678
|
+
Visibility
|
|
679
|
+
} from "@commercetools/nimbus-icons";
|
|
680
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
530
681
|
var DEFAULT_CONFIG = {
|
|
531
682
|
...defaultPuckConfig,
|
|
532
683
|
components: { ...defaultPuckConfig.components }
|
|
@@ -539,28 +690,23 @@ var NAV_BAR_STYLE = {
|
|
|
539
690
|
gap: "12px",
|
|
540
691
|
padding: "8px 16px",
|
|
541
692
|
background: "var(--color-surface, #fff)",
|
|
542
|
-
borderBottom: "1px solid var(--color-neutral-90)",
|
|
693
|
+
borderBottom: "1px solid var(--color-neutral-90, #e0e0e0)",
|
|
543
694
|
zIndex: 200,
|
|
544
695
|
flexShrink: 0
|
|
545
696
|
};
|
|
546
|
-
var COLUMNS = [
|
|
547
|
-
{ key: "name", label: "Name" },
|
|
548
|
-
{ key: "contentType", label: "Content Type" },
|
|
549
|
-
{ key: "status", label: "Status" },
|
|
550
|
-
{ key: "updatedAt", label: "Updated" },
|
|
551
|
-
{ key: "actions", label: "Actions", shouldIgnoreRowClick: true }
|
|
552
|
-
];
|
|
553
697
|
var ContentListRoute = ({ defaultContentType, backButton }) => {
|
|
554
698
|
const history = useHistory();
|
|
555
|
-
const { contents, loading, error,
|
|
556
|
-
const
|
|
699
|
+
const { contents, loading, error, createContent, deleteContent } = usePuckContents2(defaultContentType);
|
|
700
|
+
const { templates } = usePuckTemplates3("content");
|
|
701
|
+
const [search, setSearch] = useState3("");
|
|
557
702
|
const [showCreate, setShowCreate] = useState3(false);
|
|
558
703
|
const [createName, setCreateName] = useState3("");
|
|
559
704
|
const [createType, setCreateType] = useState3(defaultContentType ?? "");
|
|
705
|
+
const [templateKey, setTemplateKey] = useState3("");
|
|
560
706
|
const [createError, setCreateError] = useState3(null);
|
|
561
707
|
const [creating, setCreating] = useState3(false);
|
|
562
708
|
const [deleting, setDeleting] = useState3(null);
|
|
563
|
-
const
|
|
709
|
+
const [pendingDelete, setPendingDelete] = useState3(null);
|
|
564
710
|
const handleCreate = async () => {
|
|
565
711
|
setCreateError(null);
|
|
566
712
|
if (!createName.trim()) {
|
|
@@ -573,15 +719,17 @@ var ContentListRoute = ({ defaultContentType, backButton }) => {
|
|
|
573
719
|
}
|
|
574
720
|
setCreating(true);
|
|
575
721
|
try {
|
|
722
|
+
const template = templateKey ? templates.find((t) => t.key === templateKey) : void 0;
|
|
576
723
|
const input = {
|
|
577
724
|
name: createName.trim(),
|
|
578
725
|
contentType: createType.trim(),
|
|
579
|
-
data: { content: [], root: { props: {} } }
|
|
726
|
+
data: template?.value.puckData ?? { content: [], root: { props: {} } }
|
|
580
727
|
};
|
|
581
728
|
const created = await createContent(input);
|
|
582
729
|
setShowCreate(false);
|
|
583
730
|
setCreateName("");
|
|
584
731
|
setCreateType(defaultContentType ?? "");
|
|
732
|
+
setTemplateKey("");
|
|
585
733
|
history.push(`/${created.key}`, { contentName: created.value.name });
|
|
586
734
|
} catch (err) {
|
|
587
735
|
setCreateError(err.message);
|
|
@@ -589,163 +737,227 @@ var ContentListRoute = ({ defaultContentType, backButton }) => {
|
|
|
589
737
|
setCreating(false);
|
|
590
738
|
}
|
|
591
739
|
};
|
|
592
|
-
const handleDelete = async (
|
|
593
|
-
|
|
594
|
-
setDeleting(key);
|
|
740
|
+
const handleDelete = async (item) => {
|
|
741
|
+
setDeleting(item.key);
|
|
595
742
|
try {
|
|
596
|
-
await deleteContent(key);
|
|
743
|
+
await deleteContent(item.key);
|
|
744
|
+
setPendingDelete(null);
|
|
597
745
|
} finally {
|
|
598
746
|
setDeleting(null);
|
|
599
747
|
}
|
|
600
748
|
};
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
749
|
+
const term = search.trim().toLowerCase();
|
|
750
|
+
const filteredContents = term ? contents.filter(
|
|
751
|
+
(c) => c.value.name.toLowerCase().includes(term) || c.value.contentType.toLowerCase().includes(term)
|
|
752
|
+
) : contents;
|
|
753
|
+
const rows = filteredContents.map((c) => ({ ...c, id: c.key }));
|
|
754
|
+
const columns = [
|
|
755
|
+
{
|
|
756
|
+
id: "name",
|
|
757
|
+
header: "Name",
|
|
758
|
+
accessor: (row) => row.value.name,
|
|
759
|
+
render: ({ row }) => /* @__PURE__ */ jsx5(Text3, { fontWeight: "bold", children: row.value.name })
|
|
760
|
+
},
|
|
761
|
+
{
|
|
762
|
+
id: "contentType",
|
|
763
|
+
header: "Content Type",
|
|
764
|
+
accessor: (row) => row.value.contentType,
|
|
765
|
+
render: ({ row }) => /* @__PURE__ */ jsx5(
|
|
766
|
+
"code",
|
|
610
767
|
{
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
768
|
+
style: {
|
|
769
|
+
background: "#f4f4f4",
|
|
770
|
+
padding: "2px 6px",
|
|
771
|
+
borderRadius: "4px",
|
|
772
|
+
fontSize: "11px",
|
|
773
|
+
fontFamily: "monospace"
|
|
774
|
+
},
|
|
775
|
+
children: row.value.contentType
|
|
614
776
|
}
|
|
615
777
|
)
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
778
|
+
},
|
|
779
|
+
{
|
|
780
|
+
id: "status",
|
|
781
|
+
header: "Status",
|
|
782
|
+
accessor: () => "",
|
|
783
|
+
isSortable: false,
|
|
784
|
+
render: ({ row }) => {
|
|
785
|
+
const hasDraft = !!row.states.draft;
|
|
786
|
+
const hasPublished = !!row.states.published;
|
|
787
|
+
return /* @__PURE__ */ jsxs3(Stack3, { direction: "row", gap: "100", wrap: "wrap", children: [
|
|
788
|
+
hasDraft && /* @__PURE__ */ jsx5(Badge2, { colorPalette: "warning", size: "xs", children: "Draft" }),
|
|
789
|
+
hasPublished && /* @__PURE__ */ jsx5(Badge2, { colorPalette: "positive", size: "xs", children: "Published" }),
|
|
790
|
+
!hasDraft && !hasPublished && /* @__PURE__ */ jsx5(Badge2, { colorPalette: "neutral", size: "xs", children: "No state" })
|
|
791
|
+
] });
|
|
792
|
+
}
|
|
793
|
+
},
|
|
794
|
+
{
|
|
795
|
+
id: "updatedAt",
|
|
796
|
+
header: "Updated",
|
|
797
|
+
accessor: (row) => row.value.updatedAt,
|
|
798
|
+
render: ({ row }) => /* @__PURE__ */ jsx5(Text3, { color: "neutral.11", children: new Date(row.value.updatedAt).toLocaleDateString() })
|
|
799
|
+
},
|
|
800
|
+
{
|
|
801
|
+
id: "actions",
|
|
802
|
+
header: "Actions",
|
|
803
|
+
accessor: () => "",
|
|
804
|
+
isSortable: false,
|
|
805
|
+
render: ({ row }) => /* @__PURE__ */ jsxs3(Stack3, { direction: "row", gap: "100", alignItems: "center", children: [
|
|
806
|
+
/* @__PURE__ */ jsx5(
|
|
807
|
+
IconButton2,
|
|
808
|
+
{
|
|
809
|
+
"aria-label": `Edit ${row.value.name}`,
|
|
810
|
+
variant: "ghost",
|
|
811
|
+
size: "xs",
|
|
812
|
+
onPress: () => history.push(`/${row.key}`, { contentName: row.value.name }),
|
|
813
|
+
children: /* @__PURE__ */ jsx5(Edit2, {})
|
|
814
|
+
}
|
|
815
|
+
),
|
|
816
|
+
/* @__PURE__ */ jsx5(
|
|
817
|
+
IconButton2,
|
|
649
818
|
{
|
|
650
|
-
label:
|
|
651
|
-
|
|
652
|
-
|
|
819
|
+
"aria-label": `Preview ${row.value.name}`,
|
|
820
|
+
variant: "ghost",
|
|
821
|
+
size: "xs",
|
|
822
|
+
onPress: () => history.push(`/${row.key}/preview`, { contentName: row.value.name }),
|
|
823
|
+
children: /* @__PURE__ */ jsx5(Visibility, {})
|
|
653
824
|
}
|
|
654
825
|
),
|
|
655
|
-
/* @__PURE__ */
|
|
826
|
+
/* @__PURE__ */ jsx5(
|
|
827
|
+
IconButton2,
|
|
828
|
+
{
|
|
829
|
+
"aria-label": `Delete ${row.value.name}`,
|
|
830
|
+
variant: "ghost",
|
|
831
|
+
colorPalette: "critical",
|
|
832
|
+
size: "xs",
|
|
833
|
+
isDisabled: deleting === row.key,
|
|
834
|
+
onPress: () => setPendingDelete(row),
|
|
835
|
+
children: /* @__PURE__ */ jsx5(Delete2, {})
|
|
836
|
+
}
|
|
837
|
+
)
|
|
656
838
|
] })
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
839
|
+
}
|
|
840
|
+
];
|
|
841
|
+
return /* @__PURE__ */ jsxs3("div", { style: { maxWidth: "1200px", margin: "0 auto", padding: "32px 24px" }, children: [
|
|
842
|
+
/* @__PURE__ */ jsxs3(Stack3, { direction: "column", gap: "600", children: [
|
|
843
|
+
/* @__PURE__ */ jsxs3(Stack3, { direction: "row", justifyContent: "space-between", alignItems: "center", children: [
|
|
844
|
+
/* @__PURE__ */ jsxs3(Stack3, { direction: "row", gap: "400", alignItems: "center", children: [
|
|
845
|
+
backButton,
|
|
846
|
+
/* @__PURE__ */ jsx5(Text3, { as: "h1", fontSize: "2xl", fontWeight: "700", children: "Content Items" })
|
|
847
|
+
] }),
|
|
848
|
+
/* @__PURE__ */ jsxs3(Button2, { variant: "solid", onPress: () => setShowCreate((v) => !v), children: [
|
|
849
|
+
/* @__PURE__ */ jsx5(Icon2, { as: Add2 }),
|
|
850
|
+
" New Content"
|
|
851
|
+
] })
|
|
852
|
+
] }),
|
|
853
|
+
showCreate && /* @__PURE__ */ jsx5(Card2.Root, { variant: "outlined", children: /* @__PURE__ */ jsx5(Card2.Body, { children: /* @__PURE__ */ jsxs3(Stack3, { direction: "column", gap: "400", children: [
|
|
854
|
+
/* @__PURE__ */ jsx5(Text3, { as: "h4", fontSize: "xl", fontWeight: "700", children: "Create Content Item" }),
|
|
855
|
+
createError && /* @__PURE__ */ jsx5(Text3, { color: "critical.11", children: createError }),
|
|
856
|
+
/* @__PURE__ */ jsxs3(Stack3, { direction: "row", gap: "400", children: [
|
|
857
|
+
/* @__PURE__ */ jsx5("div", { style: { flex: 1 }, children: /* @__PURE__ */ jsxs3(FormField2.Root, { children: [
|
|
858
|
+
/* @__PURE__ */ jsx5(FormField2.Label, { children: "Name" }),
|
|
859
|
+
/* @__PURE__ */ jsx5(FormField2.Input, { children: /* @__PURE__ */ jsx5(
|
|
860
|
+
TextInput2,
|
|
861
|
+
{
|
|
862
|
+
value: createName,
|
|
863
|
+
onChange: (v) => setCreateName(v),
|
|
864
|
+
placeholder: "e.g. Homepage Hero"
|
|
865
|
+
}
|
|
866
|
+
) })
|
|
867
|
+
] }) }),
|
|
868
|
+
/* @__PURE__ */ jsx5("div", { style: { flex: 1 }, children: /* @__PURE__ */ jsxs3(FormField2.Root, { children: [
|
|
869
|
+
/* @__PURE__ */ jsx5(FormField2.Label, { children: "Content Type" }),
|
|
870
|
+
/* @__PURE__ */ jsx5(FormField2.Input, { children: /* @__PURE__ */ jsx5(
|
|
871
|
+
TextInput2,
|
|
872
|
+
{
|
|
873
|
+
value: createType,
|
|
874
|
+
onChange: (v) => setCreateType(v),
|
|
875
|
+
placeholder: "e.g. hero, banner"
|
|
876
|
+
}
|
|
877
|
+
) })
|
|
878
|
+
] }) })
|
|
879
|
+
] }),
|
|
880
|
+
/* @__PURE__ */ jsxs3(FormField2.Root, { children: [
|
|
881
|
+
/* @__PURE__ */ jsx5(FormField2.Label, { children: "Template" }),
|
|
882
|
+
/* @__PURE__ */ jsx5(FormField2.Input, { children: /* @__PURE__ */ jsx5(
|
|
883
|
+
Select2.Root,
|
|
884
|
+
{
|
|
885
|
+
"aria-label": "Template",
|
|
886
|
+
selectedKey: templateKey || "empty",
|
|
887
|
+
onSelectionChange: (key) => setTemplateKey(key == null || key === "empty" ? "" : String(key)),
|
|
888
|
+
children: /* @__PURE__ */ jsxs3(Select2.Options, { children: [
|
|
889
|
+
/* @__PURE__ */ jsx5(Select2.Option, { id: "empty", children: "Empty" }),
|
|
890
|
+
templates.map((t) => /* @__PURE__ */ jsx5(Select2.Option, { id: t.key, children: t.value.name }, t.key))
|
|
891
|
+
] })
|
|
892
|
+
}
|
|
893
|
+
) })
|
|
894
|
+
] }),
|
|
895
|
+
/* @__PURE__ */ jsxs3(Stack3, { direction: "row", gap: "200", children: [
|
|
896
|
+
/* @__PURE__ */ jsx5(Button2, { variant: "solid", onPress: () => void handleCreate(), isDisabled: creating, children: creating ? "Creating\u2026" : "Create" }),
|
|
897
|
+
/* @__PURE__ */ jsx5(Button2, { variant: "outline", onPress: () => setShowCreate(false), children: "Cancel" })
|
|
898
|
+
] })
|
|
899
|
+
] }) }) }),
|
|
900
|
+
/* @__PURE__ */ jsx5("div", { style: { maxWidth: 360 }, children: /* @__PURE__ */ jsx5(
|
|
660
901
|
TextInput2,
|
|
661
902
|
{
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
903
|
+
"aria-label": "Search content",
|
|
904
|
+
placeholder: "Search by name or content type\u2026",
|
|
905
|
+
value: search,
|
|
906
|
+
onChange: (v) => setSearch(v),
|
|
907
|
+
width: "100%",
|
|
908
|
+
trailingElement: search !== "" ? /* @__PURE__ */ jsx5(
|
|
909
|
+
IconButton2,
|
|
910
|
+
{
|
|
911
|
+
"aria-label": "Clear search",
|
|
912
|
+
variant: "ghost",
|
|
913
|
+
colorPalette: "neutral",
|
|
914
|
+
size: "2xs",
|
|
915
|
+
onPress: () => setSearch(""),
|
|
916
|
+
children: /* @__PURE__ */ jsx5(Close2, {})
|
|
917
|
+
}
|
|
918
|
+
) : void 0
|
|
665
919
|
}
|
|
666
920
|
) }),
|
|
667
|
-
/* @__PURE__ */
|
|
668
|
-
|
|
669
|
-
{
|
|
670
|
-
label: "Filter",
|
|
671
|
-
iconLeft: /* @__PURE__ */ jsx4(SearchIcon2, {}),
|
|
672
|
-
onClick: handleFilter
|
|
673
|
-
}
|
|
674
|
-
),
|
|
675
|
-
/* @__PURE__ */ jsx4(
|
|
676
|
-
FlatButton2,
|
|
677
|
-
{
|
|
678
|
-
label: "Clear",
|
|
679
|
-
onClick: () => {
|
|
680
|
-
setFilterType("");
|
|
681
|
-
void fetchContents(void 0);
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
),
|
|
685
|
-
/* @__PURE__ */ jsx4(FlatButton2, { label: "Refresh", onClick: () => void refresh() })
|
|
921
|
+
error && /* @__PURE__ */ jsx5(Text3, { color: "critical.11", children: error }),
|
|
922
|
+
loading ? /* @__PURE__ */ jsx5("div", { style: { display: "flex", justifyContent: "center", padding: "48px" }, children: /* @__PURE__ */ jsx5(LoadingSpinner3, {}) }) : contents.length === 0 ? /* @__PURE__ */ jsx5(Stack3, { direction: "column", gap: "400", alignItems: "center", children: /* @__PURE__ */ jsx5(Text3, { color: "neutral.11", children: "No content items found." }) }) : /* @__PURE__ */ jsx5(DataTable2, { columns, rows, "aria-label": "Content items" })
|
|
686
923
|
] }),
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
DataTable2,
|
|
924
|
+
/* @__PURE__ */ jsx5(
|
|
925
|
+
Dialog2.Root,
|
|
690
926
|
{
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
case "actions":
|
|
723
|
-
return /* @__PURE__ */ jsxs3(Spacings3.Inline, { scale: "s", alignItems: "center", children: [
|
|
724
|
-
/* @__PURE__ */ jsx4(
|
|
725
|
-
PrimaryButton2,
|
|
726
|
-
{
|
|
727
|
-
label: "Edit",
|
|
728
|
-
size: "20",
|
|
729
|
-
onClick: () => history.push(`/${row.key}`, { contentName: row.value.name })
|
|
730
|
-
}
|
|
731
|
-
),
|
|
732
|
-
/* @__PURE__ */ jsx4(
|
|
733
|
-
FlatButton2,
|
|
734
|
-
{
|
|
735
|
-
tone: "critical",
|
|
736
|
-
label: deleting === row.key ? "\u2026" : "Delete",
|
|
737
|
-
isDisabled: deleting === row.key,
|
|
738
|
-
onClick: () => void handleDelete(row.key)
|
|
739
|
-
}
|
|
740
|
-
)
|
|
741
|
-
] });
|
|
742
|
-
default:
|
|
743
|
-
return null;
|
|
744
|
-
}
|
|
745
|
-
}
|
|
927
|
+
isOpen: pendingDelete !== null,
|
|
928
|
+
onOpenChange: (open) => {
|
|
929
|
+
if (!open) setPendingDelete(null);
|
|
930
|
+
},
|
|
931
|
+
children: /* @__PURE__ */ jsxs3(Dialog2.Content, { children: [
|
|
932
|
+
/* @__PURE__ */ jsxs3(Dialog2.Header, { children: [
|
|
933
|
+
/* @__PURE__ */ jsx5(Dialog2.Title, { children: "Delete content item?" }),
|
|
934
|
+
/* @__PURE__ */ jsx5(Dialog2.CloseTrigger, {})
|
|
935
|
+
] }),
|
|
936
|
+
/* @__PURE__ */ jsx5(Dialog2.Body, { children: /* @__PURE__ */ jsxs3(Text3, { children: [
|
|
937
|
+
"Are you sure you want to delete",
|
|
938
|
+
" ",
|
|
939
|
+
/* @__PURE__ */ jsx5(Text3, { as: "span", fontWeight: "700", children: pendingDelete?.value.name }),
|
|
940
|
+
" ",
|
|
941
|
+
"and all its versions? This cannot be undone."
|
|
942
|
+
] }) }),
|
|
943
|
+
/* @__PURE__ */ jsxs3(Dialog2.Footer, { children: [
|
|
944
|
+
/* @__PURE__ */ jsx5(Button2, { slot: "close", variant: "outline", isDisabled: deleting !== null, children: "Cancel" }),
|
|
945
|
+
/* @__PURE__ */ jsx5(
|
|
946
|
+
Button2,
|
|
947
|
+
{
|
|
948
|
+
colorPalette: "critical",
|
|
949
|
+
isDisabled: deleting !== null,
|
|
950
|
+
onPress: () => {
|
|
951
|
+
if (pendingDelete) void handleDelete(pendingDelete);
|
|
952
|
+
},
|
|
953
|
+
children: deleting !== null ? "Deleting\u2026" : "Delete"
|
|
954
|
+
}
|
|
955
|
+
)
|
|
956
|
+
] })
|
|
957
|
+
] })
|
|
746
958
|
}
|
|
747
959
|
)
|
|
748
|
-
] })
|
|
960
|
+
] });
|
|
749
961
|
};
|
|
750
962
|
var ContentEditorRoute = ({ config, backButton }) => {
|
|
751
963
|
const { contentKey } = useParams();
|
|
@@ -764,9 +976,13 @@ var ContentEditorRoute = ({ config, backButton }) => {
|
|
|
764
976
|
revertToPublished,
|
|
765
977
|
loadVersions
|
|
766
978
|
} = usePuckContent2(contentKey);
|
|
979
|
+
const { createTemplate } = usePuckTemplates3("content");
|
|
767
980
|
const latestDataRef = useRef2(null);
|
|
768
|
-
const [hasUnsavedChanges, setHasUnsavedChanges] = useState3(false);
|
|
769
981
|
const [isApplyingVersion, setIsApplyingVersion] = useState3(false);
|
|
982
|
+
const [reloadNonce, setReloadNonce] = useState3(0);
|
|
983
|
+
const [pendingNav, setPendingNav] = useState3(null);
|
|
984
|
+
const [templateDialogOpen, setTemplateDialogOpen] = useState3(false);
|
|
985
|
+
const [templateSaving, setTemplateSaving] = useState3(false);
|
|
770
986
|
const currentData = states.draft?.data ?? content?.data ?? { content: [], root: { props: {} } };
|
|
771
987
|
const versionHistory = useVersionHistoryPanel2({
|
|
772
988
|
versions,
|
|
@@ -776,37 +992,52 @@ var ContentEditorRoute = ({ config, backButton }) => {
|
|
|
776
992
|
const diff = useVersionDiff2(versionHistory.previewData, currentData);
|
|
777
993
|
const isPreviewingRef = useRef2(false);
|
|
778
994
|
isPreviewingRef.current = versionHistory.isPreviewingHistory;
|
|
779
|
-
const
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
995
|
+
const canvasKey = `${contentKey}:${versionHistory.selectedVersionId ?? "current"}:${reloadNonce}`;
|
|
996
|
+
const { isDirty: hasUnsavedChanges, markChange, markSaved } = useDirtyState2(canvasKey);
|
|
997
|
+
const guardedNavigate = useCallback2(
|
|
998
|
+
(navFn) => {
|
|
999
|
+
if (hasUnsavedChanges) {
|
|
1000
|
+
setPendingNav(() => navFn);
|
|
1001
|
+
} else {
|
|
1002
|
+
navFn();
|
|
1003
|
+
}
|
|
1004
|
+
},
|
|
1005
|
+
[hasUnsavedChanges]
|
|
1006
|
+
);
|
|
1007
|
+
const handleChange = useCallback2(
|
|
1008
|
+
(data) => {
|
|
1009
|
+
if (isPreviewingRef.current) return;
|
|
1010
|
+
latestDataRef.current = data;
|
|
1011
|
+
markChange(data);
|
|
1012
|
+
},
|
|
1013
|
+
[markChange]
|
|
1014
|
+
);
|
|
784
1015
|
const handleSave = useCallback2(async () => {
|
|
785
1016
|
const data = latestDataRef.current;
|
|
786
1017
|
if (!data) return;
|
|
787
1018
|
try {
|
|
788
1019
|
await saveDraft(data);
|
|
789
|
-
|
|
1020
|
+
markSaved(data);
|
|
790
1021
|
} catch (err) {
|
|
791
1022
|
console.error("[ContentManagerRouter] save error:", err);
|
|
792
1023
|
}
|
|
793
|
-
}, [saveDraft]);
|
|
1024
|
+
}, [saveDraft, markSaved]);
|
|
794
1025
|
const handlePublish = useCallback2(
|
|
795
1026
|
async (data) => {
|
|
796
1027
|
try {
|
|
797
1028
|
await saveDraft(data);
|
|
798
|
-
|
|
1029
|
+
markSaved(data);
|
|
799
1030
|
await publish(false);
|
|
800
1031
|
} catch (err) {
|
|
801
1032
|
console.error("[ContentManagerRouter] publish error:", err);
|
|
802
1033
|
}
|
|
803
1034
|
},
|
|
804
|
-
[saveDraft, publish]
|
|
1035
|
+
[saveDraft, publish, markSaved]
|
|
805
1036
|
);
|
|
806
1037
|
const handleRevert = useCallback2(async () => {
|
|
807
1038
|
try {
|
|
808
1039
|
await revertToPublished();
|
|
809
|
-
|
|
1040
|
+
setReloadNonce((n) => n + 1);
|
|
810
1041
|
} catch (err) {
|
|
811
1042
|
console.error("[ContentManagerRouter] revert error:", err);
|
|
812
1043
|
}
|
|
@@ -817,14 +1048,14 @@ var ContentEditorRoute = ({ config, backButton }) => {
|
|
|
817
1048
|
setIsApplyingVersion(true);
|
|
818
1049
|
try {
|
|
819
1050
|
await saveDraft(versionData);
|
|
820
|
-
|
|
1051
|
+
markSaved(versionData);
|
|
821
1052
|
versionHistory.clearSelection();
|
|
822
1053
|
} catch (err) {
|
|
823
1054
|
console.error("[ContentManagerRouter] apply version error:", err);
|
|
824
1055
|
} finally {
|
|
825
1056
|
setIsApplyingVersion(false);
|
|
826
1057
|
}
|
|
827
|
-
}, [versionHistory, saveDraft]);
|
|
1058
|
+
}, [versionHistory, saveDraft, markSaved]);
|
|
828
1059
|
const contentConfig = useMemo2(() => {
|
|
829
1060
|
const otherRootFields = Object.fromEntries(
|
|
830
1061
|
Object.entries(config.root?.fields ?? {}).filter(([k]) => k !== "title")
|
|
@@ -846,22 +1077,38 @@ var ContentEditorRoute = ({ config, backButton }) => {
|
|
|
846
1077
|
}
|
|
847
1078
|
};
|
|
848
1079
|
}, [config]);
|
|
1080
|
+
const handleCreateTemplate = useCallback2(
|
|
1081
|
+
async (name, withoutData) => {
|
|
1082
|
+
const source = latestDataRef.current ?? currentData;
|
|
1083
|
+
const puckData = withoutData ? stripPuckDataToTemplate2(source, contentConfig) : source;
|
|
1084
|
+
setTemplateSaving(true);
|
|
1085
|
+
try {
|
|
1086
|
+
await createTemplate({ name, kind: "content", puckData });
|
|
1087
|
+
setTemplateDialogOpen(false);
|
|
1088
|
+
} catch (err) {
|
|
1089
|
+
console.error("[ContentManagerRouter] create template error:", err);
|
|
1090
|
+
} finally {
|
|
1091
|
+
setTemplateSaving(false);
|
|
1092
|
+
}
|
|
1093
|
+
},
|
|
1094
|
+
[createTemplate, currentData, contentConfig]
|
|
1095
|
+
);
|
|
849
1096
|
if (loading) {
|
|
850
|
-
return /* @__PURE__ */
|
|
851
|
-
/* @__PURE__ */
|
|
852
|
-
/* @__PURE__ */
|
|
1097
|
+
return /* @__PURE__ */ jsx5("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", height: "100vh" }, children: /* @__PURE__ */ jsxs3(Stack3, { direction: "column", gap: "400", alignItems: "center", children: [
|
|
1098
|
+
/* @__PURE__ */ jsx5(LoadingSpinner3, {}),
|
|
1099
|
+
/* @__PURE__ */ jsx5(Text3, { color: "neutral.11", children: "Loading editor\u2026" })
|
|
853
1100
|
] }) });
|
|
854
1101
|
}
|
|
855
1102
|
if (error) {
|
|
856
|
-
return /* @__PURE__ */
|
|
857
|
-
/* @__PURE__ */
|
|
1103
|
+
return /* @__PURE__ */ jsx5("div", { style: { padding: "32px" }, children: /* @__PURE__ */ jsxs3(Text3, { color: "critical.11", children: [
|
|
1104
|
+
/* @__PURE__ */ jsx5("strong", { children: "Error loading content:" }),
|
|
858
1105
|
" ",
|
|
859
1106
|
error
|
|
860
1107
|
] }) });
|
|
861
1108
|
}
|
|
862
1109
|
const activeData = versionHistory.previewData ?? currentData;
|
|
863
1110
|
const toolbarStates = states;
|
|
864
|
-
return /* @__PURE__ */
|
|
1111
|
+
return /* @__PURE__ */ jsxs3(
|
|
865
1112
|
VersionHistoryProvider2,
|
|
866
1113
|
{
|
|
867
1114
|
diff,
|
|
@@ -874,82 +1121,164 @@ var ContentEditorRoute = ({ config, backButton }) => {
|
|
|
874
1121
|
onApply: () => void handleApplyVersion(),
|
|
875
1122
|
onDiscard: versionHistory.clearSelection,
|
|
876
1123
|
onLoadVersions: versionHistory.openPanel,
|
|
877
|
-
children:
|
|
878
|
-
/* @__PURE__ */ jsxs3("div", { style:
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
1124
|
+
children: [
|
|
1125
|
+
/* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
|
|
1126
|
+
/* @__PURE__ */ jsxs3("div", { style: NAV_BAR_STYLE, children: [
|
|
1127
|
+
backButton,
|
|
1128
|
+
backButton && /* @__PURE__ */ jsx5(Text3, { color: "neutral.11", children: "/" }),
|
|
1129
|
+
/* @__PURE__ */ jsxs3(
|
|
1130
|
+
Button2,
|
|
1131
|
+
{
|
|
1132
|
+
variant: "ghost",
|
|
1133
|
+
onPress: () => guardedNavigate(() => history.push("/")),
|
|
1134
|
+
children: [
|
|
1135
|
+
/* @__PURE__ */ jsx5(Icon2, { as: ChevronLeft }),
|
|
1136
|
+
" Content Items"
|
|
1137
|
+
]
|
|
1138
|
+
}
|
|
1139
|
+
),
|
|
1140
|
+
/* @__PURE__ */ jsx5(Text3, { color: "neutral.11", children: "/" }),
|
|
1141
|
+
/* @__PURE__ */ jsx5(Text3, { fontWeight: "bold", children: contentName })
|
|
1142
|
+
] }),
|
|
1143
|
+
/* @__PURE__ */ jsxs3("div", { className: "puck-editor-fill", style: { flex: 1, overflow: "hidden" }, children: [
|
|
1144
|
+
/* @__PURE__ */ jsx5(ComponentSearchProvider2, { children: /* @__PURE__ */ jsx5(
|
|
1145
|
+
Puck2,
|
|
1146
|
+
{
|
|
1147
|
+
config: contentConfig,
|
|
1148
|
+
data: activeData,
|
|
1149
|
+
onChange: handleChange,
|
|
1150
|
+
onPublish: handlePublish,
|
|
1151
|
+
overrides: {
|
|
1152
|
+
fieldTypes: nimbusFieldTypes2,
|
|
1153
|
+
header: () => versionHistory.isPreviewingHistory ? /* @__PURE__ */ jsxs3(
|
|
1154
|
+
Stack3,
|
|
1155
|
+
{
|
|
1156
|
+
gridArea: "header",
|
|
1157
|
+
direction: "row",
|
|
1158
|
+
gap: "200",
|
|
1159
|
+
alignItems: "center",
|
|
1160
|
+
justifyContent: "flex-end",
|
|
1161
|
+
padding: "200",
|
|
1162
|
+
children: [
|
|
1163
|
+
/* @__PURE__ */ jsx5(
|
|
1164
|
+
VersionPreviewBanner2,
|
|
1165
|
+
{
|
|
1166
|
+
timestamp: versionHistory.selectedVersion.timestamp,
|
|
1167
|
+
onApply: () => void handleApplyVersion(),
|
|
1168
|
+
onDiscard: versionHistory.clearSelection,
|
|
1169
|
+
isApplying: isApplyingVersion
|
|
1170
|
+
}
|
|
1171
|
+
),
|
|
1172
|
+
/* @__PURE__ */ jsx5(VersionHistoryButton2, { disabled: isApplyingVersion })
|
|
1173
|
+
]
|
|
1174
|
+
}
|
|
1175
|
+
) : /* @__PURE__ */ jsx5(
|
|
1176
|
+
EditorToolbar2,
|
|
1177
|
+
{
|
|
1178
|
+
title: content?.name ?? contentName,
|
|
1179
|
+
saving,
|
|
1180
|
+
isDirty: hasUnsavedChanges,
|
|
1181
|
+
states: toolbarStates,
|
|
1182
|
+
onSave: () => void handleSave(),
|
|
1183
|
+
onPublish: () => void handlePublish(activeData),
|
|
1184
|
+
onRevert: () => void handleRevert(),
|
|
1185
|
+
onPreview: () => guardedNavigate(
|
|
1186
|
+
() => history.push(`/${contentKey}/preview`, { contentName })
|
|
1187
|
+
),
|
|
1188
|
+
onCreateTemplate: () => setTemplateDialogOpen(true),
|
|
1189
|
+
createTemplateLabel: "Create a template from this content",
|
|
1190
|
+
showPublishButton: true
|
|
1191
|
+
}
|
|
1192
|
+
),
|
|
1193
|
+
components: ({ children }) => /* @__PURE__ */ jsx5(ComponentsPanel2, { children }),
|
|
1194
|
+
componentItem: ({ children, name }) => /* @__PURE__ */ jsx5(ComponentItemFilter2, { name, children }),
|
|
1195
|
+
fields: ({ children, isLoading }) => /* @__PURE__ */ jsx5(VersionAwareFieldsPanel2, { isLoading, children })
|
|
1196
|
+
}
|
|
1197
|
+
},
|
|
1198
|
+
`${versionHistory.selectedVersionId ?? "current"}:${reloadNonce}`
|
|
1199
|
+
) }),
|
|
1200
|
+
/* @__PURE__ */ jsx5(PropertiesResizer, {})
|
|
1201
|
+
] })
|
|
892
1202
|
] }),
|
|
893
|
-
/* @__PURE__ */
|
|
894
|
-
|
|
1203
|
+
/* @__PURE__ */ jsx5(
|
|
1204
|
+
UnsavedChangesDialog,
|
|
895
1205
|
{
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
EditorToolbar2,
|
|
914
|
-
{
|
|
915
|
-
saving,
|
|
916
|
-
isDirty: hasUnsavedChanges,
|
|
917
|
-
states: toolbarStates,
|
|
918
|
-
onSave: () => void handleSave(),
|
|
919
|
-
onPublish: () => void handlePublish(activeData),
|
|
920
|
-
onRevert: () => void handleRevert(),
|
|
921
|
-
showPublishButton: true
|
|
922
|
-
}
|
|
923
|
-
),
|
|
924
|
-
components: ({ children }) => /* @__PURE__ */ jsx4(ComponentsPanel2, { children }),
|
|
925
|
-
componentItem: ({ children, name }) => /* @__PURE__ */ jsx4(ComponentItemFilter2, { name, children }),
|
|
926
|
-
fields: ({ children, isLoading }) => /* @__PURE__ */ jsx4(VersionAwareFieldsPanel2, { isLoading, children })
|
|
927
|
-
}
|
|
928
|
-
},
|
|
929
|
-
versionHistory.selectedVersionId ?? "current"
|
|
930
|
-
) }) })
|
|
931
|
-
] })
|
|
1206
|
+
isOpen: pendingNav !== null,
|
|
1207
|
+
onOpenChange: (open) => {
|
|
1208
|
+
if (!open) setPendingNav(null);
|
|
1209
|
+
},
|
|
1210
|
+
onConfirm: () => pendingNav?.()
|
|
1211
|
+
}
|
|
1212
|
+
),
|
|
1213
|
+
/* @__PURE__ */ jsx5(
|
|
1214
|
+
CreateTemplateDialog2,
|
|
1215
|
+
{
|
|
1216
|
+
isOpen: templateDialogOpen,
|
|
1217
|
+
onOpenChange: (open) => setTemplateDialogOpen(open),
|
|
1218
|
+
onConfirm: handleCreateTemplate,
|
|
1219
|
+
saving: templateSaving
|
|
1220
|
+
}
|
|
1221
|
+
)
|
|
1222
|
+
]
|
|
932
1223
|
}
|
|
933
1224
|
);
|
|
934
1225
|
};
|
|
1226
|
+
var ContentPreviewRoute = ({ config, backButton }) => {
|
|
1227
|
+
const { contentKey } = useParams();
|
|
1228
|
+
const history = useHistory();
|
|
1229
|
+
const location = useLocation();
|
|
1230
|
+
const contentName = location.state?.contentName ?? contentKey ?? "Content";
|
|
1231
|
+
return /* @__PURE__ */ jsxs3("div", { children: [
|
|
1232
|
+
/* @__PURE__ */ jsxs3("div", { style: NAV_BAR_STYLE, children: [
|
|
1233
|
+
backButton,
|
|
1234
|
+
backButton && /* @__PURE__ */ jsx5(Text3, { color: "neutral.11", children: "/" }),
|
|
1235
|
+
/* @__PURE__ */ jsxs3(Button2, { variant: "ghost", onPress: () => history.push("/"), children: [
|
|
1236
|
+
/* @__PURE__ */ jsx5(Icon2, { as: ChevronLeft }),
|
|
1237
|
+
" Content Items"
|
|
1238
|
+
] }),
|
|
1239
|
+
/* @__PURE__ */ jsx5(Text3, { color: "neutral.11", children: "/" }),
|
|
1240
|
+
/* @__PURE__ */ jsx5(
|
|
1241
|
+
Button2,
|
|
1242
|
+
{
|
|
1243
|
+
variant: "ghost",
|
|
1244
|
+
onPress: () => history.push(`/${contentKey}`, { contentName }),
|
|
1245
|
+
children: contentName
|
|
1246
|
+
}
|
|
1247
|
+
),
|
|
1248
|
+
/* @__PURE__ */ jsx5(Badge2, { colorPalette: "primary", size: "xs", children: "Preview" }),
|
|
1249
|
+
/* @__PURE__ */ jsx5("div", { style: { marginLeft: "auto" }, children: /* @__PURE__ */ jsxs3(Button2, { variant: "outline", size: "xs", onPress: () => history.goBack(), children: [
|
|
1250
|
+
/* @__PURE__ */ jsx5(Icon2, { as: Close2 }),
|
|
1251
|
+
" Close preview"
|
|
1252
|
+
] }) })
|
|
1253
|
+
] }),
|
|
1254
|
+
/* @__PURE__ */ jsx5(PuckRenderer, { type: "content", contentKey, mode: "preview", config })
|
|
1255
|
+
] });
|
|
1256
|
+
};
|
|
935
1257
|
var ContentManagerRouterInner = ({
|
|
936
1258
|
config,
|
|
937
1259
|
defaultContentType,
|
|
938
1260
|
backButton
|
|
939
1261
|
}) => /* @__PURE__ */ jsxs3(Switch, { children: [
|
|
940
|
-
/* @__PURE__ */
|
|
1262
|
+
/* @__PURE__ */ jsx5(
|
|
941
1263
|
Route,
|
|
942
1264
|
{
|
|
943
1265
|
exact: true,
|
|
944
1266
|
path: "/",
|
|
945
|
-
render: () => /* @__PURE__ */
|
|
1267
|
+
render: () => /* @__PURE__ */ jsx5(ContentListRoute, { defaultContentType, backButton })
|
|
1268
|
+
}
|
|
1269
|
+
),
|
|
1270
|
+
/* @__PURE__ */ jsx5(
|
|
1271
|
+
Route,
|
|
1272
|
+
{
|
|
1273
|
+
path: "/:contentKey/preview",
|
|
1274
|
+
render: () => /* @__PURE__ */ jsx5(ContentPreviewRoute, { config, backButton })
|
|
946
1275
|
}
|
|
947
1276
|
),
|
|
948
|
-
/* @__PURE__ */
|
|
1277
|
+
/* @__PURE__ */ jsx5(
|
|
949
1278
|
Route,
|
|
950
1279
|
{
|
|
951
1280
|
path: "/:contentKey",
|
|
952
|
-
render: () => /* @__PURE__ */
|
|
1281
|
+
render: () => /* @__PURE__ */ jsx5(ContentEditorRoute, { config, backButton })
|
|
953
1282
|
}
|
|
954
1283
|
)
|
|
955
1284
|
] });
|
|
@@ -959,17 +1288,19 @@ var ContentManager = ({
|
|
|
959
1288
|
projectKey,
|
|
960
1289
|
businessUnitKey,
|
|
961
1290
|
jwtToken,
|
|
1291
|
+
locale,
|
|
962
1292
|
config = DEFAULT_CONFIG,
|
|
963
1293
|
defaultContentType,
|
|
964
1294
|
backButton
|
|
965
|
-
}) => /* @__PURE__ */
|
|
1295
|
+
}) => /* @__PURE__ */ jsx5(EnsureNimbusProvider, { locale, children: /* @__PURE__ */ jsx5(EnsureIntlProvider, { children: /* @__PURE__ */ jsx5(
|
|
966
1296
|
PuckApiProvider3,
|
|
967
1297
|
{
|
|
968
1298
|
baseURL,
|
|
969
1299
|
projectKey,
|
|
970
1300
|
businessUnitKey,
|
|
971
1301
|
jwtToken,
|
|
972
|
-
|
|
1302
|
+
locale,
|
|
1303
|
+
children: /* @__PURE__ */ jsx5(BrowserRouter, { basename: parentUrl, children: /* @__PURE__ */ jsx5(
|
|
973
1304
|
ContentManagerRouterInner,
|
|
974
1305
|
{
|
|
975
1306
|
config,
|
|
@@ -978,7 +1309,7 @@ var ContentManager = ({
|
|
|
978
1309
|
}
|
|
979
1310
|
) })
|
|
980
1311
|
}
|
|
981
|
-
) });
|
|
1312
|
+
) }) });
|
|
982
1313
|
export {
|
|
983
1314
|
ContentEditor,
|
|
984
1315
|
ContentManager,
|