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
121 lines
3.1 KiB
JavaScript
121 lines
3.1 KiB
JavaScript
/**
|
|
* ds-panel.js
|
|
* Bottom panel component - holds team-specific tabs
|
|
*/
|
|
|
|
import { getPanelConfig } from '../../config/panel-config.js';
|
|
|
|
class DSPanel extends HTMLElement {
|
|
constructor() {
|
|
super();
|
|
this.currentTab = null;
|
|
this.tabs = [];
|
|
this.advancedMode = false;
|
|
}
|
|
|
|
/**
|
|
* Configure panel with team-specific tabs
|
|
* @param {string} teamId - Team identifier (ui, ux, qa, admin)
|
|
* @param {boolean} advancedMode - Whether advanced mode is enabled
|
|
*/
|
|
configure(teamId, advancedMode = false) {
|
|
this.advancedMode = advancedMode;
|
|
this.tabs = getPanelConfig(teamId, advancedMode);
|
|
|
|
// Set first tab as current if not already set
|
|
if (this.tabs.length > 0 && !this.currentTab) {
|
|
this.currentTab = this.tabs[0].id;
|
|
}
|
|
|
|
// Re-render with new configuration
|
|
this.render();
|
|
this.setupEventListeners();
|
|
}
|
|
|
|
connectedCallback() {
|
|
this.render();
|
|
this.setupEventListeners();
|
|
}
|
|
|
|
render() {
|
|
this.innerHTML = `
|
|
<div class="panel-header">
|
|
${this.tabs.map(tab => `
|
|
<div class="panel-tab ${tab.id === this.currentTab ? 'active' : ''}"
|
|
data-tab="${tab.id}">
|
|
${tab.label}
|
|
</div>
|
|
`).join('')}
|
|
</div>
|
|
<div class="panel-content">
|
|
<div id="panel-tab-content">
|
|
${this.renderTabContent(this.currentTab)}
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
setupEventListeners() {
|
|
this.querySelectorAll('.panel-tab').forEach(tab => {
|
|
tab.addEventListener('click', (e) => {
|
|
const tabId = e.currentTarget.dataset.tab;
|
|
this.switchTab(tabId);
|
|
});
|
|
});
|
|
}
|
|
|
|
switchTab(tabId) {
|
|
if (tabId === this.currentTab) return;
|
|
|
|
this.currentTab = tabId;
|
|
|
|
// Update active state
|
|
this.querySelectorAll('.panel-tab').forEach(tab => {
|
|
tab.classList.toggle('active', tab.dataset.tab === tabId);
|
|
});
|
|
|
|
// Update content
|
|
const content = this.querySelector('#panel-tab-content');
|
|
if (content) {
|
|
content.innerHTML = this.renderTabContent(tabId);
|
|
}
|
|
|
|
// Dispatch tab-switch event
|
|
this.dispatchEvent(new CustomEvent('panel-tab-switch', {
|
|
bubbles: true,
|
|
detail: { tab: tabId }
|
|
}));
|
|
}
|
|
|
|
renderTabContent(tabId) {
|
|
// Find tab configuration
|
|
const tabConfig = this.tabs.find(tab => tab.id === tabId);
|
|
if (!tabConfig) {
|
|
return '<div style="padding: 16px; color: var(--vscode-text-dim);">Tab not found</div>';
|
|
}
|
|
|
|
// Dynamically create component based on configuration
|
|
const componentTag = tabConfig.component;
|
|
const propsString = Object.entries(tabConfig.props || {})
|
|
.map(([key, value]) => `${key}="${value}"`)
|
|
.join(' ');
|
|
|
|
return `<${componentTag} ${propsString}></${componentTag}>`;
|
|
}
|
|
|
|
// Public method for workdesks to update panel content
|
|
setTabContent(tabId, content) {
|
|
const tabContent = this.querySelector('#panel-tab-content');
|
|
if (this.currentTab === tabId && tabContent) {
|
|
if (typeof content === 'string') {
|
|
tabContent.innerHTML = content;
|
|
} else {
|
|
tabContent.innerHTML = '';
|
|
tabContent.appendChild(content);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
customElements.define('ds-panel', DSPanel);
|