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
234 lines
6.9 KiB
JavaScript
234 lines
6.9 KiB
JavaScript
/**
|
|
* ds-esre-editor.js
|
|
* Editor for ESRE (Explicit Style Requirements and Expectations)
|
|
* QA Team Tool #2
|
|
*/
|
|
|
|
import { createEditorView, setupEditorHandlers } from '../../utils/tool-templates.js';
|
|
import { ComponentHelpers } from '../../utils/component-helpers.js';
|
|
import contextStore from '../../stores/context-store.js';
|
|
|
|
class DSESREEditor extends HTMLElement {
|
|
constructor() {
|
|
super();
|
|
this.esreContent = '';
|
|
this.isSaving = false;
|
|
}
|
|
|
|
async connectedCallback() {
|
|
this.render();
|
|
await this.loadESRE();
|
|
}
|
|
|
|
async loadESRE() {
|
|
try {
|
|
const context = contextStore.getMCPContext();
|
|
if (!context.project_id) {
|
|
throw new Error('No project selected');
|
|
}
|
|
|
|
// Load ESRE from project configuration
|
|
const response = await fetch(`/api/projects/${context.project_id}/esre`);
|
|
if (response.ok) {
|
|
const result = await response.json();
|
|
this.esreContent = result.content || '';
|
|
this.renderEditor();
|
|
} else {
|
|
// No ESRE yet, start with template
|
|
this.esreContent = this.getESRETemplate();
|
|
this.renderEditor();
|
|
}
|
|
} catch (error) {
|
|
console.error('[DSESREEditor] Failed to load ESRE:', error);
|
|
this.esreContent = this.getESRETemplate();
|
|
this.renderEditor();
|
|
}
|
|
}
|
|
|
|
getESRETemplate() {
|
|
return `# Explicit Style Requirements and Expectations (ESRE)
|
|
|
|
## Project: ${contextStore.get('projectId') || 'Design System'}
|
|
|
|
### Color Requirements
|
|
- Primary colors must match Figma specifications exactly
|
|
- Accessibility: All text must meet WCAG 2.1 AA contrast ratios
|
|
- Color tokens must be used instead of hardcoded hex values
|
|
|
|
### Typography Requirements
|
|
- Font families: [Specify approved fonts]
|
|
- Font sizes must use design system scale
|
|
- Line heights must maintain readability
|
|
- Letter spacing should follow design specifications
|
|
|
|
### Spacing Requirements
|
|
- All spacing must use design system spacing scale
|
|
- Margins and padding should be consistent across components
|
|
- Grid system: [Specify grid specifications]
|
|
|
|
### Component Requirements
|
|
- All components must be built from design system primitives
|
|
- Component variants must match Figma component variants
|
|
- Props should follow naming conventions
|
|
|
|
### Responsive Requirements
|
|
- Breakpoints: [Specify breakpoints]
|
|
- Mobile-first approach required
|
|
- Touch targets must be at least 44x44px
|
|
|
|
### Accessibility Requirements
|
|
- All interactive elements must be keyboard accessible
|
|
- ARIA labels required for icon-only buttons
|
|
- Focus indicators must be visible
|
|
- Screen reader testing required
|
|
|
|
### Performance Requirements
|
|
- Initial load time: [Specify target]
|
|
- Time to Interactive: [Specify target]
|
|
- Bundle size limits: [Specify limits]
|
|
|
|
### Browser Support
|
|
- Chrome: Latest 2 versions
|
|
- Firefox: Latest 2 versions
|
|
- Safari: Latest 2 versions
|
|
- Edge: Latest 2 versions
|
|
|
|
---
|
|
|
|
## Validation Checklist
|
|
|
|
### Pre-Deployment
|
|
- [ ] All colors match Figma specifications
|
|
- [ ] Typography follows design system scale
|
|
- [ ] Spacing uses design tokens
|
|
- [ ] Components match design system library
|
|
- [ ] Responsive behavior validated
|
|
- [ ] Accessibility audit passed
|
|
- [ ] Performance metrics met
|
|
- [ ] Cross-browser testing completed
|
|
|
|
### QA Testing
|
|
- [ ] Visual comparison with Figma
|
|
- [ ] Keyboard navigation tested
|
|
- [ ] Screen reader compatibility verified
|
|
- [ ] Mobile devices tested
|
|
- [ ] Edge cases validated
|
|
|
|
---
|
|
|
|
Last updated: ${new Date().toISOString().split('T')[0]}
|
|
`;
|
|
}
|
|
|
|
renderEditor() {
|
|
const container = this.querySelector('#editor-container');
|
|
if (!container) return;
|
|
|
|
const config = {
|
|
title: 'ESRE Editor',
|
|
content: this.esreContent,
|
|
language: 'markdown',
|
|
onSave: (content) => this.saveESRE(content),
|
|
onExport: (content) => this.exportESRE(content)
|
|
};
|
|
|
|
container.innerHTML = createEditorView(config);
|
|
setupEditorHandlers(container, config);
|
|
}
|
|
|
|
async saveESRE(content) {
|
|
this.isSaving = true;
|
|
const saveBtn = document.querySelector('#editor-save-btn');
|
|
if (saveBtn) {
|
|
saveBtn.disabled = true;
|
|
saveBtn.textContent = '⏳ Saving...';
|
|
}
|
|
|
|
try {
|
|
const context = contextStore.getMCPContext();
|
|
if (!context.project_id) {
|
|
throw new Error('No project selected');
|
|
}
|
|
|
|
// Save ESRE via API
|
|
const response = await fetch('/api/esre/save', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
projectId: context.project_id,
|
|
content
|
|
})
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Save failed: ${response.statusText}`);
|
|
}
|
|
|
|
this.esreContent = content;
|
|
ComponentHelpers.showToast?.('ESRE saved successfully', 'success');
|
|
} catch (error) {
|
|
console.error('[DSESREEditor] Save failed:', error);
|
|
ComponentHelpers.showToast?.(`Save failed: ${error.message}`, 'error');
|
|
} finally {
|
|
this.isSaving = false;
|
|
if (saveBtn) {
|
|
saveBtn.disabled = false;
|
|
saveBtn.textContent = '💾 Save';
|
|
}
|
|
}
|
|
}
|
|
|
|
exportESRE(content) {
|
|
const blob = new Blob([content], { type: 'text/markdown' });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
const projectId = contextStore.get('projectId') || 'project';
|
|
a.href = url;
|
|
a.download = `${projectId}-esre.md`;
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
ComponentHelpers.showToast?.('ESRE exported', 'success');
|
|
}
|
|
|
|
render() {
|
|
this.innerHTML = `
|
|
<div style="display: flex; flex-direction: column; height: 100%;">
|
|
<!-- Info Banner -->
|
|
<div style="padding: 12px 16px; background: rgba(255, 191, 0, 0.1); border-bottom: 1px solid var(--vscode-border);">
|
|
<div style="display: flex; align-items: center; gap: 12px;">
|
|
<div style="font-size: 20px;">📋</div>
|
|
<div style="flex: 1;">
|
|
<div style="font-size: 11px; font-weight: 600; margin-bottom: 2px;">
|
|
ESRE: Explicit Style Requirements and Expectations
|
|
</div>
|
|
<div style="font-size: 10px; color: var(--vscode-text-dim);">
|
|
Define clear specifications for design implementation and QA validation
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Editor Container -->
|
|
<div id="editor-container" style="flex: 1; overflow: hidden;">
|
|
${createEditorView({
|
|
title: 'ESRE Editor',
|
|
content: this.esreContent,
|
|
language: 'markdown',
|
|
onSave: (content) => this.saveESRE(content),
|
|
onExport: (content) => this.exportESRE(content)
|
|
})}
|
|
</div>
|
|
|
|
<!-- Help Footer -->
|
|
<div style="padding: 8px 16px; border-top: 1px solid var(--vscode-border); font-size: 10px; color: var(--vscode-text-dim);">
|
|
💡 Tip: Use Markdown formatting for clear documentation. Save changes before closing.
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
customElements.define('ds-esre-editor', DSESREEditor);
|
|
|
|
export default DSESREEditor;
|