@tideworthy/tidysites 0.1.10 → 0.1.11
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 -2
- package/bin/tidysites.mjs +31 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,8 +22,8 @@ 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] [--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. A page taller than 2400px comes in 1600px bands (`<name>-band-01.jpg`, …), top to bottom, that an image reader can take in one at a time |
|
|
26
|
-
| `tidysites measure <path or url> [--mobile] [--tablet] [--desktop] [--wide] [--all] [--full]` | the page as the browser lays it out: every heading, paragraph, button, picture and section box with its computed type (size, line height, weight, family, colour) and box (position, size, padding, margin, background), saved as JSON under `.tidysites/measures/` and printed. Measure the old page and the new one at the same width and style to the numbers |
|
|
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. A page taller than 2400px comes in 1600px bands (`<name>-band-01.jpg`, …), top to bottom, that an image reader can take in one at a time. `--menu` opens every navigation menu (burgers, `<details>`, hover dropdowns) before the capture; `--open a,b` clicks those selectors and `--hover a,b` shows the submenus under them, for a popup, a tab or one dropdown |
|
|
26
|
+
| `tidysites measure <path or url> [--mobile] [--tablet] [--desktop] [--wide] [--all] [--full]` | the page as the browser lays it out: every heading, paragraph, button, picture and section box with its computed type (size, line height, weight, family, colour) and box (position, size, padding, margin, background), saved as JSON under `.tidysites/measures/` and printed. Measure the old page and the new one at the same width and style to the numbers. The same `--menu`, `--open` and `--hover` as `shot`, so a dropdown's open type is measured |
|
|
27
27
|
| `tidysites redirect [add <old path> <new path> \| rm <old path>]` | the website's redirects: an old address that must keep working after a port goes here; they ship with the next publish |
|
|
28
28
|
| `tidysites pages` | every address the website renders |
|
|
29
29
|
| `tidysites page <path> [--html]` | the rendered page, section by section, with the key each section carries |
|
|
@@ -59,6 +59,8 @@ out of a file is cleared on the website at the next push. `id` and
|
|
|
59
59
|
a file you changed and have not pushed; it keeps the file and the difference
|
|
60
60
|
shows in `status`.
|
|
61
61
|
|
|
62
|
+
Styling: a row's `.css` file is scoped to that row (every rule is prefixed with the row's own selector), so it cannot style the rest of the page; rules for the whole page, the sections and the theme's classes go in `business/business.css`.
|
|
63
|
+
|
|
62
64
|
Images: an image field, a hero's image or a Columns image slot takes
|
|
63
65
|
`{ "$media": { "url": "https://...", "alt": "what it shows" } }` and the
|
|
64
66
|
push fetches the file into the website's library; a file the library already
|
package/bin/tidysites.mjs
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
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] [--tablet] [--desktop] [--wide] [--all] [--first-screen] screenshot to .tidysites/shots (none = desktop and mobile); a tall page comes in 1600px bands
|
|
11
|
-
* measure <path|url> [--mobile] [--tablet] [--desktop] [--wide] [--all] [--full] the computed type and boxes of a page: the numbers to style to and diff
|
|
10
|
+
* shot <path|url> [--mobile] [--tablet] [--desktop] [--wide] [--all] [--first-screen] [--menu] [--open sel,..] [--hover sel,..] screenshot to .tidysites/shots (none = desktop and mobile); a tall page comes in 1600px bands; --menu opens every navigation menu first
|
|
11
|
+
* measure <path|url> [--mobile] [--tablet] [--desktop] [--wide] [--all] [--full] [--menu] [--open sel,..] [--hover sel,..] the computed type and boxes of a page: the numbers to style to and diff
|
|
12
12
|
* redirect [add <old> <new> | rm <old>] the website's redirects (an old address that must keep working goes here)
|
|
13
13
|
* pages every address the website renders
|
|
14
14
|
* page <path> [--html] the rendered page, section by section
|
|
@@ -189,9 +189,13 @@ async function pull({ dir, cfg }, collections = null, { overwrite = new Set(), m
|
|
|
189
189
|
// website's version underneath it, so status shows the difference and a push carries the new stamp.
|
|
190
190
|
const files = {};
|
|
191
191
|
const kept = [];
|
|
192
|
+
const removedHere = readRemoved(dir);
|
|
193
|
+
const heldBack = [];
|
|
192
194
|
for (const [collection, entries] of Object.entries(doc.content)) {
|
|
193
195
|
for (const e of entries) {
|
|
194
196
|
const key = `${collection}/${e.slug ?? e.id}`;
|
|
197
|
+
// Removed here with `tidysites rm` and not pruned yet: the website still has it, the folder does not get it back.
|
|
198
|
+
if (removedHere.has(key) && !overwrite.has(key)) { heldBack.push(key); continue; }
|
|
195
199
|
const mine = local[key];
|
|
196
200
|
const was = prev?.entries?.[key];
|
|
197
201
|
// An entry this push just wrote is the website's now: its file takes the website's version ($media
|
|
@@ -244,6 +248,7 @@ async function pull({ dir, cfg }, collections = null, { overwrite = new Set(), m
|
|
|
244
248
|
for (const c of doc.collections.filter((c) => c.count)) say(` ${c.slug.padEnd(20)} ${c.count}`);
|
|
245
249
|
if (snap.menus) say(` ${'menus'.padEnd(20)} ${Object.keys(snap.menus).length}`);
|
|
246
250
|
for (const k of kept) say(` kept your unpushed changes in ${k}`);
|
|
251
|
+
if (heldBack.length) say(` ${heldBack.length} entr${heldBack.length === 1 ? 'y' : 'ies'} you removed here stay removed (the website still has them until \`push --prune\`)`);
|
|
247
252
|
}
|
|
248
253
|
|
|
249
254
|
/** The menus alone: files and the snapshot's menus, the entries untouched. */
|
|
@@ -339,6 +344,8 @@ async function push(ctx) {
|
|
|
339
344
|
process.exit(1);
|
|
340
345
|
}
|
|
341
346
|
say(`Pushed: ${r.content.created} created, ${r.content.updated} updated${r.images ? `, ${r.images} image${r.images === 1 ? '' : 's'} added` : ''}${r.images_reused ? `, ${r.images_reused} already in the library` : ''}${r.removed ? `, ${r.removed} removed` : ''}.`);
|
|
347
|
+
// Removed from the website now: the folder stops holding them back.
|
|
348
|
+
if (removeKeys.length) { const rem = readRemoved(ctx.dir); for (const k of removeKeys) rem.delete(k); writeRemoved(ctx.dir, rem); }
|
|
342
349
|
if (r.missing?.length) say(`Not found to remove: ${r.missing.map((m) => `${m.collection}/${m.slug}`).join(', ')}`);
|
|
343
350
|
}
|
|
344
351
|
for (const name of menus) {
|
|
@@ -363,7 +370,7 @@ async function shot(ctx, target = positional[0] ?? '/', opts = {}) {
|
|
|
363
370
|
// --desktop, --mobile, --tablet, --wide, any of them together; --all for every width; none = desktop and mobile.
|
|
364
371
|
const picked = ['desktop', 'mobile', 'tablet', 'wide'].filter((v) => flags[v]);
|
|
365
372
|
const view = flags.all ? 'all' : picked.length ? picked.join(',') : (opts.view ?? 'both');
|
|
366
|
-
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' }) };
|
|
373
|
+
const args = { site_id: ctx.cfg.site, view, full_page: !(flags['first-screen'] || opts.firstScreen), ...openStates(), ...(isUrl ? { url: target } : { path: target, site: flags.live ? 'live' : 'preview' }) };
|
|
367
374
|
const { json, images } = await tool(ctx.cfg, 'screenshot_website', args);
|
|
368
375
|
const outDir = join(ctx.dir, META, 'shots');
|
|
369
376
|
mkdirSync(outDir, { recursive: true });
|
|
@@ -382,13 +389,23 @@ async function shot(ctx, target = positional[0] ?? '/', opts = {}) {
|
|
|
382
389
|
if (!images.length) say(json ? JSON.stringify(json).slice(0, 500) : 'No image came back.');
|
|
383
390
|
}
|
|
384
391
|
|
|
392
|
+
/** What a shot or a measure opens first: --menu (every navigation menu), --open <selector,...> (clicked), --hover <selector,...> (their submenus shown). */
|
|
393
|
+
function openStates() {
|
|
394
|
+
const list = (v) => (v ? String(v).split(',').map((x) => x.trim()).filter(Boolean) : []);
|
|
395
|
+
const out = {};
|
|
396
|
+
if (flags.menu) out.menu = true;
|
|
397
|
+
if (flags.open) out.open = list(flags.open);
|
|
398
|
+
if (flags.hover) out.hover = list(flags.hover);
|
|
399
|
+
return out;
|
|
400
|
+
}
|
|
401
|
+
|
|
385
402
|
/** The computed type and boxes of a page, old or new, at one or several widths: the numbers a port styles to. */
|
|
386
403
|
async function measure(ctx) {
|
|
387
404
|
const target = positional[0] ?? '/';
|
|
388
405
|
const isUrl = /^https?:\/\//.test(target);
|
|
389
406
|
const picked = ['desktop', 'mobile', 'tablet', 'wide'].filter((v) => flags[v]);
|
|
390
407
|
const view = flags.all ? 'all' : picked.length ? picked.join(',') : 'desktop';
|
|
391
|
-
const args = { site_id: ctx.cfg.site, view, ...(isUrl ? { url: target } : { path: target, site: flags.live ? 'live' : 'preview' }) };
|
|
408
|
+
const args = { site_id: ctx.cfg.site, view, ...openStates(), ...(isUrl ? { url: target } : { path: target, site: flags.live ? 'live' : 'preview' }) };
|
|
392
409
|
const { json } = await tool(ctx.cfg, 'measure_website', args);
|
|
393
410
|
if (!json?.views) fail('No measurements came back.');
|
|
394
411
|
const outDir = join(ctx.dir, META, 'measures');
|
|
@@ -556,12 +573,21 @@ function rmCmd({ dir }) {
|
|
|
556
573
|
const f = join(colDir, `${sl}.${ext}`);
|
|
557
574
|
if (existsSync(f)) { rmSync(f); hit = true; }
|
|
558
575
|
}
|
|
559
|
-
if (hit) { removed++; say(`- ${collection}/${sl}`); } else say(`${collection}/${sl}: no such entry file`);
|
|
576
|
+
if (hit) { removed++; say(`- ${collection}/${sl}`); rememberRemoved(dir, `${collection}/${sl}`); } else say(`${collection}/${sl}: no such entry file`);
|
|
560
577
|
}
|
|
561
578
|
}
|
|
562
579
|
say(`${removed} entr${removed === 1 ? 'y' : 'ies'} removed from the folder; \`tidysites push --prune\` removes them from the website.`);
|
|
563
580
|
}
|
|
564
581
|
|
|
582
|
+
/**
|
|
583
|
+
* Entries removed here and not yet pruned from the website. A pull (the one after a failed push included) does not
|
|
584
|
+
* write them back; `push --prune` removes them from the website and forgets them. The list lives beside the snapshot.
|
|
585
|
+
*/
|
|
586
|
+
const REMOVED_FILE = 'removed.json';
|
|
587
|
+
function readRemoved(dir) { return new Set(readJson(join(dir, META, REMOVED_FILE)) ?? []); }
|
|
588
|
+
function writeRemoved(dir, set) { writeFileSync(join(dir, META, REMOVED_FILE), JSON.stringify([...set].sort(), null, '\t')); }
|
|
589
|
+
function rememberRemoved(dir, key) { const s = readRemoved(dir); s.add(key); writeRemoved(dir, s); }
|
|
590
|
+
|
|
565
591
|
async function publish(ctx) {
|
|
566
592
|
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`.');
|
|
567
593
|
// A website live on the client's own domain is never published from here: the website refuses (409 live_domain) and says who may.
|
package/package.json
CHANGED