@cardinali-studio/adminkit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/dist/api.d.ts +195 -0
  2. package/dist/api.js +118 -0
  3. package/dist/app/App.d.ts +3 -0
  4. package/dist/app/App.js +320 -0
  5. package/dist/app/app.css +2068 -0
  6. package/dist/app/index.d.ts +18 -0
  7. package/dist/app/index.js +33 -0
  8. package/dist/app/lib/bookings.d.ts +132 -0
  9. package/dist/app/lib/bookings.js +79 -0
  10. package/dist/app/lib/deliveries.d.ts +95 -0
  11. package/dist/app/lib/deliveries.js +104 -0
  12. package/dist/app/lib/delivery-drop.d.ts +1 -0
  13. package/dist/app/lib/delivery-drop.js +72 -0
  14. package/dist/app/lib/delivery-upload.d.ts +78 -0
  15. package/dist/app/lib/delivery-upload.js +585 -0
  16. package/dist/app/lib/groups.d.ts +9 -0
  17. package/dist/app/lib/groups.js +32 -0
  18. package/dist/app/lib/home.d.ts +11 -0
  19. package/dist/app/lib/home.js +67 -0
  20. package/dist/app/lib/overview.d.ts +82 -0
  21. package/dist/app/lib/overview.js +68 -0
  22. package/dist/app/lib/pages.d.ts +24 -0
  23. package/dist/app/lib/pages.js +156 -0
  24. package/dist/app/lib/publish.d.ts +18 -0
  25. package/dist/app/lib/publish.js +63 -0
  26. package/dist/app/lib/reorder.d.ts +3 -0
  27. package/dist/app/lib/reorder.js +31 -0
  28. package/dist/app/lib/requests.d.ts +10 -0
  29. package/dist/app/lib/requests.js +67 -0
  30. package/dist/app/lib/router.d.ts +1 -0
  31. package/dist/app/lib/router.js +14 -0
  32. package/dist/app/lib/settings.d.ts +29 -0
  33. package/dist/app/lib/settings.js +82 -0
  34. package/dist/app/lib/slug.d.ts +3 -0
  35. package/dist/app/lib/slug.js +23 -0
  36. package/dist/app/lib/text.d.ts +1 -0
  37. package/dist/app/lib/text.js +13 -0
  38. package/dist/app/lib/theme.d.ts +7 -0
  39. package/dist/app/lib/theme.js +43 -0
  40. package/dist/app/lib/upload-queue.d.ts +35 -0
  41. package/dist/app/lib/upload-queue.js +167 -0
  42. package/dist/app/routes/AboutEditor.d.ts +15 -0
  43. package/dist/app/routes/AboutEditor.js +122 -0
  44. package/dist/app/routes/Bookings.d.ts +21 -0
  45. package/dist/app/routes/Bookings.js +134 -0
  46. package/dist/app/routes/Deliveries.d.ts +37 -0
  47. package/dist/app/routes/Deliveries.js +563 -0
  48. package/dist/app/routes/GallerySectionsEditor.d.ts +12 -0
  49. package/dist/app/routes/GallerySectionsEditor.js +107 -0
  50. package/dist/app/routes/HomeEditor.d.ts +10 -0
  51. package/dist/app/routes/HomeEditor.js +188 -0
  52. package/dist/app/routes/Overview.d.ts +17 -0
  53. package/dist/app/routes/Overview.js +318 -0
  54. package/dist/app/routes/PageActions.d.ts +12 -0
  55. package/dist/app/routes/PageActions.js +93 -0
  56. package/dist/app/routes/PageEditor.d.ts +23 -0
  57. package/dist/app/routes/PageEditor.js +233 -0
  58. package/dist/app/routes/PageSeoEditor.d.ts +13 -0
  59. package/dist/app/routes/PageSeoEditor.js +102 -0
  60. package/dist/app/routes/PagesList.d.ts +10 -0
  61. package/dist/app/routes/PagesList.js +76 -0
  62. package/dist/app/routes/PortfolioWorksEditor.d.ts +12 -0
  63. package/dist/app/routes/PortfolioWorksEditor.js +139 -0
  64. package/dist/app/routes/Requests.d.ts +13 -0
  65. package/dist/app/routes/Requests.js +30 -0
  66. package/dist/app/routes/SiteSettingsEditor.d.ts +21 -0
  67. package/dist/app/routes/SiteSettingsEditor.js +66 -0
  68. package/dist/app/routes/UploadDock.d.ts +1 -0
  69. package/dist/app/routes/UploadDock.js +66 -0
  70. package/dist/app/routes/WorkshopEditionsEditor.d.ts +12 -0
  71. package/dist/app/routes/WorkshopEditionsEditor.js +101 -0
  72. package/dist/app/site.d.ts +37 -0
  73. package/dist/app/site.js +18 -0
  74. package/dist/app/ui/MediaSlot.d.ts +10 -0
  75. package/dist/app/ui/MediaSlot.js +20 -0
  76. package/dist/app/ui/OpenCard.d.ts +18 -0
  77. package/dist/app/ui/OpenCard.js +20 -0
  78. package/dist/app/ui/ParagraphEditor.d.ts +8 -0
  79. package/dist/app/ui/ParagraphEditor.js +37 -0
  80. package/dist/app/ui/dnd.d.ts +1 -0
  81. package/dist/app/ui/dnd.js +11 -0
  82. package/dist/app/ui/icons.d.ts +26 -0
  83. package/dist/app/ui/icons.js +45 -0
  84. package/dist/config.d.ts +5 -0
  85. package/dist/config.js +26 -0
  86. package/dist/form/MediaBrowser.d.ts +13 -0
  87. package/dist/form/MediaBrowser.js +24 -0
  88. package/dist/form/MediaPicker.d.ts +10 -0
  89. package/dist/form/MediaPicker.js +20 -0
  90. package/dist/form/SchemaForm.d.ts +21 -0
  91. package/dist/form/SchemaForm.js +67 -0
  92. package/dist/form/Trash.d.ts +1 -0
  93. package/dist/form/Trash.js +42 -0
  94. package/dist/form/fields/index.d.ts +1 -0
  95. package/dist/form/fields/index.js +110 -0
  96. package/dist/form/fields/objectList.d.ts +1 -0
  97. package/dist/form/fields/objectList.js +99 -0
  98. package/dist/form/index.d.ts +8 -0
  99. package/dist/form/index.js +8 -0
  100. package/dist/form/media/Lightbox.d.ts +4 -0
  101. package/dist/form/media/Lightbox.js +70 -0
  102. package/dist/form/media/MediaFolders.d.ts +20 -0
  103. package/dist/form/media/MediaFolders.js +116 -0
  104. package/dist/form/media/MediaGrid.d.ts +8 -0
  105. package/dist/form/media/MediaGrid.js +139 -0
  106. package/dist/form/media/UploadDialog.d.ts +4 -0
  107. package/dist/form/media/UploadDialog.js +37 -0
  108. package/dist/form/media/useMediaLibrary.d.ts +55 -0
  109. package/dist/form/media/useMediaLibrary.js +495 -0
  110. package/dist/form/prose/ProseBar.d.ts +21 -0
  111. package/dist/form/prose/ProseBar.js +111 -0
  112. package/dist/form/prose/ProseField.d.ts +11 -0
  113. package/dist/form/prose/ProseField.js +152 -0
  114. package/dist/form/prose/pages.d.ts +6 -0
  115. package/dist/form/prose/pages.js +13 -0
  116. package/dist/form/registry.d.ts +20 -0
  117. package/dist/form/registry.js +15 -0
  118. package/dist/frontmatter.d.ts +20 -0
  119. package/dist/frontmatter.js +202 -0
  120. package/dist/functions/_middleware.js +101 -0
  121. package/dist/functions/_shared/analytics-ga4.js +248 -0
  122. package/dist/functions/_shared/analytics-umami.js +119 -0
  123. package/dist/functions/_shared/assets.js +90 -0
  124. package/dist/functions/_shared/b2.js +300 -0
  125. package/dist/functions/_shared/delivery-crypto.js +99 -0
  126. package/dist/functions/_shared/delivery-purge.js +222 -0
  127. package/dist/functions/_shared/edge-cache.js +37 -0
  128. package/dist/functions/_shared/exif.js +53 -0
  129. package/dist/functions/_shared/github.js +138 -0
  130. package/dist/functions/_shared/imagesize.js +101 -0
  131. package/dist/functions/_shared/media-content.js +200 -0
  132. package/dist/functions/_shared/pending-media.js +98 -0
  133. package/dist/functions/_shared/refs.js +155 -0
  134. package/dist/functions/api/analytics.js +106 -0
  135. package/dist/functions/api/assets/delete.js +241 -0
  136. package/dist/functions/api/assets/folder.js +43 -0
  137. package/dist/functions/api/assets/folders.js +32 -0
  138. package/dist/functions/api/assets/move.js +253 -0
  139. package/dist/functions/api/assets/preview.js +17 -0
  140. package/dist/functions/api/assets/trash/delete.js +13 -0
  141. package/dist/functions/api/assets/trash/empty.js +16 -0
  142. package/dist/functions/api/assets/trash/restore.js +43 -0
  143. package/dist/functions/api/assets/trash.js +28 -0
  144. package/dist/functions/api/assets/upload.js +54 -0
  145. package/dist/functions/api/assets/usage.js +41 -0
  146. package/dist/functions/api/assets.js +94 -0
  147. package/dist/functions/api/deliveries.js +629 -0
  148. package/dist/functions/api/delivery/hero.js +21 -0
  149. package/dist/functions/api/delivery/image.js +35 -0
  150. package/dist/functions/api/delivery/multipart.js +261 -0
  151. package/dist/functions/api/pages/get.js +26 -0
  152. package/dist/functions/api/pages.js +354 -0
  153. package/dist/functions/api/publish.js +134 -0
  154. package/dist/functions/api/requests.js +57 -0
  155. package/dist/functions/api/settings.js +236 -0
  156. package/dist/functions/api/singleton.js +105 -0
  157. package/dist/functions/api/storage.js +125 -0
  158. package/dist/functions/index.js +124 -0
  159. package/dist/functions/site.js +38 -0
  160. package/dist/gallery.d.ts +28 -0
  161. package/dist/gallery.js +18 -0
  162. package/dist/index.d.ts +10 -0
  163. package/dist/index.js +10 -0
  164. package/dist/model.d.ts +2 -0
  165. package/dist/model.js +47 -0
  166. package/dist/normalize.d.ts +50 -0
  167. package/dist/normalize.js +120 -0
  168. package/dist/preview.d.ts +3 -0
  169. package/dist/preview.js +82 -0
  170. package/dist/prose.d.ts +17 -0
  171. package/dist/prose.js +205 -0
  172. package/dist/registries.d.ts +43 -0
  173. package/dist/registries.js +29 -0
  174. package/dist/serialize.d.ts +26 -0
  175. package/dist/serialize.js +136 -0
  176. package/dist/testing.d.ts +26 -0
  177. package/dist/testing.js +66 -0
  178. package/dist/theme.css +636 -0
  179. package/dist/yaml.d.ts +8 -0
  180. package/dist/yaml.js +90 -0
  181. package/package.json +97 -0
package/dist/api.d.ts ADDED
@@ -0,0 +1,195 @@
1
+ export declare class ApiError extends Error {
2
+ code: string;
3
+ status: number;
4
+ constructor(message: string, code: string, status: number);
5
+ }
6
+ export interface AssetFile {
7
+ key: string;
8
+ name: string;
9
+ size: number;
10
+ url: string;
11
+ uploaded?: string;
12
+ capturedAt?: string;
13
+ type?: string;
14
+ w?: number | null;
15
+ h?: number | null;
16
+ }
17
+ export interface AssetFolder {
18
+ prefix: string;
19
+ name: string;
20
+ count?: number;
21
+ label?: string;
22
+ }
23
+ export interface TrashItem {
24
+ trashKey: string;
25
+ originalKey: string;
26
+ name: string;
27
+ deletedAt?: string;
28
+ size: number;
29
+ type?: string;
30
+ previewUrl: string;
31
+ }
32
+ export interface ContactRequestRow {
33
+ id: number;
34
+ name: string;
35
+ email: string;
36
+ message: string;
37
+ created_at: string;
38
+ handled_at: string | null;
39
+ }
40
+ /** Una pagina come arriva dall'elenco: identità, versione del file, e il modello. */
41
+ export interface RepoPage {
42
+ slug: string;
43
+ url: string;
44
+ /** Lo `sha` del blob su GitHub: identifica la VERSIONE di questo file, non il suo contenuto. */
45
+ sha: string;
46
+ page: Record<string, unknown>;
47
+ }
48
+ export declare const api: {
49
+ pages: () => Promise<{
50
+ ok: true;
51
+ commit: string;
52
+ pages: RepoPage[];
53
+ }>;
54
+ pageBody: (slug: string) => Promise<{
55
+ ok: true;
56
+ slug: string;
57
+ body: string;
58
+ page: Record<string, unknown>;
59
+ }>;
60
+ savePages: (pages: unknown[]) => Promise<{
61
+ ok: true;
62
+ commit: string;
63
+ files: number;
64
+ skipped: string[];
65
+ shas?: Record<string, string>;
66
+ }>;
67
+ publishState: () => Promise<{
68
+ ok: true;
69
+ configured: boolean;
70
+ ahead: number;
71
+ behind: number;
72
+ error?: string;
73
+ commits: {
74
+ message: string;
75
+ date: string | null;
76
+ }[];
77
+ }>;
78
+ publish: () => Promise<{
79
+ ok: true;
80
+ published: boolean;
81
+ commit?: string;
82
+ message?: string;
83
+ }>;
84
+ assets: (prefix?: string, opts?: {
85
+ recursive?: boolean;
86
+ }) => Promise<{
87
+ ok: true;
88
+ prefix: string;
89
+ label?: string;
90
+ folders: AssetFolder[];
91
+ files: AssetFile[];
92
+ }>;
93
+ folders: () => Promise<{
94
+ ok: true;
95
+ folders: AssetFolder[];
96
+ }>;
97
+ /** `label` è il nome per esteso; lo slug della chiave lo calcola il server e lo restituisce. */
98
+ createFolder: (parent: string, name: string, opts?: {
99
+ label?: string;
100
+ relabel?: boolean;
101
+ }) => Promise<{
102
+ ok: true;
103
+ prefix: string;
104
+ exists?: boolean;
105
+ label?: string;
106
+ }>;
107
+ /** Con `skipRefs` copia senza cancellare gli originali e restituisce la mappa degli URL. */
108
+ move: (keys: string[], dest: string, opts?: {
109
+ skipRefs?: boolean;
110
+ }) => Promise<{
111
+ ok: true;
112
+ moved: number;
113
+ finalized?: number;
114
+ urlMap?: Record<string, string>;
115
+ pagesUpdated: string[];
116
+ failed: {
117
+ key: string;
118
+ error: string;
119
+ }[];
120
+ warning?: string;
121
+ }>;
122
+ /** Riscrive i riferimenti, poi elimina gli originali le cui copie sono state verificate. */
123
+ moveApplyRefs: (applyRefs: Record<string, string>) => Promise<{
124
+ ok: true;
125
+ moved: number;
126
+ finalized?: number;
127
+ pagesUpdated: string[];
128
+ failed: {
129
+ key: string;
130
+ error: string;
131
+ }[];
132
+ warning?: string;
133
+ }>;
134
+ usage: (target: {
135
+ keys?: string[];
136
+ prefixes?: string[];
137
+ }) => Promise<{
138
+ ok: true;
139
+ usage: Record<string, string[]>;
140
+ pages: string[];
141
+ count: number;
142
+ selectedCount: number;
143
+ blockers: {
144
+ path: string;
145
+ label: string;
146
+ reason: string;
147
+ }[];
148
+ }>;
149
+ remove: (target: {
150
+ keys?: string[];
151
+ prefixes?: string[];
152
+ }, opts?: {
153
+ refsOnly?: boolean;
154
+ skipRefs?: boolean;
155
+ refsToken?: string;
156
+ }) => Promise<{
157
+ ok: true;
158
+ trashed: number;
159
+ pagesUpdated: string[];
160
+ refsToken?: string;
161
+ }>;
162
+ requests: () => Promise<{
163
+ ok: true;
164
+ requests: ContactRequestRow[];
165
+ }>;
166
+ markRequest: (id: number, handled: boolean) => Promise<{
167
+ ok: true;
168
+ }>;
169
+ deleteRequest: (id: number) => Promise<{
170
+ ok: true;
171
+ }>;
172
+ /** L'upload NON è JSON: corpo grezzo e metadati negli header (vedi assets/upload.js). */
173
+ upload: (prefix: string, file: File) => Promise<AssetFile>;
174
+ trash: () => Promise<{
175
+ ok: true;
176
+ items: TrashItem[];
177
+ }>;
178
+ trashRestore: (trashKeys: string[]) => Promise<{
179
+ ok: true;
180
+ restored: string[];
181
+ conflicts: {
182
+ originalKey: string;
183
+ restoredAs: string;
184
+ }[];
185
+ }>;
186
+ trashDelete: (trashKeys: string[]) => Promise<{
187
+ ok: true;
188
+ removed: number;
189
+ }>;
190
+ trashEmpty: () => Promise<{
191
+ ok: true;
192
+ removed: number;
193
+ }>;
194
+ };
195
+ export declare function uploadQueue(prefix: string, files: File[], onProgress: (done: number, total: number, last?: AssetFile, error?: string) => void, concurrency?: number): Promise<AssetFile[]>;
package/dist/api.js ADDED
@@ -0,0 +1,118 @@
1
+ /* Client tipizzato degli endpoint dell'admin. Un posto solo per sapere che forma hanno le
2
+ * risposte — e, soprattutto, per riconoscere i codici che il server ora sa distinguere:
3
+ * `unauthenticated` (sessione scaduta), `conflict` (qualcuno ha salvato nel frattempo),
4
+ * `unreadable` (un file che non sappiamo riprodurre). Prima qualunque errore diventava
5
+ * "backend non collegato", che manda a cercare il guasto dalla parte sbagliata. */
6
+ export class ApiError extends Error {
7
+ code;
8
+ status;
9
+ constructor(message, code, status) {
10
+ super(message);
11
+ this.name = "ApiError";
12
+ this.code = code;
13
+ this.status = status;
14
+ }
15
+ }
16
+ async function call(url, init) {
17
+ const res = await fetch(url, { cache: "no-store", ...init });
18
+ let body = null;
19
+ try {
20
+ body = await res.json();
21
+ }
22
+ catch { /* risposta non JSON */ }
23
+ if (!res.ok || (body && body.ok === false)) {
24
+ const code = body?.code ?? (res.status === 401 ? "unauthenticated" : "error");
25
+ throw new ApiError(body?.error ?? `HTTP ${res.status}`, code, res.status);
26
+ }
27
+ return body;
28
+ }
29
+ const post = (url, data) => call(url, {
30
+ method: "POST",
31
+ headers: { "Content-Type": "application/json" },
32
+ body: JSON.stringify(data),
33
+ });
34
+ export const api = {
35
+ // ---- pagine
36
+ /* L'elenco viene DAL REPO, non da `/index.json`, che è il sito pubblicato e quindi indietro
37
+ * di una build. `sha` è quello del file su GitHub e torna indietro nel salvataggio: è il modo
38
+ * di accorgersi che qualcun altro ha toccato la stessa pagina nel frattempo. */
39
+ pages: () => call("/admin/api/pages"),
40
+ /* Il corpo markdown, che nell'elenco non c'è: sono testi lunghi e servono solo alla pagina
41
+ * che si sta aprendo. `page` è il modello letto dallo stesso file. */
42
+ pageBody: (slug) => call(`/admin/api/pages/get?slug=${encodeURIComponent(slug)}`),
43
+ /* `shas` è la versione di ogni file DOPO il commit: senza, il salvataggio successivo
44
+ * partirebbe da una versione che non esiste più e verrebbe rifiutato. */
45
+ savePages: (pages) => post("/admin/api/pages", { pages }),
46
+ // ---- pubblicazione
47
+ /* Salvare scrive sulla bozza e non fa partire nessuna build; è questo che manda online. Due
48
+ * gesti separati, quindi due chiamate: una chiede quanto c'è di non pubblicato, l'altra lo
49
+ * pubblica. */
50
+ publishState: () => call("/admin/api/publish"),
51
+ publish: () => post("/admin/api/publish", {}),
52
+ // ---- media
53
+ /* `recursive` scende a qualunque profondità e restituisce solo chiave e nome dei file: serve
54
+ * a spostare o cancellare una cartella intera senza lasciare indietro ciò che sta annidato. */
55
+ assets: (prefix = "", opts = {}) => call(`/admin/api/assets?prefix=${encodeURIComponent(prefix)}${opts.recursive ? "&recursive=1" : ""}`),
56
+ folders: () => call("/admin/api/assets/folders"),
57
+ /** `label` è il nome per esteso; lo slug della chiave lo calcola il server e lo restituisce. */
58
+ createFolder: (parent, name, opts = {}) => post("/admin/api/assets/folder", { parent, name, ...opts }),
59
+ /** Con `skipRefs` copia senza cancellare gli originali e restituisce la mappa degli URL. */
60
+ move: (keys, dest, opts = {}) => post("/admin/api/assets/move", { keys, dest, ...opts }),
61
+ /** Riscrive i riferimenti, poi elimina gli originali le cui copie sono state verificate. */
62
+ moveApplyRefs: (applyRefs) => post("/admin/api/assets/move", { applyRefs }),
63
+ usage: (target) => post("/admin/api/assets/usage", target),
64
+ /* `refsOnly` pulisce solo i riferimenti nelle pagine (un commit, niente file spostati);
65
+ * `skipRefs` sposta i file e non tocca il repo. Servono a spezzare una cancellazione grande
66
+ * in più richieste senza fare un commit — cioè una build — per ogni gruppo. */
67
+ remove: (target, opts = {}) => post("/admin/api/assets/delete", { ...target, ...opts }),
68
+ // ---- richieste dal form di contatto
69
+ requests: () => call("/admin/api/requests"),
70
+ markRequest: (id, handled) => call("/admin/api/requests", {
71
+ method: "PATCH",
72
+ headers: { "Content-Type": "application/json" },
73
+ body: JSON.stringify({ id, handled }),
74
+ }),
75
+ deleteRequest: (id) => call("/admin/api/requests", {
76
+ method: "DELETE",
77
+ headers: { "Content-Type": "application/json" },
78
+ body: JSON.stringify({ id }),
79
+ }),
80
+ /** L'upload NON è JSON: corpo grezzo e metadati negli header (vedi assets/upload.js). */
81
+ upload: (prefix, file) => call("/admin/api/assets/upload", {
82
+ method: "POST",
83
+ headers: {
84
+ "Content-Type": file.type || "application/octet-stream",
85
+ "X-Prefix": prefix,
86
+ "X-Filename": encodeURIComponent(file.name),
87
+ },
88
+ body: file,
89
+ }),
90
+ // ---- cestino
91
+ trash: () => call("/admin/api/assets/trash"),
92
+ trashRestore: (trashKeys) => post("/admin/api/assets/trash/restore", { trashKeys }),
93
+ trashDelete: (trashKeys) => post("/admin/api/assets/trash/delete", { trashKeys }),
94
+ trashEmpty: () => post("/admin/api/assets/trash/empty", {}),
95
+ };
96
+ /* Coda di upload a concorrenza limitata. Il vecchio admin caricava un file alla volta
97
+ * (app.js:922), il che su quaranta foto è tedioso senza motivo; tutte insieme invece saturano
98
+ * la connessione e rendono il progresso illeggibile. Tre è il compromesso.
99
+ * Un file che fallisce non ferma gli altri: si segnala e si prosegue. */
100
+ export async function uploadQueue(prefix, files, onProgress, concurrency = 3) {
101
+ const out = [];
102
+ let done = 0, next = 0;
103
+ const worker = async () => {
104
+ while (next < files.length) {
105
+ const file = files[next++];
106
+ try {
107
+ const r = await api.upload(prefix, file);
108
+ out.push(r);
109
+ onProgress(++done, files.length, r);
110
+ }
111
+ catch (e) {
112
+ onProgress(++done, files.length, undefined, `${file.name}: ${e.message}`);
113
+ }
114
+ }
115
+ };
116
+ await Promise.all(Array.from({ length: Math.min(concurrency, files.length) }, worker));
117
+ return out;
118
+ }
@@ -0,0 +1,3 @@
1
+ import "../theme.css";
2
+ import "./app.css";
3
+ export declare function App(): import("react").JSX.Element;