Spaces:
Configuration error
Configuration error
| // Desktop application script for SpotSync Alpha | |
| // Tab switching functionality for code preview | |
| function showTab(tabName) { | |
| // Hide all tabs | |
| document.getElementById('main-tab')?.classList.add('hidden'); | |
| document.getElementById('watcher-tab')?.classList.add('hidden'); | |
| document.getElementById('executor-tab')?.classList.add('hidden'); | |
| document.getElementById('models-tab')?.classList.add('hidden'); | |
| document.getElementById('security-tab')?.classList.add('hidden'); | |
| // Show selected tab | |
| document.getElementById(`${tabName}-tab`)?.classList.remove('hidden'); | |
| // Update active tab button styles | |
| const tabButtons = document.querySelectorAll('[onclick^="showTab"]'); | |
| tabButtons.forEach(button => { | |
| if (button.textContent.includes(tabName)) { | |
| button.classList.remove('text-gray-400', 'hover:text-gray-200'); | |
| button.classList.add('border-cyan-500', 'text-cyan-300'); | |
| button.classList.add('tab-active'); | |
| } else { | |
| button.classList.remove('border-cyan-500', 'text-cyan-300', 'tab-active'); | |
| button.classList.add('text-gray-400', 'hover:text-gray-200'); | |
| } | |
| }); | |
| } | |
| // Copy code to clipboard | |
| function copyCode() { | |
| const activeTab = document.querySelector('#code-container > pre:not(.hidden)'); | |
| if (!activeTab) return; | |
| const codeText = activeTab.textContent; | |
| // Use Electron's clipboard API if available | |
| if (typeof require !== 'undefined') { | |
| const { clipboard } = require('electron'); | |
| clipboard.writeText(codeText); | |
| showDesktopNotification('Code copied to clipboard'); | |
| } else { | |
| navigator.clipboard.writeText(codeText).then(() => { | |
| showDesktopNotification('Code copied to clipboard'); | |
| }); | |
| } | |
| } | |
| // Show desktop notification | |
| function showDesktopNotification(message, type = 'info') { | |
| // Create notification element | |
| const notification = document.createElement('div'); | |
| notification.className = 'tray-notification desktop-fade-in'; | |
| const icon = type === 'success' ? 'check-circle' : type === 'error' ? 'alert-circle' : 'info'; | |
| const color = type === 'success' ? 'text-green-400' : type === 'error' ? 'text-red-400' : 'text-cyan-400'; | |
| notification.innerHTML = ` | |
| <div class="flex items-start gap-3"> | |
| <i data-feather="${icon}" class="w-5 h-5 ${color}"></i> | |
| <div class="flex-1"> | |
| <p class="text-sm font-medium text-gray-100">${message}</p> | |
| <p class="text-xs text-gray-400 mt-1">Just now</p> | |
| </div> | |
| <button onclick="this.parentElement.parentElement.remove()" class="text-gray-400 hover:text-gray-200"> | |
| <i data-feather="x" class="w-4 h-4"></i> | |
| </button> | |
| </div> | |
| `; | |
| document.body.appendChild(notification); | |
| feather.replace(); | |
| // Show notification | |
| setTimeout(() => notification.classList.add('show'), 10); | |
| // Auto remove after 5 seconds | |
| setTimeout(() => { | |
| if (notification.parentElement) { | |
| notification.classList.remove('show'); | |
| setTimeout(() => { | |
| if (notification.parentElement) { | |
| notification.remove(); | |
| } | |
| }, 300); | |
| } | |
| }, 5000); | |
| } | |
| // Simulate live trade data | |
| function simulateLiveTrades() { | |
| const tradeFeed = document.getElementById('trade-feed'); | |
| if (!tradeFeed) return; | |
| const trades = [ | |
| { symbol: 'BTCUSDT', side: 'BUY', quantity: 0.05, price: '64320.50', time: new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}) }, | |
| { symbol: 'ETHUSDT', side: 'SELL', quantity: 1.20, price: '3415.75', time: new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}) }, | |
| { symbol: 'SOLUSDT', side: 'BUY', quantity: 12.50, price: '185.30', time: new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}) }, | |
| { symbol: 'ADAUSDT', side: 'BUY', quantity: 500, price: '0.6420', time: new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}) }, | |
| { symbol: 'BNBUSDT', side: 'SELL', quantity: 3.20, price: '420.10', time: new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}) } | |
| ]; | |
| const trade = trades[Math.floor(Math.random() * trades.length)]; | |
| const sideClass = trade.side === 'BUY' ? 'text-green-400' : 'text-red-400'; | |
| const sideIcon = trade.side === 'BUY' ? 'trending-up' : 'trending-down'; | |
| const tradeElement = document.createElement('div'); | |
| tradeElement.className = 'flex items-center justify-between p-3 bg-gray-800/50 rounded-lg desktop-fade-in'; | |
| tradeElement.innerHTML = ` | |
| <div class="flex items-center gap-3"> | |
| <i data-feather="${sideIcon}" class="w-4 h-4 ${sideClass}"></i> | |
| <span class="font-semibold">${trade.symbol}</span> | |
| <span class="text-gray-400">${trade.quantity} @ ${trade.price}</span> | |
| </div> | |
| <span class="text-sm text-gray-400">${trade.time}</span> | |
| `; | |
| if (tradeFeed.children.length >= 5) { | |
| tradeFeed.removeChild(tradeFeed.lastChild); | |
| } | |
| tradeFeed.insertBefore(tradeElement, tradeFeed.firstChild); | |
| feather.replace(); | |
| } | |
| // Update system metrics periodically | |
| function updateMetrics() { | |
| const metrics = { | |
| 'uptime': '99.8%', | |
| 'followers': '3', | |
| 'trades': `${Math.floor(Math.random() * 10 + 40)}`, | |
| 'success': `${(Math.random() * 2 + 97.5).toFixed(1)}%` | |
| }; | |
| for (const [key, value] of Object.entries(metrics)) { | |
| const element = document.getElementById(`metric-${key}`); | |
| if (element) { | |
| element.textContent = value; | |
| } | |
| } | |
| } | |
| // Toggle engine status | |
| function toggleEngineStatus() { | |
| const button = document.querySelector('button:has(i[data-feather="pause"])'); | |
| const statusLight = document.querySelector('.relative .w-3.h-3'); | |
| if (button.innerHTML.includes('Pause')) { | |
| button.innerHTML = '<i data-feather="play" class="w-3 h-3"></i> Start Engine'; | |
| if (statusLight) { | |
| statusLight.classList.remove('bg-green-500'); | |
| statusLight.classList.add('bg-yellow-500'); | |
| } | |
| showDesktopNotification('Trading engine paused', 'info'); | |
| } else { | |
| button.innerHTML = '<i data-feather="pause" class="w-3 h-3"></i> Pause Engine'; | |
| if (statusLight) { | |
| statusLight.classList.remove('bg-yellow-500'); | |
| statusLight.classList.add('bg-green-500'); | |
| } | |
| showDesktopNotification('Trading engine started', 'success'); | |
| } | |
| feather.replace(); | |
| } | |
| // Export logs function | |
| function exportLogs() { | |
| showDesktopNotification('Exporting trade logs to CSV...', 'info'); | |
| // Simulate export process | |
| setTimeout(() => { | |
| showDesktopNotification('Logs exported successfully to Downloads folder', 'success'); | |
| }, 1500); | |
| } | |
| // Add new follower | |
| function addFollower() { | |
| showDesktopNotification('Opening follower configuration wizard...', 'info'); | |
| // In a real app, this would open a modal or new window | |
| setTimeout(() => { | |
| const followers = parseInt(document.getElementById('metric-followers').textContent); | |
| document.getElementById('metric-followers').textContent = followers + 1; | |
| showDesktopNotification('New follower added successfully', 'success'); | |
| }, 1000); | |
| } | |
| // Initialize desktop context menu | |
| function initContextMenu() { | |
| document.addEventListener('contextmenu', function(e) { | |
| e.preventDefault(); | |
| // Remove existing context menu | |
| const existingMenu = document.getElementById('context-menu'); | |
| if (existingMenu) { | |
| existingMenu.remove(); | |
| } | |
| // Create new context menu | |
| const contextMenu = document.createElement('div'); | |
| contextMenu.id = 'context-menu'; | |
| contextMenu.className = 'context-menu'; | |
| contextMenu.style.position = 'fixed'; | |
| contextMenu.style.left = `${e.pageX}px`; | |
| contextMenu.style.top = `${e.pageY}px`; | |
| // Menu items based on target | |
| const menuItems = [ | |
| { label: 'Copy', icon: 'copy', action: () => copyCode() }, | |
| { label: 'Refresh', icon: 'refresh-cw', action: () => window.location.reload() }, | |
| { label: 'Inspect Element', icon: 'code', action: () => { | |
| if (typeof require !== 'undefined') { | |
| const { remote } = require('electron'); | |
| remote.getCurrentWindow().webContents.openDevTools(); | |
| } | |
| }}, | |
| { label: 'Export Data', icon: 'download', action: () => exportLogs() } | |
| ]; | |
| menuItems.forEach(item => { | |
| const menuItem = document.createElement('div'); | |
| menuItem.className = 'context-menu-item flex items-center gap-2'; | |
| menuItem.innerHTML = ` | |
| <i data-feather="${item.icon}" class="w-3 h-3"></i> | |
| <span>${item.label}</span> | |
| `; | |
| menuItem.addEventListener('click', () => { | |
| item.action(); | |
| contextMenu.remove(); | |
| }); | |
| contextMenu.appendChild(menuItem); | |
| }); | |
| document.body.appendChild(contextMenu); | |
| feather.replace(); | |
| // Close menu when clicking elsewhere | |
| document.addEventListener('click', function closeMenu() { | |
| contextMenu.remove(); | |
| document.removeEventListener('click', closeMenu); | |
| }); | |
| }); | |
| } | |
| // Initialize all animations and effects | |
| function initAnimations() { | |
| const elements = document.querySelectorAll('.desktop-fade-in'); | |
| elements.forEach((element, index) => { | |
| element.style.animationDelay = `${index * 0.1}s`; | |
| }); | |
| } | |
| // Initialize everything when the DOM is loaded | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Initialize Feather icons | |
| feather.replace(); | |
| // Initialize components | |
| initAnimations(); | |
| initContextMenu(); | |
| // Set up intervals for dynamic updates | |
| setInterval(simulateLiveTrades, 5000); | |
| setInterval(updateMetrics, 3000); | |
| // Start with first tab active | |
| showTab('main'); | |
| // Add event listeners for desktop buttons | |
| document.querySelector('button:has(i[data-feather="play"])')?.addEventListener('click', toggleEngineStatus); | |
| document.querySelector('button:has(i[data-feather="user-plus"])')?.addEventListener('click', addFollower); | |
| document.querySelector('button:has(i[data-feather="download"])')?.addEventListener('click', exportLogs); | |
| // Add keyboard shortcuts for desktop | |
| document.addEventListener('keydown', function(e) { | |
| // Ctrl/Cmd + 1-5 to switch tabs | |
| if ((e.ctrlKey || e.metaKey) && e.key >= '1' && e.key <= '5') { | |
| const tabNames = ['main', 'watcher', 'executor', 'models', 'security']; | |
| const index = parseInt(e.key) - 1; | |
| if (tabNames[index]) { | |
| showTab(tabNames[index]); | |
| e.preventDefault(); | |
| } | |
| } | |
| // Ctrl/Cmd + E to toggle engine | |
| if ((e.ctrlKey || e.metaKey) && e.key === 'e') { | |
| toggleEngineStatus(); | |
| e.preventDefault(); | |
| } | |
| // Ctrl/Cmd + N to add follower | |
| if ((e.ctrlKey || e.metaKey) && e.key === 'n') { | |
| addFollower(); | |
| e.preventDefault(); | |
| } | |
| // Ctrl/Cmd + S to export logs | |
| if ((e.ctrlKey || e.metaKey) && e.key === 's') { | |
| exportLogs(); | |
| e.preventDefault(); | |
| } | |
| // F12 for dev tools | |
| if (e.key === 'F12') { | |
| if (typeof require !== 'undefined') { | |
| const { remote } = require('electron'); | |
| remote.getCurrentWindow().webContents.openDevTools(); | |
| e.preventDefault(); | |
| } | |
| } | |
| }); | |
| // Show welcome notification | |
| setTimeout(() => { | |
| showDesktopNotification('SpotSync Alpha Desktop is running in system tray', 'info'); | |
| }, 1000); | |
| }); | |