@commercetools-demo/puck-content-manager 0.5.2 → 0.6.1

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