nimazasinich
commited on
Commit
·
088f23f
1
Parent(s):
95f2676
Add files via upload
Browse files- PROJECT_STRUCTURE_REPORT.md +128 -0
- UI_STRUCTURE_GUIDE.md +339 -0
- UI_USAGE_SCRIPT.md +715 -0
PROJECT_STRUCTURE_REPORT.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Crypto Data Source - Project Structure Report
|
| 2 |
+
|
| 3 |
+
## Overview
|
| 4 |
+
|
| 5 |
+
A comprehensive cryptocurrency data aggregation and analysis platform designed for deployment on Hugging Face Spaces. The system provides real-time market data, AI-powered sentiment analysis, trading signals, and multi-source data aggregation.
|
| 6 |
+
|
| 7 |
+
## Architecture Layers
|
| 8 |
+
|
| 9 |
+
### 1. **Entry Points**
|
| 10 |
+
|
| 11 |
+
- **`main.py`**: FastAPI entry point for HuggingFace Spaces (port 7860)
|
| 12 |
+
- **`app.py`**: Flask-based fallback server with basic endpoints
|
| 13 |
+
- **`hf_unified_server.py`**: Main FastAPI application with unified routing
|
| 14 |
+
|
| 15 |
+
### 2. **API Layer** (`/api/`)
|
| 16 |
+
|
| 17 |
+
- **FastAPI Routers** (`backend/routers/`): 28 router modules for different API domains
|
| 18 |
+
- **Legacy Endpoints** (`api/`): 15+ endpoint modules for various services
|
| 19 |
+
- **WebSocket Support**: Real-time data streaming via WebSocket endpoints
|
| 20 |
+
- **Key Features**:
|
| 21 |
+
- Multi-source data aggregation
|
| 22 |
+
- AI trading signals and sentiment analysis
|
| 23 |
+
- OHLCV data endpoints
|
| 24 |
+
- News aggregation
|
| 25 |
+
- Resource management APIs
|
| 26 |
+
|
| 27 |
+
### 3. **Backend Services** (`backend/services/`)
|
| 28 |
+
|
| 29 |
+
- **70 service modules** organized by functionality:
|
| 30 |
+
- **Data Collection**: `unified_data_collector.py`, `market_data_aggregator.py`, `news_aggregator.py`
|
| 31 |
+
- **AI/ML**: `real_ai_models.py`, `ai_service_unified.py`, `hf_inference_api_client.py`
|
| 32 |
+
- **Trading**: `futures_trading_service.py`, `backtesting_service.py`
|
| 33 |
+
- **Providers**: Integration with CoinGecko, Binance, CryptoPanic, etc.
|
| 34 |
+
- **Fallback Management**: `multi_source_fallback_engine.py`, `provider_fallback_manager.py`
|
| 35 |
+
- **Resource Management**: `master_resource_orchestrator.py`, `resources_registry_service.py`
|
| 36 |
+
|
| 37 |
+
### 4. **Data Collection** (`collectors/`)
|
| 38 |
+
|
| 39 |
+
- **15 collector modules** for:
|
| 40 |
+
- Market data collection
|
| 41 |
+
- News aggregation
|
| 42 |
+
- Sentiment analysis
|
| 43 |
+
- On-chain data
|
| 44 |
+
- Whale tracking
|
| 45 |
+
- Scheduled data collection
|
| 46 |
+
|
| 47 |
+
### 5. **Database Layer** (`database/`)
|
| 48 |
+
|
| 49 |
+
- **SQLAlchemy models** (`models.py`)
|
| 50 |
+
- **Database manager** (`db_manager.py`)
|
| 51 |
+
- **Data access layer** (`data_access.py`)
|
| 52 |
+
- **Migration support** (`migrations.py`)
|
| 53 |
+
- **Schema definition** (`schema_complete.sql`)
|
| 54 |
+
|
| 55 |
+
### 6. **Monitoring & Health** (`monitoring/`)
|
| 56 |
+
|
| 57 |
+
- Health checking system
|
| 58 |
+
- Rate limiting
|
| 59 |
+
- Source pool management
|
| 60 |
+
- Scheduler for background tasks
|
| 61 |
+
|
| 62 |
+
### 7. **Core Infrastructure** (`core/`)
|
| 63 |
+
|
| 64 |
+
- Smart proxy manager
|
| 65 |
+
- Smart fallback manager
|
| 66 |
+
- Resource management utilities
|
| 67 |
+
|
| 68 |
+
### 8. **Configuration**
|
| 69 |
+
|
| 70 |
+
- **`config.py`**: Main configuration with HuggingFace integration
|
| 71 |
+
- **`providers_config_extended.json`**: Provider configurations
|
| 72 |
+
- **`api-resources/`**: Unified API resource registry
|
| 73 |
+
- **Strategy/Scoring configs**: Trading and scoring configurations
|
| 74 |
+
|
| 75 |
+
### 9. **Frontend** (`static/`, `templates/`)
|
| 76 |
+
|
| 77 |
+
- **263 static files**: HTML, CSS, JavaScript
|
| 78 |
+
- Dashboard UI
|
| 79 |
+
- System monitoring interface
|
| 80 |
+
- Multi-page architecture
|
| 81 |
+
|
| 82 |
+
### 10. **Workers** (`workers/`)
|
| 83 |
+
|
| 84 |
+
- Background worker processes
|
| 85 |
+
- Data processing tasks
|
| 86 |
+
|
| 87 |
+
## Key Technologies
|
| 88 |
+
|
| 89 |
+
- **Backend**: FastAPI, Flask
|
| 90 |
+
- **AI/ML**: HuggingFace Inference API, custom sentiment models
|
| 91 |
+
- **Data Sources**: CoinGecko, Binance, CryptoPanic, AlphaVantage, etc.
|
| 92 |
+
- **Database**: SQLAlchemy (SQLite/PostgreSQL)
|
| 93 |
+
- **Real-time**: WebSocket support
|
| 94 |
+
- **Deployment**: Docker, HuggingFace Spaces
|
| 95 |
+
|
| 96 |
+
## Key Features
|
| 97 |
+
|
| 98 |
+
1. **Multi-Source Data Aggregation**: Aggregates data from 70+ API providers
|
| 99 |
+
2. **AI-Powered Analysis**: Sentiment analysis, trading signals, decision support
|
| 100 |
+
3. **Fallback System**: Automatic failover between data sources
|
| 101 |
+
4. **Real-time Updates**: WebSocket support for live data streaming
|
| 102 |
+
5. **Resource Management**: Dynamic API key rotation and smart access management
|
| 103 |
+
6. **Health Monitoring**: Self-healing system with health checks
|
| 104 |
+
7. **Trading Support**: Backtesting, futures trading, signal generation
|
| 105 |
+
|
| 106 |
+
## Project Statistics
|
| 107 |
+
|
| 108 |
+
- **Total Python Files**: ~200+
|
| 109 |
+
- **API Endpoints**: 100+ endpoints across multiple routers
|
| 110 |
+
- **Service Modules**: 70 backend services
|
| 111 |
+
- **Data Collectors**: 15 collector modules
|
| 112 |
+
- **API Providers**: 70+ integrated providers
|
| 113 |
+
- **Frontend Assets**: 263 static files
|
| 114 |
+
|
| 115 |
+
## Deployment
|
| 116 |
+
|
| 117 |
+
- **Primary**: HuggingFace Spaces (Docker)
|
| 118 |
+
- **Port**: 7860 (HF standard)
|
| 119 |
+
- **Entry Point**: `hf_unified_server:app`
|
| 120 |
+
- **Health Check**: `/api/health`
|
| 121 |
+
|
| 122 |
+
## Notable Design Patterns
|
| 123 |
+
|
| 124 |
+
- **Multi-source fallback**: Automatic provider switching on failure
|
| 125 |
+
- **Lazy loading**: Resources loaded on-demand to optimize memory
|
| 126 |
+
- **Service-oriented**: Modular service architecture
|
| 127 |
+
- **Router-based**: FastAPI router pattern for API organization
|
| 128 |
+
- **Provider abstraction**: Unified interface for multiple data sources
|
UI_STRUCTURE_GUIDE.md
ADDED
|
@@ -0,0 +1,339 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Crypto Intelligence Hub - UI Structure Guide
|
| 2 |
+
|
| 3 |
+
## Overview
|
| 4 |
+
|
| 5 |
+
The application uses a **multi-page architecture** with shared components and a dynamic layout injection system. Each page is standalone but shares common layouts, utilities, and components.
|
| 6 |
+
|
| 7 |
+
## Architecture
|
| 8 |
+
|
| 9 |
+
### 1. **Page Structure** (`/static/pages/`)
|
| 10 |
+
|
| 11 |
+
Each page is a self-contained module in its own directory:
|
| 12 |
+
|
| 13 |
+
```
|
| 14 |
+
static/pages/
|
| 15 |
+
├── dashboard/ # Main dashboard with stats
|
| 16 |
+
├── market/ # Market data and prices
|
| 17 |
+
├── models/ # AI models status
|
| 18 |
+
├── sentiment/ # Sentiment analysis
|
| 19 |
+
├── ai-analyst/ # AI trading advisor
|
| 20 |
+
├── trading-assistant/ # Trading signals
|
| 21 |
+
├── news/ # News feed
|
| 22 |
+
├── providers/ # API provider management
|
| 23 |
+
├── diagnostics/ # System diagnostics
|
| 24 |
+
└── api-explorer/ # API testing tool
|
| 25 |
+
```
|
| 26 |
+
|
| 27 |
+
**Page Template Structure:**
|
| 28 |
+
|
| 29 |
+
```html
|
| 30 |
+
<!DOCTYPE html>
|
| 31 |
+
<html>
|
| 32 |
+
<head>
|
| 33 |
+
<!-- Meta, CSS imports -->
|
| 34 |
+
<!-- Shared CSS: design-system, layout, components -->
|
| 35 |
+
<!-- Page-specific CSS -->
|
| 36 |
+
</head>
|
| 37 |
+
<body>
|
| 38 |
+
<div class="app-container">
|
| 39 |
+
<!-- Layout containers (injected by LayoutManager) -->
|
| 40 |
+
<aside id="sidebar-container"></aside>
|
| 41 |
+
<header id="header-container"></header>
|
| 42 |
+
|
| 43 |
+
<!-- Page-specific content -->
|
| 44 |
+
<main class="main-content">
|
| 45 |
+
<div class="page-content">
|
| 46 |
+
<!-- Your page content here -->
|
| 47 |
+
</div>
|
| 48 |
+
</main>
|
| 49 |
+
</div>
|
| 50 |
+
|
| 51 |
+
<!-- Scripts -->
|
| 52 |
+
<script type="module">
|
| 53 |
+
// Initialize LayoutManager
|
| 54 |
+
import LayoutManager from '/static/shared/js/core/layout-manager.js';
|
| 55 |
+
await LayoutManager.init('page-name');
|
| 56 |
+
|
| 57 |
+
// Your page logic here
|
| 58 |
+
</script>
|
| 59 |
+
</body>
|
| 60 |
+
</html>
|
| 61 |
+
```
|
| 62 |
+
|
| 63 |
+
### 2. **Shared Components** (`/static/shared/`)
|
| 64 |
+
|
| 65 |
+
#### **Layouts** (`/shared/layouts/`)
|
| 66 |
+
|
| 67 |
+
- `header.html` - App header with status badge
|
| 68 |
+
- `sidebar.html` - Navigation sidebar
|
| 69 |
+
- `footer.html` - Footer content
|
| 70 |
+
|
| 71 |
+
#### **Core JavaScript** (`/shared/js/core/`)
|
| 72 |
+
|
| 73 |
+
- `layout-manager.js` - Injects layouts, manages navigation
|
| 74 |
+
- `api-client.js` - HTTP client with caching
|
| 75 |
+
- `polling-manager.js` - Auto-refresh system
|
| 76 |
+
- `config.js` - Central configuration
|
| 77 |
+
|
| 78 |
+
#### **Components** (`/shared/js/components/`)
|
| 79 |
+
|
| 80 |
+
- `toast.js` - Notification system
|
| 81 |
+
- `modal.js` - Modal dialogs
|
| 82 |
+
- `table.js` - Data tables
|
| 83 |
+
- `chart.js` - Chart.js wrapper
|
| 84 |
+
- `loading.js` - Loading states
|
| 85 |
+
|
| 86 |
+
#### **CSS** (`/shared/css/`)
|
| 87 |
+
|
| 88 |
+
- `design-system.css` - CSS variables, tokens
|
| 89 |
+
- `global.css` - Base styles
|
| 90 |
+
- `layout.css` - Layout styles
|
| 91 |
+
- `components.css` - Component styles
|
| 92 |
+
|
| 93 |
+
### 3. **NewResourceApi** (`/NewResourceApi/`)
|
| 94 |
+
|
| 95 |
+
Protobuf-based API structure for resource management:
|
| 96 |
+
|
| 97 |
+
- `api.py` - API definitions
|
| 98 |
+
- `api_pb2.py` - Generated protobuf code
|
| 99 |
+
- `test_api.py` - API testing utilities
|
| 100 |
+
|
| 101 |
+
## Key Systems
|
| 102 |
+
|
| 103 |
+
### Layout Manager
|
| 104 |
+
|
| 105 |
+
**Purpose:** Dynamically injects shared layouts (header, sidebar, footer) into pages.
|
| 106 |
+
|
| 107 |
+
**Usage:**
|
| 108 |
+
|
| 109 |
+
```javascript
|
| 110 |
+
import LayoutManager from '/static/shared/js/core/layout-manager.js';
|
| 111 |
+
|
| 112 |
+
// Initialize layouts (injects header, sidebar, footer)
|
| 113 |
+
await LayoutManager.init('dashboard'); // 'dashboard' = active page name
|
| 114 |
+
|
| 115 |
+
// Set active page in navigation
|
| 116 |
+
LayoutManager.setActivePage('market');
|
| 117 |
+
|
| 118 |
+
// Update API status badge
|
| 119 |
+
LayoutManager.updateApiStatus('online', '✓ System Active');
|
| 120 |
+
```
|
| 121 |
+
|
| 122 |
+
**Features:**
|
| 123 |
+
|
| 124 |
+
- Automatic layout injection
|
| 125 |
+
- API health monitoring
|
| 126 |
+
- Theme management (dark/light)
|
| 127 |
+
- Mobile-responsive sidebar
|
| 128 |
+
- Fallback layouts if files fail to load
|
| 129 |
+
|
| 130 |
+
### API Client
|
| 131 |
+
|
| 132 |
+
**Purpose:** Centralized HTTP client with caching and error handling.
|
| 133 |
+
|
| 134 |
+
**Usage:**
|
| 135 |
+
|
| 136 |
+
```javascript
|
| 137 |
+
import { ApiClient } from '/static/shared/js/core/api-client.js';
|
| 138 |
+
|
| 139 |
+
const client = new ApiClient();
|
| 140 |
+
|
| 141 |
+
// GET request with caching
|
| 142 |
+
const data = await client.get('/api/market/top', {
|
| 143 |
+
cache: true,
|
| 144 |
+
ttl: 30000 // 30 seconds
|
| 145 |
+
});
|
| 146 |
+
|
| 147 |
+
// POST request
|
| 148 |
+
const result = await client.post('/api/sentiment/analyze', {
|
| 149 |
+
text: 'Bitcoin is bullish!'
|
| 150 |
+
});
|
| 151 |
+
```
|
| 152 |
+
|
| 153 |
+
### Polling Manager
|
| 154 |
+
|
| 155 |
+
**Purpose:** Auto-refresh data with smart pause/resume.
|
| 156 |
+
|
| 157 |
+
**Usage:**
|
| 158 |
+
|
| 159 |
+
```javascript
|
| 160 |
+
import { PollingManager } from '/static/shared/js/core/polling-manager.js';
|
| 161 |
+
|
| 162 |
+
const poller = new PollingManager({
|
| 163 |
+
interval: 5000, // 5 seconds
|
| 164 |
+
pauseOnHidden: true // Pause when tab is hidden
|
| 165 |
+
});
|
| 166 |
+
|
| 167 |
+
// Start polling
|
| 168 |
+
poller.start(async () => {
|
| 169 |
+
const data = await fetch('/api/market/top').then(r => r.json());
|
| 170 |
+
updateUI(data);
|
| 171 |
+
});
|
| 172 |
+
|
| 173 |
+
// Stop polling
|
| 174 |
+
poller.stop();
|
| 175 |
+
```
|
| 176 |
+
|
| 177 |
+
### Component System
|
| 178 |
+
|
| 179 |
+
**Toast Notifications:**
|
| 180 |
+
|
| 181 |
+
```javascript
|
| 182 |
+
import { Toast } from '/static/shared/js/components/toast.js';
|
| 183 |
+
|
| 184 |
+
Toast.success('Data loaded successfully');
|
| 185 |
+
Toast.error('Failed to fetch data');
|
| 186 |
+
Toast.info('Processing...');
|
| 187 |
+
```
|
| 188 |
+
|
| 189 |
+
**Modal Dialogs:**
|
| 190 |
+
|
| 191 |
+
```javascript
|
| 192 |
+
import { Modal } from '/static/shared/js/components/modal.js';
|
| 193 |
+
|
| 194 |
+
const modal = new Modal({
|
| 195 |
+
title: 'Confirm Action',
|
| 196 |
+
content: '<p>Are you sure?</p>',
|
| 197 |
+
buttons: [
|
| 198 |
+
{ text: 'Cancel', action: () => modal.close() },
|
| 199 |
+
{ text: 'Confirm', action: () => { /* ... */ } }
|
| 200 |
+
]
|
| 201 |
+
});
|
| 202 |
+
modal.show();
|
| 203 |
+
```
|
| 204 |
+
|
| 205 |
+
## Page Development Workflow
|
| 206 |
+
|
| 207 |
+
### Step 1: Create Page Directory
|
| 208 |
+
|
| 209 |
+
```
|
| 210 |
+
static/pages/my-page/
|
| 211 |
+
├── index.html
|
| 212 |
+
├── my-page.css
|
| 213 |
+
└── my-page.js (optional)
|
| 214 |
+
```
|
| 215 |
+
|
| 216 |
+
### Step 2: Create HTML Structure
|
| 217 |
+
|
| 218 |
+
```html
|
| 219 |
+
<!DOCTYPE html>
|
| 220 |
+
<html lang="en" data-theme="dark">
|
| 221 |
+
<head>
|
| 222 |
+
<meta charset="UTF-8">
|
| 223 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 224 |
+
<title>My Page | Crypto Hub</title>
|
| 225 |
+
|
| 226 |
+
<!-- Shared CSS -->
|
| 227 |
+
<link rel="stylesheet" href="/static/shared/css/design-system.css">
|
| 228 |
+
<link rel="stylesheet" href="/static/shared/css/layout.css">
|
| 229 |
+
<link rel="stylesheet" href="/static/shared/css/components.css">
|
| 230 |
+
|
| 231 |
+
<!-- Page CSS -->
|
| 232 |
+
<link rel="stylesheet" href="/static/pages/my-page/my-page.css">
|
| 233 |
+
</head>
|
| 234 |
+
<body>
|
| 235 |
+
<div class="app-container">
|
| 236 |
+
<aside id="sidebar-container"></aside>
|
| 237 |
+
<header id="header-container"></header>
|
| 238 |
+
|
| 239 |
+
<main class="main-content">
|
| 240 |
+
<div class="page-content">
|
| 241 |
+
<h1>My Page</h1>
|
| 242 |
+
<!-- Your content -->
|
| 243 |
+
</div>
|
| 244 |
+
</main>
|
| 245 |
+
</div>
|
| 246 |
+
|
| 247 |
+
<script type="module">
|
| 248 |
+
import LayoutManager from '/static/shared/js/core/layout-manager.js';
|
| 249 |
+
import { ApiClient } from '/static/shared/js/core/api-client.js';
|
| 250 |
+
|
| 251 |
+
// Initialize layout
|
| 252 |
+
await LayoutManager.init('my-page');
|
| 253 |
+
|
| 254 |
+
// Your page logic
|
| 255 |
+
const client = new ApiClient();
|
| 256 |
+
const data = await client.get('/api/endpoint');
|
| 257 |
+
// ... update UI
|
| 258 |
+
</script>
|
| 259 |
+
</body>
|
| 260 |
+
</html>
|
| 261 |
+
```
|
| 262 |
+
|
| 263 |
+
### Step 3: Add to Navigation
|
| 264 |
+
|
| 265 |
+
Update `/static/shared/layouts/sidebar.html`:
|
| 266 |
+
|
| 267 |
+
```html
|
| 268 |
+
<li>
|
| 269 |
+
<a href="/static/pages/my-page/index.html"
|
| 270 |
+
class="nav-link"
|
| 271 |
+
data-page="my-page">
|
| 272 |
+
My Page
|
| 273 |
+
</a>
|
| 274 |
+
</li>
|
| 275 |
+
```
|
| 276 |
+
|
| 277 |
+
### Step 4: Register in Config
|
| 278 |
+
|
| 279 |
+
Update `/static/shared/js/core/config.js`:
|
| 280 |
+
|
| 281 |
+
```javascript
|
| 282 |
+
export const PAGE_METADATA = [
|
| 283 |
+
// ... existing pages
|
| 284 |
+
{ page: 'my-page', title: 'My Page | Crypto Hub', icon: 'star' }
|
| 285 |
+
];
|
| 286 |
+
```
|
| 287 |
+
|
| 288 |
+
## Best Practices
|
| 289 |
+
|
| 290 |
+
1. **Always use LayoutManager.init()** - Ensures layouts are injected
|
| 291 |
+
2. **Use shared components** - Don't reinvent toast, modal, etc.
|
| 292 |
+
3. **Follow naming conventions** - Page name matches directory name
|
| 293 |
+
4. **Use API client** - Don't use raw fetch() for API calls
|
| 294 |
+
5. **Handle loading states** - Use Loading component
|
| 295 |
+
6. **Responsive design** - Test on mobile (sidebar auto-hides)
|
| 296 |
+
7. **Error handling** - Use Toast for user feedback
|
| 297 |
+
8. **Cache API calls** - Use ApiClient caching for performance
|
| 298 |
+
|
| 299 |
+
## File Paths
|
| 300 |
+
|
| 301 |
+
**Absolute paths (recommended):**
|
| 302 |
+
|
| 303 |
+
- `/static/shared/js/core/layout-manager.js`
|
| 304 |
+
- `/static/pages/dashboard/index.html`
|
| 305 |
+
|
| 306 |
+
**Relative paths (from page directory):**
|
| 307 |
+
|
| 308 |
+
- `../../shared/js/core/layout-manager.js`
|
| 309 |
+
- `../dashboard/index.html`
|
| 310 |
+
|
| 311 |
+
## Theme System
|
| 312 |
+
|
| 313 |
+
The app supports dark/light themes:
|
| 314 |
+
|
| 315 |
+
```javascript
|
| 316 |
+
// Toggle theme
|
| 317 |
+
LayoutManager.toggleTheme();
|
| 318 |
+
|
| 319 |
+
// Get current theme
|
| 320 |
+
const theme = document.documentElement.getAttribute('data-theme');
|
| 321 |
+
```
|
| 322 |
+
|
| 323 |
+
Theme is persisted in `localStorage` as `crypto_monitor_theme`.
|
| 324 |
+
|
| 325 |
+
## API Status Monitoring
|
| 326 |
+
|
| 327 |
+
LayoutManager automatically monitors API health:
|
| 328 |
+
|
| 329 |
+
- Checks `/api/health` every 30 seconds
|
| 330 |
+
- Updates status badge in header
|
| 331 |
+
- Pauses when tab is hidden
|
| 332 |
+
- Enters offline mode after 3 failures
|
| 333 |
+
|
| 334 |
+
## Mobile Support
|
| 335 |
+
|
| 336 |
+
- Sidebar auto-hides on screens < 1024px
|
| 337 |
+
- Hamburger menu in header toggles sidebar
|
| 338 |
+
- Touch-friendly components
|
| 339 |
+
- Responsive grid layouts
|
UI_USAGE_SCRIPT.md
ADDED
|
@@ -0,0 +1,715 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# UI Structure Usage Script / Guide
|
| 2 |
+
|
| 3 |
+
## How to Use the Application's UI Structure
|
| 4 |
+
|
| 5 |
+
This document provides step-by-step instructions on how to work with the multi-page architecture, shared components, and layout system.
|
| 6 |
+
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
## Part 1: Understanding the Structure
|
| 10 |
+
|
| 11 |
+
### Architecture Overview
|
| 12 |
+
|
| 13 |
+
The application follows a **modular multi-page architecture**:
|
| 14 |
+
|
| 15 |
+
1. **Pages** (`/static/pages/`) - Standalone page modules
|
| 16 |
+
2. **Shared Components** (`/static/shared/`) - Reusable layouts, utilities, components
|
| 17 |
+
3. **Layout Manager** - Dynamically injects header, sidebar, footer
|
| 18 |
+
4. **API Client** - Centralized HTTP client with caching
|
| 19 |
+
5. **Component System** - Toast, Modal, Table, Chart, Loading
|
| 20 |
+
|
| 21 |
+
### Key Principles
|
| 22 |
+
|
| 23 |
+
- Each page is self-contained but shares common layouts
|
| 24 |
+
- Layouts are injected dynamically (not hardcoded in each page)
|
| 25 |
+
- All API calls go through the centralized API client
|
| 26 |
+
- Components are reusable across pages
|
| 27 |
+
- Theme system (dark/light) is managed globally
|
| 28 |
+
|
| 29 |
+
---
|
| 30 |
+
|
| 31 |
+
## Part 2: Creating a New Page
|
| 32 |
+
|
| 33 |
+
### Step-by-Step Process
|
| 34 |
+
|
| 35 |
+
#### Step 1: Create Directory Structure
|
| 36 |
+
|
| 37 |
+
```
|
| 38 |
+
Location: /static/pages/your-page-name/
|
| 39 |
+
Files needed:
|
| 40 |
+
- index.html (required)
|
| 41 |
+
- your-page-name.css (optional, for page-specific styles)
|
| 42 |
+
- your-page-name.js (optional, for page-specific logic)
|
| 43 |
+
```
|
| 44 |
+
|
| 45 |
+
#### Step 2: Create the HTML Template
|
| 46 |
+
|
| 47 |
+
**Template Structure:**
|
| 48 |
+
|
| 49 |
+
```html
|
| 50 |
+
<!DOCTYPE html>
|
| 51 |
+
<html lang="en" data-theme="dark">
|
| 52 |
+
<head>
|
| 53 |
+
<!-- Meta tags -->
|
| 54 |
+
<meta charset="UTF-8">
|
| 55 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 56 |
+
<title>Your Page Title | Crypto Hub</title>
|
| 57 |
+
|
| 58 |
+
<!-- Shared CSS (always include these) -->
|
| 59 |
+
<link rel="stylesheet" href="/static/shared/css/design-system.css">
|
| 60 |
+
<link rel="stylesheet" href="/static/shared/css/layout.css">
|
| 61 |
+
<link rel="stylesheet" href="/static/shared/css/components.css">
|
| 62 |
+
<link rel="stylesheet" href="/static/shared/css/utilities.css">
|
| 63 |
+
|
| 64 |
+
<!-- Page-specific CSS -->
|
| 65 |
+
<link rel="stylesheet" href="/static/pages/your-page-name/your-page-name.css">
|
| 66 |
+
|
| 67 |
+
<!-- Error suppressor (suppresses browser warnings) -->
|
| 68 |
+
<script src="/static/shared/js/utils/error-suppressor.js"></script>
|
| 69 |
+
</head>
|
| 70 |
+
<body>
|
| 71 |
+
<!-- App Container (required structure) -->
|
| 72 |
+
<div class="app-container">
|
| 73 |
+
|
| 74 |
+
<!-- Sidebar Container (LayoutManager will inject sidebar here) -->
|
| 75 |
+
<aside id="sidebar-container"></aside>
|
| 76 |
+
|
| 77 |
+
<!-- Main Content Area -->
|
| 78 |
+
<main class="main-content">
|
| 79 |
+
|
| 80 |
+
<!-- Header Container (LayoutManager will inject header here) -->
|
| 81 |
+
<header id="header-container"></header>
|
| 82 |
+
|
| 83 |
+
<!-- Your Page Content -->
|
| 84 |
+
<div class="page-content">
|
| 85 |
+
<!-- Your page-specific content goes here -->
|
| 86 |
+
<h1>Your Page Title</h1>
|
| 87 |
+
<div id="your-content-container">
|
| 88 |
+
<!-- Content -->
|
| 89 |
+
</div>
|
| 90 |
+
</div>
|
| 91 |
+
|
| 92 |
+
</main>
|
| 93 |
+
</div>
|
| 94 |
+
|
| 95 |
+
<!-- Scripts (at end of body) -->
|
| 96 |
+
<script type="module">
|
| 97 |
+
// Import LayoutManager (required)
|
| 98 |
+
import LayoutManager from '/static/shared/js/core/layout-manager.js';
|
| 99 |
+
|
| 100 |
+
// Import API Client (if you need API calls)
|
| 101 |
+
import { ApiClient } from '/static/shared/js/core/api-client.js';
|
| 102 |
+
|
| 103 |
+
// Import components you need
|
| 104 |
+
import { Toast } from '/static/shared/js/components/toast.js';
|
| 105 |
+
import { Loading } from '/static/shared/js/components/loading.js';
|
| 106 |
+
|
| 107 |
+
// Initialize Layout Manager (this injects header, sidebar, footer)
|
| 108 |
+
await LayoutManager.init('your-page-name');
|
| 109 |
+
|
| 110 |
+
// Your page initialization code
|
| 111 |
+
async function initPage() {
|
| 112 |
+
// Show loading state
|
| 113 |
+
Loading.show();
|
| 114 |
+
|
| 115 |
+
try {
|
| 116 |
+
// Fetch data using API client
|
| 117 |
+
const client = new ApiClient();
|
| 118 |
+
const data = await client.get('/api/your-endpoint');
|
| 119 |
+
|
| 120 |
+
// Update UI with data
|
| 121 |
+
updateUI(data);
|
| 122 |
+
|
| 123 |
+
// Show success message
|
| 124 |
+
Toast.success('Data loaded successfully');
|
| 125 |
+
} catch (error) {
|
| 126 |
+
// Show error message
|
| 127 |
+
Toast.error('Failed to load data: ' + error.message);
|
| 128 |
+
} finally {
|
| 129 |
+
// Hide loading state
|
| 130 |
+
Loading.hide();
|
| 131 |
+
}
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
// Call initialization
|
| 135 |
+
initPage();
|
| 136 |
+
</script>
|
| 137 |
+
</body>
|
| 138 |
+
</html>
|
| 139 |
+
```
|
| 140 |
+
|
| 141 |
+
#### Step 3: Register the Page
|
| 142 |
+
|
| 143 |
+
**A. Add to Sidebar Navigation**
|
| 144 |
+
|
| 145 |
+
Edit: `/static/shared/layouts/sidebar.html`
|
| 146 |
+
|
| 147 |
+
Add navigation link:
|
| 148 |
+
|
| 149 |
+
```html
|
| 150 |
+
<li>
|
| 151 |
+
<a href="/static/pages/your-page-name/index.html"
|
| 152 |
+
class="nav-link"
|
| 153 |
+
data-page="your-page-name">
|
| 154 |
+
<span class="icon">📊</span>
|
| 155 |
+
<span>Your Page Name</span>
|
| 156 |
+
</a>
|
| 157 |
+
</li>
|
| 158 |
+
```
|
| 159 |
+
|
| 160 |
+
**B. Register in Config**
|
| 161 |
+
|
| 162 |
+
Edit: `/static/shared/js/core/config.js`
|
| 163 |
+
|
| 164 |
+
Add to `PAGE_METADATA` array:
|
| 165 |
+
|
| 166 |
+
```javascript
|
| 167 |
+
export const PAGE_METADATA = [
|
| 168 |
+
// ... existing pages
|
| 169 |
+
{
|
| 170 |
+
page: 'your-page-name',
|
| 171 |
+
title: 'Your Page Title | Crypto Hub',
|
| 172 |
+
icon: 'star'
|
| 173 |
+
}
|
| 174 |
+
];
|
| 175 |
+
```
|
| 176 |
+
|
| 177 |
+
---
|
| 178 |
+
|
| 179 |
+
## Part 3: Using Shared Components
|
| 180 |
+
|
| 181 |
+
### Layout Manager
|
| 182 |
+
|
| 183 |
+
**Purpose:** Manages shared layouts (header, sidebar, footer)
|
| 184 |
+
|
| 185 |
+
**Basic Usage:**
|
| 186 |
+
|
| 187 |
+
```javascript
|
| 188 |
+
import LayoutManager from '/static/shared/js/core/layout-manager.js';
|
| 189 |
+
|
| 190 |
+
// Initialize (injects layouts, sets active page)
|
| 191 |
+
await LayoutManager.init('page-name');
|
| 192 |
+
|
| 193 |
+
// Set active page in navigation
|
| 194 |
+
LayoutManager.setActivePage('dashboard');
|
| 195 |
+
|
| 196 |
+
// Update API status badge
|
| 197 |
+
LayoutManager.updateApiStatus('online', '✓ System Active');
|
| 198 |
+
LayoutManager.updateApiStatus('offline', '✗ Offline');
|
| 199 |
+
LayoutManager.updateApiStatus('degraded', '⚠ Degraded');
|
| 200 |
+
|
| 201 |
+
// Toggle theme
|
| 202 |
+
LayoutManager.toggleTheme();
|
| 203 |
+
|
| 204 |
+
// Get current theme
|
| 205 |
+
const theme = document.documentElement.getAttribute('data-theme');
|
| 206 |
+
```
|
| 207 |
+
|
| 208 |
+
### API Client
|
| 209 |
+
|
| 210 |
+
**Purpose:** Centralized HTTP client with caching and error handling
|
| 211 |
+
|
| 212 |
+
**Basic Usage:**
|
| 213 |
+
|
| 214 |
+
```javascript
|
| 215 |
+
import { ApiClient } from '/static/shared/js/core/api-client.js';
|
| 216 |
+
|
| 217 |
+
const client = new ApiClient();
|
| 218 |
+
|
| 219 |
+
// GET request with caching
|
| 220 |
+
const data = await client.get('/api/market/top', {
|
| 221 |
+
cache: true,
|
| 222 |
+
ttl: 30000 // Cache for 30 seconds
|
| 223 |
+
});
|
| 224 |
+
|
| 225 |
+
// POST request
|
| 226 |
+
const result = await client.post('/api/sentiment/analyze', {
|
| 227 |
+
text: 'Bitcoin is bullish!'
|
| 228 |
+
});
|
| 229 |
+
|
| 230 |
+
// PUT request
|
| 231 |
+
await client.put('/api/settings', { theme: 'dark' });
|
| 232 |
+
|
| 233 |
+
// DELETE request
|
| 234 |
+
await client.delete('/api/resource/123');
|
| 235 |
+
|
| 236 |
+
// With error handling
|
| 237 |
+
try {
|
| 238 |
+
const data = await client.get('/api/endpoint');
|
| 239 |
+
} catch (error) {
|
| 240 |
+
console.error('API Error:', error);
|
| 241 |
+
Toast.error('Failed to fetch data');
|
| 242 |
+
}
|
| 243 |
+
```
|
| 244 |
+
|
| 245 |
+
### Polling Manager
|
| 246 |
+
|
| 247 |
+
**Purpose:** Auto-refresh data with smart pause/resume
|
| 248 |
+
|
| 249 |
+
**Usage:**
|
| 250 |
+
|
| 251 |
+
```javascript
|
| 252 |
+
import { PollingManager } from '/static/shared/js/core/polling-manager.js';
|
| 253 |
+
|
| 254 |
+
// Create poller
|
| 255 |
+
const poller = new PollingManager({
|
| 256 |
+
interval: 5000, // Poll every 5 seconds
|
| 257 |
+
pauseOnHidden: true, // Pause when tab is hidden
|
| 258 |
+
maxRetries: 3 // Max retries on failure
|
| 259 |
+
});
|
| 260 |
+
|
| 261 |
+
// Start polling
|
| 262 |
+
poller.start(async () => {
|
| 263 |
+
const client = new ApiClient();
|
| 264 |
+
const data = await client.get('/api/market/top');
|
| 265 |
+
updateMarketData(data);
|
| 266 |
+
});
|
| 267 |
+
|
| 268 |
+
// Stop polling
|
| 269 |
+
poller.stop();
|
| 270 |
+
|
| 271 |
+
// Pause temporarily
|
| 272 |
+
poller.pause();
|
| 273 |
+
|
| 274 |
+
// Resume
|
| 275 |
+
poller.resume();
|
| 276 |
+
```
|
| 277 |
+
|
| 278 |
+
### Toast Notifications
|
| 279 |
+
|
| 280 |
+
**Purpose:** User feedback messages
|
| 281 |
+
|
| 282 |
+
**Usage:**
|
| 283 |
+
|
| 284 |
+
```javascript
|
| 285 |
+
import { Toast } from '/static/shared/js/components/toast.js';
|
| 286 |
+
|
| 287 |
+
// Success message
|
| 288 |
+
Toast.success('Operation completed successfully');
|
| 289 |
+
|
| 290 |
+
// Error message
|
| 291 |
+
Toast.error('Failed to save changes');
|
| 292 |
+
|
| 293 |
+
// Info message
|
| 294 |
+
Toast.info('Processing your request...');
|
| 295 |
+
|
| 296 |
+
// Warning message
|
| 297 |
+
Toast.warning('Please check your input');
|
| 298 |
+
|
| 299 |
+
// Custom message
|
| 300 |
+
Toast.show('Custom message', 'info', 5000); // message, type, duration
|
| 301 |
+
```
|
| 302 |
+
|
| 303 |
+
### Modal Dialogs
|
| 304 |
+
|
| 305 |
+
**Purpose:** Popup dialogs for confirmations, forms, etc.
|
| 306 |
+
|
| 307 |
+
**Usage:**
|
| 308 |
+
|
| 309 |
+
```javascript
|
| 310 |
+
import { Modal } from '/static/shared/js/components/modal.js';
|
| 311 |
+
|
| 312 |
+
// Simple modal
|
| 313 |
+
const modal = new Modal({
|
| 314 |
+
title: 'Confirm Action',
|
| 315 |
+
content: '<p>Are you sure you want to proceed?</p>',
|
| 316 |
+
buttons: [
|
| 317 |
+
{
|
| 318 |
+
text: 'Cancel',
|
| 319 |
+
class: 'btn-secondary',
|
| 320 |
+
action: () => modal.close()
|
| 321 |
+
},
|
| 322 |
+
{
|
| 323 |
+
text: 'Confirm',
|
| 324 |
+
class: 'btn-primary',
|
| 325 |
+
action: () => {
|
| 326 |
+
// Perform action
|
| 327 |
+
performAction();
|
| 328 |
+
modal.close();
|
| 329 |
+
}
|
| 330 |
+
}
|
| 331 |
+
]
|
| 332 |
+
});
|
| 333 |
+
modal.show();
|
| 334 |
+
|
| 335 |
+
// Modal with form
|
| 336 |
+
const formModal = new Modal({
|
| 337 |
+
title: 'Add Item',
|
| 338 |
+
content: `
|
| 339 |
+
<form id="add-form">
|
| 340 |
+
<input type="text" name="name" placeholder="Name" required>
|
| 341 |
+
<button type="submit">Add</button>
|
| 342 |
+
</form>
|
| 343 |
+
`,
|
| 344 |
+
onClose: () => console.log('Modal closed')
|
| 345 |
+
});
|
| 346 |
+
formModal.show();
|
| 347 |
+
```
|
| 348 |
+
|
| 349 |
+
### Loading Component
|
| 350 |
+
|
| 351 |
+
**Purpose:** Show/hide loading states
|
| 352 |
+
|
| 353 |
+
**Usage:**
|
| 354 |
+
|
| 355 |
+
```javascript
|
| 356 |
+
import { Loading } from '/static/shared/js/components/loading.js';
|
| 357 |
+
|
| 358 |
+
// Show loading overlay
|
| 359 |
+
Loading.show('Loading data...');
|
| 360 |
+
|
| 361 |
+
// Hide loading
|
| 362 |
+
Loading.hide();
|
| 363 |
+
|
| 364 |
+
// Show loading in specific container
|
| 365 |
+
Loading.showIn('#my-container', 'Loading...');
|
| 366 |
+
|
| 367 |
+
// Hide loading in container
|
| 368 |
+
Loading.hideIn('#my-container');
|
| 369 |
+
```
|
| 370 |
+
|
| 371 |
+
### Table Component
|
| 372 |
+
|
| 373 |
+
**Purpose:** Data tables with sorting and filtering
|
| 374 |
+
|
| 375 |
+
**Usage:**
|
| 376 |
+
|
| 377 |
+
```javascript
|
| 378 |
+
import { DataTable } from '/static/shared/js/components/table.js';
|
| 379 |
+
|
| 380 |
+
const table = new DataTable('#table-container', {
|
| 381 |
+
columns: [
|
| 382 |
+
{ key: 'name', label: 'Name', sortable: true },
|
| 383 |
+
{ key: 'price', label: 'Price', sortable: true, formatter: (val) => `$${val}` },
|
| 384 |
+
{ key: 'change', label: 'Change', sortable: true }
|
| 385 |
+
],
|
| 386 |
+
data: marketData,
|
| 387 |
+
searchable: true,
|
| 388 |
+
pagination: true,
|
| 389 |
+
pageSize: 10
|
| 390 |
+
});
|
| 391 |
+
|
| 392 |
+
// Update data
|
| 393 |
+
table.updateData(newData);
|
| 394 |
+
|
| 395 |
+
// Refresh
|
| 396 |
+
table.refresh();
|
| 397 |
+
```
|
| 398 |
+
|
| 399 |
+
### Chart Component
|
| 400 |
+
|
| 401 |
+
**Purpose:** Chart.js wrapper for data visualization
|
| 402 |
+
|
| 403 |
+
**Usage:**
|
| 404 |
+
|
| 405 |
+
```javascript
|
| 406 |
+
import { Chart } from '/static/shared/js/components/chart.js';
|
| 407 |
+
|
| 408 |
+
const chart = new Chart('#chart-container', {
|
| 409 |
+
type: 'line',
|
| 410 |
+
data: {
|
| 411 |
+
labels: dates,
|
| 412 |
+
datasets: [{
|
| 413 |
+
label: 'Price',
|
| 414 |
+
data: prices,
|
| 415 |
+
borderColor: '#8B5CF6'
|
| 416 |
+
}]
|
| 417 |
+
},
|
| 418 |
+
options: {
|
| 419 |
+
responsive: true,
|
| 420 |
+
maintainAspectRatio: false
|
| 421 |
+
}
|
| 422 |
+
});
|
| 423 |
+
|
| 424 |
+
// Update chart data
|
| 425 |
+
chart.updateData(newData);
|
| 426 |
+
```
|
| 427 |
+
|
| 428 |
+
---
|
| 429 |
+
|
| 430 |
+
## Part 4: Common Patterns
|
| 431 |
+
|
| 432 |
+
### Pattern 1: Page with Data Fetching
|
| 433 |
+
|
| 434 |
+
```javascript
|
| 435 |
+
import LayoutManager from '/static/shared/js/core/layout-manager.js';
|
| 436 |
+
import { ApiClient } from '/static/shared/js/core/api-client.js';
|
| 437 |
+
import { Toast } from '/static/shared/js/components/toast.js';
|
| 438 |
+
import { Loading } from '/static/shared/js/components/loading.js';
|
| 439 |
+
|
| 440 |
+
// Initialize
|
| 441 |
+
await LayoutManager.init('my-page');
|
| 442 |
+
|
| 443 |
+
// Fetch and display data
|
| 444 |
+
async function loadData() {
|
| 445 |
+
Loading.show('Loading data...');
|
| 446 |
+
|
| 447 |
+
try {
|
| 448 |
+
const client = new ApiClient();
|
| 449 |
+
const data = await client.get('/api/endpoint');
|
| 450 |
+
|
| 451 |
+
renderData(data);
|
| 452 |
+
Toast.success('Data loaded');
|
| 453 |
+
} catch (error) {
|
| 454 |
+
Toast.error('Failed to load: ' + error.message);
|
| 455 |
+
} finally {
|
| 456 |
+
Loading.hide();
|
| 457 |
+
}
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
function renderData(data) {
|
| 461 |
+
const container = document.getElementById('data-container');
|
| 462 |
+
container.innerHTML = data.map(item => `
|
| 463 |
+
<div class="data-item">
|
| 464 |
+
<h3>${item.name}</h3>
|
| 465 |
+
<p>${item.description}</p>
|
| 466 |
+
</div>
|
| 467 |
+
`).join('');
|
| 468 |
+
}
|
| 469 |
+
|
| 470 |
+
// Load on page load
|
| 471 |
+
loadData();
|
| 472 |
+
```
|
| 473 |
+
|
| 474 |
+
### Pattern 2: Page with Auto-Refresh
|
| 475 |
+
|
| 476 |
+
```javascript
|
| 477 |
+
import LayoutManager from '/static/shared/js/core/layout-manager.js';
|
| 478 |
+
import { ApiClient } from '/static/shared/js/core/api-client.js';
|
| 479 |
+
import { PollingManager } from '/static/shared/js/core/polling-manager.js';
|
| 480 |
+
|
| 481 |
+
await LayoutManager.init('my-page');
|
| 482 |
+
|
| 483 |
+
const client = new ApiClient();
|
| 484 |
+
const poller = new PollingManager({ interval: 10000 });
|
| 485 |
+
|
| 486 |
+
async function refreshData() {
|
| 487 |
+
try {
|
| 488 |
+
const data = await client.get('/api/endpoint', { cache: false });
|
| 489 |
+
updateUI(data);
|
| 490 |
+
} catch (error) {
|
| 491 |
+
console.error('Refresh failed:', error);
|
| 492 |
+
}
|
| 493 |
+
}
|
| 494 |
+
|
| 495 |
+
// Start auto-refresh
|
| 496 |
+
poller.start(refreshData);
|
| 497 |
+
|
| 498 |
+
// Initial load
|
| 499 |
+
refreshData();
|
| 500 |
+
|
| 501 |
+
// Cleanup on page unload
|
| 502 |
+
window.addEventListener('beforeunload', () => {
|
| 503 |
+
poller.stop();
|
| 504 |
+
});
|
| 505 |
+
```
|
| 506 |
+
|
| 507 |
+
### Pattern 3: Form Submission
|
| 508 |
+
|
| 509 |
+
```javascript
|
| 510 |
+
import { ApiClient } from '/static/shared/js/core/api-client.js';
|
| 511 |
+
import { Toast } from '/static/shared/js/components/toast.js';
|
| 512 |
+
import { Loading } from '/static/shared/js/components/loading.js';
|
| 513 |
+
|
| 514 |
+
document.getElementById('my-form').addEventListener('submit', async (e) => {
|
| 515 |
+
e.preventDefault();
|
| 516 |
+
|
| 517 |
+
const formData = new FormData(e.target);
|
| 518 |
+
const data = Object.fromEntries(formData);
|
| 519 |
+
|
| 520 |
+
Loading.show('Submitting...');
|
| 521 |
+
|
| 522 |
+
try {
|
| 523 |
+
const client = new ApiClient();
|
| 524 |
+
const result = await client.post('/api/submit', data);
|
| 525 |
+
|
| 526 |
+
Toast.success('Submitted successfully!');
|
| 527 |
+
e.target.reset();
|
| 528 |
+
} catch (error) {
|
| 529 |
+
Toast.error('Submission failed: ' + error.message);
|
| 530 |
+
} finally {
|
| 531 |
+
Loading.hide();
|
| 532 |
+
}
|
| 533 |
+
});
|
| 534 |
+
```
|
| 535 |
+
|
| 536 |
+
### Pattern 4: Interactive Table with Actions
|
| 537 |
+
|
| 538 |
+
```javascript
|
| 539 |
+
import { DataTable } from '/static/shared/js/components/table.js';
|
| 540 |
+
import { Modal } from '/static/shared/js/components/modal.js';
|
| 541 |
+
import { ApiClient } from '/static/shared/js/core/api-client.js';
|
| 542 |
+
|
| 543 |
+
const table = new DataTable('#table-container', {
|
| 544 |
+
columns: [
|
| 545 |
+
{ key: 'name', label: 'Name' },
|
| 546 |
+
{ key: 'status', label: 'Status' },
|
| 547 |
+
{
|
| 548 |
+
key: 'actions',
|
| 549 |
+
label: 'Actions',
|
| 550 |
+
render: (row) => `
|
| 551 |
+
<button onclick="editItem(${row.id})">Edit</button>
|
| 552 |
+
<button onclick="deleteItem(${row.id})">Delete</button>
|
| 553 |
+
`
|
| 554 |
+
}
|
| 555 |
+
],
|
| 556 |
+
data: items
|
| 557 |
+
});
|
| 558 |
+
|
| 559 |
+
async function deleteItem(id) {
|
| 560 |
+
const modal = new Modal({
|
| 561 |
+
title: 'Confirm Delete',
|
| 562 |
+
content: '<p>Are you sure?</p>',
|
| 563 |
+
buttons: [
|
| 564 |
+
{ text: 'Cancel', action: () => modal.close() },
|
| 565 |
+
{
|
| 566 |
+
text: 'Delete',
|
| 567 |
+
action: async () => {
|
| 568 |
+
const client = new ApiClient();
|
| 569 |
+
await client.delete(`/api/items/${id}`);
|
| 570 |
+
table.refresh();
|
| 571 |
+
modal.close();
|
| 572 |
+
}
|
| 573 |
+
}
|
| 574 |
+
]
|
| 575 |
+
});
|
| 576 |
+
modal.show();
|
| 577 |
+
}
|
| 578 |
+
```
|
| 579 |
+
|
| 580 |
+
---
|
| 581 |
+
|
| 582 |
+
## Part 5: File Paths Reference
|
| 583 |
+
|
| 584 |
+
### Absolute Paths (Recommended)
|
| 585 |
+
|
| 586 |
+
```
|
| 587 |
+
/static/shared/js/core/layout-manager.js
|
| 588 |
+
/static/shared/css/design-system.css
|
| 589 |
+
/static/pages/dashboard/index.html
|
| 590 |
+
```
|
| 591 |
+
|
| 592 |
+
### Relative Paths (From Page Directory)
|
| 593 |
+
|
| 594 |
+
```
|
| 595 |
+
../../shared/js/core/layout-manager.js
|
| 596 |
+
../../shared/css/design-system.css
|
| 597 |
+
../dashboard/index.html
|
| 598 |
+
```
|
| 599 |
+
|
| 600 |
+
### Import Statements
|
| 601 |
+
|
| 602 |
+
```javascript
|
| 603 |
+
// ES6 Modules (recommended)
|
| 604 |
+
import LayoutManager from '/static/shared/js/core/layout-manager.js';
|
| 605 |
+
import { ApiClient } from '/static/shared/js/core/api-client.js';
|
| 606 |
+
|
| 607 |
+
// Dynamic imports
|
| 608 |
+
const { Toast } = await import('/static/shared/js/components/toast.js');
|
| 609 |
+
```
|
| 610 |
+
|
| 611 |
+
---
|
| 612 |
+
|
| 613 |
+
## Part 6: Best Practices Checklist
|
| 614 |
+
|
| 615 |
+
### ✅ Do's
|
| 616 |
+
|
| 617 |
+
- Always use `LayoutManager.init()` in every page
|
| 618 |
+
- Use `ApiClient` for all API calls (don't use raw `fetch()`)
|
| 619 |
+
- Show loading states with `Loading` component
|
| 620 |
+
- Provide user feedback with `Toast` notifications
|
| 621 |
+
- Handle errors gracefully with try/catch
|
| 622 |
+
- Use shared CSS classes from design system
|
| 623 |
+
- Follow the page template structure
|
| 624 |
+
- Register new pages in config and sidebar
|
| 625 |
+
- Use absolute paths for imports
|
| 626 |
+
- Clean up polling/intervals on page unload
|
| 627 |
+
|
| 628 |
+
### ❌ Don'ts
|
| 629 |
+
|
| 630 |
+
- Don't hardcode layouts in pages (use LayoutManager)
|
| 631 |
+
- Don't use raw `fetch()` for API calls
|
| 632 |
+
- Don't create duplicate components (use shared ones)
|
| 633 |
+
- Don't forget error handling
|
| 634 |
+
- Don't use inline styles (use CSS classes)
|
| 635 |
+
- Don't forget to register pages in navigation
|
| 636 |
+
- Don't use relative paths that break on different routes
|
| 637 |
+
- Don't forget to stop polling/intervals
|
| 638 |
+
|
| 639 |
+
---
|
| 640 |
+
|
| 641 |
+
## Part 7: Troubleshooting
|
| 642 |
+
|
| 643 |
+
### Layout Not Showing
|
| 644 |
+
|
| 645 |
+
- Check that `LayoutManager.init()` is called
|
| 646 |
+
- Verify containers exist: `#sidebar-container`, `#header-container`
|
| 647 |
+
- Check browser console for errors
|
| 648 |
+
- Verify file paths are correct
|
| 649 |
+
|
| 650 |
+
### API Calls Failing
|
| 651 |
+
|
| 652 |
+
- Check that `ApiClient` is imported correctly
|
| 653 |
+
- Verify endpoint URLs are correct
|
| 654 |
+
- Check network tab for actual requests
|
| 655 |
+
- Verify CORS settings if calling external APIs
|
| 656 |
+
|
| 657 |
+
### Components Not Working
|
| 658 |
+
|
| 659 |
+
- Check that component scripts are imported
|
| 660 |
+
- Verify component initialization code
|
| 661 |
+
- Check browser console for errors
|
| 662 |
+
- Ensure CSS is loaded
|
| 663 |
+
|
| 664 |
+
### Navigation Not Highlighting
|
| 665 |
+
|
| 666 |
+
- Verify page name matches `data-page` attribute
|
| 667 |
+
- Check that `LayoutManager.setActivePage()` is called
|
| 668 |
+
- Verify page is registered in `PAGE_METADATA`
|
| 669 |
+
|
| 670 |
+
---
|
| 671 |
+
|
| 672 |
+
## Part 8: Quick Reference
|
| 673 |
+
|
| 674 |
+
### Required Imports for Every Page
|
| 675 |
+
|
| 676 |
+
```javascript
|
| 677 |
+
import LayoutManager from '/static/shared/js/core/layout-manager.js';
|
| 678 |
+
await LayoutManager.init('page-name');
|
| 679 |
+
```
|
| 680 |
+
|
| 681 |
+
### Common Component Imports
|
| 682 |
+
|
| 683 |
+
```javascript
|
| 684 |
+
import { ApiClient } from '/static/shared/js/core/api-client.js';
|
| 685 |
+
import { Toast } from '/static/shared/js/components/toast.js';
|
| 686 |
+
import { Loading } from '/static/shared/js/components/loading.js';
|
| 687 |
+
import { Modal } from '/static/shared/js/components/modal.js';
|
| 688 |
+
import { PollingManager } from '/static/shared/js/core/polling-manager.js';
|
| 689 |
+
```
|
| 690 |
+
|
| 691 |
+
### Required HTML Structure
|
| 692 |
+
|
| 693 |
+
```html
|
| 694 |
+
<div class="app-container">
|
| 695 |
+
<aside id="sidebar-container"></aside>
|
| 696 |
+
<header id="header-container"></header>
|
| 697 |
+
<main class="main-content">
|
| 698 |
+
<div class="page-content">
|
| 699 |
+
<!-- Your content -->
|
| 700 |
+
</div>
|
| 701 |
+
</main>
|
| 702 |
+
</div>
|
| 703 |
+
```
|
| 704 |
+
|
| 705 |
+
### Required CSS Imports
|
| 706 |
+
|
| 707 |
+
```html
|
| 708 |
+
<link rel="stylesheet" href="/static/shared/css/design-system.css">
|
| 709 |
+
<link rel="stylesheet" href="/static/shared/css/layout.css">
|
| 710 |
+
<link rel="stylesheet" href="/static/shared/css/components.css">
|
| 711 |
+
```
|
| 712 |
+
|
| 713 |
+
---
|
| 714 |
+
|
| 715 |
+
This guide provides the complete framework for working with the UI structure. Follow these patterns and practices to maintain consistency and leverage the shared component system effectively.
|