kss-modern 1.3.0-beta.0 → 1.3.0-beta.2
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 +1 -1
- package/dist/node/lib/index.d.mts +1 -1
- package/dist/node/lib/index.d.ts +1 -1
- package/dist/node/lib/index.mjs +280 -104
- package/dist/styleguide-assets/.vite/manifest.json +29 -13
- package/dist/styleguide-assets/a11y-report-BgeWSrYe.js +186 -0
- package/dist/styleguide-assets/{clipboard-BUvXbiCa.js → clipboard-CHYspHPs.js} +1 -1
- package/dist/styleguide-assets/fullpage-D-fU_bAa.js +913 -0
- package/dist/styleguide-assets/{html-validator-BGApR8VB.js → html-validator-DJGwslsw.js} +99 -105
- package/dist/styleguide-assets/{icons-C6KKEuT_.js → icons-Cip2t08v.js} +1 -1
- package/dist/styleguide-assets/kss-modern-BJ971T05.css +3 -0
- package/dist/styleguide-assets/{preview-BNQ_kTZ_.js → preview-DEipbLLB.js} +8 -7
- package/dist/styleguide-assets/section-previews-D-Mr2eVX.js +49 -0
- package/dist/styleguide-assets/{utils-DrMb1LbR.js → utils-DtB-AzJa.js} +3 -3
- package/package.json +1 -1
- package/dist/styleguide-assets/fullpage-DpAT8aw3.js +0 -385
- package/dist/styleguide-assets/kss-modern-Bw6-exnr.css +0 -3
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ A modern, KSS-compatible styleguide generator. Parses KSS comment blocks from CS
|
|
|
9
9
|
- Pug template support via worker thread pool
|
|
10
10
|
- Color palette and icon gallery documentation
|
|
11
11
|
- Figma embed integration with light/dark theme sync
|
|
12
|
-
- Accessibility auditing (axe-core) and HTML validation
|
|
12
|
+
- Accessibility auditing (axe-core) and HTML validation, per component or page-wide via `window.kssAudit()` for CI and AI agents
|
|
13
13
|
- Markdown descriptions with custom components (alerts, accordions)
|
|
14
14
|
- Dark mode with three-way toggle (System/Light/Dark)
|
|
15
15
|
- Global search, keyboard navigation, and "Open in Editor" links
|
package/dist/node/lib/index.d.ts
CHANGED
package/dist/node/lib/index.mjs
CHANGED
|
@@ -16,11 +16,11 @@ import githubLightDefault from '@shikijs/themes/github-light-default';
|
|
|
16
16
|
import MarkdownItAsync from 'markdown-it-async';
|
|
17
17
|
import { createHighlighterCore } from 'shiki/core';
|
|
18
18
|
import { createJavaScriptRegexEngine } from 'shiki/engine/javascript';
|
|
19
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
19
20
|
import os from 'node:os';
|
|
20
21
|
import { Worker } from 'node:worker_threads';
|
|
21
22
|
import fs$1 from 'node:fs/promises';
|
|
22
23
|
import { objectEntries } from '@antfu/utils';
|
|
23
|
-
import { readFileSync } from 'node:fs';
|
|
24
24
|
import chokidar from 'chokidar';
|
|
25
25
|
import 'pug';
|
|
26
26
|
import 'consola';
|
|
@@ -217,6 +217,9 @@ function escape(str) {
|
|
|
217
217
|
return String(str).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
218
218
|
}
|
|
219
219
|
const when = (condition, content) => condition ? content() : "";
|
|
220
|
+
function attrs(obj) {
|
|
221
|
+
return Object.entries(obj).filter(([, value]) => value !== null && value !== void 0 && value !== false).map(([key, value]) => value === true ? key : `${key}="${value}"`).join(" ");
|
|
222
|
+
}
|
|
220
223
|
|
|
221
224
|
const alertRenderer = (bodyContent, props) => {
|
|
222
225
|
const type = props.type || "info";
|
|
@@ -390,7 +393,7 @@ function shiftHeadingLevels(markdownContent, rootHeadingLevel) {
|
|
|
390
393
|
}
|
|
391
394
|
return markdownContent;
|
|
392
395
|
}
|
|
393
|
-
|
|
396
|
+
function getMarkdownRenderer() {
|
|
394
397
|
if (!md) {
|
|
395
398
|
md = MarkdownItAsync({ linkify: true, typographer: true });
|
|
396
399
|
md.use(markdownItComponent, {
|
|
@@ -411,6 +414,29 @@ async function parseMarkdown(data) {
|
|
|
411
414
|
)
|
|
412
415
|
);
|
|
413
416
|
}
|
|
417
|
+
return md;
|
|
418
|
+
}
|
|
419
|
+
const RENDER_CACHE_MAX_ENTRIES = 2e3;
|
|
420
|
+
const renderCache = /* @__PURE__ */ new Map();
|
|
421
|
+
async function renderMarkdownCached(source) {
|
|
422
|
+
const cached = renderCache.get(source);
|
|
423
|
+
if (cached !== void 0) {
|
|
424
|
+
return cached;
|
|
425
|
+
}
|
|
426
|
+
const promise = getMarkdownRenderer().renderAsync(source);
|
|
427
|
+
renderCache.set(source, promise);
|
|
428
|
+
promise.catch(() => {
|
|
429
|
+
if (renderCache.get(source) === promise)
|
|
430
|
+
renderCache.delete(source);
|
|
431
|
+
});
|
|
432
|
+
if (renderCache.size > RENDER_CACHE_MAX_ENTRIES) {
|
|
433
|
+
const oldest = renderCache.keys().next().value;
|
|
434
|
+
if (oldest !== void 0 && oldest !== source)
|
|
435
|
+
renderCache.delete(oldest);
|
|
436
|
+
}
|
|
437
|
+
return promise;
|
|
438
|
+
}
|
|
439
|
+
async function parseMarkdown(data) {
|
|
414
440
|
if ("filePath" in data) {
|
|
415
441
|
const doesFileExist = fs.existsSync(data.filePath);
|
|
416
442
|
if (!doesFileExist) {
|
|
@@ -419,12 +445,12 @@ async function parseMarkdown(data) {
|
|
|
419
445
|
}
|
|
420
446
|
let fileContent = await fs.readFile(data.filePath, "utf8");
|
|
421
447
|
fileContent = shiftHeadingLevels(fileContent, data.rootHeadingLevel);
|
|
422
|
-
const parsedMarkdown = await
|
|
448
|
+
const parsedMarkdown = await renderMarkdownCached(fileContent);
|
|
423
449
|
return parsedMarkdown;
|
|
424
450
|
} else {
|
|
425
451
|
let fileContent = data.markdownContent.replace("Markdown:", "");
|
|
426
452
|
fileContent = shiftHeadingLevels(fileContent, data.rootHeadingLevel);
|
|
427
|
-
return await
|
|
453
|
+
return await renderMarkdownCached(fileContent);
|
|
428
454
|
}
|
|
429
455
|
}
|
|
430
456
|
|
|
@@ -1038,8 +1064,17 @@ function getPugDependencyGraph() {
|
|
|
1038
1064
|
}
|
|
1039
1065
|
const __filename$1 = fileURLToPath(import.meta.url);
|
|
1040
1066
|
const __dirname$1 = path.dirname(__filename$1);
|
|
1041
|
-
|
|
1042
|
-
const
|
|
1067
|
+
function resolveWorkerFile() {
|
|
1068
|
+
const candidates = ["./worker.ts", "./worker.mjs", "./pug/worker.mjs"];
|
|
1069
|
+
for (const candidate of candidates) {
|
|
1070
|
+
const resolved = path.resolve(__dirname$1, candidate);
|
|
1071
|
+
if (existsSync(resolved))
|
|
1072
|
+
return resolved;
|
|
1073
|
+
}
|
|
1074
|
+
return void 0;
|
|
1075
|
+
}
|
|
1076
|
+
const workerFilePathResolved = resolveWorkerFile();
|
|
1077
|
+
let warnedMissingWorker = false;
|
|
1043
1078
|
const slots = Array.from({ length: MAX_POOL_SIZE }, () => ({ tail: Promise.resolve(), active: 0 }));
|
|
1044
1079
|
const allWorkers = /* @__PURE__ */ new Set();
|
|
1045
1080
|
function slotIndexFor(id) {
|
|
@@ -1051,6 +1086,8 @@ function slotIndexFor(id) {
|
|
|
1051
1086
|
return (hash >>> 0) % MAX_POOL_SIZE;
|
|
1052
1087
|
}
|
|
1053
1088
|
function spawnWorker(index) {
|
|
1089
|
+
if (!workerFilePathResolved)
|
|
1090
|
+
throw new Error("pug compile worker file could not be located");
|
|
1054
1091
|
const worker = new Worker(workerFilePathResolved, { name: `pug-worker-${index}` });
|
|
1055
1092
|
allWorkers.add(worker);
|
|
1056
1093
|
return worker;
|
|
@@ -1185,7 +1222,11 @@ async function compileIds(mode, contentDir, repository, ids) {
|
|
|
1185
1222
|
if (misses.length === 0)
|
|
1186
1223
|
return clonedRepository;
|
|
1187
1224
|
const errors = [];
|
|
1188
|
-
|
|
1225
|
+
if (!workerFilePathResolved && misses.length > INLINE_THRESHOLD && !warnedMissingWorker) {
|
|
1226
|
+
warnedMissingWorker = true;
|
|
1227
|
+
logger.warn("Pug compile worker not found; compiling markup on the main thread. Rebuilds stay correct but are slower.");
|
|
1228
|
+
}
|
|
1229
|
+
const useInline = !workerFilePathResolved || mode === "development" && misses.length <= INLINE_THRESHOLD;
|
|
1189
1230
|
if (useInline) {
|
|
1190
1231
|
await Promise.all(misses.map((id) => compileInline(mode, contentDir, clonedRepository, id, errors)));
|
|
1191
1232
|
} else {
|
|
@@ -1209,6 +1250,66 @@ async function compilePugMarkupIncremental(mode, contentDir, repository, ids) {
|
|
|
1209
1250
|
return compileIds(mode, contentDir, repository, wanted);
|
|
1210
1251
|
}
|
|
1211
1252
|
|
|
1253
|
+
function createRebuildQueue(handlers) {
|
|
1254
|
+
let isRunning = false;
|
|
1255
|
+
let isStructuralPending = false;
|
|
1256
|
+
const pendingMarkupFiles = /* @__PURE__ */ new Set();
|
|
1257
|
+
let idleResolvers = [];
|
|
1258
|
+
const hasPendingWork = () => isStructuralPending || pendingMarkupFiles.size > 0;
|
|
1259
|
+
const releaseIdleWaiters = () => {
|
|
1260
|
+
const resolvers = idleResolvers;
|
|
1261
|
+
idleResolvers = [];
|
|
1262
|
+
resolvers.forEach((resolve) => resolve());
|
|
1263
|
+
};
|
|
1264
|
+
const runNext = async () => {
|
|
1265
|
+
if (isStructuralPending) {
|
|
1266
|
+
isStructuralPending = false;
|
|
1267
|
+
pendingMarkupFiles.clear();
|
|
1268
|
+
await handlers.onStructural();
|
|
1269
|
+
return;
|
|
1270
|
+
}
|
|
1271
|
+
const changedFiles = [...pendingMarkupFiles];
|
|
1272
|
+
pendingMarkupFiles.clear();
|
|
1273
|
+
await handlers.onMarkup(changedFiles);
|
|
1274
|
+
};
|
|
1275
|
+
const drain = async () => {
|
|
1276
|
+
if (isRunning)
|
|
1277
|
+
return;
|
|
1278
|
+
isRunning = true;
|
|
1279
|
+
try {
|
|
1280
|
+
while (hasPendingWork()) {
|
|
1281
|
+
try {
|
|
1282
|
+
await runNext();
|
|
1283
|
+
} catch (error) {
|
|
1284
|
+
handlers.onError?.(error);
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
} finally {
|
|
1288
|
+
isRunning = false;
|
|
1289
|
+
releaseIdleWaiters();
|
|
1290
|
+
}
|
|
1291
|
+
};
|
|
1292
|
+
return {
|
|
1293
|
+
requestStructural: () => {
|
|
1294
|
+
isStructuralPending = true;
|
|
1295
|
+
void drain();
|
|
1296
|
+
},
|
|
1297
|
+
requestMarkup: (changedFiles) => {
|
|
1298
|
+
for (const file of changedFiles) {
|
|
1299
|
+
pendingMarkupFiles.add(file);
|
|
1300
|
+
}
|
|
1301
|
+
void drain();
|
|
1302
|
+
},
|
|
1303
|
+
whenIdle: () => {
|
|
1304
|
+
if (!isRunning && !hasPendingWork())
|
|
1305
|
+
return Promise.resolve();
|
|
1306
|
+
return new Promise((resolve) => {
|
|
1307
|
+
idleResolvers.push(resolve);
|
|
1308
|
+
});
|
|
1309
|
+
}
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1212
1313
|
const TRANSIENT_FS_ERROR_CODES = /* @__PURE__ */ new Set(["ENOENT", "EBUSY", "EPERM", "EACCES"]);
|
|
1213
1314
|
function isTransientFsError(error) {
|
|
1214
1315
|
if (typeof error !== "object" || error === null)
|
|
@@ -1253,7 +1354,7 @@ async function generateFullPageFile(data) {
|
|
|
1253
1354
|
<meta name="theme-color" media="(prefers-color-scheme: light)" content="${data.theme.light}">
|
|
1254
1355
|
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="${data.theme.dark}">
|
|
1255
1356
|
` : `<meta name="theme-color" content="${data.theme}">`}
|
|
1256
|
-
<script type="module" src="/styleguide-assets/fullpage-
|
|
1357
|
+
<script type="module" src="/styleguide-assets/fullpage-D-fU_bAa.js"><\/script>
|
|
1257
1358
|
${computedStyleTags}
|
|
1258
1359
|
</head>
|
|
1259
1360
|
<body${data.page.bodyclass ? ` class="${data.page.bodyclass}"` : ""}>
|
|
@@ -1265,6 +1366,9 @@ async function generateFullPageFile(data) {
|
|
|
1265
1366
|
await logicalWriteFile(data.filePath, content);
|
|
1266
1367
|
}
|
|
1267
1368
|
|
|
1369
|
+
function getSectionTitleLine(section) {
|
|
1370
|
+
return section.source.css.line + 1;
|
|
1371
|
+
}
|
|
1268
1372
|
function getHasSectionExternalFullpage(section) {
|
|
1269
1373
|
return section.markup.length > 0 && (section.icons === void 0 || section.icons.length === 0) && (section.colors === void 0 || section.colors.length === 0);
|
|
1270
1374
|
}
|
|
@@ -1540,10 +1644,17 @@ function getMainContentSectionWrapper(section, html) {
|
|
|
1540
1644
|
}
|
|
1541
1645
|
return `<p class="mt-2${section.sectionLevel === "second" ? " text-xl" : ""}">${section.description}</p>`;
|
|
1542
1646
|
};
|
|
1647
|
+
const sourceAttributes = attrs({
|
|
1648
|
+
"data-section-reference": sanitizeSpecialCharacters(section.id),
|
|
1649
|
+
"data-source-file": sanitizeSpecialCharacters(section.source.css.file),
|
|
1650
|
+
"data-source-line": getSectionTitleLine(section),
|
|
1651
|
+
"data-markup-file": section.source.markup?.file ? sanitizeSpecialCharacters(section.source.markup.file) : void 0
|
|
1652
|
+
});
|
|
1543
1653
|
return `
|
|
1544
|
-
<section
|
|
1545
|
-
id="section-${sectionSanitizeId(section.id)}"
|
|
1654
|
+
<section
|
|
1655
|
+
id="section-${sectionSanitizeId(section.id)}"
|
|
1546
1656
|
class="styleguide-section border-b px-4 py-10 border-b-styleguide-border scroll-mt-[50px] md:px-10"
|
|
1657
|
+
${sourceAttributes}
|
|
1547
1658
|
>
|
|
1548
1659
|
<div class="flex items-center justify-between gap-6">
|
|
1549
1660
|
<a class="relative group" href="#section-${sectionSanitizeId(section.id)}">
|
|
@@ -1580,7 +1691,7 @@ function getMainContentRegular(section, config) {
|
|
|
1580
1691
|
if (config.mode === "development" && config.launchInEditor) {
|
|
1581
1692
|
const computedRootPath = config.launchInEditor && typeof config.launchInEditor === "object" && "rootDir" in config.launchInEditor ? config.launchInEditor.rootDir : process.cwd();
|
|
1582
1693
|
const cssFilePath = ensureStartingSlash(path.join(computedRootPath, section.source.css.file));
|
|
1583
|
-
const cssLineNumber = section
|
|
1694
|
+
const cssLineNumber = getSectionTitleLine(section);
|
|
1584
1695
|
openInEditorPaths.css = {
|
|
1585
1696
|
vscode: `vscode://file//${cssFilePath}:${cssLineNumber}`,
|
|
1586
1697
|
phpstorm: `phpstorm://open?file=${cssFilePath}&line=${cssLineNumber}`
|
|
@@ -1602,7 +1713,7 @@ function getMainContentRegular(section, config) {
|
|
|
1602
1713
|
};
|
|
1603
1714
|
const renderOpenInEditorLink = (editorType, contentType, link) => `
|
|
1604
1715
|
<a
|
|
1605
|
-
class="hidden editor-${editorType}-only @md:inline-flex items-center group/${editorType} gap-1.5 p-4 desktop-device-only cursor-pointer active:scale-90 transition hover:text-styleguide-highlight duration-200"
|
|
1716
|
+
class="pointer-events-auto hidden editor-${editorType}-only @md:inline-flex items-center group/${editorType} gap-1.5 p-4 desktop-device-only cursor-pointer active:scale-90 transition hover:text-styleguide-highlight duration-200"
|
|
1606
1717
|
href="${link}"
|
|
1607
1718
|
>
|
|
1608
1719
|
<span class="hidden @2xl:inline-block">Open ${contentType}</span>
|
|
@@ -1635,47 +1746,59 @@ function getMainContentRegular(section, config) {
|
|
|
1635
1746
|
</div>
|
|
1636
1747
|
|
|
1637
1748
|
<!-- Code -->
|
|
1638
|
-
<
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1749
|
+
<div class="relative @container">
|
|
1750
|
+
<details class="group">
|
|
1751
|
+
<summary class="flex cursor-pointer items-center rounded-b-2xl px-6 text-sm font-light bg-styleguide-bg">
|
|
1752
|
+
<span class="flex gap-2 items-center py-4 select-none">
|
|
1753
|
+
<svg class="h-4 w-4 group-open:rotate-90 transition-transform" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor">
|
|
1754
|
+
<path fill-rule="evenodd" d="M6.22 4.22a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06-1.06L8.94 8 6.22 5.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd"/>
|
|
1755
|
+
</svg>
|
|
1756
|
+
|
|
1757
|
+
<span class="group-open:hidden">Show code</span>
|
|
1758
|
+
<span class="group-open:block hidden">Hide code</span>
|
|
1759
|
+
</span>
|
|
1760
|
+
</summary>
|
|
1761
|
+
|
|
1762
|
+
<div class="border-t p-6 text-sm bg-styleguide-bg-highlight border-styleguide-border">
|
|
1763
|
+
<div
|
|
1764
|
+
id="code-fullpage-${sectionSanitizeId(section.id)}"
|
|
1765
|
+
class="overflow-x-auto w-full code-highlight"
|
|
1766
|
+
data-source-code="${encodeURIComponent(sourceCode)}"
|
|
1767
|
+
data-source-lang="html"
|
|
1768
|
+
></div>
|
|
1769
|
+
</div>
|
|
1770
|
+
</details>
|
|
1644
1771
|
|
|
1645
|
-
|
|
1646
|
-
<span class="group-open:block hidden">Hide code</span>
|
|
1647
|
-
</span>
|
|
1648
|
-
|
|
1649
|
-
<span class="flex items-center">
|
|
1772
|
+
<span class="pointer-events-none absolute top-0 right-0 flex items-center pr-6 text-sm font-light">
|
|
1650
1773
|
${section.figma ? `<a
|
|
1651
|
-
class="inline-flex items-center group/figma gap-1.5 p-4 desktop-device-only cursor-pointer active:scale-90 transition hover:text-styleguide-highlight duration-200"
|
|
1774
|
+
class="pointer-events-auto inline-flex items-center group/figma gap-1.5 p-4 desktop-device-only cursor-pointer active:scale-90 transition hover:text-styleguide-highlight duration-200"
|
|
1652
1775
|
href="${computeFigmaExternalLink(section.figma)}"
|
|
1653
1776
|
target="_blank"
|
|
1654
1777
|
>
|
|
1655
1778
|
<span class="hidden @2xl:inline-block">Open in</span>
|
|
1656
1779
|
<span class="sr-only">Figma</span>
|
|
1657
|
-
<img
|
|
1780
|
+
<img
|
|
1658
1781
|
src="styleguide-assets/icons/figma.svg"
|
|
1659
|
-
width="600"
|
|
1660
|
-
height="600"
|
|
1661
|
-
class="size-4 saturate-0 group-hover/figma:saturate-100 transition"
|
|
1662
|
-
alt="Figma Logo"
|
|
1663
|
-
aria-hidden="true"
|
|
1782
|
+
width="600"
|
|
1783
|
+
height="600"
|
|
1784
|
+
class="size-4 saturate-0 group-hover/figma:saturate-100 transition"
|
|
1785
|
+
alt="Figma Logo"
|
|
1786
|
+
aria-hidden="true"
|
|
1664
1787
|
>
|
|
1665
1788
|
</a>` : ""}
|
|
1666
|
-
|
|
1789
|
+
|
|
1667
1790
|
${openInEditorPaths.html ? `
|
|
1668
1791
|
${renderOpenInEditorLink("phpstorm", openInEditorPaths.html.phpstorm.includes(".pug") ? "Pug" : "HTML", openInEditorPaths.html.phpstorm)}
|
|
1669
1792
|
${renderOpenInEditorLink("vscode", openInEditorPaths.html.phpstorm.includes(".pug") ? "Pug" : "HTML", openInEditorPaths.html.vscode)}
|
|
1670
1793
|
` : ""}
|
|
1671
|
-
|
|
1794
|
+
|
|
1672
1795
|
${openInEditorPaths.css ? `
|
|
1673
1796
|
${renderOpenInEditorLink("phpstorm", "CSS", openInEditorPaths.css.phpstorm)}
|
|
1674
1797
|
${renderOpenInEditorLink("vscode", "CSS", openInEditorPaths.css.vscode)}
|
|
1675
1798
|
` : ""}
|
|
1676
1799
|
|
|
1677
1800
|
<button
|
|
1678
|
-
class="inline-flex items-center gap-1.5 p-4 cursor-pointer active:scale-90 transition hover:text-styleguide-highlight duration-200"
|
|
1801
|
+
class="pointer-events-auto inline-flex items-center gap-1.5 p-4 cursor-pointer active:scale-90 transition hover:text-styleguide-highlight duration-200"
|
|
1679
1802
|
type="button"
|
|
1680
1803
|
data-clipboard-value="${encodeURIComponent(sourceCode)}"
|
|
1681
1804
|
data-clipboard-uri-encoded="true"
|
|
@@ -1690,7 +1813,7 @@ function getMainContentRegular(section, config) {
|
|
|
1690
1813
|
</button>
|
|
1691
1814
|
|
|
1692
1815
|
<button
|
|
1693
|
-
class="inline-flex items-center gap-1.5 p-4 cursor-pointer active:scale-90 transition hover:text-styleguide-highlight duration-200"
|
|
1816
|
+
class="pointer-events-auto inline-flex items-center gap-1.5 p-4 cursor-pointer active:scale-90 transition hover:text-styleguide-highlight duration-200"
|
|
1694
1817
|
type="button"
|
|
1695
1818
|
data-code-audit-iframe="preview-fullpage-${sectionSanitizeId(section.id)}"
|
|
1696
1819
|
aria-controls="code-audit-dialog"
|
|
@@ -1699,10 +1822,10 @@ function getMainContentRegular(section, config) {
|
|
|
1699
1822
|
<svg class="h-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 122.88 122.88" aria-hidden="true"><title>accessibility</title><path fill="currentcolor" d="M61.44,0A61.46,61.46,0,1,1,18,18,61.21,61.21,0,0,1,61.44,0Zm-.39,74.18L52.1,98.91a4.94,4.94,0,0,1-2.58,2.83A5,5,0,0,1,42.7,95.5l6.24-17.28a26.3,26.3,0,0,0,1.17-4,40.64,40.64,0,0,0,.54-4.18c.24-2.53.41-5.27.54-7.9s.22-5.18.29-7.29c.09-2.63-.62-2.8-2.73-3.3l-.44-.1-18-3.39A5,5,0,0,1,27.08,46a5,5,0,0,1,5.05-7.74l19.34,3.63c.77.07,1.52.16,2.31.25a57.64,57.64,0,0,0,7.18.53A81.13,81.13,0,0,0,69.9,42c.9-.1,1.75-.21,2.6-.29l18.25-3.42A5,5,0,0,1,94.5,39a5,5,0,0,1,1.3,7,5,5,0,0,1-3.21,2.09L75.15,51.37c-.58.13-1.1.22-1.56.29-1.82.31-2.72.47-2.61,3.06.08,1.89.31,4.15.61,6.51.35,2.77.81,5.71,1.29,8.4.31,1.77.6,3.19,1,4.55s.79,2.75,1.39,4.42l6.11,16.9a5,5,0,0,1-6.82,6.24,4.94,4.94,0,0,1-2.58-2.83L63,74.23,62,72.4l-1,1.78Zm.39-53.52a8.83,8.83,0,1,1-6.24,2.59,8.79,8.79,0,0,1,6.24-2.59Zm36.35,4.43a51.42,51.42,0,1,0,15,36.35,51.27,51.27,0,0,0-15-36.35Z"/></svg>
|
|
1700
1823
|
<span class="hidden md:inline-block">Audit</span>
|
|
1701
1824
|
</button>
|
|
1702
|
-
|
|
1825
|
+
|
|
1703
1826
|
${getHasSectionExternalFullpage(section) ? `
|
|
1704
1827
|
<a
|
|
1705
|
-
class="hidden [.styleguide-section--large_&]:inline-block -mr-2 px-2 py-4 group/externallink hover:text-styleguide-highlight focus:text-styleguide-highlight"
|
|
1828
|
+
class="pointer-events-auto hidden [.styleguide-section--large_&]:inline-block -mr-2 px-2 py-4 group/externallink hover:text-styleguide-highlight focus:text-styleguide-highlight"
|
|
1706
1829
|
href="/${section.fullpageFileName}"
|
|
1707
1830
|
target="_blank"
|
|
1708
1831
|
title="Open ${section.header} in fullpage"
|
|
@@ -1714,17 +1837,7 @@ function getMainContentRegular(section, config) {
|
|
|
1714
1837
|
</a>
|
|
1715
1838
|
` : ""}
|
|
1716
1839
|
</span>
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
<div class="border-t p-6 text-sm bg-styleguide-bg-highlight border-styleguide-border">
|
|
1720
|
-
<div
|
|
1721
|
-
id="code-fullpage-${sectionSanitizeId(section.id)}"
|
|
1722
|
-
class="overflow-x-auto w-full code-highlight"
|
|
1723
|
-
data-source-code="${encodeURIComponent(sourceCode)}"
|
|
1724
|
-
data-source-lang="html"
|
|
1725
|
-
></div>
|
|
1726
|
-
</div>
|
|
1727
|
-
</details>
|
|
1840
|
+
</div>
|
|
1728
1841
|
</div>
|
|
1729
1842
|
|
|
1730
1843
|
${section.modifiers?.length > 0 ? `
|
|
@@ -2060,7 +2173,7 @@ async function generatePreviewFile(data) {
|
|
|
2060
2173
|
<meta name="theme-color" media="(prefers-color-scheme: light)" content="${data.theme.light}">
|
|
2061
2174
|
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="${data.theme.dark}">
|
|
2062
2175
|
` : `<meta name="theme-color" content="${data.theme}">`}
|
|
2063
|
-
<link rel="stylesheet" type="text/css" href="/styleguide-assets/kss-modern-
|
|
2176
|
+
<link rel="stylesheet" type="text/css" href="/styleguide-assets/kss-modern-BJ971T05.css">
|
|
2064
2177
|
<script>
|
|
2065
2178
|
//#region client/lib/iframe-resize.ts
|
|
2066
2179
|
var e = [
|
|
@@ -2223,7 +2336,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
2223
2336
|
//#endregion
|
|
2224
2337
|
;
|
|
2225
2338
|
<\/script>
|
|
2226
|
-
<script type="module" src="/styleguide-assets/preview-
|
|
2339
|
+
<script type="module" src="/styleguide-assets/preview-DEipbLLB.js"><\/script>
|
|
2227
2340
|
<link rel="preload" href="/styleguide-assets/fonts/geist-mono-latin-400-normal.woff2" as="font" type="font/woff2" crossorigin="anonymous">
|
|
2228
2341
|
<link rel="preload" href="/styleguide-assets/fonts/geist-mono-latin-600-normal.woff2" as="font" type="font/woff2" crossorigin="anonymous">
|
|
2229
2342
|
<link rel="preload" href="/styleguide-assets/fonts/geist-mono-latin-300-normal.woff2" as="font" type="font/woff2" crossorigin="anonymous">
|
|
@@ -2278,6 +2391,26 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
2278
2391
|
await logicalWriteFile(data.filePath, content);
|
|
2279
2392
|
}
|
|
2280
2393
|
|
|
2394
|
+
function batchDebounce(fn, windowMs) {
|
|
2395
|
+
let timer;
|
|
2396
|
+
let buffer = [];
|
|
2397
|
+
return (item) => {
|
|
2398
|
+
buffer.push(item);
|
|
2399
|
+
if (timer !== void 0) {
|
|
2400
|
+
clearTimeout(timer);
|
|
2401
|
+
}
|
|
2402
|
+
timer = setTimeout(() => {
|
|
2403
|
+
const batch = buffer;
|
|
2404
|
+
buffer = [];
|
|
2405
|
+
timer = void 0;
|
|
2406
|
+
fn(batch);
|
|
2407
|
+
}, windowMs);
|
|
2408
|
+
};
|
|
2409
|
+
}
|
|
2410
|
+
|
|
2411
|
+
const BATCH_SETTLE_MS = 300;
|
|
2412
|
+
const POLLING_INTERVAL_MS = 300;
|
|
2413
|
+
const USE_POLLING = process.env.FORCE_POLLING === "1" || existsSync("/.dockerenv") || existsSync("/run/.containerenv") || process.env.container !== void 0;
|
|
2281
2414
|
const VALID_CSS_FILE_TYPES = [".css", ".scss", ".sass", ".less"];
|
|
2282
2415
|
const MARKUP_FILE_TYPES = [".pug", ".html"];
|
|
2283
2416
|
function isCssFile(filePath) {
|
|
@@ -2308,11 +2441,33 @@ function tryReadFileSync(filePath) {
|
|
|
2308
2441
|
throw error;
|
|
2309
2442
|
}
|
|
2310
2443
|
}
|
|
2444
|
+
function planRebuilds(changes) {
|
|
2445
|
+
const structural = changes.some((change) => change.category === "structural");
|
|
2446
|
+
if (structural) {
|
|
2447
|
+
return { structural: true, markupFiles: [] };
|
|
2448
|
+
}
|
|
2449
|
+
const markupFiles = [...new Set(
|
|
2450
|
+
changes.filter((change) => change.category === "markup").map((change) => change.path)
|
|
2451
|
+
)];
|
|
2452
|
+
return { structural: false, markupFiles };
|
|
2453
|
+
}
|
|
2311
2454
|
function watchStyleguideForChanges(watchPath, handlers) {
|
|
2312
2455
|
if (typeof handlers.onStructuralChange !== "function" || typeof handlers.onMarkupChange !== "function") {
|
|
2313
2456
|
throw new TypeError("styleguide watch requires onStructuralChange and onMarkupChange callbacks");
|
|
2314
2457
|
}
|
|
2315
2458
|
const regexFileContents = /* @__PURE__ */ new Map();
|
|
2459
|
+
const dispatch = batchDebounce((changes) => {
|
|
2460
|
+
const { structural, markupFiles } = planRebuilds(changes);
|
|
2461
|
+
if (structural) {
|
|
2462
|
+
handlers.onStructuralChange();
|
|
2463
|
+
return;
|
|
2464
|
+
}
|
|
2465
|
+
if (markupFiles.length > 0) {
|
|
2466
|
+
handlers.onMarkupChange(markupFiles);
|
|
2467
|
+
}
|
|
2468
|
+
}, BATCH_SETTLE_MS);
|
|
2469
|
+
const requestStructural = () => dispatch({ category: "structural" });
|
|
2470
|
+
const requestMarkup = (filePath) => dispatch({ category: "markup", path: path.resolve(filePath) });
|
|
2316
2471
|
const handleCssAdd = (filePath) => {
|
|
2317
2472
|
const contents = tryReadFileSync(filePath);
|
|
2318
2473
|
if (contents === void 0)
|
|
@@ -2322,7 +2477,7 @@ function watchStyleguideForChanges(watchPath, handlers) {
|
|
|
2322
2477
|
return;
|
|
2323
2478
|
}
|
|
2324
2479
|
regexFileContents.set(filePath, currentFileMatches);
|
|
2325
|
-
|
|
2480
|
+
requestStructural();
|
|
2326
2481
|
};
|
|
2327
2482
|
const handleCssChange = (filePath) => {
|
|
2328
2483
|
const previousFileMatches = regexFileContents.get(filePath);
|
|
@@ -2336,47 +2491,48 @@ function watchStyleguideForChanges(watchPath, handlers) {
|
|
|
2336
2491
|
if (currentFileMatches === null) {
|
|
2337
2492
|
return;
|
|
2338
2493
|
}
|
|
2339
|
-
|
|
2494
|
+
requestStructural();
|
|
2340
2495
|
return;
|
|
2341
2496
|
}
|
|
2342
2497
|
if (matchArraysEqual(previousFileMatches, currentFileMatches)) {
|
|
2343
2498
|
return;
|
|
2344
2499
|
}
|
|
2345
2500
|
regexFileContents.set(filePath, currentFileMatches);
|
|
2346
|
-
|
|
2501
|
+
requestStructural();
|
|
2347
2502
|
};
|
|
2348
2503
|
const handleCssUnlink = (filePath) => {
|
|
2349
2504
|
regexFileContents.delete(filePath);
|
|
2350
|
-
|
|
2505
|
+
requestStructural();
|
|
2506
|
+
};
|
|
2507
|
+
const routeEvent = (filePath, handleCss) => {
|
|
2508
|
+
if (isCssFile(filePath))
|
|
2509
|
+
handleCss(filePath);
|
|
2510
|
+
else if (isMarkdownFile(filePath))
|
|
2511
|
+
requestStructural();
|
|
2512
|
+
else if (isMarkupFile(filePath))
|
|
2513
|
+
requestMarkup(filePath);
|
|
2351
2514
|
};
|
|
2352
2515
|
const validFileTypes = [...VALID_CSS_FILE_TYPES, ".md", ...MARKUP_FILE_TYPES];
|
|
2353
2516
|
return chokidar.watch(watchPath, {
|
|
2354
2517
|
ignoreInitial: true,
|
|
2518
|
+
usePolling: USE_POLLING,
|
|
2519
|
+
interval: POLLING_INTERVAL_MS,
|
|
2520
|
+
// Wait until a file has stopped being written before emitting — collapses the
|
|
2521
|
+
// multi-event sequence an atomic-save editor (JetBrains, vim with
|
|
2522
|
+
// backupcopy=auto) produces for a single save, and guarantees the read in the
|
|
2523
|
+
// CSS handlers sees complete content rather than a half-written file.
|
|
2524
|
+
awaitWriteFinish: {
|
|
2525
|
+
stabilityThreshold: 100,
|
|
2526
|
+
pollInterval: 20
|
|
2527
|
+
},
|
|
2355
2528
|
// @ts-expect-error - chokidar types seem to be incomplete, ignore
|
|
2356
2529
|
ignored: (filePath, stats) => {
|
|
2357
2530
|
return stats?.isFile() && !validFileTypes.some((type) => filePath.endsWith(type));
|
|
2358
2531
|
}
|
|
2359
|
-
}).on("add", (filePath) => {
|
|
2360
|
-
if (
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
handlers.onStructuralChange();
|
|
2364
|
-
else if (isMarkupFile(filePath))
|
|
2365
|
-
handlers.onMarkupChange(path.resolve(filePath));
|
|
2366
|
-
}).on("change", (filePath) => {
|
|
2367
|
-
if (isCssFile(filePath))
|
|
2368
|
-
handleCssChange(filePath);
|
|
2369
|
-
else if (isMarkdownFile(filePath))
|
|
2370
|
-
handlers.onStructuralChange();
|
|
2371
|
-
else if (isMarkupFile(filePath))
|
|
2372
|
-
handlers.onMarkupChange(path.resolve(filePath));
|
|
2373
|
-
}).on("unlink", (filePath) => {
|
|
2374
|
-
if (isCssFile(filePath))
|
|
2375
|
-
handleCssUnlink(filePath);
|
|
2376
|
-
else if (isMarkdownFile(filePath))
|
|
2377
|
-
handlers.onStructuralChange();
|
|
2378
|
-
else if (isMarkupFile(filePath))
|
|
2379
|
-
handlers.onMarkupChange(path.resolve(filePath));
|
|
2532
|
+
}).on("add", (filePath) => routeEvent(filePath, handleCssAdd)).on("change", (filePath) => routeEvent(filePath, handleCssChange)).on("unlink", (filePath) => routeEvent(filePath, handleCssUnlink)).on("error", (error) => {
|
|
2533
|
+
if (isTransientFsError(error))
|
|
2534
|
+
return;
|
|
2535
|
+
logger.error("Styleguide watcher error (ignored to keep the dev server running):", error);
|
|
2380
2536
|
});
|
|
2381
2537
|
}
|
|
2382
2538
|
|
|
@@ -2589,6 +2745,19 @@ async function buildContext(config) {
|
|
|
2589
2745
|
ownerLocationById
|
|
2590
2746
|
};
|
|
2591
2747
|
}
|
|
2748
|
+
const ASSETS_MARKER_FILE = ".kss-modern-assets";
|
|
2749
|
+
function getAssetsBuildId(theme) {
|
|
2750
|
+
return `kss-modern-BJ971T05.css
|
|
2751
|
+
${JSON.stringify(theme)}
|
|
2752
|
+
`;
|
|
2753
|
+
}
|
|
2754
|
+
async function readAssetsBuildId(markerPath) {
|
|
2755
|
+
try {
|
|
2756
|
+
return await fs.readFile(markerPath, "utf-8");
|
|
2757
|
+
} catch {
|
|
2758
|
+
return void 0;
|
|
2759
|
+
}
|
|
2760
|
+
}
|
|
2592
2761
|
async function copyStyleguideAssets(config) {
|
|
2593
2762
|
const __filename = fileURLToPath(import.meta.url);
|
|
2594
2763
|
const __dirname = path.dirname(__filename);
|
|
@@ -2600,11 +2769,16 @@ async function copyStyleguideAssets(config) {
|
|
|
2600
2769
|
};
|
|
2601
2770
|
const assetsDirectoryPath = findAssetsDirectoryPath();
|
|
2602
2771
|
const assetsDirectoryOutputPath = path.join(config.outDir, "styleguide-assets");
|
|
2603
|
-
const
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2772
|
+
const markerPath = path.join(assetsDirectoryOutputPath, ASSETS_MARKER_FILE);
|
|
2773
|
+
const expectedBuildId = getAssetsBuildId(config.theme);
|
|
2774
|
+
const currentBuildId = await readAssetsBuildId(markerPath);
|
|
2775
|
+
if (currentBuildId === expectedBuildId) {
|
|
2776
|
+
return;
|
|
2607
2777
|
}
|
|
2778
|
+
await fs.remove(assetsDirectoryOutputPath);
|
|
2779
|
+
await fs.copy(assetsDirectoryPath, assetsDirectoryOutputPath);
|
|
2780
|
+
await generateFaviconFiles(assetsDirectoryOutputPath, config.theme);
|
|
2781
|
+
await fs.writeFile(markerPath, expectedBuildId);
|
|
2608
2782
|
}
|
|
2609
2783
|
async function buildAll(config) {
|
|
2610
2784
|
if (config.mode === "production" && await fs.exists(config.outDir)) {
|
|
@@ -2700,35 +2874,37 @@ async function watchStyleguide(config, onChange, onError) {
|
|
|
2700
2874
|
}
|
|
2701
2875
|
let context = initialBuild.context;
|
|
2702
2876
|
const contentDirPath = config.contentDir.endsWith("/") ? config.contentDir : `${config.contentDir}/`;
|
|
2703
|
-
|
|
2704
|
-
// css/scss/md edits can change section structure -> full rebuild + fresh context
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
}
|
|
2714
|
-
})().catch((error) => {
|
|
2715
|
-
logger.error("Error during rebuild:", error);
|
|
2716
|
-
});
|
|
2877
|
+
const queue = createRebuildQueue({
|
|
2878
|
+
// css/scss/md/yaml edits can change section structure -> full rebuild + fresh context
|
|
2879
|
+
onStructural: async () => {
|
|
2880
|
+
const localBuild = await buildAll(config);
|
|
2881
|
+
context = localBuild.context;
|
|
2882
|
+
if (onChange)
|
|
2883
|
+
onChange({ type: "structural" });
|
|
2884
|
+
if (onError && localBuild.errors) {
|
|
2885
|
+
onError(localBuild.errors);
|
|
2886
|
+
}
|
|
2717
2887
|
},
|
|
2718
|
-
//
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2888
|
+
// .pug/.html source edits -> recompile + rewrite only the sections that depend on them
|
|
2889
|
+
onMarkup: async (changedFiles) => {
|
|
2890
|
+
const dependencyGraph = getPugDependencyGraph();
|
|
2891
|
+
const affected = [...new Set(
|
|
2892
|
+
changedFiles.flatMap((changedFile) => dependencyGraph.getAffectedSections(changedFile))
|
|
2893
|
+
)];
|
|
2894
|
+
if (affected.length === 0)
|
|
2895
|
+
return;
|
|
2896
|
+
await rebuildSections(config, context, affected);
|
|
2897
|
+
if (onChange)
|
|
2898
|
+
onChange({ type: "markup", files: changedFiles, sections: affected });
|
|
2899
|
+
},
|
|
2900
|
+
onError: (error) => {
|
|
2901
|
+
logger.error("Error during rebuild:", error);
|
|
2730
2902
|
}
|
|
2731
2903
|
});
|
|
2904
|
+
watchStyleguideForChanges(contentDirPath, {
|
|
2905
|
+
onStructuralChange: queue.requestStructural,
|
|
2906
|
+
onMarkupChange: queue.requestMarkup
|
|
2907
|
+
});
|
|
2732
2908
|
}
|
|
2733
2909
|
|
|
2734
2910
|
export { buildAll, buildStyleguide, logger, parseStyleguide, rebuildSections, watchStyleguide };
|