@ampless/admin 0.2.0-alpha.10 → 0.2.0-alpha.12
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/{chunk-QMVFRT62.js → chunk-2ITWLRYF.js} +1 -5
- package/dist/chunk-4YEBIBFG.js +48 -0
- package/dist/chunk-5OIPGVGG.js +198 -0
- package/dist/chunk-7IJDOT2K.js +1197 -0
- package/dist/chunk-7IR4F7GA.js +6 -0
- package/dist/chunk-BFZODSUT.js +71 -0
- package/dist/chunk-BYLCQYEQ.js +21 -0
- package/dist/chunk-GDQC5X46.js +250 -0
- package/dist/chunk-QVUTNQZH.js +21 -0
- package/dist/chunk-TZWSXAHD.js +32 -0
- package/dist/chunk-XHWECTED.js +1125 -0
- package/dist/chunk-XXJDT6FF.js +335 -0
- package/dist/chunk-XZQRPXKN.js +41 -0
- package/dist/components/admin-dashboard.d.ts +10 -0
- package/dist/components/admin-dashboard.js +9 -0
- package/dist/components/edit-post-view.d.ts +9 -0
- package/dist/components/edit-post-view.js +14 -0
- package/dist/components/index.d.ts +0 -1
- package/dist/components/index.js +23 -25
- package/dist/components/login-view.d.ts +5 -0
- package/dist/components/login-view.js +9 -0
- package/dist/components/media-view.d.ts +5 -0
- package/dist/components/media-view.js +12 -0
- package/dist/components/new-post-view.d.ts +5 -0
- package/dist/components/new-post-view.js +14 -0
- package/dist/components/posts-list-view.d.ts +5 -0
- package/dist/components/posts-list-view.js +11 -0
- package/dist/index.d.ts +12 -7
- package/dist/index.js +15 -9
- package/dist/metafile-esm.json +1 -1
- package/dist/pages/index.d.ts +6 -1
- package/dist/pages/index.js +28 -11
- package/package.json +1 -1
- package/dist/chunk-PAL62MXF.js +0 -3228
- package/dist/login-view-BKrSZLJu.d.ts +0 -24
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
useT
|
|
4
|
+
} from "./chunk-OFHKZNZS.js";
|
|
5
|
+
|
|
6
|
+
// src/components/image-upload-dialog.tsx
|
|
7
|
+
import { useEffect, useRef, useState } from "react";
|
|
8
|
+
import ReactCrop, { centerCrop, makeAspectCrop } from "react-image-crop";
|
|
9
|
+
import "react-image-crop/dist/ReactCrop.css";
|
|
10
|
+
import { shouldSkipProcessing } from "ampless/media";
|
|
11
|
+
import {
|
|
12
|
+
Dialog,
|
|
13
|
+
DialogContent,
|
|
14
|
+
DialogDescription,
|
|
15
|
+
DialogHeader,
|
|
16
|
+
DialogTitle,
|
|
17
|
+
Button,
|
|
18
|
+
Input,
|
|
19
|
+
Label
|
|
20
|
+
} from "@ampless/runtime/ui";
|
|
21
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
22
|
+
var ASPECTS = {
|
|
23
|
+
free: void 0,
|
|
24
|
+
"1:1": 1,
|
|
25
|
+
"4:3": 4 / 3,
|
|
26
|
+
"16:9": 16 / 9,
|
|
27
|
+
"3:2": 3 / 2
|
|
28
|
+
};
|
|
29
|
+
var ASPECT_CHOICES = ["free", "1:1", "4:3", "16:9", "3:2"];
|
|
30
|
+
var FORMAT_CHOICES = ["auto", "webp", "jpeg"];
|
|
31
|
+
var MAX_DIMENSION_PRESETS = [640, 1024, 1600, 2400, 4e3];
|
|
32
|
+
var MIN_DIMENSION = 100;
|
|
33
|
+
var MAX_DIMENSION_CEILING = 8e3;
|
|
34
|
+
function clampMaxDimension(value, fallback) {
|
|
35
|
+
if (!Number.isFinite(value) || value <= 0) return fallback;
|
|
36
|
+
return Math.min(MAX_DIMENSION_CEILING, Math.max(MIN_DIMENSION, Math.round(value)));
|
|
37
|
+
}
|
|
38
|
+
function clampQuality(value) {
|
|
39
|
+
if (!Number.isFinite(value)) return 0.85;
|
|
40
|
+
return Math.min(1, Math.max(0, value));
|
|
41
|
+
}
|
|
42
|
+
function resolveFormat(choice, inputMime, losslessForPng) {
|
|
43
|
+
if (choice === "auto") {
|
|
44
|
+
return {
|
|
45
|
+
format: "webp",
|
|
46
|
+
lossless: losslessForPng && inputMime === "image/png"
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return { format: choice, lossless: false };
|
|
50
|
+
}
|
|
51
|
+
function buildInitialCrop(naturalWidth, naturalHeight, aspect) {
|
|
52
|
+
if (aspect) {
|
|
53
|
+
return centerCrop(
|
|
54
|
+
makeAspectCrop({ unit: "%", width: 100 }, aspect, naturalWidth, naturalHeight),
|
|
55
|
+
naturalWidth,
|
|
56
|
+
naturalHeight
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return { unit: "%", x: 0, y: 0, width: 100, height: 100 };
|
|
60
|
+
}
|
|
61
|
+
function ImageUploadDialog({
|
|
62
|
+
file,
|
|
63
|
+
remaining,
|
|
64
|
+
busy = false,
|
|
65
|
+
defaults,
|
|
66
|
+
onConfirm,
|
|
67
|
+
onSkip,
|
|
68
|
+
onCancel
|
|
69
|
+
}) {
|
|
70
|
+
const t = useT();
|
|
71
|
+
const defaultMaxDimension = defaults?.maxDimension ?? 2400;
|
|
72
|
+
const defaultQuality = defaults?.quality ?? 0.85;
|
|
73
|
+
const losslessForPng = defaults?.losslessForPng ?? true;
|
|
74
|
+
const [original, setOriginal] = useState(false);
|
|
75
|
+
const [aspect, setAspect] = useState("free");
|
|
76
|
+
const [crop, setCrop] = useState(void 0);
|
|
77
|
+
const [percentCrop, setPercentCrop] = useState(null);
|
|
78
|
+
const [naturalSize, setNaturalSize] = useState(null);
|
|
79
|
+
const [formatChoice, setFormatChoice] = useState("auto");
|
|
80
|
+
const [losslessOverride, setLosslessOverride] = useState(null);
|
|
81
|
+
const [quality, setQuality] = useState(defaultQuality);
|
|
82
|
+
const [maxDimension, setMaxDimension] = useState(defaultMaxDimension);
|
|
83
|
+
const [previewUrl, setPreviewUrl] = useState(null);
|
|
84
|
+
const imgRef = useRef(null);
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
setOriginal(false);
|
|
87
|
+
setAspect("free");
|
|
88
|
+
setCrop(void 0);
|
|
89
|
+
setPercentCrop(null);
|
|
90
|
+
setNaturalSize(null);
|
|
91
|
+
setFormatChoice("auto");
|
|
92
|
+
setLosslessOverride(null);
|
|
93
|
+
setQuality(defaultQuality);
|
|
94
|
+
setMaxDimension(defaultMaxDimension);
|
|
95
|
+
}, [file, defaultQuality, defaultMaxDimension]);
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
if (!naturalSize) return;
|
|
98
|
+
const next = buildInitialCrop(naturalSize.width, naturalSize.height, ASPECTS[aspect]);
|
|
99
|
+
setCrop(next);
|
|
100
|
+
setPercentCrop(next);
|
|
101
|
+
}, [aspect, naturalSize]);
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (!file) {
|
|
104
|
+
setPreviewUrl(null);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const url = URL.createObjectURL(file);
|
|
108
|
+
setPreviewUrl(url);
|
|
109
|
+
return () => URL.revokeObjectURL(url);
|
|
110
|
+
}, [file]);
|
|
111
|
+
if (!file) return null;
|
|
112
|
+
const isImage = file.type.startsWith("image/");
|
|
113
|
+
const passthrough = !isImage || shouldSkipProcessing(file.type);
|
|
114
|
+
const showCropper = !passthrough && !original;
|
|
115
|
+
const { format, lossless: autoLossless } = resolveFormat(formatChoice, file.type, losslessForPng);
|
|
116
|
+
const lossless = losslessOverride ?? autoLossless;
|
|
117
|
+
const showLosslessToggle = !original && !passthrough && format === "webp";
|
|
118
|
+
const showQualitySlider = !original && !passthrough && (format === "jpeg" || format === "webp" && !lossless);
|
|
119
|
+
function handleImageLoad(e) {
|
|
120
|
+
const { naturalWidth, naturalHeight } = e.currentTarget;
|
|
121
|
+
setNaturalSize({ width: naturalWidth, height: naturalHeight });
|
|
122
|
+
const initial = buildInitialCrop(naturalWidth, naturalHeight, ASPECTS[aspect]);
|
|
123
|
+
setCrop(initial);
|
|
124
|
+
setPercentCrop(initial);
|
|
125
|
+
}
|
|
126
|
+
function handleConfirm() {
|
|
127
|
+
if (!file || busy) return;
|
|
128
|
+
if (original || passthrough) {
|
|
129
|
+
onConfirm(file, { original: true });
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
let cropArea = void 0;
|
|
133
|
+
if (percentCrop && naturalSize) {
|
|
134
|
+
const x = Math.round(percentCrop.x / 100 * naturalSize.width);
|
|
135
|
+
const y = Math.round(percentCrop.y / 100 * naturalSize.height);
|
|
136
|
+
const width = Math.round(percentCrop.width / 100 * naturalSize.width);
|
|
137
|
+
const height = Math.round(percentCrop.height / 100 * naturalSize.height);
|
|
138
|
+
if (width > 0 && height > 0 && (x !== 0 || y !== 0 || width !== naturalSize.width || height !== naturalSize.height)) {
|
|
139
|
+
cropArea = { x, y, width, height };
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
onConfirm(file, {
|
|
143
|
+
crop: cropArea,
|
|
144
|
+
maxDimension: clampMaxDimension(maxDimension, defaultMaxDimension),
|
|
145
|
+
format,
|
|
146
|
+
quality: clampQuality(quality),
|
|
147
|
+
lossless: format === "webp" ? lossless : false
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
return /* @__PURE__ */ jsx(
|
|
151
|
+
Dialog,
|
|
152
|
+
{
|
|
153
|
+
open: true,
|
|
154
|
+
onOpenChange: (open) => {
|
|
155
|
+
if (open) return;
|
|
156
|
+
onCancel();
|
|
157
|
+
},
|
|
158
|
+
children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-h-[90vh] max-w-4xl overflow-y-auto", children: [
|
|
159
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
160
|
+
/* @__PURE__ */ jsx(DialogTitle, { className: "truncate", children: file.name }),
|
|
161
|
+
/* @__PURE__ */ jsxs(DialogDescription, { children: [
|
|
162
|
+
remaining > 1 ? t("media.dialog.remaining", { count: remaining }) : `${formatBytes(file.size)} \xB7 ${file.type || "unknown"}`,
|
|
163
|
+
busy && t("media.dialog.uploading")
|
|
164
|
+
] })
|
|
165
|
+
] }),
|
|
166
|
+
previewUrl && showCropper && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center rounded-md bg-black/90 p-2", children: /* @__PURE__ */ jsx(
|
|
167
|
+
ReactCrop,
|
|
168
|
+
{
|
|
169
|
+
crop,
|
|
170
|
+
aspect: ASPECTS[aspect],
|
|
171
|
+
minWidth: 20,
|
|
172
|
+
minHeight: 20,
|
|
173
|
+
onChange: (_pixel, percent) => {
|
|
174
|
+
setCrop(percent);
|
|
175
|
+
setPercentCrop(percent);
|
|
176
|
+
},
|
|
177
|
+
children: /* @__PURE__ */ jsx(
|
|
178
|
+
"img",
|
|
179
|
+
{
|
|
180
|
+
ref: imgRef,
|
|
181
|
+
src: previewUrl,
|
|
182
|
+
alt: "preview",
|
|
183
|
+
className: "block max-h-[60vh] max-w-full",
|
|
184
|
+
onLoad: handleImageLoad
|
|
185
|
+
}
|
|
186
|
+
)
|
|
187
|
+
}
|
|
188
|
+
) }),
|
|
189
|
+
previewUrl && !showCropper && isImage && /* @__PURE__ */ jsx("div", { className: "flex h-48 items-center justify-center rounded-md bg-muted", children: /* @__PURE__ */ jsx("img", { src: previewUrl, alt: "preview", className: "max-h-full max-w-full object-contain" }) }),
|
|
190
|
+
!isImage && // Non-image upload: skip the broken-img preview. Show the
|
|
191
|
+
// file's name / size / mime so the admin can confirm before
|
|
192
|
+
// committing the bytes to S3.
|
|
193
|
+
/* @__PURE__ */ jsxs("div", { className: "flex h-32 flex-col items-center justify-center gap-1 rounded-md bg-muted text-sm text-muted-foreground", children: [
|
|
194
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: file.name }),
|
|
195
|
+
/* @__PURE__ */ jsxs("span", { className: "font-mono text-xs", children: [
|
|
196
|
+
formatBytes(file.size),
|
|
197
|
+
" \xB7 ",
|
|
198
|
+
file.type || "unknown"
|
|
199
|
+
] })
|
|
200
|
+
] }),
|
|
201
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
202
|
+
/* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
|
|
203
|
+
/* @__PURE__ */ jsx(
|
|
204
|
+
"input",
|
|
205
|
+
{
|
|
206
|
+
type: "checkbox",
|
|
207
|
+
checked: original,
|
|
208
|
+
disabled: busy,
|
|
209
|
+
onChange: (e) => setOriginal(e.target.checked)
|
|
210
|
+
}
|
|
211
|
+
),
|
|
212
|
+
/* @__PURE__ */ jsx("span", { children: t("media.dialog.useOriginal") }),
|
|
213
|
+
passthrough && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t("media.dialog.passthroughNote") })
|
|
214
|
+
] }),
|
|
215
|
+
!original && !passthrough && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
216
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
217
|
+
/* @__PURE__ */ jsx(Label, { children: t("media.dialog.aspectRatio") }),
|
|
218
|
+
/* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-2", children: ASPECT_CHOICES.map((choice) => /* @__PURE__ */ jsx(
|
|
219
|
+
Button,
|
|
220
|
+
{
|
|
221
|
+
type: "button",
|
|
222
|
+
variant: aspect === choice ? "default" : "outline",
|
|
223
|
+
size: "sm",
|
|
224
|
+
disabled: busy,
|
|
225
|
+
onClick: () => setAspect(choice),
|
|
226
|
+
children: choice
|
|
227
|
+
},
|
|
228
|
+
choice
|
|
229
|
+
)) })
|
|
230
|
+
] }),
|
|
231
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
232
|
+
/* @__PURE__ */ jsx(Label, { children: t("media.dialog.outputFormat") }),
|
|
233
|
+
/* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-2", children: FORMAT_CHOICES.map((choice) => /* @__PURE__ */ jsx(
|
|
234
|
+
Button,
|
|
235
|
+
{
|
|
236
|
+
type: "button",
|
|
237
|
+
variant: formatChoice === choice ? "default" : "outline",
|
|
238
|
+
size: "sm",
|
|
239
|
+
disabled: busy,
|
|
240
|
+
onClick: () => {
|
|
241
|
+
setFormatChoice(choice);
|
|
242
|
+
setLosslessOverride(null);
|
|
243
|
+
},
|
|
244
|
+
children: choice
|
|
245
|
+
},
|
|
246
|
+
choice
|
|
247
|
+
)) })
|
|
248
|
+
] }),
|
|
249
|
+
showLosslessToggle && /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
|
|
250
|
+
/* @__PURE__ */ jsx(
|
|
251
|
+
"input",
|
|
252
|
+
{
|
|
253
|
+
type: "checkbox",
|
|
254
|
+
checked: lossless,
|
|
255
|
+
disabled: busy,
|
|
256
|
+
onChange: (e) => setLosslessOverride(e.target.checked)
|
|
257
|
+
}
|
|
258
|
+
),
|
|
259
|
+
/* @__PURE__ */ jsx("span", { children: t("media.dialog.losslessWebp") })
|
|
260
|
+
] }),
|
|
261
|
+
showQualitySlider && /* @__PURE__ */ jsxs("div", { children: [
|
|
262
|
+
/* @__PURE__ */ jsx(Label, { children: t("media.dialog.quality", { value: Math.round(quality * 100) }) }),
|
|
263
|
+
/* @__PURE__ */ jsx(
|
|
264
|
+
"input",
|
|
265
|
+
{
|
|
266
|
+
type: "range",
|
|
267
|
+
min: 50,
|
|
268
|
+
max: 100,
|
|
269
|
+
step: 1,
|
|
270
|
+
disabled: busy,
|
|
271
|
+
value: Math.round(quality * 100),
|
|
272
|
+
onChange: (e) => setQuality(Number(e.target.value) / 100),
|
|
273
|
+
className: "mt-2 w-full"
|
|
274
|
+
}
|
|
275
|
+
)
|
|
276
|
+
] }),
|
|
277
|
+
/* @__PURE__ */ jsxs("div", { className: "max-w-xs", children: [
|
|
278
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "maxDimension", children: t("media.dialog.maxDimension") }),
|
|
279
|
+
/* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-2", children: MAX_DIMENSION_PRESETS.map((preset) => /* @__PURE__ */ jsx(
|
|
280
|
+
Button,
|
|
281
|
+
{
|
|
282
|
+
type: "button",
|
|
283
|
+
variant: maxDimension === preset ? "default" : "outline",
|
|
284
|
+
size: "sm",
|
|
285
|
+
disabled: busy,
|
|
286
|
+
onClick: () => setMaxDimension(preset),
|
|
287
|
+
children: preset
|
|
288
|
+
},
|
|
289
|
+
preset
|
|
290
|
+
)) }),
|
|
291
|
+
/* @__PURE__ */ jsx(
|
|
292
|
+
Input,
|
|
293
|
+
{
|
|
294
|
+
id: "maxDimension",
|
|
295
|
+
type: "number",
|
|
296
|
+
className: "mt-2",
|
|
297
|
+
min: MIN_DIMENSION,
|
|
298
|
+
max: MAX_DIMENSION_CEILING,
|
|
299
|
+
disabled: busy,
|
|
300
|
+
value: maxDimension,
|
|
301
|
+
onChange: (e) => setMaxDimension(Number(e.target.value) || defaultMaxDimension)
|
|
302
|
+
}
|
|
303
|
+
)
|
|
304
|
+
] })
|
|
305
|
+
] })
|
|
306
|
+
] }),
|
|
307
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
|
|
308
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", type: "button", onClick: onCancel, children: t("media.dialog.cancelAll") }),
|
|
309
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", type: "button", disabled: busy, onClick: onSkip, children: t("media.dialog.skip") }),
|
|
310
|
+
/* @__PURE__ */ jsx(Button, { type: "button", disabled: busy, onClick: handleConfirm, children: busy ? t("media.dialog.uploadingButton") : t("media.dialog.upload") })
|
|
311
|
+
] })
|
|
312
|
+
] })
|
|
313
|
+
}
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
function formatBytes(bytes) {
|
|
317
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
318
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
319
|
+
return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// src/lib/admin-config-client.ts
|
|
323
|
+
var cmsConfig = null;
|
|
324
|
+
function setAdminCmsConfigClient(config) {
|
|
325
|
+
cmsConfig = config;
|
|
326
|
+
}
|
|
327
|
+
function getMediaProcessingDefaults() {
|
|
328
|
+
return cmsConfig?.media?.processing;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export {
|
|
332
|
+
ImageUploadDialog,
|
|
333
|
+
setAdminCmsConfigClient,
|
|
334
|
+
getMediaProcessingDefaults
|
|
335
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
PostForm
|
|
4
|
+
} from "./chunk-7IJDOT2K.js";
|
|
5
|
+
import {
|
|
6
|
+
readAdminSiteIdFromCookie
|
|
7
|
+
} from "./chunk-TZWSXAHD.js";
|
|
8
|
+
import {
|
|
9
|
+
useT
|
|
10
|
+
} from "./chunk-OFHKZNZS.js";
|
|
11
|
+
|
|
12
|
+
// src/components/edit-post-view.tsx
|
|
13
|
+
import { useEffect, useState, use } from "react";
|
|
14
|
+
import { notFound } from "next/navigation";
|
|
15
|
+
import { getPostById } from "ampless";
|
|
16
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
17
|
+
function EditPostPage({ params }) {
|
|
18
|
+
const t = useT();
|
|
19
|
+
const { postId } = use(params);
|
|
20
|
+
const [post, setPost] = useState(null);
|
|
21
|
+
const [loading, setLoading] = useState(true);
|
|
22
|
+
const [missing, setMissing] = useState(false);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const siteId = readAdminSiteIdFromCookie();
|
|
25
|
+
getPostById(postId, { siteId }).then((p) => {
|
|
26
|
+
if (!p) setMissing(true);
|
|
27
|
+
else setPost(p);
|
|
28
|
+
}).finally(() => setLoading(false));
|
|
29
|
+
}, [postId]);
|
|
30
|
+
if (loading)
|
|
31
|
+
return /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-7xl p-4 md:p-8", children: t("common.loading") });
|
|
32
|
+
if (missing) notFound();
|
|
33
|
+
return /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-7xl p-4 md:p-8", children: [
|
|
34
|
+
/* @__PURE__ */ jsx("h1", { className: "mb-6 text-2xl font-bold md:mb-8 md:text-3xl", children: t("posts.form.editTitle") }),
|
|
35
|
+
post && /* @__PURE__ */ jsx(PostForm, { post })
|
|
36
|
+
] });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export {
|
|
40
|
+
EditPostPage
|
|
41
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Admin home / dashboard. Lists post counts. Marked client-side because
|
|
5
|
+
* it reads from the AppSync client directly (no server-rendered query
|
|
6
|
+
* yet — listed posts come from Amplify SDK at mount time).
|
|
7
|
+
*/
|
|
8
|
+
declare function AdminDashboard(): react_jsx_runtime.JSX.Element;
|
|
9
|
+
|
|
10
|
+
export { AdminDashboard };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
EditPostPage
|
|
4
|
+
} from "../chunk-XZQRPXKN.js";
|
|
5
|
+
import "../chunk-7IJDOT2K.js";
|
|
6
|
+
import "../chunk-TZWSXAHD.js";
|
|
7
|
+
import "../chunk-7IR4F7GA.js";
|
|
8
|
+
import "../chunk-XXJDT6FF.js";
|
|
9
|
+
import "../chunk-2ITWLRYF.js";
|
|
10
|
+
import "../chunk-OFHKZNZS.js";
|
|
11
|
+
import "../chunk-OPQ3SAZJ.js";
|
|
12
|
+
export {
|
|
13
|
+
EditPostPage
|
|
14
|
+
};
|
|
@@ -2,7 +2,6 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import { L as Locale, D as Dictionary } from '../i18n-DzXXcIQQ.js';
|
|
3
3
|
import { Config, Post, ThemeManifest, LocalizedString, MediaProcessingDefaults } from 'ampless';
|
|
4
4
|
import { AmplessOutputs } from '@ampless/runtime';
|
|
5
|
-
export { A as AdminDashboard, E as EditPostPage, L as LoginPage, M as MediaPage, N as NewPostPage, P as PostsList } from '../login-view-BKrSZLJu.js';
|
|
6
5
|
import { ProcessOptions } from 'ampless/media';
|
|
7
6
|
export { invalidateSiteSettingsCache } from '../lib/theme-actions.js';
|
|
8
7
|
|
package/dist/components/index.js
CHANGED
|
@@ -1,53 +1,51 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import {
|
|
3
|
-
AdminDashboard,
|
|
4
3
|
AdminProviders,
|
|
5
|
-
EditPostPage,
|
|
6
|
-
ImageUploadDialog,
|
|
7
|
-
LoginPage,
|
|
8
|
-
MediaPage,
|
|
9
|
-
MediaPicker,
|
|
10
|
-
MediaUploader,
|
|
11
|
-
NewPostPage,
|
|
12
|
-
PostForm,
|
|
13
|
-
PostsList,
|
|
14
4
|
Sidebar,
|
|
15
5
|
SiteSelector,
|
|
16
6
|
SiteSettingsForm,
|
|
17
|
-
ThemeSettingsForm
|
|
18
|
-
|
|
7
|
+
ThemeSettingsForm
|
|
8
|
+
} from "../chunk-XHWECTED.js";
|
|
9
|
+
import {
|
|
10
|
+
invalidateSiteSettingsCache
|
|
11
|
+
} from "../chunk-VXEVLHGL.js";
|
|
12
|
+
import {
|
|
13
|
+
MediaUploader
|
|
14
|
+
} from "../chunk-GDQC5X46.js";
|
|
15
|
+
import {
|
|
16
|
+
MediaPicker,
|
|
17
|
+
PostForm,
|
|
19
18
|
sanitizeName,
|
|
20
|
-
setAdminCmsConfig,
|
|
21
19
|
uploadProcessedImage
|
|
22
|
-
} from "../chunk-
|
|
20
|
+
} from "../chunk-7IJDOT2K.js";
|
|
21
|
+
import {
|
|
22
|
+
readAdminSiteIdFromCookie,
|
|
23
|
+
setAdminCmsConfig
|
|
24
|
+
} from "../chunk-TZWSXAHD.js";
|
|
25
|
+
import {
|
|
26
|
+
ADMIN_SITE_COOKIE
|
|
27
|
+
} from "../chunk-7IR4F7GA.js";
|
|
28
|
+
import {
|
|
29
|
+
ImageUploadDialog
|
|
30
|
+
} from "../chunk-XXJDT6FF.js";
|
|
23
31
|
import {
|
|
24
|
-
ADMIN_SITE_COOKIE,
|
|
25
32
|
publicMediaUrl,
|
|
26
33
|
setAdminMediaContext
|
|
27
|
-
} from "../chunk-
|
|
34
|
+
} from "../chunk-2ITWLRYF.js";
|
|
28
35
|
import {
|
|
29
36
|
I18nProvider,
|
|
30
37
|
useLocale,
|
|
31
38
|
useT
|
|
32
39
|
} from "../chunk-OFHKZNZS.js";
|
|
33
40
|
import "../chunk-OPQ3SAZJ.js";
|
|
34
|
-
import {
|
|
35
|
-
invalidateSiteSettingsCache
|
|
36
|
-
} from "../chunk-VXEVLHGL.js";
|
|
37
41
|
export {
|
|
38
42
|
ADMIN_SITE_COOKIE,
|
|
39
|
-
AdminDashboard,
|
|
40
43
|
AdminProviders,
|
|
41
|
-
EditPostPage,
|
|
42
44
|
I18nProvider,
|
|
43
45
|
ImageUploadDialog,
|
|
44
|
-
LoginPage,
|
|
45
|
-
MediaPage,
|
|
46
46
|
MediaPicker,
|
|
47
47
|
MediaUploader,
|
|
48
|
-
NewPostPage,
|
|
49
48
|
PostForm,
|
|
50
|
-
PostsList,
|
|
51
49
|
Sidebar,
|
|
52
50
|
SiteSelector,
|
|
53
51
|
SiteSettingsForm,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
MediaPage
|
|
4
|
+
} from "../chunk-BYLCQYEQ.js";
|
|
5
|
+
import "../chunk-GDQC5X46.js";
|
|
6
|
+
import "../chunk-XXJDT6FF.js";
|
|
7
|
+
import "../chunk-2ITWLRYF.js";
|
|
8
|
+
import "../chunk-OFHKZNZS.js";
|
|
9
|
+
import "../chunk-OPQ3SAZJ.js";
|
|
10
|
+
export {
|
|
11
|
+
MediaPage
|
|
12
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
NewPostPage
|
|
4
|
+
} from "../chunk-QVUTNQZH.js";
|
|
5
|
+
import "../chunk-7IJDOT2K.js";
|
|
6
|
+
import "../chunk-TZWSXAHD.js";
|
|
7
|
+
import "../chunk-7IR4F7GA.js";
|
|
8
|
+
import "../chunk-XXJDT6FF.js";
|
|
9
|
+
import "../chunk-2ITWLRYF.js";
|
|
10
|
+
import "../chunk-OFHKZNZS.js";
|
|
11
|
+
import "../chunk-OPQ3SAZJ.js";
|
|
12
|
+
export {
|
|
13
|
+
NewPostPage
|
|
14
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -24,14 +24,19 @@ interface CreateAdminOpts {
|
|
|
24
24
|
cmsConfig: Config;
|
|
25
25
|
/**
|
|
26
26
|
* Optional pre-built ampless runtime instance for cross-package
|
|
27
|
-
* sharing.
|
|
28
|
-
*
|
|
29
|
-
* `
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
27
|
+
* sharing. Accepts either the instance itself OR a thunk (sync or
|
|
28
|
+
* async). The thunk form is the recommended one for the template
|
|
29
|
+
* scaffold's `lib/admin.ts` — it lets the consumer break the
|
|
30
|
+
* `lib/admin.ts → lib/ampless.ts → themes-registry → … → lib/admin.ts`
|
|
31
|
+
* static-import cycle by lazily resolving `ampless` via `import()`
|
|
32
|
+
* inside the thunk body (the module isn't loaded until the first
|
|
33
|
+
* `loadSiteSettings` / `loadThemeConfig` call, by which time all
|
|
34
|
+
* other modules have finished initialising).
|
|
35
|
+
*
|
|
36
|
+
* When omitted, server pages that depend on settings / theme config
|
|
37
|
+
* throw at request time.
|
|
33
38
|
*/
|
|
34
|
-
ampless?: Ampless;
|
|
39
|
+
ampless?: Ampless | (() => Ampless | Promise<Ampless>);
|
|
35
40
|
/**
|
|
36
41
|
* Locale for admin UI strings. Pass a string code ('en', 'ja') for a
|
|
37
42
|
* built-in dictionary, or an object literal to override specific
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
-
ADMIN_SITE_COOKIE
|
|
2
|
+
ADMIN_SITE_COOKIE
|
|
3
|
+
} from "./chunk-7IR4F7GA.js";
|
|
4
|
+
import {
|
|
3
5
|
createMedia
|
|
4
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-2ITWLRYF.js";
|
|
5
7
|
import {
|
|
6
8
|
getDictionary,
|
|
7
9
|
resolveLocale,
|
|
@@ -82,15 +84,19 @@ function createAdmin(opts) {
|
|
|
82
84
|
const amplifyServer = createAmplifyServer(outputs);
|
|
83
85
|
const auth = createAuthServer(amplifyServer);
|
|
84
86
|
const media = createMedia(outputs, cmsConfig);
|
|
85
|
-
|
|
86
|
-
function
|
|
87
|
-
if (
|
|
87
|
+
let amplessCache = null;
|
|
88
|
+
async function resolveAmpless() {
|
|
89
|
+
if (amplessCache) return amplessCache;
|
|
90
|
+
if (amplessIn === void 0 || amplessIn === null) {
|
|
88
91
|
throw new Error(
|
|
89
92
|
"[@ampless/admin] createAdmin was called without an `ampless` runtime instance, but a method that needs one (loadSiteSettings / loadThemeConfig) was invoked. Pass `ampless` in the `createAdmin` options so admin can reuse your public-side runtime."
|
|
90
93
|
);
|
|
91
94
|
}
|
|
92
|
-
|
|
95
|
+
const resolved = typeof amplessIn === "function" ? await amplessIn() : amplessIn;
|
|
96
|
+
amplessCache = resolved;
|
|
97
|
+
return resolved;
|
|
93
98
|
}
|
|
99
|
+
const eagerAmpless = amplessIn !== void 0 && amplessIn !== null && typeof amplessIn !== "function" ? amplessIn : null;
|
|
94
100
|
return {
|
|
95
101
|
t: (key, vars) => translate(dict, key, vars),
|
|
96
102
|
locale,
|
|
@@ -101,12 +107,12 @@ function createAdmin(opts) {
|
|
|
101
107
|
amplifyServer,
|
|
102
108
|
currentAdminSiteId: adminSite.currentAdminSiteId,
|
|
103
109
|
adminSiteOptions: adminSite.adminSiteOptions,
|
|
104
|
-
loadSiteSettings: (siteId) =>
|
|
105
|
-
loadThemeConfig: (siteId) =>
|
|
110
|
+
loadSiteSettings: async (siteId) => (await resolveAmpless()).loadSiteSettings(siteId),
|
|
111
|
+
loadThemeConfig: async (siteId) => (await resolveAmpless()).loadThemeConfig(siteId),
|
|
106
112
|
publicMediaUrl: media.publicMediaUrl,
|
|
107
113
|
outputs,
|
|
108
114
|
cmsConfig,
|
|
109
|
-
ampless
|
|
115
|
+
ampless: eagerAmpless
|
|
110
116
|
};
|
|
111
117
|
}
|
|
112
118
|
export {
|