From 4b1557888e6026765d5eaa9a278151119d398adc Mon Sep 17 00:00:00 2001 From: Aleksei Fedorov Date: Sat, 6 Sep 2025 14:08:37 +0000 Subject: [PATCH 1/2] feat: optimize CSS structure and add missing definitions - Remove unused CSS classes (.pulse, @keyframes pulse) - Add missing CSS definitions for JavaScript-used classes: * Connection styles: .connection-box, .connection-text, .connection-details * Syscall styles: .syscall-box, .syscall-text * File label styles: .file-label, .file-label-bg * Tooltip styles: .tooltip * Bezier curve styles: .bezier-curve, .file-endpoint * Semicircle menu styles: .semicircle-menu, .menu-item, .menu-icon, .individual-menu-bar, .individual-menu-label - Improve responsive design with media queries for new classes - Ensure consistent font usage across all components - Organize CSS by functionality for better maintainability --- static/css/main.css | 132 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 123 insertions(+), 9 deletions(-) diff --git a/static/css/main.css b/static/css/main.css index af3c417..1d6a947 100755 --- a/static/css/main.css +++ b/static/css/main.css @@ -79,24 +79,138 @@ svg { stroke-width: 0.7; } -/* Animations */ -@keyframes pulse { - 0% { opacity: 0.6; } - 50% { opacity: 1; } - 100% { opacity: 0.6; } +/* Connection styles */ +.connection-box { + fill: rgba(255, 255, 255, 0.04); + stroke: #aaa; + stroke-width: 0.5; + rx: 4; +} + +.connection-text { + font-size: 12px; + fill: #444; + font-family: 'Share Tech Mono', monospace; +} + +.connection-details { + font-size: 10px; + fill: #666; + font-family: 'Share Tech Mono', monospace; +} + +/* Syscall styles */ +.syscall-box { + fill: rgba(255, 255, 255, 0.04); + stroke: #aaa; + stroke-width: 0.5; +} + +.syscall-text { + font-size: 12px; + fill: #444; + font-family: 'Share Tech Mono', monospace; +} + +/* File label styles */ +.file-label { + font-size: 11px; + fill: #333; + font-family: 'Share Tech Mono', monospace; + text-anchor: start; +} + +.file-label-bg { + fill: rgba(255, 255, 255, 0.8); + stroke: #ccc; + stroke-width: 0.5; + rx: 2; +} + +/* Tooltip styles */ +.tooltip { + position: absolute; + background: rgba(0, 0, 0, 0.9); + color: white; + padding: 8px; + border-radius: 4px; + font-size: 12px; + pointer-events: none; + z-index: 1000; + max-width: 300px; +} + +/* Bezier curve styles */ +.bezier-curve { + fill: none; + stroke: rgba(100, 100, 100, 0.2); + stroke-width: 0.7; } -.pulse { - animation: pulse 2s infinite; +.file-endpoint { + fill: #555; + stroke: #222; + stroke-width: 0.5; +} + +/* Semicircle menu styles */ +.semicircle-menu { + fill: rgba(255, 255, 255, 0.04); + stroke: #aaa; + stroke-width: 0.5; +} + +.menu-item { + fill: rgba(255, 255, 255, 0.04); + stroke: #aaa; + stroke-width: 0.5; + cursor: pointer; +} + +.menu-item:hover { + fill: rgba(255, 255, 255, 0.08); +} + +.menu-icon { + fill: #444; + font-family: 'Share Tech Mono', monospace; + font-size: 12px; + text-anchor: middle; + dominant-baseline: central; +} + +.individual-menu-bar { + fill: rgba(255, 255, 255, 0.04); + stroke: #aaa; + stroke-width: 0.5; +} + +.individual-menu-label { + fill: #444; + font-family: 'Share Tech Mono', monospace; + font-size: 11px; + text-anchor: start; + dominant-baseline: central; } +/* Animations - removed unused pulse animation */ + /* Responsiveness */ @media (max-width: 768px) { - .socket-text { + .socket-text, .connection-text, .syscall-text { + font-size: 10px; + } + + .feature-text, .connection-details { + font-size: 9px; + } + + .file-label, .menu-icon, .individual-menu-label { font-size: 10px; } - .feature-text { + .tooltip { font-size: 10px; + max-width: 250px; } } From 0e67bfd7c5656ca8bacfa7ee944ec6b4a56e182c Mon Sep 17 00:00:00 2001 From: Aleksei Fedorov Date: Sat, 6 Sep 2025 20:36:57 +0000 Subject: [PATCH 2/2] Add right semicircle menu with Linux component icons - Implement RightSemicircleMenuManager class - Add 8 Linux component SVG icons (kernel, processes, memory, files, network, devices, security, scheduler) - Create semicircle menu attached to right edge of screen - Add horizontal lines connecting icons to labels - Use dark gray color scheme for icons, lines, and labels - Integrate with main.js drawing cycle - Add debug logging for troubleshooting --- index.html | 14 +- static/css/main.css | 40 +++++- static/images/device-driver.svg | 16 +++ static/images/file-system.svg | 13 ++ static/images/linux-kernel.svg | 14 ++ static/images/memory-manager.svg | 13 ++ static/images/network-stack.svg | 17 +++ static/images/process-manager.svg | 13 ++ static/images/scheduler.svg | 16 +++ static/images/security-module.svg | 9 ++ static/js/main.js | 34 ++++- static/js/right-semicircle-menu.js | 207 +++++++++++++++++++++++++++++ 12 files changed, 403 insertions(+), 3 deletions(-) create mode 100644 static/images/device-driver.svg create mode 100644 static/images/file-system.svg create mode 100644 static/images/linux-kernel.svg create mode 100644 static/images/memory-manager.svg create mode 100644 static/images/network-stack.svg create mode 100644 static/images/process-manager.svg create mode 100644 static/images/scheduler.svg create mode 100644 static/images/security-module.svg create mode 100644 static/js/right-semicircle-menu.js diff --git a/index.html b/index.html index 22db10e..90fb080 100755 --- a/index.html +++ b/index.html @@ -26,6 +26,18 @@ - + + + diff --git a/static/css/main.css b/static/css/main.css index 1d6a947..9ccb810 100755 --- a/static/css/main.css +++ b/static/css/main.css @@ -153,7 +153,45 @@ svg { stroke-width: 0.5; } -/* Semicircle menu styles */ +/* Right semicircle menu styles */ +.right-semicircle-menu { + fill: rgba(255, 255, 255, 0.05); + stroke: rgba(255, 255, 255, 0.1); + stroke-width: 1px; +} + +.right-menu-item { + fill: #333; + stroke: #555; + stroke-width: 1px; + cursor: pointer; +} + +.right-menu-item:hover { + fill: #444; +} + +.right-menu-icon { + font-size: 14px; + fill: #fff; + text-anchor: middle; + dominant-baseline: central; +} + +.right-menu-line { + stroke: rgba(255, 255, 255, 0.3); + stroke-width: 1px; +} + +.right-menu-label { + font-size: 11px; + fill: rgba(255, 255, 255, 0.7); + font-family: 'Share Tech Mono', monospace; + text-anchor: end; + dominant-baseline: central; +} + +/* Legacy semicircle menu styles (kept for compatibility) */ .semicircle-menu { fill: rgba(255, 255, 255, 0.04); stroke: #aaa; diff --git a/static/images/device-driver.svg b/static/images/device-driver.svg new file mode 100644 index 0000000..64e42c5 --- /dev/null +++ b/static/images/device-driver.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/static/images/file-system.svg b/static/images/file-system.svg new file mode 100644 index 0000000..f5ae2ac --- /dev/null +++ b/static/images/file-system.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/static/images/linux-kernel.svg b/static/images/linux-kernel.svg new file mode 100644 index 0000000..c989b41 --- /dev/null +++ b/static/images/linux-kernel.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/static/images/memory-manager.svg b/static/images/memory-manager.svg new file mode 100644 index 0000000..c9b1e2f --- /dev/null +++ b/static/images/memory-manager.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/static/images/network-stack.svg b/static/images/network-stack.svg new file mode 100644 index 0000000..7dcbc6f --- /dev/null +++ b/static/images/network-stack.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/static/images/process-manager.svg b/static/images/process-manager.svg new file mode 100644 index 0000000..5fbb7c0 --- /dev/null +++ b/static/images/process-manager.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/static/images/scheduler.svg b/static/images/scheduler.svg new file mode 100644 index 0000000..cbee56f --- /dev/null +++ b/static/images/scheduler.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/static/images/security-module.svg b/static/images/security-module.svg new file mode 100644 index 0000000..2681035 --- /dev/null +++ b/static/images/security-module.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/static/js/main.js b/static/js/main.js index f634608..b492354 100755 --- a/static/js/main.js +++ b/static/js/main.js @@ -171,6 +171,7 @@ const svg = d3.select("svg"); let syscallsManager; let resizeTimeout; let nginxFilesManager; +let rightSemicircleMenuManager; // Application initialization function initApp() { @@ -184,9 +185,27 @@ function initApp() { connectionsManager.startAutoUpdate(3000); window.nginxFilesManager = new NginxFilesManager(); - // Draw main interface + + // Initialize right semicircle menu manager + console.log('🎯 RightSemicircleMenuManager class available:', typeof RightSemicircleMenuManager); + if (typeof RightSemicircleMenuManager !== 'undefined') { + window.rightSemicircleMenuManager = new RightSemicircleMenuManager(); + console.log('🎯 RightSemicircleMenuManager initialized:', window.rightSemicircleMenuManager); + } else { + console.error('❌ RightSemicircleMenuManager class not found!'); + } + + // Draw main interface FIRST draw(); + // Then render semicircle AFTER draw() completes + setTimeout(() => { + if (window.rightSemicircleMenuManager) { + console.log('🎯 Force rendering semicircle after draw()...'); + window.rightSemicircleMenuManager.renderRightSemicircleMenu(); + } + }, 100); + // Start updates syscallsManager.startAutoUpdate(3000); @@ -201,6 +220,13 @@ function setupEventListeners() { clearTimeout(resizeTimeout); resizeTimeout = setTimeout(() => { draw(); + // Render semicircle after draw() completes + setTimeout(() => { + if (window.rightSemicircleMenuManager) { + console.log('🎯 Force rendering semicircle after resize...'); + window.rightSemicircleMenuManager.renderRightSemicircleMenu(); + } + }, 50); }, 100); }); @@ -217,6 +243,7 @@ function setupEventListeners() { // Main drawing function function draw() { + // Clear all elements to prevent duplication svg.selectAll("*").remove(); const width = window.innerWidth; @@ -243,6 +270,11 @@ function draw() { // Draw curves at bottom drawLowerBezierGrid(); + + // Render right semicircle menu (after all other elements) + if (window.rightSemicircleMenuManager) { + window.rightSemicircleMenuManager.renderRightSemicircleMenu(); + } } // Draw central circle diff --git a/static/js/right-semicircle-menu.js b/static/js/right-semicircle-menu.js new file mode 100644 index 0000000..de44534 --- /dev/null +++ b/static/js/right-semicircle-menu.js @@ -0,0 +1,207 @@ +/** + * Right Semicircle Menu Manager + * Implements a large semicircle menu on the right side of the screen + * Based on the design example with 7-8 dark circles and horizontal lines + */ +class RightSemicircleMenuManager { + constructor() { + this.menuItems = [ + { id: 'kernel', icon: '/static/images/linux-kernel.svg', label: 'Kernel' }, + { id: 'processes', icon: '/static/images/process-manager.svg', label: 'Processes' }, + { id: 'memory', icon: '/static/images/memory-manager.svg', label: 'Memory' }, + { id: 'files', icon: '/static/images/file-system.svg', label: 'Files' }, + { id: 'network', icon: '/static/images/network-stack.svg', label: 'Network' }, + { id: 'devices', icon: '/static/images/device-driver.svg', label: 'Devices' }, + { id: 'security', icon: '/static/images/security-module.svg', label: 'Security' }, + { id: 'scheduler', icon: '/static/images/scheduler.svg', label: 'Scheduler' } + ]; + this.isVisible = false; + } + + /** + * Render the right semicircle menu + */ + renderRightSemicircleMenu() { + console.log('🎯 Rendering right semicircle menu...'); + const svg = d3.select('svg'); + const width = window.innerWidth; + const height = window.innerHeight; + console.log('📐 Screen dimensions:', { width, height }); + + // Clear existing semicircle elements + svg.selectAll('.right-semicircle-menu, .right-menu-item, .right-menu-icon, .right-menu-line, .right-menu-label').remove(); + + // Semicircle parameters - attached to right edge with cut-off edges + const menuRadius = height * 0.4; // Larger radius for better coverage + const menuX = width; // Position exactly at right edge + const menuY = height / 2; // Vertically centered + + // Create the large semicircle path (right side) + const semicirclePath = this.createSemicirclePath(menuX, menuY, menuRadius, 'right'); + console.log('🎯 Semicircle path:', semicirclePath); + console.log('🎯 Semicircle position:', { menuX, menuY, menuRadius }); + + svg.append('path') + .attr('class', 'right-semicircle-menu') + .attr('d', semicirclePath) + .style('fill', '#ffffff') // White fill like the "Filter: Active" block + .style('stroke', '#d0d0d0') // Light gray stroke for subtle border + .style('stroke-width', '1px'); // Thin stroke + + // Create menu items (circles) along the semicircle with cut-off consideration + this.menuItems.forEach((item, index) => { + // Adjust angle range to account for cut-off edges (70% of full semicircle) + const startAngle = Math.PI / 2 + Math.PI * 0.15; // Start 15% from top + const endAngle = 3 * Math.PI / 2 - Math.PI * 0.15; // End 15% from bottom + const angle = startAngle + (index * (endAngle - startAngle) / (this.menuItems.length - 1)); + + const itemRadius = menuRadius * 0.06; // Smaller dark circles + const itemDistance = menuRadius * 0.6; // Distance from center + + const itemX = menuX + Math.cos(angle) * itemDistance; + const itemY = menuY + Math.sin(angle) * itemDistance; + + // Dark circle for menu item + svg.append('circle') + .attr('class', 'right-menu-item') + .attr('cx', itemX) + .attr('cy', itemY) + .attr('r', itemRadius) + .style('fill', '#333') // Dark color + .style('stroke', '#555') + .style('stroke-width', '1px') + .style('cursor', 'pointer') + .on('click', () => this.handleMenuClick(item.id)) + .on('mouseenter', function() { + d3.select(this).style('fill', '#444'); + }) + .on('mouseleave', function() { + d3.select(this).style('fill', '#333'); + }); + + // SVG icon inside the circle + const iconSize = itemRadius * 1.5; // Slightly larger than circle + svg.append('image') + .attr('class', 'right-menu-icon') + .attr('x', itemX - iconSize/2) + .attr('y', itemY - iconSize/2) + .attr('width', iconSize) + .attr('height', iconSize) + .attr('href', item.icon); + + // Horizontal line extending left from the circle + const lineLength = menuRadius * 0.2; + const lineEndX = itemX - lineLength; + + svg.append('line') + .attr('class', 'right-menu-line') + .attr('x1', itemX - itemRadius) + .attr('y1', itemY) + .attr('x2', lineEndX) + .attr('y2', itemY) + .style('stroke', '#333') // Dark gray like the icons + .style('stroke-width', '1px'); + + // Label at the end of the line + svg.append('text') + .attr('class', 'right-menu-label') + .attr('x', lineEndX - 5) + .attr('y', itemY) + .attr('text-anchor', 'end') + .attr('dominant-baseline', 'central') + .style('font-size', '11px') + .style('fill', '#333') // Dark gray like the icons + .style('font-family', "'Share Tech Mono', monospace") + .text(item.label); + }); + + this.isVisible = true; + } + + /** + * Create semicircle path for the right side with cut-off edges + */ + createSemicirclePath(centerX, centerY, radius, side) { + if (side === 'right') { + // Calculate cut-off points (top and bottom edges) + const cutOffTop = centerY - radius * 0.7; // Cut off top 30% + const cutOffBottom = centerY + radius * 0.7; // Cut off bottom 30% + + // Calculate angles for cut-off points + const topAngle = Math.asin((cutOffTop - centerY) / radius); + const bottomAngle = Math.asin((cutOffBottom - centerY) / radius); + + // Calculate start and end points + const startX = centerX + Math.cos(topAngle) * radius; + const startY = cutOffTop; + const endX = centerX + Math.cos(bottomAngle) * radius; + const endY = cutOffBottom; + + // Create path with cut-off edges + return `M ${startX} ${startY} A ${radius} ${radius} 0 0 1 ${endX} ${endY}`; + } + return ''; + } + + /** + * Handle menu item click + */ + handleMenuClick(itemId) { + console.log(`Right menu clicked: ${itemId}`); + // Add functionality for each menu item + switch(itemId) { + case 'kernel': + // Show kernel view + console.log('🔧 Kernel view selected'); + break; + case 'processes': + // Show processes view + console.log('👤 Processes view selected'); + break; + case 'memory': + // Show memory view + console.log('🧠 Memory view selected'); + break; + case 'files': + // Show files view + console.log('📁 Files view selected'); + break; + case 'network': + // Show network view + console.log('🌐 Network view selected'); + break; + case 'devices': + // Show devices view + console.log('🔌 Devices view selected'); + break; + case 'security': + // Show security view + console.log('🔒 Security view selected'); + break; + case 'scheduler': + // Show scheduler view + console.log('⏰ Scheduler view selected'); + break; + } + } + + /** + * Toggle menu visibility + */ + toggle() { + if (this.isVisible) { + this.hide(); + } else { + this.renderRightSemicircleMenu(); + } + } + + /** + * Hide the menu + */ + hide() { + const svg = d3.select('svg'); + svg.selectAll('.right-semicircle-menu, .right-menu-item, .right-menu-icon, .right-menu-line, .right-menu-label').remove(); + this.isVisible = false; + } +}