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