@commercetools-demo/puck-page-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
@@ -65,42 +55,42 @@ var EnsureIntlProvider = ({ children }) => {
65
55
  );
66
56
  };
67
57
 
68
- // src/PageManager.tsx
69
- var import_data_table = __toESM(require("@commercetools-uikit/data-table"));
70
- var import_primary_button = __toESM(require("@commercetools-uikit/primary-button"));
71
- var import_secondary_button = __toESM(require("@commercetools-uikit/secondary-button"));
72
- var import_flat_button = __toESM(require("@commercetools-uikit/flat-button"));
73
- var import_card = __toESM(require("@commercetools-uikit/card"));
74
- var import_spacings = __toESM(require("@commercetools-uikit/spacings"));
75
- var import_text = __toESM(require("@commercetools-uikit/text"));
76
- var import_loading_spinner = __toESM(require("@commercetools-uikit/loading-spinner"));
77
- var import_text_input = __toESM(require("@commercetools-uikit/text-input"));
78
- var import_label = __toESM(require("@commercetools-uikit/label"));
79
- var import_icons = require("@commercetools-uikit/icons");
58
+ // src/EnsureNimbusProvider.tsx
59
+ var import_styled_system = require("@chakra-ui/react/styled-system");
60
+ var import_nimbus = require("@commercetools/nimbus");
80
61
  var import_jsx_runtime2 = require("react/jsx-runtime");
62
+ var SCOPED_SYSTEM_KEY = /* @__PURE__ */ Symbol.for(
63
+ "@commercetools-demo/puck:nimbus-scoped-system"
64
+ );
65
+ var globalScope = globalThis;
66
+ var scopedSystem = globalScope[SCOPED_SYSTEM_KEY] ?? (globalScope[SCOPED_SYSTEM_KEY] = (0, import_styled_system.createSystem)({
67
+ // `_config` is the fully-merged Nimbus + Chakra config used to build the
68
+ // stock system; reusing it keeps all Nimbus theming intact.
69
+ ...import_nimbus.system._config,
70
+ preflight: false,
71
+ globalCss: {}
72
+ }));
73
+ var EnsureNimbusProvider = ({
74
+ locale = "en",
75
+ children
76
+ }) => /* @__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 }) }) });
77
+
78
+ // src/PageManager.tsx
79
+ var import_nimbus2 = require("@commercetools/nimbus");
80
+ var import_nimbus_icons = require("@commercetools/nimbus-icons");
81
+ var import_jsx_runtime3 = require("react/jsx-runtime");
81
82
  var DEFAULT_CONFIG = {
82
83
  ...import_puck_editor.defaultPuckConfig,
83
84
  components: { ...import_puck_editor.defaultPuckConfig.components }
84
85
  };
86
+ var STATUS_BADGE = {
87
+ draft: { colorPalette: "warning", label: "Draft" },
88
+ published: { colorPalette: "positive", label: "Published" },
89
+ none: { colorPalette: "neutral", label: "No state" }
90
+ };
85
91
  var StatusBadge = ({ variant }) => {
86
- const styles = variant === "published" ? { background: "var(--color-success-95)", color: "var(--color-success-40)", border: "1px solid var(--color-success-85)" } : variant === "draft" ? { background: "var(--color-warning-95)", color: "var(--color-warning-40)", border: "1px solid var(--color-warning-85)" } : { background: "var(--color-neutral-95)", color: "var(--color-neutral-50)", border: "1px solid var(--color-neutral-85)" };
87
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
88
- "span",
89
- {
90
- style: {
91
- ...styles,
92
- display: "inline-flex",
93
- alignItems: "center",
94
- padding: "2px 8px",
95
- borderRadius: "var(--border-radius-20)",
96
- fontSize: "var(--font-size-10)",
97
- fontWeight: "var(--font-weight-600)",
98
- marginRight: "4px",
99
- whiteSpace: "nowrap"
100
- },
101
- children: variant === "published" ? "Published" : variant === "draft" ? "Draft" : "No state"
102
- }
103
- );
92
+ const meta = STATUS_BADGE[variant];
93
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Badge, { colorPalette: meta.colorPalette, size: "xs", children: meta.label });
104
94
  };
105
95
  var NAV_BAR_STYLE = {
106
96
  position: "sticky",
@@ -110,26 +100,23 @@ var NAV_BAR_STYLE = {
110
100
  gap: "12px",
111
101
  padding: "8px 16px",
112
102
  background: "var(--color-surface, #fff)",
113
- borderBottom: "1px solid var(--color-neutral-90)",
103
+ borderBottom: "1px solid var(--color-neutral-90, #e0e0e0)",
114
104
  zIndex: 200,
115
105
  flexShrink: 0
116
106
  };
117
- var COLUMNS = [
118
- { key: "name", label: "Name" },
119
- { key: "slug", label: "Slug" },
120
- { key: "status", label: "Status" },
121
- { key: "updatedAt", label: "Updated" },
122
- { key: "actions", label: "Actions", shouldIgnoreRowClick: true }
123
- ];
124
107
  var PageList = ({ backButton }) => {
125
108
  const history = (0, import_react_router_dom.useHistory)();
126
109
  const { pages, loading, error, createPage, deletePage, refresh } = (0, import_puck_api.usePuckPages)();
110
+ const { templates } = (0, import_puck_api.usePuckTemplates)("page");
127
111
  const [creating, setCreating] = (0, import_react2.useState)(false);
128
112
  const [newName, setNewName] = (0, import_react2.useState)("");
129
113
  const [newSlug, setNewSlug] = (0, import_react2.useState)("");
114
+ const [templateKey, setTemplateKey] = (0, import_react2.useState)("");
130
115
  const [formError, setFormError] = (0, import_react2.useState)("");
131
116
  const [submitting, setSubmitting] = (0, import_react2.useState)(false);
132
117
  const [deleting, setDeleting] = (0, import_react2.useState)(null);
118
+ const [pendingDelete, setPendingDelete] = (0, import_react2.useState)(null);
119
+ const [search, setSearch] = (0, import_react2.useState)("");
133
120
  const handleCreate = async () => {
134
121
  if (!newName.trim()) {
135
122
  setFormError("Name is required");
@@ -146,10 +133,15 @@ var PageList = ({ backButton }) => {
146
133
  name: newName.trim(),
147
134
  slug: newSlug.trim().startsWith("/") ? newSlug.trim() : `/${newSlug.trim()}`
148
135
  };
136
+ if (templateKey) {
137
+ const template = templates.find((t) => t.key === templateKey);
138
+ if (template) input.puckData = template.value.puckData;
139
+ }
149
140
  const created = await createPage(input);
150
141
  setCreating(false);
151
142
  setNewName("");
152
143
  setNewSlug("");
144
+ setTemplateKey("");
153
145
  history.push(`/${created.key}/edit`, { pageName: created.value.name });
154
146
  } catch (err) {
155
147
  setFormError(err.message);
@@ -158,206 +150,323 @@ var PageList = ({ backButton }) => {
158
150
  }
159
151
  };
160
152
  const handleDelete = async (page) => {
161
- if (!confirm(`Delete "${page.value.name}"? This cannot be undone.`)) return;
162
153
  setDeleting(page.key);
163
154
  try {
164
155
  await deletePage(page.key);
165
156
  await refresh();
157
+ setPendingDelete(null);
166
158
  } finally {
167
159
  setDeleting(null);
168
160
  }
169
161
  };
170
162
  if (loading) {
171
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { padding: "64px", display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_loading_spinner.default, {}) });
163
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { padding: "64px", display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.LoadingSpinner, {}) });
172
164
  }
173
165
  if (error) {
174
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { padding: "32px" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_text.default.Body, { tone: "negative", children: [
166
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { padding: "32px" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Text, { color: "critical.11", children: [
175
167
  "Error: ",
176
168
  error
177
169
  ] }) });
178
170
  }
179
- const rows = pages.map((p) => ({ ...p, id: p.key }));
180
- 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: [
181
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_spacings.default.Inline, { justifyContent: "space-between", alignItems: "center", children: [
182
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_spacings.default.Inline, { scale: "m", alignItems: "center", children: [
183
- backButton,
184
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_text.default.Headline, { as: "h1", children: "Puck Pages" })
185
- ] }),
186
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
187
- import_primary_button.default,
171
+ const term = search.trim().toLowerCase();
172
+ const filteredPages = term ? pages.filter(
173
+ (p) => p.value.name.toLowerCase().includes(term) || p.value.slug.toLowerCase().includes(term)
174
+ ) : pages;
175
+ const rows = filteredPages.map((p) => ({ ...p, id: p.key }));
176
+ const columns = [
177
+ {
178
+ id: "name",
179
+ header: "Name",
180
+ accessor: (row) => row.value.name,
181
+ render: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Text, { fontWeight: "bold", children: row.value.name })
182
+ },
183
+ {
184
+ id: "slug",
185
+ header: "Slug",
186
+ accessor: (row) => row.value.slug,
187
+ render: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
188
+ "code",
188
189
  {
189
- label: "New Page",
190
- iconLeft: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.PlusThinIcon, {}),
191
- onClick: () => setCreating(true)
190
+ style: {
191
+ background: "#f4f4f4",
192
+ padding: "2px 6px",
193
+ borderRadius: "4px",
194
+ fontSize: "11px",
195
+ fontFamily: "monospace"
196
+ },
197
+ children: row.value.slug
192
198
  }
193
199
  )
194
- ] }),
195
- creating && /* @__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: [
196
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_text.default.Subheadline, { as: "h4", isBold: true, children: "Create New Page" }),
197
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_spacings.default.Inline, { scale: "m", children: [
198
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_spacings.default.Stack, { scale: "xs", children: [
199
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_label.default, { htmlFor: "new-page-name", children: "Name *" }),
200
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
201
- import_text_input.default,
202
- {
203
- id: "new-page-name",
204
- value: newName,
205
- onChange: (e) => setNewName(e.target.value),
206
- placeholder: "Home Page"
207
- }
208
- )
209
- ] }) }),
210
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_spacings.default.Stack, { scale: "xs", children: [
211
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_label.default, { htmlFor: "new-page-slug", children: "Slug *" }),
212
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
213
- import_text_input.default,
214
- {
215
- id: "new-page-slug",
216
- value: newSlug,
217
- onChange: (e) => setNewSlug(e.target.value),
218
- placeholder: "/home"
219
- }
220
- )
221
- ] }) })
222
- ] }),
223
- formError && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_text.default.Body, { tone: "negative", children: formError }),
224
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_spacings.default.Inline, { scale: "s", children: [
225
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
226
- import_primary_button.default,
200
+ },
201
+ {
202
+ id: "status",
203
+ header: "Status",
204
+ accessor: () => "",
205
+ isSortable: false,
206
+ render: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Stack, { direction: "row", gap: "100", wrap: "wrap", children: [
207
+ row.states.draft && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StatusBadge, { variant: "draft" }),
208
+ row.states.published && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StatusBadge, { variant: "published" }),
209
+ !row.states.draft && !row.states.published && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StatusBadge, { variant: "none" })
210
+ ] })
211
+ },
212
+ {
213
+ id: "updatedAt",
214
+ header: "Updated",
215
+ accessor: (row) => row.value.updatedAt,
216
+ render: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Text, { fontSize: "xs", color: "neutral.11", children: new Date(row.value.updatedAt).toLocaleString() })
217
+ },
218
+ {
219
+ id: "actions",
220
+ header: "Actions",
221
+ accessor: () => "",
222
+ isSortable: false,
223
+ render: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Stack, { direction: "row", gap: "100", alignItems: "center", children: [
224
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
225
+ import_nimbus2.IconButton,
227
226
  {
228
- label: submitting ? "Creating\u2026" : "Create",
229
- onClick: () => void handleCreate(),
230
- isDisabled: submitting
227
+ "aria-label": `Edit ${row.value.name}`,
228
+ variant: "ghost",
229
+ size: "xs",
230
+ onPress: () => history.push(`/${row.key}/edit`, { pageName: row.value.name }),
231
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus_icons.Edit, {})
231
232
  }
232
233
  ),
233
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
234
- import_secondary_button.default,
234
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
235
+ import_nimbus2.IconButton,
235
236
  {
236
- label: "Cancel",
237
- onClick: () => {
238
- setCreating(false);
239
- setFormError("");
240
- }
237
+ "aria-label": `Preview ${row.value.name}`,
238
+ variant: "ghost",
239
+ size: "xs",
240
+ onPress: () => history.push(`/${row.key}/preview`, { pageName: row.value.name }),
241
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus_icons.Visibility, {})
242
+ }
243
+ ),
244
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
245
+ import_nimbus2.IconButton,
246
+ {
247
+ "aria-label": `Delete ${row.value.name}`,
248
+ variant: "ghost",
249
+ colorPalette: "critical",
250
+ size: "xs",
251
+ isDisabled: deleting === row.key,
252
+ onPress: () => setPendingDelete(row),
253
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus_icons.Delete, {})
241
254
  }
242
255
  )
243
256
  ] })
244
- ] }) }),
245
- pages.length === 0 && !creating ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_spacings.default.Stack, { scale: "m", alignItems: "center", children: [
246
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_text.default.Body, { tone: "secondary", children: "No pages yet." }),
247
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
248
- import_primary_button.default,
249
- {
250
- label: "Create first page",
251
- iconLeft: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.PlusThinIcon, {}),
252
- onClick: () => setCreating(true)
253
- }
254
- )
255
- ] }) : pages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
256
- import_data_table.default,
257
- {
258
- columns: COLUMNS,
259
- rows,
260
- itemRenderer: (row, column) => {
261
- switch (column.key) {
262
- case "name":
263
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_spacings.default.Stack, { scale: "xs", children: [
264
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_text.default.Body, { isBold: true, children: row.value.name }),
265
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_text.default.Detail, { tone: "secondary", children: row.key })
266
- ] });
267
- case "slug":
268
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
269
- "code",
270
- {
271
- style: {
272
- background: "var(--color-neutral-95)",
273
- padding: "2px 6px",
274
- borderRadius: "var(--border-radius-4)",
275
- fontSize: "var(--font-size-10)",
276
- fontFamily: "monospace"
277
- },
278
- children: row.value.slug
279
- }
280
- );
281
- case "status":
282
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
283
- row.states.draft && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(StatusBadge, { variant: "draft" }),
284
- row.states.published && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(StatusBadge, { variant: "published" }),
285
- !row.states.draft && !row.states.published && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(StatusBadge, { variant: "none" })
286
- ] });
287
- case "updatedAt":
288
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_text.default.Body, { tone: "secondary", children: new Date(row.value.updatedAt).toLocaleString() });
289
- case "actions":
290
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
291
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
292
- import_primary_button.default,
293
- {
294
- label: "Edit",
295
- size: "20",
296
- onClick: () => history.push(`/${row.key}/edit`, { pageName: row.value.name })
297
- }
298
- ),
299
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
300
- import_secondary_button.default,
301
- {
302
- label: "Preview",
303
- size: "20",
304
- onClick: () => history.push(`/${row.key}/preview`, { pageName: row.value.name })
305
- }
306
- ),
307
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
308
- import_flat_button.default,
309
- {
310
- tone: "critical",
311
- label: deleting === row.key ? "\u2026" : "Delete",
312
- isDisabled: deleting === row.key,
313
- onClick: () => void handleDelete(row)
314
- }
315
- )
316
- ] });
317
- default:
318
- return null;
257
+ }
258
+ ];
259
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { maxWidth: "1200px", margin: "0 auto", padding: "32px 24px" }, children: [
260
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Stack, { direction: "column", gap: "600", children: [
261
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", children: [
262
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Stack, { direction: "row", gap: "400", alignItems: "center", children: [
263
+ backButton,
264
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Text, { as: "h1", fontSize: "2xl", fontWeight: "700", children: "Pages" })
265
+ ] }),
266
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Button, { variant: "solid", onPress: () => setCreating(true), children: [
267
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Icon, { as: import_nimbus_icons.Add }),
268
+ " New Page"
269
+ ] })
270
+ ] }),
271
+ creating && /* @__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: [
272
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Text, { as: "h4", fontSize: "xl", fontWeight: "700", children: "Create New Page" }),
273
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Stack, { direction: "row", gap: "400", children: [
274
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.FormField.Root, { isRequired: true, children: [
275
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.FormField.Label, { children: "Name" }),
276
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.FormField.Input, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
277
+ import_nimbus2.TextInput,
278
+ {
279
+ value: newName,
280
+ onChange: (v) => setNewName(v),
281
+ placeholder: "Home Page"
282
+ }
283
+ ) })
284
+ ] }) }),
285
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.FormField.Root, { isRequired: true, children: [
286
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.FormField.Label, { children: "Slug" }),
287
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.FormField.Input, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
288
+ import_nimbus2.TextInput,
289
+ {
290
+ value: newSlug,
291
+ onChange: (v) => setNewSlug(v),
292
+ placeholder: "/home"
293
+ }
294
+ ) })
295
+ ] }) })
296
+ ] }),
297
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.FormField.Root, { children: [
298
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.FormField.Label, { children: "Template" }),
299
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.FormField.Input, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
300
+ import_nimbus2.Select.Root,
301
+ {
302
+ "aria-label": "Template",
303
+ selectedKey: templateKey || "empty",
304
+ onSelectionChange: (key) => setTemplateKey(key == null || key === "empty" ? "" : String(key)),
305
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Select.Options, { children: [
306
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Select.Option, { id: "empty", children: "Empty" }),
307
+ templates.map((t) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Select.Option, { id: t.key, children: t.value.name }, t.key))
308
+ ] })
309
+ }
310
+ ) })
311
+ ] }),
312
+ formError && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Text, { color: "critical.11", children: formError }),
313
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Stack, { direction: "row", gap: "200", children: [
314
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Button, { variant: "solid", onPress: () => void handleCreate(), isDisabled: submitting, children: submitting ? "Creating\u2026" : "Create" }),
315
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
316
+ import_nimbus2.Button,
317
+ {
318
+ variant: "outline",
319
+ onPress: () => {
320
+ setCreating(false);
321
+ setFormError("");
322
+ },
323
+ children: "Cancel"
324
+ }
325
+ )
326
+ ] })
327
+ ] }) }) }),
328
+ pages.length === 0 && !creating ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Stack, { direction: "column", gap: "400", alignItems: "center", children: [
329
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Text, { color: "neutral.11", children: "No pages yet." }),
330
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Button, { variant: "solid", onPress: () => setCreating(true), children: [
331
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Icon, { as: import_nimbus_icons.Add }),
332
+ " Create first page"
333
+ ] })
334
+ ] }) : pages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Stack, { direction: "column", gap: "400", children: [
335
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { maxWidth: 360 }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
336
+ import_nimbus2.TextInput,
337
+ {
338
+ "aria-label": "Search pages",
339
+ placeholder: "Search by name or path\u2026",
340
+ value: search,
341
+ onChange: (v) => setSearch(v),
342
+ width: "100%",
343
+ trailingElement: search !== "" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
344
+ import_nimbus2.IconButton,
345
+ {
346
+ "aria-label": "Clear search",
347
+ variant: "ghost",
348
+ colorPalette: "neutral",
349
+ size: "2xs",
350
+ onPress: () => setSearch(""),
351
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus_icons.Close, {})
352
+ }
353
+ ) : void 0
319
354
  }
320
- }
355
+ ) }),
356
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "puck-page-list", children: [
357
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("style", { children: `
358
+ .puck-page-list .pin-rows-column-header,
359
+ .puck-page-list [data-slot="pin-row-cell"] { display: none !important; }
360
+ ` }),
361
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.DataTable, { columns, rows, "aria-label": "Pages" })
362
+ ] })
363
+ ] }) : null
364
+ ] }),
365
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
366
+ import_nimbus2.Dialog.Root,
367
+ {
368
+ isOpen: pendingDelete !== null,
369
+ onOpenChange: (open) => {
370
+ if (!open) setPendingDelete(null);
371
+ },
372
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Dialog.Content, { children: [
373
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Dialog.Header, { children: [
374
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Dialog.Title, { children: "Delete page?" }),
375
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Dialog.CloseTrigger, {})
376
+ ] }),
377
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Dialog.Body, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Text, { children: [
378
+ "Are you sure you want to delete",
379
+ " ",
380
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Text, { as: "span", fontWeight: "700", children: pendingDelete?.value.name }),
381
+ "? This cannot be undone."
382
+ ] }) }),
383
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Dialog.Footer, { children: [
384
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Button, { slot: "close", variant: "outline", isDisabled: deleting !== null, children: "Cancel" }),
385
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
386
+ import_nimbus2.Button,
387
+ {
388
+ colorPalette: "critical",
389
+ isDisabled: deleting !== null,
390
+ onPress: () => {
391
+ if (pendingDelete) void handleDelete(pendingDelete);
392
+ },
393
+ children: deleting !== null ? "Deleting\u2026" : "Delete"
394
+ }
395
+ )
396
+ ] })
397
+ ] })
321
398
  }
322
- ) : null
323
- ] }) });
399
+ )
400
+ ] });
324
401
  };
325
402
  var PageEditorRoute = ({ config, backButton }) => {
326
403
  const { pageKey } = (0, import_react_router_dom.useParams)();
327
404
  const history = (0, import_react_router_dom.useHistory)();
328
405
  const location = (0, import_react_router_dom.useLocation)();
329
- const { baseURL, projectKey, businessUnitKey, jwtToken } = (0, import_puck_api.usePuckApiContext)();
406
+ const { baseURL, projectKey, businessUnitKey, jwtToken, locale } = (0, import_puck_api.usePuckApiContext)();
330
407
  const pageName = location.state?.pageName ?? pageKey ?? "Page";
331
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
332
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: NAV_BAR_STYLE, children: [
408
+ const [isDirty, setIsDirty] = (0, import_react2.useState)(false);
409
+ const [pendingNav, setPendingNav] = (0, import_react2.useState)(null);
410
+ const guardedNavigate = (0, import_react2.useCallback)(
411
+ (navFn) => {
412
+ if (isDirty) {
413
+ setPendingNav(() => navFn);
414
+ } else {
415
+ navFn();
416
+ }
417
+ },
418
+ [isDirty]
419
+ );
420
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
421
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: NAV_BAR_STYLE, children: [
333
422
  backButton,
334
- backButton && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_text.default.Body, { tone: "secondary", children: "/" }),
335
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
336
- import_flat_button.default,
423
+ backButton && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Text, { color: "neutral.11", children: "/" }),
424
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
425
+ import_nimbus2.Button,
337
426
  {
338
- label: "Pages",
339
- icon: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.AngleLeftIcon, {}),
340
- iconPosition: "left",
341
- onClick: () => history.push("/")
427
+ variant: "ghost",
428
+ onPress: () => guardedNavigate(() => history.push("/")),
429
+ children: [
430
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Icon, { as: import_nimbus_icons.ChevronLeft }),
431
+ " Pages"
432
+ ]
342
433
  }
343
434
  ),
344
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_text.default.Body, { tone: "secondary", children: "/" }),
345
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_text.default.Body, { isBold: true, children: pageName })
435
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Text, { color: "neutral.11", children: "/" }),
436
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Text, { fontWeight: "bold", children: pageName })
346
437
  ] }),
347
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { flex: 1, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
348
- import_puck_editor.PuckEditor,
349
- {
350
- baseURL,
351
- projectKey,
352
- businessUnitKey,
353
- jwtToken: jwtToken ?? "",
354
- pageKey,
355
- config,
356
- onError: (err) => {
357
- console.error("[PageManager] editor error:", err);
438
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "puck-editor-fill", style: { flex: 1, overflow: "hidden" }, children: [
439
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
440
+ import_puck_editor.PuckEditor,
441
+ {
442
+ baseURL,
443
+ projectKey,
444
+ businessUnitKey,
445
+ jwtToken: jwtToken ?? "",
446
+ locale,
447
+ pageKey,
448
+ config,
449
+ onDirtyChange: setIsDirty,
450
+ onPreview: () => guardedNavigate(
451
+ () => history.push(`/${pageKey}/preview`, { pageName })
452
+ ),
453
+ onError: (err) => {
454
+ console.error("[PageManager] editor error:", err);
455
+ }
358
456
  }
457
+ ),
458
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_puck_editor.PropertiesResizer, {})
459
+ ] }),
460
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
461
+ import_puck_editor.UnsavedChangesDialog,
462
+ {
463
+ isOpen: pendingNav !== null,
464
+ onOpenChange: (open) => {
465
+ if (!open) setPendingNav(null);
466
+ },
467
+ onConfirm: () => pendingNav?.()
359
468
  }
360
- ) })
469
+ )
361
470
  ] });
362
471
  };
363
472
  var PagePreviewRoute = ({ config, backButton }) => {
@@ -365,56 +474,39 @@ var PagePreviewRoute = ({ config, backButton }) => {
365
474
  const history = (0, import_react_router_dom.useHistory)();
366
475
  const location = (0, import_react_router_dom.useLocation)();
367
476
  const pageName = location.state?.pageName ?? pageKey ?? "Page";
368
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
369
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: NAV_BAR_STYLE, children: [
477
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
478
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: NAV_BAR_STYLE, children: [
370
479
  backButton,
371
- backButton && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_text.default.Body, { tone: "secondary", children: "/" }),
372
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
373
- import_flat_button.default,
374
- {
375
- label: "Pages",
376
- icon: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.AngleLeftIcon, {}),
377
- iconPosition: "left",
378
- onClick: () => history.push("/")
379
- }
380
- ),
381
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_text.default.Body, { tone: "secondary", children: "/" }),
382
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_text.default.Body, { isBold: true, children: pageName }),
383
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
384
- "span",
385
- {
386
- style: {
387
- background: "var(--color-primary-95)",
388
- color: "var(--color-primary-25)",
389
- border: "1px solid var(--color-primary-85)",
390
- display: "inline-flex",
391
- alignItems: "center",
392
- padding: "2px 10px",
393
- borderRadius: "var(--border-radius-20)",
394
- fontSize: "var(--font-size-10)",
395
- fontWeight: "var(--font-weight-600)"
396
- },
397
- children: "Preview"
398
- }
399
- )
480
+ backButton && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Text, { color: "neutral.11", children: "/" }),
481
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Button, { variant: "ghost", onPress: () => history.push("/"), children: [
482
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Icon, { as: import_nimbus_icons.ChevronLeft }),
483
+ " Pages"
484
+ ] }),
485
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Text, { color: "neutral.11", children: "/" }),
486
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Text, { fontWeight: "bold", children: pageName }),
487
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Badge, { colorPalette: "primary", size: "xs", children: "Preview" }),
488
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { marginLeft: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_nimbus2.Button, { variant: "outline", size: "xs", onPress: () => history.goBack(), children: [
489
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_nimbus2.Icon, { as: import_nimbus_icons.Close }),
490
+ " Close preview"
491
+ ] }) })
400
492
  ] }),
401
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_puck_renderer.PuckRenderer, { pageKey, mode: "preview", config })
493
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_puck_renderer.PuckRenderer, { pageKey, mode: "preview", config })
402
494
  ] });
403
495
  };
404
- var PageManagerInner = ({ config, backButton }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_router_dom.Switch, { children: [
405
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_router_dom.Route, { exact: true, path: "/", render: () => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PageList, { backButton }) }),
406
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
496
+ var PageManagerInner = ({ config, backButton }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_router_dom.Switch, { children: [
497
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_router_dom.Route, { exact: true, path: "/", render: () => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PageList, { backButton }) }),
498
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
407
499
  import_react_router_dom.Route,
408
500
  {
409
501
  path: "/:pageKey/edit",
410
- render: () => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PageEditorRoute, { config, backButton })
502
+ render: () => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PageEditorRoute, { config, backButton })
411
503
  }
412
504
  ),
413
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
505
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
414
506
  import_react_router_dom.Route,
415
507
  {
416
508
  path: "/:pageKey/preview",
417
- render: () => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PagePreviewRoute, { config, backButton })
509
+ render: () => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PagePreviewRoute, { config, backButton })
418
510
  }
419
511
  )
420
512
  ] });
@@ -424,18 +516,20 @@ var PageManager = ({
424
516
  projectKey,
425
517
  businessUnitKey,
426
518
  jwtToken,
519
+ locale,
427
520
  config = DEFAULT_CONFIG,
428
521
  backButton
429
- }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EnsureIntlProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
522
+ }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(EnsureNimbusProvider, { locale, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(EnsureIntlProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
430
523
  import_puck_api.PuckApiProvider,
431
524
  {
432
525
  baseURL,
433
526
  projectKey,
434
527
  businessUnitKey,
435
528
  jwtToken,
436
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_router_dom.BrowserRouter, { basename: parentUrl, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PageManagerInner, { config, backButton }) })
529
+ locale,
530
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_router_dom.BrowserRouter, { basename: parentUrl, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PageManagerInner, { config, backButton }) })
437
531
  }
438
- ) });
532
+ ) }) });
439
533
  // Annotate the CommonJS export names for ESM import in node:
440
534
  0 && (module.exports = {
441
535
  PageManager