Files
p2ns/plugin-sites/peer.visualize/www/index.html
T
2026-05-30 21:01:31 -04:00

286 lines
12 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#0a0e1a">
<title>P2NS Network Visualization</title>
<link rel="icon" href="/favicon.ico" sizes="32x32">
<link rel="icon" href="/branding/p2ns-favicon-32.png" type="image/png" sizes="32x32">
<link rel="icon" href="/branding/p2ns-favicon-192.png" type="image/png" sizes="192x192">
<link rel="apple-touch-icon" href="/branding/p2ns-favicon-192.png">
<link rel="manifest" href="/manifest.json">
<link rel="stylesheet" href="/css/branding.css">
<link rel="stylesheet" href="/css/tailwind.css">
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="https://global.profile/css/profile-modal.css">
<link rel="stylesheet" href="https://unpkg.com/vis-network@latest/styles/vis-network.min.css">
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js"></script>
<script src="https://unpkg.com/vis-network@latest/standalone/umd/vis-network.min.js"></script>
</head>
<body>
<div class="container">
<!-- Header -->
<header class="header">
<div class="header-content header-brand">
<img src="/branding/p2ns-icon.png" alt="" class="brand-lockup-logo" width="32" height="32">
<h1>P2NS Network Visualization</h1>
<p class="subtitle">Visualize and explore the P2NS network</p>
</div>
<div class="header-status">
<div class="status" role="status" aria-live="polite">
<div class="status-indicator" id="statusIndicator" aria-label="Connection status"></div>
<span id="statusText">Connecting...</span>
</div>
</div>
</header>
<!-- Main Content -->
<div class="main-content">
<!-- Sidebar -->
<aside class="sidebar">
<!-- View Tabs -->
<div class="sidebar-section">
<h2>Views</h2>
<div>
<a href="#overview" class="view-tab active" data-view="system-overview">System Overview</a>
<a href="#network-graph" class="view-tab" data-view="network-graph">Network Graph</a>
<a href="#peer-details" class="view-tab" data-view="peer-details">Peer Details</a>
<a href="#domain-map" class="view-tab" data-view="domain-map">Domain Map</a>
</div>
</div>
<!-- Controls -->
<div class="sidebar-section" style="overflow-y: auto; overflow-x: hidden; min-height: 0; flex: 1;">
<h2>Controls</h2>
<!-- Layout Options -->
<div class="control-group">
<label class="control-label" for="layoutSelect">Layout</label>
<select id="layoutSelect" class="control-select">
<option value="force">Force-Directed</option>
<option value="hierarchical">Hierarchical</option>
</select>
</div>
<!-- Filters -->
<div class="control-group">
<label class="control-label">Filters</label>
<div class="control-checkbox-group">
<label class="control-checkbox">
<input type="checkbox" id="filterConnected" checked>
<span>Connected Peers</span>
</label>
<label class="control-checkbox">
<input type="checkbox" id="filterDomains" checked>
<span>Domains</span>
</label>
<label id="filterOfflinePeersLabel" class="control-checkbox hidden">
<input type="checkbox" id="filterOfflinePeers">
<span>Show Offline Peers</span>
</label>
</div>
</div>
<!-- Search -->
<div class="control-group">
<label class="control-label" for="searchInput">Search</label>
<input type="text" id="searchInput" placeholder="Search peers/domains..." class="control-input">
</div>
</div>
<!-- Stats -->
<div class="sidebar-section">
<h2>Stats</h2>
<div class="stats-list">
<div class="stat-item">
<span class="stat-label">Peers Seen:</span>
<span id="statPeers" class="stat-value">0</span>
</div>
<div class="stat-item">
<span class="stat-label">Domains:</span>
<span id="statDomains" class="stat-value">0</span>
</div>
<div class="stat-item">
<span class="stat-label">Connections:</span>
<span id="statConnections" class="stat-value">0</span>
</div>
</div>
</div>
</aside>
<!-- Main Visualization Area -->
<main class="main-viz-area">
<!-- View Container -->
<div id="viewContainer" class="flex-1 relative">
<!-- System Overview View (Default) -->
<div id="system-overview-view" class="view-content active">
<div class="system-overview-content">
<div class="metrics-container">
<div class="metrics-grid">
<div class="metric-card">
<h3>Total Peers Seen</h3>
<p class="metric-value primary" id="metricTotalPeers">0</p>
</div>
<div class="metric-card">
<h3>Connected Peers</h3>
<p class="metric-value success" id="metricConnectedPeers">0</p>
</div>
<div class="metric-card">
<h3>Total Domains</h3>
<p class="metric-value secondary" id="metricTotalDomains">0</p>
</div>
</div>
<div class="metrics-grid-centered">
<div class="metric-card">
<h3>System Uptime</h3>
<p class="metric-value" id="metricUptime">--</p>
</div>
<div class="metric-card">
<h3>Active Connections</h3>
<p class="metric-value warning" id="metricActiveConnections">0</p>
</div>
</div>
</div>
<div class="charts-grid">
<div class="chart-card">
<h3>Peer Connection Timeline</h3>
<div class="chart-container">
<canvas id="timelineChart"></canvas>
</div>
</div>
<div class="chart-card">
<h3>Connection Duration Distribution</h3>
<div class="chart-container">
<canvas id="durationChart"></canvas>
</div>
</div>
</div>
</div>
</div>
<!-- Network Graph View -->
<div id="network-graph-view" class="view-content">
<div id="graphContainer"></div>
</div>
<!-- Peer Details View -->
<div id="peer-details-view" class="view-content">
<div class="peer-details-content">
<div id="peerList" class="peer-list">
<!-- Peer items will be inserted here -->
</div>
</div>
</div>
<!-- Domain Map View -->
<div id="domain-map-view" class="view-content">
<div id="domainMapContainer"></div>
</div>
</div>
<!-- Peer Details Panel (Sidebar) -->
<div id="peerDetailsPanel" class="hidden">
<div class="peer-details-header">
<h3>Peer Details</h3>
<button id="closePeerDetails" class="close-btn" aria-label="Close"></button>
</div>
<div id="peerDetailsContent">
<!-- Peer details will be inserted here -->
</div>
</div>
</main>
</div>
</div>
<!-- Profile Modal Component -->
<div id="profile-modal" class="profile-modal" style="display: none;">
<div class="profile-modal-backdrop"></div>
<div class="profile-modal-content">
<button class="profile-modal-close" aria-label="Close" onclick="if(window.ProfileModal){window.ProfileModal.close();}">&times;</button>
<div class="profile-modal-loading" id="profile-modal-loading">
<div class="loading-spinner"></div>
<p>Loading profile...</p>
</div>
<div class="profile-modal-error" id="profile-modal-error" style="display: none;">
<p>Failed to load profile</p>
</div>
<div class="profile-modal-body" id="profile-modal-body" style="display: none;">
<div class="profile-modal-header">
<div class="profile-modal-avatar-container">
<img id="profile-modal-avatar" class="profile-modal-avatar" alt="Avatar" onerror="this.style.display='none'; document.getElementById('profile-modal-avatar-placeholder').style.display='flex';">
<div id="profile-modal-avatar-placeholder" class="profile-modal-avatar-placeholder" style="display: none;">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
<circle cx="12" cy="7" r="4"></circle>
</svg>
</div>
</div>
<div class="profile-modal-header-info">
<h2 id="profile-modal-name" class="profile-modal-name">Loading...</h2>
<p id="profile-modal-peerid" class="profile-modal-peerid">...</p>
</div>
</div>
<div class="profile-modal-bio" id="profile-modal-bio-container" style="display: none;">
<p id="profile-modal-bio" class="profile-modal-bio-text"></p>
</div>
<div class="profile-modal-details" id="profile-modal-details">
<div class="profile-modal-detail-item" id="profile-modal-email-item" style="display: none;">
<span class="profile-modal-detail-icon">📧</span>
<a id="profile-modal-email" href="#" class="profile-modal-detail-link"></a>
</div>
<div class="profile-modal-detail-item" id="profile-modal-website-item" style="display: none;">
<span class="profile-modal-detail-icon">🌐</span>
<a id="profile-modal-website" href="#" target="_blank" rel="noopener noreferrer" class="profile-modal-detail-link"></a>
</div>
<div class="profile-modal-detail-item" id="profile-modal-x-item" style="display: none;">
<span class="profile-modal-detail-icon">🐦</span>
<a id="profile-modal-x" href="#" target="_blank" rel="noopener noreferrer" class="profile-modal-detail-link"></a>
</div>
</div>
<div class="profile-modal-actions" id="profile-modal-actions" style="display: none;">
<button id="profile-modal-block-btn" class="profile-modal-action-btn profile-modal-action-btn-block" style="display: none;">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"></circle>
<line x1="4.93" y1="4.93" x2="19.07" y2="19.07"></line>
</svg>
Block
</button>
<button id="profile-modal-unblock-btn" class="profile-modal-action-btn profile-modal-action-btn-unblock" style="display: none;">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"></circle>
<path d="M12 6v6l4 2"></path>
</svg>
Unblock
</button>
</div>
</div>
</div>
</div>
<!-- Scripts -->
<script src="/sdk-utils.js"></script>
<script src="/js/utils.js"></script>
<script src="/js/data-processor.js"></script>
<script src="/js/websocket-client.js"></script>
<script src="https://global.profile/js/profile-modal.js"></script>
<script src="/js/visualization/dashboard.js"></script>
<script src="/js/visualization/peer-details.js"></script>
<script src="/js/visualization/network-graph.js"></script>
<script src="/js/visualization/domain-map.js"></script>
<script src="/js/app.js"></script>
</body>
</html>