Initial commit: Clean DSS implementation
Migrated from design-system-swarm with fresh git history.
Old project history preserved in /home/overbits/apps/design-system-swarm
Core components:
- MCP Server (Python FastAPI with mcp 1.23.1)
- Claude Plugin (agents, commands, skills, strategies, hooks, core)
- DSS Backend (dss-mvp1 - token translation, Figma sync)
- Admin UI (Node.js/React)
- Server (Node.js/Express)
- Storybook integration (dss-mvp1/.storybook)
Self-contained configuration:
- All paths relative or use DSS_BASE_PATH=/home/overbits/dss
- PYTHONPATH configured for dss-mvp1 and dss-claude-plugin
- .env file with all configuration
- Claude plugin uses ${CLAUDE_PLUGIN_ROOT} for portability
Migration completed: $(date)
🤖 Clean migration with full functionality preserved
This commit is contained in:
174
admin-ui/js/components/tools/ds-storybook-figma-compare.js
Normal file
174
admin-ui/js/components/tools/ds-storybook-figma-compare.js
Normal file
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* ds-storybook-figma-compare.js
|
||||
* Side-by-side Storybook and Figma component comparison
|
||||
* UI Team Tool #1
|
||||
*/
|
||||
|
||||
import { createComparisonView, setupComparisonHandlers } from '../../utils/tool-templates.js';
|
||||
import { ComponentHelpers } from '../../utils/component-helpers.js';
|
||||
import contextStore from '../../stores/context-store.js';
|
||||
import apiClient from '../../services/api-client.js';
|
||||
|
||||
class DSStorybookFigmaCompare extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.storybookUrl = '';
|
||||
this.figmaUrl = '';
|
||||
this.selectedComponent = null;
|
||||
}
|
||||
|
||||
async connectedCallback() {
|
||||
await this.loadProjectConfig();
|
||||
this.render();
|
||||
this.setupEventListeners();
|
||||
}
|
||||
|
||||
async loadProjectConfig() {
|
||||
try {
|
||||
const context = contextStore.getMCPContext();
|
||||
if (!context.project_id) {
|
||||
throw new Error('No project selected');
|
||||
}
|
||||
|
||||
// Fetch project configuration to get Storybook URL and Figma file
|
||||
const project = await apiClient.getProject(context.project_id);
|
||||
this.storybookUrl = project.storybook_url || '';
|
||||
this.figmaUrl = project.figma_ui_file || '';
|
||||
} catch (error) {
|
||||
console.error('[DSStorybookFigmaCompare] Failed to load project config:', error);
|
||||
}
|
||||
}
|
||||
|
||||
setupEventListeners() {
|
||||
const storybookInput = this.querySelector('#storybook-url-input');
|
||||
const figmaInput = this.querySelector('#figma-url-input');
|
||||
const loadBtn = this.querySelector('#load-comparison-btn');
|
||||
|
||||
if (storybookInput) {
|
||||
storybookInput.value = this.storybookUrl;
|
||||
}
|
||||
|
||||
if (figmaInput) {
|
||||
figmaInput.value = this.figmaUrl;
|
||||
}
|
||||
|
||||
if (loadBtn) {
|
||||
loadBtn.addEventListener('click', () => this.loadComparison());
|
||||
}
|
||||
|
||||
// Setup comparison handlers (sync scroll, zoom, etc.)
|
||||
const comparisonContainer = this.querySelector('#comparison-container');
|
||||
if (comparisonContainer) {
|
||||
setupComparisonHandlers(comparisonContainer, {});
|
||||
}
|
||||
}
|
||||
|
||||
loadComparison() {
|
||||
const storybookInput = this.querySelector('#storybook-url-input');
|
||||
const figmaInput = this.querySelector('#figma-url-input');
|
||||
|
||||
this.storybookUrl = storybookInput?.value || '';
|
||||
this.figmaUrl = figmaInput?.value || '';
|
||||
|
||||
if (!this.storybookUrl || !this.figmaUrl) {
|
||||
ComponentHelpers.showToast?.('Please enter both Storybook and Figma URLs', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate URLs
|
||||
try {
|
||||
new URL(this.storybookUrl);
|
||||
new URL(this.figmaUrl);
|
||||
} catch (error) {
|
||||
ComponentHelpers.showToast?.('Invalid URL format', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Update comparison view
|
||||
const comparisonContainer = this.querySelector('#comparison-container');
|
||||
if (comparisonContainer) {
|
||||
comparisonContainer.innerHTML = createComparisonView({
|
||||
leftTitle: 'Storybook',
|
||||
rightTitle: 'Figma',
|
||||
leftSrc: this.storybookUrl,
|
||||
rightSrc: this.figmaUrl
|
||||
});
|
||||
|
||||
// Re-setup handlers after re-render
|
||||
setupComparisonHandlers(comparisonContainer, {});
|
||||
|
||||
ComponentHelpers.showToast?.('Comparison loaded', 'success');
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
this.innerHTML = `
|
||||
<div style="display: flex; flex-direction: column; height: 100%;">
|
||||
<!-- Configuration Panel -->
|
||||
<div style="padding: 16px; border-bottom: 1px solid var(--vscode-border); background: var(--vscode-sidebar);">
|
||||
<h3 style="font-size: 12px; font-weight: 600; margin-bottom: 12px;">Component Comparison Configuration</h3>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr auto; gap: 12px; align-items: end;">
|
||||
<div>
|
||||
<label style="display: block; font-size: 11px; font-weight: 600; margin-bottom: 4px; color: var(--vscode-text-dim);">
|
||||
Storybook URL
|
||||
</label>
|
||||
<input
|
||||
type="url"
|
||||
id="storybook-url-input"
|
||||
placeholder="https://storybook.example.com/..."
|
||||
class="input"
|
||||
style="width: 100%; font-size: 11px;"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label style="display: block; font-size: 11px; font-weight: 600; margin-bottom: 4px; color: var(--vscode-text-dim);">
|
||||
Figma URL
|
||||
</label>
|
||||
<input
|
||||
type="url"
|
||||
id="figma-url-input"
|
||||
placeholder="https://figma.com/file/..."
|
||||
class="input"
|
||||
style="width: 100%; font-size: 11px;"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button id="load-comparison-btn" class="button" style="font-size: 11px; padding: 6px 16px;">
|
||||
🔍 Load Comparison
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 8px; font-size: 10px; color: var(--vscode-text-dim);">
|
||||
💡 Tip: Navigate to the same component in both Storybook and Figma for accurate comparison
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Comparison View -->
|
||||
<div id="comparison-container" style="flex: 1; overflow: hidden;">
|
||||
${this.storybookUrl && this.figmaUrl ? createComparisonView({
|
||||
leftTitle: 'Storybook',
|
||||
rightTitle: 'Figma',
|
||||
leftSrc: this.storybookUrl,
|
||||
rightSrc: this.figmaUrl
|
||||
}) : `
|
||||
<div style="display: flex; align-items: center; justify-content: center; height: 100%; text-align: center; padding: 48px;">
|
||||
<div>
|
||||
<div style="font-size: 48px; margin-bottom: 16px;">🔍</div>
|
||||
<h3 style="font-size: 14px; font-weight: 600; margin-bottom: 8px;">No Comparison Loaded</h3>
|
||||
<p style="font-size: 12px; color: var(--vscode-text-dim);">
|
||||
Enter Storybook and Figma URLs above to start comparing components
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
`}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('ds-storybook-figma-compare', DSStorybookFigmaCompare);
|
||||
|
||||
export default DSStorybookFigmaCompare;
|
||||
Reference in New Issue
Block a user