create-payload-canvas 0.5.2 → 0.6.1
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 +16 -9
- package/dist/config.js +17 -10
- package/dist/features.js +17 -9
- package/dist/index.js +6 -0
- package/dist/options.js +33 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ The CLI asks for the project name, your Postgres details, which starter features
|
|
|
27
27
|
5. Sets the package name, removes the repo-only scripts and the dev dependencies they needed, and points `payload-canvas` at a source (see below).
|
|
28
28
|
6. Writes `.env` from `.env.example` with your `DATABASE_URL` and a new random `PAYLOAD_SECRET`.
|
|
29
29
|
7. Creates the database.
|
|
30
|
-
8. Installs dependencies with pnpm (npm if pnpm is missing).
|
|
30
|
+
8. Installs dependencies with pnpm (npm if pnpm is missing), then writes `src/payload-types.ts` again for the kept features.
|
|
31
31
|
9. Runs `seed:demo` if you chose to seed. On a fresh database the seed creates the tables. Without the demo seed, it runs `seed:classes`, which adds the editable classes that the ready-made sections use.
|
|
32
32
|
10. Prints a summary with the exact next commands.
|
|
33
33
|
|
|
@@ -35,17 +35,20 @@ It never runs `payload migrate`. Local development uses `push: true`, so the sch
|
|
|
35
35
|
|
|
36
36
|
## Features
|
|
37
37
|
|
|
38
|
-
The starter has a few parts
|
|
38
|
+
The starter has a few optional parts. Google reviews is off by default; all the others are on. Without `--yes`, the CLI shows a list with the default ones checked. Check or uncheck the ones you want. A `--<feature>` flag adds a feature and a `--no-<feature>` flag leaves it out, without asking.
|
|
39
39
|
|
|
40
|
-
| Feature | Flag | What
|
|
40
|
+
| Feature | Flag | What it changes |
|
|
41
41
|
|---|---|---|
|
|
42
|
-
| Admin look | `--no-look` | Neutral colors and finer details in the admin (`src/admin/look`). |
|
|
42
|
+
| Admin look | `--no-look` | Neutral colors and finer details in the admin (`src/admin/look`), status badges and list cells by field type (`src/admin/list`), and array rows named by their content (`src/admin/fields`). |
|
|
43
43
|
| Sidebar navigation | `--no-nav` | The grouped sidebar with icons (`src/admin/nav`). The admin uses Payload's default sidebar. |
|
|
44
|
-
| Dashboard widgets | `--no-dashboard` | Quick actions, recent edits,
|
|
44
|
+
| Dashboard widgets | `--no-dashboard` | Quick actions, recent edits, open comments, form messages, site checks, broken links (404s and links to missing pages), unused media (with a full list at `/admin/unused-media`), scheduled publishes and analytics; "Waiting to publish" can be added (`src/admin/dashboard`). The reference index behind unused media and broken links (`src/admin/references`, `pnpm references:rebuild`). The admin shows Payload's collection cards. |
|
|
45
45
|
| Demo content | `--no-demo` | The demo pages, posts and images seed (`scripts/seed-demo.ts` and the `seed:demo` script). This also turns off seeding. |
|
|
46
46
|
| AI assistant | `--no-ai` | The chat panel in the page builder, and its settings in `.env`. |
|
|
47
|
+
| Media gallery | `--no-gallery` | Media as a grid of thumbnails with a lightbox and drag-and-drop upload ([`payload-media-gallery`](https://www.npmjs.com/package/payload-media-gallery)). Without it, Media uses Payload's table. |
|
|
48
|
+
| Workflows | `--no-workflows` | The visual workflow builder (Automation → Workflows), the Run tab on jobs, and the starter tasks in `src/jobs` ([`payload-workflows`](https://www.npmjs.com/package/payload-workflows)). |
|
|
49
|
+
| Google reviews | `--reviews` (off by default) | Adds a Reviews collection and Review Settings that sync a Google place's reviews ([`payload-google-reviews`](https://www.npmjs.com/package/payload-google-reviews), with the optional scraper). You set the place in the admin after setup. |
|
|
47
50
|
|
|
48
|
-
|
|
51
|
+
For each feature that is off, the CLI deletes its files and its npm packages from `package.json`, and removes its lines from `src/payload.config.ts`, `next.config.ts`, `src/app/(payload)/custom.scss`, `.env.example`, `README.md` and the admin import map. After the install it runs `generate:types`, so `src/payload-types.ts` matches the kept features. The project type-checks with any mix of features.
|
|
49
52
|
|
|
50
53
|
## Flags
|
|
51
54
|
|
|
@@ -63,7 +66,8 @@ The CLI deletes the feature's files and removes its lines from `src/payload.conf
|
|
|
63
66
|
| `--skip-db` | Do not connect to Postgres. Writes `.env` only. This also skips seeding. |
|
|
64
67
|
| `--seed` / `--no-seed` | Seed demo content, or not. |
|
|
65
68
|
| `--no-install` | Do not install. This also skips seeding. |
|
|
66
|
-
| `--no-look`, `--no-nav`, `--no-dashboard`, `--no-demo`, `--no-ai` | Leave out a starter feature. See [Features](#features). `--no-demo` also turns off seeding. |
|
|
69
|
+
| `--no-look`, `--no-nav`, `--no-dashboard`, `--no-demo`, `--no-ai`, `--no-gallery`, `--no-workflows` | Leave out a starter feature. See [Features](#features). `--no-demo` also turns off seeding. |
|
|
70
|
+
| `--reviews` | Add Google reviews, which is off by default. Every feature also takes `--<feature>` and `--no-<feature>`. |
|
|
67
71
|
| `--github` | Download the starter from GitHub, even when the CLI runs inside a checkout. |
|
|
68
72
|
| `--ref <name>` | Branch or tag to download. Default `main`. |
|
|
69
73
|
| `--packages <path>` | Path to a checkout of the repo. The CLI packs the `payload-canvas` package from there. |
|
|
@@ -74,7 +78,7 @@ The CLI deletes the feature's files and removes its lines from `src/payload.conf
|
|
|
74
78
|
| Case | `payload-canvas` in the new project |
|
|
75
79
|
|---|---|
|
|
76
80
|
| The CLI runs inside a checkout, or you pass `--packages <path>` | a `file:./.tarballs/...` tarball, packed with `pnpm pack` (it builds `dist/` first). Commit `.tarballs/` with the project. |
|
|
77
|
-
| Neither | The version on npm (`^0.
|
|
81
|
+
| Neither | The version on npm (`^0.6.1`). |
|
|
78
82
|
|
|
79
83
|
Without `--packages`, and outside a checkout, the CLI checks the npm registry first. If the package is not on npm (for example, a `--ref` with an unreleased version), it stops before it writes any file and tells you to use `--packages <path>` or `--no-install`.
|
|
80
84
|
|
|
@@ -93,6 +97,9 @@ npx create-payload-canvas my-website --yes --no-install --skip-db
|
|
|
93
97
|
# Without the AI assistant and the demo content
|
|
94
98
|
npx create-payload-canvas my-website --yes --no-ai --no-demo
|
|
95
99
|
|
|
100
|
+
# With Google reviews, without the media gallery and workflows
|
|
101
|
+
npx create-payload-canvas my-website --yes --reviews --no-gallery --no-workflows
|
|
102
|
+
|
|
96
103
|
# From GitHub, with the package from a local checkout (before it is published)
|
|
97
104
|
npx create-payload-canvas my-website --yes --github --packages C:\code\payload-canvas
|
|
98
105
|
|
|
@@ -130,7 +137,7 @@ If the copy or pack step fails, the CLI deletes the half-made folder. If the ins
|
|
|
130
137
|
## Maintainers
|
|
131
138
|
|
|
132
139
|
- The GitHub owner is `GITHUB_OWNER` in `src/config.ts`. The list of files the CLI leaves out is `SKIP_NAMES` and `SKIP_PATHS` in the same file.
|
|
133
|
-
- The starter's `starter-features.json` lists each feature's files and
|
|
140
|
+
- The starter's `starter-features.json` lists each feature's files, scripts and npm `dependencies`. In code, a line with `@feature:<id>` starts a part that belongs to a feature, and a line with `@end:<id>` ends it (in Markdown, inside an HTML comment). The prompt, the flags and the default (`on`) come from `FEATURES` in `src/config.ts`. Add a new feature in both places.
|
|
134
141
|
- `pnpm check:features` copies the starter for every mix of features, applies it, and runs the starter's TypeScript check. Run it after you change a feature. `pnpm test` runs the unit tests.
|
|
135
142
|
- After copying, the CLI checks the new project for leftovers (`workspace:` links, paths into `packages/`, `baseUrl`, Docker files) and prints a warning for each one it finds.
|
|
136
143
|
- Build with `pnpm build`. Run from the repo with `node dist/index.js`. `pnpm pack` builds first (`prepack`).
|
package/dist/config.js
CHANGED
|
@@ -9,7 +9,7 @@ export function tarballUrl(ref) {
|
|
|
9
9
|
return `https://codeload.github.com/${GITHUB_OWNER}/${GITHUB_REPO}/tar.gz/${ref}`;
|
|
10
10
|
}
|
|
11
11
|
// Version range for the payload-canvas package when it comes from npm.
|
|
12
|
-
export const PUBLISHED_VERSION = '^0.
|
|
12
|
+
export const PUBLISHED_VERSION = '^0.6.1';
|
|
13
13
|
// The package the starter depends on: its npm name and its folder under `packages/` in the repo.
|
|
14
14
|
export const BUILDER_PACKAGE = { name: 'payload-canvas', dir: 'payload-canvas' };
|
|
15
15
|
// Files and folders of the starter that only make sense inside the repo. The CLI does not copy them.
|
|
@@ -34,14 +34,21 @@ export const SKIP_NAMES = new Set([
|
|
|
34
34
|
'docker-compose.yml',
|
|
35
35
|
]);
|
|
36
36
|
// Paths relative to the starter folder.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
//
|
|
40
|
-
//
|
|
37
|
+
// `uploads`: files visitors sent with forms (private, never part of a new project).
|
|
38
|
+
export const SKIP_PATHS = ['scripts/setup.ts', 'scripts/lib/create-database.ts', 'scripts/lib/generate-env.ts', 'docs/qa', 'uploads'];
|
|
39
|
+
// Starter features the user can turn on or off. The CLI asks about these and has a `--<id>` and a
|
|
40
|
+
// `--no-<id>` flag for each. `on: false` features are off unless the user picks them.
|
|
41
|
+
// The starter's `starter-features.json` says which files, config lines, scripts and dependencies
|
|
42
|
+
// belong to each one. A feature in that file but not in this list is always kept.
|
|
41
43
|
export const FEATURES = [
|
|
42
|
-
{ id: 'look', label: 'Admin look', hint: 'Neutral colors and finer details in the admin' },
|
|
43
|
-
{ id: 'nav', label: 'Sidebar navigation', hint: 'Grouped sidebar with icons' },
|
|
44
|
-
{ id: 'dashboard', label: 'Dashboard widgets', hint: 'Quick actions, recent edits, form messages, site checks, analytics' },
|
|
45
|
-
{ id: 'demo', label: 'Demo content', hint: 'The demo pages, posts and images seed' },
|
|
46
|
-
{ id: 'ai', label: 'AI assistant', hint: 'The chat panel in the page builder' },
|
|
44
|
+
{ id: 'look', label: 'Admin look', hint: 'Neutral colors and finer details in the admin', on: true },
|
|
45
|
+
{ id: 'nav', label: 'Sidebar navigation', hint: 'Grouped sidebar with icons', on: true },
|
|
46
|
+
{ id: 'dashboard', label: 'Dashboard widgets', hint: 'Quick actions, recent edits, form messages, site checks, analytics', on: true },
|
|
47
|
+
{ id: 'demo', label: 'Demo content', hint: 'The demo pages, posts and images seed', on: true },
|
|
48
|
+
{ id: 'ai', label: 'AI assistant', hint: 'The chat panel in the page builder', on: true },
|
|
49
|
+
{ id: 'gallery', label: 'Media gallery', hint: 'Media as a grid with a lightbox and drag-and-drop upload (payload-media-gallery)', on: true },
|
|
50
|
+
{ id: 'workflows', label: 'Workflows', hint: 'A visual workflow builder and a graph of every job run (payload-workflows)', on: true },
|
|
51
|
+
{ id: 'reviews', label: 'Google reviews', hint: 'Syncs Google reviews into a collection; needs a Google place (payload-google-reviews)', on: false },
|
|
47
52
|
];
|
|
53
|
+
/** The features that are on when the user passes no flags. */
|
|
54
|
+
export const DEFAULT_FEATURES = FEATURES.filter((feature) => feature.on).map((feature) => feature.id);
|
package/dist/features.js
CHANGED
|
@@ -53,11 +53,14 @@ function importMapKey(removedPath) {
|
|
|
53
53
|
return rel.slice('src'.length).replace(/\.[cm]?[jt]sx?$/, '');
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
|
-
* Removes the importMap.js lines that point into deleted files or folders
|
|
57
|
-
* and the map entries. `removedPaths` are relative to the project root,
|
|
56
|
+
* Removes the importMap.js lines that point into deleted files or folders, or into removed
|
|
57
|
+
* packages: the import lines and the map entries. `removedPaths` are relative to the project root,
|
|
58
|
+
* like `src/admin/nav`. `removedPackages` are npm names, like `payload-workflows`.
|
|
58
59
|
*/
|
|
59
|
-
export function stripImportMap(text, removedPaths) {
|
|
60
|
+
export function stripImportMap(text, removedPaths, removedPackages = []) {
|
|
60
61
|
const keys = removedPaths.map(importMapKey).filter((key) => key !== null);
|
|
62
|
+
// A package specifier starts right after a quote: 'pkg/rsc' or "pkg/rsc#Name".
|
|
63
|
+
keys.push(...removedPackages.flatMap((name) => [`'${name}`, `"${name}`]));
|
|
61
64
|
if (keys.length === 0)
|
|
62
65
|
return text;
|
|
63
66
|
// The key must end at a path separator, a quote or the `#export` part, so `/admin/nav` does not match `/admin/navbar`.
|
|
@@ -114,8 +117,8 @@ export function filesWithMarkers(targetDir) {
|
|
|
114
117
|
}
|
|
115
118
|
/**
|
|
116
119
|
* Turns the starter's features on or off in a copied project. For each known feature that is not in
|
|
117
|
-
* `enabledIds`, it deletes the feature's files, its package.json scripts, its marked
|
|
118
|
-
* importMap.js lines. Then it deletes `starter-features.json`.
|
|
120
|
+
* `enabledIds`, it deletes the feature's files, its package.json scripts and dependencies, its marked
|
|
121
|
+
* regions and its importMap.js lines. Then it deletes `starter-features.json`.
|
|
119
122
|
* Returns the ids it turned off, or null when the starter has no manifest (then it changes nothing).
|
|
120
123
|
*/
|
|
121
124
|
export function applyFeatures(targetDir, enabledIds) {
|
|
@@ -141,17 +144,22 @@ export function applyFeatures(targetDir, enabledIds) {
|
|
|
141
144
|
const removedPaths = off.flatMap((feature) => feature.paths);
|
|
142
145
|
for (const rel of removedPaths)
|
|
143
146
|
fs.rmSync(resolveInside(targetDir, rel), { recursive: true, force: true });
|
|
147
|
+
const removedPackages = off.flatMap((feature) => feature.dependencies ?? []);
|
|
144
148
|
const importMap = path.join(targetDir, IMPORT_MAP_FILE);
|
|
145
|
-
if (removedPaths.length > 0 && fs.existsSync(importMap)) {
|
|
146
|
-
fs.writeFileSync(importMap, stripImportMap(fs.readFileSync(importMap, 'utf8'), removedPaths));
|
|
149
|
+
if ((removedPaths.length > 0 || removedPackages.length > 0) && fs.existsSync(importMap)) {
|
|
150
|
+
fs.writeFileSync(importMap, stripImportMap(fs.readFileSync(importMap, 'utf8'), removedPaths, removedPackages));
|
|
147
151
|
}
|
|
148
|
-
// package.json scripts.
|
|
152
|
+
// package.json scripts and dependencies.
|
|
149
153
|
const scripts = off.flatMap((feature) => feature.scripts ?? []);
|
|
150
154
|
const pkgFile = path.join(targetDir, 'package.json');
|
|
151
|
-
if (scripts.length > 0 && fs.existsSync(pkgFile)) {
|
|
155
|
+
if ((scripts.length > 0 || removedPackages.length > 0) && fs.existsSync(pkgFile)) {
|
|
152
156
|
const pkg = JSON.parse(fs.readFileSync(pkgFile, 'utf8'));
|
|
153
157
|
for (const name of scripts)
|
|
154
158
|
delete pkg.scripts?.[name];
|
|
159
|
+
for (const name of removedPackages) {
|
|
160
|
+
delete pkg.dependencies?.[name];
|
|
161
|
+
delete pkg.devDependencies?.[name];
|
|
162
|
+
}
|
|
155
163
|
fs.writeFileSync(pkgFile, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
156
164
|
}
|
|
157
165
|
fs.rmSync(path.join(targetDir, MANIFEST_FILE));
|
package/dist/index.js
CHANGED
|
@@ -109,6 +109,12 @@ async function main() {
|
|
|
109
109
|
if (!installed) {
|
|
110
110
|
throw new Error(`"${manager} install" failed. The project is in ${targetDir}. Fix the error above, then run "${manager} install" there.`);
|
|
111
111
|
}
|
|
112
|
+
// The starter's payload-types.ts has the collections of every feature. Write it again for the kept ones.
|
|
113
|
+
if (removed && removed.length > 0) {
|
|
114
|
+
p.log.step('Updating src/payload-types.ts for the chosen features...');
|
|
115
|
+
if (!run(manager, ['run', 'generate:types'], targetDir))
|
|
116
|
+
p.log.warn(`Updating the types failed. Run "${manager} run generate:types" in ${targetDir}.`);
|
|
117
|
+
}
|
|
112
118
|
}
|
|
113
119
|
// 5. Seed.
|
|
114
120
|
let seeded = false;
|
package/dist/options.js
CHANGED
|
@@ -14,12 +14,15 @@ Project:
|
|
|
14
14
|
--no-install Do not install dependencies (this also skips seeding)
|
|
15
15
|
--seed / --no-seed Seed demo content (default: yes with --yes, else ask)
|
|
16
16
|
|
|
17
|
-
Features (
|
|
17
|
+
Features (without --yes the CLI asks about the ones you did not pass):
|
|
18
18
|
--no-look Leave out the admin look (neutral colors, finer details)
|
|
19
19
|
--no-nav Leave out the grouped sidebar navigation
|
|
20
20
|
--no-dashboard Leave out the dashboard widgets
|
|
21
21
|
--no-demo Leave out the demo content seed (this also turns off seeding)
|
|
22
22
|
--no-ai Leave out the AI assistant in the page builder
|
|
23
|
+
--no-gallery Leave out the media gallery (Media keeps Payload's table)
|
|
24
|
+
--no-workflows Leave out the workflow builder and the job run viewer
|
|
25
|
+
--reviews Add Google reviews (off by default; needs a Google place)
|
|
23
26
|
|
|
24
27
|
Database (default user and password: postgres):
|
|
25
28
|
--db-url <url> postgresql://user:pass@host:5432/name (replaces the flags below)
|
|
@@ -39,8 +42,28 @@ Source:
|
|
|
39
42
|
|
|
40
43
|
-h, --help Show this help
|
|
41
44
|
`;
|
|
42
|
-
//
|
|
43
|
-
const featureFlags = Object.fromEntries(FEATURES.
|
|
45
|
+
// A `--<id>` and a `--no-<id>` flag per starter feature. Help lists the one that changes the default.
|
|
46
|
+
const featureFlags = Object.fromEntries(FEATURES.flatMap((feature) => [
|
|
47
|
+
[feature.id, { type: 'boolean' }],
|
|
48
|
+
[`no-${feature.id}`, { type: 'boolean' }],
|
|
49
|
+
]));
|
|
50
|
+
/**
|
|
51
|
+
* The features chosen with flags: `--<id>` turns one on, `--no-<id>` turns it off. Returns the
|
|
52
|
+
* features that are on (flag or default) and the ids the flags decided, which the CLI does not ask about.
|
|
53
|
+
*/
|
|
54
|
+
export function featuresFromFlags(values) {
|
|
55
|
+
const decided = new Set();
|
|
56
|
+
const features = FEATURES.filter((feature) => {
|
|
57
|
+
const on = values[feature.id] === true;
|
|
58
|
+
const off = values[`no-${feature.id}`] === true;
|
|
59
|
+
if (on && off)
|
|
60
|
+
throw new Error(`--${feature.id} and --no-${feature.id} cannot be used together.`);
|
|
61
|
+
if (on || off)
|
|
62
|
+
decided.add(feature.id);
|
|
63
|
+
return on || (!off && feature.on);
|
|
64
|
+
}).map((feature) => feature.id);
|
|
65
|
+
return { features, decided };
|
|
66
|
+
}
|
|
44
67
|
function parseFlags() {
|
|
45
68
|
return parseArgs({
|
|
46
69
|
allowPositionals: true,
|
|
@@ -156,20 +179,21 @@ export async function resolveOptions() {
|
|
|
156
179
|
db.name = values['db-name'];
|
|
157
180
|
// Source.
|
|
158
181
|
const packages = values.packages ? path.resolve(process.cwd(), values.packages) : null;
|
|
159
|
-
// Features. A --no-<id> flag
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
182
|
+
// Features. A --<id> or --no-<id> flag decides one without asking. Ask about the rest.
|
|
183
|
+
const fromFlags = featuresFromFlags(values);
|
|
184
|
+
let features = fromFlags.features;
|
|
185
|
+
const open = FEATURES.filter((feature) => !fromFlags.decided.has(feature.id));
|
|
163
186
|
if (!yes && open.length > 0) {
|
|
164
187
|
const answer = await p.multiselect({
|
|
165
188
|
message: 'Which starter features do you want? (space toggles, enter confirms)',
|
|
166
189
|
options: open.map((feature) => ({ value: feature.id, label: feature.label, hint: feature.hint })),
|
|
167
|
-
initialValues:
|
|
190
|
+
initialValues: open.filter((feature) => feature.on).map((feature) => feature.id),
|
|
168
191
|
required: false,
|
|
169
192
|
});
|
|
170
193
|
if (p.isCancel(answer))
|
|
171
194
|
cancelled();
|
|
172
|
-
|
|
195
|
+
const picked = new Set(answer);
|
|
196
|
+
features = FEATURES.filter((feature) => (fromFlags.decided.has(feature.id) ? features.includes(feature.id) : picked.has(feature.id))).map((feature) => feature.id);
|
|
173
197
|
}
|
|
174
198
|
const demo = features.includes('demo');
|
|
175
199
|
// Install and seed.
|
package/package.json
CHANGED