✨ Features: - Complete light theme with improved color palette - Theme switcher in header with sun/moon icons - Theme persistence using localStorage - Smooth transitions between themes 🎨 Theme Improvements: - Softer, easier-on-eyes light theme colors - Fixed text contrast issues across all components - Enhanced member card and tab text readability - Fixed hover effects that made text disappear - Improved member overlay header and body styling 🔧 Technical Implementation: - CSS variables system for easy theme management - JavaScript ThemeManager class for theme switching - Responsive design for mobile devices - Comprehensive hover state fixes - Z-index solutions for text visibility 📱 Components Fixed: - Member cards (hostname, IP, latency, details) - Navigation tabs and content - Task summaries and progress items - Capability forms and API endpoints - Member overlay popup - Form inputs and dropdowns - Status indicators and label chips 🎯 Accessibility: - WCAG AA contrast compliance - Proper color hierarchy - Clear visual feedback - Mobile-responsive design Files added: - public/styles/theme.css - Theme system and variables - public/scripts/theme-manager.js - Theme management logic - THEME_README.md - Comprehensive documentation - THEME_IMPROVEMENTS.md - Improvement details Files modified: - public/index.html - Added theme switcher and script includes - public/styles/main.css - Updated to use CSS variables
164 lines
8.8 KiB
HTML
164 lines
8.8 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>SPORE UI</title>
|
|
<link rel="stylesheet" href="styles/main.css">
|
|
<link rel="stylesheet" href="styles/theme.css">
|
|
</head>
|
|
|
|
<body>
|
|
<div class="container">
|
|
<div class="main-navigation">
|
|
<button class="burger-btn" id="burger-btn" aria-label="Menu" title="Menu">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M3 6h18M3 12h18M3 18h18" />
|
|
</svg>
|
|
</button>
|
|
<div class="nav-left">
|
|
<button class="nav-tab active" data-view="cluster">🌐 Cluster</button>
|
|
<button class="nav-tab" data-view="topology">🔗 Topology</button>
|
|
<button class="nav-tab" data-view="firmware">📦 Firmware</button>
|
|
</div>
|
|
<div class="nav-right">
|
|
<div class="theme-switcher">
|
|
<span class="theme-label">Theme:</span>
|
|
<button class="theme-toggle" id="theme-toggle" title="Toggle theme">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<circle cx="12" cy="12" r="5"/>
|
|
<path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
<div class="cluster-status">🚀 Cluster Online</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="cluster-view" class="view-content active">
|
|
<div class="cluster-section">
|
|
<div class="cluster-header">
|
|
<div class="cluster-header-left">
|
|
<div class="primary-node-info">
|
|
<span class="primary-node-label">Primary Node:</span>
|
|
<span class="primary-node-ip" id="primary-node-ip">Discovering...</span>
|
|
<button class="primary-node-refresh" id="select-random-primary-btn"
|
|
title="🎲 Select random primary node">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14"
|
|
height="14">
|
|
<path d="M1 4v6h6M23 20v-6h-6" />
|
|
<path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<button class="refresh-btn" id="refresh-cluster-btn">
|
|
<svg class="refresh-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
stroke-width="2">
|
|
<path d="M1 4v6h6M23 20v-6h-6" />
|
|
<path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15" />
|
|
</svg>
|
|
Refresh
|
|
</button>
|
|
</div>
|
|
|
|
<div id="cluster-members-container">
|
|
<div class="loading">
|
|
<div>Loading cluster members...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="topology-view" class="view-content">
|
|
<div id="topology-graph-container">
|
|
<div class="loading">
|
|
<div>Loading network topology...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="firmware-view" class="view-content">
|
|
<div class="firmware-section">
|
|
<div id="firmware-container">
|
|
<div class="firmware-overview">
|
|
<div class="firmware-actions">
|
|
<div class="action-group">
|
|
<h3>🚀 Firmware Update</h3>
|
|
<div class="firmware-upload-compact">
|
|
<div class="compact-upload-row">
|
|
<div class="file-upload-area">
|
|
<div class="target-options">
|
|
<label class="target-option">
|
|
<input type="radio" name="target-type" value="all" checked>
|
|
<span class="radio-custom"></span>
|
|
<span class="target-label">All Nodes</span>
|
|
</label>
|
|
<label class="target-option specific-node-option">
|
|
<input type="radio" name="target-type" value="specific">
|
|
<span class="radio-custom"></span>
|
|
<span class="target-label">Specific Node</span>
|
|
<select id="specific-node-select" class="node-select">
|
|
<option value="">Select a node...</option>
|
|
</select>
|
|
</label>
|
|
<label class="target-option by-label-option">
|
|
<input type="radio" name="target-type" value="labels">
|
|
<span class="radio-custom"></span>
|
|
<span class="target-label">By Label</span>
|
|
<select id="label-select" class="label-select"
|
|
style="min-width: 220px; display: inline-block; vertical-align: middle;">
|
|
<option value="">Select a label...</option>
|
|
</select>
|
|
<div id="selected-labels-container" class="selected-labels"></div>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="file-input-wrapper">
|
|
<input type="file" id="global-firmware-file" accept=".bin,.hex"
|
|
style="display: none;">
|
|
<button class="upload-btn-compact"
|
|
onclick="document.getElementById('global-firmware-file').click()">
|
|
📁 Choose File
|
|
</button>
|
|
<span class="file-info" id="file-info">No file selected</span>
|
|
</div>
|
|
</div>
|
|
|
|
<button class="deploy-btn" id="deploy-btn" disabled>🚀 Deploy</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="firmware-nodes-list" id="firmware-nodes-list">
|
|
<!-- Nodes will be populated here -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="./vendor/d3.v7.min.js"></script>
|
|
<script src="./scripts/constants.js"></script>
|
|
<script src="./scripts/framework.js"></script>
|
|
<script src="./scripts/api-client.js"></script>
|
|
<script src="./scripts/view-models.js"></script>
|
|
<!-- Base/leaf components first -->
|
|
<script src="./scripts/components/PrimaryNodeComponent.js"></script>
|
|
<script src="./scripts/components/NodeDetailsComponent.js"></script>
|
|
<script src="./scripts/components/ClusterMembersComponent.js"></script>
|
|
<script src="./scripts/components/FirmwareComponent.js"></script>
|
|
<!-- Container/view components after their deps -->
|
|
<script src="./scripts/components/FirmwareViewComponent.js"></script>
|
|
<script src="./scripts/components/ClusterViewComponent.js"></script>
|
|
<script src="./scripts/components/ClusterStatusComponent.js"></script>
|
|
<script src="./scripts/components/TopologyGraphComponent.js"></script>
|
|
<script src="./scripts/components/ComponentsLoader.js"></script>
|
|
<script src="./scripts/theme-manager.js"></script>
|
|
<script src="./scripts/app.js"></script>
|
|
</body>
|
|
|
|
</html> |