From c6e3e5704efe45ba5de8146d956ceb2e2fcf7c78 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Wed, 7 Jan 2026 22:52:51 -0500 Subject: [PATCH] Phase 6: Terminal aesthetic refinements and notifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes: - Added blinking terminal cursor animation - Smooth hover effects for execution/worker/workflow items - Hover animation: background highlight + border expand + slide - Loading pulse animation for loading states - Slide-in animation for log entries - Terminal beep sound using Web Audio API (different tones for success/error) - Real-time terminal notifications for command completion - Toast-style notifications with green glow effects - Auto-dismiss after 3 seconds with fade-out - Visual and audio feedback for user actions Sound features: - 800Hz tone for success (higher pitch) - 200Hz tone for errors (lower pitch) - 440Hz tone for info (standard A note) - 100ms duration, exponential fade-out - Graceful fallback if Web Audio API not supported Notification features: - Fixed position top-right - Terminal-themed styling with glow - Color-coded: green for success, red for errors - Icons: ✓ success, ✗ error, ℹ info - Smooth animations (slide-in, fade-out) Co-Authored-By: Claude Sonnet 4.5 --- public/index.html | 138 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/public/index.html b/public/index.html index 9c34e3b..bcc6a74 100644 --- a/public/index.html +++ b/public/index.html @@ -690,6 +690,66 @@ min-width: 120px; font-weight: bold; } + + /* Terminal Cursor Blink */ + @keyframes cursor-blink { + 0%, 49% { opacity: 1; } + 50%, 100% { opacity: 0; } + } + + .terminal-cursor::after { + content: '▋'; + animation: cursor-blink 1s step-end infinite; + color: var(--terminal-green); + } + + /* Hover effects for execution items */ + .execution-item { + transition: all 0.2s ease; + cursor: pointer; + } + + .execution-item:hover { + background: #001a00; + border-left-width: 5px; + transform: translateX(3px); + } + + .worker-item:hover { + background: #001a00; + border-left-width: 5px; + } + + .workflow-item:hover { + background: #001a00; + border-left-width: 5px; + } + + /* Loading pulse effect */ + .loading { + animation: loading-pulse 1.5s ease-in-out infinite; + } + + @keyframes loading-pulse { + 0%, 100% { opacity: 0.6; } + 50% { opacity: 1; } + } + + /* Success/Error message animations */ + @keyframes slide-in { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } + } + + .log-entry { + animation: slide-in 0.3s ease-out; + } @@ -1498,6 +1558,77 @@ loadExecutions(); } + // Terminal beep sound (Web Audio API) + function terminalBeep(type = 'success') { + try { + const audioContext = new (window.AudioContext || window.webkitAudioContext)(); + const oscillator = audioContext.createOscillator(); + const gainNode = audioContext.createGain(); + + oscillator.connect(gainNode); + gainNode.connect(audioContext.destination); + + // Different tones for different events + if (type === 'success') { + oscillator.frequency.value = 800; // Higher pitch for success + } else if (type === 'error') { + oscillator.frequency.value = 200; // Lower pitch for errors + } else { + oscillator.frequency.value = 440; // Standard A note + } + + oscillator.type = 'sine'; + gainNode.gain.setValueAtTime(0.1, audioContext.currentTime); + gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.1); + + oscillator.start(audioContext.currentTime); + oscillator.stop(audioContext.currentTime + 0.1); + } catch (error) { + // Silently fail if Web Audio API not supported + } + } + + // Show terminal notification + function showTerminalNotification(message, type = 'info') { + const notification = document.createElement('div'); + notification.style.cssText = ` + position: fixed; + top: 80px; + right: 20px; + background: #001a00; + border: 2px solid var(--terminal-green); + color: var(--terminal-green); + padding: 15px 20px; + font-family: var(--font-mono); + z-index: 10000; + animation: slide-in 0.3s ease-out; + box-shadow: 0 0 20px rgba(0, 255, 65, 0.3); + `; + + if (type === 'error') { + notification.style.borderColor = '#ff4444'; + notification.style.color = '#ff4444'; + message = '✗ ' + message; + } else if (type === 'success') { + message = '✓ ' + message; + } else { + message = 'ℹ ' + message; + } + + notification.textContent = message; + document.body.appendChild(notification); + + // Play beep + terminalBeep(type); + + // Remove after 3 seconds + setTimeout(() => { + notification.style.opacity = '0'; + notification.style.transition = 'opacity 0.5s'; + setTimeout(() => notification.remove(), 500); + }, 3000); + } + function connectWebSocket() { const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; ws = new WebSocket(`${protocol}//${window.location.host}`); @@ -1516,6 +1647,13 @@ console.log(`Error: ${data.stderr}`); } + // Show terminal notification + if (data.success) { + showTerminalNotification('Command completed successfully', 'success'); + } else { + showTerminalNotification('Command execution failed', 'error'); + } + // If viewing execution details, refresh that specific execution const executionModal = document.getElementById('viewExecutionModal'); if (executionModal && executionModal.classList.contains('show')) {