/** * 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 = `