@ampless/admin 0.2.0-alpha.2 → 0.2.0-alpha.3

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.
@@ -1,297 +1,23 @@
1
- 'use client';
2
1
  import {
2
+ AdminDashboard,
3
+ AdminProviders,
4
+ EditPostPage,
3
5
  I18nProvider,
4
- MediaUploader,
5
- PostForm,
6
+ LoginPage,
7
+ MediaPage,
8
+ NewPostPage,
9
+ PostsList,
6
10
  Sidebar,
7
11
  SiteSelector,
8
12
  SiteSettingsForm,
9
- ThemeSettingsForm,
10
- setAdminCmsConfigClient,
11
- useT
12
- } from "../chunk-T2RSMFOI.js";
13
- import {
14
- readAdminSiteIdFromCookie,
15
- setAdminCmsConfig,
16
- setAdminMediaContext
17
- } from "../chunk-TJR3ALRJ.js";
13
+ ThemeSettingsForm
14
+ } from "../chunk-LYRCUL7H.js";
15
+ import "../chunk-FI7CM4LH.js";
16
+ import "../chunk-VXEVLHGL.js";
18
17
 
19
18
  // src/pages/admin-layout.tsx
20
19
  import { redirect } from "next/navigation";
21
-
22
- // src/pages/admin-providers.tsx
23
- import { useEffect } from "react";
24
-
25
- // src/lib/amplify-client.ts
26
- import { Amplify } from "aws-amplify";
27
- var configured = false;
28
- function configureAmplify(outputs) {
29
- if (configured) return;
30
- Amplify.configure(outputs, { ssr: true });
31
- configured = true;
32
- }
33
-
34
- // src/lib/posts-provider.ts
35
- import { generateClient } from "aws-amplify/api";
36
- import {
37
- setPostsProvider,
38
- composeSiteIdStatus,
39
- composeSiteIdSlug
40
- } from "ampless";
41
- function encodeBody(value) {
42
- if (typeof value === "string") return value;
43
- return JSON.stringify(value ?? null);
44
- }
45
- function decodeBody(value) {
46
- if (typeof value !== "string") return value;
47
- try {
48
- return JSON.parse(value);
49
- } catch {
50
- return value;
51
- }
52
- }
53
- function toCorePost(p) {
54
- return {
55
- postId: p.postId,
56
- siteId: p.siteId,
57
- slug: p.slug,
58
- title: p.title,
59
- excerpt: p.excerpt ?? void 0,
60
- format: p.format ?? "markdown",
61
- body: decodeBody(p.body),
62
- status: p.status ?? "draft",
63
- publishedAt: p.publishedAt ?? void 0,
64
- tags: (p.tags ?? []).filter((t) => typeof t === "string")
65
- };
66
- }
67
- function postTagEntries(post) {
68
- if (post.status !== "published" || !post.publishedAt || !post.tags?.length) return [];
69
- return post.tags.map((tag) => ({
70
- siteIdTag: `${post.siteId}#${tag}`,
71
- publishedAtPostId: `${post.publishedAt}#${post.postId}`
72
- }));
73
- }
74
- function entryKey(e) {
75
- return `${e.siteIdTag}|${e.publishedAtPostId}`;
76
- }
77
- var installed = false;
78
- function installAdminPostsProvider() {
79
- if (installed) return;
80
- installed = true;
81
- const client = generateClient();
82
- async function syncPostTags(post, oldPost) {
83
- const oldEntries = oldPost ? postTagEntries(oldPost) : [];
84
- const newEntries = postTagEntries(post);
85
- const oldKeys = new Set(oldEntries.map(entryKey));
86
- const newKeys = new Set(newEntries.map(entryKey));
87
- await Promise.all(
88
- oldEntries.filter((e) => !newKeys.has(entryKey(e))).map((e) => client.models.PostTag.delete(e))
89
- );
90
- await Promise.all(
91
- newEntries.filter((e) => !oldKeys.has(entryKey(e))).map(
92
- (e) => client.models.PostTag.create({
93
- siteIdTag: e.siteIdTag,
94
- publishedAtPostId: e.publishedAtPostId,
95
- siteId: post.siteId,
96
- tag: e.siteIdTag.slice(post.siteId.length + 1),
97
- postId: post.postId,
98
- publishedAt: post.publishedAt,
99
- slug: post.slug,
100
- title: post.title,
101
- excerpt: post.excerpt,
102
- tags: post.tags ?? []
103
- })
104
- )
105
- );
106
- await Promise.all(
107
- newEntries.filter((e) => oldKeys.has(entryKey(e))).map(
108
- (e) => client.models.PostTag.update({
109
- siteIdTag: e.siteIdTag,
110
- publishedAtPostId: e.publishedAtPostId,
111
- slug: post.slug,
112
- title: post.title,
113
- excerpt: post.excerpt,
114
- tags: post.tags ?? []
115
- })
116
- )
117
- );
118
- }
119
- const provider = {
120
- async list(opts = {}) {
121
- const siteId = opts.siteId ?? "default";
122
- const status = opts.status ?? "published";
123
- const filter = { siteId: { eq: siteId } };
124
- if (status !== "all") filter.status = { eq: status };
125
- const { data } = await client.models.Post.list({ filter, limit: opts.limit ?? 100 });
126
- return data.map(toCorePost);
127
- },
128
- async get(slug, opts = {}) {
129
- const siteId = opts.siteId ?? "default";
130
- const { data } = await client.models.Post.list({
131
- filter: { siteId: { eq: siteId }, slug: { eq: slug } },
132
- limit: 1
133
- });
134
- return data[0] ? toCorePost(data[0]) : null;
135
- },
136
- async getById(postId, opts = {}) {
137
- const siteId = opts.siteId ?? "default";
138
- const { data } = await client.models.Post.get({ siteId, postId });
139
- return data ? toCorePost(data) : null;
140
- },
141
- async create(input) {
142
- const postId = input.postId ?? `post-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
143
- const { data, errors } = await client.models.Post.create({
144
- siteId: input.siteId,
145
- postId,
146
- slug: input.slug,
147
- title: input.title,
148
- excerpt: input.excerpt,
149
- format: input.format,
150
- body: encodeBody(input.body),
151
- status: input.status,
152
- publishedAt: input.publishedAt,
153
- tags: input.tags,
154
- // Denormalized GSI keys. Must match every change to slug /
155
- // status — see the update() branch below.
156
- siteIdStatus: composeSiteIdStatus(input.siteId, input.status),
157
- siteIdSlug: composeSiteIdSlug(input.siteId, input.slug)
158
- });
159
- if (errors || !data) throw new Error(errors?.[0]?.message ?? "Failed to create post");
160
- const created = toCorePost(data);
161
- await syncPostTags(created, null);
162
- return created;
163
- },
164
- async update(postId, patch, opts = {}) {
165
- const siteId = opts.siteId ?? "default";
166
- const oldPost = await this.getById(postId, { siteId });
167
- const nextStatus = patch.status ?? oldPost?.status;
168
- const nextSlug = patch.slug ?? oldPost?.slug;
169
- const { data, errors } = await client.models.Post.update({
170
- siteId,
171
- postId,
172
- ...patch.slug !== void 0 && { slug: patch.slug },
173
- ...patch.title !== void 0 && { title: patch.title },
174
- ...patch.excerpt !== void 0 && { excerpt: patch.excerpt },
175
- ...patch.format !== void 0 && { format: patch.format },
176
- ...patch.body !== void 0 && { body: encodeBody(patch.body) },
177
- ...patch.status !== void 0 && { status: patch.status },
178
- ...patch.publishedAt !== void 0 && { publishedAt: patch.publishedAt },
179
- ...patch.tags !== void 0 && { tags: patch.tags },
180
- ...patch.status !== void 0 && nextStatus && { siteIdStatus: composeSiteIdStatus(siteId, nextStatus) },
181
- ...patch.slug !== void 0 && nextSlug && { siteIdSlug: composeSiteIdSlug(siteId, nextSlug) }
182
- });
183
- if (errors || !data) throw new Error(errors?.[0]?.message ?? "Failed to update post");
184
- const updated = toCorePost(data);
185
- await syncPostTags(updated, oldPost);
186
- return updated;
187
- },
188
- async remove(postId, opts = {}) {
189
- const siteId = opts.siteId ?? "default";
190
- const oldPost = await this.getById(postId, { siteId });
191
- if (oldPost) {
192
- await syncPostTags({ ...oldPost, status: "draft" }, oldPost);
193
- }
194
- const { errors } = await client.models.Post.delete({ siteId, postId });
195
- if (errors) throw new Error(errors[0]?.message ?? "Failed to delete post");
196
- }
197
- };
198
- setPostsProvider(provider);
199
- }
200
-
201
- // src/lib/kv-provider.ts
202
- import { generateClient as generateClient2 } from "aws-amplify/api";
203
- import { setKvStore } from "ampless";
204
- var installed2 = false;
205
- function installAdminKvProvider() {
206
- if (installed2) return;
207
- installed2 = true;
208
- const client = generateClient2();
209
- function requireModel() {
210
- const m = client.models.KvStore;
211
- if (!m) {
212
- throw new Error(
213
- "KvStore model is not available on the AppSync client. Did you redeploy the sandbox? Run `npx ampx sandbox` and wait for it to finish, then reload this page."
214
- );
215
- }
216
- return m;
217
- }
218
- function encodeValue(value) {
219
- return JSON.stringify(value ?? null);
220
- }
221
- function decodeValue(raw) {
222
- if (typeof raw !== "string") return raw;
223
- try {
224
- return JSON.parse(raw);
225
- } catch {
226
- return raw;
227
- }
228
- }
229
- const store = {
230
- async get(pk, sk) {
231
- const model = requireModel();
232
- const { data } = await model.get({ pk, sk });
233
- return data ? decodeValue(data.value) : null;
234
- },
235
- async query(pk) {
236
- const model = requireModel();
237
- const { data } = await model.list({
238
- filter: { pk: { eq: pk } },
239
- limit: 1e3
240
- });
241
- return (data ?? []).map((row) => ({
242
- pk: row.pk,
243
- sk: row.sk,
244
- value: decodeValue(row.value),
245
- ttl: row.ttl ?? void 0
246
- }));
247
- },
248
- async put(pk, sk, value, opts) {
249
- const model = requireModel();
250
- const ttl = opts?.ttlSeconds ? Math.floor(Date.now() / 1e3) + opts.ttlSeconds : void 0;
251
- const existing = await model.get({ pk, sk });
252
- if (existing.data) {
253
- const { errors } = await model.update({
254
- pk,
255
- sk,
256
- value: encodeValue(value),
257
- ttl: ttl ?? null
258
- });
259
- if (errors) throw new Error(errors[0]?.message ?? "KvStore.update failed");
260
- } else {
261
- const { errors } = await model.create({
262
- pk,
263
- sk,
264
- value: encodeValue(value),
265
- ttl
266
- });
267
- if (errors) throw new Error(errors[0]?.message ?? "KvStore.create failed");
268
- }
269
- },
270
- async remove(pk, sk) {
271
- const model = requireModel();
272
- const { errors } = await model.delete({ pk, sk });
273
- if (errors) throw new Error(errors[0]?.message ?? "KvStore.delete failed");
274
- }
275
- };
276
- setKvStore(store);
277
- }
278
-
279
- // src/pages/admin-providers.tsx
280
- import { Fragment, jsx } from "react/jsx-runtime";
281
- function AdminProviders({ outputs, cmsConfig, children }) {
282
- configureAmplify(outputs);
283
- setAdminCmsConfig(cmsConfig);
284
- setAdminCmsConfigClient(cmsConfig);
285
- setAdminMediaContext(outputs, cmsConfig);
286
- useEffect(() => {
287
- installAdminPostsProvider();
288
- installAdminKvProvider();
289
- }, []);
290
- return /* @__PURE__ */ jsx(Fragment, { children });
291
- }
292
-
293
- // src/pages/admin-layout.tsx
294
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
20
+ import { jsx, jsxs } from "react/jsx-runtime";
295
21
  function createAdminLayout(admin) {
296
22
  async function AdminLayout({ children }) {
297
23
  const session = await admin.getServerSession();
@@ -300,216 +26,80 @@ function createAdminLayout(admin) {
300
26
  }
301
27
  const sites = admin.adminSiteOptions();
302
28
  const currentSiteId = await admin.currentAdminSiteId();
303
- const selector = sites.length > 0 ? /* @__PURE__ */ jsx2(SiteSelector, { current: currentSiteId, sites }) : null;
304
- return /* @__PURE__ */ jsx2(AdminProviders, { outputs: admin.outputs, cmsConfig: admin.cmsConfig, children: /* @__PURE__ */ jsx2(I18nProvider, { locale: admin.locale, dict: admin.dict, children: /* @__PURE__ */ jsxs("div", { className: "flex min-h-screen", children: [
305
- /* @__PURE__ */ jsx2(Sidebar, { email: session.email, siteSelector: selector }),
306
- /* @__PURE__ */ jsx2("main", { className: "flex-1 overflow-auto", children })
29
+ const selector = sites.length > 0 ? /* @__PURE__ */ jsx(SiteSelector, { current: currentSiteId, sites }) : null;
30
+ return /* @__PURE__ */ jsx(AdminProviders, { outputs: admin.outputs, cmsConfig: admin.cmsConfig, children: /* @__PURE__ */ jsx(I18nProvider, { locale: admin.locale, dict: admin.dict, children: /* @__PURE__ */ jsxs("div", { className: "flex min-h-screen", children: [
31
+ /* @__PURE__ */ jsx(Sidebar, { email: session.email, siteSelector: selector }),
32
+ /* @__PURE__ */ jsx("main", { className: "flex-1 overflow-auto", children })
307
33
  ] }) }) });
308
34
  }
309
35
  return AdminLayout;
310
36
  }
311
37
 
312
38
  // src/pages/dashboard.tsx
313
- import { useEffect as useEffect2, useState } from "react";
314
- import Link from "next/link";
315
- import { listPosts } from "ampless";
316
- import { Button, Card, CardContent, CardHeader, CardTitle } from "@ampless/runtime/ui";
317
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
318
- function AdminDashboard() {
319
- const t = useT();
320
- const [posts, setPosts] = useState([]);
321
- const [loading, setLoading] = useState(true);
322
- useEffect2(() => {
323
- listPosts({ status: "all" }).then(setPosts).finally(() => setLoading(false));
324
- }, []);
325
- const published = posts.filter((p) => p.status === "published").length;
326
- const drafts = posts.filter((p) => p.status === "draft").length;
327
- return /* @__PURE__ */ jsxs2("div", { className: "p-8", children: [
328
- /* @__PURE__ */ jsxs2("div", { className: "mb-8 flex items-center justify-between", children: [
329
- /* @__PURE__ */ jsx3("h1", { className: "text-3xl font-bold", children: t("dashboard.title") }),
330
- /* @__PURE__ */ jsx3(Button, { asChild: true, children: /* @__PURE__ */ jsx3(Link, { href: "/admin/posts/new", children: t("dashboard.newPost") }) })
331
- ] }),
332
- /* @__PURE__ */ jsxs2("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-3", children: [
333
- /* @__PURE__ */ jsxs2(Card, { children: [
334
- /* @__PURE__ */ jsx3(CardHeader, { children: /* @__PURE__ */ jsx3(CardTitle, { children: t("dashboard.totalPosts") }) }),
335
- /* @__PURE__ */ jsxs2(CardContent, { children: [
336
- /* @__PURE__ */ jsx3("p", { className: "text-3xl font-bold", children: loading ? "\u2014" : posts.length }),
337
- /* @__PURE__ */ jsx3("p", { className: "text-sm text-muted-foreground", children: t("dashboard.totalLabel") })
338
- ] })
339
- ] }),
340
- /* @__PURE__ */ jsxs2(Card, { children: [
341
- /* @__PURE__ */ jsx3(CardHeader, { children: /* @__PURE__ */ jsx3(CardTitle, { children: t("dashboard.published") }) }),
342
- /* @__PURE__ */ jsx3(CardContent, { children: /* @__PURE__ */ jsx3("p", { className: "text-3xl font-bold", children: loading ? "\u2014" : published }) })
343
- ] }),
344
- /* @__PURE__ */ jsxs2(Card, { children: [
345
- /* @__PURE__ */ jsx3(CardHeader, { children: /* @__PURE__ */ jsx3(CardTitle, { children: t("dashboard.drafts") }) }),
346
- /* @__PURE__ */ jsx3(CardContent, { children: /* @__PURE__ */ jsx3("p", { className: "text-3xl font-bold", children: loading ? "\u2014" : drafts }) })
347
- ] })
348
- ] })
349
- ] });
350
- }
351
39
  function createAdminDashboardPage(_admin) {
352
40
  return AdminDashboard;
353
41
  }
354
42
 
355
43
  // src/pages/posts-list.tsx
356
- import { useEffect as useEffect3, useState as useState2 } from "react";
357
- import Link2 from "next/link";
358
- import { listPosts as listPosts2 } from "ampless";
359
- import {
360
- Button as Button2,
361
- Table,
362
- TableBody,
363
- TableCell,
364
- TableHead,
365
- TableHeader,
366
- TableRow
367
- } from "@ampless/runtime/ui";
368
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
369
- function PostsList() {
370
- const t = useT();
371
- const [posts, setPosts] = useState2([]);
372
- const [loading, setLoading] = useState2(true);
373
- useEffect3(() => {
374
- const siteId = readAdminSiteIdFromCookie();
375
- listPosts2({ status: "all", siteId }).then(setPosts).finally(() => setLoading(false));
376
- }, []);
377
- return /* @__PURE__ */ jsxs3("div", { className: "p-8", children: [
378
- /* @__PURE__ */ jsxs3("div", { className: "mb-8 flex items-center justify-between", children: [
379
- /* @__PURE__ */ jsx4("h1", { className: "text-3xl font-bold", children: t("posts.list.title") }),
380
- /* @__PURE__ */ jsx4(Button2, { asChild: true, children: /* @__PURE__ */ jsx4(Link2, { href: "/admin/posts/new", children: t("posts.list.newButton") }) })
381
- ] }),
382
- loading ? /* @__PURE__ */ jsx4("p", { className: "text-muted-foreground", children: t("common.loading") }) : posts.length === 0 ? /* @__PURE__ */ jsxs3("div", { className: "rounded-md border p-12 text-center", children: [
383
- /* @__PURE__ */ jsx4("p", { className: "text-muted-foreground", children: t("posts.list.empty") }),
384
- /* @__PURE__ */ jsx4(Button2, { asChild: true, className: "mt-4", children: /* @__PURE__ */ jsx4(Link2, { href: "/admin/posts/new", children: t("posts.list.createFirst") }) })
385
- ] }) : /* @__PURE__ */ jsx4("div", { className: "rounded-md border", children: /* @__PURE__ */ jsxs3(Table, { children: [
386
- /* @__PURE__ */ jsx4(TableHeader, { children: /* @__PURE__ */ jsxs3(TableRow, { children: [
387
- /* @__PURE__ */ jsx4(TableHead, { children: t("posts.list.columnTitle") }),
388
- /* @__PURE__ */ jsx4(TableHead, { children: t("posts.list.columnStatus") }),
389
- /* @__PURE__ */ jsx4(TableHead, { children: t("posts.list.columnSlug") }),
390
- /* @__PURE__ */ jsx4(TableHead, { children: t("posts.list.columnUpdated") })
391
- ] }) }),
392
- /* @__PURE__ */ jsx4(TableBody, { children: posts.map((post) => /* @__PURE__ */ jsxs3(TableRow, { children: [
393
- /* @__PURE__ */ jsx4(TableCell, { children: /* @__PURE__ */ jsx4(
394
- Link2,
395
- {
396
- href: `/admin/posts/${post.postId}`,
397
- className: "font-medium hover:underline",
398
- children: post.title
399
- }
400
- ) }),
401
- /* @__PURE__ */ jsx4(TableCell, { children: /* @__PURE__ */ jsx4(
402
- "span",
403
- {
404
- className: post.status === "published" ? "inline-block rounded-full bg-green-100 px-2 py-0.5 text-xs text-green-700" : "inline-block rounded-full bg-gray-100 px-2 py-0.5 text-xs text-gray-700",
405
- children: t(`common.${post.status}`)
406
- }
407
- ) }),
408
- /* @__PURE__ */ jsx4(TableCell, { className: "font-mono text-xs text-muted-foreground", children: post.slug }),
409
- /* @__PURE__ */ jsx4(TableCell, { className: "text-sm text-muted-foreground", children: post.publishedAt ? new Date(post.publishedAt).toLocaleDateString() : "\u2014" })
410
- ] }, post.postId)) })
411
- ] }) })
412
- ] });
413
- }
414
44
  function createPostsListPage(_admin) {
415
45
  return PostsList;
416
46
  }
417
47
 
418
48
  // src/pages/post-new.tsx
419
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
420
- function NewPostPage() {
421
- const t = useT();
422
- return /* @__PURE__ */ jsxs4("div", { className: "p-8", children: [
423
- /* @__PURE__ */ jsx5("h1", { className: "mb-8 text-3xl font-bold", children: t("posts.form.newTitle") }),
424
- /* @__PURE__ */ jsx5(PostForm, {})
425
- ] });
426
- }
427
49
  function createNewPostPage(_admin) {
428
50
  return NewPostPage;
429
51
  }
430
52
 
431
53
  // src/pages/post-edit.tsx
432
- import { useEffect as useEffect4, useState as useState3, use } from "react";
433
- import { notFound } from "next/navigation";
434
- import { getPostById } from "ampless";
435
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
436
- function EditPostPage({ params }) {
437
- const t = useT();
438
- const { postId } = use(params);
439
- const [post, setPost] = useState3(null);
440
- const [loading, setLoading] = useState3(true);
441
- const [missing, setMissing] = useState3(false);
442
- useEffect4(() => {
443
- const siteId = readAdminSiteIdFromCookie();
444
- getPostById(postId, { siteId }).then((p) => {
445
- if (!p) setMissing(true);
446
- else setPost(p);
447
- }).finally(() => setLoading(false));
448
- }, [postId]);
449
- if (loading) return /* @__PURE__ */ jsx6("div", { className: "p-8", children: t("common.loading") });
450
- if (missing) notFound();
451
- return /* @__PURE__ */ jsxs5("div", { className: "p-8", children: [
452
- /* @__PURE__ */ jsx6("h1", { className: "mb-8 text-3xl font-bold", children: t("posts.form.editTitle") }),
453
- post && /* @__PURE__ */ jsx6(PostForm, { post })
454
- ] });
455
- }
456
54
  function createEditPostPage(_admin) {
457
55
  return EditPostPage;
458
56
  }
459
57
 
460
58
  // src/pages/media.tsx
461
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
462
- function MediaPage() {
463
- const t = useT();
464
- return /* @__PURE__ */ jsxs6("div", { className: "p-8", children: [
465
- /* @__PURE__ */ jsx7("h1", { className: "mb-8 text-3xl font-bold", children: t("media.title") }),
466
- /* @__PURE__ */ jsx7(MediaUploader, {})
467
- ] });
468
- }
469
59
  function createMediaPage(_admin) {
470
60
  return MediaPage;
471
61
  }
472
62
 
473
63
  // src/pages/sites-list.tsx
474
- import Link3 from "next/link";
64
+ import Link from "next/link";
475
65
  import { DEFAULT_SITE_ID, isMultiSite, siteFor } from "ampless";
476
66
  import {
477
- Button as Button3,
478
- Table as Table2,
479
- TableBody as TableBody2,
480
- TableCell as TableCell2,
481
- TableHead as TableHead2,
482
- TableHeader as TableHeader2,
483
- TableRow as TableRow2
67
+ Button,
68
+ Table,
69
+ TableBody,
70
+ TableCell,
71
+ TableHead,
72
+ TableHeader,
73
+ TableRow
484
74
  } from "@ampless/runtime/ui";
485
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
75
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
486
76
  function createSitesListPage(admin) {
487
77
  const { cmsConfig, t } = admin;
488
78
  async function SitesPage() {
489
79
  const multi = isMultiSite(cmsConfig);
490
80
  const ids = multi ? Object.keys(cmsConfig.sites ?? {}) : [DEFAULT_SITE_ID];
491
- return /* @__PURE__ */ jsxs7("div", { className: "p-8", children: [
492
- /* @__PURE__ */ jsx8("div", { className: "mb-8 flex items-center justify-between", children: /* @__PURE__ */ jsxs7("div", { children: [
493
- /* @__PURE__ */ jsx8("h1", { className: "text-3xl font-bold", children: t("sites.list.title") }),
494
- /* @__PURE__ */ jsx8("p", { className: "mt-1 text-sm text-muted-foreground", children: t("sites.list.description") })
81
+ return /* @__PURE__ */ jsxs2("div", { className: "p-8", children: [
82
+ /* @__PURE__ */ jsx2("div", { className: "mb-8 flex items-center justify-between", children: /* @__PURE__ */ jsxs2("div", { children: [
83
+ /* @__PURE__ */ jsx2("h1", { className: "text-3xl font-bold", children: t("sites.list.title") }),
84
+ /* @__PURE__ */ jsx2("p", { className: "mt-1 text-sm text-muted-foreground", children: t("sites.list.description") })
495
85
  ] }) }),
496
- /* @__PURE__ */ jsx8("div", { className: "rounded-md border", children: /* @__PURE__ */ jsxs7(Table2, { children: [
497
- /* @__PURE__ */ jsx8(TableHeader2, { children: /* @__PURE__ */ jsxs7(TableRow2, { children: [
498
- /* @__PURE__ */ jsx8(TableHead2, { children: t("sites.list.columnSiteId") }),
499
- /* @__PURE__ */ jsx8(TableHead2, { children: t("sites.list.columnName") }),
500
- /* @__PURE__ */ jsx8(TableHead2, { children: t("sites.list.columnUrl") }),
501
- /* @__PURE__ */ jsx8(TableHead2, { children: t("sites.list.columnDomains") }),
502
- /* @__PURE__ */ jsx8(TableHead2, {})
86
+ /* @__PURE__ */ jsx2("div", { className: "rounded-md border", children: /* @__PURE__ */ jsxs2(Table, { children: [
87
+ /* @__PURE__ */ jsx2(TableHeader, { children: /* @__PURE__ */ jsxs2(TableRow, { children: [
88
+ /* @__PURE__ */ jsx2(TableHead, { children: t("sites.list.columnSiteId") }),
89
+ /* @__PURE__ */ jsx2(TableHead, { children: t("sites.list.columnName") }),
90
+ /* @__PURE__ */ jsx2(TableHead, { children: t("sites.list.columnUrl") }),
91
+ /* @__PURE__ */ jsx2(TableHead, { children: t("sites.list.columnDomains") }),
92
+ /* @__PURE__ */ jsx2(TableHead, {})
503
93
  ] }) }),
504
- /* @__PURE__ */ jsx8(TableBody2, { children: ids.map((id) => {
94
+ /* @__PURE__ */ jsx2(TableBody, { children: ids.map((id) => {
505
95
  const site = siteFor(id, cmsConfig);
506
96
  const domains = cmsConfig.sites?.[id]?.domains ?? [];
507
- return /* @__PURE__ */ jsxs7(TableRow2, { children: [
508
- /* @__PURE__ */ jsx8(TableCell2, { className: "font-mono text-xs", children: id }),
509
- /* @__PURE__ */ jsx8(TableCell2, { className: "font-medium", children: site.name }),
510
- /* @__PURE__ */ jsx8(TableCell2, { className: "text-sm text-muted-foreground", children: site.url }),
511
- /* @__PURE__ */ jsx8(TableCell2, { className: "text-sm text-muted-foreground", children: domains.length > 0 ? domains.join(", ") : "\u2014" }),
512
- /* @__PURE__ */ jsx8(TableCell2, { children: /* @__PURE__ */ jsx8(Button3, { asChild: true, variant: "outline", size: "sm", children: /* @__PURE__ */ jsx8(Link3, { href: `/admin/sites/${id}`, children: t("sites.list.edit") }) }) })
97
+ return /* @__PURE__ */ jsxs2(TableRow, { children: [
98
+ /* @__PURE__ */ jsx2(TableCell, { className: "font-mono text-xs", children: id }),
99
+ /* @__PURE__ */ jsx2(TableCell, { className: "font-medium", children: site.name }),
100
+ /* @__PURE__ */ jsx2(TableCell, { className: "text-sm text-muted-foreground", children: site.url }),
101
+ /* @__PURE__ */ jsx2(TableCell, { className: "text-sm text-muted-foreground", children: domains.length > 0 ? domains.join(", ") : "\u2014" }),
102
+ /* @__PURE__ */ jsx2(TableCell, { children: /* @__PURE__ */ jsx2(Button, { asChild: true, variant: "outline", size: "sm", children: /* @__PURE__ */ jsx2(Link, { href: `/admin/sites/${id}`, children: t("sites.list.edit") }) }) })
513
103
  ] }, id);
514
104
  }) })
515
105
  ] }) })
@@ -519,9 +109,9 @@ function createSitesListPage(admin) {
519
109
  }
520
110
 
521
111
  // src/pages/site-edit.tsx
522
- import Link4 from "next/link";
112
+ import Link2 from "next/link";
523
113
  import { siteFor as siteFor2 } from "ampless";
524
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
114
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
525
115
  function createSiteEditPage(admin) {
526
116
  const { cmsConfig, t, loadSiteSettings } = admin;
527
117
  async function EditSitePage({ params }) {
@@ -546,10 +136,10 @@ function createSiteEditPage(admin) {
546
136
  dateFormat: settings.dateFormat,
547
137
  timezone: settings.timezone
548
138
  };
549
- return /* @__PURE__ */ jsxs8("div", { className: "p-8", children: [
550
- /* @__PURE__ */ jsxs8("div", { className: "mb-8", children: [
551
- /* @__PURE__ */ jsxs8(
552
- Link4,
139
+ return /* @__PURE__ */ jsxs3("div", { className: "p-8", children: [
140
+ /* @__PURE__ */ jsxs3("div", { className: "mb-8", children: [
141
+ /* @__PURE__ */ jsxs3(
142
+ Link2,
553
143
  {
554
144
  href: "/admin/sites",
555
145
  className: "text-sm text-muted-foreground hover:underline",
@@ -559,14 +149,14 @@ function createSiteEditPage(admin) {
559
149
  ]
560
150
  }
561
151
  ),
562
- /* @__PURE__ */ jsx9("h1", { className: "mt-2 text-3xl font-bold", children: settings.site.name }),
563
- /* @__PURE__ */ jsxs8("p", { className: "text-sm text-muted-foreground", children: [
152
+ /* @__PURE__ */ jsx3("h1", { className: "mt-2 text-3xl font-bold", children: settings.site.name }),
153
+ /* @__PURE__ */ jsxs3("p", { className: "text-sm text-muted-foreground", children: [
564
154
  t("common.siteId"),
565
155
  ": ",
566
- /* @__PURE__ */ jsx9("code", { className: "font-mono", children: siteId })
156
+ /* @__PURE__ */ jsx3("code", { className: "font-mono", children: siteId })
567
157
  ] }),
568
- /* @__PURE__ */ jsx9("div", { className: "mt-4", children: /* @__PURE__ */ jsx9(
569
- Link4,
158
+ /* @__PURE__ */ jsx3("div", { className: "mt-4", children: /* @__PURE__ */ jsx3(
159
+ Link2,
570
160
  {
571
161
  href: `/admin/sites/${siteId}/theme`,
572
162
  className: "text-sm font-medium underline",
@@ -574,16 +164,16 @@ function createSiteEditPage(admin) {
574
164
  }
575
165
  ) })
576
166
  ] }),
577
- /* @__PURE__ */ jsx9(SiteSettingsForm, { siteId, initial, fallback })
167
+ /* @__PURE__ */ jsx3(SiteSettingsForm, { siteId, initial, fallback })
578
168
  ] });
579
169
  }
580
170
  return EditSitePage;
581
171
  }
582
172
 
583
173
  // src/pages/site-theme.tsx
584
- import Link5 from "next/link";
174
+ import Link3 from "next/link";
585
175
  import { siteFor as siteFor3, resolveLocalized } from "ampless";
586
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
176
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
587
177
  function createSiteThemePage(admin, themeList) {
588
178
  const { cmsConfig, t, locale, loadThemeConfig } = admin;
589
179
  async function ThemePage({ params }) {
@@ -595,10 +185,10 @@ function createSiteThemePage(admin, themeList) {
595
185
  label: m.manifest.label,
596
186
  description: m.manifest.description
597
187
  }));
598
- return /* @__PURE__ */ jsxs9("div", { className: "p-8", children: [
599
- /* @__PURE__ */ jsxs9("div", { className: "mb-8", children: [
600
- /* @__PURE__ */ jsxs9(
601
- Link5,
188
+ return /* @__PURE__ */ jsxs4("div", { className: "p-8", children: [
189
+ /* @__PURE__ */ jsxs4("div", { className: "mb-8", children: [
190
+ /* @__PURE__ */ jsxs4(
191
+ Link3,
602
192
  {
603
193
  href: `/admin/sites/${siteId}`,
604
194
  className: "text-sm text-muted-foreground hover:underline",
@@ -608,18 +198,18 @@ function createSiteThemePage(admin, themeList) {
608
198
  ]
609
199
  }
610
200
  ),
611
- /* @__PURE__ */ jsx10("h1", { className: "mt-2 text-3xl font-bold", children: t("theme.title") }),
612
- /* @__PURE__ */ jsxs9("p", { className: "text-sm text-muted-foreground", children: [
201
+ /* @__PURE__ */ jsx4("h1", { className: "mt-2 text-3xl font-bold", children: t("theme.title") }),
202
+ /* @__PURE__ */ jsxs4("p", { className: "text-sm text-muted-foreground", children: [
613
203
  t("common.active"),
614
204
  ":",
615
205
  " ",
616
- /* @__PURE__ */ jsx10("strong", { children: resolveLocalized(theme.manifest.label, locale) }),
206
+ /* @__PURE__ */ jsx4("strong", { children: resolveLocalized(theme.manifest.label, locale) }),
617
207
  " (",
618
208
  theme.activeTheme,
619
209
  ")"
620
210
  ] })
621
211
  ] }),
622
- /* @__PURE__ */ jsx10(
212
+ /* @__PURE__ */ jsx4(
623
213
  ThemeSettingsForm,
624
214
  {
625
215
  siteId,
@@ -635,194 +225,6 @@ function createSiteThemePage(admin, themeList) {
635
225
  }
636
226
 
637
227
  // src/pages/login.tsx
638
- import { useState as useState4 } from "react";
639
- import { useRouter } from "next/navigation";
640
- import {
641
- signIn,
642
- signUp,
643
- confirmSignUp,
644
- resetPassword,
645
- confirmResetPassword
646
- } from "aws-amplify/auth";
647
- import {
648
- Button as Button4,
649
- Input,
650
- Label,
651
- Card as Card2,
652
- CardContent as CardContent2,
653
- CardHeader as CardHeader2,
654
- CardTitle as CardTitle2,
655
- CardDescription
656
- } from "@ampless/runtime/ui";
657
- import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
658
- function LoginPage() {
659
- const router = useRouter();
660
- const t = useT();
661
- const [mode, setMode] = useState4("signIn");
662
- const [email, setEmail] = useState4("");
663
- const [password, setPassword] = useState4("");
664
- const [code, setCode] = useState4("");
665
- const [error, setError] = useState4(null);
666
- const [info, setInfo] = useState4(null);
667
- const [loading, setLoading] = useState4(false);
668
- function go(next) {
669
- setMode(next);
670
- setError(null);
671
- setInfo(null);
672
- setCode("");
673
- if (next === "signIn" || next === "signUp" || next === "forgot") setPassword("");
674
- }
675
- async function handleSubmit(e) {
676
- e.preventDefault();
677
- setError(null);
678
- setInfo(null);
679
- setLoading(true);
680
- try {
681
- if (mode === "signIn") {
682
- const result = await signIn({ username: email, password });
683
- if (result.isSignedIn) {
684
- router.push("/admin");
685
- router.refresh();
686
- } else {
687
- setError(t("auth.additionalStep", { step: result.nextStep.signInStep }));
688
- }
689
- } else if (mode === "signUp") {
690
- await signUp({
691
- username: email,
692
- password,
693
- options: { userAttributes: { email } }
694
- });
695
- go("confirm");
696
- } else if (mode === "confirm") {
697
- await confirmSignUp({ username: email, confirmationCode: code });
698
- const result = await signIn({ username: email, password });
699
- if (result.isSignedIn) {
700
- router.push("/admin");
701
- router.refresh();
702
- }
703
- } else if (mode === "forgot") {
704
- await resetPassword({ username: email });
705
- setMode("reset");
706
- setInfo(t("auth.forgot.codeSent"));
707
- } else if (mode === "reset") {
708
- await confirmResetPassword({
709
- username: email,
710
- confirmationCode: code,
711
- newPassword: password
712
- });
713
- const result = await signIn({ username: email, password });
714
- if (result.isSignedIn) {
715
- router.push("/admin");
716
- router.refresh();
717
- } else {
718
- setMode("signIn");
719
- setInfo(t("auth.reset.passwordUpdated"));
720
- }
721
- }
722
- } catch (err) {
723
- setError(err instanceof Error ? err.message : String(err));
724
- } finally {
725
- setLoading(false);
726
- }
727
- }
728
- const showEmail = mode !== "confirm" && mode !== "reset";
729
- const showPassword = mode === "signIn" || mode === "signUp" || mode === "reset";
730
- const showCode = mode === "confirm" || mode === "reset";
731
- return /* @__PURE__ */ jsx11("main", { className: "flex min-h-screen items-center justify-center bg-muted/30 p-4", children: /* @__PURE__ */ jsxs10(Card2, { className: "w-full max-w-md", children: [
732
- /* @__PURE__ */ jsxs10(CardHeader2, { children: [
733
- /* @__PURE__ */ jsx11(CardTitle2, { children: t(`auth.${mode}.title`) }),
734
- /* @__PURE__ */ jsx11(CardDescription, { children: t(`auth.${mode}.description`) })
735
- ] }),
736
- /* @__PURE__ */ jsx11(CardContent2, { children: /* @__PURE__ */ jsxs10("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
737
- showEmail && /* @__PURE__ */ jsxs10("div", { className: "space-y-2", children: [
738
- /* @__PURE__ */ jsx11(Label, { htmlFor: "email", children: t("auth.common.email") }),
739
- /* @__PURE__ */ jsx11(
740
- Input,
741
- {
742
- id: "email",
743
- type: "email",
744
- required: true,
745
- value: email,
746
- onChange: (e) => setEmail(e.target.value),
747
- autoComplete: "email"
748
- }
749
- )
750
- ] }),
751
- showCode && /* @__PURE__ */ jsxs10("div", { className: "space-y-2", children: [
752
- /* @__PURE__ */ jsx11(Label, { htmlFor: "code", children: t("auth.common.code") }),
753
- /* @__PURE__ */ jsx11(
754
- Input,
755
- {
756
- id: "code",
757
- required: true,
758
- value: code,
759
- onChange: (e) => setCode(e.target.value),
760
- autoComplete: "one-time-code"
761
- }
762
- )
763
- ] }),
764
- showPassword && /* @__PURE__ */ jsxs10("div", { className: "space-y-2", children: [
765
- /* @__PURE__ */ jsx11(Label, { htmlFor: "password", children: mode === "reset" ? t("auth.common.newPassword") : t("auth.common.password") }),
766
- /* @__PURE__ */ jsx11(
767
- Input,
768
- {
769
- id: "password",
770
- type: "password",
771
- required: true,
772
- minLength: 8,
773
- value: password,
774
- onChange: (e) => setPassword(e.target.value),
775
- autoComplete: mode === "signIn" ? "current-password" : "new-password"
776
- }
777
- ),
778
- (mode === "signUp" || mode === "reset") && /* @__PURE__ */ jsx11("p", { className: "text-xs text-muted-foreground", children: t("auth.common.passwordHint") })
779
- ] }),
780
- info && /* @__PURE__ */ jsx11("p", { className: "text-sm text-muted-foreground", children: info }),
781
- error && /* @__PURE__ */ jsx11("p", { className: "text-sm text-destructive", children: error }),
782
- /* @__PURE__ */ jsx11(Button4, { type: "submit", className: "w-full", disabled: loading, children: loading ? t("auth.common.working") : t(`auth.${mode}.submit`) }),
783
- /* @__PURE__ */ jsxs10("div", { className: "space-y-1 text-center text-sm", children: [
784
- mode === "signIn" && /* @__PURE__ */ jsxs10(Fragment2, { children: [
785
- /* @__PURE__ */ jsx11("p", { children: /* @__PURE__ */ jsx11(
786
- "button",
787
- {
788
- type: "button",
789
- className: "text-primary hover:underline",
790
- onClick: () => go("forgot"),
791
- children: t("auth.signIn.forgotPassword")
792
- }
793
- ) }),
794
- /* @__PURE__ */ jsx11("p", { children: /* @__PURE__ */ jsx11(
795
- "button",
796
- {
797
- type: "button",
798
- className: "text-primary hover:underline",
799
- onClick: () => go("signUp"),
800
- children: t("auth.signIn.createAccount")
801
- }
802
- ) })
803
- ] }),
804
- (mode === "signUp" || mode === "forgot" || mode === "reset") && /* @__PURE__ */ jsx11("p", { children: /* @__PURE__ */ jsx11(
805
- "button",
806
- {
807
- type: "button",
808
- className: "text-primary hover:underline",
809
- onClick: () => go("signIn"),
810
- children: t("auth.signUp.backToSignIn")
811
- }
812
- ) }),
813
- mode === "reset" && /* @__PURE__ */ jsx11("p", { children: /* @__PURE__ */ jsx11(
814
- "button",
815
- {
816
- type: "button",
817
- className: "text-primary hover:underline",
818
- onClick: () => go("forgot"),
819
- children: t("auth.reset.resendCode")
820
- }
821
- ) })
822
- ] })
823
- ] }) })
824
- ] }) });
825
- }
826
228
  function createLoginPage(_admin) {
827
229
  return LoginPage;
828
230
  }