@tideworthy/tidysites 0.1.2 → 0.1.4
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 -3
- package/bin/tidysites.mjs +34 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,12 +22,13 @@ nothing else; it lives in `.tidysites/key`, which is kept out of git.
|
|
|
22
22
|
| `tidysites status` | what changed here since the pull |
|
|
23
23
|
| `tidysites validate` | every file against the content model, with the file and the field in each message |
|
|
24
24
|
| `tidysites push [--prune] [--force] [--dry] [--only pages]` | validate, then write the created and updated entries back (with `--prune`, delete the entries whose files are gone), then pull |
|
|
25
|
-
| `tidysites shot <path or url> [--mobile] [--desktop] [--first-screen] [--live]` | a screenshot of a page of the preview site, the live site, or any address, saved under `.tidysites/shots
|
|
25
|
+
| `tidysites shot <path or url> [--mobile] [--tablet] [--desktop] [--wide] [--all] [--first-screen] [--live]` | a screenshot of a page of the preview site, the live site, or any address, saved under `.tidysites/shots/`; none of the width flags means desktop and mobile; a port compares all four |
|
|
26
26
|
| `tidysites pages` | every address the website renders |
|
|
27
27
|
| `tidysites page <path> [--html]` | the rendered page, section by section, with the key each section carries |
|
|
28
28
|
| `tidysites schema [type or collection]` | the section types and layouts, or one type's or collection's fields |
|
|
29
29
|
| `tidysites gallery [type]` | a screenshot of every section type and layout in this website's theme, or the first screen of one type |
|
|
30
30
|
| `tidysites fetch <url> [--out dir]` | a page of the site being ported: cleaned HTML, its outline (headings, navigation, images, phones, fonts, colours) and its stylesheets |
|
|
31
|
+
| `tidysites rm <collection>/<slug> ...` | delete entry files with their sidecars (`services/*` for every entry of a collection); `push --prune` then removes them from the website |
|
|
31
32
|
| `tidysites publish --yes` | the live site becomes a copy of the preview site |
|
|
32
33
|
|
|
33
34
|
A section keeps its type with its key: to replace an intro with a row, give the row its own `_key`
|
|
@@ -50,7 +51,7 @@ menus/<name>.json a menu as a tree: { "label", "items": [{ "label",
|
|
|
50
51
|
|
|
51
52
|
A new entry is a new `<collection>/<slug>.json` with at least `"data"`; the
|
|
52
53
|
slug is the file name, the status is `published` unless the file says
|
|
53
|
-
`draft`. Delete a file and `push --prune` removes the entry. A field taken
|
|
54
|
+
`draft`. Delete a file (`tidysites rm services/old-one`, or `services/*` for all) and `push --prune` removes the entry. A field taken
|
|
54
55
|
out of a file is cleared on the website at the next push. `id` and
|
|
55
56
|
`updated_at` are the website's; leave them as pulled. A pull never overwrites
|
|
56
57
|
a file you changed and have not pushed; it keeps the file and the difference
|
|
@@ -82,4 +83,4 @@ names its own in `header_row`.
|
|
|
82
83
|
3. `frame/frame.json` for the top bar, the call bar, the footer headings, the wording; `menus/primary.json` and `menus/footer.json` for the menus (an item with `children` is a dropdown).
|
|
83
84
|
4. Pages as sections: `pages/<slug>.json`, each a list in `data.sections`. Columns is the section for a band with no record behind it.
|
|
84
85
|
5. The look: brand colours and fonts on the Business record, `business/business.css` for what the tokens cannot say. The theme's own rules are written as `.ts.ts-accent` and `.ts.ts-ink .ts-prose a`, so a rule of yours needs the same weight (`.ts.ts-accent …`) to win.
|
|
85
|
-
6. `tidysites validate`, `tidysites push`, `tidysites shot
|
|
86
|
+
6. `tidysites validate`, `tidysites push`, `tidysites shot / --all`, and look at every width: a design often shows a different header above 1440px.
|
package/bin/tidysites.mjs
CHANGED
|
@@ -7,12 +7,13 @@
|
|
|
7
7
|
* status what changed here since the pull
|
|
8
8
|
* validate check the files against the content model
|
|
9
9
|
* push [--prune] [--force] [--dry] write the changes back, then pull
|
|
10
|
-
* shot <path|url> [--mobile
|
|
10
|
+
* shot <path|url> [--mobile] [--tablet] [--desktop] [--wide] [--all] [--first-screen] screenshot to .tidysites/shots (none = desktop and mobile)
|
|
11
11
|
* pages every address the website renders
|
|
12
12
|
* page <path> [--html] the rendered page, section by section
|
|
13
13
|
* schema [name] section types and layouts, or one type's or collection's fields
|
|
14
14
|
* gallery [type] screenshot of every section type in this theme, or the first screen of one type
|
|
15
15
|
* fetch <url> [--out dir] a page of the site being ported: cleaned HTML and its outline
|
|
16
|
+
* rm <collection>/<slug> ... delete entry files (globs allowed: services/*); push --prune then removes them from the website
|
|
16
17
|
* publish --yes the live site becomes a copy of the preview site
|
|
17
18
|
*
|
|
18
19
|
* The site is the remote: pull, edit, push. A push that would overwrite an
|
|
@@ -357,7 +358,9 @@ async function push(ctx) {
|
|
|
357
358
|
|
|
358
359
|
async function shot(ctx, target = positional[0] ?? '/', opts = {}) {
|
|
359
360
|
const isUrl = /^https?:\/\//.test(target);
|
|
360
|
-
|
|
361
|
+
// --desktop, --mobile, --tablet, --wide, any of them together; --all for every width; none = desktop and mobile.
|
|
362
|
+
const picked = ['desktop', 'mobile', 'tablet', 'wide'].filter((v) => flags[v]);
|
|
363
|
+
const view = flags.all ? 'all' : picked.length ? picked.join(',') : (opts.view ?? 'both');
|
|
361
364
|
const args = { site_id: ctx.cfg.site, view, full_page: !(flags['first-screen'] || opts.firstScreen), ...(isUrl ? { url: target } : { path: target, site: flags.live ? 'live' : 'preview' }) };
|
|
362
365
|
const { json, images } = await tool(ctx.cfg, 'screenshot_website', args);
|
|
363
366
|
const outDir = join(ctx.dir, META, 'shots');
|
|
@@ -366,7 +369,7 @@ async function shot(ctx, target = positional[0] ?? '/', opts = {}) {
|
|
|
366
369
|
const base = (opts.name ?? (isUrl ? new URL(target).hostname + new URL(target).pathname : target)).replace(/[^a-z0-9]+/gi, '-').replace(/^-|-$/g, '') || 'home';
|
|
367
370
|
const named = Array.isArray(json?.captures) ? json.captures : [];
|
|
368
371
|
images.forEach((img, i) => {
|
|
369
|
-
const v = named[i]?.view ?? (view === 'both' ? ['desktop', 'mobile'][i] : view);
|
|
372
|
+
const v = named[i]?.view ?? (view === 'both' ? ['desktop', 'mobile'][i] : view === 'all' ? ['desktop', 'mobile', 'tablet', 'wide'][i] : view.split(',')[i] ?? view);
|
|
370
373
|
const p = join(outDir, `${base}-${v}-${stamp}.${img.mimeType.includes('png') ? 'png' : 'jpg'}`);
|
|
371
374
|
writeFileSync(p, Buffer.from(img.base64, 'base64'));
|
|
372
375
|
say(relative(process.cwd(), p));
|
|
@@ -463,6 +466,32 @@ async function fetchCmd(ctx) {
|
|
|
463
466
|
say(`Saved to ${relative(process.cwd(), outDir)}/: ${base}.html (cleaned), ${base}.raw.html, ${base}.outline.json${cssTexts.length ? `, ${cssTexts.length} stylesheet${cssTexts.length === 1 ? '' : 's'}` : ''}`);
|
|
464
467
|
}
|
|
465
468
|
|
|
469
|
+
/**
|
|
470
|
+
* Delete entry files inside the folder, with their sidecars, so nobody has to reach for the shell's rm (which a
|
|
471
|
+
* harness may stop to ask about). Takes collection/slug paths; a trailing * takes every entry of the collection.
|
|
472
|
+
*/
|
|
473
|
+
function rmCmd({ dir }) {
|
|
474
|
+
if (!positional.length) fail('Usage: tidysites rm <collection>/<slug> [...] (services/* for every entry of a collection)');
|
|
475
|
+
let removed = 0;
|
|
476
|
+
for (const arg of positional) {
|
|
477
|
+
const m = /^([a-z][a-z0-9_]*)\/(\*|[A-Za-z0-9][A-Za-z0-9_-]*)(?:\.json)?$/.exec(arg.replace(/^\.\//, ''));
|
|
478
|
+
if (!m) fail(`${arg}: write collection/slug or collection/*`);
|
|
479
|
+
const [, collection, slug] = m;
|
|
480
|
+
const colDir = join(dir, collection);
|
|
481
|
+
if (!existsSync(colDir)) { say(`${collection}/: no such collection folder`); continue; }
|
|
482
|
+
const slugs = slug === '*' ? readdirSync(colDir).filter((f) => f.endsWith('.json')).map((f) => f.slice(0, -5)) : [slug];
|
|
483
|
+
for (const sl of slugs) {
|
|
484
|
+
let hit = false;
|
|
485
|
+
for (const ext of ['json', ...Object.keys(SIDECARS[collection] ?? SIDECARS.default)]) {
|
|
486
|
+
const f = join(colDir, `${sl}.${ext}`);
|
|
487
|
+
if (existsSync(f)) { rmSync(f); hit = true; }
|
|
488
|
+
}
|
|
489
|
+
if (hit) { removed++; say(`- ${collection}/${sl}`); } else say(`${collection}/${sl}: no such entry file`);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
say(`${removed} entr${removed === 1 ? 'y' : 'ies'} removed from the folder; \`tidysites push --prune\` removes them from the website.`);
|
|
493
|
+
}
|
|
494
|
+
|
|
466
495
|
async function publish(ctx) {
|
|
467
496
|
if (!flags.yes) fail('Publishing makes the live site a copy of the preview site. Look at it first (`tidysites shot /`), then run `tidysites publish --yes`.');
|
|
468
497
|
const { json, text } = await tool(ctx.cfg, 'publish_website', { site_id: ctx.cfg.site });
|
|
@@ -522,6 +551,8 @@ async function main() {
|
|
|
522
551
|
return schema(config());
|
|
523
552
|
case 'fetch':
|
|
524
553
|
return fetchCmd(config(false));
|
|
554
|
+
case 'rm':
|
|
555
|
+
return rmCmd(config());
|
|
525
556
|
case 'publish':
|
|
526
557
|
return publish(config());
|
|
527
558
|
case 'help':
|
package/package.json
CHANGED