mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-06 01:54:11 +08:00
- Simplified UI design command workflows (batch-generate, explore-auto, generate, update) - Enhanced style-extract and layout-extract with improved documentation - Refactored imitate-auto for better usability - Removed obsolete consolidate workflow - Added extract-computed-styles.js and extract-layout-structure.js utilities - Updated UI generation and instantiation scripts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
222 lines
5.4 KiB
JavaScript
222 lines
5.4 KiB
JavaScript
/**
|
|
* Extract Layout Structure from DOM
|
|
*
|
|
* Extracts real layout information from DOM to provide accurate
|
|
* structural data for UI replication.
|
|
*
|
|
* Usage: Execute via Chrome DevTools evaluate_script
|
|
*/
|
|
|
|
(() => {
|
|
/**
|
|
* Get element's bounding box relative to viewport
|
|
*/
|
|
const getBounds = (element) => {
|
|
const rect = element.getBoundingClientRect();
|
|
return {
|
|
x: Math.round(rect.x),
|
|
y: Math.round(rect.y),
|
|
width: Math.round(rect.width),
|
|
height: Math.round(rect.height)
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Extract layout properties from an element
|
|
*/
|
|
const extractLayoutProps = (element) => {
|
|
const s = window.getComputedStyle(element);
|
|
|
|
return {
|
|
// Core layout
|
|
display: s.display,
|
|
position: s.position,
|
|
|
|
// Flexbox
|
|
flexDirection: s.flexDirection,
|
|
justifyContent: s.justifyContent,
|
|
alignItems: s.alignItems,
|
|
flexWrap: s.flexWrap,
|
|
gap: s.gap,
|
|
|
|
// Grid
|
|
gridTemplateColumns: s.gridTemplateColumns,
|
|
gridTemplateRows: s.gridTemplateRows,
|
|
gridAutoFlow: s.gridAutoFlow,
|
|
|
|
// Dimensions
|
|
width: s.width,
|
|
height: s.height,
|
|
maxWidth: s.maxWidth,
|
|
minWidth: s.minWidth,
|
|
|
|
// Spacing
|
|
padding: s.padding,
|
|
margin: s.margin
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Identify layout pattern for an element
|
|
*/
|
|
const identifyPattern = (props) => {
|
|
const { display, flexDirection, gridTemplateColumns } = props;
|
|
|
|
if (display === 'flex') {
|
|
if (flexDirection === 'column') return 'flex-column';
|
|
if (flexDirection === 'row') return 'flex-row';
|
|
return 'flex';
|
|
}
|
|
|
|
if (display === 'grid') {
|
|
const cols = gridTemplateColumns;
|
|
if (cols && cols !== 'none') {
|
|
const colCount = cols.split(' ').length;
|
|
return `grid-${colCount}col`;
|
|
}
|
|
return 'grid';
|
|
}
|
|
|
|
if (display === 'inline-flex') return 'inline-flex';
|
|
if (display === 'block') return 'block';
|
|
|
|
return display;
|
|
};
|
|
|
|
/**
|
|
* Build layout tree recursively
|
|
*/
|
|
const buildLayoutTree = (element, depth = 0, maxDepth = 3) => {
|
|
if (depth > maxDepth) return null;
|
|
|
|
const props = extractLayoutProps(element);
|
|
const bounds = getBounds(element);
|
|
const pattern = identifyPattern(props);
|
|
|
|
// Get semantic role
|
|
const tagName = element.tagName.toLowerCase();
|
|
const classes = Array.from(element.classList).slice(0, 3); // Max 3 classes
|
|
const role = element.getAttribute('role');
|
|
|
|
// Build node
|
|
const node = {
|
|
tag: tagName,
|
|
classes: classes,
|
|
role: role,
|
|
pattern: pattern,
|
|
bounds: bounds,
|
|
layout: {
|
|
display: props.display,
|
|
position: props.position
|
|
}
|
|
};
|
|
|
|
// Add flex/grid specific properties
|
|
if (props.display === 'flex' || props.display === 'inline-flex') {
|
|
node.layout.flexDirection = props.flexDirection;
|
|
node.layout.justifyContent = props.justifyContent;
|
|
node.layout.alignItems = props.alignItems;
|
|
node.layout.gap = props.gap;
|
|
}
|
|
|
|
if (props.display === 'grid') {
|
|
node.layout.gridTemplateColumns = props.gridTemplateColumns;
|
|
node.layout.gridTemplateRows = props.gridTemplateRows;
|
|
node.layout.gap = props.gap;
|
|
}
|
|
|
|
// Process children for container elements
|
|
if (props.display === 'flex' || props.display === 'grid' || props.display === 'block') {
|
|
const children = Array.from(element.children);
|
|
if (children.length > 0 && children.length < 50) { // Limit to 50 children
|
|
node.children = children
|
|
.map(child => buildLayoutTree(child, depth + 1, maxDepth))
|
|
.filter(child => child !== null);
|
|
}
|
|
}
|
|
|
|
return node;
|
|
};
|
|
|
|
/**
|
|
* Find main layout containers
|
|
*/
|
|
const findMainContainers = () => {
|
|
const selectors = [
|
|
'body > header',
|
|
'body > nav',
|
|
'body > main',
|
|
'body > footer',
|
|
'[role="banner"]',
|
|
'[role="navigation"]',
|
|
'[role="main"]',
|
|
'[role="contentinfo"]'
|
|
];
|
|
|
|
const containers = [];
|
|
|
|
selectors.forEach(selector => {
|
|
const element = document.querySelector(selector);
|
|
if (element) {
|
|
const tree = buildLayoutTree(element, 0, 3);
|
|
if (tree) {
|
|
containers.push(tree);
|
|
}
|
|
}
|
|
});
|
|
|
|
return containers;
|
|
};
|
|
|
|
/**
|
|
* Analyze layout patterns
|
|
*/
|
|
const analyzePatterns = (containers) => {
|
|
const patterns = {
|
|
flexColumn: 0,
|
|
flexRow: 0,
|
|
grid: 0,
|
|
sticky: 0,
|
|
fixed: 0
|
|
};
|
|
|
|
const analyze = (node) => {
|
|
if (!node) return;
|
|
|
|
if (node.pattern === 'flex-column') patterns.flexColumn++;
|
|
if (node.pattern === 'flex-row') patterns.flexRow++;
|
|
if (node.pattern && node.pattern.startsWith('grid')) patterns.grid++;
|
|
if (node.layout.position === 'sticky') patterns.sticky++;
|
|
if (node.layout.position === 'fixed') patterns.fixed++;
|
|
|
|
if (node.children) {
|
|
node.children.forEach(analyze);
|
|
}
|
|
};
|
|
|
|
containers.forEach(analyze);
|
|
return patterns;
|
|
};
|
|
|
|
/**
|
|
* Main extraction function
|
|
*/
|
|
const extractLayout = () => {
|
|
const containers = findMainContainers();
|
|
const patterns = analyzePatterns(containers);
|
|
|
|
return {
|
|
metadata: {
|
|
extractedAt: new Date().toISOString(),
|
|
url: window.location.href,
|
|
method: 'layout-structure'
|
|
},
|
|
patterns: patterns,
|
|
structure: containers
|
|
};
|
|
};
|
|
|
|
// Execute and return results
|
|
return extractLayout();
|
|
})();
|