@pramen/cms-editor 0.0.52 → 0.0.53
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/README.md +57 -31
- package/dist/{app.css → editor.css} +46 -1
- package/dist/{main.a0tgw8hg.js → editor.js} +102 -102
- package/package.json +5 -1
- package/src/api.ts +15 -3
- package/src/app-context.tsx +37 -10
- package/src/main.tsx +41 -8
- package/src/mount.ts +143 -0
- package/dist/config.js +0 -15
- package/dist/fonts/README.md +0 -18
- package/dist/fonts/nc-fontina-variable.woff2 +0 -0
- package/dist/fonts.css +0 -45
- package/dist/index.html +0 -19
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @pramen/cms-editor
|
|
2
2
|
|
|
3
|
-
A **visual block/page editor** for [`@pramen/cms`](../cms) — a
|
|
4
|
-
|
|
3
|
+
A **visual block/page editor** for [`@pramen/cms`](../cms) — a React SPA that talks to the
|
|
4
|
+
CMS handlers over HTTP, served by your own site (see [Deploy it](#deploy-it)). It mutates through the *semantic* handlers
|
|
5
5
|
(`addBlock`/`updateBlock`/`reorderRegion`/`publishPage`/…), so field validation, region
|
|
6
6
|
allow-lists, and the review/publish gates are all enforced server-side.
|
|
7
7
|
|
|
@@ -26,43 +26,73 @@ allow-lists, and the review/publish gates are all enforced server-side.
|
|
|
26
26
|
## Run it
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
bun run --cwd packages/cms-editor build #
|
|
29
|
+
bun run --cwd packages/cms-editor build # -> dist/editor.js + dist/editor.css
|
|
30
30
|
bun run --cwd packages/cms-editor dev # watch + preview on http://localhost:5175
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
follow-up.)
|
|
33
|
+
The build produces exactly **two files** and no `index.html`. That is deliberate: a baked
|
|
34
|
+
shell can only hard-code root-absolute asset paths, which works at the origin root and
|
|
35
|
+
nowhere else, and its companion `config.js` was a hand-edited untyped global that failed
|
|
36
|
+
silently the moment it 404'd.
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
for any unmatched, extensionless path (deep link or refresh) and serve hashed assets from
|
|
41
|
-
the root. The dev preview server already does this; on a static host configure a catch-all
|
|
42
|
-
rewrite to `/index.html` (Cloudflare Pages/`assets` handle this by default). The bundle is
|
|
43
|
-
referenced by an **absolute** path (`/main.<hash>.js`), so it loads correctly from any route
|
|
44
|
-
depth — don't rewrite it to a relative path.
|
|
38
|
+
## Deploy it
|
|
45
39
|
|
|
46
|
-
|
|
40
|
+
A **host serves it**, from a shell it renders. For an Astro site that is one line — see
|
|
41
|
+
[`@pramen/cms-astro`](../cms-astro):
|
|
47
42
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
```js
|
|
44
|
+
// astro.config.mjs
|
|
45
|
+
pramenCms({ backend: { url: "https://cms.example.workers.dev" }, admin: true })
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
That injects a catch-all route at `/_pramen/admin`, so every view is a real server route on
|
|
49
|
+
the site's own origin: no `dist/` to copy, no SPA-fallback rewrite, and no second hostname
|
|
50
|
+
for the editor. The site's bundler emits and fingerprints `editor.js` / `editor.css` like
|
|
51
|
+
any other asset, which is what makes serving it under a prefix work.
|
|
52
|
+
|
|
53
|
+
It does not move the API, though. The editor still calls the CMS at the `backend.url` the
|
|
54
|
+
shell declares, so a CMS on its own Worker is still cross-origin and still needs
|
|
55
|
+
`CORS_ORIGINS` to allow the site. CORS goes away only when the CMS shares the site's
|
|
56
|
+
origin.
|
|
57
|
+
|
|
58
|
+
Everything the bundle needs at boot comes from that shell, and nothing else:
|
|
59
|
+
|
|
60
|
+
| What | How the shell provides it | Read by |
|
|
61
|
+
| --- | --- | --- |
|
|
62
|
+
| Where it is mounted | `data-base-path` on the mount node | `src/mount.ts` |
|
|
63
|
+
| Which Worker + tenant to call | `window.PRAMEN_CMS_EDITOR.backend` | `src/mount.ts` |
|
|
64
|
+
| Wordmark, sign-in URL, nav | the rest of `window.PRAMEN_CMS_EDITOR` | `src/brand.ts`, `src/app-context.tsx` |
|
|
65
|
+
|
|
66
|
+
The mount prefix is the constant the route was injected at, stamped onto the node by the
|
|
67
|
+
same code that injected it — so the router cannot be mounted somewhere the server does not
|
|
68
|
+
serve. Navigation is scoped to it, so a co-hosted editor intercepts only its own URLs
|
|
69
|
+
(`_404.tsx`'s catch-all matches every same-origin path, which un-scoped would mean a click
|
|
70
|
+
on the host's own `/blog` rendering the editor's "Nothing lives here").
|
|
71
|
+
|
|
72
|
+
**To write your own shell** (a Worker route, another framework), render: the stylesheet, a
|
|
73
|
+
`<div id="app" data-base-path="…">`, an inline script setting `window.PRAMEN_CMS_EDITOR`,
|
|
74
|
+
and `<script type="module" src="…editor.js">` — in that order. The dev preview in
|
|
75
|
+
`scripts/build.ts` is the smallest complete example.
|
|
76
|
+
|
|
77
|
+
## Configure it
|
|
78
|
+
|
|
79
|
+
The editor's own options travel in `window.PRAMEN_CMS_EDITOR`, which the integration writes
|
|
80
|
+
from typed options (`admin: { … }`) — there is no file to edit:
|
|
51
81
|
|
|
52
82
|
```js
|
|
53
|
-
|
|
83
|
+
admin: {
|
|
54
84
|
brand: { name: "Acme", suffix: "cms" }, // the wordmark — see below
|
|
55
85
|
// signInUrl: "/signin/", // ONLY once that page exists — see the warning
|
|
56
86
|
// hidePages: true, // collections-only deployments
|
|
57
87
|
// extraNav: [{ label: "Curation", href: "/curate" }],
|
|
58
|
-
}
|
|
88
|
+
}
|
|
59
89
|
```
|
|
60
90
|
|
|
61
|
-
> **`signInUrl` must be a page that exists
|
|
62
|
-
>
|
|
63
|
-
>
|
|
64
|
-
>
|
|
65
|
-
>
|
|
91
|
+
> **`signInUrl` must be a page that exists.** An unauthenticated load calls it after
|
|
92
|
+
> clearing the stored session, so a path that 404s into this SPA's own catch-all leaves the
|
|
93
|
+
> editor bouncing between the redirect and itself with no session to recover from. Point it
|
|
94
|
+
> at a page you have already deployed. `?setup=1` always forces the built-in screen, for
|
|
95
|
+
> pasting a first-admin JWT.
|
|
66
96
|
|
|
67
97
|
**Set `brand` when you deploy this for a client.** The editor ships as a package an agency
|
|
68
98
|
installs on someone else's behalf, so the default wordmark — `pramen · cms editor`, in the
|
|
@@ -76,12 +106,8 @@ A malformed `brand` can never take the editor down: a non-string value is ignore
|
|
|
76
106
|
than thrown on, and a `brand` that yields no usable name logs a console warning instead of
|
|
77
107
|
silently shipping "pramen" to your client.
|
|
78
108
|
|
|
79
|
-
The `<title>`
|
|
80
|
-
|
|
81
|
-
means the default shows for the moment before the bundle runs.
|
|
82
|
-
|
|
83
|
-
A clean build regenerates `config.js` when it is missing, but never overwrites one that is
|
|
84
|
-
already there — including on every `dev` rebuild — so an edit you are previewing survives.
|
|
109
|
+
The shell's `<title>` is written before the bundle runs, so the app re-applies the
|
|
110
|
+
configured brand on boot; the server-rendered tag is the pre-hydration fallback.
|
|
85
111
|
|
|
86
112
|
Settings → About still reports `pramen · cms-editor`. That row names the *software* you are
|
|
87
113
|
running, not the deployment, which is what an About panel is for.
|