Initial commit
This commit is contained in:
@@ -0,0 +1,237 @@
|
||||
# Screenshot Import Screen Generation
|
||||
|
||||
This document provides helper functions for generating screen files (.uxm, .md, .rendered.md) during screenshot import.
|
||||
|
||||
## Overview
|
||||
|
||||
Screen generation creates 3 files:
|
||||
1. **`.uxm`** - Screen metadata and component references
|
||||
2. **`.md`** - Template with `{{component:id}}` references
|
||||
3. **`.rendered.md`** - Actual ASCII preview with real data
|
||||
|
||||
## Step 1: Generate Screen Metadata (.uxm)
|
||||
|
||||
```typescript
|
||||
function generateScreenUxm(mergedData) {
|
||||
const screenId = `${mergedData.screen.type}-screen`;
|
||||
const screenName = mergedData.screen.name;
|
||||
const screenDescription = mergedData.screen.description;
|
||||
const allComponentIds = [
|
||||
...mergedData.composition.atomicComponents,
|
||||
...mergedData.composition.compositeComponents
|
||||
];
|
||||
|
||||
return {
|
||||
"id": screenId,
|
||||
"type": "container",
|
||||
"version": "1.0.0",
|
||||
"metadata": {
|
||||
"name": screenName,
|
||||
"description": screenDescription,
|
||||
"author": "Fluxwing Screenshot Import",
|
||||
"created": new Date().toISOString(),
|
||||
"modified": new Date().toISOString(),
|
||||
"tags": ["screen", mergedData.screen.type, "imported"],
|
||||
"category": "layout"
|
||||
},
|
||||
"props": {
|
||||
"title": screenName,
|
||||
"layout": mergedData.screen.layout,
|
||||
"components": allComponentIds
|
||||
},
|
||||
"ascii": {
|
||||
"templateFile": `${screenId}.md`,
|
||||
"width": 80,
|
||||
"height": 40
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Step 2: Generate Screen Template (.md)
|
||||
|
||||
```typescript
|
||||
function generateScreenTemplate(screenId, screenName, description, components, mergedData) {
|
||||
let markdown = `# ${screenName}\n\n${description}\n\n`;
|
||||
|
||||
markdown += `## Layout\n\n\`\`\`\n`;
|
||||
|
||||
// Reference all components
|
||||
for (const compId of components) {
|
||||
markdown += `{{component:${compId}}}\n\n`;
|
||||
}
|
||||
|
||||
markdown += '\`\`\`\n\n';
|
||||
|
||||
markdown += `## Components Used\n\n`;
|
||||
for (const compId of components) {
|
||||
const comp = mergedData.components.find(c => c.id === compId);
|
||||
const compName = comp ? generateComponentName(compId) : compId;
|
||||
markdown += `- \`${compId}\` - ${compName} (${comp?.type || 'unknown'})\n`;
|
||||
}
|
||||
|
||||
return markdown;
|
||||
}
|
||||
|
||||
// Helper: Convert kebab-case ID to Title Case name
|
||||
function generateComponentName(id) {
|
||||
return id.split('-').map(word =>
|
||||
word.charAt(0).toUpperCase() + word.slice(1)
|
||||
).join(' ');
|
||||
}
|
||||
```
|
||||
|
||||
## Step 3: Generate Rendered Screen (.rendered.md)
|
||||
|
||||
**CRITICAL:** Embed actual ASCII from component files, NOT `{{variables}}`
|
||||
|
||||
```typescript
|
||||
async function generateScreenRendered(screenId, screenName, description, mergedData) {
|
||||
let markdown = `# ${screenName}\n\n`;
|
||||
|
||||
markdown += `## Rendered Example\n\n\`\`\`\n`;
|
||||
|
||||
// Build complete rendered layout
|
||||
// Stack all components vertically (user can refine layout)
|
||||
const allComponentIds = [
|
||||
...mergedData.composition.atomicComponents,
|
||||
...mergedData.composition.compositeComponents
|
||||
];
|
||||
|
||||
for (const compId of allComponentIds) {
|
||||
// Read component .md file
|
||||
const compMdPath = `./fluxwing/components/${compId}.md`;
|
||||
try {
|
||||
const compMdContent = await read(compMdPath);
|
||||
|
||||
// Extract default state ASCII (between first ``` pair after "## Default State")
|
||||
const asciiMatch = compMdContent.match(/## Default State\n\n```\n([\s\S]*?)\n```/);
|
||||
if (asciiMatch) {
|
||||
markdown += asciiMatch[1] + '\n\n';
|
||||
} else {
|
||||
markdown += `[Component ${compId} - ASCII not found]\n\n`;
|
||||
}
|
||||
} catch (error) {
|
||||
markdown += `[Component ${compId} - File not found]\n\n`;
|
||||
}
|
||||
}
|
||||
|
||||
markdown += '\`\`\`\n\n';
|
||||
|
||||
// Add example data section
|
||||
markdown += `**Example Data:**\n`;
|
||||
const exampleData = generateExampleData(mergedData.screen.type);
|
||||
for (const [key, value] of Object.entries(exampleData)) {
|
||||
markdown += `- ${key}: ${value}\n`;
|
||||
}
|
||||
|
||||
return markdown;
|
||||
}
|
||||
```
|
||||
|
||||
## Step 4: Generate Example Data by Screen Type
|
||||
|
||||
```typescript
|
||||
function generateExampleData(screenType) {
|
||||
const examples = {
|
||||
"login": {
|
||||
"Email": "john.doe@example.com",
|
||||
"Password": "••••••••",
|
||||
"Button": "Sign In"
|
||||
},
|
||||
"dashboard": {
|
||||
"Revenue": "$24,567",
|
||||
"Users": "1,234",
|
||||
"Growth": "+12.5%"
|
||||
},
|
||||
"profile": {
|
||||
"Name": "Jane Smith",
|
||||
"Role": "Product Manager",
|
||||
"Email": "jane.smith@company.com"
|
||||
},
|
||||
"settings": {
|
||||
"Theme": "Dark Mode",
|
||||
"Language": "English",
|
||||
"Notifications": "Enabled"
|
||||
},
|
||||
"form": {
|
||||
"Field 1": "Example value",
|
||||
"Field 2": "Another value"
|
||||
}
|
||||
};
|
||||
|
||||
return examples[screenType] || examples["form"];
|
||||
}
|
||||
```
|
||||
|
||||
## Step 5: Write All Files Concurrently
|
||||
|
||||
```typescript
|
||||
async function writeScreenFiles(screenId, screenUxm, screenMd, screenRendered) {
|
||||
// Create screens directory
|
||||
await bash('mkdir -p ./fluxwing/screens');
|
||||
|
||||
const screenDir = './fluxwing/screens';
|
||||
const uxmPath = `${screenDir}/${screenId}.uxm`;
|
||||
const mdPath = `${screenDir}/${screenId}.md`;
|
||||
const renderedPath = `${screenDir}/${screenId}.rendered.md`;
|
||||
|
||||
// Write all 3 files concurrently
|
||||
await Promise.all([
|
||||
write(uxmPath, JSON.stringify(screenUxm, null, 2)),
|
||||
write(mdPath, screenMd),
|
||||
write(renderedPath, screenRendered)
|
||||
]);
|
||||
|
||||
return { uxmPath, mdPath, renderedPath };
|
||||
}
|
||||
```
|
||||
|
||||
## Complete Workflow
|
||||
|
||||
```typescript
|
||||
async function generateScreen(mergedData) {
|
||||
const screenId = `${mergedData.screen.type}-screen`;
|
||||
const allComponentIds = [
|
||||
...mergedData.composition.atomicComponents,
|
||||
...mergedData.composition.compositeComponents
|
||||
];
|
||||
|
||||
// Generate all content
|
||||
const screenUxm = generateScreenUxm(mergedData);
|
||||
const screenMd = generateScreenTemplate(
|
||||
screenId,
|
||||
mergedData.screen.name,
|
||||
mergedData.screen.description,
|
||||
allComponentIds,
|
||||
mergedData
|
||||
);
|
||||
const screenRendered = await generateScreenRendered(
|
||||
screenId,
|
||||
mergedData.screen.name,
|
||||
mergedData.screen.description,
|
||||
mergedData
|
||||
);
|
||||
|
||||
// Write all files
|
||||
const paths = await writeScreenFiles(screenId, screenUxm, screenMd, screenRendered);
|
||||
|
||||
console.log(`✓ Created: ${paths.uxmPath}`);
|
||||
console.log(`✓ Created: ${paths.mdPath}`);
|
||||
console.log(`✓ Created: ${paths.renderedPath}`);
|
||||
|
||||
return { screenId, ...paths };
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```typescript
|
||||
try {
|
||||
const screenResult = await generateScreen(mergedData);
|
||||
console.log(`✅ Screen generated with ${allComponentIds.length} components`);
|
||||
} catch (error) {
|
||||
console.error(`❌ Failed to generate screen: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user