Spaces:
Build error
Build error
Download static/js/main.js from smodusermc/MC: direct link, hf CLI and curl.
- Browser
- Download file 6.74 kB
-
https://huggingface.co/spaces/smodusermc/MC/resolve/main/static/js/main.js
- Command line
-
hf download hf://spaces/smodusermc/MC/static/js/main.js
-
curl -L -o main.js https://huggingface.co/spaces/smodusermc/MC/resolve/main/static/js/main.js
6.74 kB
| // ============================================ | |
| // Minecraft Server Panel - Main JavaScript | |
| // ============================================ | |
| // Toast Notification System | |
| function showToast(message, type = 'info') { | |
| const container = document.getElementById('toast-container'); | |
| if (!container) return; | |
| const toast = document.createElement('div'); | |
| toast.className = `toast ${type}`; | |
| toast.textContent = message; | |
| container.appendChild(toast); | |
| // Auto remove after 5 seconds | |
| setTimeout(() => { | |
| toast.style.animation = 'slideOut 0.3s ease forwards'; | |
| setTimeout(() => toast.remove(), 300); | |
| }, 5000); | |
| } | |
| // Add slideOut animation | |
| const style = document.createElement('style'); | |
| style.textContent = ` | |
| @keyframes slideOut { | |
| from { | |
| transform: translateX(0); | |
| opacity: 1; | |
| } | |
| to { | |
| transform: translateX(100%); | |
| opacity: 0; | |
| } | |
| } | |
| `; | |
| document.head.appendChild(style); | |
| // API Helper Functions | |
| async function apiCall(endpoint, method = 'GET', data = null) { | |
| const options = { | |
| method, | |
| headers: { | |
| 'Content-Type': 'application/json' | |
| } | |
| }; | |
| if (data && method !== 'GET') { | |
| options.body = JSON.stringify(data); | |
| } | |
| try { | |
| const response = await fetch(endpoint, options); | |
| const result = await response.json(); | |
| return result; | |
| } catch (error) { | |
| console.error('API Error:', error); | |
| throw error; | |
| } | |
| } | |
| // Server Control Functions | |
| async function serverControl(action) { | |
| try { | |
| const result = await apiCall(`/api/server/${action}`, 'POST'); | |
| showToast(result.message, result.success ? 'success' : 'error'); | |
| return result; | |
| } catch (error) { | |
| showToast(`Failed to ${action} server`, 'error'); | |
| } | |
| } | |
| // Utility Functions | |
| function formatBytes(bytes) { | |
| if (bytes === 0) return '0 B'; | |
| const k = 1024; | |
| const sizes = ['B', 'KB', 'MB', 'GB']; | |
| const i = Math.floor(Math.log(bytes) / Math.log(k)); | |
| return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; | |
| } | |
| function formatDuration(seconds) { | |
| const hours = Math.floor(seconds / 3600); | |
| const minutes = Math.floor((seconds % 3600) / 60); | |
| const secs = Math.floor(seconds % 60); | |
| if (hours > 0) { | |
| return `${hours}h ${minutes}m ${secs}s`; | |
| } else if (minutes > 0) { | |
| return `${minutes}m ${secs}s`; | |
| } | |
| return `${secs}s`; | |
| } | |
| function escapeHtml(text) { | |
| const div = document.createElement('div'); | |
| div.textContent = text; | |
| return div.innerHTML; | |
| } | |
| // Debounce function for search inputs | |
| function debounce(func, wait) { | |
| let timeout; | |
| return function executedFunction(...args) { | |
| const later = () => { | |
| clearTimeout(timeout); | |
| func(...args); | |
| }; | |
| clearTimeout(timeout); | |
| timeout = setTimeout(later, wait); | |
| }; | |
| } | |
| // Update server status indicator in sidebar | |
| function updateSidebarStatus(running, starting = false) { | |
| const indicator = document.getElementById('server-status-indicator'); | |
| if (!indicator) return; | |
| const dot = indicator.querySelector('.status-dot'); | |
| const text = indicator.querySelector('.status-text'); | |
| if (running) { | |
| dot.className = 'status-dot online'; | |
| text.textContent = 'Online'; | |
| } else if (starting) { | |
| dot.className = 'status-dot starting'; | |
| text.textContent = 'Starting'; | |
| } else { | |
| dot.className = 'status-dot offline'; | |
| text.textContent = 'Offline'; | |
| } | |
| } | |
| // Global keyboard shortcuts | |
| document.addEventListener('keydown', (e) => { | |
| // Ctrl/Cmd + K: Focus search if exists | |
| if ((e.ctrlKey || e.metaKey) && e.key === 'k') { | |
| const searchInput = document.querySelector('input[type="text"][placeholder*="Search"]'); | |
| if (searchInput) { | |
| e.preventDefault(); | |
| searchInput.focus(); | |
| } | |
| } | |
| // Escape: Close modals | |
| if (e.key === 'Escape') { | |
| const activeModal = document.querySelector('.modal.active'); | |
| if (activeModal) { | |
| activeModal.classList.remove('active'); | |
| } | |
| } | |
| }); | |
| // Initialize tooltips (if any elements have data-tooltip) | |
| document.querySelectorAll('[data-tooltip]').forEach(el => { | |
| el.addEventListener('mouseenter', (e) => { | |
| const tooltip = document.createElement('div'); | |
| tooltip.className = 'tooltip'; | |
| tooltip.textContent = el.dataset.tooltip; | |
| document.body.appendChild(tooltip); | |
| const rect = el.getBoundingClientRect(); | |
| tooltip.style.top = `${rect.bottom + 8}px`; | |
| tooltip.style.left = `${rect.left + (rect.width / 2) - (tooltip.offsetWidth / 2)}px`; | |
| }); | |
| el.addEventListener('mouseleave', () => { | |
| document.querySelectorAll('.tooltip').forEach(t => t.remove()); | |
| }); | |
| }); | |
| // Auto-refresh status periodically | |
| if (typeof io !== 'undefined') { | |
| // Socket.IO is available, status updates will come via websocket | |
| console.log('WebSocket mode enabled'); | |
| } else { | |
| // Fallback to polling | |
| setInterval(async () => { | |
| try { | |
| const status = await apiCall('/api/status'); | |
| updateSidebarStatus(status.running, status.starting); | |
| } catch (e) { | |
| // Ignore errors during polling | |
| } | |
| }, 10000); | |
| } | |
| // Confirm before leaving page if there are unsaved changes | |
| let hasUnsavedChanges = false; | |
| window.addEventListener('beforeunload', (e) => { | |
| if (hasUnsavedChanges) { | |
| e.preventDefault(); | |
| e.returnValue = ''; | |
| } | |
| }); | |
| // Mark page as having unsaved changes when editing | |
| document.querySelectorAll('textarea, input[type="text"]').forEach(el => { | |
| el.addEventListener('input', () => { | |
| if (el.classList.contains('code-editor') || el.closest('.settings-grid')) { | |
| hasUnsavedChanges = true; | |
| } | |
| }); | |
| }); | |
| // Reset unsaved changes flag after successful save | |
| const originalShowToast = showToast; | |
| showToast = function(message, type) { | |
| if (type === 'success' && (message.includes('saved') || message.includes('updated'))) { | |
| hasUnsavedChanges = false; | |
| } | |
| originalShowToast(message, type); | |
| }; | |
| // File drag and drop prevention (except on upload zones) | |
| document.addEventListener('dragover', (e) => { | |
| if (!e.target.closest('.upload-zone')) { | |
| e.preventDefault(); | |
| } | |
| }); | |
| document.addEventListener('drop', (e) => { | |
| if (!e.target.closest('.upload-zone')) { | |
| e.preventDefault(); | |
| } | |
| }); | |
| // Console log for debugging | |
| console.log('MC Server Panel loaded'); | |
| console.log('Version: 1.0.0'); | |
| console.log('Minecraft: 1.21.1'); | |
| console.log('Fabric: 0.17.1'); |