| # β‘ Quick Integration Guide | |
| ## 1. Add New CSS Files to HTML | |
| Add these lines to `templates/unified_dashboard.html` in the `<head>` section: | |
| ```html | |
| <!-- NEW: Enterprise Design System --> | |
| <link rel="stylesheet" href="/static/css/design-tokens.css"> | |
| <link rel="stylesheet" href="/static/css/enterprise-components.css"> | |
| <link rel="stylesheet" href="/static/css/navigation.css"> | |
| <link rel="stylesheet" href="/static/css/toast.css"> | |
| <link rel="stylesheet" href="/static/css/accessibility.css"> | |
| ``` | |
| ## 2. Add New JavaScript Files | |
| Add these before the closing `</body>` tag: | |
| ```html | |
| <!-- NEW: Core Libraries --> | |
| <script src="/static/js/icons.js"></script> | |
| <script src="/static/js/provider-discovery.js"></script> | |
| <script src="/static/js/toast.js"></script> | |
| <script src="/static/js/accessibility.js"></script> | |
| ``` | |
| ## 3. Initialize Provider Discovery | |
| Add this script after all JavaScript files are loaded: | |
| ```html | |
| <script> | |
| document.addEventListener('DOMContentLoaded', async () => { | |
| console.log('[App] Initializing...'); | |
| try { | |
| // Initialize provider discovery engine | |
| await providerDiscovery.init(); | |
| // Show success message | |
| toast.success('Provider discovery engine initialized!', { | |
| title: 'System Ready', | |
| duration: 3000 | |
| }); | |
| console.log('[App] Providers loaded:', providerDiscovery.getStats()); | |
| } catch (error) { | |
| console.error('[App] Initialization failed:', error); | |
| toast.error('Failed to initialize provider discovery', { | |
| title: 'Error', | |
| duration: 5000 | |
| }); | |
| } | |
| }); | |
| </script> | |
| ``` | |
| ## 4. Replace Provider Tab Content | |
| Find the "Providers" tab section and replace with: | |
| ```html | |
| <div id="providers-tab" class="tab-content"> | |
| <!-- Provider Stats --> | |
| <div class="grid grid-cols-4 gap-4 mb-4"> | |
| <div class="stat-card"> | |
| <div class="stat-label">Total Providers</div> | |
| <div class="stat-value" id="provider-count-total">200</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-label">Free APIs</div> | |
| <div class="stat-value" id="provider-count-free">150</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-label">Categories</div> | |
| <div class="stat-value" id="provider-count-categories">11</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-label">Online</div> | |
| <div class="stat-value stat-change positive" id="provider-count-online">120</div> | |
| </div> | |
| </div> | |
| <!-- Search & Filters --> | |
| <div class="card mb-4"> | |
| <div class="flex gap-4"> | |
| <input type="search" id="provider-search" | |
| placeholder="Search providers..." | |
| class="form-input flex-1" | |
| role="searchbox" | |
| aria-label="Search providers"> | |
| <select id="provider-category-filter" class="form-select" style="width: 200px;"> | |
| <option value="">All Categories</option> | |
| <option value="market_data">Market Data</option> | |
| <option value="exchange">Exchanges</option> | |
| <option value="defi">DeFi</option> | |
| <option value="blockchain_explorer">Explorers</option> | |
| <option value="news">News</option> | |
| <option value="sentiment">Sentiment</option> | |
| <option value="analytics">Analytics</option> | |
| </select> | |
| <button class="btn btn-secondary" onclick="refreshProviders()"> | |
| <span id="refresh-icon"></span> | |
| Refresh | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Provider Grid --> | |
| <div id="providers-grid" class="grid grid-cols-3 gap-4"> | |
| <!-- Auto-generated by provider-discovery.js --> | |
| </div> | |
| </div> | |
| <script> | |
| // Render providers | |
| async function loadProviders() { | |
| const search = document.getElementById('provider-search').value; | |
| const category = document.getElementById('provider-category-filter').value; | |
| providerDiscovery.renderProviders('providers-grid', { | |
| search: search || undefined, | |
| category: category || undefined, | |
| sortBy: 'priority' | |
| }); | |
| // Update stats | |
| const stats = providerDiscovery.getStats(); | |
| document.getElementById('provider-count-total').textContent = stats.total; | |
| document.getElementById('provider-count-free').textContent = stats.free; | |
| document.getElementById('provider-count-categories').textContent = stats.categories; | |
| document.getElementById('provider-count-online').textContent = stats.statuses.online; | |
| } | |
| function refreshProviders() { | |
| toast.info('Refreshing providers...', { duration: 2000 }); | |
| providerDiscovery.init().then(() => { | |
| loadProviders(); | |
| toast.success('Providers refreshed!', { duration: 2000 }); | |
| }); | |
| } | |
| // Event listeners | |
| document.getElementById('provider-search')?.addEventListener('input', | |
| debounce(loadProviders, 300)); | |
| document.getElementById('provider-category-filter')?.addEventListener('change', | |
| loadProviders); | |
| // Debounce helper | |
| function debounce(func, wait) { | |
| let timeout; | |
| return function(...args) { | |
| clearTimeout(timeout); | |
| timeout = setTimeout(() => func.apply(this, args), wait); | |
| }; | |
| } | |
| // Load on tab switch | |
| // Call loadProviders() when Providers tab becomes active | |
| </script> | |
| ``` | |
| ## 5. Add Icons to Buttons | |
| Replace button content with icon + text: | |
| ```html | |
| <!-- Before --> | |
| <button class="btn btn-primary">Refresh</button> | |
| <!-- After --> | |
| <button class="btn btn-primary"> | |
| ${window.getIcon('refresh', 20)} | |
| Refresh | |
| </button> | |
| <!-- Or use template literals --> | |
| <button class="btn btn-primary" id="refresh-btn"></button> | |
| <script> | |
| document.getElementById('refresh-btn').innerHTML = ` | |
| ${window.getIcon('refresh', 20)} | |
| Refresh | |
| `; | |
| </script> | |
| ``` | |
| ## 6. Use Toast Notifications | |
| Replace `alert()` or `console.log()` with toasts: | |
| ```javascript | |
| // Success messages | |
| toast.success('Data loaded successfully!'); | |
| // Errors | |
| toast.error('Failed to connect to API', { | |
| title: 'Connection Error', | |
| duration: 5000 | |
| }); | |
| // Warnings | |
| toast.warning('API rate limit approaching', { | |
| duration: 4000 | |
| }); | |
| // Info | |
| toast.info('Fetching latest data...', { | |
| duration: 2000 | |
| }); | |
| ``` | |
| ## 7. Make Tables Responsive | |
| Wrap existing tables: | |
| ```html | |
| <!-- Before --> | |
| <table class="table">...</table> | |
| <!-- After --> | |
| <div class="table-container"> | |
| <table class="table table-striped">...</table> | |
| </div> | |
| ``` | |
| ## 8. Add Loading States | |
| ```html | |
| <!-- Skeleton loader --> | |
| <div class="skeleton" style="height: 200px; width: 100%;"></div> | |
| <!-- Spinner --> | |
| <div class="spinner"></div> | |
| <!-- On elements --> | |
| <div id="data-container" aria-busy="true"> | |
| <div class="skeleton" style="height: 100px;"></div> | |
| </div> | |
| <script> | |
| async function loadData() { | |
| const container = document.getElementById('data-container'); | |
| a11y.markAsLoading(container, 'Loading data'); | |
| try { | |
| const data = await fetchData(); | |
| container.innerHTML = renderData(data); | |
| } finally { | |
| a11y.unmarkAsLoading(container); | |
| } | |
| } | |
| </script> | |
| ``` | |
| ## 9. Test Everything | |
| ```javascript | |
| // Check provider discovery | |
| console.log('Providers:', providerDiscovery.getAllProviders().length); | |
| console.log('Categories:', providerDiscovery.getCategories()); | |
| console.log('Stats:', providerDiscovery.getStats()); | |
| // Test toasts | |
| toast.success('Test success'); | |
| toast.error('Test error'); | |
| toast.warning('Test warning'); | |
| toast.info('Test info'); | |
| // Test icons | |
| console.log('Available icons:', window.iconLibrary.getAvailableIcons()); | |
| // Test accessibility | |
| announce('Test announcement', 'polite'); | |
| ``` | |
| ## 10. Optional: Backend Provider Endpoint | |
| Add this to your backend to enable health checks: | |
| ```python | |
| @app.get("/api/providers") | |
| async def get_providers(): | |
| """Return all providers from config""" | |
| import json | |
| with open('providers_config_ultimate.json', 'r') as f: | |
| config = json.load(f) | |
| return config | |
| @app.get("/api/providers/{provider_id}/health") | |
| async def check_provider_health(provider_id: str): | |
| """Check if provider is reachable""" | |
| # Implement actual health check | |
| import httpx | |
| async with httpx.AsyncClient() as client: | |
| try: | |
| # Get provider config and test endpoint | |
| response = await client.get(provider_url, timeout=5.0) | |
| return { | |
| "status": "online" if response.status_code == 200 else "offline", | |
| "response_time": response.elapsed.total_seconds() * 1000 | |
| } | |
| except Exception as e: | |
| return {"status": "offline", "error": str(e)} | |
| ``` | |
| --- | |
| ## β Verification | |
| After integration, verify: | |
| 1. **Design Tokens Work:** | |
| - Open DevTools β Console | |
| - Type: `getComputedStyle(document.body).getPropertyValue('--color-accent-blue')` | |
| - Should return: `#3b82f6` | |
| 2. **Icons Work:** | |
| - Console: `window.iconLibrary.getAvailableIcons()` | |
| - Should return: Array of 50+ icon names | |
| 3. **Provider Discovery Works:** | |
| - Console: `providerDiscovery.getStats()` | |
| - Should return: Object with provider counts | |
| 4. **Toasts Work:** | |
| - Console: `toast.success('Test!')` | |
| - Should show green toast in top-right corner | |
| 5. **Accessibility Works:** | |
| - Press Tab key β Should see blue focus outlines | |
| - Press Ctrl+K β Should focus search box (if configured) | |
| --- | |
| ## π Done! | |
| Your dashboard now has: | |
| - β Enterprise design system | |
| - β Auto-discovery of 200+ providers | |
| - β Beautiful toast notifications | |
| - β SVG icon library | |
| - β Full accessibility | |
| - β Responsive design | |
| Enjoy! π | |