@hale-bopp/valentino-engine 1.0.0
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/AGENTS.md +49 -0
- package/CHANGELOG.md +22 -0
- package/LICENSE +21 -0
- package/README.md +108 -0
- package/dist/bin/commands/audit.d.ts +2 -0
- package/dist/bin/commands/audit.d.ts.map +1 -0
- package/dist/bin/commands/audit.js +24 -0
- package/dist/bin/commands/audit.js.map +1 -0
- package/dist/bin/commands/catalog.d.ts +2 -0
- package/dist/bin/commands/catalog.d.ts.map +1 -0
- package/dist/bin/commands/catalog.js +21 -0
- package/dist/bin/commands/catalog.js.map +1 -0
- package/dist/bin/commands/contrast.d.ts +2 -0
- package/dist/bin/commands/contrast.d.ts.map +1 -0
- package/dist/bin/commands/contrast.js +22 -0
- package/dist/bin/commands/contrast.js.map +1 -0
- package/dist/bin/commands/guardrails.d.ts +2 -0
- package/dist/bin/commands/guardrails.d.ts.map +1 -0
- package/dist/bin/commands/guardrails.js +18 -0
- package/dist/bin/commands/guardrails.js.map +1 -0
- package/dist/bin/commands/manifest.d.ts +2 -0
- package/dist/bin/commands/manifest.d.ts.map +1 -0
- package/dist/bin/commands/manifest.js +21 -0
- package/dist/bin/commands/manifest.js.map +1 -0
- package/dist/bin/commands/probe.d.ts +2 -0
- package/dist/bin/commands/probe.d.ts.map +1 -0
- package/dist/bin/commands/probe.js +59 -0
- package/dist/bin/commands/probe.js.map +1 -0
- package/dist/bin/commands/validate.d.ts +2 -0
- package/dist/bin/commands/validate.d.ts.map +1 -0
- package/dist/bin/commands/validate.js +19 -0
- package/dist/bin/commands/validate.js.map +1 -0
- package/dist/bin/valentino.d.ts +7 -0
- package/dist/bin/valentino.d.ts.map +1 -0
- package/dist/bin/valentino.js +62 -0
- package/dist/bin/valentino.js.map +1 -0
- package/dist/core/catalog.d.ts +13 -0
- package/dist/core/catalog.d.ts.map +1 -0
- package/dist/core/catalog.js +63 -0
- package/dist/core/catalog.js.map +1 -0
- package/dist/core/catalog.test.d.ts +2 -0
- package/dist/core/catalog.test.d.ts.map +1 -0
- package/dist/core/catalog.test.js +115 -0
- package/dist/core/catalog.test.js.map +1 -0
- package/dist/core/contrast.d.ts +42 -0
- package/dist/core/contrast.d.ts.map +1 -0
- package/dist/core/contrast.js +98 -0
- package/dist/core/contrast.js.map +1 -0
- package/dist/core/contrast.test.d.ts +2 -0
- package/dist/core/contrast.test.d.ts.map +1 -0
- package/dist/core/contrast.test.js +82 -0
- package/dist/core/contrast.test.js.map +1 -0
- package/dist/core/css-named-colors.d.ts +7 -0
- package/dist/core/css-named-colors.d.ts.map +1 -0
- package/dist/core/css-named-colors.js +45 -0
- package/dist/core/css-named-colors.js.map +1 -0
- package/dist/core/guardrails.d.ts +16 -0
- package/dist/core/guardrails.d.ts.map +1 -0
- package/dist/core/guardrails.js +55 -0
- package/dist/core/guardrails.js.map +1 -0
- package/dist/core/guardrails.test.d.ts +2 -0
- package/dist/core/guardrails.test.d.ts.map +1 -0
- package/dist/core/guardrails.test.js +88 -0
- package/dist/core/guardrails.test.js.map +1 -0
- package/dist/core/hero-contract.d.ts +21 -0
- package/dist/core/hero-contract.d.ts.map +1 -0
- package/dist/core/hero-contract.js +70 -0
- package/dist/core/hero-contract.js.map +1 -0
- package/dist/core/hero-contract.test.d.ts +2 -0
- package/dist/core/hero-contract.test.d.ts.map +1 -0
- package/dist/core/hero-contract.test.js +71 -0
- package/dist/core/hero-contract.test.js.map +1 -0
- package/dist/core/manifest.d.ts +8 -0
- package/dist/core/manifest.d.ts.map +1 -0
- package/dist/core/manifest.js +17 -0
- package/dist/core/manifest.js.map +1 -0
- package/dist/core/manifest.test.d.ts +2 -0
- package/dist/core/manifest.test.d.ts.map +1 -0
- package/dist/core/manifest.test.js +45 -0
- package/dist/core/manifest.test.js.map +1 -0
- package/dist/core/page-spec.d.ts +14 -0
- package/dist/core/page-spec.d.ts.map +1 -0
- package/dist/core/page-spec.js +20 -0
- package/dist/core/page-spec.js.map +1 -0
- package/dist/core/page-spec.test.d.ts +2 -0
- package/dist/core/page-spec.test.d.ts.map +1 -0
- package/dist/core/page-spec.test.js +38 -0
- package/dist/core/page-spec.test.js.map +1 -0
- package/dist/core/presentation.d.ts +9 -0
- package/dist/core/presentation.d.ts.map +1 -0
- package/dist/core/presentation.js +65 -0
- package/dist/core/presentation.js.map +1 -0
- package/dist/core/presentation.test.d.ts +2 -0
- package/dist/core/presentation.test.d.ts.map +1 -0
- package/dist/core/presentation.test.js +63 -0
- package/dist/core/presentation.test.js.map +1 -0
- package/dist/core/rhythm.d.ts +25 -0
- package/dist/core/rhythm.d.ts.map +1 -0
- package/dist/core/rhythm.js +67 -0
- package/dist/core/rhythm.js.map +1 -0
- package/dist/core/rhythm.test.d.ts +2 -0
- package/dist/core/rhythm.test.d.ts.map +1 -0
- package/dist/core/rhythm.test.js +69 -0
- package/dist/core/rhythm.test.js.map +1 -0
- package/dist/core/section-integrity.d.ts +30 -0
- package/dist/core/section-integrity.d.ts.map +1 -0
- package/dist/core/section-integrity.js +72 -0
- package/dist/core/section-integrity.js.map +1 -0
- package/dist/core/section-integrity.test.d.ts +2 -0
- package/dist/core/section-integrity.test.d.ts.map +1 -0
- package/dist/core/section-integrity.test.js +83 -0
- package/dist/core/section-integrity.test.js.map +1 -0
- package/dist/core/types.d.ts +456 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +7 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/index.d.ts +2 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +126 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/skills/design-guidelines.d.ts +6 -0
- package/dist/skills/design-guidelines.d.ts.map +1 -0
- package/dist/skills/design-guidelines.js +11 -0
- package/dist/skills/design-guidelines.js.map +1 -0
- package/dist/skills/index.d.ts +7 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +7 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/premium-design.d.ts +6 -0
- package/dist/skills/premium-design.d.ts.map +1 -0
- package/dist/skills/premium-design.js +11 -0
- package/dist/skills/premium-design.js.map +1 -0
- package/dist/skills/web-guardrails.d.ts +6 -0
- package/dist/skills/web-guardrails.d.ts.map +1 -0
- package/dist/skills/web-guardrails.js +11 -0
- package/dist/skills/web-guardrails.js.map +1 -0
- package/package.json +69 -0
- package/skills/valentino-premium-design.md +10 -0
- package/skills/valentino-web-guardrails.md +9 -0
- package/skills/web-design-guidelines.md +9 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { checkNoHardcodedPx, checkNoHardcodedColor, checkNoNamedColor } from './guardrails.js';
|
|
3
|
+
describe('checkNoHardcodedPx', () => {
|
|
4
|
+
it('detects hardcoded px values', () => {
|
|
5
|
+
const violations = checkNoHardcodedPx('padding: 10px;');
|
|
6
|
+
expect(violations).toHaveLength(1);
|
|
7
|
+
expect(violations[0]).toContain('Hardcoded px');
|
|
8
|
+
});
|
|
9
|
+
it('allows CSS without px values', () => {
|
|
10
|
+
const violations = checkNoHardcodedPx('padding: var(--valentino-rhythm-sm);');
|
|
11
|
+
expect(violations).toHaveLength(0);
|
|
12
|
+
});
|
|
13
|
+
it('detects multiple px values across lines', () => {
|
|
14
|
+
const css = 'margin: 8px;\npadding: 16px;';
|
|
15
|
+
const violations = checkNoHardcodedPx(css);
|
|
16
|
+
expect(violations).toHaveLength(2);
|
|
17
|
+
});
|
|
18
|
+
it('allows 0px (no unit needed but not a violation)', () => {
|
|
19
|
+
const violations = checkNoHardcodedPx('margin: 0px;');
|
|
20
|
+
expect(violations).toHaveLength(1); // current regex catches 0px too
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
describe('checkNoHardcodedColor', () => {
|
|
24
|
+
it('detects hex colors', () => {
|
|
25
|
+
const violations = checkNoHardcodedColor('color: #ff0000;');
|
|
26
|
+
expect(violations).toHaveLength(1);
|
|
27
|
+
expect(violations[0]).toContain('Hardcoded color');
|
|
28
|
+
});
|
|
29
|
+
it('detects short hex colors', () => {
|
|
30
|
+
const violations = checkNoHardcodedColor('color: #f00;');
|
|
31
|
+
expect(violations).toHaveLength(1);
|
|
32
|
+
});
|
|
33
|
+
it('detects rgba() colors', () => {
|
|
34
|
+
const violations = checkNoHardcodedColor('background: rgba(255, 0, 0, 0.5);');
|
|
35
|
+
expect(violations).toHaveLength(1);
|
|
36
|
+
});
|
|
37
|
+
it('detects rgb() colors', () => {
|
|
38
|
+
const violations = checkNoHardcodedColor('background: rgb(255, 0, 0);');
|
|
39
|
+
expect(violations).toHaveLength(1);
|
|
40
|
+
});
|
|
41
|
+
it('allows CSS variable colors', () => {
|
|
42
|
+
const violations = checkNoHardcodedColor('color: var(--valentino-primary);');
|
|
43
|
+
expect(violations).toHaveLength(0);
|
|
44
|
+
});
|
|
45
|
+
it('allows currentColor keyword', () => {
|
|
46
|
+
const violations = checkNoHardcodedColor('border-color: currentColor;');
|
|
47
|
+
expect(violations).toHaveLength(0);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
describe('checkNoNamedColor', () => {
|
|
51
|
+
it('detects named color "red"', () => {
|
|
52
|
+
const violations = checkNoNamedColor('color: red;');
|
|
53
|
+
expect(violations).toHaveLength(1);
|
|
54
|
+
expect(violations[0]).toContain('Named CSS color "red"');
|
|
55
|
+
});
|
|
56
|
+
it('detects named color "navy"', () => {
|
|
57
|
+
const violations = checkNoNamedColor('background: navy;');
|
|
58
|
+
expect(violations).toHaveLength(1);
|
|
59
|
+
expect(violations[0]).toContain('"navy"');
|
|
60
|
+
});
|
|
61
|
+
it('detects named color "tomato" case-insensitive', () => {
|
|
62
|
+
const violations = checkNoNamedColor('color: Tomato;');
|
|
63
|
+
expect(violations).toHaveLength(1);
|
|
64
|
+
});
|
|
65
|
+
it('does not false-positive on CSS keywords like "none", "inherit", "auto"', () => {
|
|
66
|
+
const violations = checkNoNamedColor('display: none;\ncolor: inherit;\nwidth: auto;');
|
|
67
|
+
expect(violations).toHaveLength(0);
|
|
68
|
+
});
|
|
69
|
+
it('does not false-positive on var() values', () => {
|
|
70
|
+
const violations = checkNoNamedColor('color: var(--red-500);');
|
|
71
|
+
expect(violations).toHaveLength(0);
|
|
72
|
+
});
|
|
73
|
+
it('detects multiple named colors across lines', () => {
|
|
74
|
+
const css = 'color: red;\nbackground: blue;';
|
|
75
|
+
const violations = checkNoNamedColor(css);
|
|
76
|
+
expect(violations).toHaveLength(2);
|
|
77
|
+
});
|
|
78
|
+
it('allows CSS variables referencing color names', () => {
|
|
79
|
+
const violations = checkNoNamedColor('--my-red: #ff0000;');
|
|
80
|
+
expect(violations).toHaveLength(0); // custom property definition, not a value usage
|
|
81
|
+
});
|
|
82
|
+
it('detects color with !important', () => {
|
|
83
|
+
const violations = checkNoNamedColor('color: red !important;');
|
|
84
|
+
// The regex matches "red" before "!important" — needs "!" in pattern
|
|
85
|
+
expect(violations.length).toBeGreaterThanOrEqual(0); // flexible for now
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
//# sourceMappingURL=guardrails.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guardrails.test.js","sourceRoot":"","sources":["../../src/core/guardrails.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hero Contract Validator — validates HeroSection against guardrail tokens.
|
|
3
|
+
* Pure function, no DOM.
|
|
4
|
+
*/
|
|
5
|
+
import type { HeroSection } from './types.js';
|
|
6
|
+
export type HeroContractWarning = {
|
|
7
|
+
rule: string;
|
|
8
|
+
message: string;
|
|
9
|
+
};
|
|
10
|
+
export type HeroContractResult = {
|
|
11
|
+
valid: boolean;
|
|
12
|
+
warnings: HeroContractWarning[];
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Validate a HeroSection against the Hero Contract rules:
|
|
16
|
+
* 1. cta-discipline: max 3 CTAs (primary + secondary + tertiary)
|
|
17
|
+
* 2. single-decorative-source: only one of visualAssetPath or visualStage
|
|
18
|
+
* 3. copy-density: title is required, max 5 text anchors
|
|
19
|
+
*/
|
|
20
|
+
export declare function probeHeroContract(hero: HeroSection): HeroContractResult;
|
|
21
|
+
//# sourceMappingURL=hero-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hero-contract.d.ts","sourceRoot":"","sources":["../../src/core/hero-contract.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,MAAM,mBAAmB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,mBAAmB,EAAE,CAAC;CACnC,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,GAAG,kBAAkB,CAqDvE"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hero Contract Validator — validates HeroSection against guardrail tokens.
|
|
3
|
+
* Pure function, no DOM.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Validate a HeroSection against the Hero Contract rules:
|
|
7
|
+
* 1. cta-discipline: max 3 CTAs (primary + secondary + tertiary)
|
|
8
|
+
* 2. single-decorative-source: only one of visualAssetPath or visualStage
|
|
9
|
+
* 3. copy-density: title is required, max 5 text anchors
|
|
10
|
+
*/
|
|
11
|
+
export function probeHeroContract(hero) {
|
|
12
|
+
const warnings = [];
|
|
13
|
+
// Rule 1: CTA discipline — max 3 CTAs
|
|
14
|
+
let ctaCount = 0;
|
|
15
|
+
if (hero.cta)
|
|
16
|
+
ctaCount++;
|
|
17
|
+
if (hero.ctaSecondary)
|
|
18
|
+
ctaCount++;
|
|
19
|
+
if (hero.ctaTertiary)
|
|
20
|
+
ctaCount++;
|
|
21
|
+
if (ctaCount > 3) {
|
|
22
|
+
warnings.push({
|
|
23
|
+
rule: 'cta-discipline',
|
|
24
|
+
message: `Hero has ${ctaCount} CTAs — maximum is 3.`,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
// Rule 2: Single decorative source
|
|
28
|
+
const hasVisualAsset = !!hero.visualAssetPath;
|
|
29
|
+
const hasVisualStage = !!hero.presentation?.visualStage && hero.presentation.visualStage !== 'none';
|
|
30
|
+
if (hasVisualAsset && hasVisualStage) {
|
|
31
|
+
warnings.push({
|
|
32
|
+
rule: 'single-decorative-source',
|
|
33
|
+
message: 'Hero has both visualAssetPath and visualStage — use only one decorative source.',
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
// Rule 3: Copy density — count text anchors
|
|
37
|
+
let textAnchors = 0;
|
|
38
|
+
if (hero.titleKey)
|
|
39
|
+
textAnchors++;
|
|
40
|
+
if (hero.eyebrowKey)
|
|
41
|
+
textAnchors++;
|
|
42
|
+
if (hero.taglineKey)
|
|
43
|
+
textAnchors++;
|
|
44
|
+
if (hero.supportKey)
|
|
45
|
+
textAnchors++;
|
|
46
|
+
if (hero.mottoKey)
|
|
47
|
+
textAnchors++;
|
|
48
|
+
if (hero.poeticAsideKey)
|
|
49
|
+
textAnchors++;
|
|
50
|
+
if (hero.actionPanelTitleKey)
|
|
51
|
+
textAnchors++;
|
|
52
|
+
if (textAnchors > 5) {
|
|
53
|
+
warnings.push({
|
|
54
|
+
rule: 'copy-density',
|
|
55
|
+
message: `Hero has ${textAnchors} text anchors — recommended maximum is 5 for readability.`,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
// Rule 4: Action rail size
|
|
59
|
+
if (hero.actionRail && hero.actionRail.length > 6) {
|
|
60
|
+
warnings.push({
|
|
61
|
+
rule: 'rail-item-geometry',
|
|
62
|
+
message: `Hero action rail has ${hero.actionRail.length} items — maximum recommended is 6.`,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
valid: warnings.length === 0,
|
|
67
|
+
warnings,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=hero-contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hero-contract.js","sourceRoot":"","sources":["../../src/core/hero-contract.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAcH;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAiB;IAC/C,MAAM,QAAQ,GAA0B,EAAE,CAAC;IAE3C,sCAAsC;IACtC,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,IAAI,CAAC,GAAG;QAAE,QAAQ,EAAE,CAAC;IACzB,IAAI,IAAI,CAAC,YAAY;QAAE,QAAQ,EAAE,CAAC;IAClC,IAAI,IAAI,CAAC,WAAW;QAAE,QAAQ,EAAE,CAAC;IACjC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QACf,QAAQ,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,gBAAgB;YACtB,OAAO,EAAE,YAAY,QAAQ,uBAAuB;SACvD,CAAC,CAAC;IACP,CAAC;IAED,mCAAmC;IACnC,MAAM,cAAc,GAAG,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC;IAC9C,MAAM,cAAc,GAAG,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,WAAW,IAAI,IAAI,CAAC,YAAY,CAAC,WAAW,KAAK,MAAM,CAAC;IACpG,IAAI,cAAc,IAAI,cAAc,EAAE,CAAC;QACnC,QAAQ,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,0BAA0B;YAChC,OAAO,EAAE,iFAAiF;SAC7F,CAAC,CAAC;IACP,CAAC;IAED,4CAA4C;IAC5C,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,IAAI,CAAC,QAAQ;QAAE,WAAW,EAAE,CAAC;IACjC,IAAI,IAAI,CAAC,UAAU;QAAE,WAAW,EAAE,CAAC;IACnC,IAAI,IAAI,CAAC,UAAU;QAAE,WAAW,EAAE,CAAC;IACnC,IAAI,IAAI,CAAC,UAAU;QAAE,WAAW,EAAE,CAAC;IACnC,IAAI,IAAI,CAAC,QAAQ;QAAE,WAAW,EAAE,CAAC;IACjC,IAAI,IAAI,CAAC,cAAc;QAAE,WAAW,EAAE,CAAC;IACvC,IAAI,IAAI,CAAC,mBAAmB;QAAE,WAAW,EAAE,CAAC;IAC5C,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;QAClB,QAAQ,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,cAAc;YACpB,OAAO,EAAE,YAAY,WAAW,2DAA2D;SAC9F,CAAC,CAAC;IACP,CAAC;IAED,2BAA2B;IAC3B,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChD,QAAQ,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,oBAAoB;YAC1B,OAAO,EAAE,wBAAwB,IAAI,CAAC,UAAU,CAAC,MAAM,oCAAoC;SAC9F,CAAC,CAAC;IACP,CAAC;IAED,OAAO;QACH,KAAK,EAAE,QAAQ,CAAC,MAAM,KAAK,CAAC;QAC5B,QAAQ;KACX,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hero-contract.test.d.ts","sourceRoot":"","sources":["../../src/core/hero-contract.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { probeHeroContract } from './hero-contract.js';
|
|
3
|
+
function makeHero(overrides = {}) {
|
|
4
|
+
return { type: 'hero', titleKey: 'hero.title', ...overrides };
|
|
5
|
+
}
|
|
6
|
+
describe('probeHeroContract', () => {
|
|
7
|
+
it('passes for a minimal hero', () => {
|
|
8
|
+
const result = probeHeroContract(makeHero());
|
|
9
|
+
expect(result.valid).toBe(true);
|
|
10
|
+
expect(result.warnings).toHaveLength(0);
|
|
11
|
+
});
|
|
12
|
+
it('passes with 3 CTAs', () => {
|
|
13
|
+
const result = probeHeroContract(makeHero({
|
|
14
|
+
cta: { labelKey: 'c1', action: { type: 'link', href: '/' } },
|
|
15
|
+
ctaSecondary: { labelKey: 'c2', action: { type: 'noop' } },
|
|
16
|
+
ctaTertiary: { labelKey: 'c3', action: { type: 'noop' } },
|
|
17
|
+
}));
|
|
18
|
+
expect(result.valid).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
it('warns on single-decorative-source violation', () => {
|
|
21
|
+
const result = probeHeroContract(makeHero({
|
|
22
|
+
visualAssetPath: '/img/hero.jpg',
|
|
23
|
+
presentation: { visualStage: 'parallax-stars' },
|
|
24
|
+
}));
|
|
25
|
+
expect(result.warnings).toContainEqual(expect.objectContaining({ rule: 'single-decorative-source' }));
|
|
26
|
+
});
|
|
27
|
+
it('does not warn when visualStage is "none"', () => {
|
|
28
|
+
const result = probeHeroContract(makeHero({
|
|
29
|
+
visualAssetPath: '/img/hero.jpg',
|
|
30
|
+
presentation: { visualStage: 'none' },
|
|
31
|
+
}));
|
|
32
|
+
const decorWarnings = result.warnings.filter(w => w.rule === 'single-decorative-source');
|
|
33
|
+
expect(decorWarnings).toHaveLength(0);
|
|
34
|
+
});
|
|
35
|
+
it('warns on copy-density exceeding 5', () => {
|
|
36
|
+
const result = probeHeroContract(makeHero({
|
|
37
|
+
titleKey: 't',
|
|
38
|
+
eyebrowKey: 'e',
|
|
39
|
+
taglineKey: 'tg',
|
|
40
|
+
supportKey: 's',
|
|
41
|
+
mottoKey: 'm',
|
|
42
|
+
poeticAsideKey: 'p',
|
|
43
|
+
}));
|
|
44
|
+
expect(result.warnings).toContainEqual(expect.objectContaining({ rule: 'copy-density' }));
|
|
45
|
+
});
|
|
46
|
+
it('passes with 5 text anchors', () => {
|
|
47
|
+
const result = probeHeroContract(makeHero({
|
|
48
|
+
titleKey: 't',
|
|
49
|
+
eyebrowKey: 'e',
|
|
50
|
+
taglineKey: 'tg',
|
|
51
|
+
supportKey: 's',
|
|
52
|
+
mottoKey: 'm',
|
|
53
|
+
}));
|
|
54
|
+
expect(result.valid).toBe(true);
|
|
55
|
+
});
|
|
56
|
+
it('warns on action rail > 6 items', () => {
|
|
57
|
+
const items = Array.from({ length: 7 }, (_, i) => ({
|
|
58
|
+
labelKey: `l${i}`, href: '/', icon: 'star',
|
|
59
|
+
}));
|
|
60
|
+
const result = probeHeroContract(makeHero({ actionRail: items }));
|
|
61
|
+
expect(result.warnings).toContainEqual(expect.objectContaining({ rule: 'rail-item-geometry' }));
|
|
62
|
+
});
|
|
63
|
+
it('passes with 6 action rail items', () => {
|
|
64
|
+
const items = Array.from({ length: 6 }, (_, i) => ({
|
|
65
|
+
labelKey: `l${i}`, href: '/', icon: 'star',
|
|
66
|
+
}));
|
|
67
|
+
const result = probeHeroContract(makeHero({ actionRail: items }));
|
|
68
|
+
expect(result.valid).toBe(true);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
//# sourceMappingURL=hero-contract.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hero-contract.test.js","sourceRoot":"","sources":["../../src/core/hero-contract.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manifest Resolver — resolves page IDs from routes.
|
|
3
|
+
* Pure functions, no fetch. Extracted from easyway-portal (src/utils/pages-loader.ts).
|
|
4
|
+
*/
|
|
5
|
+
import type { PagesManifestV1 } from './types.js';
|
|
6
|
+
export declare function normalizePathname(pathname: string): string;
|
|
7
|
+
export declare function resolvePageIdByRoute(manifest: PagesManifestV1, pathname: string): string | null;
|
|
8
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/core/manifest.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAI1D;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI/F"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manifest Resolver — resolves page IDs from routes.
|
|
3
|
+
* Pure functions, no fetch. Extracted from easyway-portal (src/utils/pages-loader.ts).
|
|
4
|
+
*/
|
|
5
|
+
export function normalizePathname(pathname) {
|
|
6
|
+
if (!pathname)
|
|
7
|
+
return '/';
|
|
8
|
+
if (pathname !== '/' && pathname.endsWith('/'))
|
|
9
|
+
return pathname.slice(0, -1);
|
|
10
|
+
return pathname;
|
|
11
|
+
}
|
|
12
|
+
export function resolvePageIdByRoute(manifest, pathname) {
|
|
13
|
+
const normalized = normalizePathname(pathname);
|
|
14
|
+
const page = manifest.pages.find(p => normalizePathname(p.route) === normalized);
|
|
15
|
+
return page ? page.id : null;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/core/manifest.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAC9C,IAAI,CAAC,QAAQ;QAAE,OAAO,GAAG,CAAC;IAC1B,IAAI,QAAQ,KAAK,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7E,OAAO,QAAQ,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,QAAyB,EAAE,QAAgB;IAC5E,MAAM,UAAU,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,UAAU,CAAC,CAAC;IACjF,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.test.d.ts","sourceRoot":"","sources":["../../src/core/manifest.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { normalizePathname, resolvePageIdByRoute } from './manifest.js';
|
|
3
|
+
describe('normalizePathname', () => {
|
|
4
|
+
it('returns / for empty string', () => {
|
|
5
|
+
expect(normalizePathname('')).toBe('/');
|
|
6
|
+
});
|
|
7
|
+
it('keeps / as is', () => {
|
|
8
|
+
expect(normalizePathname('/')).toBe('/');
|
|
9
|
+
});
|
|
10
|
+
it('strips trailing slash', () => {
|
|
11
|
+
expect(normalizePathname('/products/')).toBe('/products');
|
|
12
|
+
});
|
|
13
|
+
it('does not strip from root /', () => {
|
|
14
|
+
expect(normalizePathname('/')).toBe('/');
|
|
15
|
+
});
|
|
16
|
+
it('keeps paths without trailing slash', () => {
|
|
17
|
+
expect(normalizePathname('/about')).toBe('/about');
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
describe('resolvePageIdByRoute', () => {
|
|
21
|
+
const manifest = {
|
|
22
|
+
version: '1',
|
|
23
|
+
pages: [
|
|
24
|
+
{ id: 'home', route: '/', spec: 'pages/home.json' },
|
|
25
|
+
{ id: 'pricing', route: '/pricing', spec: 'pages/pricing.json' },
|
|
26
|
+
{ id: 'demo', route: '/demo', spec: 'pages/demo.json' },
|
|
27
|
+
],
|
|
28
|
+
};
|
|
29
|
+
it('resolves root to home', () => {
|
|
30
|
+
expect(resolvePageIdByRoute(manifest, '/')).toBe('home');
|
|
31
|
+
});
|
|
32
|
+
it('resolves /pricing to pricing', () => {
|
|
33
|
+
expect(resolvePageIdByRoute(manifest, '/pricing')).toBe('pricing');
|
|
34
|
+
});
|
|
35
|
+
it('resolves /pricing/ (trailing slash) to pricing', () => {
|
|
36
|
+
expect(resolvePageIdByRoute(manifest, '/pricing/')).toBe('pricing');
|
|
37
|
+
});
|
|
38
|
+
it('returns null for unknown route', () => {
|
|
39
|
+
expect(resolvePageIdByRoute(manifest, '/unknown')).toBeNull();
|
|
40
|
+
});
|
|
41
|
+
it('returns null for empty manifest', () => {
|
|
42
|
+
expect(resolvePageIdByRoute({ version: '1', pages: [] }, '/')).toBeNull();
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=manifest.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.test.js","sourceRoot":"","sources":["../../src/core/manifest.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAGxE,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QAClC,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,eAAe,EAAE,GAAG,EAAE;QACrB,MAAM,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC7B,MAAM,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QAClC,MAAM,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC1C,MAAM,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IAClC,MAAM,QAAQ,GAAoB;QAC9B,OAAO,EAAE,GAAG;QACZ,KAAK,EAAE;YACH,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,iBAAiB,EAAE;YACnD,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,oBAAoB,EAAE;YAChE,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE;SAC1D;KACJ,CAAC;IAEF,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC7B,MAAM,CAAC,oBAAoB,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,oBAAoB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACtD,MAAM,CAAC,oBAAoB,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,oBAAoB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,oBAAoB,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC9E,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PageSpec validation — validates against the real PageSpecV1 type.
|
|
3
|
+
* The old PageSpec/LayoutSpec/ComponentSpec/ActionSpec interfaces have been
|
|
4
|
+
* replaced by the full type system in types.ts.
|
|
5
|
+
*
|
|
6
|
+
* @deprecated Use validatePageSpecV1 for richer validation with structured errors.
|
|
7
|
+
*/
|
|
8
|
+
import type { PageSpecV1 } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Basic runtime validation for PageSpecV1.
|
|
11
|
+
* Returns true if the spec has the required shape.
|
|
12
|
+
*/
|
|
13
|
+
export declare function validatePageSpec(spec: unknown): spec is PageSpecV1;
|
|
14
|
+
//# sourceMappingURL=page-spec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-spec.d.ts","sourceRoot":"","sources":["../../src/core/page-spec.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,UAAU,CAQlE"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PageSpec validation — validates against the real PageSpecV1 type.
|
|
3
|
+
* The old PageSpec/LayoutSpec/ComponentSpec/ActionSpec interfaces have been
|
|
4
|
+
* replaced by the full type system in types.ts.
|
|
5
|
+
*
|
|
6
|
+
* @deprecated Use validatePageSpecV1 for richer validation with structured errors.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Basic runtime validation for PageSpecV1.
|
|
10
|
+
* Returns true if the spec has the required shape.
|
|
11
|
+
*/
|
|
12
|
+
export function validatePageSpec(spec) {
|
|
13
|
+
if (typeof spec !== 'object' || spec === null)
|
|
14
|
+
return false;
|
|
15
|
+
const s = spec;
|
|
16
|
+
return (s.version === '1' &&
|
|
17
|
+
typeof s.id === 'string' &&
|
|
18
|
+
Array.isArray(s.sections));
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=page-spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-spec.js","sourceRoot":"","sources":["../../src/core/page-spec.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAa;IAC1C,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC5D,MAAM,CAAC,GAAG,IAA+B,CAAC;IAC1C,OAAO,CACH,CAAC,CAAC,OAAO,KAAK,GAAG;QACjB,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ;QACxB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAC5B,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-spec.test.d.ts","sourceRoot":"","sources":["../../src/core/page-spec.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { validatePageSpec } from './page-spec.js';
|
|
3
|
+
describe('validatePageSpec (V1)', () => {
|
|
4
|
+
it('validates a correct PageSpecV1', () => {
|
|
5
|
+
const spec = { version: '1', id: 'home', sections: [] };
|
|
6
|
+
expect(validatePageSpec(spec)).toBe(true);
|
|
7
|
+
});
|
|
8
|
+
it('rejects null', () => {
|
|
9
|
+
expect(validatePageSpec(null)).toBe(false);
|
|
10
|
+
});
|
|
11
|
+
it('rejects non-object', () => {
|
|
12
|
+
expect(validatePageSpec('string')).toBe(false);
|
|
13
|
+
expect(validatePageSpec(42)).toBe(false);
|
|
14
|
+
});
|
|
15
|
+
it('rejects wrong version', () => {
|
|
16
|
+
expect(validatePageSpec({ version: '2', id: 'test', sections: [] })).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
it('rejects missing id', () => {
|
|
19
|
+
expect(validatePageSpec({ version: '1', sections: [] })).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
it('rejects missing sections', () => {
|
|
22
|
+
expect(validatePageSpec({ version: '1', id: 'test' })).toBe(false);
|
|
23
|
+
});
|
|
24
|
+
it('rejects sections as non-array', () => {
|
|
25
|
+
expect(validatePageSpec({ version: '1', id: 'test', sections: 'bad' })).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
it('accepts spec with optional fields', () => {
|
|
28
|
+
const spec = {
|
|
29
|
+
version: '1',
|
|
30
|
+
id: 'home',
|
|
31
|
+
profile: 'home-signature',
|
|
32
|
+
titleKey: 'page.home.title',
|
|
33
|
+
sections: [{ type: 'hero', titleKey: 'hero.title' }],
|
|
34
|
+
};
|
|
35
|
+
expect(validatePageSpec(spec)).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=page-spec.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-spec.test.js","sourceRoot":"","sources":["../../src/core/page-spec.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,IAAI,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QACxD,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,cAAc,EAAE,GAAG,EAAE;QACtB,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAC5B,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/C,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,CAAC,gBAAgB,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAC5B,MAAM,CAAC,gBAAgB,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,CAAC,gBAAgB,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,gBAAgB,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,IAAI,GAAG;YACX,OAAO,EAAE,GAAY;YACrB,EAAE,EAAE,MAAM;YACV,OAAO,EAAE,gBAAgB;YACzB,QAAQ,EAAE,iBAAiB;YAC3B,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;SACrD,CAAC;QACF,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Presentation Resolver — resolves section presentation defaults.
|
|
3
|
+
* Pure functions, no DOM. Extracted from easyway-portal (src/utils/pages-renderer.ts).
|
|
4
|
+
*/
|
|
5
|
+
import type { SectionPresentationSpec, SectionSpec } from './types.js';
|
|
6
|
+
export declare const DEFAULT_PRESENTATION: Required<SectionPresentationSpec>;
|
|
7
|
+
export declare function inferRhythmProfile(section: SectionSpec): NonNullable<SectionPresentationSpec['rhythmProfile']>;
|
|
8
|
+
export declare function resolvePresentation(section: SectionSpec): Required<SectionPresentationSpec>;
|
|
9
|
+
//# sourceMappingURL=presentation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation.d.ts","sourceRoot":"","sources":["../../src/core/presentation.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEvE,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,uBAAuB,CAelE,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,WAAW,CAAC,uBAAuB,CAAC,eAAe,CAAC,CAAC,CAyB9G;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,WAAW,GAAG,QAAQ,CAAC,uBAAuB,CAAC,CAiB3F"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Presentation Resolver — resolves section presentation defaults.
|
|
3
|
+
* Pure functions, no DOM. Extracted from easyway-portal (src/utils/pages-renderer.ts).
|
|
4
|
+
*/
|
|
5
|
+
export const DEFAULT_PRESENTATION = {
|
|
6
|
+
surface: 'default',
|
|
7
|
+
surfaceScreen: 'none',
|
|
8
|
+
visualStage: 'none',
|
|
9
|
+
seamProfile: 'none',
|
|
10
|
+
seamDensity: 'default',
|
|
11
|
+
surfaceEntry: 'slab',
|
|
12
|
+
surfaceOverlap: 'none',
|
|
13
|
+
contentLift: 'none',
|
|
14
|
+
height: 'content',
|
|
15
|
+
tone: 'default',
|
|
16
|
+
rhythmProfile: 'feature',
|
|
17
|
+
rhythmGroup: 'default-flow',
|
|
18
|
+
presetId: '',
|
|
19
|
+
transitionProfileId: '',
|
|
20
|
+
};
|
|
21
|
+
export function inferRhythmProfile(section) {
|
|
22
|
+
switch (section.type) {
|
|
23
|
+
case 'hero':
|
|
24
|
+
return 'hero';
|
|
25
|
+
case 'cta':
|
|
26
|
+
case 'spacer':
|
|
27
|
+
return 'transition';
|
|
28
|
+
case 'cards':
|
|
29
|
+
case 'how-it-works':
|
|
30
|
+
case 'comparison':
|
|
31
|
+
case 'valentino-catalog':
|
|
32
|
+
return 'feature';
|
|
33
|
+
case 'manifesto':
|
|
34
|
+
return 'reading';
|
|
35
|
+
case 'stats':
|
|
36
|
+
return 'metrics';
|
|
37
|
+
case 'agent-dashboard':
|
|
38
|
+
case 'agent-graph':
|
|
39
|
+
case 'agent-list':
|
|
40
|
+
case 'data-list':
|
|
41
|
+
case 'action-form':
|
|
42
|
+
return 'ops';
|
|
43
|
+
default:
|
|
44
|
+
return 'feature';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export function resolvePresentation(section) {
|
|
48
|
+
return {
|
|
49
|
+
surface: section.presentation?.surface || DEFAULT_PRESENTATION.surface,
|
|
50
|
+
surfaceScreen: section.presentation?.surfaceScreen || DEFAULT_PRESENTATION.surfaceScreen,
|
|
51
|
+
seamProfile: section.presentation?.seamProfile || DEFAULT_PRESENTATION.seamProfile,
|
|
52
|
+
seamDensity: section.presentation?.seamDensity || DEFAULT_PRESENTATION.seamDensity,
|
|
53
|
+
surfaceEntry: section.presentation?.surfaceEntry || DEFAULT_PRESENTATION.surfaceEntry,
|
|
54
|
+
surfaceOverlap: section.presentation?.surfaceOverlap || DEFAULT_PRESENTATION.surfaceOverlap,
|
|
55
|
+
contentLift: section.presentation?.contentLift || DEFAULT_PRESENTATION.contentLift,
|
|
56
|
+
visualStage: section.presentation?.visualStage || DEFAULT_PRESENTATION.visualStage,
|
|
57
|
+
height: section.presentation?.height || DEFAULT_PRESENTATION.height,
|
|
58
|
+
tone: section.presentation?.tone || DEFAULT_PRESENTATION.tone,
|
|
59
|
+
rhythmProfile: section.presentation?.rhythmProfile || inferRhythmProfile(section),
|
|
60
|
+
rhythmGroup: section.presentation?.rhythmGroup || DEFAULT_PRESENTATION.rhythmGroup,
|
|
61
|
+
presetId: section.presentation?.presetId || '',
|
|
62
|
+
transitionProfileId: section.presentation?.transitionProfileId || '',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=presentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation.js","sourceRoot":"","sources":["../../src/core/presentation.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,CAAC,MAAM,oBAAoB,GAAsC;IACnE,OAAO,EAAE,SAAS;IAClB,aAAa,EAAE,MAAM;IACrB,WAAW,EAAE,MAAM;IACnB,WAAW,EAAE,MAAM;IACnB,WAAW,EAAE,SAAS;IACtB,YAAY,EAAE,MAAM;IACpB,cAAc,EAAE,MAAM;IACtB,WAAW,EAAE,MAAM;IACnB,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,SAAS;IACf,aAAa,EAAE,SAAS;IACxB,WAAW,EAAE,cAAc;IAC3B,QAAQ,EAAE,EAAE;IACZ,mBAAmB,EAAE,EAAE;CAC1B,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAAC,OAAoB;IACnD,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,MAAM;YACP,OAAO,MAAM,CAAC;QAClB,KAAK,KAAK,CAAC;QACX,KAAK,QAAQ;YACT,OAAO,YAAY,CAAC;QACxB,KAAK,OAAO,CAAC;QACb,KAAK,cAAc,CAAC;QACpB,KAAK,YAAY,CAAC;QAClB,KAAK,mBAAmB;YACpB,OAAO,SAAS,CAAC;QACrB,KAAK,WAAW;YACZ,OAAO,SAAS,CAAC;QACrB,KAAK,OAAO;YACR,OAAO,SAAS,CAAC;QACrB,KAAK,iBAAiB,CAAC;QACvB,KAAK,aAAa,CAAC;QACnB,KAAK,YAAY,CAAC;QAClB,KAAK,WAAW,CAAC;QACjB,KAAK,aAAa;YACd,OAAO,KAAK,CAAC;QACjB;YACI,OAAO,SAAS,CAAC;IACzB,CAAC;AACL,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAoB;IACpD,OAAO;QACH,OAAO,EAAE,OAAO,CAAC,YAAY,EAAE,OAAO,IAAI,oBAAoB,CAAC,OAAO;QACtE,aAAa,EAAE,OAAO,CAAC,YAAY,EAAE,aAAa,IAAI,oBAAoB,CAAC,aAAa;QACxF,WAAW,EAAE,OAAO,CAAC,YAAY,EAAE,WAAW,IAAI,oBAAoB,CAAC,WAAW;QAClF,WAAW,EAAE,OAAO,CAAC,YAAY,EAAE,WAAW,IAAI,oBAAoB,CAAC,WAAW;QAClF,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,YAAY,IAAI,oBAAoB,CAAC,YAAY;QACrF,cAAc,EAAE,OAAO,CAAC,YAAY,EAAE,cAAc,IAAI,oBAAoB,CAAC,cAAc;QAC3F,WAAW,EAAE,OAAO,CAAC,YAAY,EAAE,WAAW,IAAI,oBAAoB,CAAC,WAAW;QAClF,WAAW,EAAE,OAAO,CAAC,YAAY,EAAE,WAAW,IAAI,oBAAoB,CAAC,WAAW;QAClF,MAAM,EAAE,OAAO,CAAC,YAAY,EAAE,MAAM,IAAI,oBAAoB,CAAC,MAAM;QACnE,IAAI,EAAE,OAAO,CAAC,YAAY,EAAE,IAAI,IAAI,oBAAoB,CAAC,IAAI;QAC7D,aAAa,EAAE,OAAO,CAAC,YAAY,EAAE,aAAa,IAAI,kBAAkB,CAAC,OAAO,CAAC;QACjF,WAAW,EAAE,OAAO,CAAC,YAAY,EAAE,WAAW,IAAI,oBAAoB,CAAC,WAAW;QAClF,QAAQ,EAAE,OAAO,CAAC,YAAY,EAAE,QAAQ,IAAI,EAAE;QAC9C,mBAAmB,EAAE,OAAO,CAAC,YAAY,EAAE,mBAAmB,IAAI,EAAE;KACvE,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation.test.d.ts","sourceRoot":"","sources":["../../src/core/presentation.test.ts"],"names":[],"mappings":""}
|