070959e133
landing-page-staging / Deploy landing page to staging (push) Has been skipped
landing-page-ci / Validate landing page (push) Failing after 4s
visual-baseline / Capture visual baselines (push) Has been cancelled
bake-plugin-previews / Bake plugin previews (push) Has been cancelled
151 lines
5.4 KiB
TypeScript
151 lines
5.4 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
|
|
import { parseDesignMd } from '../../src/runtime/design-md-parse';
|
|
|
|
// The brand-generated emitter shape (apps/daemon/src/brands/design-md.ts):
|
|
// YAML frontmatter + `## Color Palette` table + `## Typography` font lines +
|
|
// `## Voice & Tone` / `## Imagery` / `## Layout`. The web parser must round-trip
|
|
// this so a brand-derived design system renders its modules.
|
|
const BRAND_EMITTER_MD = [
|
|
'---',
|
|
'name: "The Economist"',
|
|
'category: Brands',
|
|
'surface: web',
|
|
'colors:',
|
|
' economist-red: "#e3120b"',
|
|
' ink: "#0d0d0d"',
|
|
'---',
|
|
'',
|
|
'# The Economist',
|
|
'> Category: Brands',
|
|
'> Surface: web',
|
|
'*Go beyond breaking news*',
|
|
'The Economist is a weekly newspaper covering world politics and economics.',
|
|
'',
|
|
'## Color Palette',
|
|
'',
|
|
'| Role | Name | Hex | Usage |',
|
|
'| --- | --- | --- | --- |',
|
|
'| accent | Economist Red | `#E3120B` | masthead, links, CTAs |',
|
|
'| foreground | Ink | `#0D0D0D` | primary text |',
|
|
'',
|
|
'## Typography',
|
|
'',
|
|
'- **Display:** EconomistSans — weights 400, 700 — fallbacks: Source Sans 3, system-ui',
|
|
'- **Body:** EconomistSerif — weights 400 — fallbacks: Georgia, serif',
|
|
'',
|
|
'## Voice & Tone',
|
|
'',
|
|
'- **Adjectives:** authoritative, incisive, witty',
|
|
'- **Tone:** Plain, confident and analytical with a dry wit.',
|
|
'',
|
|
'### Messaging pillars',
|
|
'- Go beyond breaking news',
|
|
'- A single, coherent editorial voice',
|
|
'',
|
|
'### Vocabulary',
|
|
'- **Use:** leader, why it matters',
|
|
'- **Avoid:** clickbait, emoji',
|
|
'',
|
|
'## Imagery',
|
|
'',
|
|
'- **Style:** Bold conceptual editorial illustration.',
|
|
'- **Subjects:** world leaders, markets',
|
|
'- **Treatment:** flat colour over ink line',
|
|
'- **Avoid:** stock-photo clichés',
|
|
'',
|
|
'## Layout',
|
|
'',
|
|
'- **Radius:** 0px',
|
|
'- **Border weight:** 1px',
|
|
'- **Spacing:** 8px baseline grid',
|
|
'',
|
|
'### Posture rules',
|
|
'- White ground, near-black text, thin grey hairlines.',
|
|
].join('\n');
|
|
|
|
// A bundled preset shape (design-systems/*/DESIGN.md): numbered headings, bullet
|
|
// palette + `Families: primary=…` typography, no Voice/Imagery sections.
|
|
const PRESET_MD = [
|
|
'# Design System Inspired by Agentic',
|
|
'',
|
|
'> Category: Themed & Unique',
|
|
'> Conversational AI-first interface.',
|
|
'',
|
|
'## 2. Color',
|
|
'',
|
|
'- **Primary:** `#FF5701` — Token from style foundations.',
|
|
'- **Surface:** `#FFFFFF` — Large backgrounds and cards.',
|
|
'- **Text:** `#111827` — Body copy.',
|
|
'',
|
|
'## 3. Typography',
|
|
'',
|
|
'- **Families:** primary=Playfair Display, display=Playfair Display, mono=JetBrains Mono',
|
|
'- **Weights:** 400, 600, 700',
|
|
].join('\n');
|
|
|
|
describe('parseDesignMd', () => {
|
|
it('round-trips the brand emitter DESIGN.md shape', () => {
|
|
const parsed = parseDesignMd(BRAND_EMITTER_MD);
|
|
|
|
expect(parsed.name).toBe('The Economist');
|
|
expect(parsed.tagline).toBe('Go beyond breaking news');
|
|
expect(parsed.description).toContain('weekly newspaper');
|
|
|
|
// Color table wins over frontmatter; hexes normalize to lowercase.
|
|
const accent = parsed.colors.find((c) => c.hex === '#e3120b');
|
|
expect(accent?.name).toBe('Economist Red');
|
|
expect(accent?.usage).toContain('masthead');
|
|
expect(parsed.colors.some((c) => c.hex === '#0d0d0d')).toBe(true);
|
|
|
|
expect(parsed.typography.display?.family).toBe('EconomistSans');
|
|
expect(parsed.typography.display?.weights).toContain(400);
|
|
expect(parsed.typography.display?.fallbacks).toContain('Source Sans 3');
|
|
expect(parsed.typography.body?.family).toBe('EconomistSerif');
|
|
|
|
expect(parsed.voice.adjectives).toContain('authoritative');
|
|
expect(parsed.voice.tone).toContain('dry wit');
|
|
expect(parsed.voice.messagingPillars).toContain('Go beyond breaking news');
|
|
expect(parsed.voice.vocabulary.use).toContain('leader');
|
|
expect(parsed.voice.vocabulary.avoid).toContain('emoji');
|
|
|
|
expect(parsed.imagery.style).toContain('editorial illustration');
|
|
expect(parsed.imagery.subjects).toContain('markets');
|
|
|
|
expect(parsed.layout.radius).toBe('0px');
|
|
expect(parsed.layout.spacing).toContain('baseline grid');
|
|
expect(parsed.layout.postureRules.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('falls back to frontmatter colors when no palette table exists', () => {
|
|
const md = ['---', 'name: "Acme"', 'colors:', ' brand: "#123456"', '---', '', '# Acme'].join('\n');
|
|
const parsed = parseDesignMd(md);
|
|
expect(parsed.colors).toHaveLength(1);
|
|
expect(parsed.colors[0]?.hex).toBe('#123456');
|
|
});
|
|
|
|
it('parses the bundled preset DESIGN.md shape (numbered headings, bullet palette)', () => {
|
|
const parsed = parseDesignMd(PRESET_MD);
|
|
|
|
expect(parsed.name).toBe('Design System Inspired by Agentic');
|
|
expect(parsed.category).toBe('Themed & Unique');
|
|
|
|
expect(parsed.colors.map((c) => c.hex)).toEqual(
|
|
expect.arrayContaining(['#ff5701', '#ffffff', '#111827']),
|
|
);
|
|
const primary = parsed.colors.find((c) => c.hex === '#ff5701');
|
|
expect(primary?.role).toBe('accent');
|
|
|
|
expect(parsed.typography.display?.family).toBe('Playfair Display');
|
|
expect(parsed.typography.mono?.family).toBe('JetBrains Mono');
|
|
expect(parsed.typography.display?.weights).toEqual(expect.arrayContaining([400, 600, 700]));
|
|
});
|
|
|
|
it('returns empty modules for an empty document without throwing', () => {
|
|
const parsed = parseDesignMd('');
|
|
expect(parsed.colors).toEqual([]);
|
|
expect(parsed.typography.display).toBeUndefined();
|
|
expect(parsed.voice.adjectives).toEqual([]);
|
|
});
|
|
});
|