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:
213
admin-ui/js/components/tools/ds-navigation-demos.js
Normal file
213
admin-ui/js/components/tools/ds-navigation-demos.js
Normal file
@@ -0,0 +1,213 @@
|
||||
/**
|
||||
* ds-navigation-demos.js
|
||||
* Gallery of generated HTML navigation flow demos
|
||||
* UX Team Tool #5
|
||||
*/
|
||||
|
||||
import { createGalleryView, setupGalleryHandlers } from '../../utils/tool-templates.js';
|
||||
import { ComponentHelpers } from '../../utils/component-helpers.js';
|
||||
import contextStore from '../../stores/context-store.js';
|
||||
|
||||
class DSNavigationDemos extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.demos = [];
|
||||
this.isLoading = false;
|
||||
}
|
||||
|
||||
async connectedCallback() {
|
||||
this.render();
|
||||
this.setupEventListeners();
|
||||
await this.loadDemos();
|
||||
}
|
||||
|
||||
setupEventListeners() {
|
||||
const generateBtn = this.querySelector('#generate-demo-btn');
|
||||
if (generateBtn) {
|
||||
generateBtn.addEventListener('click', () => this.generateDemo());
|
||||
}
|
||||
}
|
||||
|
||||
async loadDemos() {
|
||||
this.isLoading = true;
|
||||
const container = this.querySelector('#demos-container');
|
||||
if (container) {
|
||||
container.innerHTML = ComponentHelpers.renderLoading('Loading navigation demos...');
|
||||
}
|
||||
|
||||
try {
|
||||
const context = contextStore.getMCPContext();
|
||||
if (!context.project_id) {
|
||||
throw new Error('No project selected');
|
||||
}
|
||||
|
||||
// Load cached demos
|
||||
const cached = localStorage.getItem(`nav_demos_${context.project_id}`);
|
||||
if (cached) {
|
||||
this.demos = JSON.parse(cached);
|
||||
} else {
|
||||
this.demos = [];
|
||||
}
|
||||
|
||||
this.renderDemoGallery();
|
||||
} catch (error) {
|
||||
console.error('[DSNavigationDemos] Failed to load demos:', error);
|
||||
if (container) {
|
||||
container.innerHTML = ComponentHelpers.renderError('Failed to load demos', error);
|
||||
}
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
async generateDemo() {
|
||||
const flowNameInput = this.querySelector('#flow-name-input');
|
||||
const flowName = flowNameInput?.value.trim() || '';
|
||||
|
||||
if (!flowName) {
|
||||
ComponentHelpers.showToast?.('Please enter a flow name', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const generateBtn = this.querySelector('#generate-demo-btn');
|
||||
if (generateBtn) {
|
||||
generateBtn.disabled = true;
|
||||
generateBtn.textContent = '⏳ Generating...';
|
||||
}
|
||||
|
||||
try {
|
||||
const context = contextStore.getMCPContext();
|
||||
|
||||
// Call navigation generation API
|
||||
const response = await fetch('/api/navigation/generate', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
projectId: context.project_id,
|
||||
flowName
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Generation failed: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
// Add to demos
|
||||
const demo = {
|
||||
id: Date.now().toString(),
|
||||
name: flowName,
|
||||
url: result.url,
|
||||
thumbnailUrl: result.thumbnailUrl,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
|
||||
this.demos.unshift(demo);
|
||||
|
||||
// Cache demos
|
||||
if (context.project_id) {
|
||||
localStorage.setItem(`nav_demos_${context.project_id}`, JSON.stringify(this.demos));
|
||||
}
|
||||
|
||||
this.renderDemoGallery();
|
||||
ComponentHelpers.showToast?.(`Demo generated: ${flowName}`, 'success');
|
||||
|
||||
// Clear input
|
||||
if (flowNameInput) {
|
||||
flowNameInput.value = '';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[DSNavigationDemos] Generation failed:', error);
|
||||
ComponentHelpers.showToast?.(`Generation failed: ${error.message}`, 'error');
|
||||
} finally {
|
||||
if (generateBtn) {
|
||||
generateBtn.disabled = false;
|
||||
generateBtn.textContent = '✨ Generate Demo';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderDemoGallery() {
|
||||
const container = this.querySelector('#demos-container');
|
||||
if (!container) return;
|
||||
|
||||
const config = {
|
||||
title: 'Navigation Flow Demos',
|
||||
items: this.demos.map(demo => ({
|
||||
id: demo.id,
|
||||
src: demo.thumbnailUrl,
|
||||
title: demo.name,
|
||||
subtitle: ComponentHelpers.formatRelativeTime(new Date(demo.timestamp))
|
||||
})),
|
||||
onItemClick: (item) => this.viewDemo(item),
|
||||
onDelete: (item) => this.deleteDemo(item)
|
||||
};
|
||||
|
||||
container.innerHTML = createGalleryView(config);
|
||||
setupGalleryHandlers(container, config);
|
||||
}
|
||||
|
||||
viewDemo(item) {
|
||||
const demo = this.demos.find(d => d.id === item.id);
|
||||
if (demo && demo.url) {
|
||||
window.open(demo.url, '_blank');
|
||||
}
|
||||
}
|
||||
|
||||
deleteDemo(item) {
|
||||
this.demos = this.demos.filter(d => d.id !== item.id);
|
||||
|
||||
// Update cache
|
||||
const context = contextStore.getMCPContext();
|
||||
if (context.project_id) {
|
||||
localStorage.setItem(`nav_demos_${context.project_id}`, JSON.stringify(this.demos));
|
||||
}
|
||||
|
||||
this.renderDemoGallery();
|
||||
ComponentHelpers.showToast?.(`Deleted ${item.title}`, 'success');
|
||||
}
|
||||
|
||||
render() {
|
||||
this.innerHTML = `
|
||||
<div style="display: flex; flex-direction: column; height: 100%;">
|
||||
<!-- Generator 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;">Generate Navigation Demo</h3>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr auto; gap: 12px; align-items: end;">
|
||||
<div>
|
||||
<label style="display: block; font-size: 11px; font-weight: 600; margin-bottom: 4px;">
|
||||
Flow Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="flow-name-input"
|
||||
placeholder="e.g., User Onboarding, Checkout Process"
|
||||
class="input"
|
||||
style="width: 100%; font-size: 11px;"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button id="generate-demo-btn" class="button" style="font-size: 11px; padding: 6px 16px;">
|
||||
✨ Generate Demo
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 8px; font-size: 10px; color: var(--vscode-text-dim);">
|
||||
💡 Generates interactive HTML demos of navigation flows
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Demos Gallery -->
|
||||
<div id="demos-container" style="flex: 1; overflow: hidden;">
|
||||
${ComponentHelpers.renderLoading('Loading demos...')}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('ds-navigation-demos', DSNavigationDemos);
|
||||
|
||||
export default DSNavigationDemos;
|
||||
Reference in New Issue
Block a user