tackl 2.0.0 → 2.2.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/README.md +4 -0
- package/bin/tackl.js +54 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,6 +11,10 @@ bunx tackl # or: bun create tackl / npm create tackl@latest
|
|
|
11
11
|
|
|
12
12
|
You'll be asked which CMS to use — **DatoCMS**, **Sanity**, or **None** — and the scaffold is pruned to match: only the chosen adapter, its dependencies, its docs, and its `.env.example` block survive.
|
|
13
13
|
|
|
14
|
+
Choosing **Sanity** sets the whole thing up: an embedded Studio at `/studio`, example schemas, and draft-mode preview routes ship in the scaffold, and the CLI offers to run `sanity init` for you — logging in, creating/linking a project, and writing your `.env`. Scaffold → `bun run dev` → `/studio` → start editing.
|
|
15
|
+
|
|
16
|
+
On your first `bun run dev`, a **setup wizard** greets you in the browser: it walks through every theme token (colours, spacing, motion, fonts, the type scale), writes your answers into `src/theme`, then deletes itself — skip it to keep the starter defaults. The scaffold commit the CLI makes is your restore point if you ever want to run it again.
|
|
17
|
+
|
|
14
18
|
## What it does
|
|
15
19
|
|
|
16
20
|
1. Verifies the directory is empty (an existing `.git`, `.gitignore`, `README.md` or `LICENSE` is fine — your repo's `.git` and remote are kept)
|
package/bin/tackl.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { execSync } from 'child_process';
|
|
3
|
-
import fs from 'fs';
|
|
4
|
-
import os from 'os';
|
|
5
|
-
import path from 'path';
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
6
|
import pc from 'picocolors';
|
|
7
7
|
import prompts from 'prompts';
|
|
8
8
|
import * as tar from 'tar';
|
|
@@ -104,16 +104,21 @@ const stripDeps = (root, deps) => {
|
|
|
104
104
|
delete json.dependencies?.[d];
|
|
105
105
|
delete json.devDependencies?.[d];
|
|
106
106
|
}
|
|
107
|
-
fs.writeFileSync(p, JSON.stringify(json, null, '\t')
|
|
107
|
+
fs.writeFileSync(p, `${JSON.stringify(json, null, '\t')}\n`);
|
|
108
108
|
};
|
|
109
109
|
|
|
110
|
+
// NOTE • Everything that exists solely for the embedded Sanity Studio
|
|
111
|
+
const SANITY_STUDIO_PATHS = ['app/(studio)', 'app/api/draft-mode', 'sanity.config.ts', 'sanity'];
|
|
112
|
+
const SANITY_DEPS = ['next-sanity', 'sanity', '@sanity/vision'];
|
|
113
|
+
|
|
110
114
|
const CMS = {
|
|
111
115
|
dato: {
|
|
112
116
|
title: 'DatoCMS',
|
|
113
117
|
prune: root => {
|
|
114
118
|
rmrf(root, 'src/cms/sanity');
|
|
115
119
|
rmrf(root, 'docs/Sanity');
|
|
116
|
-
|
|
120
|
+
for (const p of SANITY_STUDIO_PATHS) rmrf(root, p);
|
|
121
|
+
stripDeps(root, SANITY_DEPS);
|
|
117
122
|
stripEnvBlock(root, '# CMS — Sanity');
|
|
118
123
|
},
|
|
119
124
|
},
|
|
@@ -138,7 +143,8 @@ const CMS = {
|
|
|
138
143
|
rmrf(root, 'docs/Sanity');
|
|
139
144
|
rmrf(root, 'docs/DatoCMS');
|
|
140
145
|
rmrf(root, 'docs/CMS.md');
|
|
141
|
-
|
|
146
|
+
for (const p of SANITY_STUDIO_PATHS) rmrf(root, p);
|
|
147
|
+
stripDeps(root, [...SANITY_DEPS, '@datocms/cda-client', 'react-datocms', 'graphql', 'graphql-tag']);
|
|
142
148
|
stripEnvBlock(root, '# CMS — Sanity');
|
|
143
149
|
stripEnvBlock(root, '# CMS — DatoCMS');
|
|
144
150
|
},
|
|
@@ -182,7 +188,9 @@ ${pc.bold('Repository:')} https://github.com/${OWNER}/${REPO}
|
|
|
182
188
|
const targetDir = process.cwd();
|
|
183
189
|
|
|
184
190
|
if (!dirIsScaffoldable(targetDir)) {
|
|
185
|
-
log.error(
|
|
191
|
+
log.error(
|
|
192
|
+
'This directory is not empty. Run tackl inside an empty directory (a .git folder, .gitignore, README.md and LICENSE are fine).'
|
|
193
|
+
);
|
|
186
194
|
process.exit(1);
|
|
187
195
|
}
|
|
188
196
|
|
|
@@ -219,10 +227,11 @@ ${pc.bold('Repository:')} https://github.com/${OWNER}/${REPO}
|
|
|
219
227
|
|
|
220
228
|
const cms = cmsFlag || answers.cms;
|
|
221
229
|
const rawName = flagValue('--name') || path.basename(targetDir);
|
|
222
|
-
const projectName =
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
230
|
+
const projectName =
|
|
231
|
+
rawName
|
|
232
|
+
.toLowerCase()
|
|
233
|
+
.replace(/[^a-z0-9\-._]/g, '-')
|
|
234
|
+
.replace(/^[-.]+|[-.]+$/g, '') || 'tackl-app';
|
|
226
235
|
const doInstall = !args.includes('--no-install');
|
|
227
236
|
const doGit = !args.includes('--no-git');
|
|
228
237
|
const hadGit = fs.existsSync(path.join(targetDir, '.git'));
|
|
@@ -294,7 +303,7 @@ ${pc.bold('Repository:')} https://github.com/${OWNER}/${REPO}
|
|
|
294
303
|
json.version = '0.1.0';
|
|
295
304
|
delete json.repository;
|
|
296
305
|
delete json.author;
|
|
297
|
-
fs.writeFileSync(pkgPath, JSON.stringify(json, null, '\t')
|
|
306
|
+
fs.writeFileSync(pkgPath, `${JSON.stringify(json, null, '\t')}\n`);
|
|
298
307
|
log.ok('package.json updated.');
|
|
299
308
|
} catch (e) {
|
|
300
309
|
log.warn(`Could not update package.json: ${e.message}`);
|
|
@@ -330,11 +339,39 @@ ${pc.bold('Repository:')} https://github.com/${OWNER}/${REPO}
|
|
|
330
339
|
log.info('Skipped dependency install.');
|
|
331
340
|
}
|
|
332
341
|
|
|
333
|
-
|
|
342
|
+
// SECTION • Sanity project link
|
|
343
|
+
// NOTE • A Sanity scaffold isn't usable until a project id exists —
|
|
344
|
+
// sanity's own init logs in, creates/links a project and writes .env.
|
|
345
|
+
let sanityLinked = false;
|
|
346
|
+
if (cms === 'sanity' && process.stdout.isTTY) {
|
|
347
|
+
const { link } = await prompts({
|
|
348
|
+
type: 'confirm',
|
|
349
|
+
name: 'link',
|
|
350
|
+
message: 'Link a Sanity project now? (opens a browser login, writes .env)',
|
|
351
|
+
initial: true,
|
|
352
|
+
});
|
|
353
|
+
if (link) {
|
|
354
|
+
try {
|
|
355
|
+
execSync('bunx sanity@latest init --env .env', { cwd: targetDir, stdio: 'inherit' });
|
|
356
|
+
sanityLinked = true;
|
|
357
|
+
log.ok('Sanity project linked!');
|
|
358
|
+
} catch (e) {
|
|
359
|
+
log.warn(`sanity init did not complete: ${e.message}`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
console.log(`\n${pc.bold(pc.green('Success!'))} Project scaffolded.\n`);
|
|
334
365
|
console.log(' Next steps:');
|
|
335
|
-
|
|
336
|
-
if (
|
|
337
|
-
|
|
366
|
+
let step = 1;
|
|
367
|
+
if (cms === 'sanity' && !sanityLinked) {
|
|
368
|
+
console.log(` ${step++}) bunx sanity init --env .env # create/link your Sanity project`);
|
|
369
|
+
} else if (cms !== 'sanity') {
|
|
370
|
+
console.log(` ${step++}) cp .env.example .env # then fill in your values`);
|
|
371
|
+
}
|
|
372
|
+
if (!doInstall) console.log(` ${step++}) bun install`);
|
|
373
|
+
console.log(` ${step++}) bun run dev # a first-run setup wizard walks you through your theme`);
|
|
374
|
+
if (cms === 'sanity') console.log(` ${step}) open http://localhost:3000/studio to start editing content`);
|
|
338
375
|
}
|
|
339
376
|
|
|
340
377
|
main().catch(e => {
|