@cmssy/cli 10.7.0 → 10.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/init/astro/src/cmssy/layout-slot.tsx +75 -0
- package/assets/init/astro/src/pages/[...path].astro +16 -1
- package/assets/init/astro/src/pages/cmssy-edit/[...path].astro +20 -1
- package/assets/init/remix/app/cmssy/layout-slot.tsx +72 -0
- package/assets/init/remix/app/routes/page.tsx +47 -22
- package/dist/index.js +2 -0
- package/package.json +2 -2
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CmssyBlock,
|
|
3
|
+
buildBlockContext,
|
|
4
|
+
buildBlockMap,
|
|
5
|
+
type CmssyLayoutGroup,
|
|
6
|
+
} from "@cmssy/react";
|
|
7
|
+
import { CmssyLazyLayout } from "@cmssy/react/client";
|
|
8
|
+
import { blocks } from "./blocks";
|
|
9
|
+
|
|
10
|
+
export interface LayoutSlotProps {
|
|
11
|
+
groups: CmssyLayoutGroup[];
|
|
12
|
+
position: "header" | "footer";
|
|
13
|
+
locale: string;
|
|
14
|
+
defaultLocale: string;
|
|
15
|
+
enabledLocales: string[];
|
|
16
|
+
/** Set on a VERIFIED editor request; the loader reports it as `isEdit`. */
|
|
17
|
+
edit?: { editorOrigin: string | string[] };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The header and footer, which are layout blocks rather than markup you own.
|
|
22
|
+
*
|
|
23
|
+
* A React island: Astro renders it on the server for visitors (no client JS),
|
|
24
|
+
* and with `client:load` on the edit route, where the bridge needs the browser.
|
|
25
|
+
*
|
|
26
|
+
* Two renders, one per mode, and the difference is the point: server-rendered
|
|
27
|
+
* for visitors, and through the edit bridge for the editor. A header still
|
|
28
|
+
* server-rendered in edit mode is one the editor can select and cannot fill.
|
|
29
|
+
*/
|
|
30
|
+
export default function LayoutSlot({
|
|
31
|
+
groups,
|
|
32
|
+
position,
|
|
33
|
+
locale,
|
|
34
|
+
defaultLocale,
|
|
35
|
+
enabledLocales,
|
|
36
|
+
edit,
|
|
37
|
+
}: LayoutSlotProps) {
|
|
38
|
+
if (edit) {
|
|
39
|
+
return (
|
|
40
|
+
<CmssyLazyLayout
|
|
41
|
+
groups={groups}
|
|
42
|
+
position={position}
|
|
43
|
+
locale={locale}
|
|
44
|
+
defaultLocale={defaultLocale}
|
|
45
|
+
enabledLocales={enabledLocales}
|
|
46
|
+
edit={edit}
|
|
47
|
+
load={() => import("./blocks")}
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const group = groups.find((candidate) => candidate.position === position);
|
|
53
|
+
if (!group) return null;
|
|
54
|
+
|
|
55
|
+
const blockMap = buildBlockMap(blocks);
|
|
56
|
+
const context = buildBlockContext(locale, defaultLocale, enabledLocales);
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<>
|
|
60
|
+
{[...group.blocks]
|
|
61
|
+
.filter((block) => block.isActive !== false)
|
|
62
|
+
.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
|
|
63
|
+
.map((block) => (
|
|
64
|
+
<CmssyBlock
|
|
65
|
+
key={block.id}
|
|
66
|
+
block={block}
|
|
67
|
+
blockMap={blockMap}
|
|
68
|
+
locale={locale}
|
|
69
|
+
defaultLocale={defaultLocale}
|
|
70
|
+
context={context}
|
|
71
|
+
/>
|
|
72
|
+
))}
|
|
73
|
+
</>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
import { loadCmssyPage } from "@cmssy/astro";
|
|
3
3
|
import { cmssy } from "../cmssy.config";
|
|
4
4
|
import { Blocks } from "../components/Blocks";
|
|
5
|
+
import LayoutSlot from "../cmssy/layout-slot";
|
|
5
6
|
|
|
6
7
|
export const prerender = false;
|
|
7
8
|
|
|
8
|
-
const { page, locale, defaultLocale, enabledLocales } = await loadCmssyPage(
|
|
9
|
+
const { page, layouts, locale, defaultLocale, enabledLocales } = await loadCmssyPage(
|
|
9
10
|
cmssy,
|
|
10
11
|
Astro.request,
|
|
11
12
|
Astro.url,
|
|
@@ -22,6 +23,13 @@ if (!page) {
|
|
|
22
23
|
<title>{page?.seoTitle?.[locale] ?? page?.displayName?.[locale] ?? "cmssy on Astro"}</title>
|
|
23
24
|
</head>
|
|
24
25
|
<body>
|
|
26
|
+
<LayoutSlot
|
|
27
|
+
groups={layouts}
|
|
28
|
+
position="header"
|
|
29
|
+
locale={locale}
|
|
30
|
+
defaultLocale={defaultLocale}
|
|
31
|
+
enabledLocales={enabledLocales}
|
|
32
|
+
/>
|
|
25
33
|
{
|
|
26
34
|
page ? (
|
|
27
35
|
<Blocks
|
|
@@ -34,5 +42,12 @@ if (!page) {
|
|
|
34
42
|
<main><h1>Not found</h1></main>
|
|
35
43
|
)
|
|
36
44
|
}
|
|
45
|
+
<LayoutSlot
|
|
46
|
+
groups={layouts}
|
|
47
|
+
position="footer"
|
|
48
|
+
locale={locale}
|
|
49
|
+
defaultLocale={defaultLocale}
|
|
50
|
+
enabledLocales={enabledLocales}
|
|
51
|
+
/>
|
|
37
52
|
</body>
|
|
38
53
|
</html>
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
import { loadCmssyPage } from "@cmssy/astro";
|
|
3
3
|
import { cmssy } from "../../cmssy.config";
|
|
4
4
|
import CmssyEditor from "../../cmssy/editor";
|
|
5
|
+
import LayoutSlot from "../../cmssy/layout-slot";
|
|
5
6
|
|
|
6
7
|
// The editor iframe lands here (the middleware rewrites verified requests). It
|
|
7
8
|
// must be dynamic: a prerendered page never sees the query string.
|
|
8
9
|
export const prerender = false;
|
|
9
10
|
|
|
10
|
-
const { page, locale, defaultLocale, enabledLocales } = await loadCmssyPage(
|
|
11
|
+
const { page, layouts, locale, defaultLocale, enabledLocales } = await loadCmssyPage(
|
|
11
12
|
cmssy,
|
|
12
13
|
Astro.request,
|
|
13
14
|
Astro.url,
|
|
@@ -21,6 +22,15 @@ const editorOrigin = cmssy.editorOrigin ?? "*";
|
|
|
21
22
|
<title>cmssy editor</title>
|
|
22
23
|
</head>
|
|
23
24
|
<body>
|
|
25
|
+
<LayoutSlot
|
|
26
|
+
client:load
|
|
27
|
+
groups={layouts}
|
|
28
|
+
position="header"
|
|
29
|
+
locale={locale}
|
|
30
|
+
defaultLocale={defaultLocale}
|
|
31
|
+
enabledLocales={enabledLocales}
|
|
32
|
+
edit={{ editorOrigin }}
|
|
33
|
+
/>
|
|
24
34
|
<CmssyEditor
|
|
25
35
|
client:load
|
|
26
36
|
page={page}
|
|
@@ -29,5 +39,14 @@ const editorOrigin = cmssy.editorOrigin ?? "*";
|
|
|
29
39
|
enabledLocales={enabledLocales}
|
|
30
40
|
edit={{ editorOrigin }}
|
|
31
41
|
/>
|
|
42
|
+
<LayoutSlot
|
|
43
|
+
client:load
|
|
44
|
+
groups={layouts}
|
|
45
|
+
position="footer"
|
|
46
|
+
locale={locale}
|
|
47
|
+
defaultLocale={defaultLocale}
|
|
48
|
+
enabledLocales={enabledLocales}
|
|
49
|
+
edit={{ editorOrigin }}
|
|
50
|
+
/>
|
|
32
51
|
</body>
|
|
33
52
|
</html>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CmssyBlock,
|
|
3
|
+
buildBlockContext,
|
|
4
|
+
buildBlockMap,
|
|
5
|
+
type CmssyLayoutGroup,
|
|
6
|
+
} from "@cmssy/react";
|
|
7
|
+
import { CmssyLazyLayout } from "@cmssy/react/client";
|
|
8
|
+
import { blocks } from "./blocks";
|
|
9
|
+
|
|
10
|
+
export interface LayoutSlotProps {
|
|
11
|
+
groups: CmssyLayoutGroup[];
|
|
12
|
+
position: "header" | "footer";
|
|
13
|
+
locale: string;
|
|
14
|
+
defaultLocale: string;
|
|
15
|
+
enabledLocales: string[];
|
|
16
|
+
/** Set on a VERIFIED editor request; the loader reports it as `isEdit`. */
|
|
17
|
+
edit?: { editorOrigin: string | string[] };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The header and footer, which are layout blocks rather than markup you own.
|
|
22
|
+
*
|
|
23
|
+
* Two renders, one per mode, and the difference is the point: server-rendered
|
|
24
|
+
* for visitors, and through the edit bridge for the editor. A header still
|
|
25
|
+
* server-rendered in edit mode is one the editor can select and cannot fill.
|
|
26
|
+
*/
|
|
27
|
+
export function LayoutSlot({
|
|
28
|
+
groups,
|
|
29
|
+
position,
|
|
30
|
+
locale,
|
|
31
|
+
defaultLocale,
|
|
32
|
+
enabledLocales,
|
|
33
|
+
edit,
|
|
34
|
+
}: LayoutSlotProps) {
|
|
35
|
+
if (edit) {
|
|
36
|
+
return (
|
|
37
|
+
<CmssyLazyLayout
|
|
38
|
+
groups={groups}
|
|
39
|
+
position={position}
|
|
40
|
+
locale={locale}
|
|
41
|
+
defaultLocale={defaultLocale}
|
|
42
|
+
enabledLocales={enabledLocales}
|
|
43
|
+
edit={edit}
|
|
44
|
+
load={() => import("./blocks")}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const group = groups.find((candidate) => candidate.position === position);
|
|
50
|
+
if (!group) return null;
|
|
51
|
+
|
|
52
|
+
const blockMap = buildBlockMap(blocks);
|
|
53
|
+
const context = buildBlockContext(locale, defaultLocale, enabledLocales);
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<>
|
|
57
|
+
{[...group.blocks]
|
|
58
|
+
.filter((block) => block.isActive !== false)
|
|
59
|
+
.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
|
|
60
|
+
.map((block) => (
|
|
61
|
+
<CmssyBlock
|
|
62
|
+
key={block.id}
|
|
63
|
+
block={block}
|
|
64
|
+
blockMap={blockMap}
|
|
65
|
+
locale={locale}
|
|
66
|
+
defaultLocale={defaultLocale}
|
|
67
|
+
context={context}
|
|
68
|
+
/>
|
|
69
|
+
))}
|
|
70
|
+
</>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
@@ -3,6 +3,7 @@ import { createCmssyHeaders, createCmssyLoader } from "@cmssy/remix";
|
|
|
3
3
|
import { cmssy } from "../../cmssy.config";
|
|
4
4
|
import { blocks } from "../cmssy/blocks";
|
|
5
5
|
import { CmssyEditor } from "../cmssy/editor";
|
|
6
|
+
import { LayoutSlot } from "../cmssy/layout-slot";
|
|
6
7
|
import type { Route } from "./+types/page";
|
|
7
8
|
|
|
8
9
|
export const loader = createCmssyLoader(cmssy);
|
|
@@ -14,6 +15,7 @@ export const headers = createCmssyHeaders(cmssy);
|
|
|
14
15
|
export default function CmssyPage({ loaderData }: Route.ComponentProps) {
|
|
15
16
|
const {
|
|
16
17
|
page,
|
|
18
|
+
layouts,
|
|
17
19
|
locale,
|
|
18
20
|
defaultLocale,
|
|
19
21
|
enabledLocales,
|
|
@@ -28,40 +30,63 @@ export default function CmssyPage({ loaderData }: Route.ComponentProps) {
|
|
|
28
30
|
|
|
29
31
|
// A verified editor request renders the same page through the edit bridge.
|
|
30
32
|
// No separate route: a React Router page always sees its query string.
|
|
33
|
+
const slot = (position: "header" | "footer") => (
|
|
34
|
+
<LayoutSlot
|
|
35
|
+
groups={layouts}
|
|
36
|
+
position={position}
|
|
37
|
+
locale={locale}
|
|
38
|
+
defaultLocale={defaultLocale}
|
|
39
|
+
enabledLocales={enabledLocales}
|
|
40
|
+
edit={isEdit ? { editorOrigin } : undefined}
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
|
|
31
44
|
if (isEdit) {
|
|
32
45
|
return (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
46
|
+
<>
|
|
47
|
+
{slot("header")}
|
|
48
|
+
<CmssyEditor
|
|
49
|
+
page={page}
|
|
50
|
+
locale={locale}
|
|
51
|
+
defaultLocale={defaultLocale}
|
|
52
|
+
enabledLocales={enabledLocales}
|
|
53
|
+
edit={{ editorOrigin }}
|
|
54
|
+
/>
|
|
55
|
+
{slot("footer")}
|
|
56
|
+
</>
|
|
40
57
|
);
|
|
41
58
|
}
|
|
42
59
|
|
|
43
60
|
if (!page)
|
|
44
61
|
return (
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
62
|
+
<>
|
|
63
|
+
{slot("header")}
|
|
64
|
+
<main>
|
|
65
|
+
<h1>Not found</h1>
|
|
66
|
+
</main>
|
|
67
|
+
{slot("footer")}
|
|
68
|
+
</>
|
|
48
69
|
);
|
|
49
70
|
|
|
50
71
|
const blockMap = buildBlockMap(blocks);
|
|
51
72
|
const context = buildBlockContext(locale, defaultLocale, enabledLocales);
|
|
52
73
|
|
|
53
74
|
return (
|
|
54
|
-
|
|
55
|
-
{(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
75
|
+
<>
|
|
76
|
+
{slot("header")}
|
|
77
|
+
<main>
|
|
78
|
+
{(page.blocks ?? []).map((block) => (
|
|
79
|
+
<CmssyBlock
|
|
80
|
+
key={block.id}
|
|
81
|
+
block={block}
|
|
82
|
+
blockMap={blockMap}
|
|
83
|
+
locale={locale}
|
|
84
|
+
defaultLocale={defaultLocale}
|
|
85
|
+
context={context}
|
|
86
|
+
/>
|
|
87
|
+
))}
|
|
88
|
+
</main>
|
|
89
|
+
{slot("footer")}
|
|
90
|
+
</>
|
|
66
91
|
);
|
|
67
92
|
}
|
package/dist/index.js
CHANGED
|
@@ -187,6 +187,7 @@ var FRAMEWORKS = [
|
|
|
187
187
|
"src/middleware.ts",
|
|
188
188
|
"src/cmssy/blocks.ts",
|
|
189
189
|
"src/cmssy/editor.tsx",
|
|
190
|
+
"src/cmssy/layout-slot.tsx",
|
|
190
191
|
"src/cmssy/hero.tsx",
|
|
191
192
|
"src/components/Blocks.tsx",
|
|
192
193
|
"src/pages/[...path].astro",
|
|
@@ -204,6 +205,7 @@ var FRAMEWORKS = [
|
|
|
204
205
|
"app/routes.ts",
|
|
205
206
|
"app/cmssy/blocks.ts",
|
|
206
207
|
"app/cmssy/editor.tsx",
|
|
208
|
+
"app/cmssy/layout-slot.tsx",
|
|
207
209
|
"app/cmssy/hero.tsx",
|
|
208
210
|
"app/routes/page.tsx"
|
|
209
211
|
]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmssy/cli",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.8.0",
|
|
4
4
|
"description": "The cmssy CLI: `cmssy init` wires cmssy into an existing Next.js, Astro or React Router app; `cmssy link` connects it to a workspace and verifies the editor wiring.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cmssy",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"assets"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@cmssy/core": "10.
|
|
30
|
+
"@cmssy/core": "10.8.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "^20.0.0",
|