@domandigital/craft 0.18.2 → 0.19.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/CHANGELOG.md +13 -0
- package/CHARACTER.md +77 -6
- package/README.md +1 -1
- package/STANDARD.md +48 -18
- package/dist/{audit-4SFSLCKY.js → audit-43PC4LMS.js} +3 -3
- package/dist/audit.cjs +24 -3
- package/dist/audit.d.cts +30 -1
- package/dist/audit.d.ts +30 -1
- package/dist/audit.js +24 -3
- package/dist/{chunk-DARKHE6A.js → chunk-37ARRJAD.js} +18 -7
- package/dist/{chunk-6TSDYETQ.js → chunk-4LJFZH2I.js} +29 -2
- package/dist/{chunk-4QWEAL4G.js → chunk-CZ7KT452.js} +93 -1
- package/dist/{chunk-O5B5ELJH.js → chunk-DUUDGR56.js} +14 -13
- package/dist/{chunk-NTIPJ5U7.js → chunk-OKVHWXYV.js} +3 -3
- package/dist/{chunk-ZUYERAFM.js → chunk-ORFILP5L.js} +5 -5
- package/dist/{chunk-RJVG5KA6.js → chunk-P37LLKL4.js} +38 -10
- package/dist/{chunk-SL5VZJ2J.js → chunk-VDUIIWG7.js} +3 -2
- package/dist/{chunk-WFB6F3BN.js → chunk-WK2WMWTH.js} +107 -9
- package/dist/{cli-GXIW7F3E.js → cli-3P44X6E3.js} +6 -6
- package/dist/{cli-JZRQBCD4.js → cli-4D7Q5BCE.js} +6 -6
- package/dist/{cli-MDW7JTEF.js → cli-7OUA6ZSE.js} +6 -6
- package/dist/{cli-V44QEVS6.js → cli-AACBHRUG.js} +10 -10
- package/dist/{cli-BN4IT6N2.js → cli-L3VGKWZH.js} +4 -4
- package/dist/{cli-Y7Y5IROK.js → cli-TH76ATN3.js} +5 -5
- package/dist/{cli-JB4X5LAG.js → cli-VPARW6FY.js} +1 -1
- package/dist/cli.js +3 -3
- package/dist/index.cjs +279 -14
- package/dist/index.d.cts +111 -10
- package/dist/index.d.ts +111 -10
- package/dist/index.js +267 -14
- package/licences.json +27 -0
- package/package.json +1 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
snapshotUrl,
|
|
3
3
|
snapshotUrls
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-VDUIIWG7.js";
|
|
5
5
|
import {
|
|
6
6
|
describeTypicality,
|
|
7
7
|
loadNull
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-ORFILP5L.js";
|
|
9
9
|
import {
|
|
10
10
|
SOURCE_FILE,
|
|
11
11
|
finish,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
parseFlags,
|
|
15
15
|
prepareReport,
|
|
16
16
|
readPaths
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-DUUDGR56.js";
|
|
18
18
|
import {
|
|
19
19
|
toJson
|
|
20
20
|
} from "./chunk-QIEDBL4J.js";
|
|
@@ -25,9 +25,10 @@ import {
|
|
|
25
25
|
auditSnapshot,
|
|
26
26
|
componentTypicalities,
|
|
27
27
|
fingerprint,
|
|
28
|
+
rhythmOf,
|
|
28
29
|
scanSource,
|
|
29
30
|
typicality
|
|
30
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-WK2WMWTH.js";
|
|
31
32
|
|
|
32
33
|
// src/audit/cli.ts
|
|
33
34
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -69,9 +70,17 @@ function describeFingerprint(fp) {
|
|
|
69
70
|
` roundness ${fp.roundness === null ? "no buttons" : fp.roundness.toFixed(2)}`,
|
|
70
71
|
` motion ${Math.round(fp.motion * 100)}% of sections below the fold reveal on scroll`,
|
|
71
72
|
` effects ${fp.effects.join(", ") || "none"}`,
|
|
72
|
-
` layout ${fp.layout.join(" > ") || "none"}
|
|
73
|
+
` layout ${fp.layout.join(" > ") || "none"}`,
|
|
74
|
+
` rhythm ${rhythmOf(fp)?.join(" > ") ?? "not measured: sections carry no backgrounds before snapshot version 2"}`,
|
|
75
|
+
` hero ${describeHero(fp)}`
|
|
73
76
|
].join("\n");
|
|
74
77
|
}
|
|
78
|
+
function describeHero(fp) {
|
|
79
|
+
if (!fp.hero) return "none";
|
|
80
|
+
const section = fp.sections?.find((s) => s.role === "hero");
|
|
81
|
+
const parts = [section ? section.centred >= 0.5 ? "centred" : "left-aligned" : null, fp.hero.headline ? `${fp.hero.headline.class} headline at ${Math.round(fp.hero.headline.sizePx)}px` : "no headline", fp.hero.image ? fp.hero.image === "none" ? "no picture" : fp.hero.image === "full" ? "full-width picture" : `picture ${fp.hero.image}` : null];
|
|
82
|
+
return parts.filter((p) => p !== null).join(", ");
|
|
83
|
+
}
|
|
75
84
|
function merge(a, b) {
|
|
76
85
|
const byTell = { ...a.summary.byTell };
|
|
77
86
|
for (const [k, v] of Object.entries(b.summary.byTell)) byTell[k] = (byTell[k] ?? 0) + v;
|
|
@@ -126,18 +135,20 @@ async function runAudit(command, args, io) {
|
|
|
126
135
|
if (flags.pages && target) throw new Error("give a page or --pages, not both");
|
|
127
136
|
if (!target && !flags.pages) throw new Error(`usage: craft ${command} <url${command === "audit" ? " | snapshot.json> | --pages <sitemap.xml | urls.txt>" : ">"}`);
|
|
128
137
|
const viewports = viewportsOf(flags);
|
|
138
|
+
if (flags.scheme && flags.scheme !== "light" && flags.scheme !== "dark") throw new Error("--scheme takes light or dark");
|
|
139
|
+
const colorScheme = flags.scheme;
|
|
129
140
|
const audited = [];
|
|
130
141
|
const failed = [];
|
|
131
142
|
const local = target ? resolve(io.cwd, target) : "";
|
|
132
143
|
if (target && command === "audit" && /\.json$/i.test(target) && existsSync(local)) {
|
|
133
144
|
audited.push({ url: target, viewport: null, snapshot: readSnapshotFile(local) });
|
|
134
145
|
} else if (target && viewports.length === 1) {
|
|
135
|
-
const snapshot = await snapshotUrl(target, { viewport: viewports[0] });
|
|
146
|
+
const snapshot = await snapshotUrl(target, { viewport: viewports[0], colorScheme });
|
|
136
147
|
audited.push({ url: target, viewport: viewports[0] ?? null, snapshot });
|
|
137
148
|
} else {
|
|
138
149
|
const urls = flags.pages ? await resolvePages(flags.pages, io.cwd) : [target];
|
|
139
150
|
for (const viewport of viewports) {
|
|
140
|
-
for (const r of await snapshotUrls(urls, { viewport })) {
|
|
151
|
+
for (const r of await snapshotUrls(urls, { viewport, colorScheme })) {
|
|
141
152
|
if (r.snapshot) audited.push({ url: r.url, viewport: viewport ?? null, snapshot: r.snapshot });
|
|
142
153
|
else failed.push({ url: r.url, viewport: viewport ?? null, error: r.error ?? "no snapshot" });
|
|
143
154
|
}
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
levenshtein,
|
|
11
11
|
normaliseFamily,
|
|
12
12
|
parseColour
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-WK2WMWTH.js";
|
|
14
14
|
import {
|
|
15
15
|
TRADE_NOUNS
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-CZ7KT452.js";
|
|
17
17
|
|
|
18
18
|
// src/direction/types.ts
|
|
19
19
|
var DIRECTION_VERSION = 2;
|
|
@@ -541,6 +541,33 @@ var LICENCES = [
|
|
|
541
541
|
checked: "2026-09-24",
|
|
542
542
|
source: "https://iconscout.com/licenses",
|
|
543
543
|
note: "Each licence covers a single end product. Never in a tool, template or shared kit (create-site, craft, a house component library), even modified. Record the assets each site uses. Assets come from different contributors, so take one site's set from one contributor."
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
name: "Saira Semi Condensed",
|
|
547
|
+
subject: "face",
|
|
548
|
+
licence: "OFL-1.1",
|
|
549
|
+
multiClient: "yes",
|
|
550
|
+
checked: "2026-10-09",
|
|
551
|
+
source: "https://github.com/google/fonts/blob/main/ofl/sairasemicondensed/OFL.txt",
|
|
552
|
+
note: "Copyright 2016 The Saira Project Authors (omnibus.type@gmail.com), reserved font name Saira. Keep the OFL notice with the font files; a modified build may not be called Saira. Chosen for Doman Digital's own site (DOM-397, 9 October 2026)."
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
name: "Public Sans",
|
|
556
|
+
subject: "face",
|
|
557
|
+
licence: "OFL-1.1",
|
|
558
|
+
multiClient: "yes",
|
|
559
|
+
checked: "2026-10-09",
|
|
560
|
+
source: "https://github.com/google/fonts/blob/main/ofl/publicsans/OFL.txt",
|
|
561
|
+
note: "Copyright 2015 The Public Sans Project Authors (https://github.com/uswds/public-sans). Keep the OFL notice with the font files. Chosen for Doman Digital's own site (DOM-397, 9 October 2026)."
|
|
562
|
+
},
|
|
563
|
+
{
|
|
564
|
+
name: "Martian Mono",
|
|
565
|
+
subject: "face",
|
|
566
|
+
licence: "OFL-1.1",
|
|
567
|
+
multiClient: "yes",
|
|
568
|
+
checked: "2026-10-09",
|
|
569
|
+
source: "https://github.com/google/fonts/blob/main/ofl/martianmono/OFL.txt",
|
|
570
|
+
note: "Copyright 2021 The Martian Mono Project Authors (https://github.com/evilmartians/mono). Keep the OFL notice with the font files. Chosen for Doman Digital's own site (DOM-397, 9 October 2026)."
|
|
544
571
|
}
|
|
545
572
|
];
|
|
546
573
|
function faceLicence(family) {
|
|
@@ -263,8 +263,100 @@ function markupParts(file) {
|
|
|
263
263
|
function textNodeIsProse(body) {
|
|
264
264
|
return /[a-zA-Z]{2,}/.test(body) && /\s/.test(body.trim()) || /[a-zA-Z]{4,}[.!?]/.test(body);
|
|
265
265
|
}
|
|
266
|
+
var FRONT_MATTER_PROSE = /* @__PURE__ */ new Set(["title", "description"]);
|
|
267
|
+
var KEY_LINE = /^(\s*)(?:-\s+)?([A-Za-z][\w-]*)[ \t]*:[ \t]*/;
|
|
268
|
+
var BLOCK_SCALAR = /^(?:[|>][+-]?\d*|[|>]\d+[+-]?)$/;
|
|
269
|
+
function readFrontKey(line) {
|
|
270
|
+
const m = KEY_LINE.exec(line);
|
|
271
|
+
if (!m) return null;
|
|
272
|
+
return { indent: m[1].length, name: m[2], valueAt: m[0].length, value: line.slice(m[0].length) };
|
|
273
|
+
}
|
|
274
|
+
function indentOf(line) {
|
|
275
|
+
let i = 0;
|
|
276
|
+
while (i < line.length && (line[i] === " " || line[i] === " ")) i += 1;
|
|
277
|
+
return i;
|
|
278
|
+
}
|
|
279
|
+
function commentAt(value) {
|
|
280
|
+
if (value.startsWith("#")) return 0;
|
|
281
|
+
const found = /[ \t]+#/.exec(value);
|
|
282
|
+
return found ? found.index : -1;
|
|
283
|
+
}
|
|
284
|
+
function keepSpan(line, from, to) {
|
|
285
|
+
const start = Math.max(0, Math.min(from, line.length));
|
|
286
|
+
const end = Math.max(start, Math.min(to, line.length));
|
|
287
|
+
return " ".repeat(start) + line.slice(start, end) + " ".repeat(line.length - end);
|
|
288
|
+
}
|
|
289
|
+
function quoteEnd(line, from, quote) {
|
|
290
|
+
for (let i = from; i < line.length; i += 1) {
|
|
291
|
+
if (quote === '"' && line[i] === "\\") {
|
|
292
|
+
i += 1;
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
if (quote === "'" && line[i] === "'" && line[i + 1] === "'") {
|
|
296
|
+
i += 1;
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
if (line[i] === quote) return i;
|
|
300
|
+
}
|
|
301
|
+
return -1;
|
|
302
|
+
}
|
|
303
|
+
function maskFrontMatter(block) {
|
|
304
|
+
const lines = block.split("\n");
|
|
305
|
+
const out = lines.map((line) => blank(line));
|
|
306
|
+
for (let i = 1; i < lines.length; ) {
|
|
307
|
+
const line = lines[i];
|
|
308
|
+
if (line === "---" || line === "...") break;
|
|
309
|
+
const key = readFrontKey(line);
|
|
310
|
+
if (!key || !FRONT_MATTER_PROSE.has(key.name.toLowerCase())) {
|
|
311
|
+
i += 1;
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
const quote = key.value.startsWith('"') ? '"' : key.value.startsWith("'") ? "'" : "";
|
|
315
|
+
if (quote) {
|
|
316
|
+
let cursor = key.valueAt + 1;
|
|
317
|
+
while (i < lines.length && lines[i] !== "---" && lines[i] !== "...") {
|
|
318
|
+
const current = lines[i];
|
|
319
|
+
const end = quoteEnd(current, cursor, quote);
|
|
320
|
+
out[i] = keepSpan(current, cursor, end === -1 ? current.length : end);
|
|
321
|
+
i += 1;
|
|
322
|
+
cursor = 0;
|
|
323
|
+
if (end !== -1) break;
|
|
324
|
+
}
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
const hash = commentAt(key.value);
|
|
328
|
+
const body = (hash === -1 ? key.value : key.value.slice(0, hash)).trim();
|
|
329
|
+
if (BLOCK_SCALAR.test(body)) {
|
|
330
|
+
i += 1;
|
|
331
|
+
while (i < lines.length && lines[i] !== "---" && lines[i] !== "...") {
|
|
332
|
+
const current = lines[i];
|
|
333
|
+
if (current.trim() !== "" && indentOf(current) <= key.indent) break;
|
|
334
|
+
if (current.trim()) out[i] = current;
|
|
335
|
+
i += 1;
|
|
336
|
+
}
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
if (body === "" || body === "~" || /^null$/i.test(body) || body.startsWith("[") || body.startsWith("{")) {
|
|
340
|
+
i += 1;
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
out[i] = keepSpan(line, key.valueAt, hash === -1 ? line.length : key.valueAt + hash);
|
|
344
|
+
i += 1;
|
|
345
|
+
while (i < lines.length && lines[i] !== "---" && lines[i] !== "...") {
|
|
346
|
+
const current = lines[i];
|
|
347
|
+
if (current.trim() === "" || indentOf(current) <= key.indent) break;
|
|
348
|
+
if (!/^\s*#/.test(current)) {
|
|
349
|
+
const cut = commentAt(current);
|
|
350
|
+
out[i] = cut === -1 ? current : keepSpan(current, 0, cut);
|
|
351
|
+
}
|
|
352
|
+
i += 1;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
const masked = out.join("\n");
|
|
356
|
+
return masked.length === block.length ? masked : blank(block);
|
|
357
|
+
}
|
|
266
358
|
function proseBlocks(file) {
|
|
267
|
-
const masked = file.text.replace(/^(```|~~~)[\s\S]*?^\1/gm, blank).replace(/`[^`\n]*`/g, (m) => " ".repeat(m.length)).replace(/^---\n[\s\S]*?\n---\n/,
|
|
359
|
+
const masked = file.text.replace(/^(```|~~~)[\s\S]*?^\1/gm, blank).replace(/`[^`\n]*`/g, (m) => " ".repeat(m.length)).replace(/^---\n[\s\S]*?\n---\n/, (block) => maskFrontMatter(block)).replace(/<!--[\s\S]*?-->/g, blank);
|
|
268
360
|
return [{ path: file.path, text: masked, offset: 0 }];
|
|
269
361
|
}
|
|
270
362
|
function isData(path) {
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
holdHouseBlocks,
|
|
11
11
|
houseRule,
|
|
12
12
|
scanSource
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-WK2WMWTH.js";
|
|
14
14
|
import {
|
|
15
15
|
compareCompetitor,
|
|
16
16
|
compareFacts,
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
pageCopy,
|
|
22
22
|
protectedFacts,
|
|
23
23
|
visibleText
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-CZ7KT452.js";
|
|
25
25
|
|
|
26
26
|
// src/character/config.ts
|
|
27
27
|
var DEFAULT_IGNORE = [".claude", ".agents", ".cursor"];
|
|
@@ -482,7 +482,8 @@ var VALUE_FLAGS = {
|
|
|
482
482
|
"--component": "component",
|
|
483
483
|
"--competitor": "competitor",
|
|
484
484
|
"--page": "page",
|
|
485
|
-
"--builder": "builder"
|
|
485
|
+
"--builder": "builder",
|
|
486
|
+
"--scheme": "scheme"
|
|
486
487
|
};
|
|
487
488
|
function parseFlags(args) {
|
|
488
489
|
const flags = { positional: [], json: false, strict: false, staged: false, gate: false, updateBaseline: false, directions: false, visual: false, fresh: false };
|
|
@@ -600,7 +601,7 @@ async function pageSnapshot(target, cwd) {
|
|
|
600
601
|
return readSnapshot(JSON.parse(readFileSync(local, "utf8")), target);
|
|
601
602
|
}
|
|
602
603
|
if (!/^https?:\/\//.test(target)) throw new Error(`${target} is neither a URL nor a snapshot file`);
|
|
603
|
-
const { snapshotUrl } = await import("./audit-
|
|
604
|
+
const { snapshotUrl } = await import("./audit-43PC4LMS.js");
|
|
604
605
|
return snapshotUrl(target);
|
|
605
606
|
}
|
|
606
607
|
async function briefFor(flags, cwd) {
|
|
@@ -611,7 +612,7 @@ async function briefFor(flags, cwd) {
|
|
|
611
612
|
if (typeof brief === "string" && brief.trim()) return brief;
|
|
612
613
|
} else if (flags.direction) throw new Error(`no such file: ${flags.direction}`);
|
|
613
614
|
if (flags.null) {
|
|
614
|
-
const { loadNull } = await import("./cli-
|
|
615
|
+
const { loadNull } = await import("./cli-L3VGKWZH.js");
|
|
615
616
|
return loadNull(flags.null, cwd).brief;
|
|
616
617
|
}
|
|
617
618
|
return void 0;
|
|
@@ -637,31 +638,31 @@ async function compareWithCompetitor(flags, io) {
|
|
|
637
638
|
function run(argv, io) {
|
|
638
639
|
const [command, ...rest] = argv;
|
|
639
640
|
if (command === "direction") {
|
|
640
|
-
return import("./cli-
|
|
641
|
+
return import("./cli-TH76ATN3.js").then((m) => m.runDirection(rest, io));
|
|
641
642
|
}
|
|
642
643
|
if (command === "report" || command === "retrofit") {
|
|
643
|
-
return import("./cli-
|
|
644
|
+
return import("./cli-AACBHRUG.js").then((m) => m.runReport(command, rest, io));
|
|
644
645
|
}
|
|
645
646
|
if (command === "register") {
|
|
646
|
-
return import("./cli-
|
|
647
|
+
return import("./cli-VPARW6FY.js").then((m) => m.runRegister(rest, io));
|
|
647
648
|
}
|
|
648
649
|
if (command === "estate") {
|
|
649
|
-
return import("./cli-
|
|
650
|
+
return import("./cli-3P44X6E3.js").then((m) => m.runEstate(rest, io));
|
|
650
651
|
}
|
|
651
652
|
if (command === "null") {
|
|
652
|
-
return import("./cli-
|
|
653
|
+
return import("./cli-L3VGKWZH.js").then((m) => m.runNull(rest, io));
|
|
653
654
|
}
|
|
654
655
|
if (command === "calibrate") {
|
|
655
|
-
return import("./cli-
|
|
656
|
+
return import("./cli-7OUA6ZSE.js").then((m) => m.runCalibrate(rest, io));
|
|
656
657
|
}
|
|
657
658
|
if (command === "tells" && rest[0] === "harvest") {
|
|
658
|
-
return import("./cli-
|
|
659
|
+
return import("./cli-L3VGKWZH.js").then((m) => m.runHarvest(rest, io)).catch((error) => {
|
|
659
660
|
io.err(`craft: ${error.message}`);
|
|
660
661
|
return 2;
|
|
661
662
|
});
|
|
662
663
|
}
|
|
663
664
|
if (command === "snapshot" || command === "audit") {
|
|
664
|
-
return import("./cli-
|
|
665
|
+
return import("./cli-4D7Q5BCE.js").then((m) => m.runAudit(command, rest, io));
|
|
665
666
|
}
|
|
666
667
|
if (!command || command === "help" || command === "--help" || command === "-h") {
|
|
667
668
|
io.out(HELP);
|
|
@@ -33,7 +33,7 @@ var PART_AREA = {
|
|
|
33
33
|
effects: { area: "effects", choice: "motif" },
|
|
34
34
|
motion: { area: "motion", choice: "signature" }
|
|
35
35
|
};
|
|
36
|
-
var DEFAULTS = /^(?:ground )?(?:white|grey)(?: ground)?$|no scroll reveals|no reveals|accent (?:none|neutral)|^no buttons|shape no buttons
|
|
36
|
+
var DEFAULTS = /^(?:ground )?(?:white|grey|light)(?: ground)?$|no scroll reveals|no reveals|accent (?:none|neutral)|^no buttons|shape no buttons|^light page throughout$/;
|
|
37
37
|
function designFindings(findings, copyTells) {
|
|
38
38
|
return (findings?.findings ?? []).filter((f) => !copyTells.has(f.tell));
|
|
39
39
|
}
|
|
@@ -140,7 +140,7 @@ function areaOfShared(part) {
|
|
|
140
140
|
if (/accent|ground/.test(part)) return "colour";
|
|
141
141
|
if (/buttons/.test(part)) return "shape";
|
|
142
142
|
if (/reveal/.test(part)) return "motion";
|
|
143
|
-
if (/running order/.test(part)) return "layout";
|
|
143
|
+
if (/running order|hero|page throughout/.test(part)) return "layout";
|
|
144
144
|
return "effects";
|
|
145
145
|
}
|
|
146
146
|
function choiceOfShared(part) {
|
|
@@ -150,7 +150,7 @@ function choiceOfShared(part) {
|
|
|
150
150
|
if (/ground/.test(part)) return "ground";
|
|
151
151
|
if (/buttons/.test(part)) return "shape";
|
|
152
152
|
if (/reveal/.test(part)) return "signature";
|
|
153
|
-
return /running order/.test(part) ? void 0 : "motif";
|
|
153
|
+
return /running order|hero|page throughout/.test(part) ? void 0 : "motif";
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
export {
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-OQXTQQAU.js";
|
|
4
4
|
import {
|
|
5
5
|
parseFlags
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-DUUDGR56.js";
|
|
7
7
|
import {
|
|
8
8
|
toJson
|
|
9
9
|
} from "./chunk-QIEDBL4J.js";
|
|
@@ -22,10 +22,10 @@ import {
|
|
|
22
22
|
hueSwatch,
|
|
23
23
|
nullPrompt,
|
|
24
24
|
scanSource
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-WK2WMWTH.js";
|
|
26
26
|
import {
|
|
27
27
|
extractStrings
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-CZ7KT452.js";
|
|
29
29
|
|
|
30
30
|
// src/null/cli.ts
|
|
31
31
|
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from "fs";
|
|
@@ -120,7 +120,7 @@ async function build(flags, io) {
|
|
|
120
120
|
const toShoot = ids.filter((id) => existsSync(join(pages, `${id}.html`)) && !existsSync(join(shots, `${id}.json`)));
|
|
121
121
|
if (toShoot.length) {
|
|
122
122
|
io.out(`craft null: snapshotting ${toShoot.length} page${toShoot.length === 1 ? "" : "s"}`);
|
|
123
|
-
const { snapshotUrls } = await import("./audit-
|
|
123
|
+
const { snapshotUrls } = await import("./audit-43PC4LMS.js");
|
|
124
124
|
const results = await snapshotUrls(toShoot.map((id) => pathToFileURL(join(pages, `${id}.html`)).href));
|
|
125
125
|
results.forEach((r, i) => {
|
|
126
126
|
const id = toShoot[i];
|
|
@@ -241,7 +241,7 @@ async function importPages(flags, io) {
|
|
|
241
241
|
const toShoot = pages.filter((p) => !existsSync(join(shots, `${p.id}.json`)));
|
|
242
242
|
if (toShoot.length) {
|
|
243
243
|
io.out(`craft null: snapshotting ${toShoot.length} page${toShoot.length === 1 ? "" : "s"} from ${flags.builder}`);
|
|
244
|
-
const { snapshotUrls } = await import("./audit-
|
|
244
|
+
const { snapshotUrls } = await import("./audit-43PC4LMS.js");
|
|
245
245
|
const servers = /* @__PURE__ */ new Map();
|
|
246
246
|
try {
|
|
247
247
|
for (const p of toShoot) if (!servers.has(p.root)) servers.set(p.root, await serveDir(p.root));
|
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
formatDirectionMatches,
|
|
5
5
|
summariseDirection,
|
|
6
6
|
validateDirection
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-4LJFZH2I.js";
|
|
8
8
|
import {
|
|
9
9
|
loadNull
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-ORFILP5L.js";
|
|
11
11
|
import {
|
|
12
12
|
parseFlags
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-DUUDGR56.js";
|
|
14
14
|
import {
|
|
15
15
|
toJson
|
|
16
16
|
} from "./chunk-QIEDBL4J.js";
|
|
@@ -25,10 +25,12 @@ import {
|
|
|
25
25
|
estateComponentPairs,
|
|
26
26
|
fingerprint,
|
|
27
27
|
fingerprintDistance,
|
|
28
|
-
|
|
28
|
+
groundLabel,
|
|
29
29
|
hueName,
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
rhythmOf,
|
|
31
|
+
shapeName,
|
|
32
|
+
temperatureName
|
|
33
|
+
} from "./chunk-WK2WMWTH.js";
|
|
32
34
|
|
|
33
35
|
// src/estate/cli.ts
|
|
34
36
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -45,19 +47,45 @@ function addSite(register, site) {
|
|
|
45
47
|
const sites = [...register.sites.filter((s) => s.id !== site.id), site].sort((a, b) => a.id.localeCompare(b.id));
|
|
46
48
|
return { version: ESTATE_VERSION, sites };
|
|
47
49
|
}
|
|
50
|
+
function sharedGround(a, b) {
|
|
51
|
+
const [x, y] = [groundLabel(a.ground), groundLabel(b.ground)];
|
|
52
|
+
if (x === y) return `${x} ground`;
|
|
53
|
+
const temperature = temperatureName(a.ground);
|
|
54
|
+
if (temperature !== "neutral" && temperature === temperatureName(b.ground)) return `${temperature} ground`;
|
|
55
|
+
return `${a.ground.l < 0.3 ? "dark" : "light"} ground`;
|
|
56
|
+
}
|
|
57
|
+
function sharedRhythm(a, b) {
|
|
58
|
+
const bands = rhythmOf(a) ?? [];
|
|
59
|
+
const word = (band) => band;
|
|
60
|
+
if (bands.length <= 1) return `${bands[0] ? word(bands[0]) : "light"} page throughout`;
|
|
61
|
+
const second = bands[1] === "mid" ? "mid-tone band" : `${word(bands[1])} band`;
|
|
62
|
+
return `${word(bands[0])} hero then ${second}`;
|
|
63
|
+
}
|
|
64
|
+
function sharedHero(a, b) {
|
|
65
|
+
const hero = a.sections?.find((s) => s.role === "hero");
|
|
66
|
+
const placement = hero && hero.centred >= 0.5 ? "centred" : "left-aligned";
|
|
67
|
+
const headline = a.hero?.headline && b.hero?.headline && a.hero.headline.class === b.hero.headline.class ? `${a.hero.headline.class} ` : "";
|
|
68
|
+
const image = a.hero?.image && a.hero.image === b.hero?.image && a.hero.image !== "none" ? `, ${a.hero.image === "full" ? "full-width picture" : `photo ${a.hero.image}`}` : "";
|
|
69
|
+
return `${placement} ${headline}hero${image}`;
|
|
70
|
+
}
|
|
48
71
|
function sharedParts(a, b, d = fingerprintDistance(a, b)) {
|
|
49
72
|
const out = [];
|
|
50
|
-
const close = (k) =>
|
|
73
|
+
const close = (k) => {
|
|
74
|
+
const p = d.parts[k];
|
|
75
|
+
return p !== null && p <= SHARED_PART;
|
|
76
|
+
};
|
|
51
77
|
if (close("accent")) out.push(a.accent || b.accent ? `${hueName(a.accent)} accent` : "no accent");
|
|
52
78
|
if (close("type")) {
|
|
53
79
|
if (a.display.family === b.display.family) out.push(`${a.display.family} headline`);
|
|
54
80
|
if (a.body.family === b.body.family) out.push(`${a.body.family} body`);
|
|
55
81
|
}
|
|
56
|
-
if (close("ground")) out.push(
|
|
82
|
+
if (close("ground")) out.push(sharedGround(a, b));
|
|
57
83
|
if (close("shape")) out.push(`${shapeName(a.roundness)} buttons`);
|
|
58
84
|
if (close("motion")) out.push(a.motion > 0 || b.motion > 0 ? "scroll reveals" : "no reveals");
|
|
59
85
|
if (close("effects") && a.effects.length) out.push(a.effects.filter((e) => b.effects.includes(e)).join(", "));
|
|
60
|
-
if (close("
|
|
86
|
+
if (close("hero")) out.push(sharedHero(a, b));
|
|
87
|
+
if (close("rhythm")) out.push(sharedRhythm(a, b));
|
|
88
|
+
if (close("layout")) out.push("same running order");
|
|
61
89
|
return out;
|
|
62
90
|
}
|
|
63
91
|
function compareToEstate(target, register, options = {}) {
|
|
@@ -105,7 +133,7 @@ async function snapshotOf(target, cwd) {
|
|
|
105
133
|
return snap;
|
|
106
134
|
}
|
|
107
135
|
if (!/^https?:\/\//.test(target)) throw new Error(`${target} is neither a URL, a snapshot file, nor a site in the register`);
|
|
108
|
-
const { snapshotUrl } = await import("./audit-
|
|
136
|
+
const { snapshotUrl } = await import("./audit-43PC4LMS.js");
|
|
109
137
|
return snapshotUrl(target);
|
|
110
138
|
}
|
|
111
139
|
var line = (distance, sibling, shared) => `${distance.toFixed(2)}${sibling ? " SIBLING" : ""}${shared.length ? ` shares ${shared.join(", ")}` : ""}`;
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
auditSnapshot,
|
|
6
6
|
fingerprint
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-WK2WMWTH.js";
|
|
8
8
|
import {
|
|
9
9
|
SNAPSHOT_VERSION
|
|
10
10
|
} from "./chunk-QYBAVU3P.js";
|
|
@@ -505,6 +505,7 @@ function collectInPage() {
|
|
|
505
505
|
width: Math.round(b.width),
|
|
506
506
|
height: Math.round(b.height),
|
|
507
507
|
top: Math.round(b.top),
|
|
508
|
+
left: Math.round(b.left),
|
|
508
509
|
role: roleOfImage(el, src, b.width, b.height, alt),
|
|
509
510
|
alt,
|
|
510
511
|
decorative,
|
|
@@ -752,7 +753,7 @@ async function snapshotUrls(urls, options = {}) {
|
|
|
752
753
|
const out = [];
|
|
753
754
|
try {
|
|
754
755
|
for (const url of urls) {
|
|
755
|
-
const page = await browser.newPage({ viewport: options.viewport ?? { width: 1440, height: 900 } });
|
|
756
|
+
const page = await browser.newPage({ viewport: options.viewport ?? { width: 1440, height: 900 }, ...options.colorScheme ? { colorScheme: options.colorScheme } : {} });
|
|
756
757
|
try {
|
|
757
758
|
const response = await page.goto(url, { waitUntil: "domcontentloaded", timeout: options.timeoutMs ?? 45e3 });
|
|
758
759
|
const status = typeof response?.status === "function" ? response.status() : 200;
|