mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
Align design system UI kit scaffolds
This commit is contained in:
@@ -973,7 +973,7 @@ async function writeGeneratedDesignSystemFiles(
|
||||
),
|
||||
writeFile(
|
||||
path.join(dir, 'ui_kits', 'app', 'README.md'),
|
||||
`# ${input.title} UI Kit\n\nUse \`index.html\` as the applied interface example. Reuse \`components/\` as modular app shell, sidebar, assistant list, chat area, input bar, and message bubble building blocks. Replace this scaffold with source-backed modular components when repository evidence is available.\n`,
|
||||
renderUiKitReadme(input.title),
|
||||
'utf8',
|
||||
),
|
||||
...defaultUiKitComponentSpecs().map(({ fileName, componentName, purpose }) =>
|
||||
@@ -1006,7 +1006,7 @@ function renderUiKitComponent(name: string, title: string, purpose: string): str
|
||||
if (name === 'MessageBubble') return renderMessageBubbleUiKitComponent(title);
|
||||
if (name === 'PreviewCard') return renderPreviewCardUiKitComponent(title);
|
||||
if (name === 'Composer') return renderComposerUiKitComponent(title);
|
||||
return `export function ${name}({ children, title = '${escapeJsString(title)}' }) {
|
||||
return `function ${name}({ children, title = '${escapeJsString(title)}' }) {
|
||||
return (
|
||||
<section className="od-ui-kit-${name.toLowerCase()}">
|
||||
<small>${escapeTsxText(purpose)}</small>
|
||||
@@ -1015,6 +1015,8 @@ function renderUiKitComponent(name: string, title: string, purpose: string): str
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
window.${name} = ${name};
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1030,36 +1032,39 @@ function renderAppUiKitComponent(title: string): string {
|
||||
];
|
||||
|
||||
const appStyles = {
|
||||
shell: { display: 'grid', gridTemplateColumns: '72px minmax(220px, 280px) 1fr', minHeight: '720px', background: 'var(--color-background, #f7f8fa)', color: 'var(--color-text, #202124)' },
|
||||
rail: { borderRight: '1px solid var(--color-border, #dfe3e8)', background: 'var(--color-background-soft, #fff)' },
|
||||
list: { borderRight: '1px solid var(--color-border, #dfe3e8)', padding: '18px', display: 'grid', alignContent: 'start', gap: '12px' },
|
||||
shell: { display: 'grid', gridTemplateColumns: '280px minmax(240px, 300px) 1fr', minHeight: '720px', background: 'var(--color-background, #f7f8fa)', color: 'var(--color-text, #202124)' },
|
||||
workspace: { padding: '24px', display: 'grid', gap: '16px', alignContent: 'start' },
|
||||
card: { border: '1px solid var(--color-border, #dfe3e8)', borderRadius: 12, background: 'var(--color-surface, #fff)', padding: '16px' },
|
||||
eyebrow: { color: 'var(--color-text-secondary, #73777f)', fontSize: 12, fontWeight: 600, textTransform: 'uppercase', letterSpacing: 0 },
|
||||
};
|
||||
|
||||
export function App({ title = '${escapeJsString(title)}', modules = reviewModules }) {
|
||||
function App({ title = '${escapeJsString(title)}', modules = reviewModules, summary = 'Source-backed design-system workspace' }) {
|
||||
const Sidebar = window.Sidebar;
|
||||
const AssistantsList = window.AssistantsList;
|
||||
const ChatArea = window.ChatArea;
|
||||
return (
|
||||
<main style={appStyles.shell}>
|
||||
<aside style={appStyles.rail} aria-label="Product navigation" />
|
||||
<section style={appStyles.list}>
|
||||
<span style={appStyles.eyebrow}>Design system workspace</span>
|
||||
<h1>{title}</h1>
|
||||
{modules.map((module) => (
|
||||
<article key={module.id} style={appStyles.card}>
|
||||
<strong>{module.label}</strong>
|
||||
<p>{module.summary}</p>
|
||||
</article>
|
||||
))}
|
||||
</section>
|
||||
<Sidebar title={title} />
|
||||
<AssistantsList />
|
||||
<section style={appStyles.workspace}>
|
||||
<span style={appStyles.eyebrow}>Review surface</span>
|
||||
<h2>Focused cards, reusable kit, preserved evidence</h2>
|
||||
<p>Use this shell to compose preview cards next to the source-backed UI kit without turning the system into a marketing page.</p>
|
||||
<h1>{title}</h1>
|
||||
<p>{summary}</p>
|
||||
<ChatArea title={title + ' workspace'} />
|
||||
<section style={{ display: 'grid', gridTemplateColumns: 'repeat(3, minmax(0, 1fr))', gap: 12 }}>
|
||||
{modules.map((module) => (
|
||||
<article key={module.id} style={appStyles.card}>
|
||||
<strong>{module.label}</strong>
|
||||
<p>{module.summary}</p>
|
||||
</article>
|
||||
))}
|
||||
</section>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
window.App = App;
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1079,7 +1084,7 @@ const sidebarStyles = {
|
||||
badge: { fontSize: 11, color: 'var(--color-text-secondary, #73777f)' },
|
||||
};
|
||||
|
||||
export function Sidebar({ title = '${escapeJsString(title)}', activeId = 'design-system', items = sidebarItems }) {
|
||||
function Sidebar({ title = '${escapeJsString(title)}', activeId = 'design-system', items = sidebarItems }) {
|
||||
return (
|
||||
<nav style={sidebarStyles.wrap} aria-label={title}>
|
||||
<div style={sidebarStyles.header}>
|
||||
@@ -1095,6 +1100,8 @@ export function Sidebar({ title = '${escapeJsString(title)}', activeId = 'design
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
||||
window.Sidebar = Sidebar;
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1114,7 +1121,7 @@ const assistantsListStyles = {
|
||||
meta: { color: 'var(--color-text-secondary, #73777f)', fontSize: 12 },
|
||||
};
|
||||
|
||||
export function AssistantsList({ items = assistantItems }) {
|
||||
function AssistantsList({ items = assistantItems }) {
|
||||
return (
|
||||
<aside style={assistantsListStyles.panel} aria-label="Assistants">
|
||||
<header style={assistantsListStyles.header}>
|
||||
@@ -1133,6 +1140,8 @@ export function AssistantsList({ items = assistantItems }) {
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
||||
window.AssistantsList = AssistantsList;
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1150,7 +1159,9 @@ const chatAreaStyles = {
|
||||
composerSlot: { borderTop: '1px solid var(--color-border, #dfe3e8)', background: 'var(--color-surface, #fff)', padding: 16 },
|
||||
};
|
||||
|
||||
export function ChatArea({ title = '${escapeJsString(title)} review', messages = chatMessages }) {
|
||||
function ChatArea({ title = '${escapeJsString(title)} review', messages = chatMessages }) {
|
||||
const InputBar = window.InputBar;
|
||||
const MessageBubble = window.MessageBubble;
|
||||
return (
|
||||
<section style={chatAreaStyles.wrap} aria-label={title}>
|
||||
<header style={chatAreaStyles.header}>
|
||||
@@ -1159,16 +1170,15 @@ export function ChatArea({ title = '${escapeJsString(title)} review', messages =
|
||||
</header>
|
||||
<div style={chatAreaStyles.stream}>
|
||||
{messages.map((message) => (
|
||||
<article key={message.id} style={chatAreaStyles.note}>
|
||||
<small>{message.role}</small>
|
||||
<p>{message.text}</p>
|
||||
</article>
|
||||
<MessageBubble key={message.id} role={message.role} text={message.text} fromUser={message.id === 'user'} />
|
||||
))}
|
||||
</div>
|
||||
<div style={chatAreaStyles.composerSlot}>Use InputBar.jsx for the full composer surface.</div>
|
||||
<div style={chatAreaStyles.composerSlot}><InputBar title={title + ' prompt'} /></div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
window.ChatArea = ChatArea;
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1184,7 +1194,7 @@ const inputBarStyles = {
|
||||
send: { border: 0, borderRadius: 10, padding: '9px 14px', background: 'var(--color-primary, #00b96b)', color: '#fff', fontWeight: 700 },
|
||||
};
|
||||
|
||||
export function InputBar({ title = '${escapeJsString(title)} prompt', actions = inputActions }) {
|
||||
function InputBar({ title = '${escapeJsString(title)} prompt', actions = inputActions }) {
|
||||
return (
|
||||
<form style={inputBarStyles.wrap} aria-label={title}>
|
||||
<textarea style={inputBarStyles.field} placeholder="Describe the design revision, evidence to inspect, or preview card to improve." />
|
||||
@@ -1197,6 +1207,8 @@ export function InputBar({ title = '${escapeJsString(title)} prompt', actions =
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
window.InputBar = InputBar;
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1209,7 +1221,7 @@ function renderMessageBubbleUiKitComponent(title: string): string {
|
||||
status: { justifySelf: 'start', borderRadius: 999, padding: '4px 8px', background: 'var(--color-background-soft, #f7f8fa)', fontSize: 12 },
|
||||
};
|
||||
|
||||
export function MessageBubble({ role = '${escapeJsString(title)}', text = 'Source-backed design-system guidance belongs in compact, reviewable message surfaces.', status = 'grounded', fromUser = false }) {
|
||||
function MessageBubble({ role = '${escapeJsString(title)}', text = 'Source-backed design-system guidance belongs in compact, reviewable message surfaces.', status = 'grounded', fromUser = false }) {
|
||||
return (
|
||||
<article style={{ ...messageBubbleStyles.bubble, ...(fromUser ? messageBubbleStyles.user : {}) }}>
|
||||
<div style={messageBubbleStyles.meta}>
|
||||
@@ -1221,6 +1233,8 @@ export function MessageBubble({ role = '${escapeJsString(title)}', text = 'Sourc
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
||||
window.MessageBubble = MessageBubble;
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1240,7 +1254,7 @@ const previewCardStyles = {
|
||||
check: { display: 'flex', gap: 8, color: 'var(--color-text-secondary, #73777f)' },
|
||||
};
|
||||
|
||||
export function PreviewCard({ title = '${escapeJsString(title)} module', summary = 'Captures source-backed review states for one design-system module.', checks = defaultChecks }) {
|
||||
function PreviewCard({ title = '${escapeJsString(title)} module', summary = 'Captures source-backed review states for one design-system module.', checks = defaultChecks }) {
|
||||
return (
|
||||
<article style={previewCardStyles.card}>
|
||||
<header style={previewCardStyles.header}>
|
||||
@@ -1261,6 +1275,8 @@ export function PreviewCard({ title = '${escapeJsString(title)} module', summary
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
||||
window.PreviewCard = PreviewCard;
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1276,7 +1292,7 @@ const composerStyles = {
|
||||
send: { border: 0, borderRadius: 10, padding: '10px 14px', background: 'var(--color-primary, #00b96b)', color: '#fff', fontWeight: 700 },
|
||||
};
|
||||
|
||||
export function Composer({ title = '${escapeJsString(title)} feedback', actions = composerActions }) {
|
||||
function Composer({ title = '${escapeJsString(title)} feedback', actions = composerActions }) {
|
||||
return (
|
||||
<form style={composerStyles.wrap} aria-label={title}>
|
||||
<textarea style={composerStyles.field} placeholder="Describe what needs revision while keeping the source evidence intact." />
|
||||
@@ -1289,6 +1305,8 @@ export function Composer({ title = '${escapeJsString(title)} feedback', actions
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
window.Composer = Composer;
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1663,9 +1681,13 @@ function renderReadme(input: {
|
||||
.join('\n');
|
||||
return `# ${input.title}
|
||||
|
||||
${input.summary}
|
||||
A reusable Open Design package for ${input.title}.
|
||||
|
||||
## Overview
|
||||
## Product Overview
|
||||
|
||||
${input.summary} This design-system package is designed for product, app, workspace, and platform surfaces that need a reusable visual direction rather than a one-off mockup. It provides a concrete token layer, focused preview cards, and an applied UI kit so future agents can build interfaces with the same hierarchy, density, component roles, and interaction rules captured in DESIGN.md.
|
||||
|
||||
## Package Overview
|
||||
|
||||
- Category: ${input.category}
|
||||
- Surface: ${input.surface}
|
||||
@@ -1722,32 +1744,72 @@ function renderSkill(input: {
|
||||
summary: string;
|
||||
palette: GeneratedPalette;
|
||||
}): string {
|
||||
return `# ${input.title}
|
||||
const skillName = slugify(input.title);
|
||||
return `---
|
||||
name: ${skillName}
|
||||
description: Use this skill when generating Open Design artifacts that should follow ${input.title}.
|
||||
user-invocable: true
|
||||
---
|
||||
|
||||
Use this skill when generating Open Design artifacts that should follow ${input.title}.
|
||||
Read README.md, DESIGN.md, colors_and_type.css, preview/, preserved assets, context evidence, and ui_kits/app/ before generating any new interface.
|
||||
|
||||
## Style Contract
|
||||
**What's inside:**
|
||||
- DESIGN.md as the canonical source-backed rules document.
|
||||
- colors_and_type.css as the reusable token stylesheet.
|
||||
- preview/ focused review cards for color, typography, spacing, components, and brand assets.
|
||||
- ui_kits/app/ as a browser-reviewable applied interface kit with modular role components.
|
||||
- context/ provenance and evidence notes for future refreshes.
|
||||
|
||||
- Start from DESIGN.md as the source of truth.
|
||||
- Use colors_and_type.css for color, type, spacing, border, and state tokens.
|
||||
- Use context/provenance.md to understand which source materials shaped the system.
|
||||
- Prefer focused preview cards such as colors-primary, typography-specimens, component previews, and brand-assets before inventing new styles.
|
||||
- Prefer ui_kits/app/ for applied interface structure.
|
||||
- Keep output aligned with this summary: ${input.summary}
|
||||
**Source context:**
|
||||
${input.summary}
|
||||
|
||||
## Core Tokens
|
||||
**When to use this skill:**
|
||||
- Creating product-like prototypes that should follow ${input.title}.
|
||||
- Revising focused design-system preview cards or app UI kit components.
|
||||
- Building interfaces that need this package's captured density, hierarchy, tokens, and anti-patterns.
|
||||
|
||||
**How to use:**
|
||||
1. Read DESIGN.md for product context, foundations, components, motion, voice, and anti-patterns.
|
||||
2. Load colors_and_type.css instead of hardcoding palette, typography, radius, or spacing values.
|
||||
3. Inspect preview/ cards for focused modules before inventing new styling.
|
||||
4. Reuse ui_kits/app/index.html and ui_kits/app/components/ as the applied component composition.
|
||||
5. Preserve the product context, hierarchy, density, and anti-patterns documented in DESIGN.md.
|
||||
|
||||
**Design system highlights:**
|
||||
|
||||
- Background: ${input.palette.background}
|
||||
- Foreground: ${input.palette.foreground}
|
||||
- Accent: ${input.palette.accent}
|
||||
- Border: ${input.palette.border}
|
||||
`;
|
||||
}
|
||||
|
||||
## Workflow
|
||||
function renderUiKitReadme(title: string): string {
|
||||
return `# ${title} UI Kit
|
||||
|
||||
1. Read DESIGN.md.
|
||||
2. Inspect context/, preview/, and assets/ for concrete references.
|
||||
3. Generate the requested interface or artifact.
|
||||
4. Preserve the product context, hierarchy, density, and anti-patterns documented in DESIGN.md.
|
||||
This UI kit is the applied interface reference for the design system. Open \`index.html\` to review the composed app surface, then reuse the modular role components under \`components/\` when building new product-like artifacts.
|
||||
|
||||
## Structure
|
||||
|
||||
- \`index.html\` - Browser-reviewable entry that loads \`../../colors_and_type.css\`, React, ReactDOM, Babel, and the component files.
|
||||
- \`components/App.jsx\` - App shell that composes the role components.
|
||||
- \`components/Sidebar.jsx\` - Navigation rail or sidebar pattern.
|
||||
- \`components/AssistantsList.jsx\` - Object, assistant, or thread list pattern.
|
||||
- \`components/ChatArea.jsx\` - Primary workspace with message/content stream.
|
||||
- \`components/InputBar.jsx\` - Composer or command-entry surface.
|
||||
- \`components/MessageBubble.jsx\` - Message, note, or review-comment unit.
|
||||
|
||||
## Usage
|
||||
|
||||
Copy component files into a React prototype or open \`index.html\` directly for visual review. Keep \`colors_and_type.css\` loaded before the components so color, type, spacing, radius, and state variables resolve through the extracted token contract.
|
||||
|
||||
## Design Notes
|
||||
|
||||
Prefer source-backed component roles over static duplicate HTML. When repository evidence is available, replace this scaffold with components modeled from captured app shell, navigation, composer, message, and content surfaces.
|
||||
|
||||
## Source
|
||||
|
||||
Use parent \`DESIGN.md\`, \`README.md\`, \`preview/\`, and \`context/\` as the evidence trail for any future refinement.
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1774,6 +1836,23 @@ function renderCssTokens(input: { title: string; palette: GeneratedPalette }): s
|
||||
--${slug}-space-4: 16px;
|
||||
--${slug}-space-6: 24px;
|
||||
--${slug}-space-8: 32px;
|
||||
|
||||
--color-background: var(--${slug}-background);
|
||||
--color-surface: var(--${slug}-surface);
|
||||
--color-background-soft: var(--${slug}-surface-muted);
|
||||
--color-text: var(--${slug}-foreground);
|
||||
--color-text-1: var(--${slug}-foreground);
|
||||
--color-text-secondary: var(--${slug}-muted);
|
||||
--color-border: var(--${slug}-border);
|
||||
--color-primary: var(--${slug}-accent);
|
||||
--color-primary-soft: color-mix(in srgb, var(--${slug}-accent) 14%, transparent);
|
||||
--font-family: var(--${slug}-font-sans);
|
||||
--code-font-family: var(--${slug}-font-mono);
|
||||
--radius-control: var(--${slug}-radius-sm);
|
||||
--radius-card: var(--${slug}-radius-md);
|
||||
--space-2: var(--${slug}-space-2);
|
||||
--space-3: var(--${slug}-space-3);
|
||||
--space-4: var(--${slug}-space-4);
|
||||
}
|
||||
|
||||
.od-design-system-preview {
|
||||
@@ -1934,25 +2013,57 @@ function renderComponentPreviewHtml(
|
||||
summary: string,
|
||||
palette: GeneratedPalette,
|
||||
): string {
|
||||
return renderHtmlDocument(
|
||||
`${title} Interface`,
|
||||
`<main class="component-preview">
|
||||
<aside>
|
||||
<strong>${escapeHtml(title)}</strong>
|
||||
<button>Overview</button>
|
||||
<button>Components</button>
|
||||
<button>Brand</button>
|
||||
</aside>
|
||||
<section>
|
||||
<p class="eyebrow">Generated UI kit</p>
|
||||
<h1>${escapeHtml(title)}</h1>
|
||||
<p>${escapeHtml(summary)}</p>
|
||||
<div class="component-row"><button class="primary">Primary action</button><button>Secondary action</button></div>
|
||||
<article><strong>Reference card</strong><span>Use this card to review density, borders, type, and action placement.</span></article>
|
||||
</section>
|
||||
</main>`,
|
||||
palette,
|
||||
);
|
||||
const componentScripts = [
|
||||
...defaultUiKitComponentSpecs().filter((spec) => spec.componentName !== 'App'),
|
||||
...defaultUiKitComponentSpecs().filter((spec) => spec.componentName === 'App'),
|
||||
].map((spec) => ` <script type="text/babel" src="components/${spec.fileName}"></script>`).join('\n');
|
||||
return `<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>${escapeHtml(title)} Interface</title>
|
||||
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js"></script>
|
||||
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js"></script>
|
||||
<link rel="stylesheet" href="../../colors_and_type.css" />
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--ui-kit-bg: ${palette.background};
|
||||
--ui-kit-surface: #fff;
|
||||
--ui-kit-fg: ${palette.foreground};
|
||||
--ui-kit-muted: ${palette.muted};
|
||||
--ui-kit-border: ${palette.border};
|
||||
--ui-kit-accent: ${palette.accent};
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
background: var(--color-background, var(--ui-kit-bg));
|
||||
color: var(--color-text-1, var(--ui-kit-fg));
|
||||
font: 14px/1.5 var(--font-family, Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif);
|
||||
}
|
||||
#root { min-height: 100vh; }
|
||||
.ui-kit-loading {
|
||||
display: grid;
|
||||
min-height: 100vh;
|
||||
place-items: center;
|
||||
color: var(--color-text-secondary, var(--ui-kit-muted));
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="ui-kit-loading">Loading ${escapeHtml(title)} UI kit...</div></div>
|
||||
${componentScripts}
|
||||
<script type="text/babel">
|
||||
const App = window.App;
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(<App title={${scriptJson(title)}} summary={${scriptJson(summary)}} />);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderHtmlDocument(title: string, body: string, palette: GeneratedPalette): string {
|
||||
@@ -2028,6 +2139,13 @@ function escapeHtml(raw: string): string {
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
function scriptJson(raw: string): string {
|
||||
return JSON.stringify(raw)
|
||||
.replace(/</g, '\\u003c')
|
||||
.replace(/>/g, '\\u003e')
|
||||
.replace(/&/g, '\\u0026');
|
||||
}
|
||||
|
||||
function escapeTsxText(raw: string): string {
|
||||
return raw.replace(/[{}<>]/g, '');
|
||||
}
|
||||
|
||||
@@ -1211,6 +1211,9 @@ function renderGithubDesignEvidenceMarkdown(evidence: GithubDesignEvidence): str
|
||||
'',
|
||||
'- Use these source paths and snapshots as evidence before writing `DESIGN.md`.',
|
||||
'- Convert the inventory above into a Claude Design-style package: `README.md`, `SKILL.md`, `colors_and_type.css`, `preview/colors-*`, `preview/typography-specimens.html`, `preview/spacing-*`, `preview/components-*`, `preview/brand-assets.html`, `ui_kits/app/`, and preserved `assets/`, `build/`, or `fonts/` when evidence exists.',
|
||||
'- `ui_kits/app/index.html` must be a browser-reviewable component entry: load `../../colors_and_type.css`, load or import at least three files from `ui_kits/app/components/`, and mount the composed UI through ReactDOM/Babel or compiled browser-ready JavaScript. Do not duplicate a static HTML mock when modular component files exist.',
|
||||
'- `ui_kits/app/components/App.jsx` (or equivalent app shell) must compose source-backed role components such as Sidebar, AssistantsList, ChatArea, InputBar, and MessageBubble, not merely list their filenames.',
|
||||
'- Preserve at least three high-signal source examples outside `context/` under `source_examples/` when reusable component snapshots exist, so future agents can compare generated components against original source structure.',
|
||||
'- When a captured asset path begins with `build/`, copy the snapshot back into a root `build/` path with its original filename, such as `context/.../files/build/icon.png` -> `build/icon.png`. Do not satisfy build/runtime icon evidence by only renaming those files into `assets/`.',
|
||||
'- Make `preview/brand-assets.html` visibly load preserved asset files from `assets/` or `build/`; do not redraw captured logos/icons as inline placeholders.',
|
||||
'- Extract concrete colors, typography, spacing, radius, component behavior, assets, and product tone only when supported by inspected files.',
|
||||
@@ -1278,6 +1281,9 @@ function renderLocalDesignEvidenceMarkdown(evidence: LocalDesignEvidence): strin
|
||||
'',
|
||||
'- Use these local source paths and snapshots as evidence before writing `DESIGN.md`.',
|
||||
'- Convert the inventory above into a Claude Design-style package: `README.md`, `SKILL.md`, `colors_and_type.css`, `preview/colors-*`, `preview/typography-specimens.html`, `preview/spacing-*`, `preview/components-*`, `preview/brand-assets.html`, `ui_kits/app/`, and preserved `assets/`, `build/`, or `fonts/` when evidence exists.',
|
||||
'- `ui_kits/app/index.html` must be a browser-reviewable component entry: load `../../colors_and_type.css`, load or import at least three files from `ui_kits/app/components/`, and mount the composed UI through ReactDOM/Babel or compiled browser-ready JavaScript. Do not duplicate a static HTML mock when modular component files exist.',
|
||||
'- `ui_kits/app/components/App.jsx` (or equivalent app shell) must compose source-backed role components such as Sidebar, AssistantsList, ChatArea, InputBar, and MessageBubble, not merely list their filenames.',
|
||||
'- Preserve at least three high-signal source examples outside `context/` under `source_examples/` when reusable component snapshots exist, so future agents can compare generated components against original source structure.',
|
||||
'- When a captured asset path begins with `build/`, copy the snapshot back into a root `build/` path with its original filename, such as `context/.../files/build/icon.png` -> `build/icon.png`. Do not satisfy build/runtime icon evidence by only renaming those files into `assets/`.',
|
||||
'- Make `preview/brand-assets.html` visibly load preserved asset files from `assets/` or `build/`; do not redraw captured logos/icons as inline placeholders.',
|
||||
'- Extract concrete colors, typography, spacing, radius, component behavior, assets, and product tone only when supported by inspected files.',
|
||||
|
||||
@@ -87,8 +87,35 @@ describe('design systems registry', () => {
|
||||
'preview/typography-specimens.html',
|
||||
'assets/logo.svg',
|
||||
'ui_kits/app/index.html',
|
||||
'ui_kits/app/README.md',
|
||||
'ui_kits/app/components/App.jsx',
|
||||
'ui_kits/app/components/Sidebar.jsx',
|
||||
'ui_kits/app/components/AssistantsList.jsx',
|
||||
'ui_kits/app/components/ChatArea.jsx',
|
||||
'ui_kits/app/components/InputBar.jsx',
|
||||
'ui_kits/app/components/MessageBubble.jsx',
|
||||
]),
|
||||
);
|
||||
await expect(readUserDesignSystemFile(root, created.id, 'ui_kits/app/index.html'))
|
||||
.resolves
|
||||
.toMatchObject({
|
||||
content: expect.stringContaining('ReactDOM.createRoot'),
|
||||
});
|
||||
await expect(readUserDesignSystemFile(root, created.id, 'ui_kits/app/index.html'))
|
||||
.resolves
|
||||
.toMatchObject({
|
||||
content: expect.stringContaining('components/App.jsx'),
|
||||
});
|
||||
await expect(readUserDesignSystemFile(root, created.id, 'ui_kits/app/components/App.jsx'))
|
||||
.resolves
|
||||
.toMatchObject({
|
||||
content: expect.stringContaining('<Sidebar'),
|
||||
});
|
||||
await expect(readUserDesignSystemFile(root, created.id, 'ui_kits/app/components/App.jsx'))
|
||||
.resolves
|
||||
.toMatchObject({
|
||||
content: expect.stringContaining('window.App = App'),
|
||||
});
|
||||
await expect(readUserDesignSystemFile(root, created.id, 'README.md'))
|
||||
.resolves
|
||||
.toMatchObject({
|
||||
@@ -277,7 +304,12 @@ describe('design systems registry', () => {
|
||||
await expect(readUserDesignSystemFile(root, 'user:legacy', 'ui_kits/app/components/App.jsx'))
|
||||
.resolves
|
||||
.toMatchObject({
|
||||
content: expect.stringContaining('Design system workspace'),
|
||||
content: expect.stringContaining('<Sidebar'),
|
||||
});
|
||||
await expect(readUserDesignSystemFile(root, 'user:legacy', 'ui_kits/app/components/App.jsx'))
|
||||
.resolves
|
||||
.toMatchObject({
|
||||
content: expect.stringContaining('window.App = App'),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -558,6 +558,9 @@ describe('connectors tool CLI', () => {
|
||||
expect(evidenceNote).toContain('Source Evidence Inventory');
|
||||
expect(evidenceNote).toContain('Theme, tokens, and styling');
|
||||
expect(evidenceNote).toContain('Reusable components');
|
||||
expect(evidenceNote).toContain('ui_kits/app/index.html` must be a browser-reviewable component entry');
|
||||
expect(evidenceNote).toContain('ui_kits/app/components/App.jsx` (or equivalent app shell) must compose source-backed role components');
|
||||
expect(evidenceNote).toContain('source_examples/');
|
||||
await expect(readFile(path.join(tmpDir, 'context/github/acme-ui/files/src/components/Button.tsx'), 'utf8')).resolves.toContain('rounded-md');
|
||||
expect(fetchMock).toHaveBeenCalledWith(
|
||||
'http://127.0.0.1:7456/api/tools/connectors/execute',
|
||||
@@ -615,6 +618,9 @@ describe('connectors tool CLI', () => {
|
||||
expect(evidenceNote).toContain('root `build/` with their original filenames');
|
||||
expect(evidenceNote).toContain('Fonts');
|
||||
expect(evidenceNote).toContain('Claude Design-style package');
|
||||
expect(evidenceNote).toContain('ui_kits/app/index.html` must be a browser-reviewable component entry');
|
||||
expect(evidenceNote).toContain('ui_kits/app/components/App.jsx` (or equivalent app shell) must compose source-backed role components');
|
||||
expect(evidenceNote).toContain('source_examples/');
|
||||
expect(evidenceNote).toContain('context/.../files/build/icon.png` -> `build/icon.png`');
|
||||
await expect(readFile(path.join(tmpDir, 'context/local-code/cherry-studio/files/src/styles.css'), 'utf8')).resolves.toContain('--color-primary');
|
||||
const fontBytes = await readFile(path.join(tmpDir, 'context/local-code/cherry-studio/files/src/assets/fonts/ubuntu/Ubuntu-Regular.ttf'));
|
||||
|
||||
Reference in New Issue
Block a user