@cardinali-studio/adminkit 2.2.35 → 2.2.37

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/app/app.css CHANGED
@@ -2351,5 +2351,5 @@ body:has(.uk) .pane-body { padding-bottom: 190px; }
2351
2351
  @media (prefers-reduced-motion: reduce) {
2352
2352
  .ak-bug-trigger, .ak-bug-backdrop, .ak-bug-dialog { animation: none; transition: none; }
2353
2353
  }
2354
- :root[data-admin-interface="next"] .rail-foot > .ak-release-control{width:auto;height:auto;overflow:visible}
2355
- :root[data-admin-interface="next"] .rail-foot > .ak-release-control > .ak-release-trigger{width:auto;min-width:104px;display:inline-flex;gap:9px;padding:0 14px;color:var(--ak-rail-ink-on);font:600 12px/1 var(--ak-font);overflow:visible}
2354
+ :root[data-admin-interface="next"] .rail-foot > .ak-release-control.ak-release-control{width:auto;height:auto;overflow:visible}
2355
+ :root[data-admin-interface="next"] .rail-foot > .ak-release-control.ak-release-control > .ak-release-trigger{width:auto;min-width:104px;display:inline-flex;gap:9px;padding:0 14px;color:var(--ak-rail-ink-on);font:600 12px/1 var(--ak-font);overflow:visible}
@@ -348,6 +348,10 @@ export function PageEditor({ page, onChange, onRefresh, pristine, pickMedia, pic
348
348
  «Ritratto» e «Riconoscimenti» — campi di altri tipi di pagina, che compaiono perché il
349
349
  form disegna tutto ciò che lo schema dichiara e non sa quale tipo si stia modificando.
350
350
  Titolo, visibilità e SEO restano dove sono già: la barra in alto e la scheda SEO. */
351
+ if (definition?.editor && !translationActive) {
352
+ const Editor = definition.editor;
353
+ return _jsx("div", { className: "ed ed-site-page", children: _jsx(Editor, { page: page, onChange: onChange, pickMediaFiles: pickMediaFiles }, page._documentId || page.slug) });
354
+ }
351
355
  if (isPortfolio && !translationActive) {
352
356
  return (_jsxs("div", { className: "ed ed-portfolio", children: [bodyState === "error" && (_jsx("p", { className: "pe-load-error", children: "Non sono riuscito ad aggiornare i dati della pagina dal sito." })), _jsx(PortfolioWorksEditor, { value: page.works, onChange: (works) => onChange({ ...page, works }), pickMediaFiles: pickMediaFiles })] }));
353
357
  }
@@ -94,6 +94,9 @@ export function PageSeoEditor({ page, onChange, onRefresh, pristine, pickMediaFi
94
94
  const socialImage = explicitImage || automaticImage(page);
95
95
  const pageUrl = `${site().publicBase}/${page.slug}/`;
96
96
  const complete = !!seoTitle.trim() && !!seoDescription.trim() && !!socialImage;
97
+ const CustomEditor = pageType(page.type)?.seoEditor;
98
+ if (CustomEditor && !readOnly)
99
+ return _jsx(CustomEditor, { page: page, onChange: onChange, pickMediaFiles: pickMediaFiles }, page._documentId || page.slug);
97
100
  const customShape = pageType(page.type)?.seoShape;
98
101
  if (customShape)
99
102
  return _jsxs("section", { className: "seo-editor", children: [_jsx("h2", { children: "SEO e GEO" }), loadError && _jsx("p", { className: "ak-error", children: "Non sono riuscito a rileggere la pagina." }), _jsx(SchemaForm, { shape: customShape, value: (page.seo ?? {}), onChange: (seo) => { if (!readOnly)
@@ -16,6 +16,17 @@ export interface PageTypeConfig {
16
16
  creatable?: boolean;
17
17
  create?: (title: string, slug: string) => Record<string, unknown>;
18
18
  seoShape?: Shape;
19
+ seoEditor?: PageTypeConfig["editor"];
20
+ /** Content-specific visual editor inside the native page shell. */
21
+ editor?: ComponentType<{
22
+ page: Record<string, any> & {
23
+ slug: string;
24
+ };
25
+ onChange: (page: Record<string, any> & {
26
+ slug: string;
27
+ }) => void;
28
+ pickMediaFiles?: (options: import("../form/MediaPicker.js").PickerOptions) => Promise<import("../api.js").AssetFile[] | null>;
29
+ }>;
19
30
  }
20
31
  /** Lingue dei contenuti, assenti nei siti monolingui. I codici sono quelli dei sibling Hugo
21
32
  * (`index.md`, `index.en.md`): la lingua predefinita non porta alcun suffisso. */
@@ -23,20 +23,35 @@ export function Trash() {
23
23
  return (_jsxs("div", { className: "tr", children: [_jsxs("header", { className: "mb-top", children: [_jsx("span", { className: "ak-spacer" }), !!items?.length && (_jsx("button", { className: "ak-btn", onClick: async () => {
24
24
  if (!confirm(`Svuotare il cestino? ${items.length} file cancellati per sempre.`))
25
25
  return;
26
- await api.trashEmpty();
27
- await load();
26
+ try {
27
+ await api.trashEmpty();
28
+ await load();
29
+ }
30
+ catch (e) {
31
+ setError(e instanceof Error ? e.message : String(e));
32
+ }
28
33
  }, children: "Svuota il cestino" }))] }), error && _jsx("p", { className: "ak-error", children: error }), !items && _jsx("p", { className: "ak-hint", children: "Carico\u2026" }), items?.length === 0 && _jsx("p", { className: "ak-hint", children: "Il cestino \u00E8 vuoto." }), _jsx("ul", { className: "tr-list", children: items?.map((it) => (_jsxs("li", { className: "tr-row", children: [_jsx("img", { src: it.previewUrl, alt: "", className: "tr-thumb", loading: "lazy" }), _jsx("span", { className: "tr-name", children: it.name }), _jsx("code", { className: "tr-orig", children: it.originalKey }), _jsx("span", { className: "ak-hint", children: fmtSize(it.size) }), _jsx("button", { className: "ak-btn ak-btn-quiet", onClick: async () => {
29
- const r = await api.trashRestore([it.trashKey]);
30
- if (r.conflicts?.length) {
31
- alert(`Esisteva già un file con quel nome: ripristinato come ${r.conflicts[0].restoredAs}.`);
34
+ try {
35
+ const r = await api.trashRestore([it.trashKey]);
36
+ if (r.conflicts?.length) {
37
+ alert(`Esisteva già un file con quel nome: ripristinato come ${r.conflicts[0].restoredAs}.`);
38
+ }
39
+ // NB: il ripristino NON rimette i riferimenti nelle pagine — li aveva tolti la
40
+ // cancellazione. Va rifatto a mano, ed è documentato nell'endpoint.
41
+ await load();
42
+ }
43
+ catch (e) {
44
+ setError(e instanceof Error ? e.message : String(e));
32
45
  }
33
- // NB: il ripristino NON rimette i riferimenti nelle pagine — li aveva tolti la
34
- // cancellazione. Va rifatto a mano, ed è documentato nell'endpoint.
35
- await load();
36
46
  }, children: "Ripristina" }), _jsx("button", { className: "ak-btn", onClick: async () => {
37
47
  if (!confirm(`Cancellare ${it.name} per sempre? Non è più recuperabile.`))
38
48
  return;
39
- await api.trashDelete([it.trashKey]);
40
- await load();
49
+ try {
50
+ await api.trashDelete([it.trashKey]);
51
+ await load();
52
+ }
53
+ catch (e) {
54
+ setError(e instanceof Error ? e.message : String(e));
55
+ }
41
56
  }, children: "Elimina" })] }, it.trashKey))) })] }));
42
57
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cardinali-studio/adminkit",
3
- "version": "2.2.35",
3
+ "version": "2.2.37",
4
4
  "type": "module",
5
5
  "description": "Motore riusabile di un pannello di amministrazione per siti Hugo su Cloudflare Pages: codec del front matter guidato dallo schema, form React, libreria media su R2. NIENTE di specifico di un sito qui dentro.",
6
6
  "license": "0BSD",