mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-17 16:46:31 +03:00
Add new design context document
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { cp, copyFile, mkdir, rm } from 'node:fs/promises';
|
||||
import { cp, copyFile, mkdir, rm, writeFile } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { ANTIPATTERNS } from '../cli/engine/registry/antipatterns.mjs';
|
||||
import { composeHookRules } from './lib/hook-rule-presentation.js';
|
||||
|
||||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const buildDir = path.join(root, 'build-picker');
|
||||
@@ -16,6 +18,10 @@ const outputDir = path.join(root, 'skill/scripts/picker');
|
||||
const assetsSource = path.join(root, 'picker/assets');
|
||||
const assetsOutput = path.join(outputDir, 'assets');
|
||||
const runtimeAssets = ['hero-dark.jpg', 'kinpaku-gold-leaf.jpg'];
|
||||
// The design context document's images, vendored from the standalone demo:
|
||||
// per-section foil icons, the rail textures, the brand-asset placeholders, and
|
||||
// the components photo. Whole directories, so a demo re-sync stays a plain copy.
|
||||
const runtimeAssetDirs = ['audience', 'product', 'brand', 'color', 'typography', 'material', 'components'];
|
||||
// The page links ./favicon.svg, so it is also served from the output root.
|
||||
const faviconSource = path.join(assetsSource, 'favicon.svg');
|
||||
const faviconOutput = path.join(outputDir, 'favicon.svg');
|
||||
@@ -26,6 +32,13 @@ const iconDataSource = path.join(root, 'picker/data/icon-packs.json');
|
||||
const iconDataOutput = path.join(outputDir, 'icon-packs.json');
|
||||
|
||||
await rm(buildDir, { recursive: true, force: true });
|
||||
// The Hooks page's rule list, composed from the canonical detector registry so
|
||||
// the document never drifts from what the hook actually enforces. Committed and
|
||||
// regenerated every build; tests/hook-rule-presentation.test.js guards the sync.
|
||||
await writeFile(
|
||||
path.join(root, 'picker/data/hook-rules.json'),
|
||||
`${JSON.stringify(composeHookRules(ANTIPATTERNS), null, 2)}\n`,
|
||||
);
|
||||
execFileSync(
|
||||
'bun',
|
||||
['x', 'astro', 'build', '--config', 'picker/astro.config.mjs'],
|
||||
@@ -40,6 +53,9 @@ await copyFile(iconDataSource, iconDataOutput);
|
||||
for (const asset of runtimeAssets) {
|
||||
await copyFile(path.join(assetsSource, asset), path.join(assetsOutput, asset));
|
||||
}
|
||||
for (const dir of runtimeAssetDirs) {
|
||||
await cp(path.join(assetsSource, dir), path.join(assetsOutput, dir), { recursive: true });
|
||||
}
|
||||
await rm(buildDir, { recursive: true, force: true });
|
||||
|
||||
console.log(`Built ${path.relative(root, outputDir)}/`);
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
Presentation metadata for the Hooks page of the design context document.
|
||||
|
||||
The rule ids, names, and descriptions come from the canonical registry
|
||||
(cli/engine/registry/antipatterns.mjs); this module adds only how the document
|
||||
groups and labels them. `FINGERPRINT_IDS` promotes a handful of slop rules into
|
||||
their own "Fingerprints" family (model-specific signatures); `DISCIPLINES` gives
|
||||
every rule a discipline label for the collapsible groups. Both must cover the
|
||||
registry exactly — tests/hook-rule-presentation.test.js fails the suite when a
|
||||
rule is added without a discipline, so the document can never silently miss one.
|
||||
*/
|
||||
|
||||
export const FINGERPRINT_IDS = new Set([
|
||||
'gpt-thin-border-wide-shadow',
|
||||
'repeating-stripes-gradient',
|
||||
'codex-grid-background',
|
||||
'theater-slop-phrase',
|
||||
]);
|
||||
|
||||
export const DISCIPLINES = {
|
||||
'side-tab': 'Visual Details',
|
||||
'border-accent-on-rounded': 'Visual Details',
|
||||
'overused-font': 'Typography',
|
||||
'flat-type-hierarchy': 'Typography',
|
||||
'gradient-text': 'Color & Contrast',
|
||||
'ai-color-palette': 'Color & Contrast',
|
||||
'cream-palette': 'Color & Contrast',
|
||||
'nested-cards': 'Layout & Space',
|
||||
'monotonous-spacing': 'Layout & Space',
|
||||
'bounce-easing': 'Motion',
|
||||
'pulsing-dot': 'Motion',
|
||||
'blinking-cursor': 'Motion',
|
||||
'shape-assembled-illustration': 'Imagery',
|
||||
'dark-glow': 'Color & Contrast',
|
||||
'radial-halo': 'Color & Contrast',
|
||||
'radial-spotlight-glow': 'Color & Contrast',
|
||||
'marquee': 'Motion',
|
||||
'icon-tile-stack': 'Typography',
|
||||
'italic-serif-display': 'Typography',
|
||||
'hero-eyebrow-chip': 'Typography',
|
||||
'kicker-above-heading': 'Typography',
|
||||
'numbered-section-labels': 'Layout & Space',
|
||||
'em-dash-overuse': 'Copy',
|
||||
'marketing-buzzword': 'Copy',
|
||||
'aphoristic-cadence': 'Copy',
|
||||
'oversized-h1': 'Typography',
|
||||
'extreme-negative-tracking': 'Typography',
|
||||
'broken-image': 'Imagery',
|
||||
'script-error': 'Quality',
|
||||
'content-hidden-at-rest': 'Layout & Space',
|
||||
'edge-flush-cards': 'Layout & Space',
|
||||
'text-occlusion': 'Layout & Space',
|
||||
'first-viewport-column-overflow': 'Layout & Space',
|
||||
'gray-on-color': 'Color & Contrast',
|
||||
'low-contrast': 'Quality',
|
||||
'layout-transition': 'Motion',
|
||||
'line-length': 'Layout & Space',
|
||||
'cramped-padding': 'Layout & Space',
|
||||
'body-text-viewport-edge': 'Layout & Space',
|
||||
'tight-leading': 'Typography',
|
||||
'skipped-heading': 'Typography',
|
||||
'heading-rhythm': 'Layout & Space',
|
||||
'justified-text': 'Typography',
|
||||
'tiny-text': 'Typography',
|
||||
'undersized-ui-text': 'Typography',
|
||||
'all-caps-body': 'Typography',
|
||||
'wide-tracking': 'Typography',
|
||||
'text-overflow': 'Layout & Space',
|
||||
'repeated-container-text': 'Quality',
|
||||
'clipped-overflow-container': 'Layout & Space',
|
||||
'design-system-font': 'Typography',
|
||||
'design-system-color': 'Color & Contrast',
|
||||
'design-system-radius': 'Visual Details',
|
||||
'design-system-font-size': 'Typography',
|
||||
'gpt-thin-border-wide-shadow': 'Visual Details',
|
||||
'repeating-stripes-gradient': 'Visual Details',
|
||||
'codex-grid-background': 'Visual Details',
|
||||
'theater-slop-phrase': 'Copy',
|
||||
'image-hover-transform': 'Motion',
|
||||
};
|
||||
|
||||
/* One entry per registry rule, in registry order, in the exact shape the
|
||||
document's Hooks module renders. */
|
||||
export function composeHookRules(antipatterns) {
|
||||
return antipatterns.map((rule) => ({
|
||||
id: rule.id,
|
||||
name: rule.name,
|
||||
description: rule.description,
|
||||
group: FINGERPRINT_IDS.has(rule.id) ? 'fingerprints' : rule.category,
|
||||
discipline: DISCIPLINES[rule.id],
|
||||
}));
|
||||
}
|
||||
@@ -48,6 +48,7 @@ export const SUITES = {
|
||||
'tests/validate-plugin-versions.test.js',
|
||||
'tests/validate-plugin-manifest.test.js',
|
||||
'tests/plugin-paths.test.js',
|
||||
'tests/hook-rule-presentation.test.js',
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user